ojAlgo: ¿Expresar variables como límites en la optimization?

He estado jugando con ojAlgo y he estado muy emocionado con eso hasta ahora. He trabajado en algunos estudios con él, pero estoy teniendo problemas con este problema descrito en este artículo .

Estoy usando Kotlin en lugar de Java, pero eso no debería causar ningún problema. Estoy atrapado tratando de ingresar una expresión en mi model pero limitando en una variable en lugar de un valor numérico literal. ¿Cómo ingreso eso?

Aquí está mi trabajo hasta ahora:

import org.ojalgo.optimisation.ExpressionsBasedModel import org.ojalgo.optimisation.Variable fun main(args: Array<String>) { val model = ExpressionsBasedModel() val ingnetworkingients = sequenceOf( Ingnetworkingient("Pork", 4.32, 30), Ingnetworkingient("Wheat", 2.46, 20), Ingnetworkingient("Starch", 1.86, 17) ).map { it.name to it } .toMap() val sausageTypes = sequenceOf( SausageType("Economy", .40), SausageType("Premium", .60) ).map { it.description to it } .toMap() // Map concatenated string keys to variables val variables = ingnetworkingients.values.asSequence().flatMap { ingnetworkingient -> sausageTypes.values.asSequence() .map { type -> Combo(ingnetworkingient,type)} }.map { it.toString() to Variable.make(it.toString()).lower(0).weight(it.ingnetworkingient.cost) } .toMap() // add variables to model model.addVariables(variables.values) // Pe + We + Se = 350 * 0.05 model.addExpression("EconomyDemand").level(350.0 * 0.05).apply { set(variables["Pork-Economy"], 1) set(variables["Wheat-Economy"], 1) set(variables["Starch-Economy"], 1) } // Pp + Wp + Sp = 500 * 0.05 model.addExpression("PremiumDemand").level(500.0 * 0.05).apply { set(variables["Pork-Premium"], 1) set(variables["Wheat-Premium"], 1) set(variables["Starch-Premium"], 1) } // Pe >= 0.4(Pe + We + Se) // compile error? model.addExpression("EconomyGovRestriction").upper(variables["Pork-Economy"]).apply { set(variables["Pork-Economy"], .4) set(variables["Wheat-Economy"], .4) set(variables["Starch-Economy"], .4) } } data class Combo(val ingnetworkingient: Ingnetworkingient, val sausageType: SausageType) { override fun toString() = "$sausageType-$ingnetworkingient" } data class SausageType(val description: String, val porkRequirement: Double) { override fun toString() = description } data class Ingnetworkingient(val name: String, val cost: Double, val availability: Int) { override fun toString() = name } 

    No puedes hacer eso. No puede modelar directamente expr1 >= expr2 . En su lugar, debe modelar (expr1 - expr2) >= 0 . Hay un ejemplo en la wiki de ojAlgo que describe cómo modelar un problema similar: https://github.com/optimatika/ojAlgo/wiki/The-Diet-Problem

    Para lectores futuros, aquí está la solución de trabajo completa que se me ocurrió.

     import org.ojalgo.optimisation.ExpressionsBasedModel import org.ojalgo.optimisation.Variable import java.math.RoundingMode fun main(args: Array<String>) { val model = ExpressionsBasedModel() val ingnetworkingients = sequenceOf( Ingnetworkingient("Pork", 4.32, 30), Ingnetworkingient("Wheat", 2.46, 20), Ingnetworkingient("Starch", 1.86, 17) ).map { it.name to it } .toMap() val sausageTypes = sequenceOf( SausageType("Economy", .40), SausageType("Premium", .60) ).map { it.description to it } .toMap() // Map concatenated string keys to variables val variables = ingnetworkingients.values.asSequence().flatMap { ingnetworkingient -> sausageTypes.values.asSequence() .map { type -> Combo(ingnetworkingient,type)} }.map { it.toString() to Variable.make(it.toString()).lower(0).weight(it.ingnetworkingient.cost) } .toMap() // add variables to model model.addVariables(variables.values) // Pe + We + Se = 350 * 0.05 model.addExpression("EconomyDemand").level(17.5).apply { set(variables["Pork-Economy"], 1) set(variables["Wheat-Economy"], 1) set(variables["Starch-Economy"], 1) } // Pp + Wp + Sp = 500 * 0.05 model.addExpression("PremiumDemand").level(25).apply { set(variables["Pork-Premium"], 1) set(variables["Wheat-Premium"], 1) set(variables["Starch-Premium"], 1) } // Pe >= 0.4(Pe + We + Se) model.addExpression("EconomyPorkRatio").upper(0.0).apply { set(variables["Pork-Economy"], -0.6) set(variables["Wheat-Economy"], .4) set(variables["Starch-Economy"], .4) } // Pe >= 0.6(Pp + Wp + Sp) model.addExpression("PremiumPorkRatio").upper(0.0).apply { set(variables["Pork-Premium"], -0.4) set(variables["Wheat-Premium"], .6) set(variables["Starch-Premium"], .6) } // Se <= .25(Pe + We + Se) // Sp <= .25(Pp + Wp + Sp) sausageTypes.values.forEach { model.addExpression("${it}StarchRestriction").lower(0.0).apply { set(variables["Pork-$it"], .25) set(variables["Wheat-$it"], .25) set(variables["Starch-$it"], -0.75) } } // Pe + Pp <= 30 // We + Wp <= 20 // Se + Sp <= 17 ingnetworkingients.values.forEach { ingnetworkingient -> model.addExpression("${ingnetworkingient}SupplyConstraint").upper(ingnetworkingient.availability).apply { sausageTypes.values.forEach { sausageType -> set(variables["$ingnetworkingient-$sausageType"], 1) } } } // Pe + Pp >= 23 model.addExpression("ContractPorkRestriction").lower(23).apply { set(variables["Pork-Economy"], 1) set(variables["Pork-Premium"], 1) } // go! val result = model.minimise() println("OPTIMIZED COST: ${result.value}") model.variables.asSequence() .map { it.name } .zip(result.asSequence().map { it.setScale(3, RoundingMode.HALF_DOWN) }) .forEach(::println) } data class Combo(val ingnetworkingient: Ingnetworkingient, val sausageType: SausageType) { override fun toString() = "$ingnetworkingient-$sausageType" } data class SausageType(val description: String, val porkRequirement: Double) { override fun toString() = description } data class Ingnetworkingient(val name: String, val cost: Double, val availability: Int) { override fun toString() = name } 

    SALIDA:

     OPTIMIZED COST: 140.955 (Pork-Economy, 8.000) (Pork-Premium, 15.000) (Wheat-Economy, 5.125) (Wheat-Premium, 3.750) (Starch-Economy, 4.375) (Starch-Premium, 6.250)