## 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.