Example 5: Knapsack Problem
Problem Description
There are several items, each with corresponding value and weight.
| Item A | Item B | Item C | Item D | Item E | |
|---|---|---|---|---|---|
| Weight | |||||
| Value |
Objective: Select a subset of these items to maximize total value, while satisfying the following condition:
- The total weight of selected items does not exceed
.
Mathematical Model
Variables
Intermediate Values
1. Total Value
2. Total Weight
Objective Function
1. Maximize Total Value
Constraints
1. Total Weight Does Not Exceed Maximum Weight
Expected Results
Select items A, B, and E.
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 Cargo(
val weight: UInt64,
val value: UInt64
) : AutoIndexed(Cargo::class)
val cargos: List<Cargo> = ... // Item list
val maxWeight = UInt64(10U)
// Create model instance
val metaModel = LinearMetaModel("demo5")
// Define variables
val x = BinVariable1("x", Shape1(cargos.size))
for (c in cargos) {
x[c].name = "${x.name}_${c.index}"
}
metaModel.add(x)
// Define intermediate values
val cargoValue = LinearExpressionSymbol(sum(cargos) { c -> c.value * x[c] }, "value")
metaModel.add(cargoValue)
val cargoWeight = LinearExpressionSymbol(sum(cargos) { c -> c.weight * x[c] }, "weight")
metaModel.add(cargoWeight)
// Define objective function
metaModel.maximize(cargoValue, "value")
// Define constraints
metaModel.addConstraint(
cargoWeight leq maxWeight,
"weight"
)
// 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 = HashSet<Cargo>()
for (token in metaModel.tokens.tokens) {
if (token.result!! eq Flt64.one && token.variable.belongsTo(x)) {
solution.add(cargos[token.variable.vectorView[0]])
}
}Complete Implementation Reference: