Last active
October 18, 2017 01:51
-
-
Save thomasnield/8182d4d78d50a85091b86ef872545000 to your computer and use it in GitHub Desktop.
ojAlgo - The Sausage Problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import org.ojalgo.optimisation.ExpressionsBasedModel | |
| import org.ojalgo.optimisation.Variable | |
| import java.math.RoundingMode | |
| // PROBLEM DESCRIBED HERE: http://benalexkeen.com/linear-programming-with-python-and-pulp-part-4/ | |
| 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) | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment