1

나는 ojAlgo로 놀아 왔고, 지금까지 꽤 흥분했습니다. 나는 그것으로 약간의 연구를 통해 일했지만이 문제가있는 problem described in this article.ojAlgo - 최적화에서 변수를 경계로 표현 하시겠습니까?

Java 대신 Kotlin을 사용하고 있지만 문제가 발생하지 않습니다. 내 모델에 표현식을 입력하려고 시도했지만 문자 그대로 숫자 값이 아니라 변수에 경계를 표시하려고했습니다. 어떻게 입력합니까? 당신은 할 수 없습니다

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 
} 

답변

1

:

여기에 지금까지 내 작품이다. expr1 >= expr2을 직접 모델링 할 수 없습니다. 대신 (expr1 - expr2) >= 0을 모델링해야합니다. 유사한 문제를 모델링하는 방법을 설명하는 ojAlgo 위키의 예가 있습니다 : https://github.com/optimatika/ojAlgo/wiki/The-Diet-Problem

+0

난 그냥 순간 그것을 알아 냈어. 고맙습니다. – tmn

2

앞으로의 독자를 위해, 여기에 나온 전체 해결책이 있습니다.

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 
} 

OUTPUT : 당신이 게시하기 전에

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)