# Complete Optimization Problem and Solution: manufactory_1

## 1. Problem Context and Goals

### Context  
A manufacturing company is focused on optimizing its product portfolio to maximize total revenue while adhering to operational constraints. The company must determine the number of units to produce for each product, ensuring that production costs do not exceed the available budget, that demand for each product is fully met, and that production does not exceed capacity limits.  

The company has a predefined budget for production, which serves as an upper limit for the total production costs. The production cost for each product is calculated by multiplying the cost per unit by the number of units produced. The company also has specific demand requirements for each product, which must be fulfilled, and production capacity limits that cannot be exceeded.  

The operational parameters include the price of each product, the cost per unit for production, the demand for each product, and the production capacity for each product. These parameters are used to guide the decision-making process, ensuring that the optimization aligns with the company’s financial and operational goals.  

### Goals  
The primary goal of this optimization is to maximize the total revenue generated from the production of all products. Revenue is calculated by multiplying the price of each product by the number of units produced. Success is measured by achieving the highest possible revenue while staying within the constraints of the production budget, meeting all product demand, and not exceeding production capacity.  

## 2. Constraints  

The optimization must adhere to the following constraints:  
1. **Total Production Cost Constraint**: The total cost of producing all products must not exceed the available budget. The total production cost is calculated by summing the cost per unit multiplied by the number of units produced for each product.  
2. **Demand Fulfillment Constraint**: The number of units produced for each product must be at least equal to the demand for that product. This ensures that all customer orders are fulfilled.  
3. **Production Capacity Constraint**: The number of units produced for each product must not exceed the production capacity for that product. This ensures that the company does not overextend its manufacturing capabilities.  

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 1 Database Schema
-- Objective: Schema changes include creating new tables for production costs, demand, and capacity, and updating business configuration logic with budget and formulas. Missing mappings for budget, demand, and capacity are addressed.

CREATE TABLE Products (
  Price FLOAT
);

CREATE TABLE ProductionCosts (
  CostValue FLOAT
);

CREATE TABLE Demand (
  DemandValue INTEGER
);

CREATE TABLE Capacity (
  CapacityValue INTEGER
);

