# Complete Optimization Problem and Solution: pets_1

## 1. Problem Context and Goals

### Context  
The university is tasked with efficiently allocating pet care resources to students based on their pets' needs and the students' demographics. The primary business decision involves determining the amount of resources to allocate to each pet, represented as a continuous variable. The operational parameters are designed to minimize the total cost of pet care, which is calculated by multiplying the cost associated with each pet type by the resources allocated to each pet. 

The business configuration includes two critical scalar parameters: the minimum resource allocation per pet, ensuring that no pet receives negative resources, and the maximum resource allocation per pet, which reflects the university's budget constraints. These parameters serve as lower and upper bounds for the decision variables, respectively. The optimization problem is designed to ensure that each pet receives adequate care based on its type, age, and weight, while the total resources allocated do not exceed the available budget and weight capacity.

### Goals  
The optimization goal is to minimize the total cost of pet care. This is achieved by efficiently allocating resources to each pet, ensuring that the sum of the costs associated with each pet type multiplied by the resources allocated to each pet is as low as possible. Success is measured by achieving the lowest possible total cost while adhering to the constraints on resource allocation and care requirements.

## 2. Constraints    

The optimization problem is subject to several constraints that ensure the allocation of resources is both feasible and adequate. Each pet must receive a minimum level of care based on its type, ensuring that no pet is neglected. Additionally, the resources allocated to each pet must not exceed the maximum care requirement for its type, preventing over-allocation. 

The total resources allocated across all pets must not exceed the university's maximum resource allocation limit, ensuring that the budget is not exceeded. Finally, each pet must receive at least the minimum resource allocation, ensuring that no pet is allocated negative resources. These constraints are designed to maintain a balance between adequate care and budget limitations.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 2 Database Schema
-- Objective: Added resource_allocation table to map decision variables, updated business configuration logic with new scalar parameters, and ensured all mappings align with OR expert's requirements.

CREATE TABLE pet_type_costs (
  pet_type STRING,
  cost FLOAT
);

CREATE TABLE pet_care_requirements (
  pet_type STRING,
  min_care FLOAT,
  max_care FLOAT
);

CREATE TABLE resource_allocation (
  pet_id STRING,
  amount FLOAT
);


```

### Data Dictionary  
- **pet_type_costs**: This table contains the cost associated with caring for each pet type. The `pet_type` column identifies the type of pet, and the `cost` column represents the cost per pet type, which is used as a coefficient in the objective function.
  
- **pet_care_requirements**: This table defines the minimum and maximum care requirements for each pet type. The `pet_type` column identifies the type of pet, while the `min_care` and `max_care` columns represent the lower and upper bounds for resource allocation, respectively.
  
- **resource_allocation**: This table tracks the amount of resources allocated to each pet. The `pet_id` column uniquely identifies each pet, and the `amount` column represents the decision variable in the optimization problem, indicating the resources allocated to each pet.

### Current Stored Values  
```sql
-- Iteration 2 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on realistic pet care costs, care requirements, and resource allocation limits, ensuring that the optimization problem remains meaningful and solvable.

-- Realistic data for pet_type_costs
INSERT INTO pet_type_costs (pet_type, cost) VALUES ('dog', 50.0);
INSERT INTO pet_type_costs (pet_type, cost) VALUES ('cat', 30.0);
INSERT INTO pet_type_costs (pet_type, cost) VALUES ('bird', 20.0);

-- Realistic data for pet_care_requirements
INSERT INTO pet_care_requirements (pet_type, min_care, max_care) VALUES ('dog', 10.0, 100.0);
INSERT INTO pet_care_requirements (pet_type, min_care, max_care) VALUES ('cat', 5.0, 50.0);
INSERT INTO pet_care_requirements (pet_type, min_care, max_care) VALUES ('bird', 3.0, 30.0);

