Skip to content

Instantly share code, notes, and snippets.

@krishnanraman
Created September 4, 2014 19:25
Show Gist options
  • Save krishnanraman/fa2421c4b4225e79c62f to your computer and use it in GitHub Desktop.
Save krishnanraman/fa2421c4b4225e79c62f to your computer and use it in GitHub Desktop.
import org.apache.commons.math3.optim.linear._
import org.apache.commons.math3.optim._
import scala.collection.JavaConverters._
object simplex extends App {
type D = Double
def mkStr( x:(D,D,D,D,D,D,D,D)) = {
val (ham,lettuce,cheese,tuna,bread, weight, cost, calories) = x
"Ham %.2f Lettuce %.2f Cheese %.2f Tuna %.2f Bread %.2f Weight %.2f Cost %.2f Calories %.2f".format( ham,lettuce,cheese,tuna,bread,weight,cost,calories)
}
case class Item(price:D, calories:D, weight:D = 1.0)
val (ham, lettuce, cheese, tuna, bread) = (Item(4, 650), Item(1.5, 70), Item(5, 1670), Item(20, 830), Item(1.2, 1300))
val groceries = Array(ham, lettuce, cheese, tuna, bread)
val prices = groceries.map{ g => g.price }
val calories = groceries.map{ g => g.calories }
val weights = groceries.map{ g => g.weight }
val (maxCost, minCalories, maxCalories) = (100.0, 14000.0, 14100.0)
val (zeroPound, fourOunce, tenPound) = (0.0, 4/16.0, 10.0) // 16 ounces per pound
def solver = {
val range = (fourOunce to tenPound by fourOunce)
for{
h <- range; l <- range; c <- range; t <- range; b <- range // cartesian product of ham, lettuce, cheese, ...
all = List(h,l,c,t,b)
if ((all.sum > zeroPound) && (all.sum <= tenPound)) // basic sanity checks
// make ten constraints
cost = new LinearObjectiveFunction(prices, maxCost) // constraint 1. prices <= $100
nonneg = new NonNegativeConstraint(true) // constraint 2. Only want positive weights
calMin = new LinearConstraint(calories, Relationship.GEQ, minCalories) // constraint 3. calories >= 14000
calMax = new LinearConstraint(calories, Relationship.LEQ, maxCalories) // constraint 4. calories <= 14100
totalWeight = new LinearConstraint(weights, Relationship.LEQ, tenPound) // constraint 5. weights <= 10 lb
constraints = new LinearConstraintSet( { List(calMin, calMax, totalWeight) ++
{ all // constraints 6 thru 10. Want each grocery item to have a minimum weight
.zipWithIndex
.map { case (min, idx) => (min, Array.tabulate[Double](5){ i=> if (i == idx) 1.0 else 0.0 }) }
.map { case (min, array) => new LinearConstraint(array, Relationship.GEQ,min) }
}}.asJava )
optimum = try {
Some(new SimplexSolver().optimize(cost, constraints, nonneg).getFirst)
} catch { case e:Exception => None }
} yield optimum
}
solver
.flatten
.map{ optimum =>
val (h,l,c,t,b) = (optimum(0), optimum(1), optimum(2), optimum(3), optimum(4))
val totalWeight = optimum.sum
val totalCost = optimum.zip(prices).map{ case (weight,price) => weight * price }.sum
val totalCalories = optimum.zip(calories).map{ case (weight,cals) => weight * cals }.sum
mkStr((h,l,c,t,b,totalWeight, totalCost, totalCalories))
}
.distinct
.zipWithIndex
.foreach { case (str,idx) => println(idx + "." + str) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment