# Complete Optimization Problem and Solution: entrepreneur

## 1. Problem Context and Goals

### Context  
An investor is tasked with allocating a fixed budget across multiple entrepreneurs to maximize the total expected return on investment. The investor must decide how much money to allocate to each entrepreneur, ensuring that the total investment does not exceed the available budget and that no single entrepreneur receives more than a specified maximum amount. The available budget for investment is set at one million dollars, and the maximum amount that can be allocated to any single entrepreneur is two hundred thousand dollars. These parameters are designed to ensure risk management and diversification across the investment portfolio. The expected return rate for each entrepreneur is a key factor in determining the optimal allocation, as it directly influences the total return on investment.

### Goals  
The primary goal of this optimization problem is to maximize the total expected return on investment by strategically allocating the available budget across the entrepreneurs. Success is measured by the total return generated from the investments, which is calculated by multiplying the amount allocated to each entrepreneur by their respective expected return rate and summing these values across all entrepreneurs. The optimization process ensures that the allocation decisions are made in a way that respects the budget and individual investment limits while maximizing the overall return.

## 2. Constraints    

The optimization problem is subject to two key constraints:  
1. **Total Budget Constraint**: The sum of all investments allocated to the entrepreneurs must not exceed the total available budget of one million dollars. This ensures that the investor does not overspend and stays within the financial limits.  
2. **Individual Investment Limit**: The amount allocated to any single entrepreneur must not exceed two hundred thousand dollars. This constraint ensures that the investment portfolio remains diversified and that no single entrepreneur receives an disproportionately large share of the budget.  

These constraints are designed to align with the investor's risk management strategy and ensure that the allocation decisions are both financially sound and operationally feasible.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 1 Database Schema
-- Objective: Schema changes and configuration logic updates implemented to address missing optimization requirements and mapping gaps identified by the OR expert.

CREATE TABLE entrepreneurs (
  entrepreneur_id INTEGER,
  return_rate FLOAT,
  investment FLOAT
);
```

### Data Dictionary  
The `entrepreneurs` table contains the following columns, each with a specific business purpose and optimization role:  
- **entrepreneur_id**: A unique identifier for each entrepreneur, used to index the decision variables and constraints in the optimization problem.  
- **return_rate**: The expected return rate for each entrepreneur, which serves as the coefficient in the objective function to maximize the total return on investment.  
- **investment**: The amount of money allocated to each entrepreneur, which is the decision variable in the optimization problem.  

### Current Stored Values  
```sql
-- Iteration 1 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on realistic investment scenarios, considering typical return rates and budget constraints for small to medium-sized ventures.

-- Realistic data for entrepreneurs
INSERT INTO entrepreneurs (entrepreneur_id, return_rate, investment) VALUES (1, 0.12, 150000);
INSERT INTO entrepreneurs (entrepreneur_id, return_rate, investment) VALUES (2, 0.18, 200000);
INSERT INTO entrepreneurs (entrepreneur_id, return_rate, investment) VALUES (3, 0.1, 100000);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
Let \( x_i \) represent the amount of money allocated to entrepreneur \( i \), where \( i \) corresponds to the `entrepreneur_id` in the `entrepreneurs` table.  
\( x_i \geq 0 \) for all \( i \).  

#### Objective Function
Maximize the total expected return on investment:  
\[
\text{Maximize } Z = \sum_{i} (\text{return_rate}_i \times x_i)
\]  
Where \( \text{return_rate}_i \) is the expected return rate for entrepreneur \( i \).  

#### Constraints
1. **Total Budget Constraint**: The sum of all investments must not exceed the available budget of one million dollars:  
\[
\sum_{i} x_i \leq 1,000,000
\]  
2. **Individual Investment Limit**: The amount allocated to any single entrepreneur must not exceed two hundred thousand dollars:  
\[
x_i \leq 200,000 \quad \forall i
\]  

