# Complete Optimization Problem and Solution: perpetrator

## 1. Problem Context and Goals

### Context  
A security agency is tasked with minimizing the total number of casualties (both killed and injured) across various locations by strategically allocating its limited resources. The agency must decide how many resources to assign to each location to effectively monitor and prevent incidents. Historical data indicates that the allocation of resources directly impacts the reduction of casualties in each location. The agency operates under two critical operational constraints:  
1. The total number of resources available for allocation is fixed and cannot be exceeded.  
2. Each location has a maximum allowable number of casualties, which must not be surpassed.  

The agency’s decision-making process focuses on determining the optimal number of resources to allocate to each location, ensuring that the total resources used do not exceed the available capacity and that the casualties in each location remain within the predefined safety limits. This problem is inherently linear, as the relationships between resource allocation, casualties, and constraints are proportional and additive, without any nonlinear interactions such as variable products or divisions.

### Goals  
The primary goal of the agency is to minimize the total number of casualties across all locations. This is achieved by optimizing the allocation of resources to each location, ensuring that the sum of killed and injured individuals is as low as possible. Success is measured by the reduction in casualties, which is directly influenced by the effective distribution of resources. The agency aims to achieve this goal while adhering to the operational constraints of total resource availability and maximum allowable casualties per location.

## 2. Constraints  

The agency’s optimization problem is subject to the following constraints:  
1. **Total Resource Constraint**: The sum of resources allocated to all locations must not exceed the total number of resources available. This ensures that the agency does not overcommit its limited resources.  
2. **Maximum Casualties Constraint**: For each location, the sum of killed and injured individuals must not exceed the maximum allowed casualties. This ensures that safety thresholds are maintained in every location.  

These constraints are linear and proportional, ensuring that the optimization problem remains straightforward and solvable using linear methods.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 3 Database Schema
-- Objective: Added missing scalar parameters to business configuration logic, ensured schema follows normalization principles, and updated data dictionary to reflect changes.

CREATE TABLE ResourceAllocation (
  location_id INTEGER,
  resources_allocated FLOAT
);

CREATE TABLE Casualties (
  location_id INTEGER,
  killed INTEGER,
  injured INTEGER
);
```

### Data Dictionary  
- **ResourceAllocation Table**:  
  - **location_id**: A unique identifier for each location where resources are allocated.  
  - **resources_allocated**: The number of resources assigned to a specific location. This is the decision variable in the optimization problem.  

- **Casualties Table**:  
  - **location_id**: A unique identifier for each location where casualties are recorded.  
  - **killed**: The number of individuals killed in a specific location. This is a coefficient in the optimization objective.  
  - **injured**: The number of individuals injured in a specific location. This is a coefficient in the optimization objective.  

### Current Stored Values  
```sql
-- Iteration 3 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on historical data and realistic scenarios for a security agency, ensuring that the optimization problem remains meaningful and solvable.

-- Realistic data for ResourceAllocation
INSERT INTO ResourceAllocation (location_id, resources_allocated) VALUES (1, 20.0);
INSERT INTO ResourceAllocation (location_id, resources_allocated) VALUES (2, 15.0);
INSERT INTO ResourceAllocation (location_id, resources_allocated) VALUES (3, 10.0);

-- Realistic data for Casualties
INSERT INTO Casualties (location_id, killed, injured) VALUES (1, 5, 25);
INSERT INTO Casualties (location_id, killed, injured) VALUES (2, 3, 15);
INSERT INTO Casualties (location_id, killed, injured) VALUES (3, 1, 10);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_i \) be the number of resources allocated to location \( i \), where \( i \in \{1, 2, 3\} \).  
  (Controllable decision: resources_allocated in ResourceAllocation table)

#### Objective Function
Minimize the total number of casualties across all locations:  
\[
\text{Minimize } Z = 5x_1 + 25x_1 + 3x_2 + 15x_2 + 1x_3 + 10x_3
\]  
Simplified:  
\[
\text{Minimize } Z = 30x_1 + 18x_2 + 11x_3
\]  
(Objective coefficients: killed and injured from Casualties table)

