# Complete Optimization Problem and Solution: culture_company

## 1. Problem Context and Goals

### Context  
The culture company is focused on strategically investing in book clubs and movies to enhance its cultural impact. The decision-making process involves determining the optimal investment amounts for each book club and movie. These investments are represented by continuous variables: x for book clubs and y for movies. The primary objective is to maximize the cultural impact, which is calculated as a weighted sum of the equity shareholding in each book club and movie. The company must operate within a defined budget, which serves as a constraint on the total investment. The business configuration includes a total budget available for investment, which acts as a constraint bound in the optimization model, and the investment cost for each book club, which is used in constraint calculations. The company aims to make precise operational decisions that align with linear formulations, ensuring that resource limitations are addressed through expected linear constraints. The business configuration parameters, such as the total budget and investment costs, are integral to this process.

### Goals  
The primary goal of the optimization is to maximize the cultural impact of the company's investments. This is achieved by optimizing the total cultural impact, which is the sum of the contributions from the equity shareholding in each book club and movie. The success of this optimization is measured by the alignment with expected coefficient sources, ensuring that the cultural impact is maximized through strategic investment decisions. The optimization goal is clearly defined in natural language, focusing on maximizing the cultural impact without the use of mathematical formulas or symbolic notation.

## 2. Constraints    

The company must adhere to a budget constraint that limits the total investment in book clubs and movies. The expected constraint is that the sum of the investment cost per book club multiplied by the investment decision for book clubs, plus the investment decision for movies, must not exceed the total budget. This constraint is expressed in business terms that naturally lead to linear mathematical forms, avoiding any nonlinear relationships such as variable products or divisions.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 1 Database Schema
-- Objective: Schema changes include creating new tables for decision variables and constraint bounds, modifying existing tables to include missing data, and updating business configuration logic for scalar parameters and formulas.

CREATE TABLE Group_Equity_Shareholding (
  book_club_id INTEGER,
  movie_id INTEGER,
  equity_shareholding FLOAT
);

CREATE TABLE Decision_Variables (
  x FLOAT,
  y FLOAT
);

CREATE TABLE Constraint_Bounds (
  budget_constraint FLOAT
);
```

### Data Dictionary  
The data dictionary provides a comprehensive business-oriented mapping of tables and columns to their purposes and roles in the optimization process:

- **Group_Equity_Shareholding**: This table stores the cultural impact scores for book clubs and movies. It plays a crucial role in the optimization as it provides the coefficients for the objective function. The columns include:
  - **book_club_id**: An identifier for each book club, used to map equity shareholding to book clubs.
  - **movie_id**: An identifier for each movie, used to map equity shareholding to movies.
  - **equity_shareholding**: Represents the contribution to the cultural impact score, serving as a coefficient in the objective function.

- **Decision_Variables**: This table captures the investment decisions for optimization. It includes:
  - **x**: Represents the investment decision in book clubs, serving as a decision variable.
  - **y**: Represents the investment decision in movies, serving as a decision variable.

- **Constraint_Bounds**: This table contains the budget constraints for optimization. It includes:
  - **budget_constraint**: Represents the total budget constraint for investments, acting as a constraint bound in the optimization model.

### Current Stored Values  
```sql
-- Iteration 1 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on typical investment sizes for cultural projects and realistic equity shareholdings that reflect varying levels of cultural impact.

-- Realistic data for Group_Equity_Shareholding
INSERT INTO Group_Equity_Shareholding (book_club_id, movie_id, equity_shareholding) VALUES (1, None, 0.6);
INSERT INTO Group_Equity_Shareholding (book_club_id, movie_id, equity_shareholding) VALUES (2, None, 0.8);
INSERT INTO Group_Equity_Shareholding (book_club_id, movie_id, equity_shareholding) VALUES (3, None, 0.5);
INSERT INTO Group_Equity_Shareholding (book_club_id, movie_id, equity_shareholding) VALUES (None, 1, 0.7);
INSERT INTO Group_Equity_Shareholding (book_club_id, movie_id, equity_shareholding) VALUES (None, 2, 0.9);
INSERT INTO Group_Equity_Shareholding (book_club_id, movie_id, equity_shareholding) VALUES (None, 3, 0.4);

