1

J'ai joué avec ojAlgo et j'ai été assez excité avec ça jusqu'à présent. J'ai travaillé quelques études avec lui mais j'ai des problèmes avec ce problem described in this article. J'utilise Kotlin au lieu de Java, mais cela ne devrait pas poser de problèmes. Je suis coincé en essayant de saisir une expression dans mon modèle mais en limitant une variable plutôt qu'une valeur numérique littérale. Comment est-ce que je saisis cela?ojAlgo - Exprimer les variables comme des limites dans l'optimisation?

Voici mon travail jusqu'à présent:

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 
} 

Répondre

1

Vous ne pouvez pas faire cela. Vous ne pouvez pas directement modéliser expr1 >= expr2. Au lieu de cela, vous devez modéliser (expr1 - expr2) >= 0. Il y a un exemple sur le wiki ojAlgo décrivant comment modéliser un problème similaire: https://github.com/optimatika/ojAlgo/wiki/The-Diet-Problem

+0

Je viens de comprendre que des moments avant informés. Je vous remercie. – tmn

2

Pour les futurs lecteurs, voici la solution de travail complète que j'ai imaginée.

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 
} 

SORTIE:

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)