# Complete GUROBIPY implementation - Retry Attempt 4

import gurobipy as gp
from gurobipy import GRB

def device_distribution_optimization():
    # 1. MODEL & DATA SETUP
    model = gp.Model("device_distribution")
    
    # Data from the problem
    devices = [1, 2, 3]
    shops = [101, 102, 103]
    
    # Shipping costs
    shipping_cost = {
        (1, 101): 12.5,
        (2, 102): 18.0,
        (3, 103): 15.0
    }
    
    # Demand
    demand = {
        (1, 101): 60,
        (2, 102): 80,
        (3, 103): 70
    }
    
    # Storage capacity
    storage_capacity = {
        101: 250,
        102: 300,
        103: 200
    }
    
    # CRITICAL: Validate array lengths before loops
    assert len(shipping_cost) == len(demand) == len(devices) * len(shops), "Data length mismatch"
    
    # 2. VARIABLES
    x = model.addVars(devices, shops, vtype=GRB.INTEGER, name="x", lb=0)
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(shipping_cost[d, s] * x[d, s] for d in devices for s in shops), GRB.MINIMIZE)
    
    # 4. CONSTRAINTS
    
    # Demand Fulfillment
    for d in devices:
        for s in shops:
            model.addConstr(x[d, s] >= demand[d, s], name=f"demand_{d}_{s}")
    
    # Storage Capacity
    for s in shops:
        model.addConstr(gp.quicksum(x[d, s] for d in devices) <= storage_capacity[s], name=f"capacity_{s}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for d in devices:
            for s in shops:
                if x[d, s].x > 1e-6:
                    print(f"x[{d},{s}] = {x[d, s].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
device_distribution_optimization()