#### Data Source Verification
- \( \text{return_rate}_i \): `entrepreneurs.return_rate`  
- Budget limit: Business configuration parameter (1,000,000)  
- Individual investment limit: Business configuration parameter (200,000)  

This is a complete, immediately solvable LINEAR programming model.

## 5. Gurobipy Implementation

```python
#!/usr/bin/env python3
"""
Gurobipy Implementation for Entrepreneur Investment Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_investment():
    # 1. MODEL & DATA SETUP
    model = gp.Model("entrepreneur_investment")
    
    # Data from the entrepreneurs table
    entrepreneur_ids = [1, 2, 3]
    return_rates = [0.12, 0.18, 0.1]
    initial_investments = [150000, 200000, 100000]
    
    # Business configuration parameters
    total_budget = 1000000
    individual_investment_limit = 200000
    
    # CRITICAL: Validate array lengths before loops
    assert len(entrepreneur_ids) == len(return_rates) == len(initial_investments), "Array length mismatch"
    
    # 2. VARIABLES
    # Decision variables: amount allocated to each entrepreneur
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=0) 
         for i in entrepreneur_ids}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total expected return on investment
    model.setObjective(gp.quicksum(return_rates[i-1] * x[i] for i in entrepreneur_ids), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Total Budget Constraint
    model.addConstr(gp.quicksum(x[i] for i in entrepreneur_ids) <= total_budget, name="total_budget")
    
    # Individual Investment Limit
    for i in entrepreneur_ids:
        model.addConstr(x[i] <= individual_investment_limit, name=f"individual_limit_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in entrepreneur_ids:
            if x[i].x > 1e-6:
                print(f"Allocation to entrepreneur {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
if __name__ == "__main__":
    optimize_investment()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 80000.0
**Execution Time**: 1.02 seconds
**Reliability**: high
**Analysis**: Gurobipy successfully found the optimal solution with the highest efficiency in terms of execution time.

## 6. DOCplex Implementation

```python
#!/usr/bin/env python3
"""
DOCplex 2.29.245 Implementation for Entrepreneur Investment Optimization
"""

from docplex.mp.model import Model

def optimize_investment():
    """Optimize investment allocation across entrepreneurs to maximize return."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="entrepreneur_investment")
    
    # Data from the entrepreneurs table
    entrepreneur_ids = [1, 2, 3]
    return_rates = [0.12, 0.18, 0.1]
    initial_investments = [150000, 200000, 100000]
    
    # Business configuration parameters
    total_budget = 1000000
    individual_investment_limit = 200000
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(entrepreneur_ids) == len(return_rates) == len(initial_investments), "Array length mismatch"
    safe_range = range(min(len(entrepreneur_ids), len(return_rates), len(initial_investments)))  # Safe indexing
    
    # 2. VARIABLES
    # Decision variables: amount allocated to each entrepreneur
    x = {i: mdl.continuous_var(name=f"x_{entrepreneur_ids[i]}", lb=0) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total expected return on investment
    objective = mdl.sum(return_rates[i] * x[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Total Budget Constraint
    total_investment = mdl.sum(x[i] for i in safe_range)
    mdl.add_constraint(total_investment <= total_budget, ctname="total_budget")
    
    # Individual Investment Limit
    for i in safe_range:
        mdl.add_constraint(x[i] <= individual_investment_limit, ctname=f"individual_limit_{entrepreneur_ids[i]}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range:
            value = solution.get_value(x[i])
            print(f"Allocated to entrepreneur {entrepreneur_ids[i]}: ${value:.2f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Execute the optimization
if __name__ == "__main__":
    optimize_investment()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 80000.0
**Execution Time**: 5.33 seconds
**Reliability**: high
**Analysis**: DOCplex also found the optimal solution but took longer compared to Gurobipy.

## 7. Pyomo Implementation

```python
#!/usr/bin/env python3
"""
Pyomo 6.9.2 Implementation for Entrepreneur Investment Optimization
"""

import pyomo.environ as pyo
from pyomo.opt import SolverFactory

def optimize_investment():
    """Optimize investment allocation across entrepreneurs to maximize return"""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Realistic data for entrepreneurs
    entrepreneurs_data = {
        1: {'return_rate': 0.12},
        2: {'return_rate': 0.18},
        3: {'return_rate': 0.1}
    }
    
    # Business configuration parameters
    total_budget = 1000000  # $1,000,000
    max_individual_investment = 200000  # $200,000
    
    # 3. SETS (Pyomo way to define indices)
    model.I = pyo.Set(initialize=entrepreneurs_data.keys())  # Set of entrepreneurs
    
    # 4. PARAMETERS (data containers)
    model.return_rate = pyo.Param(model.I, initialize={i: entrepreneurs_data[i]['return_rate'] for i in model.I})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.NonNegativeReals, bounds=(0, max_individual_investment))
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.return_rate[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    
    # Total Budget Constraint
    def budget_rule(model):
        return sum(model.x[i] for i in model.I) <= total_budget
    model.budget_constraint = pyo.Constraint(rule=budget_rule)
    
    # Individual Investment Limit (already handled by variable bounds)
    
    # 8. SOLVING WITH GUROBI
    solver = SolverFactory('gurobi')
    
    # Optional: Set solver options
    solver.options['TimeLimit'] = 300  # 5 minutes
    solver.options['MIPGap'] = 0.01    # 1% gap
    
    # Solve the model
    results = solver.solve(model, tee=True)  # tee=True shows solver output
    
    # 9. RESULT PROCESSING
    # Check solver status
    if results.solver.termination_condition == pyo.TerminationCondition.optimal:
        print("Optimal solution found!")
        print(f"Optimal value: {pyo.value(model.objective)}")
        
        # Extract variable values
        print("\nInvestment allocations:")
        for i in model.I:
            x_val = pyo.value(model.x[i])
            if x_val > 1e-6:  # Only print non-zero values
                print(f"Entrepreneur {i}: ${x_val:.2f}")
        
    elif results.solver.termination_condition == pyo.TerminationCondition.infeasible:
        print("Problem is infeasible")
    elif results.solver.termination_condition == pyo.TerminationCondition.unbounded:
        print("Problem is unbounded")
    else:
        print(f"Solver terminated with condition: {results.solver.termination_condition}")
    
    return model

# Execute the optimization
if __name__ == "__main__":
    optimize_investment()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 80000.0
**Execution Time**: 3.10 seconds
**Reliability**: high
**Analysis**: Pyomo found the optimal solution with an execution time between Gurobipy and DOCplex.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 80000.00 | 1.02s | N/A | N/A |
| Docplex | OPTIMAL | 80000.00 | 5.33s | N/A | N/A |
| Pyomo | OPTIMAL | 80000.00 | 3.10s | N/A | N/A |

### Solver Consistency Analysis
**Result**: All solvers produced consistent results ✓
**Consistent Solvers**: gurobipy, docplex, pyomo
**Majority Vote Optimal Value**: 80000.0

### Final Recommendation
**Recommended Optimal Value**: 80000.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is recommended due to its faster execution time while still providing the same optimal solution as the other solvers.

### Business Interpretation
**Overall Strategy**: The optimal total expected return on investment is $80,000, which is the maximum achievable given the constraints.
**Objective Value Meaning**: The optimal objective value of $80,000 represents the maximum expected return on investment achievable with the given budget and individual investment limits.
**Resource Allocation Summary**: Resources should be allocated to entrepreneurs in a way that maximizes the total expected return, ensuring no single entrepreneur receives more than $200,000 and the total investment does not exceed $1,000,000.
**Implementation Recommendations**: Allocate funds to entrepreneurs based on their return rates, ensuring compliance with individual and total budget constraints. Use Gurobipy for future optimizations due to its efficiency.