# Complete Optimization Problem and Solution: tvshow

## 1. Problem Context and Goals

### Context  
The TV network is focused on optimizing its programming schedule to enhance viewership across its various channels. The primary decision involves selecting which TV series and cartoons to air, represented by a binary decision variable indicating whether a particular show is chosen for airing. The network aims to maximize total viewership by considering the number of viewers each show attracts. The operational parameters include the total available air time for each channel, the maximum allowable content type per channel, and the minimum required viewership from specific demographic groups. These parameters are crucial constraints in the optimization model, ensuring that the schedule adheres to channel capacities and demographic targets. The business configuration provides these parameters as scalar values, reflecting realistic operational limits and goals.

### Goals  
The optimization goal is to maximize the total viewership across all channels. This is achieved by selecting the optimal combination of TV series and cartoons to air, with the metric for optimization being the total number of viewers. Success is measured by the ability to maximize this viewership while adhering to the constraints provided by the operational parameters. The goal is articulated in natural language, focusing on increasing the audience size through strategic programming decisions.

## 2. Constraints    

The constraints for this optimization problem are designed to ensure that the programming schedule is feasible and meets the network's operational requirements:

- The total air time used by the selected TV series and cartoons must not exceed the available air time for each channel. This ensures that the schedule fits within the channel's broadcasting capacity.
- The content type selected for each channel must not exceed the channel's content capacity. This constraint ensures a balanced and diverse programming lineup.
- The selected programming must achieve a minimum viewership from specific demographic groups, ensuring that the network meets its audience engagement targets.

These constraints are expressed in business terms that naturally align with linear mathematical forms, avoiding any nonlinear relationships.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 1 Database Schema
-- Objective: Schema changes include creating new tables for missing optimization data, modifying existing tables to fill mapping gaps, and moving certain parameters to configuration logic for better management.

CREATE TABLE TV_series (
  Viewers_m INTEGER,
  Air_Time INTEGER,
  Content_Type STRING,
  Demographic_Target INTEGER,
  selected BOOLEAN
);

CREATE TABLE Channel (
  Total_Available_Time INTEGER,
  Content_Capacity INTEGER
);
```

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

- **TV_series Table**: This table stores information about TV series and cartoons, crucial for scheduling optimization.
  - **Viewers_m**: Represents the number of viewers in millions for each show, serving as the objective coefficient for maximizing viewership.
  - **Air_Time**: Indicates the air time required for each show, used as a constraint for total available time.
  - **Content_Type**: Describes the type of content (e.g., series, cartoon), used to ensure content capacity constraints are met.
  - **Demographic_Target**: Specifies the target demographic viewership, ensuring that minimum demographic targets are achieved.
  - **selected**: A binary indicator of whether a show is selected to air, serving as the decision variable in the optimization.

- **Channel Table**: This table contains data about each channel's scheduling constraints.
  - **Total_Available_Time**: The total air time available for each channel, used as a constraint in the optimization model.
  - **Content_Capacity**: The maximum allowable content type per channel, ensuring a balanced programming schedule.

### Current Stored Values  
```sql
-- Iteration 1 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on typical TV network scheduling constraints and viewership data, ensuring a balance between available air time, content capacity, and demographic targets.

-- Realistic data for TV_series
INSERT INTO TV_series (Viewers_m, Air_Time, Content_Type, Demographic_Target, selected) VALUES (2, 60, 'series', 80000, False);
INSERT INTO TV_series (Viewers_m, Air_Time, Content_Type, Demographic_Target, selected) VALUES (3, 90, 'cartoon', 120000, False);
INSERT INTO TV_series (Viewers_m, Air_Time, Content_Type, Demographic_Target, selected) VALUES (1, 30, 'series', 50000, False);

-- Realistic data for Channel
INSERT INTO Channel (Total_Available_Time, Content_Capacity) VALUES (48, 20);
INSERT INTO Channel (Total_Available_Time, Content_Capacity) VALUES (72, 30);
INSERT INTO Channel (Total_Available_Time, Content_Capacity) VALUES (24, 10);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_i \) be a binary decision variable for each TV show \( i \) in the `TV_series` table, where \( x_i = 1 \) if the show is selected to air, and \( x_i = 0 \) otherwise.

#### Objective Function
Maximize the total viewership:
\[ \text{Maximize } \sum_{i} \text{Viewers\_m}_i \times x_i \]

Data Source Verification:
- Coefficient \(\text{Viewers\_m}_i\) comes from `TV_series.Viewers_m`.

#### Constraints

1. **Total Air Time Constraint for Each Channel:**
   - For each channel \( j \), the total air time of selected shows must not exceed the channel's available air time.
   \[
   \sum_{i} \text{Air\_Time}_i \times x_i \leq \text{Total\_Available\_Time}_j
   \]
   - For Channel 1: \(\sum_{i} \text{Air\_Time}_i \times x_i \leq 48\)
   - For Channel 2: \(\sum_{i} \text{Air\_Time}_i \times x_i \leq 72\)
   - For Channel 3: \(\sum_{i} \text{Air\_Time}_i \times x_i \leq 24\)

   Data Source Verification:
   - Coefficient \(\text{Air\_Time}_i\) comes from `TV_series.Air_Time`.
   - Constant \(\text{Total\_Available\_Time}_j\) comes from `Channel.Total_Available_Time`.

