From d65248e80c07ca9544a41162ced7a1fc3a8fd864 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Thu, 25 Oct 2018 13:03:10 -0700 Subject: [PATCH] purge --- csp/csp/port/constraint.rkt | 129 -- csp/csp/port/domain.rkt | 63 - csp/csp/port/helper.rkt | 83 - csp/csp/port/main.rkt | 13 - csp/csp/port/problem.rkt | 118 -- csp/csp/port/solver.rkt | 120 -- csp/csp/port/test-classes.rkt | 74 - csp/csp/port/test-einstein.rkt | 168 -- csp/csp/port/test-problems.rkt | 152 -- csp/csp/port/variable.rkt | 17 - .../API Documentation.webloc | 8 - csp/csp/python-constraint/LICENSE | 23 - csp/csp/python-constraint/MANIFEST.in | 2 - csp/csp/python-constraint/PKG-INFO | 13 - csp/csp/python-constraint/README | 1 - csp/csp/python-constraint/constraint.py | 1469 ----------------- csp/csp/python-constraint/examples/abc/abc.py | 30 - .../python-constraint/examples/coins/coins.py | 30 - .../examples/crosswords/crosswords.py | 153 -- .../examples/crosswords/large.mask | 27 - .../examples/crosswords/medium.mask | 19 - .../examples/crosswords/python.mask | 8 - .../examples/crosswords/small.mask | 8 - .../examples/einstein/einstein.py | 201 --- .../examples/einstein/einstein2.py | 190 --- .../examples/queens/queens.py | 47 - .../python-constraint/examples/rooks/rooks.py | 49 - .../examples/studentdesks/studentdesks.py | 39 - .../examples/sudoku/sudoku.py | 61 - .../examples/wordmath/seisseisdoze.py | 32 - .../examples/wordmath/sendmoremoney.py | 34 - .../examples/wordmath/twotwofour.py | 28 - .../python-constraint/examples/xsum/xsum.py | 37 - csp/csp/python-constraint/setup.cfg | 6 - csp/csp/python-constraint/setup.py | 21 - csp/csp/python-constraint/testconstraint.py | 13 - csp/csp/python-constraint/trials/abcd.py | 29 - csp/csp/python-constraint/trials/coins.py | 30 - .../python-constraint/trials/constraint.py | 1434 ---------------- .../python-constraint/trials/crosswords.py | 153 -- csp/csp/python-constraint/trials/einstein.py | 201 --- csp/csp/python-constraint/trials/einstein2.py | 190 --- csp/csp/python-constraint/trials/large.mask | 27 - csp/csp/python-constraint/trials/medium.mask | 19 - csp/csp/python-constraint/trials/python.mask | 8 - csp/csp/python-constraint/trials/queens.py | 47 - csp/csp/python-constraint/trials/rooks.py | 49 - .../python-constraint/trials/seisseisdoze.py | 32 - .../python-constraint/trials/sendmoremoney.py | 34 - csp/csp/python-constraint/trials/small.mask | 8 - .../python-constraint/trials/studentdesks.py | 39 - csp/csp/python-constraint/trials/sudoku.py | 61 - .../python-constraint/trials/twotwofour.py | 28 - csp/csp/python-constraint/trials/xsum.py | 37 - 54 files changed, 5912 deletions(-) delete mode 100644 csp/csp/port/constraint.rkt delete mode 100644 csp/csp/port/domain.rkt delete mode 100644 csp/csp/port/helper.rkt delete mode 100644 csp/csp/port/main.rkt delete mode 100644 csp/csp/port/problem.rkt delete mode 100644 csp/csp/port/solver.rkt delete mode 100644 csp/csp/port/test-classes.rkt delete mode 100644 csp/csp/port/test-einstein.rkt delete mode 100644 csp/csp/port/test-problems.rkt delete mode 100644 csp/csp/port/variable.rkt delete mode 100644 csp/csp/python-constraint/API Documentation.webloc delete mode 100644 csp/csp/python-constraint/LICENSE delete mode 100644 csp/csp/python-constraint/MANIFEST.in delete mode 100644 csp/csp/python-constraint/PKG-INFO delete mode 100644 csp/csp/python-constraint/README delete mode 100644 csp/csp/python-constraint/constraint.py delete mode 100755 csp/csp/python-constraint/examples/abc/abc.py delete mode 100755 csp/csp/python-constraint/examples/coins/coins.py delete mode 100755 csp/csp/python-constraint/examples/crosswords/crosswords.py delete mode 100644 csp/csp/python-constraint/examples/crosswords/large.mask delete mode 100644 csp/csp/python-constraint/examples/crosswords/medium.mask delete mode 100644 csp/csp/python-constraint/examples/crosswords/python.mask delete mode 100644 csp/csp/python-constraint/examples/crosswords/small.mask delete mode 100755 csp/csp/python-constraint/examples/einstein/einstein.py delete mode 100755 csp/csp/python-constraint/examples/einstein/einstein2.py delete mode 100755 csp/csp/python-constraint/examples/queens/queens.py delete mode 100755 csp/csp/python-constraint/examples/rooks/rooks.py delete mode 100755 csp/csp/python-constraint/examples/studentdesks/studentdesks.py delete mode 100644 csp/csp/python-constraint/examples/sudoku/sudoku.py delete mode 100755 csp/csp/python-constraint/examples/wordmath/seisseisdoze.py delete mode 100755 csp/csp/python-constraint/examples/wordmath/sendmoremoney.py delete mode 100755 csp/csp/python-constraint/examples/wordmath/twotwofour.py delete mode 100755 csp/csp/python-constraint/examples/xsum/xsum.py delete mode 100644 csp/csp/python-constraint/setup.cfg delete mode 100755 csp/csp/python-constraint/setup.py delete mode 100644 csp/csp/python-constraint/testconstraint.py delete mode 100755 csp/csp/python-constraint/trials/abcd.py delete mode 100755 csp/csp/python-constraint/trials/coins.py delete mode 100644 csp/csp/python-constraint/trials/constraint.py delete mode 100755 csp/csp/python-constraint/trials/crosswords.py delete mode 100755 csp/csp/python-constraint/trials/einstein.py delete mode 100755 csp/csp/python-constraint/trials/einstein2.py delete mode 100644 csp/csp/python-constraint/trials/large.mask delete mode 100644 csp/csp/python-constraint/trials/medium.mask delete mode 100644 csp/csp/python-constraint/trials/python.mask delete mode 100755 csp/csp/python-constraint/trials/queens.py delete mode 100755 csp/csp/python-constraint/trials/rooks.py delete mode 100755 csp/csp/python-constraint/trials/seisseisdoze.py delete mode 100755 csp/csp/python-constraint/trials/sendmoremoney.py delete mode 100644 csp/csp/python-constraint/trials/small.mask delete mode 100755 csp/csp/python-constraint/trials/studentdesks.py delete mode 100644 csp/csp/python-constraint/trials/sudoku.py delete mode 100755 csp/csp/python-constraint/trials/twotwofour.py delete mode 100755 csp/csp/python-constraint/trials/xsum.py diff --git a/csp/csp/port/constraint.rkt b/csp/csp/port/constraint.rkt deleted file mode 100644 index d73fcd2e..00000000 --- a/csp/csp/port/constraint.rkt +++ /dev/null @@ -1,129 +0,0 @@ -#lang racket/base -(require racket/class racket/bool sugar/unstable/container sugar/list sugar/debug racket/list "helper.rkt" "variable.rkt") -(provide (all-defined-out)) - -(define constraint% - (class object% - (super-new) - - (define/public (is-true? variables domains assignments [forward-check? #f]) - ;; Perform the constraint checking - - ;; If the forwardcheck parameter is not false, besides telling if - ;; the constraint is currently broken or not, the constraint - ;; implementation may choose to hide values from the domains of - ;; unassigned variables to prevent them from being used, and thus - ;; prune the search space. - #t) - - (define/public (preprocess variables domains constraints vconstraints) - ;; todo: functionalize this - ;; Preprocess variable domains - ;; This method is called before starting to look for solutions, - ;; and is used to prune domains with specific constraint logic - ;; when possible. For instance, any constraints with a single - ;; variable may be applied on all possible values and removed, - ;; since they may act on individual values even without further - ;; knowledge about other assignments. - (when (= (length variables) 1) - (define variable (car variables)) - (define domain (hash-ref domains variable)) - (set-field! _list domain - (for/fold ([domain-values (domain)]) - ([value (in-list (domain))] - #:unless (is-true? variables domains (make-hash (list (cons variable value))))) - (remove value domain-values))) - (set! constraints (remove (list this variables) constraints)) - (hash-update! vconstraints variable (λ(val) (remove (list this variables) val))))) - - ;; Helper method for generic forward checking - ;; Currently, this method acts only when there's a single - ;; unassigned variable. - (define/public (forward-check variables domains assignments [_unassigned Unassigned]) - (define unassigned-variables - (filter-not (λ(v) (hash-has-key? assignments v)) variables)) - (cond - ;; Remove from the unassigned variable's domain - ;; all values that break our variable's constraints. - [(= (length unassigned-variables) 1) - (define unassigned-variable (car unassigned-variables)) - (define unassigned-variable-domain (hash-ref domains unassigned-variable)) - (for ([value (in-list (unassigned-variable-domain))]) - (hash-set! assignments unassigned-variable value) - (unless (is-true? variables domains assignments) - (send unassigned-variable-domain hide-value value))) - (hash-remove! assignments unassigned-variable) - (not (empty? unassigned-variable-domain))] ; if domain had no remaining values, the constraint will be impossible to meet, so return #f - [else #t])) - )) - -(define constraint%? (is-a?/c constraint%)) - -(define function-constraint% - (class constraint% - (super-new) - - (init-field func [assigned #t]) - - (field [_func func][_assigned assigned]) - - (inherit forward-check) - - (define/override (is-true? variables domains assignments [forward-check? #f] [_unassigned Unassigned]) - (define parms (map (λ(v) (hash-ref assignments v _unassigned)) variables)) - (define missing (length (filter (λ(p) (equal? p _unassigned)) parms))) - (if (> missing 0) - (and (or _assigned (apply _func parms)) - (or (not forward-check?) (not (= missing 1)) - (forward-check variables domains assignments))) - (apply _func parms))))) - -(define function-constraint%? (is-a?/c function-constraint%)) - -;; Constraint enforcing that values of all given variables are different -(define all-different-constraint% - (class constraint% - (super-new) - - (define/override (is-true? variables domains assignments [forward-check? #f] [_unassigned Unassigned]) - (define-values (assigned-vars unassigned-vars) - (partition (λ(var) (hash-has-key? assignments var)) variables)) - (define assigned-values (map (λ(var) (hash-ref assignments var)) assigned-vars)) - (cond - [(not (members-unique? assigned-values)) #f] ; constraint failed because they're not all different - [(and forward-check? - (for*/or ([unassigned-var-domain (in-list (map (λ(uv) (hash-ref domains uv)) unassigned-vars))] - [assigned-value (in-list assigned-values)] - #:when (member assigned-value (unassigned-var-domain))) - (send unassigned-var-domain hide-value assigned-value) - (empty? unassigned-var-domain))) #f] ; if domain had no remaining values, the constraint will be impossible to meet, so return #f - [else #t])))) - -(define all-different-constraint%? (is-a?/c all-different-constraint%)) - -;; Constraint enforcing that values of all given variables are different -(define all-equal-constraint% - (class constraint% - (super-new) - - (define/override (is-true? variables domains assignments [forward-check? #f] [_unassigned Unassigned]) - (define-values (assigned-vars unassigned-vars) - (partition (λ(var) (hash-has-key? assignments var)) variables)) - (define assigned-values (map (λ(var) (hash-ref assignments var)) assigned-vars)) - (define single-value (if (not (empty? assigned-values)) - (car assigned-values) - _unassigned)) - (cond - [(not (andmap (λ(v) (equal? single-value v)) assigned-values)) #f] ; constraint broken: not all values the same - [(and forward-check? (not (equal? single-value _unassigned))) - (for/and ([unassigned-var-domain (in-list (map (λ(uv) (hash-ref domains uv)) unassigned-vars))]) - ;; if single-value is not a member of each domain, constraint will be broken later, so bail out - (and (member single-value (unassigned-var-domain)) - (for ([value (in-list (unassigned-var-domain))] - #:unless (equal? value single-value)) - (send unassigned-var-domain hide-value value))))] ; otherwise hide nonconforming values - [else #t])))) - - -(define all-equal-constraint%? (is-a?/c all-equal-constraint%)) - diff --git a/csp/csp/port/domain.rkt b/csp/csp/port/domain.rkt deleted file mode 100644 index dccc55d9..00000000 --- a/csp/csp/port/domain.rkt +++ /dev/null @@ -1,63 +0,0 @@ -#lang racket/base -(require racket/class racket/list "helper.rkt") -(provide (all-defined-out)) - -;; Class used to control possible values for variables -;; When list or tuples are used as domains, they are automatically -;; converted to an instance of that class. -(define domain% - (class* object% (printable<%> (make-proc<%> get-values)) - (super-new) - (init-field set) - (field [_list set][_hidden null][_states null]) - - (define (repr) (format "" _list)) - (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)) - - (define/public (reset-state) - ;; Reset to the original domain state, including all possible values - (py-extend! _list _hidden) - (set! _hidden null) - (set! _states null)) - - (define/public (push-state) - ;; Save current domain state - ;; Variables hidden after that call are restored when that state - ;; is popped from the stack. - (py-append! _states (length _list))) - - (define/public (pop-state) - ;; Restore domain state from the top of the stack - - ;; Variables hidden since the last popped state are then available - ;; again. - (define diff (- (py-pop! _states) (length _list))) - (when (not (= 0 diff)) - (py-extend! _list (take-right _hidden diff)) - (set! _hidden (take _hidden (- (length _hidden) diff))))) - - (define/public (hide-value value) - ;; Hide the given value from the domain - - ;; After that call the given value won't be seen as a possible value - ;; on that domain anymore. The hidden value will be restored when the - ;; previous saved state is popped. - (set! _list (remove value _list)) - (py-append! _hidden value)) - - (define/public (get-values) - _list) - - (define/public (domain-pop!) - (py-pop! _list)) - - (define/public (copy) - (define copied-domain (new domain% [set _list])) - (set-field! _hidden copied-domain _hidden) - (set-field! _states copied-domain _states) - copied-domain))) - -(define domain%? (is-a?/c domain%)) - diff --git a/csp/csp/port/helper.rkt b/csp/csp/port/helper.rkt deleted file mode 100644 index c607c9ea..00000000 --- a/csp/csp/port/helper.rkt +++ /dev/null @@ -1,83 +0,0 @@ -#lang racket/base -(require racket/class racket/list (for-syntax racket/base racket/syntax)) -(provide (all-defined-out)) -(require rackunit) - -(define-syntax-rule (forever expr ...) - (for ([i (in-naturals)]) - expr ...)) - -(define-syntax-rule (forever/until expr ...) - (for/or ([i (in-naturals)]) - expr ...)) - -(define-syntax-rule (for-each-send proc objects) - (for-each (λ(o) (send o proc)) objects)) - -(define-syntax-rule (make-proc<%> proc-name) - (interface* () - ([prop:procedure - (λ(this . args) - (send/apply this proc-name args))]) - proc-name)) - -(define-simple-check (check-hash-items h1 h2) - (for/and ([(k1 v1) (in-hash h1)]) - (equal? (hash-ref h2 k1) v1))) - -(define (list-comparator xs ys) - ;; For use in sort. Compares two lists element by element. - (cond - [(equal? xs ys) #f] ; elements are same, so no sort preference - [(and (null? xs) (not (null? ys))) #t] ; ys is longer, so #t - [(and (not (null? xs)) (null? ys)) #f] ; xs is longer, so #f makes it sort later - [else (let ([x (car xs)][y (car ys)]) - (cond - [(equal? x y) (list-comparator (cdr xs) (cdr ys))] - [(and (real? x) (real? y)) (< x y)] - [(and (symbol? x) (symbol? y)) (apply stringstring (list x y)))] - [(and (string? x) (string? y)) (stringm void?)] - [set-solver (solver%? . ->m . void?)] - [get-solver (->m solver%?)] - [add-variable (any/c (or/c list? domain%?) . ->m . void?)] - [add-variables ((listof any/c) (or/c list? domain%?) . ->m . void?)] - [add-constraint (((or/c constraint%? procedure?)) ((listof any/c)) . ->*m . void?)] - [get-solution (->m any/c)] - [get-solutions (->m list?)]) - - (class* object% (printable<%>) - (super-new) - - (init-field [solver #f]) - (field [_solver (or solver (new backtracking-solver%))] - [_constraints #f] - [_variable-domains #f]) - - (reset) ; use method rather than manually set up fields - - ;; implement object printing - (define (repr) (format "" (hash-keys _variable-domains))) - (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)) - - ;; Reset the current problem definition - (define/public (reset) - (set! _constraints null) - (set! _variable-domains (make-hash))) - - ;; Set the problem solver currently in use - (define/public (set-solver solver) - (set! _solver solver)) - - ;; Get the problem solver currently in use - (define/public (get-solver) - _solver) - - ;; Add a variable to the problem - ;; Contract insures input is Domain object or list of values. - (define/public (add-variable variable domain-or-values) - (when (hash-has-key? _variable-domains variable) - (error 'add-variable (format "Tried to insert duplicated variable ~a" variable))) - (define domain (if (domain%? domain-or-values) - (send domain-or-values copy) - (new domain% [set domain-or-values]))) - (when (null? (domain)) - (error 'add-variable "domain value is null")) - (hash-set! _variable-domains variable domain)) - - ;; Add one or more variables to the problem - (define/public (add-variables variables domain) - (define in-thing (cond - [(string? variables) in-string] - [(list? variables) in-list] - [else (error 'add-variables (format "Don’t know what to do with ~a" variables))])) - (for ([var (in-thing variables)]) - (add-variable var domain))) - - ;; Add a constraint to the problem - ;; contract guarantees input is procedure or constraint% object - (define/public (add-constraint constraint-or-proc [variables null]) - (define constraint (if (procedure? constraint-or-proc) - (new function-constraint% [func constraint-or-proc]) - constraint-or-proc)) - (py-append! _constraints (list constraint variables))) - - (define-syntax-rule (solution-macro solution-proc null-proc) - (begin - (define-values (domains constraints vconstraints) (get-args)) - (if (null? domains) - (if null-proc (null-proc null) null) - (send _solver solution-proc domains constraints vconstraints)))) - - ;; Find and return a solution to the problem - (define/public (get-solution) - (solution-macro get-solution #f)) - - ;; Find and return all solutions to the problem - (define/public (get-solutions) - (solution-macro get-solutions #f)) - - ;; Return an iterator to the solutions of the problem - (define/public (get-solution-iter) - (solution-macro get-solution-iter yield)) - - (define/private (get-args) - (define variable-domains (hash-copy _variable-domains)) - - (define constraints - (let ([all-variables (hash-keys variable-domains)]) - (for/list ([(constraint variables) (in-parallel (map first _constraints) (map second _constraints))]) - (list constraint (if (null? variables) all-variables variables))))) - - (define vconstraints - (hash-copy ; converts for/hash to mutable hash - (for/hash ([variable (in-hash-keys variable-domains)]) - (values variable null)))) - - (for* ([(constraint variables) (in-parallel (map first constraints) (map second constraints))] - [variable (in-list variables)]) - (hash-update! vconstraints variable (λ(val) (cons (list constraint variables) val)))) - - (for ([(constraint variables) (in-parallel (map first constraints) (map second constraints))]) - (send constraint preprocess variables variable-domains constraints vconstraints)) - - (if (for/or ([domain (in-hash-values variable-domains)]) - (send domain reset-state) - (null? (domain))) - (values null null null) - (values variable-domains constraints vconstraints))))) \ No newline at end of file diff --git a/csp/csp/port/solver.rkt b/csp/csp/port/solver.rkt deleted file mode 100644 index 742e63bd..00000000 --- a/csp/csp/port/solver.rkt +++ /dev/null @@ -1,120 +0,0 @@ -#lang racket/base -(require racket/class sugar/unstable/container sugar/debug racket/list - racket/bool racket/generator racket/match "helper.rkt") -(provide (all-defined-out)) - -(define solver% - ;; Abstract base class for solvers - (class object% - (super-new) - (abstract get-solution) - (abstract get-solutions) - (abstract get-solution-iter))) - -(define solver%? (is-a?/c solver%)) - -(struct vvp (variable values pushdomains)) -(define-syntax-rule (pop-vvp-values! vvps) - (if (empty? vvps) - (error 'pop-vvp-values! (format "~a is null" vvps)) - (let ([vvp (car vvps)]) - (set! vvps (cdr vvps)) - (values (vvp-variable vvp) (vvp-values vvp) (vvp-pushdomains vvp))))) - -#| -(define (recursive-backtracking assignment csp) - (if (complete? assignment) - assignment - (let ([var (select-unassigned-variable csp-variables, assignment, csp)]) - (for/or ([value (in-list (order-domain-values var assignment csp))]) - if ((value . consistent-with? . assignment csp-constraints)) - (add-to assignment var value) - (define result (recursive-backtracking assignment csp)) - (when result - (and result (remove-from assignment var value))) - #f)))) -|# - -(define backtracking-solver% - ;; Problem solver with backtracking capabilities - (class solver% - (super-new) - (init-field [forwardcheck #t]) - (field [_forwardcheck forwardcheck]) - - (define/override (get-solution-iter domains constraints vconstraints) - (define sorted-variables (sort (hash-keys domains) list-comparator - #:key (λ(var) - (list (- (length (hash-ref vconstraints var))) - (length ((hash-ref domains var))) - var)))) - ;; state-retention variables - (define possible-solution (make-hash)) - (define variable-queue null) - (define variable #f) - (define values null) - (define pushdomains null) - - (define (get-next-unassigned-variable) - (for/first ([sorted-variable (in-list sorted-variables)] - #:unless (hash-has-key? possible-solution sorted-variable)) - (set! variable sorted-variable) - (set! values ((hash-ref domains variable))) - (set! pushdomains - (if _forwardcheck - (for/list ([(var domain) (in-hash domains)] - #:unless (and (equal? variable var) - (hash-has-key? possible-solution var))) - domain) - null)) - variable)) - - (define (set!-previous-variable) - (set!-values (variable values pushdomains) (pop-vvp-values! variable-queue)) - (for-each-send pop-state pushdomains)) - - (let/ec exit-k - ;; mix the degree and minimum-remaining-values (MRV) heuristics - (forever - (unless (get-next-unassigned-variable) - (yield (hash-copy possible-solution)) ; if there are no unassigned variables, solution is complete. - (if (empty? variable-queue) - (exit-k) ; all done, no other solutions possible. - (set!-previous-variable))) ; otherwise return to previous variable - - (let value-checking-loop () ; we have a variable. Do we have any values left? - (when (empty? values) ; no, so try going back to last variable and getting some values - (forever/until - (when (empty? variable-queue) (exit-k)) ; no variables left, so solver is done - (hash-remove! possible-solution variable) - (set!-previous-variable) - (not (empty? values)))) - - ;; Got a value. Check it. - (hash-set! possible-solution variable (car-pop! values)) - (for-each-send push-state pushdomains) - (unless (for/and ([constraint+variables (in-list (hash-ref vconstraints variable))]) - (let ([constraint (car constraint+variables)] - [variables (cadr constraint+variables)]) - (send constraint is-true? variables domains possible-solution pushdomains))) - ;; constraint failed, so try again - (for-each-send pop-state pushdomains) - (value-checking-loop))) - - ;; Push state before looking for next variable. - (set! variable-queue (cons (vvp variable values pushdomains) variable-queue))) - (error 'get-solution-iter "impossible to reach this")) - (void)) - - - (define (call-solution-generator domains constraints vconstraints #:first-only [first-only #f]) - (for/list ([solution (in-generator (get-solution-iter domains constraints vconstraints))] #:final first-only) - solution)) - - (define/override (get-solution . args) - (car (apply call-solution-generator #:first-only #t args))) - - (define/override (get-solutions . args) - (apply call-solution-generator args)))) - -(define backtracking-solver%? (is-a?/c backtracking-solver%)) diff --git a/csp/csp/port/test-classes.rkt b/csp/csp/port/test-classes.rkt deleted file mode 100644 index 21e129e4..00000000 --- a/csp/csp/port/test-classes.rkt +++ /dev/null @@ -1,74 +0,0 @@ -#lang racket -(require rackunit "main.rkt") - - -;; Problem: fields -(check-equal? (get-field _solver (new problem% [solver 'solver-in])) 'solver-in) -(check-equal? (get-field _constraints (new problem%)) null) -(check-equal? (get-field _variable-domains (new problem%)) (make-hash)) - -(define problem null) - -;; Problem: reset -(set! problem (new problem%)) -(define early-solutions (send problem get-solutions)) -(send problem add-variable "a" (range 3)) -(check-not-equal? (send problem get-solutions) early-solutions) -(send problem reset) -(check-equal? (send problem get-solutions) early-solutions) - -;; Problem: setSolver & get-solver -(define solver (new backtracking-solver%)) -(set! problem (new problem% [solver solver])) -(check-true (solver%? (send problem get-solver))) - -;; Problem: add-variable -(set! problem (new problem%)) -(send problem add-variable "a" '(1 2)) -(check-true (or (= (hash-ref (send problem get-solution) "a") 1) - (= (hash-ref (send problem get-solution) "a") 2))) -(check-exn exn:fail? (λ () (send problem add-variable "b" null))) ;; empty domain - - -;; Problem: add-variables -(set! problem (new problem%)) -(send problem add-variables '("a" "b") '(1 2 3)) -(check-equal? (length (send problem get-solutions)) 9) - -;; Problem: add-constraint -(set! problem (new problem%)) -(send problem add-variables '("a" "b") '(1 2 3)) -(send problem add-constraint (λ(a b) (= a (add1 b)))) -(check-equal? (length (send problem get-solutions)) 2) - - -;; FunctionConstraint, two ways: implicit and explicit -(send problem reset) -(send problem add-variables '(a b) '(1 2)) -(send problem add-constraint <) ; implicit -(check-true (let ([s (sort (hash->list (send problem get-solution)) #:key cdr <)]) - (or (equal? s '((a . 1) (b . 2))) (equal? s '((b . 1) (a . 2)))))) -(send problem reset) -(send problem add-variables '(a b) '(1 2)) -(send problem add-constraint (new function-constraint% [func <])) ; explicit -(check-true (let ([s (sort (hash->list (send problem get-solution)) #:key cdr <)]) - (or (equal? s '((a . 1) (b . 2))) (equal? s '((b . 1) (a . 2)))))) - -;; AllDifferentConstraint -(send problem reset) -(send problem add-variables '(a b) '(1 2)) -(send problem add-constraint (new all-different-constraint%)) -(let ([solutions (send problem get-solutions)]) - (check-equal? (hash-ref (first solutions) 'a) (hash-ref (second solutions) 'b)) - (check-equal? (hash-ref (second solutions) 'a) (hash-ref (first solutions) 'b))) - - -;; AllEqualConstraint -(send problem reset) -(send problem add-variables '(a b) '(1 2)) -(send problem add-constraint (new all-equal-constraint%)) -(let ([solutions (send problem get-solutions)]) - (check-equal? (hash-ref (first solutions) 'a) (hash-ref (first solutions) 'b)) - (check-equal? (hash-ref (second solutions) 'a) (hash-ref (second solutions) 'b))) - - diff --git a/csp/csp/port/test-einstein.rkt b/csp/csp/port/test-einstein.rkt deleted file mode 100644 index aeef4b4d..00000000 --- a/csp/csp/port/test-einstein.rkt +++ /dev/null @@ -1,168 +0,0 @@ -#lang racket - -(require "problem.rkt" "constraint.rkt" sugar/debug) - -#| -# There are no tricks, just pure logic, so good luck and don't give up. -# -# 1. In a street there are five houses, painted five different colours. -# 2. In each house lives a person of different nationality -# 3. These five homeowners each drink a different kind of beverage, smoke -# different brand of cigar and keep a different pet. -# -# THE QUESTION: WHO OWNS THE zebra? -# -# HINTS -# -# 1. The englishman lives in a red house. -# 2. The spaniard keeps dogs as pets. -# 5. The owner of the Green house drinks coffee. -# 3. The ukrainian drinks tea. -# 4. The Green house is on the left of the ivory house. -# 6. The person who smokes oldgold rears snails. -# 7. The owner of the Yellow house smokes kools. -# 8. The man living in the centre house drinks milk. -# 9. The Norwegian lives in the first house. -# 10. The man who smokes chesterfields lives next to the one who keeps foxes. -# 11. The man who keeps horses lives next to the man who smokes kools. -# 12. The man who smokes luckystrike drinks orangejuice. -# 13. The japanese smokes parliaments. -# 14. The Norwegian lives next to the blue house. -# 15. The man who smokes chesterfields has a neighbour who drinks water. -|# - -(define ep (new problem%)) - -(for ([idx '(1 2 3 4 5)]) - (send ep add-variable (format "color~a" idx) '("red" "ivory" "green" "yellow" "blue")) - - (send ep add-variable (format "nationality~a" idx) '("englishman" "spaniard" "ukrainian" "norwegian" "japanese")) - - (send ep add-variable (format "drink~a" idx) '("tea" "coffee" "milk" "orangejuice" "water")) - - (send ep add-variable (format "smoke~a" idx) '("oldgold" "kools" "chesterfields" "luckystrike" "parliaments")) - - (send ep add-variable (format "pet~a" idx) '("dogs" "snails" "foxes" "horses" "zebra"))) - -(for ([name '("color" "nationality" "drink" "smoke" "pet")]) - (send ep add-constraint (new all-different-constraint%) - (map (λ(idx) (format "~a~a" name idx)) '(1 2 3 4 5)))) - - -(for ([idx '(1 2 3 4 5)]) - (send ep add-constraint - (λ(n c) (or (not (equal? n "englishman")) (equal? c "red"))) - (list (format "nationality~a" idx) (format "color~a" idx))) - - - (send ep add-constraint - (λ(n p) (or (not (equal? n "spaniard")) (equal? p "dogs"))) - (list (format "nationality~a" idx) (format "pet~a" idx))) - - (send ep add-constraint - (λ(n d) (or (not (equal? n "ukrainian")) (equal? d "tea"))) - (list (format "nationality~a" idx) (format "drink~a" idx))) - - (if (< idx 5) - (send ep add-constraint - (λ(ca cb) (or (not (equal? ca "green")) (equal? cb "ivory"))) - (list (format "color~a" idx) (format "color~a" (add1 idx)))) - (send ep add-constraint - (λ(c) (not (equal? c "green"))) - (list (format "color~a" idx)))) - - (send ep add-constraint - (λ(c d) (or (not (equal? c "green")) (equal? d "coffee"))) - (list (format "color~a" idx) (format "drink~a" idx))) - - (send ep add-constraint - (λ(s p) (or (not (equal? s "oldgold")) (equal? p "snails"))) - (list (format "smoke~a" idx) (format "pet~a" idx))) - - (send ep add-constraint - (λ(c s) (or (not (equal? c "yellow")) (equal? s "kools"))) - (list (format "color~a" idx) (format "smoke~a" idx))) - - (when (= idx 3) - (send ep add-constraint - (λ(d) (equal? d "milk")) - (list (format "drink~a" idx)))) - - (when (= idx 1) - (send ep add-constraint - (λ(n) (equal? n "norwegian")) - (list (format "nationality~a" idx)))) - - (if (< 1 idx 5) - (send ep add-constraint - (λ(s pa pb) (or (not (equal? s "chesterfields")) (equal? pa "foxes") (equal? pb "foxes"))) - (list (format "smoke~a" idx) (format "pet~a" (add1 idx)) (format "pet~a" (sub1 idx)))) - (send ep add-constraint - (λ(s p) (or (not (equal? s "chesterfields")) (equal? p "foxes"))) - (list (format "smoke~a" idx) (format "pet~a" (if (= idx 1) 2 4))))) - - (if (< 1 idx 5) - (send ep add-constraint - (λ(p sa sb) (or (not (equal? p "horses")) (equal? sa "kools") (equal? sb "kools"))) - (list (format "pet~a" idx) (format "smoke~a" (add1 idx)) (format "smoke~a" (sub1 idx)))) - (send ep add-constraint - (λ(p s) (or (not (equal? p "horses")) (equal? s "kools"))) - (list (format "pet~a" idx) (format "smoke~a" (if (= idx 1) 2 4))))) - - (send ep add-constraint - (λ(s d) (or (not (equal? s "luckystrike")) (equal? d "orangejuice"))) - (list (format "smoke~a" idx) (format "drink~a" idx))) - - (send ep add-constraint - (λ(n s) (or (not (equal? n "japanese")) (equal? s "parliaments"))) - (list (format "nationality~a" idx) (format "smoke~a" idx))) - - - (if (< 1 idx 5) - (send ep add-constraint - (λ(n ca cb) (or (not (equal? n "norwegian")) (equal? ca "blue") (equal? cb "blue"))) - (list (format "nationality~a" idx) (format "color~a" (add1 idx)) (format "color~a" (sub1 idx)))) - (send ep add-constraint - (λ(n c) (or (not (equal? n "norwegian")) (equal? c "blue"))) - (list (format "nationality~a" idx) (format "color~a" (if (= idx 1) 2 4))))) - - - ) - - -(module+ main - (require rackunit) - -(define s (time (send ep get-solution))) - -(define result - (for*/list ([idx '(1 2 3 4 5)] - [name '("nationality" "color" "drink" "smoke" "pet")]) - (define key (format "~a~a" name idx)) - (format "~a ~a" key (hash-ref s key)))) - -(check-equal? result '("nationality1 norwegian" - "color1 yellow" - "drink1 water" - "smoke1 kools" - "pet1 foxes" - "nationality2 ukrainian" - "color2 blue" - "drink2 tea" - "smoke2 chesterfields" - "pet2 horses" - "nationality3 englishman" - "color3 red" - "drink3 milk" - "smoke3 oldgold" - "pet3 snails" - "nationality4 japanese" - "color4 green" - "drink4 coffee" - "smoke4 parliaments" - "pet4 zebra" - "nationality5 spaniard" - "color5 ivory" - "drink5 orangejuice" - "smoke5 luckystrike" - "pet5 dogs"))) \ No newline at end of file diff --git a/csp/csp/port/test-problems.rkt b/csp/csp/port/test-problems.rkt deleted file mode 100644 index aec12564..00000000 --- a/csp/csp/port/test-problems.rkt +++ /dev/null @@ -1,152 +0,0 @@ -#lang racket -(require "main.rkt" "test-classes.rkt") -(require rackunit) - - -;; ABC problem: -;; what is the minimum value of - -;; ABC -;; ------- -;; A+B+C - - -(define abc-problem (new problem%)) -(send abc-problem add-variables '("a" "b" "c") (range 1 10)) -(define (test-solution s) (let ([a (hash-ref s "a")] - [b (hash-ref s "b")] - [c (hash-ref s "c")]) - (/ (+ (* 100 a) (* 10 b) c) (+ a b c)))) - -(check-hash-items (argmin test-solution (send abc-problem get-solutions)) - #hash(("c" . 9) ("b" . 9) ("a" . 1))) - - -;; quarter problem: -;; 26 coins, dollars and quarters -;; that add up to $17. - -(define quarter-problem (new problem%)) -(send quarter-problem add-variables '("dollars" "quarters") (range 1 27)) -(send quarter-problem add-constraint (λ(d q) (= 17 (+ d (* 0.25 q)))) '("dollars" "quarters")) -(send quarter-problem add-constraint (λ(d q) (= 26 (+ d q))) '("dollars" "quarters")) -(check-hash-items (send quarter-problem get-solution) '#hash(("dollars" . 14) ("quarters" . 12))) - -;; coin problem 2 -#| -A collection of 33 coins, consisting of nickels, dimes, and quarters, has a value of $3.30. If there are three times as many nickels as quarters, and one-half as many dimes as nickels, how many coins of each kind are there? -|# - -(define nickel-problem (new problem%)) -(send nickel-problem add-variables '(nickels dimes quarters) (range 1 34)) -(send nickel-problem add-constraint (λ(n d q) (= 33 (+ n d q))) '(nickels dimes quarters)) -(send nickel-problem add-constraint (λ(n d q) (= 3.30 (+ (* 0.05 n) (* 0.1 d) (* 0.25 q)))) '(nickels dimes quarters)) -(send nickel-problem add-constraint (λ(n q) (= n (* 3 q))) '(nickels quarters)) -(send nickel-problem add-constraint (λ(d n) (= n (* 2 d))) '(dimes nickels)) -(check-hash-items (send nickel-problem get-solution) #hash((nickels . 18) (quarters . 6) (dimes . 9))) - -;; word math -#| -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# TWO -# + TWO -# ----- -# FOUR -|# - - -(define two-four-problem (new problem%)) -(send two-four-problem add-variables '(t w o f u r) (range 10)) -(send two-four-problem add-constraint (new all-different-constraint%)) -(send two-four-problem add-constraint (λ(t w o) (> (word-value t w o) 99)) '(t w o)) -(send two-four-problem add-constraint (λ(f o u r) (> (word-value f o u r) 999)) '(f o u r)) -(send two-four-problem add-constraint - (λ (t w o f u r) - (let ([two (word-value t w o)] - [four (word-value f o u r)]) - ((two . + . two) . = . four))) '(t w o f u r)) -(check-equal? (length (send two-four-problem get-solutions)) 7) -(send two-four-problem add-constraint (λ(r) (= r 0)) '(r)) -(check-hash-items (send two-four-problem get-solution) #hash((o . 5) (w . 6) (u . 3) (f . 1) (r . 0) (t . 7))) - - -;; xsum -#| -# Reorganize the following numbers in a way that each line of -# 5 numbers sum to 27. -# -# 1 6 -# 2 7 -# 3 -# 8 4 -# 9 5 -# -|# - -(define xsum (new problem%)) -(send xsum add-variables '(l1 l2 l3 l4 r1 r2 r3 r4 x) (range 10)) -(send xsum add-constraint (λ (l1 l2 l3 l4 x) - (and (< l1 l2 l3 l4) - (= 27 (+ l1 l2 l3 l4 x)))) '(l1 l2 l3 l4 x)) -(send xsum add-constraint (λ (r1 r2 r3 r4 x) - (and (< r1 r2 r3 r4) - (= 27 (+ r1 r2 r3 r4 x)))) '(r1 r2 r3 r4 x)) -(send xsum add-constraint (new all-different-constraint%)) -(check-equal? (length (send xsum get-solutions)) 8) - - - -;; send more money problem -#| -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# SEND -# + MORE -# ------ -# MONEY -|# - - -(define smm (new problem%)) -(send smm add-variables '(s e n d m o r y) (range 10)) -(send smm add-constraint (λ(x) (> x 0)) '(s)) -(send smm add-constraint (λ(x) (> x 0)) '(m)) -(send smm add-constraint (λ(d e y) (= (modulo (+ d e) 10) y)) '(d e y)) -(send smm add-constraint (λ(n d r e y) - (= (modulo (+ (word-value n d) (word-value r e)) 100) - (word-value e y))) '(n d r e y)) -(send smm add-constraint (λ(e n d o r y) - (= (modulo (+ (word-value e n d) (word-value o r e)) 1000) (word-value n e y))) '(e n d o r y)) -(send smm add-constraint (λ(s e n d m o r y) (= - (+ (word-value s e n d) - (word-value m o r e)) - (word-value m o n e y))) '(s e n d m o r y)) -#;(send smm add-constraint (new all-different-constraint%)) -(send smm add-constraint (λ xs (= (length (remove-duplicates xs)) (length xs))) '(s e n d m o r y)) - -(check-hash-items (send smm get-solution) '#hash((m . 1) (e . 5) (r . 8) (n . 6) (y . 2) (o . 0) (d . 7) (s . 9))) - - - - -;; queens problem -;; place queens on chessboard so they do not intersect - -(define queens-problem (new problem%)) -(define cols (range 8)) -(define rows (range 8)) -(send queens-problem add-variables cols rows) -(for* ([col1 (in-list cols)] [col2 (in-list cols)] #:when (< col1 col2)) - (send queens-problem add-constraint (λ(row1 row2 [col1 col1][col2 col2]) - (and - ;; test if two cells are on a diagonal - (not (= (abs (- row1 row2)) (abs (- col1 col2)))) - ;; test if two cells are in same row - (not (= row1 row2)))) (list col1 col2))) -(check-equal? (length (send queens-problem get-solutions)) 92) - -(module+ main - (displayln "Tests passed")) \ No newline at end of file diff --git a/csp/csp/port/variable.rkt b/csp/csp/port/variable.rkt deleted file mode 100644 index 727a469e..00000000 --- a/csp/csp/port/variable.rkt +++ /dev/null @@ -1,17 +0,0 @@ -#lang racket/base -(require racket/class "helper.rkt") -(provide (all-defined-out)) - -(define variable% - (class* object% (printable<%>) - (super-new) - (define (repr) (format "" _name)) - (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)) - - (init-field name) - (field [_name name]))) -(define variable%? (is-a?/c variable%)) - -(define Unassigned (new variable% [name "Unassigned"])) \ No newline at end of file diff --git a/csp/csp/python-constraint/API Documentation.webloc b/csp/csp/python-constraint/API Documentation.webloc deleted file mode 100644 index 3cae8191..00000000 --- a/csp/csp/python-constraint/API Documentation.webloc +++ /dev/null @@ -1,8 +0,0 @@ - - - - - URL - http://labix.org/doc/constraint/ - - diff --git a/csp/csp/python-constraint/LICENSE b/csp/csp/python-constraint/LICENSE deleted file mode 100644 index 1551a23a..00000000 --- a/csp/csp/python-constraint/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2005-2014 - Gustavo Niemeyer - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/csp/csp/python-constraint/MANIFEST.in b/csp/csp/python-constraint/MANIFEST.in deleted file mode 100644 index 18b718a2..00000000 --- a/csp/csp/python-constraint/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include constraint.py setup.py setup.cfg README LICENSE MANIFEST.in -recursive-include examples *.py *.mask diff --git a/csp/csp/python-constraint/PKG-INFO b/csp/csp/python-constraint/PKG-INFO deleted file mode 100644 index f3a51345..00000000 --- a/csp/csp/python-constraint/PKG-INFO +++ /dev/null @@ -1,13 +0,0 @@ -Metadata-Version: 1.0 -Name: python-constraint -Version: 1.2 -Summary: Python module for handling Constraint Solving Problems -Home-page: http://labix.org/python-constraint -Author: Gustavo Niemeyer -Author-email: gustavo@niemeyer.net -License: Simplified BSD -Description: - python-constraint is a module implementing support for handling CSPs - (Constraint Solving Problems) over finite domains. - -Platform: UNKNOWN diff --git a/csp/csp/python-constraint/README b/csp/csp/python-constraint/README deleted file mode 100644 index 625e7075..00000000 --- a/csp/csp/python-constraint/README +++ /dev/null @@ -1 +0,0 @@ -See http://labix.org/constraint diff --git a/csp/csp/python-constraint/constraint.py b/csp/csp/python-constraint/constraint.py deleted file mode 100644 index 462b6bc4..00000000 --- a/csp/csp/python-constraint/constraint.py +++ /dev/null @@ -1,1469 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2005-2014 - Gustavo Niemeyer -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" -@var Unassigned: Helper object instance representing unassigned values - -@sort: Problem, Variable, Domain -@group Solvers: Solver, - BacktrackingSolver, - RecursiveBacktrackingSolver, - MinConflictsSolver -@group Constraints: Constraint, - FunctionConstraint, - AllDifferentConstraint, - AllEqualConstraint, - MaxSumConstraint, - ExactSumConstraint, - MinSumConstraint, - InSetConstraint, - NotInSetConstraint, - SomeInSetConstraint, - SomeNotInSetConstraint -""" -import random -import copy - -__all__ = ["Problem", "Variable", "Domain", "Unassigned", - "Solver", "BacktrackingSolver", "RecursiveBacktrackingSolver", - "MinConflictsSolver", "Constraint", "FunctionConstraint", - "AllDifferentConstraint", "AllEqualConstraint", "MaxSumConstraint", - "ExactSumConstraint", "MinSumConstraint", "InSetConstraint", - "NotInSetConstraint", "SomeInSetConstraint", - "SomeNotInSetConstraint"] - -class Problem(object): - """ - Class used to define a problem and retrieve solutions - """ - - def __init__(self, solver=None): - """ - @param solver: Problem solver used to find solutions - (default is L{BacktrackingSolver}) - @type solver: instance of a L{Solver} subclass - """ - self._solver = solver or BacktrackingSolver() - self._constraints = [] - self._variables = {} - - def reset(self): - """ - Reset the current problem definition - - Example: - - >>> problem = Problem() - >>> problem.addVariable("a", [1, 2]) - >>> problem.reset() - >>> problem.getSolution() - >>> - """ - del self._constraints[:] - self._variables.clear() - - def setSolver(self, solver): - """ - Change the problem solver currently in use - - Example: - - >>> solver = BacktrackingSolver() - >>> problem = Problem(solver) - >>> problem.getSolver() is solver - True - - @param solver: New problem solver - @type solver: instance of a C{Solver} subclass - """ - self._solver = solver - - def getSolver(self): - """ - Obtain the problem solver currently in use - - Example: - - >>> solver = BacktrackingSolver() - >>> problem = Problem(solver) - >>> problem.getSolver() is solver - True - - @return: Solver currently in use - @rtype: instance of a L{Solver} subclass - """ - return self._solver - - def addVariable(self, variable, domain): - """ - Add a variable to the problem - - Example: - - >>> problem = Problem() - >>> problem.addVariable("a", [1, 2]) - >>> problem.getSolution() in ({'a': 1}, {'a': 2}) - True - - @param variable: Object representing a problem variable - @type variable: hashable object - @param domain: Set of items defining the possible values that - the given variable may assume - @type domain: list, tuple, or instance of C{Domain} - """ - if variable in self._variables: - raise ValueError, "Tried to insert duplicated variable %s" % \ - repr(variable) - if type(domain) in (list, tuple): - domain = Domain(domain) - elif isinstance(domain, Domain): - domain = copy.copy(domain) - else: - raise TypeError, "Domains must be instances of subclasses of "\ - "the Domain class" - if not domain: - raise ValueError, "Domain is empty" - self._variables[variable] = domain - - def addVariables(self, variables, domain): - """ - Add one or more variables to the problem - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> solutions = problem.getSolutions() - >>> len(solutions) - 9 - >>> {'a': 3, 'b': 1} in solutions - True - - @param variables: Any object containing a sequence of objects - represeting problem variables - @type variables: sequence of hashable objects - @param domain: Set of items defining the possible values that - the given variables may assume - @type domain: list, tuple, or instance of C{Domain} - """ - for variable in variables: - self.addVariable(variable, domain) - - def addConstraint(self, constraint, variables=None): - """ - Add a constraint to the problem - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b == a+1, ["a", "b"]) - >>> solutions = problem.getSolutions() - >>> - - @param constraint: Constraint to be included in the problem - @type constraint: instance a L{Constraint} subclass or a - function to be wrapped by L{FunctionConstraint} - @param variables: Variables affected by the constraint (default to - all variables). Depending on the constraint type - the order may be important. - @type variables: set or sequence of variables - """ - print "self._constraints", self._constraints - if not isinstance(constraint, Constraint): - if callable(constraint): - constraint = FunctionConstraint(constraint) - else: - raise ValueError, "Constraints must be instances of "\ - "subclasses of the Constraint class" - self._constraints.append((constraint, variables)) - print "self._constraints", self._constraints - - def getSolution(self): - """ - Find and return a solution to the problem - - Example: - - >>> problem = Problem() - >>> problem.getSolution() is None - True - >>> problem.addVariables(["a"], [42]) - >>> problem.getSolution() - {'a': 42} - - @return: Solution for the problem - @rtype: dictionary mapping variables to values - """ - domains, constraints, vconstraints = self._getArgs() - if not domains: - return None - return self._solver.getSolution(domains, constraints, vconstraints) - - def getSolutions(self): - """ - Find and return all solutions to the problem - - Example: - - >>> problem = Problem() - >>> problem.getSolutions() == [] - True - >>> problem.addVariables(["a"], [42]) - >>> problem.getSolutions() - [{'a': 42}] - - @return: All solutions for the problem - @rtype: list of dictionaries mapping variables to values - """ - domains, constraints, vconstraints = self._getArgs() - if not domains: - return [] - return self._solver.getSolutions(domains, constraints, vconstraints) - - def getSolutionIter(self): - """ - Return an iterator to the solutions of the problem - - Example: - - >>> problem = Problem() - >>> list(problem.getSolutionIter()) == [] - True - >>> problem.addVariables(["a"], [42]) - >>> iter = problem.getSolutionIter() - >>> iter.next() - {'a': 42} - >>> iter.next() - Traceback (most recent call last): - File "", line 1, in ? - StopIteration - """ - domains, constraints, vconstraints = self._getArgs() - if not domains: - return iter(()) - return self._solver.getSolutionIter(domains, constraints, - vconstraints) - - def _getArgs(self): - domains = self._variables.copy() - allvariables = domains.keys() - constraints = [] - for constraint, variables in self._constraints: - if not variables: - variables = allvariables - constraints.append((constraint, variables)) - vconstraints = {} - for variable in domains: - vconstraints[variable] = [] - for constraint, variables in constraints: - for variable in variables: - vconstraints[variable].append((constraint, variables)) - for constraint, variables in constraints[:]: - constraint.preProcess(variables, domains, - constraints, vconstraints) - for domain in domains.values(): - domain.resetState() - if not domain: - return None, None, None - #doArc8(getArcs(domains, constraints), domains, {}) - return domains, constraints, vconstraints - -# ---------------------------------------------------------------------- -# Solvers -# ---------------------------------------------------------------------- - -def getArcs(domains, constraints): - """ - Return a dictionary mapping pairs (arcs) of constrained variables - - @attention: Currently unused. - """ - arcs = {} - for x in constraints: - constraint, variables = x - if len(variables) == 2: - variable1, variable2 = variables - arcs.setdefault(variable1, {})\ - .setdefault(variable2, [])\ - .append(x) - arcs.setdefault(variable2, {})\ - .setdefault(variable1, [])\ - .append(x) - return arcs - -def doArc8(arcs, domains, assignments): - """ - Perform the ARC-8 arc checking algorithm and prune domains - - @attention: Currently unused. - """ - check = dict.fromkeys(domains, True) - while check: - variable, _ = check.popitem() - if variable not in arcs or variable in assignments: - continue - domain = domains[variable] - arcsvariable = arcs[variable] - for othervariable in arcsvariable: - arcconstraints = arcsvariable[othervariable] - if othervariable in assignments: - otherdomain = [assignments[othervariable]] - else: - otherdomain = domains[othervariable] - if domain: - changed = False - for value in domain[:]: - assignments[variable] = value - if otherdomain: - for othervalue in otherdomain: - assignments[othervariable] = othervalue - for constraint, variables in arcconstraints: - if not constraint(variables, domains, - assignments, True): - break - else: - # All constraints passed. Value is safe. - break - else: - # All othervalues failed. Kill value. - domain.hideValue(value) - changed = True - del assignments[othervariable] - del assignments[variable] - #if changed: - # check.update(dict.fromkeys(arcsvariable)) - if not domain: - return False - return True - -class Solver(object): - """ - Abstract base class for solvers - - @sort: getSolution, getSolutions, getSolutionIter - """ - - def getSolution(self, domains, constraints, vconstraints): - """ - Return one solution for the given problem - - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """ - NotImplementedError, \ - "%s is an abstract class" % self.__class__.__name__ - - def getSolutions(self, domains, constraints, vconstraints): - """ - Return all solutions for the given problem - - @param domains: Dictionary mapping variables to domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """ - raise NotImplementedError, \ - "%s provides only a single solution" % self.__class__.__name__ - - def getSolutionIter(self, domains, constraints, vconstraints): - """ - Return an iterator for the solutions of the given problem - - @param domains: Dictionary mapping variables to domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """ - raise NotImplementedError, \ - "%s doesn't provide iteration" % self.__class__.__name__ - -class BacktrackingSolver(Solver): - """ - Problem solver with backtracking capabilities - - Examples: - - >>> result = [[('a', 1), ('b', 2)], - ... [('a', 1), ('b', 3)], - ... [('a', 2), ('b', 3)]] - - >>> problem = Problem(BacktrackingSolver()) - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b > a, ["a", "b"]) - - >>> solution = problem.getSolution() - >>> sorted(solution.items()) in result - True - - >>> for solution in problem.getSolutionIter(): - ... sorted(solution.items()) in result - True - True - True - - >>> for solution in problem.getSolutions(): - ... sorted(solution.items()) in result - True - True - True - """#""" - - def __init__(self, forwardcheck=True): - """ - @param forwardcheck: If false forward checking will not be requested - to constraints while looking for solutions - (default is true) - @type forwardcheck: bool - """ - self._forwardcheck = forwardcheck - - def getSolutionIter(self, domains, constraints, vconstraints): - forwardcheck = self._forwardcheck - assignments = {} - - queue = [] - - - while True: - #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 - for item in lst: - if item[-1] not in assignments: - # Found unassigned variable - variable = item[-1] - #print "unassigned variable", variable - values = domains[variable][:] - if forwardcheck: - pushdomains = [domains[x] for x in domains - if x not in assignments and - x != variable] - else: - pushdomains = None - break - 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 - yield assignments.copy() - #print "queue", queue - if not queue: - return - variable, values, pushdomains = queue.pop() - if pushdomains: - for domain in pushdomains: - domain.popState() - - #print "variable-preloop-2", variable - #print "assignments-preloop-2", assignments - while True: - #print "starting while loop 2" - # We have a variable. Do we have any values left? - #print "values tested", values - if not values: - # No. Go back to last variable, if there's one. - del assignments[variable] - while queue: - variable, values, pushdomains = queue.pop() - if pushdomains: - for domain in pushdomains: - domain.popState() - if values: - break - del assignments[variable] - else: - return - - # Got a value. Check it. - assignments[variable] = values.pop() - - if pushdomains: - for domain in pushdomains: - domain.pushState() - #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 - if not the_result: - # Value is not good. - break - else: - #print "now breaking loop 2" - break - - if pushdomains: - for domain in pushdomains: - domain.popState() - - # Push state before looking for next variable. - queue.append((variable, values, pushdomains)) - #print "new queue", queue - - raise RuntimeError, "Can't happen" - - def getSolution(self, domains, constraints, vconstraints): - iter = self.getSolutionIter(domains, constraints, vconstraints) - try: - return iter.next() - except StopIteration: - return None - - def getSolutions(self, domains, constraints, vconstraints): - return list(self.getSolutionIter(domains, constraints, vconstraints)) - - -class RecursiveBacktrackingSolver(Solver): - """ - Recursive problem solver with backtracking capabilities - - Examples: - - >>> result = [[('a', 1), ('b', 2)], - ... [('a', 1), ('b', 3)], - ... [('a', 2), ('b', 3)]] - - >>> problem = Problem(RecursiveBacktrackingSolver()) - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b > a, ["a", "b"]) - - >>> solution = problem.getSolution() - >>> sorted(solution.items()) in result - True - - >>> for solution in problem.getSolutions(): - ... sorted(solution.items()) in result - True - True - True - - >>> problem.getSolutionIter() - Traceback (most recent call last): - ... - NotImplementedError: RecursiveBacktrackingSolver doesn't provide iteration - """#""" - - def __init__(self, forwardcheck=True): - """ - @param forwardcheck: If false forward checking will not be requested - to constraints while looking for solutions - (default is true) - @type forwardcheck: bool - """ - self._forwardcheck = forwardcheck - - def recursiveBacktracking(self, solutions, domains, vconstraints, - assignments, single): - - - # Mix the Degree and Minimum Remaing Values (MRV) heuristics - lst = [(-len(vconstraints[variable]), - len(domains[variable]), variable) for variable in domains] - lst.sort() - for item in lst: - if item[-1] not in assignments: - # Found an unassigned variable. Let's go. - breakit - else: - # No unassigned variables. We've got a solution. - solutions.append(assignments.copy()) - return solutions - - variable = item[-1] - assignments[variable] = None - - forwardcheck = self._forwardcheck - if forwardcheck: - pushdomains = [domains[x] for x in domains if x not in assignments] - else: - pushdomains = None - - for value in domains[variable]: - assignments[variable] = value - if pushdomains: - for domain in pushdomains: - domain.pushState() - for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments, - pushdomains): - # Value is not good. - break - else: - # Value is good. Recurse and get next variable. - self.recursiveBacktracking(solutions, domains, vconstraints, - assignments, single) - if solutions and single: - return solutions - if pushdomains: - for domain in pushdomains: - domain.popState() - del assignments[variable] - return solutions - - def getSolution(self, domains, constraints, vconstraints): - solutions = self.recursiveBacktracking([], domains, vconstraints, - {}, True) - return solutions and solutions[0] or None - - def getSolutions(self, domains, constraints, vconstraints): - return self.recursiveBacktracking([], domains, vconstraints, - {}, False) - - -class MinConflictsSolver(Solver): - """ - Problem solver based on the minimum conflicts theory - - Examples: - - >>> result = [[('a', 1), ('b', 2)], - ... [('a', 1), ('b', 3)], - ... [('a', 2), ('b', 3)]] - - >>> problem = Problem(MinConflictsSolver()) - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b > a, ["a", "b"]) - - >>> solution = problem.getSolution() - >>> sorted(solution.items()) in result - True - - >>> problem.getSolutions() - Traceback (most recent call last): - ... - NotImplementedError: MinConflictsSolver provides only a single solution - - >>> problem.getSolutionIter() - Traceback (most recent call last): - ... - NotImplementedError: MinConflictsSolver doesn't provide iteration - """#""" - - def __init__(self, steps=1000): - """ - @param steps: Maximum number of steps to perform before giving up - when looking for a solution (default is 1000) - @type steps: int - """ - self._steps = steps - - def getSolution(self, domains, constraints, vconstraints): - assignments = {} - # Initial assignment - for variable in domains: - assignments[variable] = random.choice(domains[variable]) - for _ in xrange(self._steps): - conflicted = False - lst = domains.keys() - random.shuffle(lst) - for variable in lst: - # Check if variable is not in conflict - for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments): - break - else: - continue - # Variable has conflicts. Find values with less conflicts. - mincount = len(vconstraints[variable]) - minvalues = [] - for value in domains[variable]: - assignments[variable] = value - count = 0 - for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments): - count += 1 - if count == mincount: - minvalues.append(value) - elif count < mincount: - mincount = count - del minvalues[:] - minvalues.append(value) - # Pick a random one from these values. - assignments[variable] = random.choice(minvalues) - conflicted = True - if not conflicted: - return assignments - return None - -# ---------------------------------------------------------------------- -# Variables -# ---------------------------------------------------------------------- - -class Variable(object): - """ - Helper class for variable definition - - Using this class is optional, since any hashable object, - including plain strings and integers, may be used as variables. - """ - - def __init__(self, name): - """ - @param name: Generic variable name for problem-specific purposes - @type name: string - """ - self.name = name - - def __repr__(self): - return self.name - -Unassigned = Variable("Unassigned") - -# ---------------------------------------------------------------------- -# Domains -# ---------------------------------------------------------------------- - -class Domain(list): - """ - Class used to control possible values for variables - - When list or tuples are used as domains, they are automatically - converted to an instance of that class. - """ - - def __init__(self, set): - """ - @param set: Set of values that the given variables may assume - @type set: set of objects comparable by equality - """ - list.__init__(self, set) - self._hidden = [] - self._states = [] - - def resetState(self): - """ - Reset to the original domain state, including all possible values - """ - self.extend(self._hidden) - del self._hidden[:] - del self._states[:] - - def pushState(self): - """ - Save current domain state - - Variables hidden after that call are restored when that state - is popped from the stack. - """ - self._states.append(len(self)) - - def popState(self): - """ - Restore domain state from the top of the stack - - Variables hidden since the last popped state are then available - again. - """ - diff = self._states.pop()-len(self) - if diff: - self.extend(self._hidden[-diff:]) - del self._hidden[-diff:] - - def hideValue(self, value): - """ - Hide the given value from the domain - - After that call the given value won't be seen as a possible value - on that domain anymore. The hidden value will be restored when the - previous saved state is popped. - - @param value: Object currently available in the domain - """ - list.remove(self, value) - self._hidden.append(value) - -# ---------------------------------------------------------------------- -# Constraints -# ---------------------------------------------------------------------- - -class Constraint(object): - """ - Abstract base class for constraints - """ - - def __call__(self, variables, domains, assignments, forwardcheck=False): - """ - Perform the constraint checking - - If the forwardcheck parameter is not false, besides telling if - the constraint is currently broken or not, the constraint - implementation may choose to hide values from the domains of - unassigned variables to prevent them from being used, and thus - prune the search space. - - @param variables: Variables affected by that constraint, in the - same order provided by the user - @type variables: sequence - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param assignments: Dictionary mapping assigned variables to their - current assumed value - @type assignments: dict - @param forwardcheck: Boolean value stating whether forward checking - should be performed or not - @return: Boolean value stating if this constraint is currently - broken or not - @rtype: bool - """#""" - return True - - def preProcess(self, variables, domains, constraints, vconstraints): - """ - Preprocess variable domains - - This method is called before starting to look for solutions, - and is used to prune domains with specific constraint logic - when possible. For instance, any constraints with a single - variable may be applied on all possible values and removed, - since they may act on individual values even without further - knowledge about other assignments. - - @param variables: Variables affected by that constraint, in the - same order provided by the user - @type variables: sequence - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """#""" - if len(variables) == 1: - variable = variables[0] - domain = domains[variable] - for value in domain[:]: - if not self(variables, domains, {variable: value}): - domain.remove(value) - constraints.remove((self, variables)) - vconstraints[variable].remove((self, variables)) - - def forwardCheck(self, variables, domains, assignments, - _unassigned=Unassigned): - """ - Helper method for generic forward checking - - Currently, this method acts only when there's a single - unassigned variable. - - @param variables: Variables affected by that constraint, in the - same order provided by the user - @type variables: sequence - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param assignments: Dictionary mapping assigned variables to their - current assumed value - @type assignments: dict - @return: Boolean value stating if this constraint is currently - broken or not - @rtype: bool - """#""" - unassignedvariable = _unassigned - #print "assignments", assignments - for variable in variables: - if variable not in assignments: - if unassignedvariable is _unassigned: - #print "boom" - unassignedvariable = variable - else: - break - else: - if unassignedvariable is not _unassigned: - # Remove from the unassigned variable domain's all - # values which break our variable's constraints. - domain = domains[unassignedvariable] - #print "domain-fc", domain - if domain: - for value in domain[:]: - assignments[unassignedvariable] = value - if not self(variables, domains, assignments): - domain.hideValue(value) - del assignments[unassignedvariable] - if not domain: - return False - return True - -class FunctionConstraint(Constraint): - """ - Constraint which wraps a function defining the constraint logic - - Examples: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> def func(a, b): - ... return b > a - >>> problem.addConstraint(func, ["a", "b"]) - >>> problem.getSolution() - {'a': 1, 'b': 2} - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> def func(a, b): - ... return b > a - >>> problem.addConstraint(FunctionConstraint(func), ["a", "b"]) - >>> problem.getSolution() - {'a': 1, 'b': 2} - """#""" - - def __init__(self, func, assigned=True): - """ - @param func: Function wrapped and queried for constraint logic - @type func: callable object - @param assigned: Whether the function may receive unassigned - variables or not - @type assigned: bool - """ - self._func = func - self._assigned = assigned - - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): - #print "in call" - #print "assignments-before", assignments - parms = [assignments.get(x, _unassigned) for x in variables] - #print "assignments-after", assignments - missing = parms.count(_unassigned) - #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 - return ((self._assigned or self._func(*parms)) and - (not forwardcheck or missing != 1 or - self.forwardCheck(variables, domains, assignments))) - return self._func(*parms) - -class AllDifferentConstraint(Constraint): - """ - Constraint enforcing that values of all given variables are different - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(AllDifferentConstraint()) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): - seen = {} - for variable in variables: - value = assignments.get(variable, _unassigned) - if value is not _unassigned: - if value in seen: - return False - seen[value] = True - if forwardcheck: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in seen: - if value in domain: - domain.hideValue(value) - if not domain: - return False - return True - -class AllEqualConstraint(Constraint): - """ - Constraint enforcing that values of all given variables are equal - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(AllEqualConstraint()) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)], [('a', 2), ('b', 2)]] - """#""" - - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): - singlevalue = _unassigned - for variable in variables: - value = assignments.get(variable, _unassigned) - if singlevalue is _unassigned: - singlevalue = value - elif value is not _unassigned and value != singlevalue: - return False - if forwardcheck and singlevalue is not _unassigned: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - if singlevalue not in domain: - return False - for value in domain[:]: - if value != singlevalue: - domain.hideValue(value) - return True - -class MaxSumConstraint(Constraint): - """ - Constraint enforcing that values of given variables sum up to - a given amount - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(MaxSumConstraint(3)) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)], [('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __init__(self, maxsum, multipliers=None): - """ - @param maxsum: Value to be considered as the maximum sum - @type maxsum: number - @param multipliers: If given, variable values will be multiplied by - the given factors before being summed to be checked - @type multipliers: sequence of numbers - """ - self._maxsum = maxsum - self._multipliers = multipliers - - def preProcess(self, variables, domains, constraints, vconstraints): - Constraint.preProcess(self, variables, domains, - constraints, vconstraints) - multipliers = self._multipliers - maxsum = self._maxsum - if multipliers: - for variable, multiplier in zip(variables, multipliers): - domain = domains[variable] - for value in domain[:]: - if value*multiplier > maxsum: - domain.remove(value) - else: - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value > maxsum: - domain.remove(value) - - def __call__(self, variables, domains, assignments, forwardcheck=False): - multipliers = self._multipliers - maxsum = self._maxsum - sum = 0 - if multipliers: - for variable, multiplier in zip(variables, multipliers): - if variable in assignments: - sum += assignments[variable]*multiplier - if type(sum) is float: - sum = round(sum, 10) - if sum > maxsum: - return False - if forwardcheck: - for variable, multiplier in zip(variables, multipliers): - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value*multiplier > maxsum: - domain.hideValue(value) - if not domain: - return False - else: - for variable in variables: - if variable in assignments: - sum += assignments[variable] - if type(sum) is float: - sum = round(sum, 10) - if sum > maxsum: - return False - if forwardcheck: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value > maxsum: - domain.hideValue(value) - if not domain: - return False - return True - -class ExactSumConstraint(Constraint): - """ - Constraint enforcing that values of given variables sum exactly - to a given amount - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(ExactSumConstraint(3)) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __init__(self, exactsum, multipliers=None): - """ - @param exactsum: Value to be considered as the exact sum - @type exactsum: number - @param multipliers: If given, variable values will be multiplied by - the given factors before being summed to be checked - @type multipliers: sequence of numbers - """ - self._exactsum = exactsum - self._multipliers = multipliers - - def preProcess(self, variables, domains, constraints, vconstraints): - Constraint.preProcess(self, variables, domains, - constraints, vconstraints) - multipliers = self._multipliers - exactsum = self._exactsum - if multipliers: - for variable, multiplier in zip(variables, multipliers): - domain = domains[variable] - for value in domain[:]: - if value*multiplier > exactsum: - domain.remove(value) - else: - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value > exactsum: - domain.remove(value) - - def __call__(self, variables, domains, assignments, forwardcheck=False): - multipliers = self._multipliers - exactsum = self._exactsum - sum = 0 - missing = False - if multipliers: - for variable, multiplier in zip(variables, multipliers): - if variable in assignments: - sum += assignments[variable]*multiplier - else: - missing = True - if type(sum) is float: - sum = round(sum, 10) - if sum > exactsum: - return False - if forwardcheck and missing: - for variable, multiplier in zip(variables, multipliers): - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value*multiplier > exactsum: - domain.hideValue(value) - if not domain: - return False - else: - for variable in variables: - if variable in assignments: - sum += assignments[variable] - else: - missing = True - if type(sum) is float: - sum = round(sum, 10) - if sum > exactsum: - return False - if forwardcheck and missing: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value > exactsum: - domain.hideValue(value) - if not domain: - return False - if missing: - return sum <= exactsum - else: - return sum == exactsum - -class MinSumConstraint(Constraint): - """ - Constraint enforcing that values of given variables sum at least - to a given amount - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(MinSumConstraint(3)) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)], [('a', 2), ('b', 2)]] - """#""" - - def __init__(self, minsum, multipliers=None): - """ - @param minsum: Value to be considered as the minimum sum - @type minsum: number - @param multipliers: If given, variable values will be multiplied by - the given factors before being summed to be checked - @type multipliers: sequence of numbers - """ - self._minsum = minsum - self._multipliers = multipliers - - def __call__(self, variables, domains, assignments, forwardcheck=False): - for variable in variables: - if variable not in assignments: - return True - else: - multipliers = self._multipliers - minsum = self._minsum - sum = 0 - if multipliers: - for variable, multiplier in zip(variables, multipliers): - sum += assignments[variable]*multiplier - else: - for variable in variables: - sum += assignments[variable] - if type(sum) is float: - sum = round(sum, 10) - return sum >= minsum - -class InSetConstraint(Constraint): - """ - Constraint enforcing that values of given variables are present in - the given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(InSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)]] - """#""" - - def __init__(self, set): - """ - @param set: Set of allowed values - @type set: set - """ - self._set = set - - def __call__(self, variables, domains, assignments, forwardcheck=False): - # preProcess() will remove it. - raise RuntimeError, "Can't happen" - - def preProcess(self, variables, domains, constraints, vconstraints): - set = self._set - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value not in set: - domain.remove(value) - vconstraints[variable].remove((self, variables)) - constraints.remove((self, variables)) - -class NotInSetConstraint(Constraint): - """ - Constraint enforcing that values of given variables are not present in - the given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(NotInSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 2), ('b', 2)]] - """#""" - - def __init__(self, set): - """ - @param set: Set of disallowed values - @type set: set - """ - self._set = set - - def __call__(self, variables, domains, assignments, forwardcheck=False): - # preProcess() will remove it. - raise RuntimeError, "Can't happen" - - def preProcess(self, variables, domains, constraints, vconstraints): - set = self._set - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value in set: - domain.remove(value) - vconstraints[variable].remove((self, variables)) - constraints.remove((self, variables)) - -class SomeInSetConstraint(Constraint): - """ - Constraint enforcing that at least some of the values of given - variables must be present in a given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(SomeInSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)], [('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __init__(self, set, n=1, exact=False): - """ - @param set: Set of values to be checked - @type set: set - @param n: Minimum number of assigned values that should be present - in set (default is 1) - @type n: int - @param exact: Whether the number of assigned values which are - present in set must be exactly C{n} - @type exact: bool - """ - self._set = set - self._n = n - self._exact = exact - - def __call__(self, variables, domains, assignments, forwardcheck=False): - set = self._set - missing = 0 - found = 0 - for variable in variables: - if variable in assignments: - found += assignments[variable] in set - else: - missing += 1 - if missing: - if self._exact: - if not (found <= self._n <= missing+found): - return False - else: - if self._n > missing+found: - return False - if forwardcheck and self._n-found == missing: - # All unassigned variables must be assigned to - # values in the set. - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if value not in set: - domain.hideValue(value) - if not domain: - return False - else: - if self._exact: - if found != self._n: - return False - else: - if found < self._n: - return False - return True - -class SomeNotInSetConstraint(Constraint): - """ - Constraint enforcing that at least some of the values of given - variables must not be present in a given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(SomeNotInSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)], [('a', 2), ('b', 2)]] - """#""" - - def __init__(self, set, n=1, exact=False): - """ - @param set: Set of values to be checked - @type set: set - @param n: Minimum number of assigned values that should not be present - in set (default is 1) - @type n: int - @param exact: Whether the number of assigned values which are - not present in set must be exactly C{n} - @type exact: bool - """ - self._set = set - self._n = n - self._exact = exact - - def __call__(self, variables, domains, assignments, forwardcheck=False): - set = self._set - missing = 0 - found = 0 - for variable in variables: - if variable in assignments: - found += assignments[variable] not in set - else: - missing += 1 - if missing: - if self._exact: - if not (found <= self._n <= missing+found): - return False - else: - if self._n > missing+found: - return False - if forwardcheck and self._n-found == missing: - # All unassigned variables must be assigned to - # values not in the set. - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if value in set: - domain.hideValue(value) - if not domain: - return False - else: - if self._exact: - if found != self._n: - return False - else: - if found < self._n: - return False - return True - -if __name__ == "__main__": - import doctest - doctest.testmod() - diff --git a/csp/csp/python-constraint/examples/abc/abc.py b/csp/csp/python-constraint/examples/abc/abc.py deleted file mode 100755 index ddc23bb7..00000000 --- a/csp/csp/python-constraint/examples/abc/abc.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python -# -# What's the minimum value for: -# -# ABC -# ------- -# A+B+C -# -# From http://www.umassd.edu/mathcontest/abc.cfm -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("abc", range(1,10)) - print min(problem.getSolutions()) - minvalue = 999/(9*3) - minsolution = {} - 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 minvalue - print minsolution - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/examples/coins/coins.py b/csp/csp/python-constraint/examples/coins/coins.py deleted file mode 100755 index 1102f3ac..00000000 --- a/csp/csp/python-constraint/examples/coins/coins.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python -# -# 100 coins must sum to $5.00 -# -# That's kind of a country-specific problem, since depending on the -# country there are different values for coins. Here is presented -# the solution for a given set. -# -from constraint import * -import sys - -def main(): - problem = Problem() - total = 5.00 - variables = ("0.01", "0.05", "0.10", "0.50", "1.00") - values = [float(x) for x in variables] - for variable, value in zip(variables, values): - problem.addVariable(variable, range(int(total/value))) - problem.addConstraint(ExactSumConstraint(total, values), variables) - problem.addConstraint(ExactSumConstraint(100)) - solutions = problem.getSolutionIter() - for i, solution in enumerate(solutions): - sys.stdout.write("%03d -> " % (i+1)) - for variable in variables: - sys.stdout.write("%s:%d " % (variable, solution[variable])) - sys.stdout.write("\n") - -if __name__ == "__main__": - main() - diff --git a/csp/csp/python-constraint/examples/crosswords/crosswords.py b/csp/csp/python-constraint/examples/crosswords/crosswords.py deleted file mode 100755 index 5cb502f0..00000000 --- a/csp/csp/python-constraint/examples/crosswords/crosswords.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/python -from constraint import * -import random -import sys - -MINLEN = 3 - -def main(puzzle, lines): - puzzle = puzzle.rstrip().splitlines() - while puzzle and not puzzle[0]: - del puzzle[0] - - # Extract horizontal words - horizontal = [] - word = [] - predefined = {} - for row in range(len(puzzle)): - for col in range(len(puzzle[row])): - char = puzzle[row][col] - if not char.isspace(): - word.append((row, col)) - if char != "#": - predefined[row, col] = char - elif word: - if len(word) > MINLEN: - horizontal.append(word[:]) - del word[:] - if word: - if len(word) > MINLEN: - horizontal.append(word[:]) - del word[:] - - # Extract vertical words - vertical = [] - validcol = True - col = 0 - while validcol: - validcol = False - for row in range(len(puzzle)): - if col >= len(puzzle[row]): - if word: - if len(word) > MINLEN: - vertical.append(word[:]) - del word[:] - else: - validcol = True - char = puzzle[row][col] - if not char.isspace(): - word.append((row, col)) - if char != "#": - predefined[row, col] = char - elif word: - if len(word) > MINLEN: - vertical.append(word[:]) - del word[:] - if word: - if len(word) > MINLEN: - vertical.append(word[:]) - del word[:] - col += 1 - - hnames = ["h%d" % i for i in range(len(horizontal))] - vnames = ["v%d" % i for i in range(len(vertical))] - - #problem = Problem(MinConflictsSolver()) - problem = Problem() - - for hi, hword in enumerate(horizontal): - for vi, vword in enumerate(vertical): - for hchar in hword: - if hchar in vword: - hci = hword.index(hchar) - vci = vword.index(hchar) - problem.addConstraint(lambda hw, vw, hci=hci, vci=vci: - hw[hci] == vw[vci], - ("h%d" % hi, "v%d" % vi)) - - for char, letter in predefined.items(): - for hi, hword in enumerate(horizontal): - if char in hword: - hci = hword.index(char) - problem.addConstraint(lambda hw, hci=hci, letter=letter: - hw[hci] == letter, ("h%d" % hi,)) - for vi, vword in enumerate(vertical): - if char in vword: - vci = vword.index(char) - problem.addConstraint(lambda vw, vci=vci, letter=letter: - vw[vci] == letter, ("v%d" % vi,)) - - wordsbylen = {} - for hword in horizontal: - wordsbylen[len(hword)] = [] - for vword in vertical: - wordsbylen[len(vword)] = [] - - for line in lines: - line = line.strip() - l = len(line) - if l in wordsbylen: - wordsbylen[l].append(line.upper()) - - for hi, hword in enumerate(horizontal): - words = wordsbylen[len(hword)] - random.shuffle(words) - problem.addVariable("h%d" % hi, words) - for vi, vword in enumerate(vertical): - words = wordsbylen[len(vword)] - random.shuffle(words) - problem.addVariable("v%d" % vi, words) - - problem.addConstraint(AllDifferentConstraint()) - - solution = problem.getSolution() - if not solution: - print "No solution found!" - - maxcol = 0 - maxrow = 0 - for hword in horizontal: - for row, col in hword: - if row > maxrow: - maxrow = row - if col > maxcol: - maxcol = col - for vword in vertical: - for row, col in vword: - if row > maxrow: - maxrow = row - if col > maxcol: - maxcol = col - - matrix = [] - for row in range(maxrow+1): - matrix.append([" "]*(maxcol+1)) - - for variable in solution: - if variable[0] == "v": - word = vertical[int(variable[1:])] - else: - word = horizontal[int(variable[1:])] - for (row, col), char in zip(word, solution[variable]): - matrix[row][col] = char - - for row in range(maxrow+1): - for col in range(maxcol+1): - sys.stdout.write(matrix[row][col]) - sys.stdout.write("\n") - -if __name__ == "__main__": - if len(sys.argv) != 3: - sys.exit("Usage: crosswords.py ") - main(open(sys.argv[1]).read(), open(sys.argv[2])) - diff --git a/csp/csp/python-constraint/examples/crosswords/large.mask b/csp/csp/python-constraint/examples/crosswords/large.mask deleted file mode 100644 index ba5364c8..00000000 --- a/csp/csp/python-constraint/examples/crosswords/large.mask +++ /dev/null @@ -1,27 +0,0 @@ - -# ######## # -# # # # # -######## # # -# # # # # -# # ######## -# # # # # # -######## # # -# # # # # # - # # # -######## # # - # # # # # - # ######## - # # # # # - # # ######## - # # # # # # - # # ######## - # # # # -######## # # - # # # # # # - # # # # # # - ######## # # - # # # # - # ######## - # # # # -######## # # - diff --git a/csp/csp/python-constraint/examples/crosswords/medium.mask b/csp/csp/python-constraint/examples/crosswords/medium.mask deleted file mode 100644 index 3332a097..00000000 --- a/csp/csp/python-constraint/examples/crosswords/medium.mask +++ /dev/null @@ -1,19 +0,0 @@ - - # -######### -# # # -# # ###### -# # # -# # # # -# # # # -######## # -# # # - # # # - ######### - # # # - ######### - # # # - # # -####### - # - diff --git a/csp/csp/python-constraint/examples/crosswords/python.mask b/csp/csp/python-constraint/examples/crosswords/python.mask deleted file mode 100644 index fe5a5767..00000000 --- a/csp/csp/python-constraint/examples/crosswords/python.mask +++ /dev/null @@ -1,8 +0,0 @@ - P - Y -####T#### - # H # - # O # -####N # - # # -######### diff --git a/csp/csp/python-constraint/examples/crosswords/small.mask b/csp/csp/python-constraint/examples/crosswords/small.mask deleted file mode 100644 index 0e43ff78..00000000 --- a/csp/csp/python-constraint/examples/crosswords/small.mask +++ /dev/null @@ -1,8 +0,0 @@ - # - # -######### - # # - # # # # -##### # # - # # # -######### diff --git a/csp/csp/python-constraint/examples/einstein/einstein.py b/csp/csp/python-constraint/examples/einstein/einstein.py deleted file mode 100755 index ede13f88..00000000 --- a/csp/csp/python-constraint/examples/einstein/einstein.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/python -# -# ALBERT EINSTEIN'S RIDDLE -# -# ARE YOU IN THE TOP 2% OF INTELLIGENT PEOPLE IN THE WORLD? -# SOLVE THE RIDDLE AND FIND OUT. -# -# There are no tricks, just pure logic, so good luck and don't give up. -# -# 1. In a street there are five houses, painted five different colours. -# 2. In each house lives a person of different nationality -# 3. These five homeowners each drink a different kind of beverage, smoke -# different brand of cigar and keep a different pet. -# -# THE QUESTION: WHO OWNS THE FISH? -# -# HINTS -# -# 1. The Brit lives in a red house. -# 2. The Swede keeps dogs as pets. -# 3. The Dane drinks tea. -# 4. The Green house is on the left of the White house. -# 5. The owner of the Green house drinks coffee. -# 6. The person who smokes Pall Mall rears birds. -# 7. The owner of the Yellow house smokes Dunhill. -# 8. The man living in the centre house drinks milk. -# 9. The Norwegian lives in the first house. -# 10. The man who smokes Blends lives next to the one who keeps cats. -# 11. The man who keeps horses lives next to the man who smokes Dunhill. -# 12. The man who smokes Blue Master drinks beer. -# 13. The German smokes Prince. -# 14. The Norwegian lives next to the blue house. -# 15. The man who smokes Blends has a neighbour who drinks water. -# -# ALBERT EINSTEIN WROTE THIS RIDDLE EARLY DURING THE 19th CENTURY. HE -# SAID THAT 98% OF THE WORLD POPULATION WOULD NOT BE ABLE TO SOLVE IT. - -from constraint import * - -# Check http://www.csc.fi/oppaat/f95/python/talot.py - -def main(): - problem = Problem() - for i in range(1,6): - problem.addVariable("color%d" % i, - ["red", "white", "green", "yellow", "blue"]) - problem.addVariable("nationality%d" % i, - ["brit", "swede", "dane", "norwegian", "german"]) - problem.addVariable("drink%d" % i, - ["tea", "coffee", "milk", "beer", "water"]) - problem.addVariable("smoke%d" % i, - ["pallmall", "dunhill", "blends", - "bluemaster", "prince"]) - problem.addVariable("pet%d" % i, - ["dogs", "birds", "cats", "horses", "fish"]) - - problem.addConstraint(AllDifferentConstraint(), - ["color%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["nationality%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["drink%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["smoke%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["pet%d" % i for i in range(1,6)]) - - for i in range(1,6): - - # Hint 1 - problem.addConstraint(lambda nationality, color: - nationality != "brit" or color == "red", - ("nationality%d" % i, "color%d" % i)) - - # Hint 2 - problem.addConstraint(lambda nationality, pet: - nationality != "swede" or pet == "dogs", - ("nationality%d" % i, "pet%d" % i)) - - # Hint 3 - problem.addConstraint(lambda nationality, drink: - nationality != "dane" or drink == "tea", - ("nationality%d" % i, "drink%d" % i)) - - # Hint 4 - if i < 5: - problem.addConstraint(lambda colora, colorb: - colora != "green" or colorb == "white", - ("color%d" % i, "color%d" % (i+1))) - else: - problem.addConstraint(lambda color: color != "green", - ("color%d" % i,)) - - # Hint 5 - problem.addConstraint(lambda color, drink: - color != "green" or drink == "coffee", - ("color%d" % i, "drink%d" % i)) - - # Hint 6 - problem.addConstraint(lambda smoke, pet: - smoke != "pallmall" or pet == "birds", - ("smoke%d" % i, "pet%d" % i)) - - # Hint 7 - problem.addConstraint(lambda color, smoke: - color != "yellow" or smoke == "dunhill", - ("color%d" % i, "smoke%d" % i)) - - # Hint 8 - if i == 3: - problem.addConstraint(lambda drink: drink == "milk", - ("drink%d" % i,)) - - # Hint 9 - if i == 1: - problem.addConstraint(lambda nationality: - nationality == "norwegian", - ("nationality%d" % i,)) - - # Hint 10 - if 1 < i < 5: - problem.addConstraint(lambda smoke, peta, petb: - smoke != "blends" or peta == "cats" or - petb == "cats", - ("smoke%d" % i, "pet%d" % (i-1), - "pet%d" % (i+1))) - else: - problem.addConstraint(lambda smoke, pet: - smoke != "blends" or pet == "cats", - ("smoke%d" % i, - "pet%d" % (i == 1 and 2 or 4))) - - # Hint 11 - if 1 < i < 5: - problem.addConstraint(lambda pet, smokea, smokeb: - pet != "horses" or smokea == "dunhill" or - smokeb == "dunhill", - ("pet%d" % i, "smoke%d" % (i-1), - "smoke%d" % (i+1))) - else: - problem.addConstraint(lambda pet, smoke: - pet != "horses" or smoke == "dunhill", - ("pet%d" % i, - "smoke%d" % (i == 1 and 2 or 4))) - - # Hint 12 - problem.addConstraint(lambda smoke, drink: - smoke != "bluemaster" or drink == "beer", - ("smoke%d" % i, "drink%d" % i)) - - # Hint 13 - problem.addConstraint(lambda nationality, smoke: - nationality != "german" or smoke == "prince", - ("nationality%d" % i, "smoke%d" % i)) - - # Hint 14 - if 1 < i < 5: - problem.addConstraint(lambda nationality, colora, colorb: - nationality != "norwegian" or - colora == "blue" or colorb == "blue", - ("nationality%d" % i, "color%d" % (i-1), - "color%d" % (i+1))) - else: - problem.addConstraint(lambda nationality, color: - nationality != "norwegian" or - color == "blue", - ("nationality%d" % i, - "color%d" % (i == 1 and 2 or 4))) - - # Hint 15 - if 1 < i < 5: - problem.addConstraint(lambda smoke, drinka, drinkb: - smoke != "blends" or - drinka == "water" or drinkb == "water", - ("smoke%d" % i, "drink%d" % (i-1), - "drink%d" % (i+1))) - else: - problem.addConstraint(lambda smoke, drink: - smoke != "blends" or drink == "water", - ("smoke%d" % i, - "drink%d" % (i == 1 and 2 or 4))) - - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - print - for solution in solutions: - showSolution(solution) - -def showSolution(solution): - for i in range(1,6): - print "House %d" % i - print "--------" - print "Nationality: %s" % solution["nationality%d" % i] - print "Color: %s" % solution["color%d" % i] - print "Drink: %s" % solution["drink%d" % i] - print "Smoke: %s" % solution["smoke%d" % i] - print "Pet: %s" % solution["pet%d" % i] - print - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/examples/einstein/einstein2.py b/csp/csp/python-constraint/examples/einstein/einstein2.py deleted file mode 100755 index d1f7b86d..00000000 --- a/csp/csp/python-constraint/examples/einstein/einstein2.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/python -# -# ALBERT EINSTEIN'S RIDDLE -# -# ARE YOU IN THE TOP 2% OF INTELLIGENT PEOPLE IN THE WORLD? -# SOLVE THE RIDDLE AND FIND OUT. -# -# There are no tricks, just pure logic, so good luck and don't give up. -# -# 1. In a street there are five houses, painted five different colours. -# 2. In each house lives a person of different nationality -# 3. These five homeowners each drink a different kind of beverage, smoke -# different brand of cigar and keep a different pet. -# -# THE QUESTION: WHO OWNS THE zebra? -# -# HINTS -# -# 1. The englishman lives in a red house. -# 2. The spaniard keeps dogs as pets. -# 5. The owner of the Green house drinks coffee. -# 3. The ukrainian drinks tea. -# 4. The Green house is on the left of the ivory house. -# 6. The person who smokes oldgold rears snails. -# 7. The owner of the Yellow house smokes kools. -# 8. The man living in the centre house drinks milk. -# 9. The Norwegian lives in the first house. -# 10. The man who smokes chesterfields lives next to the one who keeps foxes. -# 11. The man who keeps horses lives next to the man who smokes kools. -# 12. The man who smokes luckystrike drinks orangejuice. -# 13. The japanese smokes parliaments. -# 14. The Norwegian lives next to the blue house. -# 15. The man who smokes chesterfields has a neighbour who drinks water. -# -# ALBERT EINSTEIN WROTE THIS RIDDLE EARLY DURING THE 19th CENTURY. HE -# SAID THAT 98% OF THE WORLD POPULATION WOULD NOT BE ABLE TO SOLVE IT. - -from constraint import * - -# Check http://www.csc.fi/oppaat/f95/python/talot.py - -def main(): - problem = Problem() - for i in range(1,6): - problem.addVariable("color%d" % i, - ["red", "ivory", "green", "yellow", "blue"]) - problem.addVariable("nationality%d" % i, - ["englishman", "spaniard", "ukrainian", "norwegian", "japanese"]) - problem.addVariable("drink%d" % i, - ["tea", "coffee", "milk", "orangejuice", "water"]) - problem.addVariable("smoke%d" % i, - ["oldgold", "kools", "chesterfields", - "luckystrike", "parliaments"]) - problem.addVariable("pet%d" % i, - ["dogs", "snails", "foxes", "horses", "zebra"]) - - problem.addConstraint(AllDifferentConstraint(), - ["color%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["nationality%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["drink%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["smoke%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["pet%d" % i for i in range(1,6)]) - - for i in range(1,6): - - # Hint 1 - problem.addConstraint(lambda nationality, color: - nationality != "englishman" or color == "red", - ("nationality%d" % i, "color%d" % i)) - - # Hint 2 - problem.addConstraint(lambda nationality, pet: - nationality != "spaniard" or pet == "dogs", - ("nationality%d" % i, "pet%d" % i)) - - # Hint 3 - problem.addConstraint(lambda nationality, drink: - nationality != "ukrainian" or drink == "tea", - ("nationality%d" % i, "drink%d" % i)) - - # Hint 4 - if i < 5: - problem.addConstraint(lambda colora, colorb: - colora != "green" or colorb == "ivory", - ("color%d" % i, "color%d" % (i+1))) - else: - problem.addConstraint(lambda color: color != "green", - ("color%d" % i,)) - - # Hint 5 - problem.addConstraint(lambda color, drink: - color != "green" or drink == "coffee", - ("color%d" % i, "drink%d" % i)) - - # Hint 6 - problem.addConstraint(lambda smoke, pet: - smoke != "oldgold" or pet == "snails", - ("smoke%d" % i, "pet%d" % i)) - - # Hint 7 - problem.addConstraint(lambda color, smoke: - color != "yellow" or smoke == "kools", - ("color%d" % i, "smoke%d" % i)) - - # Hint 8 - if i == 3: - problem.addConstraint(lambda drink: drink == "milk", - ("drink%d" % i,)) - - # Hint 9 - if i == 1: - problem.addConstraint(lambda nationality: - nationality == "norwegian", - ("nationality%d" % i,)) - - # Hint 10 - if 1 < i < 5: - problem.addConstraint(lambda smoke, peta, petb: - smoke != "chesterfields" or peta == "foxes" or - petb == "foxes", - ("smoke%d" % i, "pet%d" % (i-1), - "pet%d" % (i+1))) - else: - problem.addConstraint(lambda smoke, pet: - smoke != "chesterfields" or pet == "foxes", - ("smoke%d" % i, - "pet%d" % (i == 1 and 2 or 4))) - - # Hint 11 - if 1 < i < 5: - problem.addConstraint(lambda pet, smokea, smokeb: - pet != "horses" or smokea == "kools" or - smokeb == "kools", - ("pet%d" % i, "smoke%d" % (i-1), - "smoke%d" % (i+1))) - else: - problem.addConstraint(lambda pet, smoke: - pet != "horses" or smoke == "kools", - ("pet%d" % i, - "smoke%d" % (i == 1 and 2 or 4))) - - # Hint 12 - problem.addConstraint(lambda smoke, drink: - smoke != "luckystrike" or drink == "orangejuice", - ("smoke%d" % i, "drink%d" % i)) - - # Hint 13 - problem.addConstraint(lambda nationality, smoke: - nationality != "japanese" or smoke == "parliaments", - ("nationality%d" % i, "smoke%d" % i)) - - # Hint 14 - if 1 < i < 5: - problem.addConstraint(lambda nationality, colora, colorb: - nationality != "norwegian" or - colora == "blue" or colorb == "blue", - ("nationality%d" % i, "color%d" % (i-1), - "color%d" % (i+1))) - else: - problem.addConstraint(lambda nationality, color: - nationality != "norwegian" or - color == "blue", - ("nationality%d" % i, - "color%d" % (i == 1 and 2 or 4))) - - - - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - print - for solution in solutions: - showSolution(solution) - -def showSolution(solution): - for i in range(1,6): - print "House %d" % i - print "--------" - print "Nationality: %s" % solution["nationality%d" % i] - print "Color: %s" % solution["color%d" % i] - print "Drink: %s" % solution["drink%d" % i] - print "Smoke: %s" % solution["smoke%d" % i] - print "Pet: %s" % solution["pet%d" % i] - print - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/examples/queens/queens.py b/csp/csp/python-constraint/examples/queens/queens.py deleted file mode 100755 index deac7131..00000000 --- a/csp/csp/python-constraint/examples/queens/queens.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/python -# -# http://mathworld.wolfram.com/QueensProblem.html -# -from constraint import * -import sys - -def main(show=False): - problem = Problem() - size = 8 - cols = range(size) - rows = range(size) - problem.addVariables(cols, rows) - for col1 in cols: - for col2 in cols: - if col1 < col2: - problem.addConstraint(lambda row1, row2, col1=col1, col2=col2: - abs(row1-row2) != abs(col1-col2) and - row1 != row2, (col1, col2)) - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - if show: - for solution in solutions: - showSolution(solution, size) - -def showSolution(solution, size): - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - for i in range(size): - sys.stdout.write(" |") - for j in range(size): - if solution[j] == i: - sys.stdout.write(" %d |" % j) - else: - sys.stdout.write(" |") - sys.stdout.write("\n") - if i != size-1: - sys.stdout.write(" |%s|\n" % ("-"*((size*4)-1))) - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - -if __name__ == "__main__": - show = False - if len(sys.argv) == 2 and sys.argv[1] == "-s": - show = True - elif len(sys.argv) != 1: - sys.exit("Usage: queens.py [-s]") - main(show) - diff --git a/csp/csp/python-constraint/examples/rooks/rooks.py b/csp/csp/python-constraint/examples/rooks/rooks.py deleted file mode 100755 index 14f88b1e..00000000 --- a/csp/csp/python-constraint/examples/rooks/rooks.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/python -# -# http://mathworld.wolfram.com/RooksProblem.html -# -from constraint import * -import sys - -def factorial(x): return x == 1 or factorial(x-1)*x - -def main(show=False): - problem = Problem() - size = 8 - cols = range(size) - rows = range(size) - problem.addVariables(cols, rows) - for col1 in cols: - for col2 in cols: - if col1 < col2: - problem.addConstraint(lambda row1, row2: row1 != row2, - (col1, col2)) - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - assert len(solutions) == factorial(size) - if show: - for solution in solutions: - showSolution(solution, size) - -def showSolution(solution, size): - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - for i in range(size): - sys.stdout.write(" |") - for j in range(size): - if solution[j] == i: - sys.stdout.write(" %d |" % j) - else: - sys.stdout.write(" |") - sys.stdout.write("\n") - if i != size-1: - sys.stdout.write(" |%s|\n" % ("-"*((size*4)-1))) - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - -if __name__ == "__main__": - show = False - if len(sys.argv) == 2 and sys.argv[1] == "-s": - show = True - elif len(sys.argv) != 1: - sys.exit("Usage: rooks.py [-s]") - main(show) - diff --git a/csp/csp/python-constraint/examples/studentdesks/studentdesks.py b/csp/csp/python-constraint/examples/studentdesks/studentdesks.py deleted file mode 100755 index e8d47792..00000000 --- a/csp/csp/python-constraint/examples/studentdesks/studentdesks.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/python -# -# http://home.chello.no/~dudley/ -# -from constraint import * -import sys - -STUDENTDESKS = [[ 0, 1, 0, 0, 0, 0], - [ 0, 2, 3, 4, 5, 6], - [ 0, 7, 8, 9, 10, 0], - [ 0, 11, 12, 13, 14, 0], - [ 15, 16, 17, 18, 19, 0], - [ 0, 0, 0, 0, 20, 0]] - -def main(): - problem = Problem() - problem.addVariables(range(1,21), ["A", "B", "C", "D", "E"]) - problem.addConstraint(SomeInSetConstraint(["A"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["B"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["C"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["D"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["E"], 4, True)) - for row in range(len(STUDENTDESKS)-1): - for col in range(len(STUDENTDESKS[row])-1): - lst = [STUDENTDESKS[row][col], STUDENTDESKS[row][col+1], - STUDENTDESKS[row+1][col], STUDENTDESKS[row+1][col+1]] - lst = [x for x in lst if x] - problem.addConstraint(AllDifferentConstraint(), lst) - showSolution(problem.getSolution()) - -def showSolution(solution): - for row in range(len(STUDENTDESKS)): - for col in range(len(STUDENTDESKS[row])): - id = STUDENTDESKS[row][col] - sys.stdout.write(" %s" % (id and solution[id] or " ")) - sys.stdout.write("\n") - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/examples/sudoku/sudoku.py b/csp/csp/python-constraint/examples/sudoku/sudoku.py deleted file mode 100644 index e79698ea..00000000 --- a/csp/csp/python-constraint/examples/sudoku/sudoku.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Sudoku puzzle solver by by Luigi Poderico (www.poderico.it). -# -from constraint import * - -problem = Problem() - -# Define the variables: 9 rows of 9 variables rangin in 1...9 -for i in range(1, 10) : - problem.addVariables(range(i*10+1, i*10+10), range(1, 10)) - -# Each row has different values -for i in range(1, 10) : - problem.addConstraint(AllDifferentConstraint(), range(i*10+1, i*10+10)) - -# Each colum has different values -for i in range(1, 10) : - problem.addConstraint(AllDifferentConstraint(), range(10+i, 100+i, 10)) - -# Each 3x3 box has different values -problem.addConstraint(AllDifferentConstraint(), [11,12,13,21,22,23,31,32,33]) -problem.addConstraint(AllDifferentConstraint(), [41,42,43,51,52,53,61,62,63]) -problem.addConstraint(AllDifferentConstraint(), [71,72,73,81,82,83,91,92,93]) - -problem.addConstraint(AllDifferentConstraint(), [14,15,16,24,25,26,34,35,36]) -problem.addConstraint(AllDifferentConstraint(), [44,45,46,54,55,56,64,65,66]) -problem.addConstraint(AllDifferentConstraint(), [74,75,76,84,85,86,94,95,96]) - -problem.addConstraint(AllDifferentConstraint(), [17,18,19,27,28,29,37,38,39]) -problem.addConstraint(AllDifferentConstraint(), [47,48,49,57,58,59,67,68,69]) -problem.addConstraint(AllDifferentConstraint(), [77,78,79,87,88,89,97,98,99]) - -# Some value is given. -initValue = [[0, 9, 0, 7, 0, 0, 8, 6, 0], - [0, 3, 1, 0, 0, 5, 0, 2, 0], - [8, 0, 6, 0, 0, 0, 0, 0, 0], - [0, 0, 7, 0, 5, 0, 0, 0, 6], - [0, 0, 0, 3, 0, 7, 0, 0, 0], - [5, 0, 0, 0, 1, 0, 7, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0, 9], - [0, 2, 0, 6, 0, 0, 0, 5, 0], - [0, 5, 4, 0, 0, 8, 0, 7, 0]] - -for i in range(1, 10) : - for j in range(1, 10): - if initValue[i-1][j-1] !=0 : - problem.addConstraint(lambda var, val=initValue[i-1][j-1]: - var==val, (i*10+j,)) - -# Get the solutions. -solutions = problem.getSolutions() - -# Print the solutions -for solution in solutions: - for i in range(1, 10): - for j in range(1, 10): - index = i*10+j - print solution[index], - print - print - diff --git a/csp/csp/python-constraint/examples/wordmath/seisseisdoze.py b/csp/csp/python-constraint/examples/wordmath/seisseisdoze.py deleted file mode 100755 index b17956db..00000000 --- a/csp/csp/python-constraint/examples/wordmath/seisseisdoze.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python -# -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# SEIS -# + SEIS -# ------ -# DOZE -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("seidoz", range(10)) - problem.addConstraint(lambda s, e: (2*s)%10 == e, "se") - problem.addConstraint(lambda i, s, z, e: ((10*2*i)+(2*s))%100 == z*10+e, - "isze") - problem.addConstraint(lambda s, e, i, d, o, z: - 2*(s*1000+e*100+i*10+s) == d*1000+o*100+z*10+e, - "seidoz") - problem.addConstraint(lambda s: s != 0, "s") - problem.addConstraint(lambda d: d != 0, "d") - problem.addConstraint(AllDifferentConstraint()) - print "SEIS+SEIS=DOZE" - for s in problem.getSolutions(): - print ("%(s)d%(e)d%(i)d%(s)s+%(s)d%(e)d%(i)d%(s)d=" - "%(d)d%(o)d%(z)d%(e)d") % s - -if __name__ == "__main__": - main() - diff --git a/csp/csp/python-constraint/examples/wordmath/sendmoremoney.py b/csp/csp/python-constraint/examples/wordmath/sendmoremoney.py deleted file mode 100755 index 894b0cd5..00000000 --- a/csp/csp/python-constraint/examples/wordmath/sendmoremoney.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python -# -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# SEND -# + MORE -# ------ -# MONEY -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("sendmory", range(10)) - problem.addConstraint(lambda d, e, y: (d+e)%10 == y, "dey") - problem.addConstraint(lambda n, d, r, e, y: (n*10+d+r*10+e)%100 == e*10+y, - "ndrey") - problem.addConstraint(lambda e, n, d, o, r, y: - (e*100+n*10+d+o*100+r*10+e)%1000 == n*100+e*10+y, - "endory") - problem.addConstraint(lambda s, e, n, d, m, o, r, y: - 1000*s+100*e+10*n+d + 1000*m+100*o+10*r+e == - 10000*m+1000*o+100*n+10*e+y, "sendmory") - problem.addConstraint(NotInSetConstraint([0]), "sm") - problem.addConstraint(AllDifferentConstraint()) - print "SEND+MORE=MONEY" - for s in problem.getSolutions(): - print "%(s)d%(e)d%(n)d%(d)d+" \ - "%(m)d%(o)d%(r)d%(e)d=" \ - "%(m)d%(o)d%(n)d%(e)d%(y)d" % s - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/examples/wordmath/twotwofour.py b/csp/csp/python-constraint/examples/wordmath/twotwofour.py deleted file mode 100755 index b9e70d6a..00000000 --- a/csp/csp/python-constraint/examples/wordmath/twotwofour.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python -# -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# TWO -# + TWO -# ----- -# FOUR -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("twofur", range(10)) - problem.addConstraint(lambda o, r: (2*o)%10 == r, "or") - problem.addConstraint(lambda w, o, u, r: ((10*2*w)+(2*o))%100 == u*10+r, - "wour") - problem.addConstraint(lambda t, w, o, f, u, r: - 2*(t*100+w*10+o) == f*1000+o*100+u*10+r, "twofur") - problem.addConstraint(NotInSetConstraint([0]), "ft") - problem.addConstraint(AllDifferentConstraint()) - print "TWO+TWO=FOUR" - for s in problem.getSolutions(): - print "%(t)d%(w)d%(o)d+%(t)d%(w)d%(o)d=%(f)d%(o)d%(u)d%(r)d" % s - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/examples/xsum/xsum.py b/csp/csp/python-constraint/examples/xsum/xsum.py deleted file mode 100755 index 0f5f70b6..00000000 --- a/csp/csp/python-constraint/examples/xsum/xsum.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/python -# -# Reorganize the following numbers in a way that each line of -# 5 numbers sum to 27. -# -# 1 6 -# 2 7 -# 3 -# 8 4 -# 9 5 -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("abcdxefgh", range(1,10)) - problem.addConstraint(lambda a, b, c, d, x: - a < b < c < d and a+b+c+d+x == 27, "abcdx") - problem.addConstraint(lambda e, f, g, h, x: - e < f < g < h and e+f+g+h+x == 27, "efghx") - problem.addConstraint(AllDifferentConstraint()) - solutions = problem.getSolutions() - print "Found %d solutions!" % len(solutions) - showSolutions(solutions) - -def showSolutions(solutions): - for solution in solutions: - print " %d %d" % (solution["a"], solution["e"]) - print " %d %d " % (solution["b"], solution["f"]) - print " %d " % (solution["x"],) - print " %d %d " % (solution["g"], solution["c"]) - print " %d %d" % (solution["h"], solution["d"]) - print - -if __name__ == "__main__": - main() - diff --git a/csp/csp/python-constraint/setup.cfg b/csp/csp/python-constraint/setup.cfg deleted file mode 100644 index 33d88e05..00000000 --- a/csp/csp/python-constraint/setup.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[bdist_rpm] -doc_files = README -use_bzip2 = 1 - -[sdist] -formats = bztar diff --git a/csp/csp/python-constraint/setup.py b/csp/csp/python-constraint/setup.py deleted file mode 100755 index cda67133..00000000 --- a/csp/csp/python-constraint/setup.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/python -from distutils.core import setup -import os - -if os.path.isfile("MANIFEST"): - os.unlink("MANIFEST") - -setup(name="python-constraint", - version = "1.2", - description = "Python module for handling Constraint Solving Problems", - author = "Gustavo Niemeyer", - author_email = "gustavo@niemeyer.net", - url = "http://labix.org/python-constraint", - license = "Simplified BSD", - long_description = -""" -python-constraint is a module implementing support for handling CSPs -(Constraint Solving Problems) over finite domains. -""", - py_modules = ["constraint"], - ) diff --git a/csp/csp/python-constraint/testconstraint.py b/csp/csp/python-constraint/testconstraint.py deleted file mode 100644 index 9b9f5c5c..00000000 --- a/csp/csp/python-constraint/testconstraint.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/python - -from constraint import * - -#p = Problem() -#p.addVariable("ab", [1, 2]) -#p.addVariable("c", [3]) -#print p.getSolutions() - -problem = Problem() -problem.addVariables(["a", "b"], [1, 2]) -problem.addConstraint(AllDifferentConstraint()) -print problem.getSolutions() \ No newline at end of file diff --git a/csp/csp/python-constraint/trials/abcd.py b/csp/csp/python-constraint/trials/abcd.py deleted file mode 100755 index 55bedaca..00000000 --- a/csp/csp/python-constraint/trials/abcd.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/python -# -# What's the minimum value for: -# -# ABC -# ------- -# A+B+C -# -# From http://www.umassd.edu/mathcontest/abc.cfm -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("abc", range(1,10)) - results = [] - for solution in problem.getSolutions(): - a = solution["a"] - b = solution["b"] - c = solution["c"] - 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() diff --git a/csp/csp/python-constraint/trials/coins.py b/csp/csp/python-constraint/trials/coins.py deleted file mode 100755 index cb47537d..00000000 --- a/csp/csp/python-constraint/trials/coins.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python -# -# 100 coins must sum to $5.00 -# -# That's kind of a country-specific problem, since depending on the -# country there are different values for coins. Here is presented -# the solution for a given set. -# -from constraint import * -import sys - -def main(): - problem = Problem() - total = 5.00 - variables = ("0.01", "0.05", "0.10", "0.25") - values = [float(x) for x in variables] - for variable, value in zip(variables, values): - problem.addVariable(variable, range(int(total/value))) - problem.addConstraint(ExactSumConstraint(total, values), variables) - problem.addConstraint(ExactSumConstraint(100)) - solutions = problem.getSolutionIter() - for i, solution in enumerate(solutions): - sys.stdout.write("%03d -> " % (i+1)) - for variable in variables: - sys.stdout.write("%s:%d " % (variable, solution[variable])) - sys.stdout.write("\n") - -if __name__ == "__main__": - main() - diff --git a/csp/csp/python-constraint/trials/constraint.py b/csp/csp/python-constraint/trials/constraint.py deleted file mode 100644 index b1cd836b..00000000 --- a/csp/csp/python-constraint/trials/constraint.py +++ /dev/null @@ -1,1434 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2005-2014 - Gustavo Niemeyer -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" -@var Unassigned: Helper object instance representing unassigned values - -@sort: Problem, Variable, Domain -@group Solvers: Solver, - BacktrackingSolver, - RecursiveBacktrackingSolver, - MinConflictsSolver -@group Constraints: Constraint, - FunctionConstraint, - AllDifferentConstraint, - AllEqualConstraint, - MaxSumConstraint, - ExactSumConstraint, - MinSumConstraint, - InSetConstraint, - NotInSetConstraint, - SomeInSetConstraint, - SomeNotInSetConstraint -""" -import random -import copy - -__all__ = ["Problem", "Variable", "Domain", "Unassigned", - "Solver", "BacktrackingSolver", "RecursiveBacktrackingSolver", - "MinConflictsSolver", "Constraint", "FunctionConstraint", - "AllDifferentConstraint", "AllEqualConstraint", "MaxSumConstraint", - "ExactSumConstraint", "MinSumConstraint", "InSetConstraint", - "NotInSetConstraint", "SomeInSetConstraint", - "SomeNotInSetConstraint"] - -class Problem(object): - """ - Class used to define a problem and retrieve solutions - """ - - def __init__(self, solver=None): - """ - @param solver: Problem solver used to find solutions - (default is L{BacktrackingSolver}) - @type solver: instance of a L{Solver} subclass - """ - self._solver = solver or BacktrackingSolver() - self._constraints = [] - self._variables = {} - - def reset(self): - """ - Reset the current problem definition - - Example: - - >>> problem = Problem() - >>> problem.addVariable("a", [1, 2]) - >>> problem.reset() - >>> problem.getSolution() - >>> - """ - del self._constraints[:] - self._variables.clear() - - def setSolver(self, solver): - """ - Change the problem solver currently in use - - Example: - - >>> solver = BacktrackingSolver() - >>> problem = Problem(solver) - >>> problem.getSolver() is solver - True - - @param solver: New problem solver - @type solver: instance of a C{Solver} subclass - """ - self._solver = solver - - def getSolver(self): - """ - Obtain the problem solver currently in use - - Example: - - >>> solver = BacktrackingSolver() - >>> problem = Problem(solver) - >>> problem.getSolver() is solver - True - - @return: Solver currently in use - @rtype: instance of a L{Solver} subclass - """ - return self._solver - - def addVariable(self, variable, domain): - """ - Add a variable to the problem - - Example: - - >>> problem = Problem() - >>> problem.addVariable("a", [1, 2]) - >>> problem.getSolution() in ({'a': 1}, {'a': 2}) - True - - @param variable: Object representing a problem variable - @type variable: hashable object - @param domain: Set of items defining the possible values that - the given variable may assume - @type domain: list, tuple, or instance of C{Domain} - """ - if variable in self._variables: - raise ValueError, "Tried to insert duplicated variable %s" % \ - repr(variable) - if type(domain) in (list, tuple): - domain = Domain(domain) - elif isinstance(domain, Domain): - domain = copy.copy(domain) - else: - raise TypeError, "Domains must be instances of subclasses of "\ - "the Domain class" - if not domain: - raise ValueError, "Domain is empty" - self._variables[variable] = domain - - def addVariables(self, variables, domain): - """ - Add one or more variables to the problem - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> solutions = problem.getSolutions() - >>> len(solutions) - 9 - >>> {'a': 3, 'b': 1} in solutions - True - - @param variables: Any object containing a sequence of objects - represeting problem variables - @type variables: sequence of hashable objects - @param domain: Set of items defining the possible values that - the given variables may assume - @type domain: list, tuple, or instance of C{Domain} - """ - for variable in variables: - self.addVariable(variable, domain) - - def addConstraint(self, constraint, variables=None): - """ - Add a constraint to the problem - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b == a+1, ["a", "b"]) - >>> solutions = problem.getSolutions() - >>> - - @param constraint: Constraint to be included in the problem - @type constraint: instance a L{Constraint} subclass or a - function to be wrapped by L{FunctionConstraint} - @param variables: Variables affected by the constraint (default to - all variables). Depending on the constraint type - the order may be important. - @type variables: set or sequence of variables - """ - if not isinstance(constraint, Constraint): - if callable(constraint): - constraint = FunctionConstraint(constraint) - else: - raise ValueError, "Constraints must be instances of "\ - "subclasses of the Constraint class" - self._constraints.append((constraint, variables)) - - def getSolution(self): - """ - Find and return a solution to the problem - - Example: - - >>> problem = Problem() - >>> problem.getSolution() is None - True - >>> problem.addVariables(["a"], [42]) - >>> problem.getSolution() - {'a': 42} - - @return: Solution for the problem - @rtype: dictionary mapping variables to values - """ - domains, constraints, vconstraints = self._getArgs() - if not domains: - return None - return self._solver.getSolution(domains, constraints, vconstraints) - - def getSolutions(self): - """ - Find and return all solutions to the problem - - Example: - - >>> problem = Problem() - >>> problem.getSolutions() == [] - True - >>> problem.addVariables(["a"], [42]) - >>> problem.getSolutions() - [{'a': 42}] - - @return: All solutions for the problem - @rtype: list of dictionaries mapping variables to values - """ - domains, constraints, vconstraints = self._getArgs() - if not domains: - return [] - return self._solver.getSolutions(domains, constraints, vconstraints) - - def getSolutionIter(self): - """ - Return an iterator to the solutions of the problem - - Example: - - >>> problem = Problem() - >>> list(problem.getSolutionIter()) == [] - True - >>> problem.addVariables(["a"], [42]) - >>> iter = problem.getSolutionIter() - >>> iter.next() - {'a': 42} - >>> iter.next() - Traceback (most recent call last): - File "", line 1, in ? - StopIteration - """ - domains, constraints, vconstraints = self._getArgs() - if not domains: - return iter(()) - return self._solver.getSolutionIter(domains, constraints, - vconstraints) - - def _getArgs(self): - domains = self._variables.copy() - allvariables = domains.keys() - constraints = [] - for constraint, variables in self._constraints: - if not variables: - variables = allvariables - constraints.append((constraint, variables)) - vconstraints = {} - for variable in domains: - vconstraints[variable] = [] - for constraint, variables in constraints: - for variable in variables: - vconstraints[variable].append((constraint, variables)) - for constraint, variables in constraints[:]: - constraint.preProcess(variables, domains, - constraints, vconstraints) - for domain in domains.values(): - domain.resetState() - if not domain: - return None, None, None - #doArc8(getArcs(domains, constraints), domains, {}) - return domains, constraints, vconstraints - -# ---------------------------------------------------------------------- -# Solvers -# ---------------------------------------------------------------------- - -def getArcs(domains, constraints): - """ - Return a dictionary mapping pairs (arcs) of constrained variables - - @attention: Currently unused. - """ - arcs = {} - for x in constraints: - constraint, variables = x - if len(variables) == 2: - variable1, variable2 = variables - arcs.setdefault(variable1, {})\ - .setdefault(variable2, [])\ - .append(x) - arcs.setdefault(variable2, {})\ - .setdefault(variable1, [])\ - .append(x) - return arcs - -def doArc8(arcs, domains, assignments): - """ - Perform the ARC-8 arc checking algorithm and prune domains - - @attention: Currently unused. - """ - check = dict.fromkeys(domains, True) - while check: - variable, _ = check.popitem() - if variable not in arcs or variable in assignments: - continue - domain = domains[variable] - arcsvariable = arcs[variable] - for othervariable in arcsvariable: - arcconstraints = arcsvariable[othervariable] - if othervariable in assignments: - otherdomain = [assignments[othervariable]] - else: - otherdomain = domains[othervariable] - if domain: - changed = False - for value in domain[:]: - assignments[variable] = value - if otherdomain: - for othervalue in otherdomain: - assignments[othervariable] = othervalue - for constraint, variables in arcconstraints: - if not constraint(variables, domains, - assignments, True): - break - else: - # All constraints passed. Value is safe. - break - else: - # All othervalues failed. Kill value. - domain.hideValue(value) - changed = True - del assignments[othervariable] - del assignments[variable] - #if changed: - # check.update(dict.fromkeys(arcsvariable)) - if not domain: - return False - return True - -class Solver(object): - """ - Abstract base class for solvers - - @sort: getSolution, getSolutions, getSolutionIter - """ - - def getSolution(self, domains, constraints, vconstraints): - """ - Return one solution for the given problem - - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """ - raise NotImplementedError, \ - "%s is an abstract class" % self.__class__.__name__ - - def getSolutions(self, domains, constraints, vconstraints): - """ - Return all solutions for the given problem - - @param domains: Dictionary mapping variables to domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """ - raise NotImplementedError, \ - "%s provides only a single solution" % self.__class__.__name__ - - def getSolutionIter(self, domains, constraints, vconstraints): - """ - Return an iterator for the solutions of the given problem - - @param domains: Dictionary mapping variables to domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """ - raise NotImplementedError, \ - "%s doesn't provide iteration" % self.__class__.__name__ - -class BacktrackingSolver(Solver): - """ - Problem solver with backtracking capabilities - - Examples: - - >>> result = [[('a', 1), ('b', 2)], - ... [('a', 1), ('b', 3)], - ... [('a', 2), ('b', 3)]] - - >>> problem = Problem(BacktrackingSolver()) - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b > a, ["a", "b"]) - - >>> solution = problem.getSolution() - >>> sorted(solution.items()) in result - True - - >>> for solution in problem.getSolutionIter(): - ... sorted(solution.items()) in result - True - True - True - - >>> for solution in problem.getSolutions(): - ... sorted(solution.items()) in result - True - True - True - """#""" - - def __init__(self, forwardcheck=True): - """ - @param forwardcheck: If false forward checking will not be requested - to constraints while looking for solutions - (default is true) - @type forwardcheck: bool - """ - self._forwardcheck = forwardcheck - - def getSolutionIter(self, domains, constraints, vconstraints): - forwardcheck = self._forwardcheck - assignments = {} - - queue = [] - - while True: - - # Mix the Degree and Minimum Remaing Values (MRV) heuristics - lst = [(-len(vconstraints[variable]), - len(domains[variable]), variable) for variable in domains] - lst.sort() - for item in lst: - if item[-1] not in assignments: - # Found unassigned variable - variable = item[-1] - values = domains[variable][:] - if forwardcheck: - pushdomains = [domains[x] for x in domains - if x not in assignments and - x != variable] - else: - pushdomains = None - break - else: - # No unassigned variables. We've got a solution. Go back - # to last variable, if there's one. - yield assignments.copy() - if not queue: - return - variable, values, pushdomains = queue.pop() - if pushdomains: - for domain in pushdomains: - domain.popState() - - while True: - # We have a variable. Do we have any values left? - if not values: - # No. Go back to last variable, if there's one. - del assignments[variable] - while queue: - variable, values, pushdomains = queue.pop() - if pushdomains: - for domain in pushdomains: - domain.popState() - if values: - break - del assignments[variable] - else: - return - - # Got a value. Check it. - assignments[variable] = values.pop() - - if pushdomains: - for domain in pushdomains: - domain.pushState() - - for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments, - pushdomains): - # Value is not good. - break - else: - break - - if pushdomains: - for domain in pushdomains: - domain.popState() - - # Push state before looking for next variable. - queue.append((variable, values, pushdomains)) - - raise RuntimeError, "Can't happen" - - def getSolution(self, domains, constraints, vconstraints): - iter = self.getSolutionIter(domains, constraints, vconstraints) - try: - return iter.next() - except StopIteration: - return None - - def getSolutions(self, domains, constraints, vconstraints): - return list(self.getSolutionIter(domains, constraints, vconstraints)) - - -class RecursiveBacktrackingSolver(Solver): - """ - Recursive problem solver with backtracking capabilities - - Examples: - - >>> result = [[('a', 1), ('b', 2)], - ... [('a', 1), ('b', 3)], - ... [('a', 2), ('b', 3)]] - - >>> problem = Problem(RecursiveBacktrackingSolver()) - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b > a, ["a", "b"]) - - >>> solution = problem.getSolution() - >>> sorted(solution.items()) in result - True - - >>> for solution in problem.getSolutions(): - ... sorted(solution.items()) in result - True - True - True - - >>> problem.getSolutionIter() - Traceback (most recent call last): - ... - NotImplementedError: RecursiveBacktrackingSolver doesn't provide iteration - """#""" - - def __init__(self, forwardcheck=True): - """ - @param forwardcheck: If false forward checking will not be requested - to constraints while looking for solutions - (default is true) - @type forwardcheck: bool - """ - self._forwardcheck = forwardcheck - - def recursiveBacktracking(self, solutions, domains, vconstraints, - assignments, single): - - # Mix the Degree and Minimum Remaing Values (MRV) heuristics - lst = [(-len(vconstraints[variable]), - len(domains[variable]), variable) for variable in domains] - lst.sort() - for item in lst: - if item[-1] not in assignments: - # Found an unassigned variable. Let's go. - break - else: - # No unassigned variables. We've got a solution. - solutions.append(assignments.copy()) - return solutions - - variable = item[-1] - assignments[variable] = None - - forwardcheck = self._forwardcheck - if forwardcheck: - pushdomains = [domains[x] for x in domains if x not in assignments] - else: - pushdomains = None - - for value in domains[variable]: - assignments[variable] = value - if pushdomains: - for domain in pushdomains: - domain.pushState() - for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments, - pushdomains): - # Value is not good. - break - else: - # Value is good. Recurse and get next variable. - self.recursiveBacktracking(solutions, domains, vconstraints, - assignments, single) - if solutions and single: - return solutions - if pushdomains: - for domain in pushdomains: - domain.popState() - del assignments[variable] - return solutions - - def getSolution(self, domains, constraints, vconstraints): - solutions = self.recursiveBacktracking([], domains, vconstraints, - {}, True) - return solutions and solutions[0] or None - - def getSolutions(self, domains, constraints, vconstraints): - return self.recursiveBacktracking([], domains, vconstraints, - {}, False) - - -class MinConflictsSolver(Solver): - """ - Problem solver based on the minimum conflicts theory - - Examples: - - >>> result = [[('a', 1), ('b', 2)], - ... [('a', 1), ('b', 3)], - ... [('a', 2), ('b', 3)]] - - >>> problem = Problem(MinConflictsSolver()) - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint(lambda a, b: b > a, ["a", "b"]) - - >>> solution = problem.getSolution() - >>> sorted(solution.items()) in result - True - - >>> problem.getSolutions() - Traceback (most recent call last): - ... - NotImplementedError: MinConflictsSolver provides only a single solution - - >>> problem.getSolutionIter() - Traceback (most recent call last): - ... - NotImplementedError: MinConflictsSolver doesn't provide iteration - """#""" - - def __init__(self, steps=1000): - """ - @param steps: Maximum number of steps to perform before giving up - when looking for a solution (default is 1000) - @type steps: int - """ - self._steps = steps - - def getSolution(self, domains, constraints, vconstraints): - assignments = {} - # Initial assignment - for variable in domains: - assignments[variable] = random.choice(domains[variable]) - for _ in xrange(self._steps): - conflicted = False - lst = domains.keys() - random.shuffle(lst) - for variable in lst: - # Check if variable is not in conflict - for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments): - break - else: - continue - # Variable has conflicts. Find values with less conflicts. - mincount = len(vconstraints[variable]) - minvalues = [] - for value in domains[variable]: - assignments[variable] = value - count = 0 - for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments): - count += 1 - if count == mincount: - minvalues.append(value) - elif count < mincount: - mincount = count - del minvalues[:] - minvalues.append(value) - # Pick a random one from these values. - assignments[variable] = random.choice(minvalues) - conflicted = True - if not conflicted: - return assignments - return None - -# ---------------------------------------------------------------------- -# Variables -# ---------------------------------------------------------------------- - -class Variable(object): - """ - Helper class for variable definition - - Using this class is optional, since any hashable object, - including plain strings and integers, may be used as variables. - """ - - def __init__(self, name): - """ - @param name: Generic variable name for problem-specific purposes - @type name: string - """ - self.name = name - - def __repr__(self): - return self.name - -Unassigned = Variable("Unassigned") - -# ---------------------------------------------------------------------- -# Domains -# ---------------------------------------------------------------------- - -class Domain(list): - """ - Class used to control possible values for variables - - When list or tuples are used as domains, they are automatically - converted to an instance of that class. - """ - - def __init__(self, set): - """ - @param set: Set of values that the given variables may assume - @type set: set of objects comparable by equality - """ - list.__init__(self, set) - self._hidden = [] - self._states = [] - - def resetState(self): - """ - Reset to the original domain state, including all possible values - """ - self.extend(self._hidden) - del self._hidden[:] - del self._states[:] - - def pushState(self): - """ - Save current domain state - - Variables hidden after that call are restored when that state - is popped from the stack. - """ - self._states.append(len(self)) - - def popState(self): - """ - Restore domain state from the top of the stack - - Variables hidden since the last popped state are then available - again. - """ - diff = self._states.pop()-len(self) - if diff: - self.extend(self._hidden[-diff:]) - del self._hidden[-diff:] - - def hideValue(self, value): - """ - Hide the given value from the domain - - After that call the given value won't be seen as a possible value - on that domain anymore. The hidden value will be restored when the - previous saved state is popped. - - @param value: Object currently available in the domain - """ - list.remove(self, value) - self._hidden.append(value) - -# ---------------------------------------------------------------------- -# Constraints -# ---------------------------------------------------------------------- - -class Constraint(object): - """ - Abstract base class for constraints - """ - - def __call__(self, variables, domains, assignments, forwardcheck=False): - """ - Perform the constraint checking - - If the forwardcheck parameter is not false, besides telling if - the constraint is currently broken or not, the constraint - implementation may choose to hide values from the domains of - unassigned variables to prevent them from being used, and thus - prune the search space. - - @param variables: Variables affected by that constraint, in the - same order provided by the user - @type variables: sequence - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param assignments: Dictionary mapping assigned variables to their - current assumed value - @type assignments: dict - @param forwardcheck: Boolean value stating whether forward checking - should be performed or not - @return: Boolean value stating if this constraint is currently - broken or not - @rtype: bool - """#""" - return True - - def preProcess(self, variables, domains, constraints, vconstraints): - """ - Preprocess variable domains - - This method is called before starting to look for solutions, - and is used to prune domains with specific constraint logic - when possible. For instance, any constraints with a single - variable may be applied on all possible values and removed, - since they may act on individual values even without further - knowledge about other assignments. - - @param variables: Variables affected by that constraint, in the - same order provided by the user - @type variables: sequence - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param constraints: List of pairs of (constraint, variables) - @type constraints: list - @param vconstraints: Dictionary mapping variables to a list of - constraints affecting the given variables. - @type vconstraints: dict - """#""" - if len(variables) == 1: - variable = variables[0] - domain = domains[variable] - for value in domain[:]: - if not self(variables, domains, {variable: value}): - domain.remove(value) - constraints.remove((self, variables)) - vconstraints[variable].remove((self, variables)) - - def forwardCheck(self, variables, domains, assignments, - _unassigned=Unassigned): - """ - Helper method for generic forward checking - - Currently, this method acts only when there's a single - unassigned variable. - - @param variables: Variables affected by that constraint, in the - same order provided by the user - @type variables: sequence - @param domains: Dictionary mapping variables to their domains - @type domains: dict - @param assignments: Dictionary mapping assigned variables to their - current assumed value - @type assignments: dict - @return: Boolean value stating if this constraint is currently - broken or not - @rtype: bool - """#""" - unassignedvariable = _unassigned - for variable in variables: - if variable not in assignments: - if unassignedvariable is _unassigned: - unassignedvariable = variable - else: - break - else: - if unassignedvariable is not _unassigned: - # Remove from the unassigned variable domain's all - # values which break our variable's constraints. - domain = domains[unassignedvariable] - if domain: - for value in domain[:]: - assignments[unassignedvariable] = value - if not self(variables, domains, assignments): - domain.hideValue(value) - del assignments[unassignedvariable] - if not domain: - return False - return True - -class FunctionConstraint(Constraint): - """ - Constraint which wraps a function defining the constraint logic - - Examples: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> def func(a, b): - ... return b > a - >>> problem.addConstraint(func, ["a", "b"]) - >>> problem.getSolution() - {'a': 1, 'b': 2} - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> def func(a, b): - ... return b > a - >>> problem.addConstraint(FunctionConstraint(func), ["a", "b"]) - >>> problem.getSolution() - {'a': 1, 'b': 2} - """#""" - - def __init__(self, func, assigned=True): - """ - @param func: Function wrapped and queried for constraint logic - @type func: callable object - @param assigned: Whether the function may receive unassigned - variables or not - @type assigned: bool - """ - self._func = func - self._assigned = assigned - - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): - parms = [assignments.get(x, _unassigned) for x in variables] - missing = parms.count(_unassigned) - if missing: - return ((self._assigned or self._func(*parms)) and - (not forwardcheck or missing != 1 or - self.forwardCheck(variables, domains, assignments))) - return self._func(*parms) - -class AllDifferentConstraint(Constraint): - """ - Constraint enforcing that values of all given variables are different - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(AllDifferentConstraint()) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): - seen = {} - for variable in variables: - value = assignments.get(variable, _unassigned) - if value is not _unassigned: - if value in seen: - return False - seen[value] = True - if forwardcheck: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in seen: - if value in domain: - domain.hideValue(value) - if not domain: - return False - return True - -class AllEqualConstraint(Constraint): - """ - Constraint enforcing that values of all given variables are equal - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(AllEqualConstraint()) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)], [('a', 2), ('b', 2)]] - """#""" - - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): - singlevalue = _unassigned - for variable in variables: - value = assignments.get(variable, _unassigned) - if singlevalue is _unassigned: - singlevalue = value - elif value is not _unassigned and value != singlevalue: - return False - if forwardcheck and singlevalue is not _unassigned: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - if singlevalue not in domain: - return False - for value in domain[:]: - if value != singlevalue: - domain.hideValue(value) - return True - -class MaxSumConstraint(Constraint): - """ - Constraint enforcing that values of given variables sum up to - a given amount - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(MaxSumConstraint(3)) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)], [('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __init__(self, maxsum, multipliers=None): - """ - @param maxsum: Value to be considered as the maximum sum - @type maxsum: number - @param multipliers: If given, variable values will be multiplied by - the given factors before being summed to be checked - @type multipliers: sequence of numbers - """ - self._maxsum = maxsum - self._multipliers = multipliers - - def preProcess(self, variables, domains, constraints, vconstraints): - Constraint.preProcess(self, variables, domains, - constraints, vconstraints) - multipliers = self._multipliers - maxsum = self._maxsum - if multipliers: - for variable, multiplier in zip(variables, multipliers): - domain = domains[variable] - for value in domain[:]: - if value*multiplier > maxsum: - domain.remove(value) - else: - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value > maxsum: - domain.remove(value) - - def __call__(self, variables, domains, assignments, forwardcheck=False): - multipliers = self._multipliers - maxsum = self._maxsum - sum = 0 - if multipliers: - for variable, multiplier in zip(variables, multipliers): - if variable in assignments: - sum += assignments[variable]*multiplier - if type(sum) is float: - sum = round(sum, 10) - if sum > maxsum: - return False - if forwardcheck: - for variable, multiplier in zip(variables, multipliers): - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value*multiplier > maxsum: - domain.hideValue(value) - if not domain: - return False - else: - for variable in variables: - if variable in assignments: - sum += assignments[variable] - if type(sum) is float: - sum = round(sum, 10) - if sum > maxsum: - return False - if forwardcheck: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value > maxsum: - domain.hideValue(value) - if not domain: - return False - return True - -class ExactSumConstraint(Constraint): - """ - Constraint enforcing that values of given variables sum exactly - to a given amount - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(ExactSumConstraint(3)) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __init__(self, exactsum, multipliers=None): - """ - @param exactsum: Value to be considered as the exact sum - @type exactsum: number - @param multipliers: If given, variable values will be multiplied by - the given factors before being summed to be checked - @type multipliers: sequence of numbers - """ - self._exactsum = exactsum - self._multipliers = multipliers - - def preProcess(self, variables, domains, constraints, vconstraints): - Constraint.preProcess(self, variables, domains, - constraints, vconstraints) - multipliers = self._multipliers - exactsum = self._exactsum - if multipliers: - for variable, multiplier in zip(variables, multipliers): - domain = domains[variable] - for value in domain[:]: - if value*multiplier > exactsum: - domain.remove(value) - else: - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value > exactsum: - domain.remove(value) - - def __call__(self, variables, domains, assignments, forwardcheck=False): - multipliers = self._multipliers - exactsum = self._exactsum - sum = 0 - missing = False - if multipliers: - for variable, multiplier in zip(variables, multipliers): - if variable in assignments: - sum += assignments[variable]*multiplier - else: - missing = True - if type(sum) is float: - sum = round(sum, 10) - if sum > exactsum: - return False - if forwardcheck and missing: - for variable, multiplier in zip(variables, multipliers): - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value*multiplier > exactsum: - domain.hideValue(value) - if not domain: - return False - else: - for variable in variables: - if variable in assignments: - sum += assignments[variable] - else: - missing = True - if type(sum) is float: - sum = round(sum, 10) - if sum > exactsum: - return False - if forwardcheck and missing: - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if sum+value > exactsum: - domain.hideValue(value) - if not domain: - return False - if missing: - return sum <= exactsum - else: - return sum == exactsum - -class MinSumConstraint(Constraint): - """ - Constraint enforcing that values of given variables sum at least - to a given amount - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(MinSumConstraint(3)) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)], [('a', 2), ('b', 2)]] - """#""" - - def __init__(self, minsum, multipliers=None): - """ - @param minsum: Value to be considered as the minimum sum - @type minsum: number - @param multipliers: If given, variable values will be multiplied by - the given factors before being summed to be checked - @type multipliers: sequence of numbers - """ - self._minsum = minsum - self._multipliers = multipliers - - def __call__(self, variables, domains, assignments, forwardcheck=False): - for variable in variables: - if variable not in assignments: - return True - else: - multipliers = self._multipliers - minsum = self._minsum - sum = 0 - if multipliers: - for variable, multiplier in zip(variables, multipliers): - sum += assignments[variable]*multiplier - else: - for variable in variables: - sum += assignments[variable] - if type(sum) is float: - sum = round(sum, 10) - return sum >= minsum - -class InSetConstraint(Constraint): - """ - Constraint enforcing that values of given variables are present in - the given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(InSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)]] - """#""" - - def __init__(self, set): - """ - @param set: Set of allowed values - @type set: set - """ - self._set = set - - def __call__(self, variables, domains, assignments, forwardcheck=False): - # preProcess() will remove it. - raise RuntimeError, "Can't happen" - - def preProcess(self, variables, domains, constraints, vconstraints): - set = self._set - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value not in set: - domain.remove(value) - vconstraints[variable].remove((self, variables)) - constraints.remove((self, variables)) - -class NotInSetConstraint(Constraint): - """ - Constraint enforcing that values of given variables are not present in - the given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(NotInSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 2), ('b', 2)]] - """#""" - - def __init__(self, set): - """ - @param set: Set of disallowed values - @type set: set - """ - self._set = set - - def __call__(self, variables, domains, assignments, forwardcheck=False): - # preProcess() will remove it. - raise RuntimeError, "Can't happen" - - def preProcess(self, variables, domains, constraints, vconstraints): - set = self._set - for variable in variables: - domain = domains[variable] - for value in domain[:]: - if value in set: - domain.remove(value) - vconstraints[variable].remove((self, variables)) - constraints.remove((self, variables)) - -class SomeInSetConstraint(Constraint): - """ - Constraint enforcing that at least some of the values of given - variables must be present in a given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(SomeInSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 1)], [('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] - """#""" - - def __init__(self, set, n=1, exact=False): - """ - @param set: Set of values to be checked - @type set: set - @param n: Minimum number of assigned values that should be present - in set (default is 1) - @type n: int - @param exact: Whether the number of assigned values which are - present in set must be exactly C{n} - @type exact: bool - """ - self._set = set - self._n = n - self._exact = exact - - def __call__(self, variables, domains, assignments, forwardcheck=False): - set = self._set - missing = 0 - found = 0 - for variable in variables: - if variable in assignments: - found += assignments[variable] in set - else: - missing += 1 - if missing: - if self._exact: - if not (found <= self._n <= missing+found): - return False - else: - if self._n > missing+found: - return False - if forwardcheck and self._n-found == missing: - # All unassigned variables must be assigned to - # values in the set. - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if value not in set: - domain.hideValue(value) - if not domain: - return False - else: - if self._exact: - if found != self._n: - return False - else: - if found < self._n: - return False - return True - -class SomeNotInSetConstraint(Constraint): - """ - Constraint enforcing that at least some of the values of given - variables must not be present in a given set - - Example: - - >>> problem = Problem() - >>> problem.addVariables(["a", "b"], [1, 2]) - >>> problem.addConstraint(SomeNotInSetConstraint([1])) - >>> sorted(sorted(x.items()) for x in problem.getSolutions()) - [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)], [('a', 2), ('b', 2)]] - """#""" - - def __init__(self, set, n=1, exact=False): - """ - @param set: Set of values to be checked - @type set: set - @param n: Minimum number of assigned values that should not be present - in set (default is 1) - @type n: int - @param exact: Whether the number of assigned values which are - not present in set must be exactly C{n} - @type exact: bool - """ - self._set = set - self._n = n - self._exact = exact - - def __call__(self, variables, domains, assignments, forwardcheck=False): - set = self._set - missing = 0 - found = 0 - for variable in variables: - if variable in assignments: - found += assignments[variable] not in set - else: - missing += 1 - if missing: - if self._exact: - if not (found <= self._n <= missing+found): - return False - else: - if self._n > missing+found: - return False - if forwardcheck and self._n-found == missing: - # All unassigned variables must be assigned to - # values not in the set. - for variable in variables: - if variable not in assignments: - domain = domains[variable] - for value in domain[:]: - if value in set: - domain.hideValue(value) - if not domain: - return False - else: - if self._exact: - if found != self._n: - return False - else: - if found < self._n: - return False - return True - -if __name__ == "__main__": - import doctest - doctest.testmod() - diff --git a/csp/csp/python-constraint/trials/crosswords.py b/csp/csp/python-constraint/trials/crosswords.py deleted file mode 100755 index 5cb502f0..00000000 --- a/csp/csp/python-constraint/trials/crosswords.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/python -from constraint import * -import random -import sys - -MINLEN = 3 - -def main(puzzle, lines): - puzzle = puzzle.rstrip().splitlines() - while puzzle and not puzzle[0]: - del puzzle[0] - - # Extract horizontal words - horizontal = [] - word = [] - predefined = {} - for row in range(len(puzzle)): - for col in range(len(puzzle[row])): - char = puzzle[row][col] - if not char.isspace(): - word.append((row, col)) - if char != "#": - predefined[row, col] = char - elif word: - if len(word) > MINLEN: - horizontal.append(word[:]) - del word[:] - if word: - if len(word) > MINLEN: - horizontal.append(word[:]) - del word[:] - - # Extract vertical words - vertical = [] - validcol = True - col = 0 - while validcol: - validcol = False - for row in range(len(puzzle)): - if col >= len(puzzle[row]): - if word: - if len(word) > MINLEN: - vertical.append(word[:]) - del word[:] - else: - validcol = True - char = puzzle[row][col] - if not char.isspace(): - word.append((row, col)) - if char != "#": - predefined[row, col] = char - elif word: - if len(word) > MINLEN: - vertical.append(word[:]) - del word[:] - if word: - if len(word) > MINLEN: - vertical.append(word[:]) - del word[:] - col += 1 - - hnames = ["h%d" % i for i in range(len(horizontal))] - vnames = ["v%d" % i for i in range(len(vertical))] - - #problem = Problem(MinConflictsSolver()) - problem = Problem() - - for hi, hword in enumerate(horizontal): - for vi, vword in enumerate(vertical): - for hchar in hword: - if hchar in vword: - hci = hword.index(hchar) - vci = vword.index(hchar) - problem.addConstraint(lambda hw, vw, hci=hci, vci=vci: - hw[hci] == vw[vci], - ("h%d" % hi, "v%d" % vi)) - - for char, letter in predefined.items(): - for hi, hword in enumerate(horizontal): - if char in hword: - hci = hword.index(char) - problem.addConstraint(lambda hw, hci=hci, letter=letter: - hw[hci] == letter, ("h%d" % hi,)) - for vi, vword in enumerate(vertical): - if char in vword: - vci = vword.index(char) - problem.addConstraint(lambda vw, vci=vci, letter=letter: - vw[vci] == letter, ("v%d" % vi,)) - - wordsbylen = {} - for hword in horizontal: - wordsbylen[len(hword)] = [] - for vword in vertical: - wordsbylen[len(vword)] = [] - - for line in lines: - line = line.strip() - l = len(line) - if l in wordsbylen: - wordsbylen[l].append(line.upper()) - - for hi, hword in enumerate(horizontal): - words = wordsbylen[len(hword)] - random.shuffle(words) - problem.addVariable("h%d" % hi, words) - for vi, vword in enumerate(vertical): - words = wordsbylen[len(vword)] - random.shuffle(words) - problem.addVariable("v%d" % vi, words) - - problem.addConstraint(AllDifferentConstraint()) - - solution = problem.getSolution() - if not solution: - print "No solution found!" - - maxcol = 0 - maxrow = 0 - for hword in horizontal: - for row, col in hword: - if row > maxrow: - maxrow = row - if col > maxcol: - maxcol = col - for vword in vertical: - for row, col in vword: - if row > maxrow: - maxrow = row - if col > maxcol: - maxcol = col - - matrix = [] - for row in range(maxrow+1): - matrix.append([" "]*(maxcol+1)) - - for variable in solution: - if variable[0] == "v": - word = vertical[int(variable[1:])] - else: - word = horizontal[int(variable[1:])] - for (row, col), char in zip(word, solution[variable]): - matrix[row][col] = char - - for row in range(maxrow+1): - for col in range(maxcol+1): - sys.stdout.write(matrix[row][col]) - sys.stdout.write("\n") - -if __name__ == "__main__": - if len(sys.argv) != 3: - sys.exit("Usage: crosswords.py ") - main(open(sys.argv[1]).read(), open(sys.argv[2])) - diff --git a/csp/csp/python-constraint/trials/einstein.py b/csp/csp/python-constraint/trials/einstein.py deleted file mode 100755 index ede13f88..00000000 --- a/csp/csp/python-constraint/trials/einstein.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/python -# -# ALBERT EINSTEIN'S RIDDLE -# -# ARE YOU IN THE TOP 2% OF INTELLIGENT PEOPLE IN THE WORLD? -# SOLVE THE RIDDLE AND FIND OUT. -# -# There are no tricks, just pure logic, so good luck and don't give up. -# -# 1. In a street there are five houses, painted five different colours. -# 2. In each house lives a person of different nationality -# 3. These five homeowners each drink a different kind of beverage, smoke -# different brand of cigar and keep a different pet. -# -# THE QUESTION: WHO OWNS THE FISH? -# -# HINTS -# -# 1. The Brit lives in a red house. -# 2. The Swede keeps dogs as pets. -# 3. The Dane drinks tea. -# 4. The Green house is on the left of the White house. -# 5. The owner of the Green house drinks coffee. -# 6. The person who smokes Pall Mall rears birds. -# 7. The owner of the Yellow house smokes Dunhill. -# 8. The man living in the centre house drinks milk. -# 9. The Norwegian lives in the first house. -# 10. The man who smokes Blends lives next to the one who keeps cats. -# 11. The man who keeps horses lives next to the man who smokes Dunhill. -# 12. The man who smokes Blue Master drinks beer. -# 13. The German smokes Prince. -# 14. The Norwegian lives next to the blue house. -# 15. The man who smokes Blends has a neighbour who drinks water. -# -# ALBERT EINSTEIN WROTE THIS RIDDLE EARLY DURING THE 19th CENTURY. HE -# SAID THAT 98% OF THE WORLD POPULATION WOULD NOT BE ABLE TO SOLVE IT. - -from constraint import * - -# Check http://www.csc.fi/oppaat/f95/python/talot.py - -def main(): - problem = Problem() - for i in range(1,6): - problem.addVariable("color%d" % i, - ["red", "white", "green", "yellow", "blue"]) - problem.addVariable("nationality%d" % i, - ["brit", "swede", "dane", "norwegian", "german"]) - problem.addVariable("drink%d" % i, - ["tea", "coffee", "milk", "beer", "water"]) - problem.addVariable("smoke%d" % i, - ["pallmall", "dunhill", "blends", - "bluemaster", "prince"]) - problem.addVariable("pet%d" % i, - ["dogs", "birds", "cats", "horses", "fish"]) - - problem.addConstraint(AllDifferentConstraint(), - ["color%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["nationality%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["drink%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["smoke%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["pet%d" % i for i in range(1,6)]) - - for i in range(1,6): - - # Hint 1 - problem.addConstraint(lambda nationality, color: - nationality != "brit" or color == "red", - ("nationality%d" % i, "color%d" % i)) - - # Hint 2 - problem.addConstraint(lambda nationality, pet: - nationality != "swede" or pet == "dogs", - ("nationality%d" % i, "pet%d" % i)) - - # Hint 3 - problem.addConstraint(lambda nationality, drink: - nationality != "dane" or drink == "tea", - ("nationality%d" % i, "drink%d" % i)) - - # Hint 4 - if i < 5: - problem.addConstraint(lambda colora, colorb: - colora != "green" or colorb == "white", - ("color%d" % i, "color%d" % (i+1))) - else: - problem.addConstraint(lambda color: color != "green", - ("color%d" % i,)) - - # Hint 5 - problem.addConstraint(lambda color, drink: - color != "green" or drink == "coffee", - ("color%d" % i, "drink%d" % i)) - - # Hint 6 - problem.addConstraint(lambda smoke, pet: - smoke != "pallmall" or pet == "birds", - ("smoke%d" % i, "pet%d" % i)) - - # Hint 7 - problem.addConstraint(lambda color, smoke: - color != "yellow" or smoke == "dunhill", - ("color%d" % i, "smoke%d" % i)) - - # Hint 8 - if i == 3: - problem.addConstraint(lambda drink: drink == "milk", - ("drink%d" % i,)) - - # Hint 9 - if i == 1: - problem.addConstraint(lambda nationality: - nationality == "norwegian", - ("nationality%d" % i,)) - - # Hint 10 - if 1 < i < 5: - problem.addConstraint(lambda smoke, peta, petb: - smoke != "blends" or peta == "cats" or - petb == "cats", - ("smoke%d" % i, "pet%d" % (i-1), - "pet%d" % (i+1))) - else: - problem.addConstraint(lambda smoke, pet: - smoke != "blends" or pet == "cats", - ("smoke%d" % i, - "pet%d" % (i == 1 and 2 or 4))) - - # Hint 11 - if 1 < i < 5: - problem.addConstraint(lambda pet, smokea, smokeb: - pet != "horses" or smokea == "dunhill" or - smokeb == "dunhill", - ("pet%d" % i, "smoke%d" % (i-1), - "smoke%d" % (i+1))) - else: - problem.addConstraint(lambda pet, smoke: - pet != "horses" or smoke == "dunhill", - ("pet%d" % i, - "smoke%d" % (i == 1 and 2 or 4))) - - # Hint 12 - problem.addConstraint(lambda smoke, drink: - smoke != "bluemaster" or drink == "beer", - ("smoke%d" % i, "drink%d" % i)) - - # Hint 13 - problem.addConstraint(lambda nationality, smoke: - nationality != "german" or smoke == "prince", - ("nationality%d" % i, "smoke%d" % i)) - - # Hint 14 - if 1 < i < 5: - problem.addConstraint(lambda nationality, colora, colorb: - nationality != "norwegian" or - colora == "blue" or colorb == "blue", - ("nationality%d" % i, "color%d" % (i-1), - "color%d" % (i+1))) - else: - problem.addConstraint(lambda nationality, color: - nationality != "norwegian" or - color == "blue", - ("nationality%d" % i, - "color%d" % (i == 1 and 2 or 4))) - - # Hint 15 - if 1 < i < 5: - problem.addConstraint(lambda smoke, drinka, drinkb: - smoke != "blends" or - drinka == "water" or drinkb == "water", - ("smoke%d" % i, "drink%d" % (i-1), - "drink%d" % (i+1))) - else: - problem.addConstraint(lambda smoke, drink: - smoke != "blends" or drink == "water", - ("smoke%d" % i, - "drink%d" % (i == 1 and 2 or 4))) - - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - print - for solution in solutions: - showSolution(solution) - -def showSolution(solution): - for i in range(1,6): - print "House %d" % i - print "--------" - print "Nationality: %s" % solution["nationality%d" % i] - print "Color: %s" % solution["color%d" % i] - print "Drink: %s" % solution["drink%d" % i] - print "Smoke: %s" % solution["smoke%d" % i] - print "Pet: %s" % solution["pet%d" % i] - print - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/trials/einstein2.py b/csp/csp/python-constraint/trials/einstein2.py deleted file mode 100755 index d1f7b86d..00000000 --- a/csp/csp/python-constraint/trials/einstein2.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/python -# -# ALBERT EINSTEIN'S RIDDLE -# -# ARE YOU IN THE TOP 2% OF INTELLIGENT PEOPLE IN THE WORLD? -# SOLVE THE RIDDLE AND FIND OUT. -# -# There are no tricks, just pure logic, so good luck and don't give up. -# -# 1. In a street there are five houses, painted five different colours. -# 2. In each house lives a person of different nationality -# 3. These five homeowners each drink a different kind of beverage, smoke -# different brand of cigar and keep a different pet. -# -# THE QUESTION: WHO OWNS THE zebra? -# -# HINTS -# -# 1. The englishman lives in a red house. -# 2. The spaniard keeps dogs as pets. -# 5. The owner of the Green house drinks coffee. -# 3. The ukrainian drinks tea. -# 4. The Green house is on the left of the ivory house. -# 6. The person who smokes oldgold rears snails. -# 7. The owner of the Yellow house smokes kools. -# 8. The man living in the centre house drinks milk. -# 9. The Norwegian lives in the first house. -# 10. The man who smokes chesterfields lives next to the one who keeps foxes. -# 11. The man who keeps horses lives next to the man who smokes kools. -# 12. The man who smokes luckystrike drinks orangejuice. -# 13. The japanese smokes parliaments. -# 14. The Norwegian lives next to the blue house. -# 15. The man who smokes chesterfields has a neighbour who drinks water. -# -# ALBERT EINSTEIN WROTE THIS RIDDLE EARLY DURING THE 19th CENTURY. HE -# SAID THAT 98% OF THE WORLD POPULATION WOULD NOT BE ABLE TO SOLVE IT. - -from constraint import * - -# Check http://www.csc.fi/oppaat/f95/python/talot.py - -def main(): - problem = Problem() - for i in range(1,6): - problem.addVariable("color%d" % i, - ["red", "ivory", "green", "yellow", "blue"]) - problem.addVariable("nationality%d" % i, - ["englishman", "spaniard", "ukrainian", "norwegian", "japanese"]) - problem.addVariable("drink%d" % i, - ["tea", "coffee", "milk", "orangejuice", "water"]) - problem.addVariable("smoke%d" % i, - ["oldgold", "kools", "chesterfields", - "luckystrike", "parliaments"]) - problem.addVariable("pet%d" % i, - ["dogs", "snails", "foxes", "horses", "zebra"]) - - problem.addConstraint(AllDifferentConstraint(), - ["color%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["nationality%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["drink%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["smoke%d" % i for i in range(1,6)]) - problem.addConstraint(AllDifferentConstraint(), - ["pet%d" % i for i in range(1,6)]) - - for i in range(1,6): - - # Hint 1 - problem.addConstraint(lambda nationality, color: - nationality != "englishman" or color == "red", - ("nationality%d" % i, "color%d" % i)) - - # Hint 2 - problem.addConstraint(lambda nationality, pet: - nationality != "spaniard" or pet == "dogs", - ("nationality%d" % i, "pet%d" % i)) - - # Hint 3 - problem.addConstraint(lambda nationality, drink: - nationality != "ukrainian" or drink == "tea", - ("nationality%d" % i, "drink%d" % i)) - - # Hint 4 - if i < 5: - problem.addConstraint(lambda colora, colorb: - colora != "green" or colorb == "ivory", - ("color%d" % i, "color%d" % (i+1))) - else: - problem.addConstraint(lambda color: color != "green", - ("color%d" % i,)) - - # Hint 5 - problem.addConstraint(lambda color, drink: - color != "green" or drink == "coffee", - ("color%d" % i, "drink%d" % i)) - - # Hint 6 - problem.addConstraint(lambda smoke, pet: - smoke != "oldgold" or pet == "snails", - ("smoke%d" % i, "pet%d" % i)) - - # Hint 7 - problem.addConstraint(lambda color, smoke: - color != "yellow" or smoke == "kools", - ("color%d" % i, "smoke%d" % i)) - - # Hint 8 - if i == 3: - problem.addConstraint(lambda drink: drink == "milk", - ("drink%d" % i,)) - - # Hint 9 - if i == 1: - problem.addConstraint(lambda nationality: - nationality == "norwegian", - ("nationality%d" % i,)) - - # Hint 10 - if 1 < i < 5: - problem.addConstraint(lambda smoke, peta, petb: - smoke != "chesterfields" or peta == "foxes" or - petb == "foxes", - ("smoke%d" % i, "pet%d" % (i-1), - "pet%d" % (i+1))) - else: - problem.addConstraint(lambda smoke, pet: - smoke != "chesterfields" or pet == "foxes", - ("smoke%d" % i, - "pet%d" % (i == 1 and 2 or 4))) - - # Hint 11 - if 1 < i < 5: - problem.addConstraint(lambda pet, smokea, smokeb: - pet != "horses" or smokea == "kools" or - smokeb == "kools", - ("pet%d" % i, "smoke%d" % (i-1), - "smoke%d" % (i+1))) - else: - problem.addConstraint(lambda pet, smoke: - pet != "horses" or smoke == "kools", - ("pet%d" % i, - "smoke%d" % (i == 1 and 2 or 4))) - - # Hint 12 - problem.addConstraint(lambda smoke, drink: - smoke != "luckystrike" or drink == "orangejuice", - ("smoke%d" % i, "drink%d" % i)) - - # Hint 13 - problem.addConstraint(lambda nationality, smoke: - nationality != "japanese" or smoke == "parliaments", - ("nationality%d" % i, "smoke%d" % i)) - - # Hint 14 - if 1 < i < 5: - problem.addConstraint(lambda nationality, colora, colorb: - nationality != "norwegian" or - colora == "blue" or colorb == "blue", - ("nationality%d" % i, "color%d" % (i-1), - "color%d" % (i+1))) - else: - problem.addConstraint(lambda nationality, color: - nationality != "norwegian" or - color == "blue", - ("nationality%d" % i, - "color%d" % (i == 1 and 2 or 4))) - - - - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - print - for solution in solutions: - showSolution(solution) - -def showSolution(solution): - for i in range(1,6): - print "House %d" % i - print "--------" - print "Nationality: %s" % solution["nationality%d" % i] - print "Color: %s" % solution["color%d" % i] - print "Drink: %s" % solution["drink%d" % i] - print "Smoke: %s" % solution["smoke%d" % i] - print "Pet: %s" % solution["pet%d" % i] - print - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/trials/large.mask b/csp/csp/python-constraint/trials/large.mask deleted file mode 100644 index ba5364c8..00000000 --- a/csp/csp/python-constraint/trials/large.mask +++ /dev/null @@ -1,27 +0,0 @@ - -# ######## # -# # # # # -######## # # -# # # # # -# # ######## -# # # # # # -######## # # -# # # # # # - # # # -######## # # - # # # # # - # ######## - # # # # # - # # ######## - # # # # # # - # # ######## - # # # # -######## # # - # # # # # # - # # # # # # - ######## # # - # # # # - # ######## - # # # # -######## # # - diff --git a/csp/csp/python-constraint/trials/medium.mask b/csp/csp/python-constraint/trials/medium.mask deleted file mode 100644 index 3332a097..00000000 --- a/csp/csp/python-constraint/trials/medium.mask +++ /dev/null @@ -1,19 +0,0 @@ - - # -######### -# # # -# # ###### -# # # -# # # # -# # # # -######## # -# # # - # # # - ######### - # # # - ######### - # # # - # # -####### - # - diff --git a/csp/csp/python-constraint/trials/python.mask b/csp/csp/python-constraint/trials/python.mask deleted file mode 100644 index fe5a5767..00000000 --- a/csp/csp/python-constraint/trials/python.mask +++ /dev/null @@ -1,8 +0,0 @@ - P - Y -####T#### - # H # - # O # -####N # - # # -######### diff --git a/csp/csp/python-constraint/trials/queens.py b/csp/csp/python-constraint/trials/queens.py deleted file mode 100755 index deac7131..00000000 --- a/csp/csp/python-constraint/trials/queens.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/python -# -# http://mathworld.wolfram.com/QueensProblem.html -# -from constraint import * -import sys - -def main(show=False): - problem = Problem() - size = 8 - cols = range(size) - rows = range(size) - problem.addVariables(cols, rows) - for col1 in cols: - for col2 in cols: - if col1 < col2: - problem.addConstraint(lambda row1, row2, col1=col1, col2=col2: - abs(row1-row2) != abs(col1-col2) and - row1 != row2, (col1, col2)) - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - if show: - for solution in solutions: - showSolution(solution, size) - -def showSolution(solution, size): - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - for i in range(size): - sys.stdout.write(" |") - for j in range(size): - if solution[j] == i: - sys.stdout.write(" %d |" % j) - else: - sys.stdout.write(" |") - sys.stdout.write("\n") - if i != size-1: - sys.stdout.write(" |%s|\n" % ("-"*((size*4)-1))) - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - -if __name__ == "__main__": - show = False - if len(sys.argv) == 2 and sys.argv[1] == "-s": - show = True - elif len(sys.argv) != 1: - sys.exit("Usage: queens.py [-s]") - main(show) - diff --git a/csp/csp/python-constraint/trials/rooks.py b/csp/csp/python-constraint/trials/rooks.py deleted file mode 100755 index 14f88b1e..00000000 --- a/csp/csp/python-constraint/trials/rooks.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/python -# -# http://mathworld.wolfram.com/RooksProblem.html -# -from constraint import * -import sys - -def factorial(x): return x == 1 or factorial(x-1)*x - -def main(show=False): - problem = Problem() - size = 8 - cols = range(size) - rows = range(size) - problem.addVariables(cols, rows) - for col1 in cols: - for col2 in cols: - if col1 < col2: - problem.addConstraint(lambda row1, row2: row1 != row2, - (col1, col2)) - solutions = problem.getSolutions() - print "Found %d solution(s)!" % len(solutions) - assert len(solutions) == factorial(size) - if show: - for solution in solutions: - showSolution(solution, size) - -def showSolution(solution, size): - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - for i in range(size): - sys.stdout.write(" |") - for j in range(size): - if solution[j] == i: - sys.stdout.write(" %d |" % j) - else: - sys.stdout.write(" |") - sys.stdout.write("\n") - if i != size-1: - sys.stdout.write(" |%s|\n" % ("-"*((size*4)-1))) - sys.stdout.write(" %s \n" % ("-"*((size*4)-1))) - -if __name__ == "__main__": - show = False - if len(sys.argv) == 2 and sys.argv[1] == "-s": - show = True - elif len(sys.argv) != 1: - sys.exit("Usage: rooks.py [-s]") - main(show) - diff --git a/csp/csp/python-constraint/trials/seisseisdoze.py b/csp/csp/python-constraint/trials/seisseisdoze.py deleted file mode 100755 index b17956db..00000000 --- a/csp/csp/python-constraint/trials/seisseisdoze.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python -# -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# SEIS -# + SEIS -# ------ -# DOZE -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("seidoz", range(10)) - problem.addConstraint(lambda s, e: (2*s)%10 == e, "se") - problem.addConstraint(lambda i, s, z, e: ((10*2*i)+(2*s))%100 == z*10+e, - "isze") - problem.addConstraint(lambda s, e, i, d, o, z: - 2*(s*1000+e*100+i*10+s) == d*1000+o*100+z*10+e, - "seidoz") - problem.addConstraint(lambda s: s != 0, "s") - problem.addConstraint(lambda d: d != 0, "d") - problem.addConstraint(AllDifferentConstraint()) - print "SEIS+SEIS=DOZE" - for s in problem.getSolutions(): - print ("%(s)d%(e)d%(i)d%(s)s+%(s)d%(e)d%(i)d%(s)d=" - "%(d)d%(o)d%(z)d%(e)d") % s - -if __name__ == "__main__": - main() - diff --git a/csp/csp/python-constraint/trials/sendmoremoney.py b/csp/csp/python-constraint/trials/sendmoremoney.py deleted file mode 100755 index 894b0cd5..00000000 --- a/csp/csp/python-constraint/trials/sendmoremoney.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python -# -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# SEND -# + MORE -# ------ -# MONEY -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("sendmory", range(10)) - problem.addConstraint(lambda d, e, y: (d+e)%10 == y, "dey") - problem.addConstraint(lambda n, d, r, e, y: (n*10+d+r*10+e)%100 == e*10+y, - "ndrey") - problem.addConstraint(lambda e, n, d, o, r, y: - (e*100+n*10+d+o*100+r*10+e)%1000 == n*100+e*10+y, - "endory") - problem.addConstraint(lambda s, e, n, d, m, o, r, y: - 1000*s+100*e+10*n+d + 1000*m+100*o+10*r+e == - 10000*m+1000*o+100*n+10*e+y, "sendmory") - problem.addConstraint(NotInSetConstraint([0]), "sm") - problem.addConstraint(AllDifferentConstraint()) - print "SEND+MORE=MONEY" - for s in problem.getSolutions(): - print "%(s)d%(e)d%(n)d%(d)d+" \ - "%(m)d%(o)d%(r)d%(e)d=" \ - "%(m)d%(o)d%(n)d%(e)d%(y)d" % s - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/trials/small.mask b/csp/csp/python-constraint/trials/small.mask deleted file mode 100644 index 0e43ff78..00000000 --- a/csp/csp/python-constraint/trials/small.mask +++ /dev/null @@ -1,8 +0,0 @@ - # - # -######### - # # - # # # # -##### # # - # # # -######### diff --git a/csp/csp/python-constraint/trials/studentdesks.py b/csp/csp/python-constraint/trials/studentdesks.py deleted file mode 100755 index e8d47792..00000000 --- a/csp/csp/python-constraint/trials/studentdesks.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/python -# -# http://home.chello.no/~dudley/ -# -from constraint import * -import sys - -STUDENTDESKS = [[ 0, 1, 0, 0, 0, 0], - [ 0, 2, 3, 4, 5, 6], - [ 0, 7, 8, 9, 10, 0], - [ 0, 11, 12, 13, 14, 0], - [ 15, 16, 17, 18, 19, 0], - [ 0, 0, 0, 0, 20, 0]] - -def main(): - problem = Problem() - problem.addVariables(range(1,21), ["A", "B", "C", "D", "E"]) - problem.addConstraint(SomeInSetConstraint(["A"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["B"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["C"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["D"], 4, True)) - problem.addConstraint(SomeInSetConstraint(["E"], 4, True)) - for row in range(len(STUDENTDESKS)-1): - for col in range(len(STUDENTDESKS[row])-1): - lst = [STUDENTDESKS[row][col], STUDENTDESKS[row][col+1], - STUDENTDESKS[row+1][col], STUDENTDESKS[row+1][col+1]] - lst = [x for x in lst if x] - problem.addConstraint(AllDifferentConstraint(), lst) - showSolution(problem.getSolution()) - -def showSolution(solution): - for row in range(len(STUDENTDESKS)): - for col in range(len(STUDENTDESKS[row])): - id = STUDENTDESKS[row][col] - sys.stdout.write(" %s" % (id and solution[id] or " ")) - sys.stdout.write("\n") - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/trials/sudoku.py b/csp/csp/python-constraint/trials/sudoku.py deleted file mode 100644 index e79698ea..00000000 --- a/csp/csp/python-constraint/trials/sudoku.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Sudoku puzzle solver by by Luigi Poderico (www.poderico.it). -# -from constraint import * - -problem = Problem() - -# Define the variables: 9 rows of 9 variables rangin in 1...9 -for i in range(1, 10) : - problem.addVariables(range(i*10+1, i*10+10), range(1, 10)) - -# Each row has different values -for i in range(1, 10) : - problem.addConstraint(AllDifferentConstraint(), range(i*10+1, i*10+10)) - -# Each colum has different values -for i in range(1, 10) : - problem.addConstraint(AllDifferentConstraint(), range(10+i, 100+i, 10)) - -# Each 3x3 box has different values -problem.addConstraint(AllDifferentConstraint(), [11,12,13,21,22,23,31,32,33]) -problem.addConstraint(AllDifferentConstraint(), [41,42,43,51,52,53,61,62,63]) -problem.addConstraint(AllDifferentConstraint(), [71,72,73,81,82,83,91,92,93]) - -problem.addConstraint(AllDifferentConstraint(), [14,15,16,24,25,26,34,35,36]) -problem.addConstraint(AllDifferentConstraint(), [44,45,46,54,55,56,64,65,66]) -problem.addConstraint(AllDifferentConstraint(), [74,75,76,84,85,86,94,95,96]) - -problem.addConstraint(AllDifferentConstraint(), [17,18,19,27,28,29,37,38,39]) -problem.addConstraint(AllDifferentConstraint(), [47,48,49,57,58,59,67,68,69]) -problem.addConstraint(AllDifferentConstraint(), [77,78,79,87,88,89,97,98,99]) - -# Some value is given. -initValue = [[0, 9, 0, 7, 0, 0, 8, 6, 0], - [0, 3, 1, 0, 0, 5, 0, 2, 0], - [8, 0, 6, 0, 0, 0, 0, 0, 0], - [0, 0, 7, 0, 5, 0, 0, 0, 6], - [0, 0, 0, 3, 0, 7, 0, 0, 0], - [5, 0, 0, 0, 1, 0, 7, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0, 9], - [0, 2, 0, 6, 0, 0, 0, 5, 0], - [0, 5, 4, 0, 0, 8, 0, 7, 0]] - -for i in range(1, 10) : - for j in range(1, 10): - if initValue[i-1][j-1] !=0 : - problem.addConstraint(lambda var, val=initValue[i-1][j-1]: - var==val, (i*10+j,)) - -# Get the solutions. -solutions = problem.getSolutions() - -# Print the solutions -for solution in solutions: - for i in range(1, 10): - for j in range(1, 10): - index = i*10+j - print solution[index], - print - print - diff --git a/csp/csp/python-constraint/trials/twotwofour.py b/csp/csp/python-constraint/trials/twotwofour.py deleted file mode 100755 index b9e70d6a..00000000 --- a/csp/csp/python-constraint/trials/twotwofour.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python -# -# Assign equal values to equal letters, and different values to -# different letters, in a way that satisfies the following sum: -# -# TWO -# + TWO -# ----- -# FOUR -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("twofur", range(10)) - problem.addConstraint(lambda o, r: (2*o)%10 == r, "or") - problem.addConstraint(lambda w, o, u, r: ((10*2*w)+(2*o))%100 == u*10+r, - "wour") - problem.addConstraint(lambda t, w, o, f, u, r: - 2*(t*100+w*10+o) == f*1000+o*100+u*10+r, "twofur") - problem.addConstraint(NotInSetConstraint([0]), "ft") - problem.addConstraint(AllDifferentConstraint()) - print "TWO+TWO=FOUR" - for s in problem.getSolutions(): - print "%(t)d%(w)d%(o)d+%(t)d%(w)d%(o)d=%(f)d%(o)d%(u)d%(r)d" % s - -if __name__ == "__main__": - main() diff --git a/csp/csp/python-constraint/trials/xsum.py b/csp/csp/python-constraint/trials/xsum.py deleted file mode 100755 index 0f5f70b6..00000000 --- a/csp/csp/python-constraint/trials/xsum.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/python -# -# Reorganize the following numbers in a way that each line of -# 5 numbers sum to 27. -# -# 1 6 -# 2 7 -# 3 -# 8 4 -# 9 5 -# -from constraint import * - -def main(): - problem = Problem() - problem.addVariables("abcdxefgh", range(1,10)) - problem.addConstraint(lambda a, b, c, d, x: - a < b < c < d and a+b+c+d+x == 27, "abcdx") - problem.addConstraint(lambda e, f, g, h, x: - e < f < g < h and e+f+g+h+x == 27, "efghx") - problem.addConstraint(AllDifferentConstraint()) - solutions = problem.getSolutions() - print "Found %d solutions!" % len(solutions) - showSolutions(solutions) - -def showSolutions(solutions): - for solution in solutions: - print " %d %d" % (solution["a"], solution["e"]) - print " %d %d " % (solution["b"], solution["f"]) - print " %d " % (solution["x"],) - print " %d %d " % (solution["g"], solution["c"]) - print " %d %d" % (solution["h"], solution["d"]) - print - -if __name__ == "__main__": - main() -