#### Constraints
1. **Total Resource Constraint**: The sum of resources allocated to all locations must not exceed the total available resources (assume total resources = 45):  
\[
x_1 + x_2 + x_3 \leq 45
\]  
(Constraint coefficient: 1 for each \( x_i \), constant: total resources available)

2. **Maximum Casualties Constraint**: For each location, the sum of killed and injured individuals must not exceed the maximum allowed casualties (assume maximum casualties per location = 30):  
\[
30x_1 \leq 30  
18x_2 \leq 30  
11x_3 \leq 30
\]  
(Constraint coefficients: 30, 18, 11 from objective function, constant: maximum allowed casualties)

#### Data Source Verification
- **Objective Function Coefficients**:  
  - \( 30x_1 \): Sum of killed (5) and injured (25) for location 1 (Casualties table).  
  - \( 18x_2 \): Sum of killed (3) and injured (15) for location 2 (Casualties table).  
  - \( 11x_3 \): Sum of killed (1) and injured (10) for location 3 (Casualties table).  

- **Total Resource Constraint**:  
  - Total resources available = 45 (business configuration parameter).  

- **Maximum Casualties Constraint**:  
  - Maximum allowed casualties per location = 30 (business configuration parameter).  

This is a complete, immediately solvable LINEAR mathematical model with all numerical coefficients derived from the provided data.

## 5. Gurobipy Implementation

```python
#!/usr/bin/env python3
"""
Gurobipy Implementation for Security Agency Resource Allocation Problem
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_resource_allocation():
    """Optimize resource allocation to minimize casualties across locations."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("ResourceAllocation")
    
    # Data from the problem
    locations = [1, 2, 3]
    casualties_coeff = {1: 30, 2: 18, 3: 11}  # Sum of killed and injured per location
    total_resources = 45
    max_casualties = 30
    
    # CRITICAL: Validate array lengths before loops
    assert len(locations) == len(casualties_coeff), "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=0) for i in locations}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(casualties_coeff[i] * x[i] for i in locations), GRB.MINIMIZE)
    
    # 4. CONSTRAINTS
    
    # Total Resource Constraint
    model.addConstr(gp.quicksum(x[i] for i in locations) <= total_resources, name="total_resources")
    
    # Maximum Casualties Constraint
    for i in locations:
        model.addConstr(casualties_coeff[i] * x[i] <= max_casualties, name=f"max_casualties_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in locations:
            if x[i].x > 1e-6:
                print(f"Resources allocated to location {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

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

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 0.0
**Execution Time**: 0.18 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution with zero casualties, indicating no resources need to be allocated. This aligns with the constraints and objective function.

## 6. DOCplex Implementation

```python
#!/usr/bin/env python3
"""
DOCplex 2.29.245 Implementation for Security Agency Resource Allocation Problem
"""

from docplex.mp.model import Model

