FreshFoods operates three farms (Farm A, Farm B, and Farm C) to grow and supply fresh produce to four grocery stores (Store 1, Store 2, Store 3, and Store 4). The production cost, yield capacity, water usage (per ton), and fertilizer usage (per ton) for each farm are given in the table below:

| Farm | Production Cost ($/ton) | Yield Capacity (tons) | Water Usage (m³/ton) | Fertilizer Usage (kg/ton) |
| ---- | ----------------------- | --------------------- | -------------------- | ------------------------- |
| A    | 100                     | 500                   | 6                    | 5                         |
| B    | 120                     | 400                   | 8                    | 4                         |
| C    | 150                     | 600                   | 6                    | 3                         |

The demand (in tons) for each grocery store is as follows:

| Store 1 | Store 2 | Store 3 | Store 4 |
| ------- | ------- | ------- | ------- |
| 200     | 300     | 400     | 500     |

The transportation cost (in $/ton) from each farm to each grocery store is given in the table below:

| Farm | Store 1 | Store 2 | Store 3 | Store 4 |
| ---- | ------- | ------- | ------- | ------- |
| A    | 20      | 25      | 30      | 15      |
| B    | 22      | 26      | 32      | 18      |
| C    | 18      | 24      | 28      | 14      |

To meet sustainability goals, the total produce shipped must use no more than 7 m³ of water per ton and no more than 4 kg of fertilizer per ton. How to minimize the total cost while satisfying the demand and sustainability constraints?

Problem type: LP (Small: 12 variables, 9 constraints, 44 nonzeros)

Mathematical model:
Set:
1. Farm
The set of farms, \( F = \{1, 2, 3\} \)  # 1: Farm A, 2: Farm B, 3: Farm C
2. Store
The set of stores, \( S = \{1, 2, 3, 4\} \)  # 1: Store 1, 2: Store 2, 3: Store 3, 4: Store 4

Parameter:
1. ProductionCost
[100, 120, 150]
2. YieldCapacity
[500, 400, 600]
3. WaterUsage
[6, 8, 6]
4. FertilizerUsage
[5, 4, 3]
5. Demand
[200, 300, 400, 500]
6. TransportationCost
[[20, 25, 30, 15], 
 [22, 26, 32, 18], 
 [18, 24, 28, 14]]
7. MaxWaterUsageperTon
7
8. MaxFertilizerUsageperTon
4

Decision variable:
1. AmountProduced
Continuous variable, \( AmountProduced[f][s] \forall f \in F, s \in S \), where \( AmountProduced[f][s] \) is the amount of produce shipped from farm \( f \) to store \( s \).

Objective:
1. Minimize the total cost of production and transportation.
min: \sum_{f \in F} ProductionCost[f] * \sum_{s \in S} AmountProduced[f][s] + \sum_{f \in F} \sum_{s \in S} TransportationCost[f][s] * AmountProduced[f][s]

Constraint:
1. Demand constraint.
\sum_{f \in F} AmountProduced[f][s] \geq Demand[s] \forall s \in S
2. Yield capacity constraint.
\sum_{s \in S} AmountProduced[f][s] \leq YieldCapacity[f] \forall f \in F
3. Water usage constraint.
\sum_{f \in F}\sum_{s \in S} WaterUsage[f] * AmountProduced[f][s] \leq MaxWaterUsageperTon * \sum_{s \in S}\sum_{f \in F} AmountProduced[f][s]
4. Fertilizer usage constraint.
\sum_{f \in F}\sum_{s \in S} FertilizerUsage[f] * AmountProduced[f][s] \leq MaxFertilizerUsageperTon * \sum_{s \in S}\sum_{f \in F} AmountProduced[f][s]
5. Non-negativity constraint.
AmountProduced[f][s] \geq 0 \forall f \in F, s \in S

Type:
Continuous, Linear, Linear
LP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_farm_production_optimization(
    ProductionCost=[100, 120, 150],
    YieldCapacity=[500, 400, 600],
    WaterUsage=[6, 8, 6],
    FertilizerUsage=[5, 4, 3],
    Demand=[200, 300, 400, 500],
    TransportationCost=[
        [20, 25, 30, 15],
        [22, 26, 32, 18],
        [18, 24, 28, 14]
    ],
    MaxWaterUsageperTon=7,
    MaxFertilizerUsageperTon=4
):
    """
    Models and solves the farm production and distribution optimization problem.
    """
    # Create a new model
    model = gp.Model("Farm Production and Distribution Optimization")

    # Sets
    Farms = range(len(ProductionCost))
    Stores = range(len(Demand))

    # Decision Variables
    AmountProduced = {}
    for f in Farms:
        for s in Stores:
            AmountProduced[f, s] = model.addVar(
                vtype=GRB.CONTINUOUS,
                name=f"AmountProduced_{f+1}_{s+1}"
            )

    # Objective: Minimize total production and transportation costs
    obj = gp.quicksum(
        ProductionCost[f] * AmountProduced[f, s] + TransportationCost[f][s] * AmountProduced[f, s]
        for f in Farms
        for s in Stores
    )
    model.setObjective(obj, GRB.MINIMIZE)

    # Constraint 1: Demand constraint - each store's demand must be met
    for s in Stores:
        model.addConstr(
            gp.quicksum(AmountProduced[f, s] for f in Farms) >= Demand[s],
            f"Demand_{s+1}"
        )

    # Constraint 2: Yield capacity constraint - each farm's production cannot exceed capacity
    for f in Farms:
        model.addConstr(
            gp.quicksum(AmountProduced[f, s] for s in Stores) <= YieldCapacity[f],
            f"YieldCapacity_{f+1}"
        )

    # Constraint 3: Water usage constraint - average water usage cannot exceed maximum
    total_production = gp.quicksum(AmountProduced[f, s] for f in Farms for s in Stores)
    total_water_usage = gp.quicksum(WaterUsage[f] * AmountProduced[f, s] for f in Farms for s in Stores)
    model.addConstr(
        total_water_usage <= MaxWaterUsageperTon * total_production,
        "WaterUsage"
    )

    # Constraint 4: Fertilizer usage constraint - average fertilizer usage cannot exceed maximum
    total_fertilizer_usage = gp.quicksum(FertilizerUsage[f] * AmountProduced[f, s] for f in Farms for s in Stores)
    model.addConstr(
        total_fertilizer_usage <= MaxFertilizerUsageperTon * total_production,
        "FertilizerUsage"
    )

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


Solution status: OPTIMAL
Optimal objective value: 203500