Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

An attempt with constraint solvers

  • Loading branch information...
commit 2ab05ed19a383ea960d3e8ea36d9f663076abe2c 1 parent c2fcf37
@lvh authored
View
3  project.clj
@@ -3,4 +3,5 @@
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
- :dependencies [[org.clojure/clojure "1.5.1"]])
+ :dependencies [[org.clojure/clojure "1.5.1"]
+ [loco "0.1.0"]])
View
30 src/hood/constraint.clj
@@ -0,0 +1,30 @@
+(ns hood.constraint
+ [:require
+ [loco.core :refer [solution]]
+ [loco.constraints :refer :all]])
+
+(defn alloc
+ "Allocates using a constraint solver.
+
+ apps is a seq of all applications.
+ budget is the total budget.
+ target is the term to optimize.
+ "
+ [apps budget target]
+ (let [n (count apps)
+ allocs (for [i (range (count apps))] [:allocation i])
+ grant-constrs (for [i (range n)]
+ ($in [:allocation i]
+ 0 (:requested (apps i))))
+ budget-constr ($<= (apply $+ allocs) budget)
+ constraints (conj grant-constrs budget-constr)]
+ (solution constraints :maximize target)))
+
+(defn linear-target
+ [apps score]
+ (let [ratios (map #(/ (score %) (:requested %)) apps)
+ scale (/ 100 (- (apply max ratios) (apply min ratios)))
+ scaled-ratios (vec (map #(long (* scale %)) ratios))
+ scaled-allocs (for [i (range (count apps))]
+ ($* [:allocation i] (scaled-ratios i)))]
+ (apply $+ scaled-allocs)))
View
36 test/hood/constraint_test.clj
@@ -0,0 +1,36 @@
+(ns hood.constraint-test
+ (:require [hood.constraint :refer :all]
+ [clojure.test :refer :all]))
+
+(def applications
+ [{:name "Alice", :score 5, :requested 120}
+ {:name "Bob", :score 4, :requested 100}
+ {:name "Carol", :score 3, :requested 80}])
+
+;; Keep in mind that most applications won't actually have a score
+;; attribute. In this case, we're doing it so that the scoring
+;; function is just :score, and that it's easy to tweak.
+
+(defn sane-target?
+ "Basic sanity checking for a target function.
+
+ Checks that this target is a sum of products of allocation vectors
+ times long weights.
+ "
+ [target]
+ (and
+ (= (:type target) :+)
+ (let [subtargets (:args target)]
+ (and
+ (= (set (map :type subtargets)) #{:*})
+ (= (map :arg1 subtargets) [[:allocation 0] [:allocation 1] [:allocation 2]])
+ (= (set (map (comp type :arg2) subtargets)) #{Long})))))
+
+(deftest target-tests
+ (testing "linear target produces k * var constraints"
+ (is (sane-target? (linear-target applications :score)))))
+
+(deftest alloc-tests
+ (testing "linear allocation of test applications"
+ (is (= (alloc applications 200 (linear-target applications :score))
+ {}))))
Please sign in to comment.
Something went wrong with that request. Please try again.