Global Freight Solutions (GFS), a logistics company, needs to transport goods across three regions using services from three shipping providers. Each provider offers different cost structures and service mixes for large, medium, and small shipments, as detailed in Table as follows:

| Supplier | Cost Per Shipment ($) | Percent Large | Percent Medium | Percent Small |
|----------|-----------------------|---------------|----------------|---------------|
| 1        | 5.2                   | 45            | 35             | 20            |
| 2        | 4.7                   | 30            | 45             | 25            |
| 3        | 3.5                   | 15            | 20             | 65            |

GFS must fulfill a minimum monthly demand of at least 500 large shipments, 300 medium shipments, and 300 small shipments while minimizing total costs. Additionally, due to capacity constraints, no more than 700 shipments can be contracted from any single provider each month. Determine what the lowest possible cost is.

Problem type: ILP (Toy: 3 variables, 6 constraints, 12 nonzeros)

Mathematical model:
Set:
1. Supplier
The set of suppliers, \( S = \{1, 2, 3\} \) 
2. ShipmentType
The set of shipment types, \( T = \{1, 2, 3\} \)  # 1: large, 2: medium, 3: small

Parameter:
1. CostPerShipment
[5.2, 4.7, 3.5]
2. Percent
[[45, 35, 20], [30, 45, 25], [15, 20, 65]]
3. Demand
[500, 300, 300]
4. MaxShipment
[700, 700, 700]

Decision variable:
1. ShipmentNum
Integer variable, \( ShipmentNum[s] \forall s \in S \), where \( ShipmentNum[s] \) is the number of shipments contracted from supplier \( s \).

Objective:
1. Minimize the total cost of shipments.
min: \sum_{s \in S} CostPerShipment[s] * ShipmentNum[s]

Constraint:
1. Shipment number constraint.
ShipmentNum[s] \leq MaxShipment[s] \forall s \in S
2. Demand satisfaction constraint.
\sum_{s \in S} Percent[s][g] * ShipmentNum[s] \geq Demand[g] \forall g \in T
3. Shipment number non-negativity constraint.
ShipmentNum[s] \geq 0 \forall s \in S

Type:
Integer, Linear, Linear
ILP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_supplier_shipment_optimization(
    CostPerShipment=[5.2, 4.7, 3.5],
    Percent=[
        [45, 35, 20],
        [30, 45, 25],
        [15, 20, 65]
    ],
    Demand=[500, 300, 300],
    MaxShipment=[700, 700, 700]
):
    # Create a new model
    model = gp.Model("Supplier Shipment Optimization")

    # Sets
    Suppliers = range(len(CostPerShipment))
    ShipmentTypes = range(len(Demand))

    # Decision Variables
    ShipmentNum = model.addVars(Suppliers, vtype=GRB.INTEGER, name="ShipmentNum")

    # Objective: Minimize total cost of shipments
    obj = gp.quicksum(CostPerShipment[s] * ShipmentNum[s] for s in Suppliers)
    model.setObjective(obj, GRB.MINIMIZE)

    # Constraint 1: Shipment number constraint (cannot exceed maximum)
    for s in Suppliers:
        model.addConstr(
            ShipmentNum[s] <= MaxShipment[s],
            f"MaxShipment_{s+1}"
        )

    # Constraint 2: Demand satisfaction constraint
    for t in ShipmentTypes:
        # Convert percentage to decimal
        model.addConstr(
            gp.quicksum((Percent[s][t] / 100) * ShipmentNum[s] for s in Suppliers) >= Demand[t],
            f"DemandSatisfaction_{t+1}"
        )

    # Optimize the model
    model.optimize()

    # Return results
    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.objVal}
    else:
        return {"status": f"{model.status}"}


if __name__ == "__main__":
    result = solve_supplier_shipment_optimization()
    print(result)

Solution status: OPTIMAL
Optimal objective value: 6553.7