Example 8: Production Problem
Problem Description
Given a set of machines and products, each product has an associated profit, each machine has a finite capacity, and the production of each product requires a certain number of hours from each machine.
Product A | Product B | Product C | Product D | Product E | |
---|---|---|---|---|---|
Profit |
Equipment A | Equipment B | Equipment C | Equipment D | |
---|---|---|---|---|
Amount |
Product A | Product B | Product C | Product D | Product E | |
---|---|---|---|---|---|
Equipment A | |||||
Equipment B | |||||
Equipment C | |||||
Equipment D |
Determine the production quantities of each product that maximize total revenue, while satisfying the following conditions:
- Each machine's manhours must not exceed
.
Mathematical Model
Variables
Intermediate Expressions
1. Total Profit
2. Total ManHours
Objective Function
1. Maximize Profit
Constraints
1. ManHours Limit
Expected Result
Produce
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 Product(
val profit: Flt64
) : AutoIndexed(Product::class)
data class Equipment(
val amount: UInt64,
val manHours: Map<Product, Flt64>
) : AutoIndexed(Equipment::class)
private val maxManHours = Flt64(2000)
private val products: List<Product> = ... // product data
private val equipments: List<Equipment> = ... // equipment data
// create a model instance
val metaModel = LinearMetaModel("demo8")
// define variables
val x = UIntVariable1("x", Shape1(products.size))
for (p in products) {
x[p].name = "${x.name}_${p.index}"
}
metaModel.add(x)
// define intermediate expressions
val profit = LinearExpressionSymbol(sum(products.map { p ->
p.profit * x[p]
}), "profit")
metaModel.add(profit)
val manHours = LinearIntermediateSymbols1(
"man_hours",
Shape1(equipments.size)
) { i, _ ->
val e = equipments[i]
LinearExpressionSymbol(
sum(products.mapNotNull { p -> e.manHours[p]?.let { it * x[p] } }),
"man_hours_${e.index}"
)
}
metaModel.add(manHours)
// define objective function
metaModel.maximize(profit, "profit")
// define constraints
for (e in equipments) {
metaModel.addConstraint(
manHours[e] leq e.amount.toFlt64() * maxManHours,
"eq_man_hours_${e.index}"
)
}
// solve the model
val solver = ScipLinearSolver()
when (val ret = solver(metaModel)) {
is Ok -> {
metaModel.tokens.setSolution(ret.value.solution)
}
is Failed -> {}
}
// parse results
val solution = HashMap<Product, UInt64>()
for (token in metaModel.tokens.tokens) {
if (token.result!! neq Flt64.one && token.variable.belongsTo(x)) {
solution[products[token.variable.vectorView[0]]] = token.result!!.round().toUInt64()
}
}
For the complete implementation, please refer to: