# Complete Optimization Problem and Solution: flight_4

## 1. Problem Context and Goals

### Context  
The airline is focused on optimizing the allocation of its flights across various routes to maximize the total number of passengers transported. Each route has a specific passenger capacity, and the airline aims to ensure that all routes are serviced by at least one flight. The decision variable in this context is the number of flights assigned to each route, which is an integer value. The operational parameters include the total number of flights available for allocation and the maximum number of flights that can be assigned to each route. These parameters are used as constraints in the optimization model. The airline's business configuration specifies that there are a total of 12 flights available for allocation, and no more than 5 flights can be assigned to any single route. This setup ensures that the optimization problem remains linear, focusing on maximizing passenger transport without involving nonlinear relationships.

### Goals  
The primary goal of the optimization is to maximize the total number of passengers transported across all routes. This is achieved by strategically assigning flights to routes based on their passenger capacities. The success of this optimization is measured by the total number of passengers, which is calculated by summing the product of the passenger capacity of each route and the number of flights assigned to that route. The objective is clearly defined in linear terms, focusing on maximizing passenger transport while adhering to the constraints of flight availability and route capacity.

## 2. Constraints    

The optimization problem is subject to several constraints that ensure the solution is feasible and aligns with business requirements:

- The total number of flights assigned across all routes must not exceed the total number of flights available, which is 12.
- Each route can have a maximum of 5 flights assigned to it, ensuring that no single route is over-serviced.
- Every route must have at least one flight assigned to ensure that all routes are operational.

These constraints are 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 missing optimization data and updating configuration logic for scalar parameters and formulas.

CREATE TABLE routes (
  route_id INTEGER,
  passenger_capacity INTEGER
);

CREATE TABLE flights (
  route_id INTEGER,
  number_of_flights INTEGER
);
```

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

- **Routes Table**: This table stores data specific to each route, including the passenger capacity. The passenger capacity serves as a coefficient in the objective function, representing the potential number of passengers that can be transported on each route.
  - **route_id**: A unique identifier for each route, used to link route data.
  - **passenger_capacity**: The maximum number of passengers that can be accommodated on the route, used as a coefficient in the optimization objective.

- **Flights Table**: This table records the number of flights assigned to each route, which is the primary decision variable in the optimization model.
  - **route_id**: An identifier linking to the route, ensuring that flight assignments are correctly associated with their respective routes.
  - **number_of_flights**: The number of flights assigned to the route, serving as the decision variable in the optimization process.

### Current Stored Values  
```sql
-- Iteration 1 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on typical airline operations, ensuring that the number of flights and passenger capacities are realistic for a mid-sized airline.

-- Realistic data for routes
INSERT INTO routes (route_id, passenger_capacity) VALUES (1, 150);
INSERT INTO routes (route_id, passenger_capacity) VALUES (2, 200);
INSERT INTO routes (route_id, passenger_capacity) VALUES (3, 250);

-- Realistic data for flights
INSERT INTO flights (route_id, number_of_flights) VALUES (1, 3);
INSERT INTO flights (route_id, number_of_flights) VALUES (2, 4);
INSERT INTO flights (route_id, number_of_flights) VALUES (3, 5);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_1 \) be the number of flights assigned to route 1.
- Let \( x_2 \) be the number of flights assigned to route 2.
- Let \( x_3 \) be the number of flights assigned to route 3.

These decision variables are integers representing the number of flights allocated to each route.

#### Objective Function
Maximize the total number of passengers transported:

\[
\text{Maximize } Z = 150x_1 + 200x_2 + 250x_3
\]

**Data Source Verification:**
- Coefficient 150 from `routes.passenger_capacity` for route 1.
- Coefficient 200 from `routes.passenger_capacity` for route 2.
- Coefficient 250 from `routes.passenger_capacity` for route 3.

#### Constraints
1. Total number of flights assigned across all routes must not exceed 12:

\[
x_1 + x_2 + x_3 \leq 12
\]

2. Each route can have a maximum of 5 flights assigned:

\[
x_1 \leq 5
\]
\[
x_2 \leq 5
\]
\[
x_3 \leq 5
\]

3. Each route must have at least one flight assigned:

\[
x_1 \geq 1
\]
\[
x_2 \geq 1
\]
\[
x_3 \geq 1
\]

4. Non-negativity and integer constraints:

\[
x_1, x_2, x_3 \in \mathbb{Z}^+ 
\]

**Data Source Verification:**
- Total flights constraint (12) from business configuration.
- Maximum flights per route (5) from business configuration.
- Minimum flights per route (1) from business requirement.

