# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_investments():
    """Optimize investment allocation to maximize expected return."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("investment_optimization")
    
    # Data: Expected return rates and maximum money requested by each entrepreneur
    expected_return_rates = [0.12, 0.18, 0.22]
    money_requested = [20000, 25000, 30000]
    total_budget = 60000
    
    # Number of entrepreneurs
    n_entrepreneurs = len(expected_return_rates)
    
    # CRITICAL: Validate array lengths before loops
    assert len(expected_return_rates) == len(money_requested) == n_entrepreneurs, "Array length mismatch"
    
    # 2. VARIABLES
    # Investment amounts for each entrepreneur
    investments = model.addVars(n_entrepreneurs, vtype=GRB.CONTINUOUS, name="investment", lb=0)
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total expected return
    model.setObjective(gp.quicksum(expected_return_rates[i] * investments[i] for i in range(n_entrepreneurs)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Total budget constraint
    model.addConstr(gp.quicksum(investments[i] for i in range(n_entrepreneurs)) <= total_budget, name="budget_constraint")
    
    # Individual investment constraints
    for i in range(n_entrepreneurs):
        model.addConstr(investments[i] <= money_requested[i], name=f"max_investment_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_entrepreneurs):
            if investments[i].x > 1e-6:
                print(f"Investment in entrepreneur {i+1}: {investments[i].x:.2f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_investments()