Skip to content

Example 7: Transportation Problem

Problem Description

There are several warehouses and several stores. Each warehouse has a corresponding goods quantity, each store has a corresponding goods demand, and there is a cost for transporting 1kg of goods from each warehouse to each store.

Warehouse AWarehouse BWarehouse C
Goods Quantity510kg470kg520kg
Store AStore BStore CStore D
Goods Demand200kg400kg600kg300kg
Store AStore BStore CStore D
Warehouse A1213217
Warehouse B1417818
Warehouse C1011915

Determine the goods transportation quantity from each warehouse to each store to minimize total cost.

Mathematical Model

Variables

xws: Goods transportation quantity from warehouse w to store s.

Intermediate Values

1. Total Cost

Cost=wWsSCostwsxws

2. Warehouse Shipment Quantity

Shipmentw=sSxws,wW

3. Store Purchase Quantity

Purchases=wWxws,sS

Objective Function

1. Minimize Total Cost

minCost

Constraints

1. Warehouse Shipment Quantity Cannot Exceed Goods Quantity

s.t.ShipmentwStoragew,wW

2. Store Purchase Quantity Must Meet Demand

s.t.PurchasesDemands,sS

Expected Results

Store AStore BStore CStore D
Warehouse A200kg10kg0kg300kg
Warehouse B0kg0kg470kg0kg
Warehouse C0kg390kg130kg0kg

Code Implementation

kotlin
import fuookami.ospf.kotlin.utils.math.*
import fuookami.ospf.kotlin.utils.concept.*
import fuookami.ospf.kotlin.utils.functional.*
import fuookami.ospf.kotlin.utils.multi_array.*
import fuookami.ospf.kotlin.core.frontend.variable.*
import fuookami.ospf.kotlin.core.frontend.expression.monomial.*
import fuookami.ospf.kotlin.core.frontend.expression.polynomial.*
import fuookami.ospf.kotlin.core.frontend.expression.symbol.*
import fuookami.ospf.kotlin.core.frontend.inequality.*
import fuookami.ospf.kotlin.core.frontend.model.mechanism.*
import fuookami.ospf.kotlin.core.backend.plugins.scip.*

data class Store(
    val demand: Flt64
) : AutoIndexed(Store::class)

data class Warehouse(
    val stowage: Flt64,
    val cost: Map<Store, Flt64>
) : AutoIndexed(Warehouse::class)

val stores: List<Store> = ... // Store list
val warehouses: List<Warehouse> = ... // Warehouse list

// Create model instance
val metaModel = LinearMetaModel("demo7")

// Define variables
val x = UIntVariable2("x", Shape2(warehouses.size, stores.size))
for (w in warehouses) {
    for (s in stores) {
        x[w, s].name = "${x.name}_(${w.index},${s.index})"
    }
}
metaModel.add(x)

// Define intermediate values
val cost = LinearExpressionSymbol(sum(warehouses.map { w ->
    sum(stores.filter { w.cost.contains(it) }.map { s ->
        w.cost[s]!! * x[w, s]
    })
}), "cost")
metaModel.add(cost)

val shipment = LinearIntermediateSymbols1(
    "shipment",
    Shape1(warehouses.size)
) { i, _ ->
    val w = warehouses[i]
    LinearExpressionSymbol(
        sum(stores.filter { w.cost.contains(it) }.map { s -> x[w, s] }),
        "shipment_${w.index}"
    )
}
metaModel.add(shipment)

val purchase = LinearIntermediateSymbols1(
    "purchase",
    Shape1(stores.size)
) { i, _ ->
    val s = stores[i]
    LinearExpressionSymbol(
        sum(warehouses.filter { w -> w.cost.contains(s) }.map { w -> x[w, s] }),
        "purchase_${s.index}"
    )
}
metaModel.add(purchase)

// Define objective function
metaModel.minimize(cost, "cost")

// Define constraints
for(w in warehouses){
    metaModel.addConstraint(
        shipment[w] leq w.stowage,
        "stowage_${w.index}"
    )
}

for(s in stores){
    metaModel.addConstraint(
        purchase[s] geq s.demand,
        "demand_${s.index}"
    )
}

// Call solver to solve
val solver = ScipLinearSolver()
when (val ret = solver(metaModel)) {
    is Ok -> {
        metaModel.tokens.setSolution(ret.value.solution)
    }

    is Failed -> {}
}

// Parse results
val solution = stores.associateWith { warehouses.associateWith { Flt64.zero }.toMutableMap() }
for (token in metaModel.tokens.tokens) {
    if (token.result!! geq Flt64.one && token.variable.belongsTo(x)) {
        val warehouse = warehouses[token.variable.vectorView[0]]
        val store = stores[token.variable.vectorView[1]]
        solution[store]!![warehouse] = solution[store]!![warehouse]!! + token.result!!
    }
}

Complete Implementation Reference: