# Complete GUROBIPY implementation - Retry Attempt 4

import gurobipy as gp
from gurobipy import GRB

def optimize_candidate_poll():
    """Optimize the candidate poll investment strategy using Gurobipy."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("candidate_poll_optimization")
    
    # Data from the problem
    poll_sources = [1, 2, 3]
    support_rates = {1: 0.3, 2: 0.4, 3: 0.5}
    conversion_rates = {1: 0.05, 2: 0.07, 3: 0.1}
    total_budget = 100000
    min_investment = 1000
    max_support_rate = 0.8
    
    # CRITICAL: Validate array lengths before loops
    assert len(poll_sources) == len(support_rates) == len(conversion_rates), "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=min_investment) for i in poll_sources}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(
        gp.quicksum(support_rates[i] + conversion_rates[i] * x[i] for i in poll_sources),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Budget Constraint
    model.addConstr(
        gp.quicksum(x[i] for i in poll_sources) <= total_budget,
        name="budget_constraint"
    )
    
    # Maximum Support Rate Constraint
    for i in poll_sources:
        model.addConstr(
            support_rates[i] + conversion_rates[i] * x[i] <= max_support_rate,
            name=f"max_support_rate_{i}"
        )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in poll_sources:
            print(f"Investment in poll source {i}: {x[i].x:.2f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
optimize_candidate_poll()