From b6102f22eea98692b9a11cf28cc7a21a3b9d8f75 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Wed, 1 Oct 2014 20:41:27 -0700 Subject: [PATCH] improvements --- csp/constraint.rkt | 80 +++++++++++------------ csp/python-constraint/constraint.py | 63 +++++++++--------- csp/python-constraint/examples/abc/abc.py | 2 +- csp/python-constraint/testconstraint.py | 6 +- csp/python-constraint/trials/abc.py | 17 +++-- 5 files changed, 82 insertions(+), 86 deletions(-) diff --git a/csp/constraint.rkt b/csp/constraint.rkt index 33b4de72..76807042 100644 --- a/csp/constraint.rkt +++ b/csp/constraint.rkt @@ -55,7 +55,7 @@ [_variables (make-hash)]) - (define (repr) (format "" _variables)) + (define (repr) (format "" (hash-keys _variables))) (define/public (custom-print out quoting-depth) (print (repr) out)) (define/public (custom-display out) (displayln (repr) out)) (define/public (custom-write out) (write (repr) out)) @@ -270,19 +270,18 @@ (define return-result #t) (define unassignedvariable _unassigned) - (report assignments) + ;(report assignments) (let/ec break - (for ([variable (in-list (report variables))]) + (for ([variable (in-list variables)]) (when (not (variable . in? . assignments)) (if (equal? unassignedvariable _unassigned) - (begin (displayln "boom") - (set! unassignedvariable variable)) + (set! unassignedvariable variable) (break)))) (when (not (equal? unassignedvariable _unassigned)) ;; Remove from the unassigned variable domain's all ;; values which break our variable's constraints. (define domain (hash-ref domains unassignedvariable)) - (report domain domain-fc) + ;(report domain domain-fc) (when (not (null? (get-field _list domain))) (for ([value (in-list (get-field _list domain))]) (hash-set! assignments unassignedvariable value) @@ -304,22 +303,20 @@ (field [_func func][_assigned assigned]) (inherit forwardCheck) - (define/override (call variables domains assignments [forwardcheck #f] [_unassigned Unassigned]) - (displayln "in call") - (report assignments assignments-before) + (define/override (call variables domains assignments [forwardcheck #f] [_unassigned Unassigned])1 + ;(report assignments assignments-before) (define parms (for/list ([x (in-list variables)]) (if (hash-has-key? assignments x) (hash-ref assignments x) _unassigned))) - (report assignments assignments-after) + ;(report assignments assignments-after) (define missing (length (filter (λ(v) (equal? v _unassigned)) parms))) - (displayln "dang") (if (> missing 0) (begin - (report missing) - (report _assigned) - (report parms) - (report (apply _func parms)) - (report forwardcheck) - (report assignments assignments-to-fc) + ;(report missing) + ;(report _assigned) + ;(report parms) + ;(report (apply _func parms)) + ;(report forwardcheck) + ;(report assignments assignments-to-fc) (and (or _assigned (apply _func parms)) (or (not forwardcheck) (not (= missing 1)) (forwardCheck variables domains assignments)))) @@ -333,7 +330,6 @@ ;; Variables ;; ---------------------------------------------------------------------- - (define Variable (class* object% (printable<%>) (super-new) @@ -381,7 +377,7 @@ (let/ec break-loop1 (set! return-k break-loop1) (let loop1 () - (displayln "starting while loop 1") + ;(displayln "starting while loop 1") ;; Mix the Degree and Minimum Remaing Values (MRV) heuristics @@ -389,14 +385,14 @@ (list (* -1 (length (hash-ref vconstraints variable))) (length (get-field _list (hash-ref domains variable))) variable)) list-comparator)) - (report lst) + ;(report lst) (let/ec break-for-loop (for ([item (in-list lst)]) (when (not ((last item) . in? . assignments)) ; Found unassigned variable (set! variable (last item)) - (report variable unassigned-variable) + ;(report variable unassigned-variable) (set! values (send (hash-ref domains variable) copy)) (set! pushdomains (if forwardcheck @@ -421,15 +417,15 @@ (for ([domain (in-list pushdomains)]) (send domain popState))) - (report variable variable-preloop-2) - (report assignments assignments-preloop-2) + ;(report variable variable-preloop-2) + ;(report assignments assignments-preloop-2) (let/ec break-loop2 (let loop2 () - (displayln "starting while loop 2") + ;(displayln "starting while loop 2") ;; We have a variable. Do we have any values left? - (report values values-tested) + ;(report values values-tested) (when (null? (get-field _list values)) ;; No. Go back to last variable, if there's one. @@ -457,20 +453,21 @@ (for ([domain (in-list pushdomains)]) (send domain pushState)) - (report pushdomains pushdomains1) - (report domains domains1) + ;(report pushdomains pushdomains1) + ;(report domains domains1) (let/ec break-for-loop (for ([cvpair (in-list (hash-ref vconstraints variable))]) (match-define (cons constraint variables) cvpair) (define the_result (send constraint call variables domains assignments pushdomains)) - (report pushdomains pushdomains2) - (report domains domains2) - (report the_result) + ;(report pushdomains pushdomains2) + ;(report domains domains2) + ;(report the_result) (when (not the_result) ;; Value is not good. (break-for-loop))) - (begin (displayln "now breaking loop 2") (break-loop2))) + (begin ;(displayln "now breaking loop 2") + (break-loop2))) (for ([domain (in-list pushdomains)]) (send domain popState)) @@ -479,7 +476,7 @@ ;; Push state before looking for next variable. (py-append! queue (list variable (get-field _list (send values copy)) pushdomains)) - (report queue new-queue) + ;(report queue new-queue) (loop1))) (if want-to-return @@ -502,14 +499,15 @@ (module+ main (define problem (new Problem)) - (send problem addVariables '("a" "b") '(1 2 3 4)) - (define (func a b) - (cond - [(and (real? b) (real? a)) (> b a)] - [(Variable? b) #t] - [else #f])) - (send problem addConstraint func '("a" "b")) + (send problem addVariables '("a" "b" "c") (range 1 10)) +; (send problem addConstraint (λ(a b) (and (> a 0) (= b (* 211 a)))) '("a" "b")) + (displayln (format "The solution to ~a is ~a" problem - (send problem getSolutions))) - ) \ No newline at end of file + (argmin (λ(h) + (let ([a (hash-ref h "a")] + [b (hash-ref h "b")] + [c (hash-ref h "c")]) + (/ (+ (* 100 a) (* 10 b) c) (+ a b c)))) + (send problem getSolutions))))) + \ No newline at end of file diff --git a/csp/python-constraint/constraint.py b/csp/python-constraint/constraint.py index 58e25d00..3ec9b1a4 100644 --- a/csp/python-constraint/constraint.py +++ b/csp/python-constraint/constraint.py @@ -376,7 +376,7 @@ class Solver(object): constraints affecting the given variables. @type vconstraints: dict """ - raise NotImplementedError, \ + NotImplementedError, \ "%s is an abstract class" % self.__class__.__name__ def getSolutions(self, domains, constraints, vconstraints): @@ -456,18 +456,18 @@ class BacktrackingSolver(Solver): queue = [] while True: - print "starting while loop 1" + #print "starting while loop 1" # Mix the Degree and Minimum Remaing Values (MRV) heuristics lst = [(-len(vconstraints[variable]), len(domains[variable]), variable) for variable in domains] lst.sort() - print "lst", lst + #print "lst", lst for item in lst: if item[-1] not in assignments: # Found unassigned variable variable = item[-1] - print "unassigned variable", variable + #print "unassigned variable", variable values = domains[variable][:] if forwardcheck: pushdomains = [domains[x] for x in domains @@ -479,10 +479,10 @@ class BacktrackingSolver(Solver): else: # No unassigned variables. We've got a solution. Go back # to last variable, if there's one. - print "solution time" - print "solution assignments", assignments + #print "solution time" + #print "solution assignments", assignments yield assignments.copy() - print "queue", queue + #print "queue", queue if not queue: return variable, values, pushdomains = queue.pop() @@ -490,12 +490,12 @@ class BacktrackingSolver(Solver): for domain in pushdomains: domain.popState() - print "variable-preloop-2", variable - print "assignments-preloop-2", assignments + #print "variable-preloop-2", variable + #print "assignments-preloop-2", assignments while True: - print "starting while loop 2" + #print "starting while loop 2" # We have a variable. Do we have any values left? - print "values tested", values + #print "values tested", values if not values: # No. Go back to last variable, if there's one. del assignments[variable] @@ -516,21 +516,20 @@ class BacktrackingSolver(Solver): if pushdomains: for domain in pushdomains: domain.pushState() - print "pushdomains1", pushdomains - print "domains1", domains + #print "pushdomains1", pushdomains + #print "domains1", domains for constraint, variables in vconstraints[variable]: the_result = constraint(variables, domains, assignments, pushdomains) - print "pushdomains2", pushdomains - print "domains2", domains - print "the_result", the_result - raise KeyError("stop") + #print "pushdomains2", pushdomains + #print "domains2", domains + #print "the_result", the_result if not the_result: # Value is not good. break else: - print "now breaking loop 2" + #print "now breaking loop 2" break if pushdomains: @@ -539,7 +538,7 @@ class BacktrackingSolver(Solver): # Push state before looking for next variable. queue.append((variable, values, pushdomains)) - print "new queue", queue + #print "new queue", queue raise RuntimeError, "Can't happen" @@ -899,11 +898,11 @@ class Constraint(object): @rtype: bool """#""" unassignedvariable = _unassigned - print "assignments", assignments + #print "assignments", assignments for variable in variables: if variable not in assignments: if unassignedvariable is _unassigned: - print "boom" + #print "boom" unassignedvariable = variable else: break @@ -912,7 +911,7 @@ class Constraint(object): # Remove from the unassigned variable domain's all # values which break our variable's constraints. domain = domains[unassignedvariable] - print "domain-fc", domain + #print "domain-fc", domain if domain: for value in domain[:]: assignments[unassignedvariable] = value @@ -959,19 +958,19 @@ class FunctionConstraint(Constraint): def __call__(self, variables, domains, assignments, forwardcheck=False, _unassigned=Unassigned): - print "in call" - print "assignments-before", assignments + #print "in call" + #print "assignments-before", assignments parms = [assignments.get(x, _unassigned) for x in variables] - print "assignments-after", assignments + #print "assignments-after", assignments missing = parms.count(_unassigned) - print "dang" + #print "dang" if missing: - print "missing", missing - print "self._assigned", self._assigned - print "parms", parms - print "self._func(*parms)", self._func(*parms) - print "forwardcheck", forwardcheck - print "assignments-to-fc", assignments + #print "missing", missing + #print "self._assigned", self._assigned + #print "parms", parms + #print "self._func(*parms)", self._func(*parms) + #print "forwardcheck", forwardcheck + #print "assignments-to-fc", assignments return ((self._assigned or self._func(*parms)) and (not forwardcheck or missing != 1 or self.forwardCheck(variables, domains, assignments))) diff --git a/csp/python-constraint/examples/abc/abc.py b/csp/python-constraint/examples/abc/abc.py index c10bc675..ddc23bb7 100755 --- a/csp/python-constraint/examples/abc/abc.py +++ b/csp/python-constraint/examples/abc/abc.py @@ -13,7 +13,7 @@ from constraint import * def main(): problem = Problem() problem.addVariables("abc", range(1,10)) - problem.getSolutions() + print min(problem.getSolutions()) minvalue = 999/(9*3) minsolution = {} for solution in problem.getSolutions(): diff --git a/csp/python-constraint/testconstraint.py b/csp/python-constraint/testconstraint.py index 5fa2b484..21dd89fc 100644 --- a/csp/python-constraint/testconstraint.py +++ b/csp/python-constraint/testconstraint.py @@ -8,8 +8,8 @@ from constraint import * #print p.getSolutions() problem = Problem() -problem.addVariables(["a", "b"], [1, 2]) +problem.addVariables(["a", "b"], range(500)) def func(a, b): - return b > a + return a > 0 and b == 211 * a problem.addConstraint(func, ["a", "b"]) -problem.getSolution() +print problem.getSolutions() diff --git a/csp/python-constraint/trials/abc.py b/csp/python-constraint/trials/abc.py index 800cf2c0..55bedaca 100755 --- a/csp/python-constraint/trials/abc.py +++ b/csp/python-constraint/trials/abc.py @@ -13,18 +13,17 @@ from constraint import * def main(): problem = Problem() problem.addVariables("abc", range(1,10)) - problem.getSolutions() - minvalue = 999/(9*3) - minsolution = {} - for solution in problem.getSolutions(): + results = [] + for solution in problem.getSolutions(): a = solution["a"] b = solution["b"] c = solution["c"] - value = (a*100+b*10+c)/(a+b+c) - if value < minvalue: - minsolution = solution - print (minsolution["a"]*100+minsolution["b"]*10+minsolution["c"])/(minsolution["a"]+minsolution["b"]+minsolution["c"]) - print minsolution + results.append((((a*100) + (b*10) + c) / (a + b + c + 0.0), (a*100) + (b*10) + c)) + + results.sort() + + print results[0] + if __name__ == "__main__": main()