2. **Content Type Capacity Constraint for Each Channel:**
   - For each channel \( j \), the number of selected shows of each content type must not exceed the channel's content capacity.
   \[
   \sum_{i \in \text{Content\_Type}} x_i \leq \text{Content\_Capacity}_j
   \]
   - For Channel 1: \(\sum_{i \in \text{series}} x_i \leq 20\)
   - For Channel 2: \(\sum_{i \in \text{cartoon}} x_i \leq 30\)
   - For Channel 3: \(\sum_{i \in \text{series}} x_i \leq 10\)

   Data Source Verification:
   - Coefficient \(\text{Content\_Type}\) comes from `TV_series.Content_Type`.
   - Constant \(\text{Content\_Capacity}_j\) comes from `Channel.Content_Capacity`.

3. **Minimum Demographic Viewership Constraint:**
   - Ensure that the selected programming achieves a minimum viewership from specific demographic groups.
   \[
   \sum_{i} \text{Demographic\_Target}_i \times x_i \geq \text{Minimum\_Demographic\_Target}
   \]
   - Assume a minimum demographic target of 200,000 viewers across all channels.

   Data Source Verification:
   - Coefficient \(\text{Demographic\_Target}_i\) comes from `TV_series.Demographic_Target`.

This linear programming model can be solved using standard optimization software to determine the optimal selection of TV shows that maximizes viewership while satisfying all constraints.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation - Retry Attempt 4

import gurobipy as gp
from gurobipy import GRB

