[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v2

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v2

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multiechelon_chain_v2",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "Plant",
    "DC1",
    "DC2",
    "Store1",
    "Store2",
    "Store3"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "Plant": 8174.125923331587,
    "DC1": 3474.8210135904546,
    "DC2": 4131.976792991967,
    "Store1": 570.6196903715588,
    "Store2": 543.3681657022936,
    "Store3": 523.7522710232104
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "Plant": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC1": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "DC2": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "Store1": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store2": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store3": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      303,
      302,
      371,
      329,
      439,
      515,
      651,
      836,
      1242,
      1389,
      1396,
      1405,
      1144,
      1021,
      763,
      586,
      378,
      371,
      332,
      335
    ],
    "SKU_Premium": [
      170,
      168,
      181,
      185,
      231,
      258,
      337,
      480,
      554,
      715,
      706,
      592,
      620,
      511,
      397,
      289,
      218,
      185,
      172,
      171
    ],
    "SKU_ShortLife": [
      119,
      136,
      116,
      126,
      152,
      214,
      310,
      340,
      482,
      523,
      594,
      517,
      376,
      356,
      244,
      206,
      178,
      165,
      120,
      142
    ]
  },
  "demand_share": {
    "Plant": 0.0,
    "DC1": 0.0,
    "DC2": 0.0,
    "Store1": 0.3,
    "Store2": 0.4,
    "Store3": 0.3
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "Plant",
        "DC1"
      ],
      [
        "Plant",
        "DC2"
      ],
      [
        "DC1",
        "Store1"
      ],
      [
        "DC1",
        "Store2"
      ],
      [
        "DC2",
        "Store2"
      ],
      [
        "DC2",
        "Store3"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v3

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v3

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multiechelon_chain_v3",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "Plant",
    "DC1",
    "DC2",
    "Store1",
    "Store2",
    "Store3"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "Plant": 7636.056212789862,
    "DC1": 4575.052368264268,
    "DC2": 3856.8306184928415,
    "Store1": 576.5948896306264,
    "Store2": 521.8922423791751,
    "Store3": 679.0933700497394
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "Plant": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC1": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "DC2": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "Store1": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store2": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store3": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      260,
      304,
      333,
      398,
      499,
      615,
      680,
      1027,
      1206,
      1175,
      1418,
      1414,
      1134,
      840,
      703,
      484,
      430,
      372,
      325,
      312
    ],
    "SKU_Premium": [
      156,
      162,
      186,
      191,
      225,
      268,
      343,
      409,
      524,
      620,
      660,
      646,
      518,
      511,
      355,
      265,
      214,
      174,
      144,
      163
    ],
    "SKU_ShortLife": [
      104,
      127,
      119,
      158,
      170,
      231,
      245,
      384,
      380,
      428,
      490,
      447,
      397,
      413,
      248,
      195,
      185,
      142,
      130,
      108
    ]
  },
  "demand_share": {
    "Plant": 0.0,
    "DC1": 0.0,
    "DC2": 0.0,
    "Store1": 0.3,
    "Store2": 0.4,
    "Store3": 0.3
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "Plant",
        "DC1"
      ],
      [
        "Plant",
        "DC2"
      ],
      [
        "DC1",
        "Store1"
      ],
      [
        "DC1",
        "Store2"
      ],
      [
        "DC2",
        "Store2"
      ],
      [
        "DC2",
        "Store3"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v4

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v4

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multiechelon_chain_v4",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "Plant",
    "DC1",
    "DC2",
    "Store1",
    "Store2",
    "Store3"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "Plant": 7464.857246572141,
    "DC1": 4184.413862370035,
    "DC2": 4402.082575285726,
    "Store1": 635.488987491309,
    "Store2": 562.2161541552067,
    "Store3": 650.9184303035677
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "Plant": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC1": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "DC2": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "Store1": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store2": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store3": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      291,
      338,
      332,
      334,
      496,
      481,
      769,
      823,
      1246,
      1379,
      1182,
      1070,
      1136,
      1014,
      642,
      472,
      382,
      366,
      309,
      279
    ],
    "SKU_Premium": [
      131,
      173,
      173,
      186,
      193,
      253,
      392,
      501,
      550,
      686,
      691,
      639,
      575,
      400,
      324,
      247,
      214,
      180,
      158,
      169
    ],
    "SKU_ShortLife": [
      137,
      141,
      139,
      129,
      163,
      204,
      276,
      334,
      394,
      521,
      527,
      494,
      504,
      361,
      264,
      197,
      156,
      152,
      117,
      116
    ]
  },
  "demand_share": {
    "Plant": 0.0,
    "DC1": 0.0,
    "DC2": 0.0,
    "Store1": 0.3,
    "Store2": 0.4,
    "Store3": 0.3
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "Plant",
        "DC1"
      ],
      [
        "Plant",
        "DC2"
      ],
      [
        "DC1",
        "Store1"
      ],
      [
        "DC1",
        "Store2"
      ],
      [
        "DC2",
        "Store2"
      ],
      [
        "DC2",
        "Store3"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v0

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v0

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_ring_routing_v0",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "DC1": 3200.0,
    "DC2": 2800.0,
    "DC3": 2400.0,
    "DC4": 2400.0,
    "DC5": 2000.0
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      303,
      311,
      328,
      365,
      435,
      549,
      711,
      906,
      1100,
      1245,
      1300,
      1245,
      1100,
      906,
      711,
      549,
      435,
      365,
      328,
      311
    ],
    "SKU_Premium": [
      151,
      155,
      164,
      182,
      217,
      274,
      355,
      453,
      550,
      622,
      650,
      622,
      550,
      453,
      355,
      274,
      217,
      182,
      164,
      155
    ],
    "SKU_ShortLife": [
      121,
      124,
      131,
      146,
      174,
      219,
      284,
      362,
      440,
      498,
      520,
      498,
      440,
      362,
      284,
      219,
      174,
      146,
      131,
      124
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "DC1",
        "DC2"
      ],
      [
        "DC2",
        "DC3"
      ],
      [
        "DC3",
        "DC4"
      ],
      [
        "DC4",
        "DC5"
      ],
      [
        "DC5",
        "DC1"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v1

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v1

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_ring_routing_v1",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "DC1": 2991.8326868227214,
    "DC2": 2532.9007952808656,
    "DC3": 2608.4258534753153,
    "DC4": 2118.6262010983583,
    "DC5": 2207.6219002477706
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      342,
      293,
      376,
      397,
      429,
      588,
      811,
      952,
      1238,
      1392,
      1210,
      1308,
      1038,
      1007,
      614,
      540,
      496,
      335,
      330,
      270
    ],
    "SKU_Premium": [
      135,
      140,
      159,
      203,
      203,
      238,
      356,
      489,
      624,
      593,
      583,
      576,
      608,
      468,
      357,
      252,
      220,
      192,
      178,
      148
    ],
    "SKU_ShortLife": [
      125,
      132,
      136,
      149,
      185,
      248,
      318,
      366,
      375,
      542,
      502,
      484,
      374,
      326,
      272,
      224,
      174,
      161,
      121,
      105
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "DC1",
        "DC2"
      ],
      [
        "DC2",
        "DC3"
      ],
      [
        "DC3",
        "DC4"
      ],
      [
        "DC4",
        "DC5"
      ],
      [
        "DC5",
        "DC1"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v2

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v2

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_ring_routing_v2",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "DC1": 2784.2919716531696,
    "DC2": 2460.849040129472,
    "DC3": 2434.741837346542,
    "DC4": 2443.1677837295156,
    "DC5": 1976.9535918402903
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      301,
      279,
      325,
      328,
      441,
      563,
      793,
      898,
      1206,
      1331,
      1459,
      1086,
      1114,
      998,
      787,
      495,
      462,
      386,
      284,
      332
    ],
    "SKU_Premium": [
      154,
      165,
      140,
      177,
      185,
      257,
      399,
      429,
      570,
      647,
      555,
      691,
      547,
      442,
      336,
      314,
      228,
      189,
      140,
      157
    ],
    "SKU_ShortLife": [
      110,
      113,
      144,
      129,
      179,
      240,
      260,
      315,
      449,
      525,
      579,
      500,
      378,
      328,
      256,
      220,
      174,
      162,
      127,
      110
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "DC1",
        "DC2"
      ],
      [
        "DC2",
        "DC3"
      ],
      [
        "DC3",
        "DC4"
      ],
      [
        "DC4",
        "DC5"
      ],
      [
        "DC5",
        "DC1"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v3

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_ring_routing
Scenario ID: retail_f7_ring_routing_v3

[BUSINESS DESCRIPTION]
Business narrative:
Locations are connected in a directed ring, mimicking a truck route that visits each location in a fixed cycle. Inventory can only move along the ring edges, and storage capacities are tightened so that the chosen routing structure affects feasibility and cost. Demand is local and exogenous at each node, and unmet demand is lost and penalized.

Structure cues:
- The transshipment network in the JSON forms a directed cycle: DC1->DC2->DC3->DC4->DC5->DC1. Inventory can be shipped only along these ring edges.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities are scaled to 80% of normal values.
- For each product, location, and period, inventory reflects previous stock, local production, inbound ring shipments, outbound ring shipments, sales, and waste, and must remain non-negative.
- Demand at each location is met from local inventory and inbound ring shipments; there are no shortcuts across the ring.
- Inventory that moves further along the route must pass through intermediate locations in sequence.
- Lead times for ring shipments are effectively zero in this archetype, and substitution behavior is as encoded.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, lost sales, and transshipment costs) while respecting the ring network structure and tighter storage capacities.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_ring_routing_v3",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "DC1": 2930.9112388773356,
    "DC2": 2577.6761352570757,
    "DC3": 2199.5198000037785,
    "DC4": 2262.2877146418004,
    "DC5": 1874.0180327715484
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      337,
      334,
      296,
      367,
      439,
      628,
      694,
      787,
      1066,
      1292,
      1147,
      1420,
      1024,
      930,
      669,
      533,
      390,
      328,
      299,
      325
    ],
    "SKU_Premium": [
      133,
      175,
      183,
      182,
      238,
      297,
      313,
      459,
      603,
      639,
      632,
      541,
      566,
      483,
      383,
      280,
      233,
      180,
      178,
      155
    ],
    "SKU_ShortLife": [
      127,
      106,
      132,
      143,
      173,
      231,
      243,
      391,
      443,
      438,
      568,
      490,
      479,
      383,
      318,
      233,
      195,
      161,
      128,
      133
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "DC1",
        "DC2"
      ],
      [
        "DC2",
        "DC3"
      ],
      [
        "DC3",
        "DC4"
      ],
      [
        "DC4",
        "DC5"
      ],
      [
        "DC5",
        "DC1"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.