# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_office_allocation():
    """Optimize office space allocation to maximize market value."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("company_office")
    
    # Data from the problem context
    market_values = [12.0, 18.0, 14.5]  # Market values in billions
    sales = [6.5, 8.0, 7.0]  # Sales in billions
    stories = [12, 18, 15]  # Number of stories in each building
    minimum_sales_requirement = 20.0  # Minimum sales requirement in billions
    
    n_companies = len(market_values)
    n_buildings = len(stories)
    
    # CRITICAL: Validate array lengths before loops
    assert len(market_values) == len(sales) == n_companies, "Company data length mismatch"
    assert len(stories) == n_buildings, "Building data length mismatch"
    
    # 2. VARIABLES
    # Decision variables: x[i, j] = 1 if company j is allocated to building i
    x = model.addVars(n_buildings, n_companies, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total market value
    model.setObjective(gp.quicksum(market_values[j] * x[i, j] for i in range(n_buildings) for j in range(n_companies)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Building capacity constraints
    model.addConstrs((gp.quicksum(x[i, j] for j in range(n_companies)) <= stories[i] for i in range(n_buildings)), name="building_capacity")
    
    # Minimum sales performance constraint
    model.addConstr(gp.quicksum(sales[j] * x[i, j] for i in range(n_buildings) for j in range(n_companies)) >= minimum_sales_requirement, name="min_sales")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_buildings):
            for j in range(n_companies):
                if x[i, j].x > 1e-6:
                    print(f"Company {j} is allocated to Building {i}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_office_allocation()