ojAlgo – Выражение переменных как границ в оптимизации?

Я играю с ojAlgo, и до сих пор я был в восторге от этого. Я проработал несколько исследований, но у меня возникли проблемы с этой проблемой, описанной в этой статье .

Я использую Kotlin вместо Java, но это не должно вызывать никаких проблем. Я застрял, пытаясь ввести выражение в мою модель, но ограничивая переменную, а не буквенное числовое значение. Как это ввести?

Вот моя работа:

import org.ojalgo.optimisation.ExpressionsBasedModel import org.ojalgo.optimisation.Variable fun main(args: Array<String>) { val model = ExpressionsBasedModel() val ingredients = sequenceOf( Ingredient("Pork", 4.32, 30), Ingredient("Wheat", 2.46, 20), Ingredient("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 = ingredients.values.asSequence().flatMap { ingredient -> sausageTypes.values.asSequence() .map { type -> Combo(ingredient,type)} }.map { it.toString() to Variable.make(it.toString()).lower(0).weight(it.ingredient.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 ingredient: Ingredient, val sausageType: SausageType) { override fun toString() = "$sausageType-$ingredient" } data class SausageType(val description: String, val porkRequirement: Double) { override fun toString() = description } data class Ingredient(val name: String, val cost: Double, val availability: Int) { override fun toString() = name } 

    Вы не можете этого сделать. Вы не можете напрямую моделировать expr1 >= expr2 . Вместо этого вам нужно моделировать (expr1 - expr2) >= 0 . В вики ojAlgo есть пример, описывающий, как моделировать аналогичную проблему: https://github.com/optimatika/ojAlgo/wiki/The-Diet-Problem

    Для будущих читателей, вот полное рабочее решение, которое я придумал.

     import org.ojalgo.optimisation.ExpressionsBasedModel import org.ojalgo.optimisation.Variable import java.math.RoundingMode fun main(args: Array<String>) { val model = ExpressionsBasedModel() val ingredients = sequenceOf( Ingredient("Pork", 4.32, 30), Ingredient("Wheat", 2.46, 20), Ingredient("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 = ingredients.values.asSequence().flatMap { ingredient -> sausageTypes.values.asSequence() .map { type -> Combo(ingredient,type)} }.map { it.toString() to Variable.make(it.toString()).lower(0).weight(it.ingredient.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 ingredients.values.forEach { ingredient -> model.addExpression("${ingredient}SupplyConstraint").upper(ingredient.availability).apply { sausageTypes.values.forEach { sausageType -> set(variables["$ingredient-$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 ingredient: Ingredient, val sausageType: SausageType) { override fun toString() = "$ingredient-$sausageType" } data class SausageType(val description: String, val porkRequirement: Double) { override fun toString() = description } data class Ingredient(val name: String, val cost: Double, val availability: Int) { override fun toString() = name } 

    ВЫВОД:

     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)