Problem description:
A logistics company manages shipments between 3 suppliers (S1, S2, S3), 2 cross-docking warehouses (W1, W2), and 4 customers (C1, C2, C3, C4). The suppliers have weekly capacities of [120, 150, 90] units respectively. Customers demand [80, 60, 70, 90] units weekly. 

Transport costs per unit:
- Direct shipping: S1→[C1,C2,C3,C4] costs [8,10,12,14], S2→[C1,C2,C3,C4] costs [9,7,11,13], S3→[C1,C2,C3,C4] costs [11,9,8,10]
- Cross-docking first leg: S1→[W1,W2] costs [4,5], S2→[W1,W2] costs [6,3], S3→[W1,W2] costs [5,4]
- Cross-docking second leg: W1→[C1,C2,C3,C4] costs [6,5,7,9], W2→[C1,C2,C3,C4] costs [7,6,5,8]
Cross-docking handling cost is $2/unit at each warehouse. Maximum throughput at W1 is 200 units, W2 is 180 units. 

The company wants to minimize total logistics costs while meeting all customer demands without exceeding supplier capacities and warehouse throughput limits.

Problem type: LP (Medium: 26 variables, 11 constraints, 58 nonzeros)

Mathematical model:
Set:
1. Suppliers 
The set of Suppliers, \( S = \{1, 2, 3\} \)
2. Warehouses
The set of Warehouses, \( W = \{1, 2\} \)
3. Customers
The set of Customers, \( C = \{1, 2, 3, 4\} \)

Parameter:
1. SupplierCapacities
[120, 150, 90] units for S1, S2, S3 respectively
2. CustomerDemands
[80, 60, 70, 90] units for C1 to C4 respectively
3. DirectCost
Matrix d where d[s,c] is direct shipping cost from supplier s to customer c:
d = [[8,10,12,14], [9,7,11,13], [11,9,8,10]]
4. FirstLegCost
Matrix f where f[s,w] is cost from supplier s to warehouse w:
f = [[4,5], [6,3], [5,4]]
5. SecondLegCost
Matrix l where l[w,c] is cost from warehouse w to customer c:
l = [[6,5,7,9], [7,6,5,8]]
6. HandlingCost
2 per unit at any warehouse
7. WarehouseCapacity
[200, 180] units for W1 and W2 respectively

Decision variable:
1. DirectShip
Continuous variable \( x_{sc} \geq 0 \) for all \( s \in S, c \in C \), units shipped directly from supplier s to customer c
2. CrossDockFirst
Continuous variable \( y_{sw} \geq 0 \) for all \( s \in S, w \in W \), units shipped from supplier s to warehouse w
3. CrossDockSecond
Continuous variable \( z_{wc} \geq 0 \) for all \( w \in W, c \in C \), units shipped from warehouse w to customer c

Objective:
Minimize total logistics cost including transportation and handling:
min: 
\( \sum_{s\in S}\sum_{c\in C} d[s][c] \cdot x_{sc} \) (direct shipping) 
\( + \sum_{s\in S}\sum_{w\in W} f[s][w] \cdot y_{sw} \) (first leg) 
\( + \sum_{w\in W}\sum_{c\in C} l[w][c] \cdot z_{wc} \) (second leg)
\( + 2 \cdot \sum_{w\in W}\sum_{c\in C} z_{wc} \) (handling)

Constraint:
1. Supplier capacity not exceeded
\( \sum_{c\in C}x_{sc} + \sum_{w\in W}y_{sw} \leq SupplierCapacities_s, \forall s \in S \)
2. Customer demand satisfied
\( \sum_{s\in S}x_{sc} + \sum_{w\in W}z_{wc} = CustomerDemands_c, \forall c \in C \)
3. Warehouse flow balance
\( \sum_{s\in S}y_{sw} = \sum_{c\in C}z_{wc}, \forall w \in W \)
4. Warehouse capacity limit
\( \sum_{s\in S}y_{sw} \leq WarehouseCapacity_w, \forall w \in W \)

