# Complete GUROBIPY implementation - Retry Attempt 4

import gurobipy as gp
from gurobipy import GRB

def naval_optimization():
    # 1. MODEL & DATA SETUP
    model = gp.Model("battle_death_minimization")
    
    # Example data setup (replace with actual data retrieval logic)
    ships = [1, 2, 3]
    battles = [101, 102, 103]
    deaths_data = {
        (1, 101): 15,
        (2, 102): 25,
        (3, 103): 5
    }
    min_ships_required = {
        101: 3,
        102: 5,
        103: 2
    }
    max_ships = 5  # Example maximum number of ships available

    # CRITICAL: Validate array lengths before loops
    assert len(deaths_data) == len(ships) * len(battles), "Array length mismatch"

    # 2. VARIABLES
    # Binary decision variables for ship assignments
    x = model.addVars(ships, battles, vtype=GRB.BINARY, name="x")

    # 3. OBJECTIVE FUNCTION
    # Minimize the total number of deaths
    model.setObjective(gp.quicksum(deaths_data[i, j] * x[i, j] for i in ships for j in battles), GRB.MINIMIZE)

    # 4. CONSTRAINTS
    # Each ship can be assigned to at most one battle
    model.addConstrs((gp.quicksum(x[i, j] for j in battles) <= 1 for i in ships), name="ship_assignment")

    # Each battle must receive at least the minimum required number of ships
    model.addConstrs((gp.quicksum(x[i, j] for i in ships) >= min_ships_required[j] for j in battles), name="battle_requirement")

    # The total number of ships assigned cannot exceed the maximum number available
    model.addConstr(gp.quicksum(x[i, j] for i in ships for j in battles) <= max_ships, name="max_ships")

    # 5. SOLVING & RESULTS
    model.optimize()

    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in ships:
            for j in battles:
                if x[i, j].x > 1e-6:
                    print(f"Ship {i} assigned to Battle {j}: {x[i, j].x:.0f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")

    return model

# Run the optimization
naval_optimization()