This linear model is ready to be solved using a linear or mixed-integer programming solver, ensuring that the airline maximizes passenger transport while adhering to operational constraints.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_flight_allocation():
    """Optimize flight allocation to maximize passenger transport"""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("flight_4")
    
    # Data: Passenger capacities for each route
    passenger_capacities = [150, 200, 250]
    n_routes = len(passenger_capacities)
    
    # Validate array lengths
    assert n_routes == 3, "Expected 3 routes"
    
    # 2. VARIABLES
    # Decision variables: Number of flights assigned to each route
    flights = model.addVars(n_routes, vtype=GRB.INTEGER, name="flights", lb=1, ub=5)
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total number of passengers transported
    model.setObjective(gp.quicksum(passenger_capacities[i] * flights[i] for i in range(n_routes)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    # Total number of flights assigned must not exceed 12
    model.addConstr(gp.quicksum(flights[i] for i in range(n_routes)) <= 12, name="total_flights")
    
    # Each route must have at least one flight assigned (handled by lb=1 in variable definition)
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_routes):
            print(f"Route {i+1} flights: {flights[i].x:.0f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_flight_allocation()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 2550.0
**Execution Time**: 0.21 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution quickly with the expected optimal value, indicating high reliability.

## 6. DOCplex Implementation

```python
# Complete DOCPLEX implementation

from docplex.mp.model import Model

def optimize_flight_allocation():
    """Optimize flight allocation to maximize passenger transport"""

    # 1. MODEL & DATA SETUP
    mdl = Model(name="flight_4")
    
    # Data from the problem context
    passenger_capacities = [150, 200, 250]
    total_flights_available = 12
    max_flights_per_route = 5
    min_flights_per_route = 1
    
    # Validate array lengths
    n_routes = len(passenger_capacities)
    assert n_routes == 3, "Expected 3 routes based on problem data"
    safe_range = range(n_routes)  # Safe indexing
    
    # 2. VARIABLES
    # Integer variables for the number of flights assigned to each route
    flights = {i: mdl.integer_var(name=f"x_{i+1}", lb=min_flights_per_route, ub=max_flights_per_route) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total number of passengers transported
    objective = mdl.sum(passenger_capacities[i] * flights[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    # Total number of flights assigned across all routes must not exceed the total available
    total_flights = mdl.sum(flights[i] for i in safe_range)
    mdl.add_constraint(total_flights <= total_flights_available, ctname="total_flights_limit")
    
    # Each route must have at least one flight assigned (already handled by variable bounds)
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range:
            value = solution.get_value(flights[i])
            print(f"Flights assigned to route {i+1}: {value}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

    return mdl

# Run the optimization
optimize_flight_allocation()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 2550.0
**Execution Time**: 7.04 seconds
**Reliability**: high
**Analysis**: DOCplex also found the optimal solution, albeit with a longer execution time, but the result is consistent with other solvers.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def flight_optimization():
    """Optimize flight allocation to maximize passenger transport"""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Passenger capacities for each route
    passenger_capacities = [150, 200, 250]
    n_routes = len(passenger_capacities)
    
    # CRITICAL: Validate array lengths before indexing
    assert n_routes == 3, "Expected 3 routes based on problem statement"
    
    # 3. SETS
    model.R = pyo.RangeSet(1, n_routes)  # 1-based indexing for routes
    
    # 4. PARAMETERS
    model.passenger_capacity = pyo.Param(model.R, initialize={i+1: passenger_capacities[i] for i in range(n_routes)})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.R, within=pyo.NonNegativeIntegers, bounds=(1, 5))  # At least 1 flight, at most 5 flights per route
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.passenger_capacity[i] * model.x[i] for i in model.R)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    # Total number of flights constraint
    def total_flights_rule(model):
        return sum(model.x[i] for i in model.R) <= 12
    model.total_flights_constraint = pyo.Constraint(rule=total_flights_rule)
    
    # 8. SOLVING WITH GUROBI
    solver = SolverFactory('gurobi')
    
    # Solve the model
    results = solver.solve(model, tee=True)
    
    # 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("\nFlight allocations:")
        for i in model.R:
            x_val = pyo.value(model.x[i])
            print(f"Route {i}: {x_val} flights")
        
    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
flight_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 2550.0
**Execution Time**: 1.94 seconds
**Reliability**: high
**Analysis**: Pyomo achieved the optimal solution with a moderate execution time, confirming the consistency of results.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 2550.00 | 0.21s | N/A | N/A |
| Docplex | OPTIMAL | 2550.00 | 7.04s | N/A | N/A |
| Pyomo | OPTIMAL | 2550.00 | 1.94s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 2550.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy provided the optimal solution with the fastest execution time, making it the most efficient choice for this problem.

### Optimal Decision Variables
- **x_1** = 5.000
  - *Business Meaning*: Number of flights assigned to route 2, maximizing passenger capacity.
- **x_2** = 5.000
  - *Business Meaning*: Number of flights assigned to route 3, maximizing passenger capacity.
- **x_3** = 2.000
  - *Business Meaning*: Resource allocation for x_3

### Business Interpretation
**Overall Strategy**: The optimal allocation of flights maximizes passenger transport within the given constraints.
**Objective Value Meaning**: The optimal objective value of 2550 represents the maximum number of passengers that can be transported given the constraints.
**Resource Allocation Summary**: Allocate 5 flights to route 1, 5 flights to route 2, and 2 flights to route 3 to achieve optimal passenger transport.
**Implementation Recommendations**: Implement the flight allocation as per the recommended decision variables to maximize passenger transport efficiency.