# Complete Optimization Problem and Solution: phone_1

## 1. Problem Context and Goals

### Context  
A mobile phone company is focused on optimizing the production of its various phone models to achieve maximum profitability. The decision at hand involves determining the number of units to produce for each phone model, denoted as `units_produced[i]`, where `i` represents each distinct phone model. The primary objective is to maximize the total profit, which is calculated as the sum of the profit per unit for each model multiplied by the number of units produced for that model.

The company operates under specific resource constraints, which include the total available RAM, ROM, and screen resources. These constraints are critical as they define the maximum capacity for production. The total available RAM, ROM, and screen resources are scalar parameters that guide the production limits. The business configuration includes:

- Total available RAM for production, which serves as the constraint bound for RAM usage.
- Total available ROM for production, which serves as the constraint bound for ROM usage.
- Total available screen resources for production, which serves as the constraint bound for screen usage.

The operational parameters are aligned with a linear objective, ensuring that the decision-making process is straightforward and adheres to linear relationships. The focus is on precise operational decision-making that leads to linear formulations, avoiding any scenarios that would require nonlinear relationships such as variable products or divisions. The business configuration parameters are referenced appropriately to ensure a consistent and realistic production plan.

### Goals  
The primary goal of the optimization process is to maximize the total profit from the production of mobile phone models. This involves determining the optimal number of units to produce for each model to achieve the highest possible profit. The metric to optimize is the total profit, which is calculated as the sum of the profit per unit for each phone model multiplied by the number of units produced for that model. Success is measured by the alignment of production decisions with the expected profit coefficients, ensuring that the optimization goal is clearly defined and achievable within the given resource constraints.

## 2. Constraints    

The production process is subject to several constraints that ensure the efficient use of available resources. These constraints are described in business terms that naturally lead to linear mathematical forms:

- The total RAM required for the production of all phone models must not exceed the total available RAM. This constraint ensures that the production plan is feasible given the RAM resources.
- The total ROM required for the production of all phone models must not exceed the total available ROM. This constraint ensures that the production plan is feasible given the ROM resources.
- The total screen resources required for the production of all phone models must not exceed the total available screen resources. This constraint ensures that the production plan is feasible given the screen resources.

These constraints are critical in guiding the production decisions and ensuring that the optimization process remains within the bounds of available resources.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 1 Database Schema
-- Objective: Schema changes include creating new tables for decision variables, objective coefficients, and constraint bounds, and moving scalar parameters to configuration logic. This addresses the OR expert's mapping gaps and missing data requirements.

CREATE TABLE PhoneModels (
  model_id INTEGER,
  RAM_required INTEGER,
  ROM_required INTEGER,
  screen_required INTEGER
);

CREATE TABLE ObjectiveCoefficients (
  model_id INTEGER,
  profit_per_unit FLOAT
);

CREATE TABLE DecisionVariables (
  model_id INTEGER,
  units_produced INTEGER
);
```

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

- **PhoneModels**: This table contains details of each phone model, including the resource requirements for RAM, ROM, and screen resources. It plays a crucial role in the optimization process by providing the necessary data for constraint calculations.
  - **model_id**: A unique identifier for each phone model, used to reference decision variables and coefficients.
  - **RAM_required**: The amount of RAM required per unit of the phone model, used in the RAM constraint calculation.
  - **ROM_required**: The amount of ROM required per unit of the phone model, used in the ROM constraint calculation.
  - **screen_required**: The screen resources required per unit of the phone model, used in the screen constraint calculation.

- **ObjectiveCoefficients**: This table contains the profit per unit for each phone model, serving as the objective coefficients in the optimization process.
  - **model_id**: A reference to the phone model, linking profit to the specific model.
  - **profit_per_unit**: The profit earned per unit of the phone model, used as a coefficient in the objective function.

- **DecisionVariables**: This table records the number of units produced for each phone model, representing the decision variables in the optimization model.
  - **model_id**: A reference to the phone model, linking production units to the specific model.
  - **units_produced**: The number of units produced for the phone model, serving as 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 resource requirements and profit margins for different phone models, ensuring that the total available resources are sufficient to produce a meaningful number of units for each model.

-- Realistic data for PhoneModels
INSERT INTO PhoneModels (model_id, RAM_required, ROM_required, screen_required) VALUES (1, 4, 16, 1);
INSERT INTO PhoneModels (model_id, RAM_required, ROM_required, screen_required) VALUES (2, 8, 32, 2);
INSERT INTO PhoneModels (model_id, RAM_required, ROM_required, screen_required) VALUES (3, 16, 64, 3);

-- Realistic data for ObjectiveCoefficients
INSERT INTO ObjectiveCoefficients (model_id, profit_per_unit) VALUES (1, 50.0);
INSERT INTO ObjectiveCoefficients (model_id, profit_per_unit) VALUES (2, 75.0);
INSERT INTO ObjectiveCoefficients (model_id, profit_per_unit) VALUES (3, 100.0);

-- Realistic data for DecisionVariables
INSERT INTO DecisionVariables (model_id, units_produced) VALUES (1, 2000);
INSERT INTO DecisionVariables (model_id, units_produced) VALUES (2, 1000);
INSERT INTO DecisionVariables (model_id, units_produced) VALUES (3, 500);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_1 \) be the number of units produced for phone model 1.
- Let \( x_2 \) be the number of units produced for phone model 2.
- Let \( x_3 \) be the number of units produced for phone model 3.

#### Objective Function
Maximize the total profit:
\[ \text{Maximize } Z = 50x_1 + 75x_2 + 100x_3 \]

Data Source Verification:
- Coefficients 50, 75, and 100 are from `ObjectiveCoefficients.profit_per_unit` for models 1, 2, and 3, respectively.

#### Constraints
1. **RAM Constraint**: The total RAM used must not exceed the available RAM.
   \[ 4x_1 + 8x_2 + 16x_3 \leq \text{Total Available RAM} \]

2. **ROM Constraint**: The total ROM used must not exceed the available ROM.
   \[ 16x_1 + 32x_2 + 64x_3 \leq \text{Total Available ROM} \]

3. **Screen Constraint**: The total screen resources used must not exceed the available screen resources.
   \[ 1x_1 + 2x_2 + 3x_3 \leq \text{Total Available Screen Resources} \]

Data Source Verification:
- Coefficients for RAM, ROM, and screen requirements are from `PhoneModels.RAM_required`, `PhoneModels.ROM_required`, and `PhoneModels.screen_required` for models 1, 2, and 3, respectively.
- The constants for the right-hand side of the constraints are from business configuration parameters: Total Available RAM, Total Available ROM, and Total Available Screen Resources.

#### Non-negativity Constraints
- \( x_1, x_2, x_3 \geq 0 \)

This linear programming model can be solved using standard optimization software to determine the optimal production quantities \( x_1, x_2, \) and \( x_3 \) that maximize the total profit while adhering to the resource constraints.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_phone_production(total_ram, total_rom, total_screen):
    """Optimize phone production to maximize profit given resource constraints."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("phone_production")
    
    # Data from the database
    model_ids = [1, 2, 3]
    ram_requirements = [4, 8, 16]
    rom_requirements = [16, 32, 64]
    screen_requirements = [1, 2, 3]
    profit_per_unit = [50.0, 75.0, 100.0]
    
    # CRITICAL: Validate array lengths before loops
    assert len(model_ids) == len(ram_requirements) == len(rom_requirements) == len(screen_requirements) == len(profit_per_unit), "Array length mismatch"
    
    # 2. VARIABLES
    # Variable dictionaries for units produced
    units_produced = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=0) for i in model_ids}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total profit
    model.setObjective(gp.quicksum(profit_per_unit[i-1] * units_produced[i] for i in model_ids), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # RAM Constraint
    model.addConstr(gp.quicksum(ram_requirements[i-1] * units_produced[i] for i in model_ids) <= total_ram, name="RAM_constraint")
    
    # ROM Constraint
    model.addConstr(gp.quicksum(rom_requirements[i-1] * units_produced[i] for i in model_ids) <= total_rom, name="ROM_constraint")
    
    # Screen Constraint
    model.addConstr(gp.quicksum(screen_requirements[i-1] * units_produced[i] for i in model_ids) <= total_screen, name="Screen_constraint")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in model_ids:
            if units_produced[i].x > 1e-6:
                print(f"Units produced for model {i}: {units_produced[i].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Example usage with total available resources
total_available_ram = 10000  # Example value
total_available_rom = 20000  # Example value
total_available_screen = 5000  # Example value

optimize_phone_production(total_available_ram, total_available_rom, total_available_screen)
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 62500.0
**Execution Time**: 0.17 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 optimize_phone_production(total_ram, total_rom, total_screen):
    """Optimize phone production to maximize profit given resource constraints."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="phone_production")
    
    # Data from the problem context
    model_ids = [1, 2, 3]
    ram_requirements = [4, 8, 16]
    rom_requirements = [16, 32, 64]
    screen_requirements = [1, 2, 3]
    profit_per_unit = [50.0, 75.0, 100.0]
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(model_ids) == len(ram_requirements) == len(rom_requirements) == len(screen_requirements) == len(profit_per_unit), "Array length mismatch"
    safe_range = range(len(model_ids))  # Safe indexing
    
    # 2. VARIABLES
    units_produced = {i: mdl.continuous_var(name=f"x_{i}", lb=0) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total profit
    total_profit = mdl.sum(profit_per_unit[i] * units_produced[i] for i in safe_range)
    mdl.maximize(total_profit)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # RAM Constraint
    total_ram_usage = mdl.sum(ram_requirements[i] * units_produced[i] for i in safe_range)
    mdl.add_constraint(total_ram_usage <= total_ram, ctname="ram_constraint")
    
    # ROM Constraint
    total_rom_usage = mdl.sum(rom_requirements[i] * units_produced[i] for i in safe_range)
    mdl.add_constraint(total_rom_usage <= total_rom, ctname="rom_constraint")
    
    # Screen Constraint
    total_screen_usage = mdl.sum(screen_requirements[i] * units_produced[i] for i in safe_range)
    mdl.add_constraint(total_screen_usage <= total_screen, ctname="screen_constraint")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range:
            value = solution.get_value(units_produced[i])
            if value > 1e-6:
                print(f"Units produced for model {model_ids[i]}: {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Example usage with total available resources
optimize_phone_production(total_ram=10000, total_rom=20000, total_screen=5000)
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 62500.0
**Execution Time**: 1.33 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 phone_optimization():
    """Optimize phone production for maximum profit"""

    # 1. MODEL CREATION
    model = pyo.ConcreteModel()

    # 2. DATA SETUP
    # Data from the problem statement
    n_models = 3
    profits = [50.0, 75.0, 100.0]
    ram_requirements = [4, 8, 16]
    rom_requirements = [16, 32, 64]
    screen_requirements = [1, 2, 3]
    
    # Total available resources
    total_ram = 10000  # Example value
    total_rom = 20000  # Example value
    total_screen = 5000  # Example value

    # CRITICAL: Validate array lengths before indexing
    assert len(profits) == len(ram_requirements) == len(rom_requirements) == len(screen_requirements) == n_models, "Array length mismatch"

    # 3. SETS
    model.I = pyo.RangeSet(1, n_models)  # 1-based indexing

    # 4. PARAMETERS
    model.profit = pyo.Param(model.I, initialize={i+1: profits[i] for i in range(n_models)})
    model.ram = pyo.Param(model.I, initialize={i+1: ram_requirements[i] for i in range(n_models)})
    model.rom = pyo.Param(model.I, initialize={i+1: rom_requirements[i] for i in range(n_models)})
    model.screen = pyo.Param(model.I, initialize={i+1: screen_requirements[i] for i in range(n_models)})

    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.NonNegativeReals)

    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.profit[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)

    # 7. CONSTRAINTS
    def ram_constraint_rule(model):
        return sum(model.ram[i] * model.x[i] for i in model.I) <= total_ram
    model.ram_constraint = pyo.Constraint(rule=ram_constraint_rule)

    def rom_constraint_rule(model):
        return sum(model.rom[i] * model.x[i] for i in model.I) <= total_rom
    model.rom_constraint = pyo.Constraint(rule=rom_constraint_rule)

    def screen_constraint_rule(model):
        return sum(model.screen[i] * model.x[i] for i in model.I) <= total_screen
    model.screen_constraint = pyo.Constraint(rule=screen_constraint_rule)

    # 8. SOLVING WITH GUROBI
    solver = SolverFactory('gurobi')

    # Solve the model
    results = solver.solve(model, tee=True)

    # 9. RESULT PROCESSING
    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

# Run the optimization
phone_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 62500.0
**Execution Time**: 0.84 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 | 62500.00 | 0.17s | N/A | N/A |
| Docplex | OPTIMAL | 62500.00 | 1.33s | N/A | N/A |
| Pyomo | OPTIMAL | 62500.00 | 0.84s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 62500.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is recommended due to its fastest execution time and high reliability, making it suitable for scenarios requiring quick decision-making.

### Business Interpretation
**Overall Strategy**: The optimal production plan maximizes profit while adhering to resource constraints, ensuring efficient use of available resources.
**Objective Value Meaning**: The optimal objective value of 62500 represents the maximum profit achievable under the given constraints.
**Resource Allocation Summary**: Resources should be allocated to maximize production of phone models based on their profit contribution and resource requirements.
**Implementation Recommendations**: Implement the production plan using Gurobipy's solution, ensuring resource constraints are monitored and adjusted as necessary to maintain optimal production levels.