You are the manager of a large cross-docking center responsible for assigning docks for the next hour's operations, which involves 4 arriving shipments and 3 departing shipments. The center has 4 inbound docks (I1, I2, I3, I4) and 3 outbound docks (O1, O2, O3), distributed across two different operational zones. The docks in Zone A include I1, I2, and O1, while Zone B includes I3, I4, O2, and O3. The efficiency of forklift operations within a zone decreases with congestion, which is modeled as a cost function that is quadratic in the total number of items passing through that zone. The congestion cost coefficient is 0.00005 for Zone A and 0.00004 for Zone B. Decision-makers need to assign a unique dock to each shipment to minimize the total internal handling cost, which is composed of a base handling cost and a zonal congestion cost. The base handling cost is ¥0.1 per item. The arriving shipments consist of four suppliers: S1 with 200 items, S2 with 150 items, S3 with 180 items, and S4 with 220 items. The departing shipments consist of three retailers: R1 with 250 items, R2 with 300 items, and R3 with 200 items. How should the center assign each shipment to a unique dock to minimize the total internal handling cost?

Problem type: NLP (Small: 25 variables, 14 constraints, 50 nonzeros)

Mathematical model:
Set:
1.  InboundShipments
    The set of arriving shipments, \( S = \{1, 2, 3, 4\} \)
2.  OutboundShipments
    The set of departing shipments, \( R = \{1, 2, 3\} \)
3.  InboundDocks
    The set of inbound docks, \( I = \{1, 2, 3, 4\} \)
4.  OutboundDocks
    The set of outbound docks, \( O = \{1, 2, 3\} \)
5.  Zones
    The set of operational zones, \( Z = \{1, 2\} \) # 1: Zone A, 2: Zone B

Parameter:
1.  NumItemsInbound
    [200, 150, 180, 220] # Number of items in each arriving shipment s ∈ S
2.  NumItemsOutbound
    [250, 300, 200] # Number of items in each departing shipment r ∈ R
3.  InboundDockInZone
    [[1, 1, 0, 0], [0, 0, 1, 1]] # Binary matrix indicating if inbound dock i ∈ I is in zone z ∈ Z
4.  OutboundDockInZone
    [[1, 0, 0], [0, 1, 1]] # Binary matrix indicating if outbound dock o ∈ O is in zone z ∈ Z
5.  CongestionCoefficient
    [0.00005, 0.00004] # Congestion cost coefficient for each zone z ∈ Z
6.  BaseHandlingCost
    0.1 # Base handling cost per item in ¥

Decision variable:
1.  AssignInbound
    Binary variable, \( AssignInbound[s][i] \forall s \in S, i \in I \), equals 1 if arriving shipment \(s\) is assigned to inbound dock \(i\), 0 otherwise.
2.  AssignOutbound
    Binary variable, \( AssignOutbound[r][o] \forall r \in R, o \in O \), equals 1 if departing shipment \(r\) is assigned to outbound dock \(o\), 0 otherwise.

Objective:
1.  Minimize the total internal handling cost.
    min: \( \sum_{z \in Z} CongestionCoefficient[z] \cdot (\sum_{s \in S}\sum_{i \in I} AssignInbound[s][i] \cdot NumItemsInbound[s] \cdot InboundDockInZone[z][i] + \sum_{r \in R}\sum_{o \in O} AssignOutbound[r][o] \cdot NumItemsOutbound[r] \cdot OutboundDockInZone[z][o])^2 + BaseHandlingCost \cdot (\sum_{s \in S} NumItemsInbound[s] + \sum_{r \in R} NumItemsOutbound[r]) \)

Constraint:
1.  Each arriving shipment must be assigned to exactly one inbound dock.
    \( \sum_{i \in I} AssignInbound[s][i] = 1 \forall s \in S \)
2.  Each inbound dock must be assigned to exactly one arriving shipment.
    \( \sum_{s \in S} AssignInbound[s][i] = 1 \forall i \in I \)
3.  Each departing shipment must be assigned to exactly one outbound dock.
    \( \sum_{o \in O} AssignOutbound[r][o] = 1 \forall r \in R \)