Type:
Continuous, Linear, Linear
LP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_logistics_optimization(
    suppliers=[0, 1, 2],
    warehouses=[0, 1],
    customers=[0, 1, 2, 3],
    supplier_capacities=[120, 150, 90],
    customer_demands=[80, 60, 70, 90],
    direct_cost=[
        [8, 10, 12, 14],  # S1→C1,C2,C3,C4
        [9, 7, 11, 13],  # S2→C1,C2,C3,C4
        [11, 9, 8, 10]  # S3→C1,C2,C3,C4
    ],
    first_leg_cost=[
        [4, 5],  # S1→W1,W2
        [6, 3],  # S2→W1,W2
        [5, 4]  # S3→W1,W2
    ],
    second_leg_cost=[
        [6, 5, 7, 9],  # W1→C1,C2,C3,C4
        [7, 6, 5, 8]  # W2→C1,C2,C3,C4
    ],
    handling_cost=2,
    warehouse_capacities=[200, 180]
):
    """
    Models and solves the logistics optimization problem.
    """
    # Create a new model
    model = gp.Model("LogisticsOptimization")

    # ========== Define Decision Variables ==========
    # Direct shipment variables (supplier → customer)
    direct_ship = model.addVars(suppliers,
                                customers,
                                lb=0.0,
                                vtype=GRB.CONTINUOUS,
                                name="DirectShip")

    # Cross-docking first leg variables (supplier → warehouse)
    cross_dock_first = model.addVars(suppliers,
                                     warehouses,
                                     lb=0.0,
                                     vtype=GRB.CONTINUOUS,
                                     name="CrossDockFirst")

    # Cross-docking second leg variables (warehouse → customer)
    cross_dock_second = model.addVars(warehouses,
                                      customers,
                                      lb=0.0,
                                      vtype=GRB.CONTINUOUS,
                                      name="CrossDockSecond")

    # ========== Set Objective Function ==========
    # Direct shipping cost component
    direct_shipping_cost = gp.quicksum(direct_cost[s][c] *
                                       direct_ship[s, c] for s in suppliers
                                       for c in customers)

    # First leg shipping cost component
    first_leg_shipping_cost = gp.quicksum(
        first_leg_cost[s][w] * cross_dock_first[s, w] for s in suppliers
        for w in warehouses)

    # Second leg shipping cost component
    second_leg_shipping_cost = gp.quicksum(
        second_leg_cost[w][c] * cross_dock_second[w, c] for w in warehouses
        for c in customers)

    # Handling cost component (applied to all cross-docked units)
    handling_cost_total = handling_cost * gp.quicksum(
        cross_dock_second[w, c] for w in warehouses for c in customers)

    # Set objective: minimize total cost
    model.setObjective(
        direct_shipping_cost + first_leg_shipping_cost +
        second_leg_shipping_cost + handling_cost_total, GRB.MINIMIZE)

    # ========== Add Constraints ==========
    # 1. Supplier capacity constraints
    for s in suppliers:
        model.addConstr(gp.quicksum(direct_ship[s, c] for c in customers) +
                        gp.quicksum(cross_dock_first[s, w]
                                    for w in warehouses)
                        <= supplier_capacities[s],
                        name=f"SupplierCapacity_{s}")

    # 2. Customer demand satisfaction
    for c in customers:
        model.addConstr(
            gp.quicksum(direct_ship[s, c] for s in suppliers) +
            gp.quicksum(cross_dock_second[w, c]
                        for w in warehouses) == customer_demands[c],
            name=f"CustomerDemand_{c}")

    # 3. Warehouse flow balance (inflow = outflow)
    for w in warehouses:
        model.addConstr(gp.quicksum(cross_dock_first[s, w]
                                    for s in suppliers) == gp.quicksum(
                                        cross_dock_second[w, c]
                                        for c in customers),
                        name=f"WarehouseFlowBalance_{w}")

    # 4. Warehouse throughput capacity
    for w in warehouses:
        model.addConstr(gp.quicksum(cross_dock_first[s, w]
                                    for s in suppliers)
                        <= warehouse_capacities[w],
                        name=f"WarehouseCapacity_{w}")

    # ========== Solve the Model ==========
    model.optimize()

    # --- 6. Return Results ---
    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.ObjVal}
    else:
        return {"status": f"{model.status}"}


# Run the solver function
if __name__ == "__main__":
    result = solve_logistics_optimization()
    print(result)

Solution status: OPTIMAL
Optimal objective value: 2660