# Complete Optimization Problem and Solution: medicine_enzyme_interaction

## 1. Problem Context and Goals

### Context  
A pharmaceutical company is preparing for a clinical trial and needs to select a combination of medicines that maximizes the overall effectiveness of the treatment while ensuring patient safety and managing trial complexity. Each medicine has a known effectiveness score, which quantifies its potential benefit, and an adverse interaction score, which measures its potential risks when combined with other medicines. The company must decide which medicines to include in the trial, with the decision for each medicine being binary—either it is selected or it is not.

The selection process is guided by two critical operational parameters:  
1. **Maximum Allowed Total Adverse Interaction Score**: The total adverse interaction score of all selected medicines must not exceed 0.5, ensuring patient safety.  
2. **Maximum Number of Medicines That Can Be Selected**: No more than 3 medicines can be included in the trial to manage complexity and resource allocation.  

Additionally, only medicines that are FDA-approved are eligible for selection. The company aims to make these decisions in a way that maximizes the total effectiveness score of the selected medicines while adhering to these constraints.

### Goals  
The primary goal of this optimization problem is to maximize the total effectiveness score of the medicines selected for the clinical trial. This is achieved by carefully choosing which medicines to include, ensuring that their combined effectiveness is as high as possible. Success is measured by the sum of the effectiveness scores of the selected medicines, with higher values indicating a more effective treatment combination. The optimization process ensures that this goal is achieved while respecting the constraints on adverse interactions, the number of medicines, and FDA approval status.

## 2. Constraints  

The selection of medicines for the clinical trial is subject to the following constraints:  
1. **Adverse Interaction Limit**: The total adverse interaction score of all selected medicines must not exceed the maximum allowed value of 0.5. This ensures that the combined risk of the selected medicines remains within safe limits.  
2. **Medicine Count Limit**: The total number of medicines selected for the trial must not exceed the maximum allowed value of 3. This constraint helps manage the complexity and resource requirements of the trial.  
3. **FDA Approval Requirement**: Only medicines that are FDA-approved can be selected for the trial. This ensures that all included medicines meet regulatory standards for safety and efficacy.  

These constraints ensure that the selected combination of medicines is both effective and safe, while also being practical to implement in a clinical trial setting.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 3 Database Schema
-- Objective: Schema changes include adding missing scalar parameters to business configuration logic and ensuring all optimization mappings are complete. No table modifications or deletions were necessary.

CREATE TABLE medicine_effectiveness (
  medicine_id INTEGER,
  effectiveness_score FLOAT
);

CREATE TABLE medicine_adverse_interaction (
  medicine_id INTEGER,
  adverse_interaction_score FLOAT
);

CREATE TABLE medicine (
  medicine_id INTEGER,
  FDA_approved BOOLEAN
);

CREATE TABLE medicine_selection (
  medicine_id INTEGER,
  is_selected BOOLEAN
);
```

### Data Dictionary  
- **medicine_effectiveness**:  
  - **Purpose**: Stores the effectiveness scores of medicines based on enzyme interactions.  
  - **Columns**:  
    - `medicine_id`: Unique identifier for each medicine.  
    - `effectiveness_score`: Quantifies the potential benefit of the medicine.  

- **medicine_adverse_interaction**:  
  - **Purpose**: Stores the adverse interaction scores of medicines based on enzyme interactions.  
  - **Columns**:  
    - `medicine_id`: Unique identifier for each medicine.  
    - `adverse_interaction_score`: Measures the potential risk of the medicine when combined with others.  

- **medicine**:  
  - **Purpose**: Lists all medicines along with their FDA approval status.  
  - **Columns**:  
    - `medicine_id`: Unique identifier for each medicine.  
    - `FDA_approved`: Indicates whether the medicine is approved by the FDA.  

- **medicine_selection**:  
  - **Purpose**: Tracks the selection status of each medicine for the clinical trial.  
  - **Columns**:  
    - `medicine_id`: Unique identifier for each medicine.  
    - `is_selected`: Indicates whether the medicine has been selected for the trial.  

### Current Stored Values  
```sql
-- Iteration 3 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on realistic pharmaceutical data, ensuring effectiveness scores and adverse interaction scores are within plausible ranges. The number of medicines and their FDA approval statuses were chosen to reflect a typical clinical trial scenario.

-- Realistic data for medicine_effectiveness
INSERT INTO medicine_effectiveness (medicine_id, effectiveness_score) VALUES (1, 0.85);
INSERT INTO medicine_effectiveness (medicine_id, effectiveness_score) VALUES (2, 0.75);
INSERT INTO medicine_effectiveness (medicine_id, effectiveness_score) VALUES (3, 0.9);

-- Realistic data for medicine_adverse_interaction
INSERT INTO medicine_adverse_interaction (medicine_id, adverse_interaction_score) VALUES (1, 0.15);
INSERT INTO medicine_adverse_interaction (medicine_id, adverse_interaction_score) VALUES (2, 0.25);
INSERT INTO medicine_adverse_interaction (medicine_id, adverse_interaction_score) VALUES (3, 0.1);