4.  Each outbound dock must be assigned to exactly one departing shipment.
    \( \sum_{r \in R} AssignOutbound[r][o] = 1 \forall o \in O \)
5.  Variable domain constraints.
    \( AssignInbound[s][i] \in \{0, 1\} \forall s \in S, i \in I \)
    \( AssignOutbound[r][o] \in \{0, 1\} \forall r \in R, o \in O \)

Type:
Integer, Non-linear, Linear
NLP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB

def solve_cross_docking_qap(
    inbound_shipments=['S1', 'S2', 'S3', 'S4'],
    outbound_shipments=['R1', 'R2', 'R3'],
    inbound_docks=['I1', 'I2', 'I3', 'I4'],
    outbound_docks=['O1', 'O2', 'O3'],
    zones=['A', 'B'],
    shipment_items={
        'S1': 200, 'S2': 150, 'S3': 180, 'S4': 220,
        'R1': 250, 'R2': 300, 'R3': 200
    },
    dock_zones={
        'I1': 'A', 'I2': 'A', 'O1': 'A',
        'I3': 'B', 'I4': 'B', 'O2': 'B', 'O3': 'B'
    },
    congestion_coeffs={'A': 0.00005, 'B': 0.00004},
    base_handling_cost_per_item=0.1
):
    """
    Solves the Cross-Docking Center dock assignment problem to minimize
    the total internal handling cost. This is a Quadratic Assignment Problem (QAP)
    due to the non-linear congestion cost function.
    """
    # Create a new model
    model = gp.Model("CrossDockingCenter")

    # --- Decision Variables ---
    # Binary variable: 1 if an inbound shipment is assigned to an inbound dock
    assign_inbound = model.addVars(inbound_shipments, inbound_docks, vtype=GRB.BINARY, name="AssignInbound")
    
    # Binary variable: 1 if an outbound shipment is assigned to an outbound dock
    assign_outbound = model.addVars(outbound_shipments, outbound_docks, vtype=GRB.BINARY, name="AssignOutbound")

    # --- Constraints (Assignment Logic) ---
    # 1. Each inbound shipment must be assigned to exactly one inbound dock.
    model.addConstrs((assign_inbound.sum(s, '*') == 1 for s in inbound_shipments), name="AssignEachInboundShipment")
    
    # 2. Each inbound dock can only be assigned to one inbound shipment.
    model.addConstrs((assign_inbound.sum('*', i) == 1 for i in inbound_docks), name="AssignEachInboundDock")

    # 3. Each outbound shipment must be assigned to exactly one outbound dock.
    model.addConstrs((assign_outbound.sum(r, '*') == 1 for r in outbound_shipments), name="AssignEachOutboundShipment")

    # 4. Each outbound dock can only be assigned to one outbound shipment.
    model.addConstrs((assign_outbound.sum('*', o) == 1 for o in outbound_docks), name="AssignEachOutboundDock")
    
    # --- Objective Function: Minimize Total Cost ---
    
    # 1. Calculate total items flowing through each zone based on assignments
    items_in_zone = {}
    for z in zones:
        inbound_items_in_zone = gp.quicksum(
            assign_inbound[s, i] * shipment_items[s] 
            for s, i in assign_inbound if dock_zones[i] == z
        )
        outbound_items_in_zone = gp.quicksum(
            assign_outbound[r, o] * shipment_items[r] 
            for r, o in assign_outbound if dock_zones[o] == z
        )
        items_in_zone[z] = inbound_items_in_zone + outbound_items_in_zone

    # 2. Calculate the non-linear congestion cost
    congestion_cost = gp.quicksum(
        congestion_coeffs[z] * items_in_zone[z] * items_in_zone[z] for z in zones
    )
    
    # 3. Calculate the fixed base handling cost
    total_items = sum(shipment_items.values())
    base_cost = base_handling_cost_per_item * total_items
    
    model.setObjective(congestion_cost + base_cost, GRB.MINIMIZE)

    # Optimize the model
    model.optimize()

    # --- 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_cross_docking_qap()
    print(result)

Solution status: OPTIMAL
Optimal objective value: 200.001