# Complete DOCPLEX implementation

from docplex.mp.model import Model

def optimize_office_allocation():
    """Optimize the allocation of office spaces to maximize market value."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="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
    
    # Validate array lengths to prevent IndexError
    assert len(market_values) == len(sales), "Array length mismatch for companies"
    assert len(stories) > 0, "No buildings available"
    
    num_companies = len(market_values)
    num_buildings = len(stories)
    
    # Safe indexing range
    safe_range_companies = range(num_companies)
    safe_range_buildings = range(num_buildings)
    
    # 2. VARIABLES
    # Binary decision variables for allocation
    x = {(i, j): mdl.binary_var(name=f"x_{i}_{j}") for i in safe_range_buildings for j in safe_range_companies}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total market value of the allocated companies
    objective = mdl.sum(market_values[j] * x[i, j] for i in safe_range_buildings for j in safe_range_companies)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Building Capacity Constraints
    for i in safe_range_buildings:
        mdl.add_constraint(mdl.sum(x[i, j] for j in safe_range_companies) <= stories[i], ctname=f"capacity_{i}")
    
    # Minimum Sales Performance Constraint
    total_sales = mdl.sum(sales[j] * x[i, j] for i in safe_range_buildings for j in safe_range_companies)
    mdl.add_constraint(total_sales >= minimum_sales_requirement, ctname="min_sales")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range_buildings:
            for j in safe_range_companies:
                if solution.get_value(x[i, j]) > 0.5:  # Check if the company is allocated
                    print(f"Company {j} is allocated to Building {i}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
optimize_office_allocation()