CREATE TABLE ProductionPlan (
  UnitsProduced FLOAT
);
```

### Data Dictionary  
- **Products**: Contains the price of each product, which is used to calculate revenue in the optimization objective.  
  - **Price**: The price of the product, serving as a coefficient in the revenue calculation.  
- **ProductionCosts**: Contains the cost per unit for producing each product, used to calculate total production costs.  
  - **CostValue**: The cost per unit for production, serving as a coefficient in the total production cost constraint.  
- **Demand**: Contains the demand for each product, which sets the minimum number of units that must be produced.  
  - **DemandValue**: The demand for the product, serving as the lower bound in the demand fulfillment constraint.  
- **Capacity**: Contains the production capacity for each product, which sets the maximum number of units that can be produced.  
  - **CapacityValue**: The production capacity for the product, serving as the upper bound in the production capacity constraint.  
- **ProductionPlan**: Contains the number of units produced for each product, which are the decision variables in the optimization model.  
  - **UnitsProduced**: The number of units produced for the product, representing the decision variable 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 manufacturing scenarios, ensuring that production costs, demand, and capacity are realistic and aligned with the business context. The budget was set to ensure it covers the production costs while leaving room for optimization.

-- Realistic data for Products
INSERT INTO Products (Price) VALUES (10.5);
INSERT INTO Products (Price) VALUES (15.0);
INSERT INTO Products (Price) VALUES (20.0);

-- Realistic data for ProductionCosts
INSERT INTO ProductionCosts (CostValue) VALUES (2.5);
INSERT INTO ProductionCosts (CostValue) VALUES (3.0);
INSERT INTO ProductionCosts (CostValue) VALUES (4.0);

-- Realistic data for Demand
INSERT INTO Demand (DemandValue) VALUES (100);
INSERT INTO Demand (DemandValue) VALUES (150);
INSERT INTO Demand (DemandValue) VALUES (200);

-- Realistic data for Capacity
INSERT INTO Capacity (CapacityValue) VALUES (500);
INSERT INTO Capacity (CapacityValue) VALUES (600);
INSERT INTO Capacity (CapacityValue) VALUES (700);

-- Realistic data for ProductionPlan
INSERT INTO ProductionPlan (UnitsProduced) VALUES (50.0);
INSERT INTO ProductionPlan (UnitsProduced) VALUES (75.0);
INSERT INTO ProductionPlan (UnitsProduced) VALUES (100.0);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_i \) represent the number of units produced for product \( i \), where \( i = 1, 2, 3 \).  
  \( x_i \) is a continuous variable (LP).

#### Objective Function
Maximize the total revenue:  
\[
\text{Maximize } Z = 10.5x_1 + 15.0x_2 + 20.0x_3
\]

#### Constraints
1. **Total Production Cost Constraint**:  
   The total production cost must not exceed the available budget.  
   \[
   2.5x_1 + 3.0x_2 + 4.0x_3 \leq \text{Budget}
   \]  
   (Assume the budget is a predefined constant, e.g., 5000, based on realistic scenarios.)

2. **Demand Fulfillment Constraint**:  
   The number of units produced must meet or exceed the demand for each product.  
   \[
   x_1 \geq 100, \quad x_2 \geq 150, \quad x_3 \geq 200
   \]

3. **Production Capacity Constraint**:  
   The number of units produced must not exceed the production capacity for each product.  
   \[
   x_1 \leq 500, \quad x_2 \leq 600, \quad x_3 \leq 700
   \]

#### Data Source Verification
- **Objective Function Coefficients**:  
  \( 10.5, 15.0, 20.0 \) come from `Products.Price`.  
- **Total Production Cost Coefficients**:  
  \( 2.5, 3.0, 4.0 \) come from `ProductionCosts.CostValue`.  
- **Demand Fulfillment Constants**:  
  \( 100, 150, 200 \) come from `Demand.DemandValue`.  
- **Production Capacity Constants**:  
  \( 500, 600, 700 \) come from `Capacity.CapacityValue`.  

This is a complete, immediately solvable LINEAR mathematical model with all numerical coefficients derived from the provided data.

## 5. Gurobipy Implementation

```python
#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Manufacturing Optimization Problem
"""

import gurobipy as gp
from gurobipy import GRB

def manufacturing_optimization():
    """Optimize product portfolio to maximize revenue while adhering to constraints."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("manufactory_1")
    
    # Data from the problem
    prices = [10.5, 15.0, 20.0]
    costs = [2.5, 3.0, 4.0]
    demands = [100, 150, 200]
    capacities = [500, 600, 700]
    budget = 5000
    
    # Number of products
    n_products = len(prices)
    
    # CRITICAL: Validate array lengths before loops
    assert len(prices) == len(costs) == len(demands) == len(capacities) == n_products, "Array length mismatch"
    
    # 2. VARIABLES
    # Decision variables: number of units produced for each product
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=0) for i in range(n_products)}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total revenue
    model.setObjective(gp.quicksum(prices[i] * x[i] for i in range(n_products)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Total Production Cost Constraint
    model.addConstr(gp.quicksum(costs[i] * x[i] for i in range(n_products)) <= budget, name="total_cost")
    
    # Demand Fulfillment Constraints
    for i in range(n_products):
        model.addConstr(x[i] >= demands[i], name=f"demand_{i}")
    
    # Production Capacity Constraints
    for i in range(n_products):
        model.addConstr(x[i] <= capacities[i], name=f"capacity_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_products):
            print(f"x[{i}] = {x[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
if __name__ == "__main__":
    manufacturing_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 24680.0
**Execution Time**: 0.18 seconds
**Reliability**: high
**Analysis**: Gurobipy achieved the optimal solution with the fastest execution time, indicating high efficiency and reliability.

## 6. DOCplex Implementation

```python
#!/usr/bin/env python3
"""
DOCPLEX Implementation for Manufacturing Optimization Problem
"""

from docplex.mp.model import Model

def manufacturing_optimization():
    """Optimize product portfolio to maximize revenue under constraints."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="manufactory_1")
    
    # Data from the problem statement
    prices = [10.5, 15.0, 20.0]
    costs = [2.5, 3.0, 4.0]
    demands = [100, 150, 200]
    capacities = [500, 600, 700]
    budget = 5000  # Predefined budget
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(prices) == len(costs) == len(demands) == len(capacities), "Array length mismatch"
    safe_range = range(min(len(prices), len(costs), len(demands), len(capacities)))  # Safe indexing
    
    # 2. VARIABLES
    # Decision variables: number of units produced for each product
    x = {i: mdl.continuous_var(name=f"x_{i}", lb=0) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total revenue
    revenue = mdl.sum(prices[i] * x[i] for i in safe_range)
    mdl.maximize(revenue)
    
    # 4. CONSTRAINTS
    
    # Total Production Cost Constraint
    total_cost = mdl.sum(costs[i] * x[i] for i in safe_range)
    mdl.add_constraint(total_cost <= budget, ctname="total_cost_constraint")
    
    # Demand Fulfillment Constraint
    for i in safe_range:
        mdl.add_constraint(x[i] >= demands[i], ctname=f"demand_{i}")
    
    # Production Capacity Constraint
    for i in safe_range:
        mdl.add_constraint(x[i] <= capacities[i], ctname=f"capacity_{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"x[{i}] = {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

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

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 24680.0
**Execution Time**: 1.11 seconds
**Reliability**: high
**Analysis**: DOCplex also achieved the optimal solution but with a significantly longer execution time compared to Gurobipy.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def manufactory_optimization():
    """Optimize product portfolio to maximize revenue while adhering to constraints."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Define the number of products
    n_products = 3
    
    # Define the data from the problem
    prices = [10.5, 15.0, 20.0]
    costs = [2.5, 3.0, 4.0]
    demands = [100, 150, 200]
    capacities = [500, 600, 700]
    budget = 5000  # Assume a predefined budget
    
    # CRITICAL: Validate array lengths before indexing
    assert len(prices) == len(costs) == len(demands) == len(capacities) == n_products, "Array length mismatch"
    
    # 3. SETS (Pyomo way to define indices)
    model.I = pyo.RangeSet(1, n_products)  # 1-based indexing
    
    # 4. PARAMETERS (data containers)
    model.price = pyo.Param(model.I, initialize={i+1: prices[i] for i in range(n_products)})
    model.cost = pyo.Param(model.I, initialize={i+1: costs[i] for i in range(n_products)})
    model.demand = pyo.Param(model.I, initialize={i+1: demands[i] for i in range(n_products)})
    model.capacity = pyo.Param(model.I, initialize={i+1: capacities[i] for i in range(n_products)})
    model.budget = pyo.Param(initialize=budget)
    
    # 5. VARIABLES
    # Continuous variables for units produced
    model.x = pyo.Var(model.I, within=pyo.NonNegativeReals)
    
    # 6. OBJECTIVE FUNCTION
    # Maximize total revenue
    def obj_rule(model):
        return sum(model.price[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    
    # Total Production Cost Constraint
    def total_cost_rule(model):
        return sum(model.cost[i] * model.x[i] for i in model.I) <= model.budget
    model.total_cost_constraint = pyo.Constraint(rule=total_cost_rule)
    
    # Demand Fulfillment Constraint
    def demand_rule(model, i):
        return model.x[i] >= model.demand[i]
    model.demand_constraint = pyo.Constraint(model.I, rule=demand_rule)
    
    # Production Capacity Constraint
    def capacity_rule(model, i):
        return model.x[i] <= model.capacity[i]
    model.capacity_constraint = pyo.Constraint(model.I, rule=capacity_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)}")
        
        # Extract variable values
        print("\nVariable values:")
        for i in model.I:
            x_val = pyo.value(model.x[i])
            if x_val > 1e-6:  # Only print non-zero values
                print(f"x[{i}] = {x_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

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

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 24680.0
**Execution Time**: 0.92 seconds
**Reliability**: high
**Analysis**: Pyomo achieved the optimal solution with an execution time between Gurobipy and DOCplex, indicating moderate efficiency.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 24680.00 | 0.18s | N/A | N/A |
| Docplex | OPTIMAL | 24680.00 | 1.11s | N/A | N/A |
| Pyomo | OPTIMAL | 24680.00 | 0.92s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 24680.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is recommended due to its optimal solution and significantly faster execution time compared to DOCplex and Pyomo.

### Business Interpretation
**Overall Strategy**: The optimal solution maximizes total revenue while adhering to budget, demand, and capacity constraints.
**Objective Value Meaning**: The optimal total revenue of 24680.0 indicates the maximum achievable revenue given the constraints.
**Resource Allocation Summary**: Resources should be allocated to produce the optimal number of units for each product, ensuring budget, demand, and capacity constraints are met.
**Implementation Recommendations**: Implement the production plan as per the optimal solution, ensuring continuous monitoring of budget and capacity to maintain optimal revenue.