A manufacturing company needs to procure 5 key components (C1-C5, fractional procurement allowed) from 3 potential suppliers (S1-S3) for the next quarter. Each supplier has different pricing, reliability scores (0-1 scale), and maximum supply capacities. The company has forecasted component demands and wants to minimize total procurement cost while ensuring: (1) at least 60% of each component comes from suppliers with reliability ≥0.8, (2) no more than 40% of total spend goes to any single supplier, and (3) all demand is met. The quarterly demand is [1200, 800, 1500, 900, 600] units for C1-C5 respectively. Supplier data: S1 offers prices [12,15,18,20,22] $/unit with reliability 0.85 and capacity 2000 units; S2 offers [14,16,17,19,21] $/unit with reliability 0.75 and capacity 1800 units; S3 offers [13,14,19,18,20] $/unit with with reliability 0.90 and capacity 2500 units.

Problem type: LP (Medium: 15 variables, 16 constraints, 85 nonzeros)

Mathematical model:
Set:
1. Components
The set of components, \( C = \{1, 2, 3, 4, 5\} \) representing C1-C5
2. Suppliers
The set of suppliers, \( S = \{1, 2, 3\} \) representing S1-S3

Parameter:
1. Demand
[1200, 800, 1500, 900, 600] units for each \( c \in C \)
2. Price
\( p_{scsc} \): Price from supplier \( s \) for component \( c \),
S1: [12,15,18,20,22], S2: [14,16,17,19,21], S3: [13,14,19,18,20]
3. Reliability
\( r_s \): [0.85, 0.75, 0.90] for S1-S3
4. Capacity
\( cap_s \): [2000, 1800, 2500] units for S1-S3
5. MinReliableFraction
0
.6 (minimum fraction from reliable suppliers)
6. MaxSupplierSpendFraction
0.4 (maximum spend share per supplier)

Decision variable:
1. ProcurementQuantity
\( q_{sc} \geq 0 \) for all \( s \in S, c \in C \), quantity purchased from supplier \( s \) for component \( c \)

Objective:
Minimize total procurement cost
min: \( \sum_{s\in S}\sum_{c\in C} p_{sc} \cdot q_{sc} \)

Constraint:
1. Demand satisfaction
\( \sum_{s\in S} q_{sc} = Demand_c, \forall c \in C \)
2. Supplier capacity
\( \sum_{c\in C} q_{sc} \leq cap_s, \forall s \in S \)
3. Reliable sourcing requirement
\( \sum_{s\in S | r_s \geq 0.8} q_{sc} \geq 0.6 \cdot Demand_c, \forall c \in C \)
4. Spend concentration limit
\( \sum_{c\in C} p_{sc} \cdot q_{sc} \leq 0.4 \cdot \sum_{s'\in S}\sum_{c\in C} p_{s'c} \cdot q_{s'c}, \forall s \in S \)

Type:
Continuous, Linear, Linear
LP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_procurement_problem(
    components=[1, 2, 3, 4, 5],
    suppliers=[1, 2, 3],
    demand={1: 1200, 2: 800, 3: 1500, 4: 900, 5: 600},
    price_data=None,
    reliability={1: 0.85, 2: 0.75, 3: 0.90},
    capacity={1: 2000, 2: 1800, 3: 2500},
    min_reliable_frac=0.6,
    max_spend_frac=0.4
):
    """Solve the supplier procurement optimization problem using Gurobi."""
    if price_data is None:
        price = {
            1: {1: 12, 2: 15, 3: 18, 4: 20, 5: 22},
            2: {1: 14, 2: 16, 3: 17, 4: 19, 5: 21},
            3: {1: 13, 2: 14, 3: 19, 4: 18, 5: 20}
        }
    else:
        price = price_data

    model = gp.Model("ComponentProcurement")

    q = model.addVars(suppliers, components, name="q", lb=0)

    total_cost = gp.quicksum(price[s][c] * q[s, c] for s in suppliers for c in components)
    model.setObjective(total_cost, GRB.MINIMIZE)

    for c in components:
        model.addConstr(gp.quicksum(q[s, c] for s in suppliers) == demand[c])

    for s in suppliers:
        model.addConstr(gp.quicksum(q[s, c] for c in components) <= capacity[s])

    reliable_suppliers = [s for s in suppliers if reliability[s] >= 0.8]
    for c in components:
        model.addConstr(gp.quicksum(q[s, c] for s in reliable_suppliers) >= min_reliable_frac * demand[c])

    total_spend = gp.quicksum(price[s][c] * q[s, c] for s in suppliers for c in components)
    for s in suppliers:
        supplier_spend = gp.quicksum(price[s][c] * q[s, c] for c in components)
        model.addConstr(supplier_spend <= max_spend_frac * total_spend)

    model.optimize()

    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.ObjVal}
    else:
        return {"status": f"{model.status}"}


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


Solution status: OPTIMAL
Optimal objective value: 80740.21739