-- Realistic data for medicine
INSERT INTO medicine (medicine_id, FDA_approved) VALUES (1, True);
INSERT INTO medicine (medicine_id, FDA_approved) VALUES (2, False);
INSERT INTO medicine (medicine_id, FDA_approved) VALUES (3, True);

-- Realistic data for medicine_selection
INSERT INTO medicine_selection (medicine_id, is_selected) VALUES (1, False);
INSERT INTO medicine_selection (medicine_id, is_selected) VALUES (2, False);
INSERT INTO medicine_selection (medicine_id, is_selected) VALUES (3, False);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_i \) be a binary decision variable indicating whether medicine \( i \) is selected for the clinical trial.  
  \( x_i = 1 \) if medicine \( i \) is selected, and \( x_i = 0 \) otherwise.  
  \( i \in \{1, 2, 3\} \) (based on the provided data).

#### Objective Function
Maximize the total effectiveness score of the selected medicines:  
\[
\text{Maximize } Z = 0.85x_1 + 0.75x_2 + 0.9x_3
\]  
**Data Source Verification**:  
- Coefficients \( 0.85, 0.75, 0.9 \) are from `medicine_effectiveness.effectiveness_score`.

#### Constraints
1. **Adverse Interaction Limit**: The total adverse interaction score of the selected medicines must not exceed 0.5:  
\[
0.15x_1 + 0.25x_2 + 0.1x_3 \leq 0.5
\]  
**Data Source Verification**:  
- Coefficients \( 0.15, 0.25, 0.1 \) are from `medicine_adverse_interaction.adverse_interaction_score`.

2. **Medicine Count Limit**: The total number of selected medicines must not exceed 3:  
\[
x_1 + x_2 + x_3 \leq 3
\]  
**Data Source Verification**:  
- This constraint is based on the business requirement.

3. **FDA Approval Requirement**: Only FDA-approved medicines can be selected:  
\[
x_2 = 0
\]  
**Data Source Verification**:  
- Medicine 2 is not FDA-approved, as per `medicine.FDA_approved`.

4. **Binary Decision Variables**:  
\[
x_i \in \{0, 1\} \quad \forall i \in \{1, 2, 3\}
\]  
**Data Source Verification**:  
- This is a standard requirement for binary decision variables.

This is a complete, immediately solvable Mixed-Integer Linear Programming (MILP) model with all numerical coefficients derived from the provided data.

## 5. Gurobipy Implementation

```python
#!/usr/bin/env python3
"""
Gurobipy implementation for medicine_enzyme_interaction optimization problem
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_medicine_selection():
    """Optimize medicine selection for clinical trial"""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("medicine_selection")
    
    # Data from the problem
    medicine_ids = [1, 2, 3]
    effectiveness_scores = {1: 0.85, 2: 0.75, 3: 0.9}
    adverse_interaction_scores = {1: 0.15, 2: 0.25, 3: 0.1}
    fda_approved = {1: True, 2: False, 3: True}
    
    # Validate array lengths
    assert len(medicine_ids) == len(effectiveness_scores) == len(adverse_interaction_scores) == len(fda_approved), "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.BINARY, name=f"x_{i}") for i in medicine_ids}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(effectiveness_scores[i] * x[i] for i in medicine_ids), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    # Adverse Interaction Limit
    model.addConstr(gp.quicksum(adverse_interaction_scores[i] * x[i] for i in medicine_ids) <= 0.5, name="adverse_interaction_limit")
    
    # Medicine Count Limit
    model.addConstr(gp.quicksum(x[i] for i in medicine_ids) <= 3, name="medicine_count_limit")
    
    # FDA Approval Requirement
    for i in medicine_ids:
        if not fda_approved[i]:
            model.addConstr(x[i] == 0, name=f"fda_approval_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in medicine_ids:
            if x[i].x > 1e-6:
                print(f"Medicine {i} is selected: {x[i].x:.0f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
optimize_medicine_selection()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 1.75
**Execution Time**: 0.17 seconds
**Reliability**: high
**Analysis**: Gurobipy found the optimal solution quickly with a low execution time.

## 6. DOCplex Implementation

```python
#!/usr/bin/env python3
"""
DOCplex implementation for medicine_enzyme_interaction optimization problem
"""

from docplex.mp.model import Model

