Skip to content

Transportation & Allocation Network (LP) ​

Problem ClassSolverKey APIsLinks
Linear Programming (LP)HiGHS (default)m.continuous(), m.constraint(), c, minimize, dot

The transportation problem is one of the most fundamental network optimization models: determine how many units to ship from each supply origin (factory) to each destination (store) to minimize total shipping cost while respecting factory supply limits and meeting store demands.

This example demonstrates how to construct a 2D matrix of decision variables using m.continuous(factories, stores) and write aggregated constraints declaratively via dot() and m.constraint(c...).

Problem Inputs ​

We have 3 factories (Tokyo, Nagoya, Osaka) shipping to 4 regional stores (North, East, West, South):

Factory \ StoreNorth ($/unit)East ($/unit)West ($/unit)South ($/unit)Supply Capacity
Tokyo$4$2$7$8120 units
Nagoya$6$4$3$5100 units
Osaka$9$7$2$380 units
Store Demand70 units90 units60 units60 unitsTotal: 280 / 300

Mathematical Formulation ​

Let xf,s≥0x_{f, s} \ge 0 be the quantity shipped from factory f∈Ff \in F to store s∈Ss \in S, and cf,sc_{f, s} be the unit shipping cost.

Minimize∑f∈F∑s∈Scf,s xf,sSubject to∑s∈Sxf,s≤Supplyf∀f∈F(Factory capacity)∑f∈Fxf,s≥Demands∀s∈S(Store demand)xf,s≥0∀f∈F,s∈S\begin{aligned} \text{Minimize} \quad & \sum_{f \in F} \sum_{s \in S} c_{f,s} \, x_{f,s} \\ \text{Subject to} \quad & \sum_{s \in S} x_{f,s} \le \text{Supply}_f \quad \forall f \in F \quad (\text{Factory capacity}) \\ & \sum_{f \in F} x_{f,s} \ge \text{Demand}_s \quad \forall s \in S \quad (\text{Store demand}) \\ & x_{f,s} \ge 0 \quad \forall f \in F, s \in S \end{aligned}

Implementation in WaSHI ​

typescript
import { Model, sum, dot, c, minimize } from "@ohtaman/washi";

const factories = ["Tokyo", "Nagoya", "Osaka"] as const;
const stores = ["North", "East", "West", "South"] as const;

const shippingCost = {
  Tokyo:  { North: 4, East: 2, West: 7, South: 8 },
  Nagoya: { North: 6, East: 4, West: 3, South: 5 },
  Osaka:  { North: 9, East: 7, West: 2, South: 3 },
};

const supplies = { Tokyo: 120, Nagoya: 100, Osaka: 80 };
const demands = { North: 70, East: 90, West: 60, South: 60 };

async function runTransportation() {
  const m = new Model("TransportationNetwork");

  // 1. Create 2D continuous variables: ship[factory][store] >= 0
  const ship = m.continuous([...factories], [...stores], { lb: 0 });

  // 2. Objective: Minimize total shipping cost across all routes via 2D dot product
  m.objective(minimize(dot(shippingCost, ship)));

  // 3. Supply constraints (row sums): outgoing from f <= supplies[f]
  for (const f of factories) {
    m.constraint(
      c`${sum(stores, (s) => ship[f][s])} <= ${supplies[f]}`,
      `supply_${f}`
    );
  }

  // 4. Demand constraints (column sums): incoming to s >= demands[s]
  for (const s of stores) {
    m.constraint(
      c`${sum(factories, (f) => ship[f][s])} >= ${demands[s]}`,
      `demand_${s}`
    );
  }

  const status = await m.solve();
  console.log(`Status: ${status}, Total Shipping Cost: $${m.objectiveValue}`);
  for (const f of factories) {
    const routes = stores
      .map((s) => `${s}:${Math.round(ship[f][s].value ?? 0)}`)
      .join(", ");
    console.log(`  ${f.padEnd(7)} -> ${routes}`);
  }
}

runTransportation();

Released under the MIT License.