[SCENARIO]
Family: F1 (Core Operations)
Archetype: retail_f1_jit_logic
Scenario ID: retail_f1_jit_logic_v3

[BUSINESS DESCRIPTION]
Business narrative:
This scenario represents a just-in-time regime where holding inventory is very expensive. The retailer still faces exogenous seasonal demand at each location, cannot backorder customers, and has limited per-product production capacity per period. Because holding costs are high, the retailer is incentivized to keep inventories as lean as possible while still avoiding excessive lost sales.

Structure cues:
- The physical network and decision timing are the same as in retail_f1_base: single-echelon, multi-product, multi-location, with local demand and local inventory.
- Inventory at each location carries over from the previous period, is increased by local production that arrives without delay, and is reduced by sales and any intentional waste. Stock levels must remain non-negative, and any demand in excess of available stock is treated as lost sales.
- 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]. These limits must be respected.
- Substitution behavior (Basic's demand served by Premium), absence of transshipment, and zero lead times all match the baseline archetype.
- Holding cost coefficients in the JSON are scaled up substantially compared with retail_f1_base, making on-hand inventory much more expensive relative to lost sales. The underlying constraint structure is unchanged.
- The objective is to minimize total cost including purchasing, holding, waste, and lost sales, with the higher holding cost forcing a just-in-time style of operation.

[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: F1 (Core Operations)
Archetype: retail_f1_jit_logic
Scenario ID: retail_f1_jit_logic_v3

[BUSINESS DESCRIPTION]
Business narrative:
This scenario represents a just-in-time regime where holding inventory is very expensive. The retailer still faces exogenous seasonal demand at each location, cannot backorder customers, and has limited per-product production capacity per period. Because holding costs are high, the retailer is incentivized to keep inventories as lean as possible while still avoiding excessive lost sales.

Structure cues:
- The physical network and decision timing are the same as in retail_f1_base: single-echelon, multi-product, multi-location, with local demand and local inventory.
- Inventory at each location carries over from the previous period, is increased by local production that arrives without delay, and is reduced by sales and any intentional waste. Stock levels must remain non-negative, and any demand in excess of available stock is treated as lost sales.
- 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]. These limits must be respected.
- Substitution behavior (Basic's demand served by Premium), absence of transshipment, and zero lead times all match the baseline archetype.
- Holding cost coefficients in the JSON are scaled up substantially compared with retail_f1_base, making on-hand inventory much more expensive relative to lost sales. The underlying constraint structure is unchanged.
- The objective is to minimize total cost including purchasing, holding, waste, and lost sales, with the higher holding cost forcing a just-in-time style of operation.

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

```json
{
  "name": "retail_f1_jit_logic_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": 4555.306381840641,
    "DC2": 3422.9891952366816,
    "DC3": 3109.676300553904,
    "DC4": 2978.9533068169394,
    "DC5": 2419.4473267149483
  },
  "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": [
      344,
      349,
      329,
      376,
      437,
      599,
      604,
      928,
      959,
      1064,
      1163,
      1146,
      936,
      781,
      660,
      601,
      444,
      356,
      359,
      316
    ],
    "SKU_Premium": [
      141,
      159,
      148,
      185,
      196,
      243,
      337,
      512,
      594,
      708,
      617,
      697,
      615,
      407,
      305,
      270,
      214,
      156,
      164,
      156
    ],
    "SKU_ShortLife": [
      115,
      110,
      140,
      147,
      196,
      239,
      250,
      348,
      415,
      531,
      550,
      536,
      454,
      310,
      271,
      249,
      173,
      153,
      115,
      125
    ]
  },
  "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": 20.0,
      "SKU_Premium": 30.0,
      "SKU_ShortLife": 20.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": []
  }
}
```

[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: F1 (Core Operations)
Archetype: retail_f1_jit_logic
Scenario ID: retail_f1_jit_logic_v4

[BUSINESS DESCRIPTION]
Business narrative:
This scenario represents a just-in-time regime where holding inventory is very expensive. The retailer still faces exogenous seasonal demand at each location, cannot backorder customers, and has limited per-product production capacity per period. Because holding costs are high, the retailer is incentivized to keep inventories as lean as possible while still avoiding excessive lost sales.

Structure cues:
- The physical network and decision timing are the same as in retail_f1_base: single-echelon, multi-product, multi-location, with local demand and local inventory.
- Inventory at each location carries over from the previous period, is increased by local production that arrives without delay, and is reduced by sales and any intentional waste. Stock levels must remain non-negative, and any demand in excess of available stock is treated as lost sales.
- 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]. These limits must be respected.
- Substitution behavior (Basic's demand served by Premium), absence of transshipment, and zero lead times all match the baseline archetype.
- Holding cost coefficients in the JSON are scaled up substantially compared with retail_f1_base, making on-hand inventory much more expensive relative to lost sales. The underlying constraint structure is unchanged.
- The objective is to minimize total cost including purchasing, holding, waste, and lost sales, with the higher holding cost forcing a just-in-time style of operation.

[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: F1 (Core Operations)
Archetype: retail_f1_jit_logic
Scenario ID: retail_f1_jit_logic_v4

[BUSINESS DESCRIPTION]
Business narrative:
This scenario represents a just-in-time regime where holding inventory is very expensive. The retailer still faces exogenous seasonal demand at each location, cannot backorder customers, and has limited per-product production capacity per period. Because holding costs are high, the retailer is incentivized to keep inventories as lean as possible while still avoiding excessive lost sales.

Structure cues:
- The physical network and decision timing are the same as in retail_f1_base: single-echelon, multi-product, multi-location, with local demand and local inventory.
- Inventory at each location carries over from the previous period, is increased by local production that arrives without delay, and is reduced by sales and any intentional waste. Stock levels must remain non-negative, and any demand in excess of available stock is treated as lost sales.
- 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]. These limits must be respected.
- Substitution behavior (Basic's demand served by Premium), absence of transshipment, and zero lead times all match the baseline archetype.
- Holding cost coefficients in the JSON are scaled up substantially compared with retail_f1_base, making on-hand inventory much more expensive relative to lost sales. The underlying constraint structure is unchanged.
- The objective is to minimize total cost including purchasing, holding, waste, and lost sales, with the higher holding cost forcing a just-in-time style of operation.

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

```json
{
  "name": "retail_f1_jit_logic_v4",
  "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": 4360.258165461391,
    "DC2": 3699.6661096856687,
    "DC3": 2889.2660497979646,
    "DC4": 2969.6855695873214,
    "DC5": 2574.1834181917643
  },
  "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": [
      311,
      267,
      330,
      395,
      470,
      548,
      738,
      853,
      1188,
      1289,
      1443,
      1356,
      1201,
      1034,
      811,
      496,
      393,
      338,
      300,
      356
    ],
    "SKU_Premium": [
      149,
      171,
      173,
      167,
      239,
      293,
      363,
      470,
      617,
      591,
      571,
      714,
      569,
      499,
      302,
      261,
      235,
      200,
      153,
      133
    ],
    "SKU_ShortLife": [
      112,
      126,
      126,
      132,
      165,
      244,
      287,
      328,
      467,
      443,
      501,
      508,
      391,
      319,
      313,
      191,
      157,
      137,
      119,
      128
    ]
  },
  "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": 20.0,
      "SKU_Premium": 30.0,
      "SKU_ShortLife": 20.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": []
  }
}
```

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v0

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v0

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

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

```json
{
  "name": "retail_f2_cannibalization_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": 2000.0,
    "DC2": 1750.0,
    "DC3": 1500.0,
    "DC4": 1500.0,
    "DC5": 1250.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": [
      606,
      622,
      656,
      730,
      870,
      1098,
      1422,
      1812,
      2200,
      2490,
      2600,
      2490,
      2200,
      1812,
      1422,
      1098,
      870,
      730,
      656,
      622
    ],
    "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": 5.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": []
  }
}
```

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v1

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v1

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

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

```json
{
  "name": "retail_f2_cannibalization_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": 1778.8028994099282,
    "DC2": 1557.6602758218983,
    "DC3": 1361.536642922949,
    "DC4": 1531.1222473565335,
    "DC5": 1338.3709482251743
  },
  "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": [
      679,
      617,
      719,
      784,
      840,
      1226,
      1249,
      1661,
      2347,
      2751,
      2890,
      2656,
      2361,
      1877,
      1232,
      939,
      748,
      751,
      607,
      647
    ],
    "SKU_Premium": [
      130,
      170,
      157,
      198,
      218,
      276,
      403,
      451,
      481,
      581,
      698,
      653,
      575,
      507,
      322,
      290,
      249,
      184,
      162,
      137
    ],
    "SKU_ShortLife": [
      136,
      141,
      122,
      133,
      168,
      202,
      324,
      339,
      450,
      491,
      485,
      431,
      394,
      356,
      258,
      192,
      171,
      167,
      142,
      126
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 5.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": []
  }
}
```

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v2

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v2

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

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

```json
{
  "name": "retail_f2_cannibalization_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": 2244.0402236247196,
    "DC2": 1699.331200549469,
    "DC3": 1280.5201027175053,
    "DC4": 1539.7512559729769,
    "DC5": 1119.0333113901247
  },
  "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": [
      637,
      578,
      753,
      788,
      831,
      1253,
      1398,
      1619,
      2460,
      2471,
      2232,
      2120,
      2129,
      1972,
      1595,
      1199,
      820,
      727,
      747,
      674
    ],
    "SKU_Premium": [
      146,
      148,
      164,
      172,
      188,
      303,
      315,
      385,
      519,
      678,
      607,
      538,
      476,
      406,
      373,
      304,
      241,
      160,
      181,
      134
    ],
    "SKU_ShortLife": [
      111,
      127,
      125,
      148,
      175,
      223,
      312,
      372,
      387,
      516,
      525,
      563,
      455,
      359,
      268,
      186,
      172,
      157,
      116,
      110
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 5.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": []
  }
}
```

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v3

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v3

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

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

```json
{
  "name": "retail_f2_cannibalization_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": 2159.267870664336,
    "DC2": 1947.1171093504597,
    "DC3": 1484.7541613610883,
    "DC4": 1517.4769188514363,
    "DC5": 1359.4549478997042
  },
  "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": [
      535,
      549,
      722,
      665,
      990,
      1229,
      1406,
      1546,
      2147,
      2418,
      2875,
      2175,
      2027,
      1984,
      1633,
      1129,
      843,
      777,
      672,
      646
    ],
    "SKU_Premium": [
      136,
      175,
      175,
      178,
      201,
      279,
      407,
      473,
      489,
      641,
      569,
      563,
      506,
      437,
      325,
      306,
      220,
      192,
      168,
      141
    ],
    "SKU_ShortLife": [
      111,
      122,
      118,
      138,
      173,
      199,
      318,
      309,
      380,
      528,
      590,
      475,
      480,
      307,
      276,
      201,
      191,
      153,
      133,
      113
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 5.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": []
  }
}
```

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v4

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

[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: F2 (Assortment and Substitution)
Archetype: retail_f2_cannibalization
Scenario ID: retail_f2_cannibalization_v4

[BUSINESS DESCRIPTION]
Business narrative:
The retailer heavily promotes a low-margin basic product, strongly increasing its demand and making lost sales on that product relatively cheap, while shared storage is tightened. Because all products share limited storage, stocking more of the promoted basic product can displace higher-margin premium and short-life items. Customers can still switch along the substitution pattern in the category, but the promotional focus on the basic product creates cannibalization pressure.

Structure cues:
- The underlying inventory and substitution structure is the same as in retail_f2_circular_sub, with a single-echelon system, shared storage at each location, and a directed substitution graph defined in the JSON.
- 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]. The JSON reduces storage capacity, making space more scarce.
- The JSON increases demand for the basic product and reduces its lost sales penalty while keeping higher margins on other items.
- Tight shared storage capacity means that choosing to stock more of the basic product can crowd out premium and short-life items in the warehouse, purely through the capacity and cost parameters.
- Inventory remains non-negative, lost sales capture unsatisfied demand after substitution, and there is still no transshipment or backordering.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales), and the cannibalization effect is driven by the interplay of demand, margin, lost sales penalties, and capacity parameters rather than by any change to the model's basic structure.

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

```json
{
  "name": "retail_f2_cannibalization_v4",
  "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": 2130.0920075505283,
    "DC2": 1791.593449254044,
    "DC3": 1333.4028661526593,
    "DC4": 1355.7222579803988,
    "DC5": 1135.6893821866583
  },
  "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": [
      523,
      585,
      727,
      652,
      890,
      1034,
      1410,
      1630,
      2505,
      2393,
      2510,
      2326,
      2212,
      1892,
      1553,
      1170,
      989,
      748,
      654,
      692
    ],
    "SKU_Premium": [
      140,
      143,
      159,
      201,
      219,
      300,
      359,
      433,
      616,
      659,
      660,
      551,
      567,
      509,
      326,
      254,
      224,
      155,
      149,
      175
    ],
    "SKU_ShortLife": [
      115,
      107,
      122,
      153,
      182,
      226,
      291,
      349,
      377,
      552,
      527,
      425,
      481,
      414,
      304,
      248,
      196,
      155,
      143,
      106
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 5.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": []
  }
}
```

[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.