def optimize_medicine_selection():
    """Optimize medicine selection for clinical trial"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="medicine_enzyme_interaction")
    
    # Data from the problem statement
    medicine_ids = [1, 2, 3]
    effectiveness_scores = [0.85, 0.75, 0.9]
    adverse_interaction_scores = [0.15, 0.25, 0.1]
    fda_approved = [True, False, True]
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(medicine_ids) == len(effectiveness_scores) == len(adverse_interaction_scores) == len(fda_approved), "Array length mismatch"
    safe_range = range(min(len(medicine_ids), len(effectiveness_scores), len(adverse_interaction_scores), len(fda_approved)))  # Safe indexing
    
    # 2. VARIABLES
    # Binary decision variables for medicine selection
    x = {i: mdl.binary_var(name=f"x_{medicine_ids[i]}") for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total effectiveness score
    objective = mdl.sum(effectiveness_scores[i] * x[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Constraint 1: Adverse Interaction Limit
    adverse_interaction_limit = mdl.sum(adverse_interaction_scores[i] * x[i] for i in safe_range)
    mdl.add_constraint(adverse_interaction_limit <= 0.5, ctname="adverse_interaction_limit")
    
    # Constraint 2: Medicine Count Limit
    medicine_count_limit = mdl.sum(x[i] for i in safe_range)
    mdl.add_constraint(medicine_count_limit <= 3, ctname="medicine_count_limit")
    
    # Constraint 3: FDA Approval Requirement
    for i in safe_range:
        if not fda_approved[i]:
            mdl.add_constraint(x[i] == 0, ctname=f"fda_approval_{medicine_ids[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])
            if value > 1e-6:
                print(f"Medicine {medicine_ids[i]} selected: {value:.0f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

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

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 1.75
**Execution Time**: 1.10 seconds
**Reliability**: high
**Analysis**: DOCplex also found the optimal solution but took longer compared to Gurobipy.

## 7. Pyomo Implementation

```python
#!/usr/bin/env python3
"""
Pyomo 6.9.2 Implementation for Medicine Selection Optimization Problem
"""

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

def medicine_selection_optimization():
    """Optimize medicine selection for clinical trial"""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    medicine_ids = [1, 2, 3]
    effectiveness_scores = [0.85, 0.75, 0.9]
    adverse_interaction_scores = [0.15, 0.25, 0.1]
    FDA_approved = [True, False, True]
    
    # CRITICAL: Validate array lengths before indexing
    assert len(medicine_ids) == len(effectiveness_scores) == len(adverse_interaction_scores) == len(FDA_approved), "Array length mismatch"
    
    # 3. SETS
    model.I = pyo.Set(initialize=medicine_ids)  # Medicine IDs
    
    # 4. PARAMETERS
    model.effectiveness = pyo.Param(model.I, initialize={i: s for i, s in zip(medicine_ids, effectiveness_scores)})
    model.adverse_interaction = pyo.Param(model.I, initialize={i: s for i, s in zip(medicine_ids, adverse_interaction_scores)})
    model.FDA_approved = pyo.Param(model.I, initialize={i: a for i, a in zip(medicine_ids, FDA_approved)})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.Binary)  # Selection decision variables
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.effectiveness[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    
    # Adverse Interaction Limit
    def adverse_interaction_rule(model):
        return sum(model.adverse_interaction[i] * model.x[i] for i in model.I) <= 0.5
    model.adverse_interaction_constraint = pyo.Constraint(rule=adverse_interaction_rule)
    
    # Medicine Count Limit
    def medicine_count_rule(model):
        return sum(model.x[i] for i in model.I) <= 3
    model.medicine_count_constraint = pyo.Constraint(rule=medicine_count_rule)
    
    # FDA Approval Requirement
    def FDA_approval_rule(model, i):
        if not model.FDA_approved[i]:
            return model.x[i] == 0
        return pyo.Constraint.Skip
    model.FDA_approval_constraint = pyo.Constraint(model.I, rule=FDA_approval_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(f"Optimal value: {pyo.value(model.objective)}")
        
        # Extract variable values
        print("\nSelected Medicines:")
        for i in model.I:
            if pyo.value(model.x[i]) > 0.5:  # Only print selected medicines
                print(f"Medicine {i} is 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

if __name__ == "__main__":
    medicine_selection_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 1.75
**Execution Time**: 0.90 seconds
**Reliability**: high
**Analysis**: Pyomo found the optimal solution but had the longest execution time among the three solvers.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 1.75 | 0.17s | N/A | N/A |
| Docplex | OPTIMAL | 1.75 | 1.10s | N/A | N/A |
| Pyomo | OPTIMAL | 1.75 | 0.90s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 1.75
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is recommended due to its faster execution time while still providing the same optimal solution as the other solvers.

### Optimal Decision Variables
- **x_1** = 1.000
  - *Business Meaning*: Medicine 1 is selected for the clinical trial, contributing 0.85 to the effectiveness score.
- **x_2** = 0.000
  - *Business Meaning*: Medicine 2 is not selected due to FDA approval constraints.
- **x_3** = 1.000
  - *Business Meaning*: Medicine 3 is selected for the clinical trial, contributing 0.9 to the effectiveness score.

### Business Interpretation
**Overall Strategy**: The optimal selection of medicines for the clinical trial includes Medicine 1 and Medicine 3, maximizing the total effectiveness score while adhering to all constraints.
**Objective Value Meaning**: The total effectiveness score of 1.75 indicates the combined effectiveness of the selected medicines in the clinical trial.
**Resource Allocation Summary**: Resources should be allocated to include Medicine 1 and Medicine 3 in the clinical trial, ensuring compliance with adverse interaction limits and FDA approval requirements.
**Implementation Recommendations**: Proceed with the clinical trial using Medicine 1 and Medicine 3. Ensure all regulatory and safety constraints are met during the trial.