def optimize_tv_schedule():
    """Optimize TV schedule to maximize viewership."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("tvshow")
    
    # Data from the problem statement
    viewers_m = [2, 3, 1]
    air_time = [60, 90, 30]
    content_type = ['series', 'cartoon', 'series']
    demographic_target = [80000, 120000, 50000]
    
    total_available_time = [48, 72, 24]
    content_capacity = [20, 30, 10]
    
    minimum_demographic_target = 200000
    
    n_shows = len(viewers_m)
    n_channels = len(total_available_time)
    
    # CRITICAL: Validate array lengths before loops
    assert len(viewers_m) == len(air_time) == len(content_type) == len(demographic_target) == n_shows, "Array length mismatch"
    assert len(total_available_time) == len(content_capacity) == n_channels, "Channel array length mismatch"
    
    # 2. VARIABLES
    x = model.addVars(n_shows, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(viewers_m[i] * x[i] for i in range(n_shows)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Total Air Time Constraint for Each Channel
    for j in range(n_channels):
        model.addConstr(gp.quicksum(air_time[i] * x[i] for i in range(n_shows)) <= total_available_time[j], name=f"air_time_channel_{j}")
    
    # Content Type Capacity Constraint for Each Channel
    for j in range(n_channels):
        model.addConstr(gp.quicksum(x[i] for i in range(n_shows) if content_type[i] == 'series') <= content_capacity[j], name=f"content_capacity_series_channel_{j}")
        model.addConstr(gp.quicksum(x[i] for i in range(n_shows) if content_type[i] == 'cartoon') <= content_capacity[j], name=f"content_capacity_cartoon_channel_{j}")
    
    # Minimum Demographic Viewership Constraint
    model.addConstr(gp.quicksum(demographic_target[i] * x[i] for i in range(n_shows)) >= minimum_demographic_target, name="min_demographic_target")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_shows):
            if x[i].x > 1e-6:
                print(f"Show {i} selected: 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
optimize_tv_schedule()
```

### Execution Results
**Status**: INFEASIBLE
**Error**: Problem is infeasible
**Analysis**: Gurobipy consistently reports infeasibility, indicating that the constraints may be too restrictive or conflicting.

## 6. DOCplex Implementation

```python
# Complete DOCPLEX implementation - Retry Attempt 4

from docplex.mp.model import Model

def optimize_tv_schedule():
    # 1. MODEL & DATA SETUP
    mdl = Model(name="tvshow_optimization")
    
    # Data from the problem statement
    viewers_m = [2, 3, 1]
    air_time = [60, 90, 30]
    content_type = ['series', 'cartoon', 'series']
    demographic_target = [80000, 120000, 50000]
    
    total_available_time = [48, 72, 24]
    content_capacity = [20, 30, 10]
    
    # Minimum demographic target
    minimum_demographic_target = 200000
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(viewers_m) == len(air_time) == len(content_type) == len(demographic_target), "Array length mismatch"
    safe_range = range(len(viewers_m))  # Safe indexing
    
    # 2. VARIABLES
    x = {i: mdl.binary_var(name=f"x_{i}") for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    objective = mdl.sum(viewers_m[i] * x[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Total Air Time Constraint for Each Channel
    for j, total_time in enumerate(total_available_time):
        mdl.add_constraint(mdl.sum(air_time[i] * x[i] for i in safe_range) <= total_time, ctname=f"total_air_time_channel_{j}")
    
    # Content Type Capacity Constraint for Each Channel
    for j, capacity in enumerate(content_capacity):
        mdl.add_constraint(mdl.sum(x[i] for i in safe_range if content_type[i] == 'series') <= capacity, ctname=f"content_capacity_series_channel_{j}")
        mdl.add_constraint(mdl.sum(x[i] for i in safe_range if content_type[i] == 'cartoon') <= capacity, ctname=f"content_capacity_cartoon_channel_{j}")
    
    # Minimum Demographic Viewership Constraint
    mdl.add_constraint(mdl.sum(demographic_target[i] * x[i] for i in safe_range) >= minimum_demographic_target, ctname="min_demographic_target")
    
    # 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])
            if value > 1e-6:
                print(f"x[{i}] = {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

    return mdl

# Run the optimization
optimize_tv_schedule()
```

### Execution Results
**Status**: INFEASIBLE
**Error**: Problem is infeasible
**Analysis**: DOCplex also reports infeasibility, supporting the conclusion that the problem constraints are not satisfiable.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation - Retry Attempt 4

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

def tvshow_optimization():
    """TV Show Scheduling Optimization using Pyomo"""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Data from the problem statement
    viewers_m = [2, 3, 1]
    air_time = [60, 90, 30]
    content_type = ['series', 'cartoon', 'series']
    demographic_target = [80000, 120000, 50000]
    
    total_available_time = [48, 72, 24]
    content_capacity = [20, 30, 10]
    minimum_demographic_target = 200000
    
    # CRITICAL: Validate array lengths before indexing
    n_shows = len(viewers_m)
    n_channels = len(total_available_time)
    assert len(air_time) == len(content_type) == len(demographic_target) == n_shows, "Array length mismatch"
    assert len(total_available_time) == len(content_capacity) == n_channels, "Channel array length mismatch"
    
    # 3. SETS
    model.I = pyo.RangeSet(1, n_shows)  # Shows
    model.J = pyo.RangeSet(1, n_channels)  # Channels
    
    # 4. PARAMETERS
    model.viewers_m = pyo.Param(model.I, initialize={i+1: viewers_m[i] for i in range(n_shows)})
    model.air_time = pyo.Param(model.I, initialize={i+1: air_time[i] for i in range(n_shows)})
    model.demographic_target = pyo.Param(model.I, initialize={i+1: demographic_target[i] for i in range(n_shows)})
    model.total_available_time = pyo.Param(model.J, initialize={j+1: total_available_time[j] for j in range(n_channels)})
    model.content_capacity = pyo.Param(model.J, initialize={j+1: content_capacity[j] for j in range(n_channels)})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.Binary)
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.viewers_m[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    
    # Total Air Time Constraint for Each Channel
    def air_time_constraint_rule(model, j):
        return sum(model.air_time[i] * model.x[i] for i in model.I) <= model.total_available_time[j]
    model.air_time_constraint = pyo.Constraint(model.J, rule=air_time_constraint_rule)
    
    # Content Type Capacity Constraint for Each Channel
    def content_capacity_constraint_rule(model, j):
        return sum(model.x[i] for i in model.I if content_type[i-1] == 'series') <= model.content_capacity[j]
    model.content_capacity_constraint = pyo.Constraint(model.J, rule=content_capacity_constraint_rule)
    
    # Minimum Demographic Viewership Constraint
    def demographic_constraint_rule(model):
        return sum(model.demographic_target[i] * model.x[i] for i in model.I) >= minimum_demographic_target
    model.demographic_constraint = pyo.Constraint(rule=demographic_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("\nSelected shows:")
        for i in model.I:
            if pyo.value(model.x[i]) > 0.5:  # Binary variable, check if selected
                print(f"Show {i} selected")
        
    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
tvshow_optimization()
```

### Execution Results
**Status**: INFEASIBLE
**Error**: Problem is infeasible
**Analysis**: Pyomo's infeasibility result aligns with the other solvers, suggesting a consistent issue with the problem formulation.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | INFEASIBLE | N/A | 0.19s | N/A | 4 |
| Docplex | INFEASIBLE | N/A | 1.86s | N/A | 4 |
| Pyomo | INFEASIBLE | N/A | 1.95s | N/A | 4 |

### Solver Consistency Analysis
**Result**: All solvers produced consistent results ✓
**Consistent Solvers**: gurobipy, docplex, pyomo
**Solver Retry Summary**: gurobipy: 4 attempts, docplex: 4 attempts, pyomo: 4 attempts

### Final Recommendation
**Confidence Level**: HIGH
**Preferred Solver(s)**: multiple
**Reasoning**: All solvers consistently report infeasibility, suggesting the issue lies with the problem formulation rather than the solvers.

### Business Interpretation
**Overall Strategy**: The current constraints do not allow for a feasible solution, indicating a need to revisit the constraints or data.
**Objective Value Meaning**: The objective value represents the total viewership if a feasible solution is found.
**Resource Allocation Summary**: Currently, resources cannot be allocated due to infeasibility. Constraints need adjustment.
**Implementation Recommendations**: Review and potentially relax constraints, especially the minimum demographic viewership and content type capacities, to find a feasible solution.