def optimize_resource_allocation():
    """Optimize resource allocation to minimize total casualties."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="Resource_Allocation")
    
    # Data from the problem
    locations = [1, 2, 3]
    casualties_coeff = {1: 30, 2: 18, 3: 11}  # Sum of killed and injured per location
    total_resources = 45
    max_casualties_per_location = 30
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(locations) == len(casualties_coeff), "Array length mismatch"
    safe_range = range(min(len(locations), len(casualties_coeff)))  # Safe indexing
    
    # 2. VARIABLES
    # Decision variables: resources allocated to each location
    x = {i: mdl.continuous_var(name=f"x_{i}", lb=0) for i in locations}
    
    # 3. OBJECTIVE FUNCTION
    # Minimize total casualties: Z = 30x1 + 18x2 + 11x3
    objective = mdl.sum(casualties_coeff[i] * x[i] for i in locations)
    mdl.minimize(objective)
    
    # 4. CONSTRAINTS
    
    # Total Resource Constraint: x1 + x2 + x3 <= 45
    total_resource_usage = mdl.sum(x[i] for i in locations)
    mdl.add_constraint(total_resource_usage <= total_resources, ctname="total_resources")
    
    # Maximum Casualties Constraint: 30x1 <= 30, 18x2 <= 30, 11x3 <= 30
    for i in locations:
        mdl.add_constraint(casualties_coeff[i] * x[i] <= max_casualties_per_location, ctname=f"max_casualties_{i}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in locations:
            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

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

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 0.0
**Execution Time**: 1.08 seconds
**Reliability**: high
**Analysis**: DOCplex also found an optimal solution with zero casualties, consistent with Gurobipy's results. The execution time was longer but still reliable.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def optimize_resource_allocation():
    """Optimize resource allocation to minimize casualties across locations."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    locations = [1, 2, 3]
    casualties_coeff = {1: 30, 2: 18, 3: 11}  # Coefficients from objective function
    total_resources = 45
    max_casualties = 30
    
    # CRITICAL: Validate array lengths before indexing
    assert len(locations) == len(casualties_coeff), "Array length mismatch"
    
    # 3. SETS (Pyomo way to define indices)
    model.I = pyo.Set(initialize=locations)  # Set of locations
    
    # 4. PARAMETERS (data containers)
    model.casualties_coeff = pyo.Param(model.I, initialize=casualties_coeff)
    
    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.NonNegativeReals)  # Resources allocated to each location
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.casualties_coeff[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.minimize)
    
    # 7. CONSTRAINTS
    
    # Total Resource Constraint
    def total_resource_rule(model):
        return sum(model.x[i] for i in model.I) <= total_resources
    model.total_resource_constraint = pyo.Constraint(rule=total_resource_rule)
    
    # Maximum Casualties Constraint
    def max_casualties_rule(model, i):
        return model.casualties_coeff[i] * model.x[i] <= max_casualties
    model.max_casualties_constraint = pyo.Constraint(model.I, rule=max_casualties_rule)
    
    # 8. SOLVING WITH GUROBI (your available solver)
    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("\nResource Allocation:")
        for i in model.I:
            x_val = pyo.value(model.x[i])
            if x_val > 1e-6:  # Only print non-zero values
                print(f"Location {i}: {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

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

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 0.0
**Execution Time**: 0.91 seconds
**Reliability**: high
**Analysis**: Pyomo confirmed the optimal solution with zero casualties, further validating the results. The execution time was intermediate between Gurobipy and DOCplex.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 0.00 | 0.18s | N/A | N/A |
| Docplex | OPTIMAL | 0.00 | 1.08s | N/A | N/A |
| Pyomo | OPTIMAL | 0.00 | 0.91s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 0.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: multiple
**Reasoning**: All three solvers (Gurobipy, DOCplex, Pyomo) consistently found the same optimal solution, indicating high reliability. Gurobipy is preferred for its speed, but the consistency across solvers strengthens confidence in the results.

### Optimal Decision Variables
- **x_1** = 0.000
  - *Business Meaning*: Resources allocated to location 1. Optimal value is 0, meaning no resources are needed here.
- **x_2** = 0.000
  - *Business Meaning*: Resources allocated to location 2. Optimal value is 0, meaning no resources are needed here.
- **x_3** = 0.000
  - *Business Meaning*: Resources allocated to location 3. Optimal value is 0, meaning no resources are needed here.

### Business Interpretation
**Overall Strategy**: The optimal solution suggests that no resources need to be allocated to any location to minimize casualties, as the constraints are already satisfied without any allocation.
**Objective Value Meaning**: The optimal objective value of 0 indicates that no casualties occur when no resources are allocated, as the constraints are inherently satisfied.
**Resource Allocation Summary**: No resources need to be allocated to any location to meet the constraints and minimize casualties.
**Implementation Recommendations**: Verify the constraints and objective function to ensure they accurately reflect the business scenario. If confirmed, implement the solution by not allocating resources to the specified locations.