Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do basic optimisation using loco

I am trying to do a basic example of optimisation using loco.

I have a vector of costs the index of which corresponds to the integer value of a number of slots and would like to minimize the sum of the costs for a distinct subset of the slots.

Please see my attempt below, which fails to work because there is no "link" between the picked slots and the costs.

(def costs [10 10 20 20 30 30 40 40 10 10])

(let [slot-vars (for [i (range 5)] ($in [:slot i] 1 10))
      cost-vars (for [i (range 10)] ($in [:cost i] 10 40))]
  (solution
   (concat
    slot-vars
    cost-vars
    [($distinct (for [i (range 5)] [:slot i]))]
    (for [i (range 5)]
      ($= [:cost i] (get costs i))))
   :minimize (apply $+ (for [i (range 5)] [:slot i]))))
like image 505
mac Avatar asked Jul 06 '17 16:07

mac


1 Answers

First, I'm not entirely sure I understand the point of this problem, because clearly the solution is to just take the 5 smallest values in the list. But if you want to make loco do it, I agree that the knapsack constraint is a handy tool for this. Contrary to what Mike said in his comment, I don't see any obstacle to using knapsack for minimization. Let the weights all be 1, and enforce that the weights add up to 5 in order to select 5 out of the 10 slots. I've used the variable [:include i] to indicate whether slot i should be included in the subset (1 for true and 0 for false). We want to minimize the dot product of the vector of :include variables and the cost vector.

(def costs [10 10 20 20 30 30 40 40 10 10])
(def weights (repeat 10 1))

(def include-vars (for [i (range 10)] [:include i]))
(def include-constraints (for [i (range 10)] ($in [:include i] 0 1)))

(def model
  (concat
   include-constraints
   [($knapsack weights costs include-vars 5 :total)
    ($in :total 0 (apply + costs))]))

(solution model :minimize :total)

The result is:

{[:include 4] 0, [:include 6] 0, [:include 9] 1, [:include 1] 1, [:include 3] 0, [:include 8] 1, :total 60, [:include 0] 1, [:include 7] 0, [:include 2] 1, [:include 5] 0}
like image 143
puzzler Avatar answered Sep 19 '22 16:09

puzzler