-- Realistic data for Decision_Variables
INSERT INTO Decision_Variables (x, y) VALUES (20000, None);
INSERT INTO Decision_Variables (x, y) VALUES (30000, None);
INSERT INTO Decision_Variables (x, y) VALUES (15000, None);
INSERT INTO Decision_Variables (x, y) VALUES (None, 25000);
INSERT INTO Decision_Variables (x, y) VALUES (None, 35000);
INSERT INTO Decision_Variables (x, y) VALUES (None, 10000);

-- Realistic data for Constraint_Bounds
INSERT INTO Constraint_Bounds (budget_constraint) VALUES (1000000);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- \( x_1, x_2, x_3 \): Investment amounts in book clubs 1, 2, and 3, respectively (continuous variables).
- \( y_1, y_2, y_3 \): Investment amounts in movies 1, 2, and 3, respectively (continuous variables).

#### Objective Function
Maximize the total cultural impact:
\[ 
\text{Maximize } Z = 0.6x_1 + 0.8x_2 + 0.5x_3 + 0.7y_1 + 0.9y_2 + 0.4y_3 
\]

Data Source Verification:
- Coefficients for \( x_1, x_2, x_3 \) are from `Group_Equity_Shareholding.equity_shareholding` for book clubs.
- Coefficients for \( y_1, y_2, y_3 \) are from `Group_Equity_Shareholding.equity_shareholding` for movies.

#### Constraints
1. Budget Constraint:
\[ 
x_1 + x_2 + x_3 + y_1 + y_2 + y_3 \leq 1000000 
\]

Data Source Verification:
- The budget constraint value is from `Constraint_Bounds.budget_constraint`.

2. Non-negativity Constraints:
\[ 
x_1, x_2, x_3, y_1, y_2, y_3 \geq 0 
\]

This formulation provides a linear optimization model that can be solved using linear programming techniques to determine the optimal investment amounts in book clubs and movies to maximize cultural impact while adhering to the budget constraint.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_cultural_impact():
    """Optimize investment in book clubs and movies to maximize cultural impact."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("culture_company")
    
    # Coefficients for the objective function
    book_club_coeffs = [0.6, 0.8, 0.5]
    movie_coeffs = [0.7, 0.9, 0.4]
    
    # Budget constraint
    budget_constraint = 1000000
    
    # Validate array lengths
    n_book_clubs = len(book_club_coeffs)
    n_movies = len(movie_coeffs)
    assert n_book_clubs == 3, "Expected 3 book clubs"
    assert n_movies == 3, "Expected 3 movies"
    
    # 2. VARIABLES
    # Investment amounts in book clubs
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i+1}", lb=0) 
         for i in range(n_book_clubs)}
    
    # Investment amounts in movies
    y = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"y_{i+1}", lb=0) 
         for i in range(n_movies)}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total cultural impact
    model.setObjective(
        gp.quicksum(book_club_coeffs[i] * x[i] for i in range(n_book_clubs)) +
        gp.quicksum(movie_coeffs[i] * y[i] for i in range(n_movies)), 
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    # Budget constraint
    model.addConstr(
        gp.quicksum(x[i] for i in range(n_book_clubs)) +
        gp.quicksum(y[i] for i in range(n_movies)) <= budget_constraint, 
        name="budget_constraint"
    )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_book_clubs):
            if x[i].x > 1e-6:
                print(f"x[{i+1}] = {x[i].x:.3f}")
        for i in range(n_movies):
            if y[i].x > 1e-6:
                print(f"y[{i+1}] = {y[i].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_cultural_impact()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 900000.0
**Execution Time**: 0.62 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution quickly with the shortest execution time, indicating efficient performance and reliability.

## 6. DOCplex Implementation

```python
# Complete DOCPLEX implementation

from docplex.mp.model import Model

def culture_company_optimization():
    """Optimization for Culture Company to maximize cultural impact"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="culture_company")
    
    # Coefficients for the objective function from Group_Equity_Shareholding
    book_club_coeffs = [0.6, 0.8, 0.5]
    movie_coeffs = [0.7, 0.9, 0.4]
    
    # Budget constraint from Constraint_Bounds
    budget_constraint = 1000000
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(book_club_coeffs) == len(movie_coeffs) == 3, "Array length mismatch"
    safe_range = range(min(len(book_club_coeffs), len(movie_coeffs)))  # Safe indexing
    
    # 2. VARIABLES
    # Investment amounts in book clubs and movies
    x = {i: mdl.continuous_var(name=f"x_{i+1}", lb=0) for i in safe_range}
    y = {i: mdl.continuous_var(name=f"y_{i+1}", lb=0) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total cultural impact
    objective = mdl.sum(book_club_coeffs[i] * x[i] + movie_coeffs[i] * y[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Budget constraint
    total_investment = mdl.sum(x[i] + y[i] for i in safe_range)
    mdl.add_constraint(total_investment <= budget_constraint, ctname="budget_constraint")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range:
            x_value = solution.get_value(x[i])
            y_value = solution.get_value(y[i])
            if x_value > 1e-6:
                print(f"x[{i+1}] = {x_value:.3f}")
            if y_value > 1e-6:
                print(f"y[{i+1}] = {y_value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
culture_company_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 900000.0
**Execution Time**: 4.10 seconds
**Reliability**: high
**Analysis**: DOCplex also found an optimal solution, albeit with a longer execution time compared to Gurobipy, but still reliable.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def culture_company_optimization():
    """Optimize investment in book clubs and movies to maximize cultural impact."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Coefficients for the objective function
    book_club_coeffs = [0.6, 0.8, 0.5]
    movie_coeffs = [0.7, 0.9, 0.4]
    
    # Budget constraint
    budget_constraint = 1000000
    
    # Validate array lengths
    n_book_clubs = len(book_club_coeffs)
    n_movies = len(movie_coeffs)
    assert n_book_clubs == 3 and n_movies == 3, "Array length mismatch for coefficients"
    
    # 3. SETS
    model.B = pyo.RangeSet(1, n_book_clubs)  # Book clubs
    model.M = pyo.RangeSet(1, n_movies)      # Movies
    
    # 4. PARAMETERS
    model.book_club_coeff = pyo.Param(model.B, initialize={i+1: book_club_coeffs[i] for i in range(n_book_clubs)})
    model.movie_coeff = pyo.Param(model.M, initialize={i+1: movie_coeffs[i] for i in range(n_movies)})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.B, within=pyo.NonNegativeReals)  # Investment in book clubs
    model.y = pyo.Var(model.M, within=pyo.NonNegativeReals)  # Investment in movies
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.book_club_coeff[i] * model.x[i] for i in model.B) + \
               sum(model.movie_coeff[j] * model.y[j] for j in model.M)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    def budget_rule(model):
        return sum(model.x[i] for i in model.B) + sum(model.y[j] for j in model.M) <= budget_constraint
    model.budget_constraint = pyo.Constraint(rule=budget_rule)
    
    # 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):.3f}")
        
        # Extract variable values
        print("\nInvestment values:")
        for i in model.B:
            x_val = pyo.value(model.x[i])
            if x_val > 1e-6:  # Only print non-zero values
                print(f"Investment in book club {i}: {x_val:.3f}")
        
        for j in model.M:
            y_val = pyo.value(model.y[j])
            if y_val > 1e-6:  # Only print non-zero values
                print(f"Investment in movie {j}: {y_val:.3f}")
        
    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

# Run the optimization
culture_company_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 900000.0
**Execution Time**: 2.44 seconds
**Reliability**: high
**Analysis**: Pyomo achieved the optimal solution with a moderate execution time, demonstrating reliability and consistency with other solvers.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 900000.00 | 0.62s | N/A | N/A |
| Docplex | OPTIMAL | 900000.00 | 4.10s | N/A | N/A |
| Pyomo | OPTIMAL | 900000.00 | 2.44s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 900000.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is preferred due to its efficient execution time and consistent results with other solvers.

### Business Interpretation
**Overall Strategy**: The optimal investment strategy maximizes cultural impact within the budget constraints.
**Objective Value Meaning**: The optimal objective value of 900000.0 represents the maximum achievable cultural impact given the budget constraint.
**Resource Allocation Summary**: Allocate resources to investments in book clubs and movies to achieve the highest cultural impact.
**Implementation Recommendations**: Implement the investment strategy using the recommended solver (Gurobipy) for efficient and reliable results.