-- Realistic data for resource_allocation
INSERT INTO resource_allocation (pet_id, amount) VALUES ('pet1', 50.0);
INSERT INTO resource_allocation (pet_id, amount) VALUES ('pet2', 30.0);
INSERT INTO resource_allocation (pet_id, amount) VALUES ('pet3', 20.0);


```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_i \) be the amount of resources allocated to pet \( i \), where \( i \) represents each pet in the `resource_allocation` table.  
  \( x_i \) is a continuous variable.

#### Objective Function
Minimize the total cost of pet care:  
\[
\text{Minimize} \quad \sum_{i} c_i \cdot x_i
\]  
where \( c_i \) is the cost associated with the pet type of pet \( i \).

#### Constraints
1. **Minimum Care Requirement**: Each pet must receive at least the minimum care required for its type:  
\[
x_i \geq m_i \quad \forall i
\]  
where \( m_i \) is the minimum care requirement for the pet type of pet \( i \).

2. **Maximum Care Requirement**: Each pet must not receive more than the maximum care allowed for its type:  
\[
x_i \leq M_i \quad \forall i
\]  
where \( M_i \) is the maximum care requirement for the pet type of pet \( i \).

3. **Total Resource Limit**: The total resources allocated across all pets must not exceed the university's maximum resource allocation limit \( R \):  
\[
\sum_{i} x_i \leq R
\]

4. **Non-Negativity**: Resources allocated to each pet must be non-negative:  
\[
x_i \geq 0 \quad \forall i
\]

#### Data Source Verification
- \( c_i \): `pet_type_costs.cost` (cost per pet type)  
- \( m_i \): `pet_care_requirements.min_care` (minimum care per pet type)  
- \( M_i \): `pet_care_requirements.max_care` (maximum care per pet type)  
- \( R \): Business configuration parameter (maximum total resource allocation limit)  

#### Numerical Example
Using the provided data:  
- \( c_i \): 50.0 (dog), 30.0 (cat), 20.0 (bird)  
- \( m_i \): 10.0 (dog), 5.0 (cat), 3.0 (bird)  
- \( M_i \): 100.0 (dog), 50.0 (cat), 30.0 (bird)  
- \( R \): Assume \( R = 200.0 \) (example value for total resource limit)  

The complete linear programming formulation is:  
\[
\text{Minimize} \quad 50x_1 + 30x_2 + 20x_3
\]  
Subject to:  
\[
x_1 \geq 10.0, \quad x_2 \geq 5.0, \quad x_3 \geq 3.0  
\]  
\[
x_1 \leq 100.0, \quad x_2 \leq 50.0, \quad x_3 \leq 30.0  
\]  
\[
x_1 + x_2 + x_3 \leq 200.0  
\]  
\[
x_1, x_2, x_3 \geq 0  
\]

This is a complete, immediately solvable linear programming model.

## 5. Gurobipy Implementation

```python
#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Pet Care Resource Allocation
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_pet_care():
    """Optimize pet care resource allocation using Gurobipy"""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("pet_care_optimization")
    
    # Data from the database
    pet_type_costs = {'dog': 50.0, 'cat': 30.0, 'bird': 20.0}
    pet_care_requirements = {'dog': {'min_care': 10.0, 'max_care': 100.0},
                             'cat': {'min_care': 5.0, 'max_care': 50.0},
                             'bird': {'min_care': 3.0, 'max_care': 30.0}}
    resource_allocation = {'pet1': {'pet_type': 'dog', 'amount': 50.0},
                           'pet2': {'pet_type': 'cat', 'amount': 30.0},
                           'pet3': {'pet_type': 'bird', 'amount': 20.0}}
    
    # Business configuration parameter
    R = 200.0  # Maximum total resource allocation limit
    
    # Validate data consistency
    pets = list(resource_allocation.keys())
    assert len(pets) > 0, "No pets found in resource_allocation"
    
    # 2. VARIABLES
    x = {pet: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{pet}", lb=0) 
         for pet in pets}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(
        gp.quicksum(pet_type_costs[resource_allocation[pet]['pet_type']] * x[pet] 
                    for pet in pets), 
        GRB.MINIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Minimum Care Requirement
    for pet in pets:
        pet_type = resource_allocation[pet]['pet_type']
        min_care = pet_care_requirements[pet_type]['min_care']
        model.addConstr(x[pet] >= min_care, name=f"min_care_{pet}")
    
    # Maximum Care Requirement
    for pet in pets:
        pet_type = resource_allocation[pet]['pet_type']
        max_care = pet_care_requirements[pet_type]['max_care']
        model.addConstr(x[pet] <= max_care, name=f"max_care_{pet}")
    
    # Total Resource Limit
    model.addConstr(gp.quicksum(x[pet] for pet in pets) <= R, name="total_resource_limit")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for pet in pets:
            if x[pet].x > 1e-6:
                print(f"Resources allocated to {pet}: {x[pet].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
if __name__ == "__main__":
    optimize_pet_care()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 710.0
**Execution Time**: 0.18 seconds
**Reliability**: high
**Analysis**: Gurobipy found the optimal solution quickly with an execution time of 0.183 seconds, indicating high efficiency and reliability.

## 6. DOCplex Implementation

```python
#!/usr/bin/env python3
"""
DOCplex implementation for pet care resource allocation optimization
"""

from docplex.mp.model import Model

def pet_care_optimization():
    """Optimize pet care resource allocation to minimize total cost"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="pet_care_optimization")
    
    # Data from the database
    pet_type_costs = {'dog': 50.0, 'cat': 30.0, 'bird': 20.0}
    pet_care_requirements = {'dog': (10.0, 100.0), 'cat': (5.0, 50.0), 'bird': (3.0, 30.0)}
    resource_allocation = {'pet1': 'dog', 'pet2': 'cat', 'pet3': 'bird'}
    
    # Business configuration parameter
    R = 200.0  # Maximum total resource allocation limit
    
    # CRITICAL: Validate array lengths to prevent IndexError
    n_pets = len(resource_allocation)
    assert n_pets > 0, "No pets found in resource_allocation"
    
    # 2. VARIABLES
    # Decision variables: amount of resources allocated to each pet
    x = {pet_id: mdl.continuous_var(name=f"x_{pet_id}", lb=0) for pet_id in resource_allocation}
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the total cost of pet care
    objective = mdl.sum(pet_type_costs[resource_allocation[pet_id]] * x[pet_id] for pet_id in resource_allocation)
    mdl.minimize(objective)
    
    # 4. CONSTRAINTS
    
    # Minimum Care Requirement
    for pet_id in resource_allocation:
        pet_type = resource_allocation[pet_id]
        min_care = pet_care_requirements[pet_type][0]
        mdl.add_constraint(x[pet_id] >= min_care, ctname=f"min_care_{pet_id}")
    
    # Maximum Care Requirement
    for pet_id in resource_allocation:
        pet_type = resource_allocation[pet_id]
        max_care = pet_care_requirements[pet_type][1]
        mdl.add_constraint(x[pet_id] <= max_care, ctname=f"max_care_{pet_id}")
    
    # Total Resource Limit
    total_resources = mdl.sum(x[pet_id] for pet_id in resource_allocation)
    mdl.add_constraint(total_resources <= R, ctname="total_resource_limit")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for pet_id in resource_allocation:
            value = solution.get_value(x[pet_id])
            print(f"Resources allocated to {pet_id}: {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
if __name__ == "__main__":
    pet_care_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 710.0
**Execution Time**: 1.06 seconds
**Reliability**: medium
**Analysis**: DOCplex also found the optimal solution but took longer (1.059 seconds) compared to Gurobipy, suggesting slightly lower efficiency.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def pet_care_optimization():
    """Optimize pet care resource allocation to minimize total cost."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Pet types and their costs
    pet_type_costs = {'dog': 50.0, 'cat': 30.0, 'bird': 20.0}
    
    # Pet care requirements (min and max care per pet type)
    pet_care_requirements = {
        'dog': {'min_care': 10.0, 'max_care': 100.0},
        'cat': {'min_care': 5.0, 'max_care': 50.0},
        'bird': {'min_care': 3.0, 'max_care': 30.0}
    }
    
    # Resource allocation data (pet_id and initial amount)
    resource_allocation = {
        'pet1': {'pet_type': 'dog', 'amount': 50.0},
        'pet2': {'pet_type': 'cat', 'amount': 30.0},
        'pet3': {'pet_type': 'bird', 'amount': 20.0}
    }
    
    # Maximum total resource allocation limit
    R = 200.0
    
    # 3. SETS (Pyomo way to define indices)
    model.P = pyo.Set(initialize=resource_allocation.keys())  # Set of pets
    
    # 4. PARAMETERS (data containers)
    model.cost = pyo.Param(model.P, initialize={p: pet_type_costs[resource_allocation[p]['pet_type']] for p in model.P})
    model.min_care = pyo.Param(model.P, initialize={p: pet_care_requirements[resource_allocation[p]['pet_type']]['min_care'] for p in model.P})
    model.max_care = pyo.Param(model.P, initialize={p: pet_care_requirements[resource_allocation[p]['pet_type']]['max_care'] for p in model.P})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.P, within=pyo.NonNegativeReals)  # Resources allocated to each pet
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.cost[p] * model.x[p] for p in model.P)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.minimize)
    
    # 7. CONSTRAINTS
    # Minimum care requirement
    def min_care_rule(model, p):
        return model.x[p] >= model.min_care[p]
    model.min_care_constraint = pyo.Constraint(model.P, rule=min_care_rule)
    
    # Maximum care requirement
    def max_care_rule(model, p):
        return model.x[p] <= model.max_care[p]
    model.max_care_constraint = pyo.Constraint(model.P, rule=max_care_rule)
    
    # Total resource limit
    def total_resource_rule(model):
        return sum(model.x[p] for p in model.P) <= R
    model.total_resource_constraint = pyo.Constraint(rule=total_resource_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("Optimal solution found!")
        print(f"Optimal value: {pyo.value(model.objective)}")
        
        # Extract variable values
        print("\nResource allocation:")
        for p in model.P:
            x_val = pyo.value(model.x[p])
            print(f"Pet {p}: {x_val:.3f} resources")
        
    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
if __name__ == "__main__":
    pet_care_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 710.0
**Execution Time**: 0.92 seconds
**Reliability**: medium
**Analysis**: Pyomo found the optimal solution with an execution time of 0.920 seconds, which is slower than Gurobipy but faster than DOCplex.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 710.00 | 0.18s | N/A | N/A |
| Docplex | OPTIMAL | 710.00 | 1.06s | N/A | N/A |
| Pyomo | OPTIMAL | 710.00 | 0.92s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 710.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is recommended due to its faster execution time and high reliability, making it the most efficient solver for this problem.

### Business Interpretation
**Overall Strategy**: The optimal total cost of pet care is $710. This ensures that all pets receive the minimum required care without exceeding the university's resource limit.
**Objective Value Meaning**: The optimal total cost of $710 represents the minimum expenditure required to meet all pet care requirements within the resource constraints.
**Resource Allocation Summary**: Resources should be allocated as follows: dogs receive 10.0 units, cats receive 5.0 units, and birds receive 3.0 units, totaling 18.0 units, which is well within the university's limit of 200.0 units.
**Implementation Recommendations**: Implement the resource allocation plan as per the optimal solution. Monitor the actual resource usage to ensure it stays within the recommended limits and adjust as necessary based on any changes in pet care requirements or resource availability.