|
|
|
@ -12,6 +12,12 @@
|
|
|
|
|
|
|
|
|
|
(struct $csp ([vars #:mutable]
|
|
|
|
|
[constraints #:mutable]) #:transparent)
|
|
|
|
|
(define csp? $csp?)
|
|
|
|
|
(define vars $csp-vars)
|
|
|
|
|
(define constraints $csp-constraints)
|
|
|
|
|
(define-syntax-rule (in-constraints csp) (in-list ($csp-constraints csp)))
|
|
|
|
|
(define-syntax-rule (in-vars csp) (in-list ($csp-vars csp)))
|
|
|
|
|
|
|
|
|
|
(struct $constraint (names proc) #:transparent
|
|
|
|
|
#:property prop:procedure
|
|
|
|
|
(λ (constraint csp)
|
|
|
|
@ -21,24 +27,29 @@
|
|
|
|
|
(for/and ([args (in-cartesian (map (λ (cname) ($csp-vals csp cname)) ($constraint-names constraint)))])
|
|
|
|
|
(apply ($constraint-proc constraint) args))))
|
|
|
|
|
|
|
|
|
|
(define (make-constraint [names null] [proc values])
|
|
|
|
|
($constraint names proc))
|
|
|
|
|
|
|
|
|
|
(struct $var (name domain) #:transparent)
|
|
|
|
|
(define $var-name? symbol?)
|
|
|
|
|
(define name? symbol?)
|
|
|
|
|
(define $var-vals $var-domain)
|
|
|
|
|
(define var-name $var-name)
|
|
|
|
|
|
|
|
|
|
(struct $cvar $var (past) #:transparent)
|
|
|
|
|
(struct $avar $var () #:transparent)
|
|
|
|
|
(define assigned-var? $avar?)
|
|
|
|
|
|
|
|
|
|
(define (make-csp [vds null] [constraints null])
|
|
|
|
|
($csp vds constraints))
|
|
|
|
|
(define (make-csp [vars null] [constraints null])
|
|
|
|
|
($csp vars constraints))
|
|
|
|
|
|
|
|
|
|
(define/contract (add-vars! csp names-or-procedure [vals-or-procedure empty])
|
|
|
|
|
(($csp? (or/c (listof $var-name?) procedure?)) ((or/c (listof any/c) procedure?)) . ->* . void?)
|
|
|
|
|
((csp? (or/c (listof name?) procedure?)) ((or/c (listof any/c) procedure?)) . ->* . void?)
|
|
|
|
|
(for/fold ([vars ($csp-vars csp)]
|
|
|
|
|
#:result (set-$csp-vars! csp vars))
|
|
|
|
|
([name (in-list (if (procedure? names-or-procedure)
|
|
|
|
|
(names-or-procedure)
|
|
|
|
|
names-or-procedure))])
|
|
|
|
|
(when (memq name (map $var-name vars))
|
|
|
|
|
(when (memq name (map var-name vars))
|
|
|
|
|
(raise-argument-error 'add-vars! "var that doesn't already exist" name))
|
|
|
|
|
(append vars (list ($var name
|
|
|
|
|
(if (procedure? vals-or-procedure)
|
|
|
|
@ -46,25 +57,25 @@
|
|
|
|
|
vals-or-procedure))))))
|
|
|
|
|
|
|
|
|
|
(define/contract (add-var! csp name [vals-or-procedure empty])
|
|
|
|
|
(($csp? $var-name?) ((or/c (listof any/c) procedure?)) . ->* . void?)
|
|
|
|
|
((csp? name?) ((or/c (listof any/c) procedure?)) . ->* . void?)
|
|
|
|
|
(add-vars! csp (list name) vals-or-procedure))
|
|
|
|
|
|
|
|
|
|
(define/contract (add-constraints! csp proc namess [proc-name #false])
|
|
|
|
|
(($csp? procedure? (listof (listof $var-name?))) ((or/c #false $var-name?)) . ->* . void?)
|
|
|
|
|
(set-$csp-constraints! csp (append ($csp-constraints csp)
|
|
|
|
|
((csp? procedure? (listof (listof name?))) ((or/c #false name?)) . ->* . void?)
|
|
|
|
|
(set-$csp-constraints! csp (append (constraints csp)
|
|
|
|
|
(for/list ([names (in-list namess)])
|
|
|
|
|
(for ([name (in-list names)])
|
|
|
|
|
(check-name-in-csp! 'add-constraints! csp name))
|
|
|
|
|
($constraint names (if proc-name
|
|
|
|
|
(procedure-rename proc proc-name)
|
|
|
|
|
proc))))))
|
|
|
|
|
(make-constraint names (if proc-name
|
|
|
|
|
(procedure-rename proc proc-name)
|
|
|
|
|
proc))))))
|
|
|
|
|
|
|
|
|
|
(define/contract (add-pairwise-constraint! csp proc var-names [proc-name #false])
|
|
|
|
|
(($csp? procedure? (listof $var-name?)) ($var-name?) . ->* . void?)
|
|
|
|
|
((csp? procedure? (listof name?)) (name?) . ->* . void?)
|
|
|
|
|
(add-constraints! csp proc (combinations var-names 2) proc-name))
|
|
|
|
|
|
|
|
|
|
(define/contract (add-constraint! csp proc var-names [proc-name #false])
|
|
|
|
|
(($csp? procedure? (listof $var-name?)) ($var-name?) . ->* . void?)
|
|
|
|
|
((csp? procedure? (listof name?)) (name?) . ->* . void?)
|
|
|
|
|
(add-constraints! csp proc (list var-names) proc-name))
|
|
|
|
|
|
|
|
|
|
(define/contract (alldiff= x y)
|
|
|
|
@ -74,6 +85,7 @@
|
|
|
|
|
(struct inconsistency-signal (csp) #:transparent)
|
|
|
|
|
|
|
|
|
|
(struct $backtrack (names) #:transparent)
|
|
|
|
|
(define (backtrack! [names null]) (raise ($backtrack names)))
|
|
|
|
|
|
|
|
|
|
(define current-select-variable (make-parameter #f))
|
|
|
|
|
(define current-order-values (make-parameter #f))
|
|
|
|
@ -82,28 +94,30 @@
|
|
|
|
|
(define current-shuffle (make-parameter #t))
|
|
|
|
|
|
|
|
|
|
(define/contract (check-name-in-csp! caller csp name)
|
|
|
|
|
(symbol? $csp? $var-name? . -> . void?)
|
|
|
|
|
(define names (map $var-name ($csp-vars csp)))
|
|
|
|
|
(symbol? csp? name? . -> . void?)
|
|
|
|
|
(define names (map var-name (vars csp)))
|
|
|
|
|
(unless (memq name names)
|
|
|
|
|
(raise-argument-error caller (format "one of these existing csp var names: ~v" names) name)))
|
|
|
|
|
|
|
|
|
|
(define/contract ($csp-var csp name)
|
|
|
|
|
($csp? $var-name? . -> . $var?)
|
|
|
|
|
(check-name-in-csp! '$csp-var csp name)
|
|
|
|
|
(for/first ([var (in-list ($csp-vars csp))]
|
|
|
|
|
#:when (eq? name ($var-name var)))
|
|
|
|
|
(define/contract (csp-var csp name)
|
|
|
|
|
(csp? name? . -> . $var?)
|
|
|
|
|
(check-name-in-csp! 'csp-var csp name)
|
|
|
|
|
(for/first ([var (in-vars csp)]
|
|
|
|
|
#:when (eq? name (var-name var)))
|
|
|
|
|
var))
|
|
|
|
|
|
|
|
|
|
(define/contract ($csp-vals csp name)
|
|
|
|
|
($csp? $var-name? . -> . (listof any/c))
|
|
|
|
|
(check-name-in-csp! '$csp-vals csp name)
|
|
|
|
|
($var-domain ($csp-var csp name)))
|
|
|
|
|
(csp? name? . -> . (listof any/c))
|
|
|
|
|
(check-name-in-csp! 'csp-vals csp name)
|
|
|
|
|
($var-domain (csp-var csp name)))
|
|
|
|
|
|
|
|
|
|
(define order-domain-values values)
|
|
|
|
|
|
|
|
|
|
(define/contract (assigned-name? csp name)
|
|
|
|
|
($csp? $var-name? . -> . boolean?)
|
|
|
|
|
(and (memq name (map $var-name (filter $avar? ($csp-vars csp)))) #true))
|
|
|
|
|
(csp? name? . -> . any/c)
|
|
|
|
|
(for/first ([var (in-vars csp)]
|
|
|
|
|
#:when (assigned-var? var))
|
|
|
|
|
(eq? name (var-name var))))
|
|
|
|
|
|
|
|
|
|
(define (reduce-arity proc pattern)
|
|
|
|
|
(unless (match (procedure-arity proc)
|
|
|
|
@ -112,11 +126,10 @@
|
|
|
|
|
(raise-argument-error 'reduce-arity (format "list of length ~a, same as procedure arity" (procedure-arity proc)) pattern))
|
|
|
|
|
(define reduced-arity-name (string->symbol (format "reduced-arity-~a" (object-name proc))))
|
|
|
|
|
(define-values (boxed-id-names vals) (partition box? pattern))
|
|
|
|
|
(define id-names (map unbox boxed-id-names))
|
|
|
|
|
(define new-arity (length id-names))
|
|
|
|
|
(define new-arity (length boxed-id-names))
|
|
|
|
|
(procedure-rename
|
|
|
|
|
(λ xs
|
|
|
|
|
(unless (= (length xs) new-arity)
|
|
|
|
|
(unless (= (length xs) new-arity)
|
|
|
|
|
(apply raise-arity-error reduced-arity-name new-arity xs))
|
|
|
|
|
(apply proc (for/fold ([acc empty]
|
|
|
|
|
[xs xs]
|
|
|
|
@ -129,47 +142,44 @@
|
|
|
|
|
reduced-arity-name))
|
|
|
|
|
|
|
|
|
|
(define/contract (reduce-constraint-arity csp [minimum-arity 3])
|
|
|
|
|
(($csp?) ((or/c #false exact-nonnegative-integer?)) . ->* . $csp?)
|
|
|
|
|
((csp?) ((or/c #false exact-nonnegative-integer?)) . ->* . csp?)
|
|
|
|
|
(let ([assigned-name? (curry assigned-name? csp)])
|
|
|
|
|
(define (partially-assigned? constraint)
|
|
|
|
|
(ormap assigned-name? ($constraint-names constraint)))
|
|
|
|
|
($csp ($csp-vars csp)
|
|
|
|
|
(for/list ([constraint (in-list ($csp-constraints csp))])
|
|
|
|
|
(cond
|
|
|
|
|
[(and (if minimum-arity (<= minimum-arity (constraint-arity constraint)) #true)
|
|
|
|
|
(partially-assigned? constraint))
|
|
|
|
|
(match-define ($constraint cnames proc) constraint)
|
|
|
|
|
($constraint (filter-not assigned-name? cnames)
|
|
|
|
|
;; pattern is mix of values and boxed symbols (indicating variables to persist)
|
|
|
|
|
;; use boxes here as cheap way to distinguish id symbols from value symbols
|
|
|
|
|
(let ([reduce-arity-pattern (for/list ([cname (in-list cnames)])
|
|
|
|
|
(if (assigned-name? cname)
|
|
|
|
|
(first ($csp-vals csp cname))
|
|
|
|
|
(box cname)))])
|
|
|
|
|
(reduce-arity proc reduce-arity-pattern)))]
|
|
|
|
|
[else constraint])))))
|
|
|
|
|
(make-csp (vars csp)
|
|
|
|
|
(for/list ([constraint (in-constraints csp)])
|
|
|
|
|
(cond
|
|
|
|
|
[(and (if minimum-arity (<= minimum-arity (constraint-arity constraint)) #true)
|
|
|
|
|
(partially-assigned? constraint))
|
|
|
|
|
(match-define ($constraint cnames proc) constraint)
|
|
|
|
|
($constraint (filter-not assigned-name? cnames)
|
|
|
|
|
;; pattern is mix of values and boxed symbols (indicating variables to persist)
|
|
|
|
|
;; use boxes here as cheap way to distinguish id symbols from value symbols
|
|
|
|
|
(let ([reduce-arity-pattern (for/list ([cname (in-list cnames)])
|
|
|
|
|
(if (assigned-name? cname)
|
|
|
|
|
(first ($csp-vals csp cname))
|
|
|
|
|
(box cname)))])
|
|
|
|
|
(reduce-arity proc reduce-arity-pattern)))]
|
|
|
|
|
[else constraint])))))
|
|
|
|
|
|
|
|
|
|
(define/contract (assign-val csp name val)
|
|
|
|
|
($csp? $var-name? any/c . -> . $csp?)
|
|
|
|
|
(define assigned-csp ($csp
|
|
|
|
|
(for/list ([var ($csp-vars csp)])
|
|
|
|
|
(if (eq? name ($var-name var))
|
|
|
|
|
($avar name (list val))
|
|
|
|
|
var))
|
|
|
|
|
($csp-constraints csp)))
|
|
|
|
|
assigned-csp)
|
|
|
|
|
(csp? name? any/c . -> . csp?)
|
|
|
|
|
(make-csp
|
|
|
|
|
(for/list ([var (vars csp)])
|
|
|
|
|
(if (eq? name (var-name var))
|
|
|
|
|
($avar name (list val))
|
|
|
|
|
var))
|
|
|
|
|
(constraints csp)))
|
|
|
|
|
|
|
|
|
|
(define/contract (unassigned-vars csp)
|
|
|
|
|
($csp? . -> . (listof (and/c $var? (not/c $avar?))))
|
|
|
|
|
(for/list ([var (in-list ($csp-vars csp))]
|
|
|
|
|
#:unless ($avar? var))
|
|
|
|
|
var))
|
|
|
|
|
(csp? . -> . (listof (and/c $var? (not/c assigned-var?))))
|
|
|
|
|
(filter-not assigned-var? (vars csp)))
|
|
|
|
|
|
|
|
|
|
(define/contract (first-unassigned-variable csp)
|
|
|
|
|
($csp? . -> . (or/c #false (and/c $var? (not/c $avar?))))
|
|
|
|
|
(csp? . -> . (or/c #false (and/c $var? (not/c assigned-var?))))
|
|
|
|
|
(match (unassigned-vars csp)
|
|
|
|
|
[(? empty?) #false]
|
|
|
|
|
[xs (first xs)]))
|
|
|
|
|
[(cons x _) x]))
|
|
|
|
|
|
|
|
|
|
(define/contract (argmin-random-tie proc xs)
|
|
|
|
|
(procedure? (non-empty-listof any/c) . -> . any/c)
|
|
|
|
@ -180,21 +190,22 @@
|
|
|
|
|
(first xs)))
|
|
|
|
|
|
|
|
|
|
(define/contract (minimum-remaining-values csp)
|
|
|
|
|
($csp? . -> . (or/c #false (and/c $var? (not/c $avar?))))
|
|
|
|
|
(csp? . -> . (or/c #false (and/c $var? (not/c assigned-var?))))
|
|
|
|
|
(match (unassigned-vars csp)
|
|
|
|
|
[(? empty?) #false]
|
|
|
|
|
[xs (argmin-random-tie (λ (var) (length ($var-domain var))) xs)]))
|
|
|
|
|
|
|
|
|
|
(define mrv minimum-remaining-values)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define/contract (var-degree csp var)
|
|
|
|
|
($csp? $var? . -> . exact-nonnegative-integer?)
|
|
|
|
|
(for/sum ([constraint (in-list ($csp-constraints csp))]
|
|
|
|
|
#:when (memq ($var-name var) ($constraint-names constraint)))
|
|
|
|
|
(csp? $var? . -> . exact-nonnegative-integer?)
|
|
|
|
|
(for/sum ([constraint (in-constraints csp)]
|
|
|
|
|
#:when (memq (var-name var) ($constraint-names constraint)))
|
|
|
|
|
1))
|
|
|
|
|
|
|
|
|
|
(define/contract (blended-variable-selector csp)
|
|
|
|
|
($csp? . -> . (or/c #false (and/c $var? (not/c $avar?))))
|
|
|
|
|
(csp? . -> . (or/c #false (and/c $var? (not/c assigned-var?))))
|
|
|
|
|
(define uvars (unassigned-vars csp))
|
|
|
|
|
(cond
|
|
|
|
|
[(empty? uvars) #false]
|
|
|
|
@ -208,7 +219,7 @@
|
|
|
|
|
(length ($var-vals var)))
|
|
|
|
|
|
|
|
|
|
(define/contract (mrv-degree-hybrid csp)
|
|
|
|
|
($csp? . -> . (or/c #f $var?))
|
|
|
|
|
(csp? . -> . (or/c #f $var?))
|
|
|
|
|
(define uvars (unassigned-vars csp))
|
|
|
|
|
(cond
|
|
|
|
|
[(empty? uvars) #false]
|
|
|
|
@ -228,7 +239,7 @@
|
|
|
|
|
(define (no-inference csp name) csp)
|
|
|
|
|
|
|
|
|
|
(define/contract (relating-only constraints names)
|
|
|
|
|
((listof $constraint?) (listof $var-name?) . -> . (listof $constraint?))
|
|
|
|
|
((listof $constraint?) (listof name?) . -> . (listof $constraint?))
|
|
|
|
|
(for*/list ([constraint (in-list constraints)]
|
|
|
|
|
[cnames (in-value ($constraint-names constraint))]
|
|
|
|
|
#:when (and (= (length names) (length cnames))
|
|
|
|
@ -236,16 +247,22 @@
|
|
|
|
|
(memq name cnames))))
|
|
|
|
|
constraint))
|
|
|
|
|
|
|
|
|
|
(define (binary-constraint? constraint)
|
|
|
|
|
(= 2 (constraint-arity constraint)))
|
|
|
|
|
|
|
|
|
|
(define (constraint-relates? constraint name)
|
|
|
|
|
(and (memq name ($constraint-names constraint)) #true))
|
|
|
|
|
|
|
|
|
|
(define/contract (forward-check csp aname)
|
|
|
|
|
($csp? $var-name? . -> . $csp?)
|
|
|
|
|
(csp? name? . -> . csp?)
|
|
|
|
|
(define aval (first ($csp-vals csp aname)))
|
|
|
|
|
(define (check-var var)
|
|
|
|
|
(match var
|
|
|
|
|
;; don't check against assigned vars, or the reference var
|
|
|
|
|
;; (which is probably assigned but maybe not)
|
|
|
|
|
[(? (λ (x) (or ($avar? x) (eq? ($var-name x) aname)))) var]
|
|
|
|
|
[(? (λ (x) (or (assigned-var? x) (eq? (var-name x) aname)))) var]
|
|
|
|
|
[($var name vals)
|
|
|
|
|
(match (($csp-constraints csp) . relating-only . (list aname name))
|
|
|
|
|
(match ((constraints csp) . relating-only . (list aname name))
|
|
|
|
|
[(? empty?) var]
|
|
|
|
|
[constraints
|
|
|
|
|
(define new-vals
|
|
|
|
@ -259,7 +276,7 @@
|
|
|
|
|
($cvar name new-vals (cons aname (if ($cvar? var)
|
|
|
|
|
($cvar-past var)
|
|
|
|
|
null)))])]))
|
|
|
|
|
(define checked-vars (map check-var ($csp-vars csp)))
|
|
|
|
|
(define checked-vars (map check-var (vars csp)))
|
|
|
|
|
;; conflict-set will be empty if there are no empty domains
|
|
|
|
|
(define conflict-set (for*/list ([var (in-list checked-vars)]
|
|
|
|
|
#:when (empty? ($var-domain var))
|
|
|
|
@ -271,21 +288,21 @@
|
|
|
|
|
;; If we just bail out at the first conflict, we may backjump too far based on its history
|
|
|
|
|
;; (and thereby miss parts of the search tree)
|
|
|
|
|
(when (pair? conflict-set)
|
|
|
|
|
(raise ($backtrack conflict-set)))
|
|
|
|
|
(backtrack! conflict-set))
|
|
|
|
|
;; Discard constraints that have produced singleton domains
|
|
|
|
|
;; (they have no further use)
|
|
|
|
|
(define nonsingleton-constraints
|
|
|
|
|
(for/list ([constraint (in-list ($csp-constraints csp))]
|
|
|
|
|
(for/list ([constraint (in-constraints csp)]
|
|
|
|
|
#:unless (and
|
|
|
|
|
(= 2 (constraint-arity constraint)) ; binary constraint
|
|
|
|
|
(memq aname ($constraint-names constraint)) ; includes target name
|
|
|
|
|
(binary-constraint? constraint)
|
|
|
|
|
(constraint-relates? constraint aname)
|
|
|
|
|
(let ([other-name (first (remq aname ($constraint-names constraint)))]) ; and something else
|
|
|
|
|
(= (length ($csp-vals csp other-name)) 1)))) ; that has only one value
|
|
|
|
|
constraint))
|
|
|
|
|
($csp checked-vars nonsingleton-constraints))
|
|
|
|
|
(make-csp checked-vars nonsingleton-constraints))
|
|
|
|
|
|
|
|
|
|
(define/contract (constraint-checkable? c names)
|
|
|
|
|
($constraint? (listof $var-name?) . -> . boolean?)
|
|
|
|
|
($constraint? (listof name?) . -> . boolean?)
|
|
|
|
|
(and (for/and ([cname (in-list ($constraint-names c))])
|
|
|
|
|
(memq cname names))
|
|
|
|
|
#true))
|
|
|
|
@ -298,27 +315,27 @@
|
|
|
|
|
(= 1 (length ($var-domain var))))
|
|
|
|
|
|
|
|
|
|
(define/contract (check-constraints csp)
|
|
|
|
|
($csp? . -> . $csp?)
|
|
|
|
|
(csp? . -> . csp?)
|
|
|
|
|
;; this time, we're not limited to assigned variables
|
|
|
|
|
;; (that is, vars that have been deliberately assigned in the backtrack process thus far)
|
|
|
|
|
;; we also want to use "singleton" vars (that is, vars that have been reduced to a single domain value by forward checking)
|
|
|
|
|
(define singleton-varnames (for/list ([var (in-list ($csp-vars csp))]
|
|
|
|
|
(define singleton-varnames (for/list ([var (in-vars csp)]
|
|
|
|
|
#:when (singleton-var? var))
|
|
|
|
|
($var-name var)))
|
|
|
|
|
(var-name var)))
|
|
|
|
|
(define-values (checkable-constraints other-constraints)
|
|
|
|
|
(partition (λ (c) (constraint-checkable? c singleton-varnames)) ($csp-constraints csp)))
|
|
|
|
|
(partition (λ (c) (constraint-checkable? c singleton-varnames)) (constraints csp)))
|
|
|
|
|
(for ([constraint (in-list (sort checkable-constraints < #:key constraint-arity))]
|
|
|
|
|
#:unless (constraint csp))
|
|
|
|
|
(raise ($backtrack null)))
|
|
|
|
|
($csp ($csp-vars csp) other-constraints))
|
|
|
|
|
(backtrack!))
|
|
|
|
|
(make-csp (vars csp) other-constraints))
|
|
|
|
|
|
|
|
|
|
(define/contract (make-nodes-consistent csp)
|
|
|
|
|
($csp? . -> . $csp?)
|
|
|
|
|
(csp? . -> . csp?)
|
|
|
|
|
;; todo: why does this function slow down searches?
|
|
|
|
|
($csp
|
|
|
|
|
(for/list ([var (in-list ($csp-vars csp))])
|
|
|
|
|
(for/list ([var (in-vars csp)])
|
|
|
|
|
(match-define ($var name vals) var)
|
|
|
|
|
(define procs (for*/list ([constraint (in-list ($csp-constraints csp))]
|
|
|
|
|
(define procs (for*/list ([constraint (in-constraints csp)]
|
|
|
|
|
[cnames (in-value ($constraint-names constraint))]
|
|
|
|
|
#:when (and (= 1 (length cnames)) (eq? name (car cnames))))
|
|
|
|
|
($constraint-proc constraint)))
|
|
|
|
@ -326,7 +343,7 @@
|
|
|
|
|
(for*/fold ([vals vals])
|
|
|
|
|
([proc (in-list procs)])
|
|
|
|
|
(filter proc vals))))
|
|
|
|
|
($csp-constraints csp)))
|
|
|
|
|
(constraints csp)))
|
|
|
|
|
|
|
|
|
|
(define/contract (backtracking-solver
|
|
|
|
|
csp
|
|
|
|
@ -334,7 +351,7 @@
|
|
|
|
|
(or (current-select-variable) first-unassigned-variable)]
|
|
|
|
|
#:order-values [order-domain-values (or (current-order-values) first-domain-value)]
|
|
|
|
|
#:inference [inference (or (current-inference) no-inference)])
|
|
|
|
|
(($csp?) (#:select-variable procedure? #:order-values procedure? #:inference procedure?) . ->* . generator?)
|
|
|
|
|
((csp?) (#:select-variable procedure? #:order-values procedure? #:inference procedure?) . ->* . generator?)
|
|
|
|
|
(generator ()
|
|
|
|
|
(let loop ([csp csp])
|
|
|
|
|
(match (select-unassigned-variable csp)
|
|
|
|
@ -360,8 +377,8 @@
|
|
|
|
|
;; todo: min-conflicts solver
|
|
|
|
|
|
|
|
|
|
(define/contract ($csp-assocs csp)
|
|
|
|
|
($csp? . -> . (listof (cons/c $var-name? any/c)))
|
|
|
|
|
(for/list ([var (in-list ($csp-vars csp))])
|
|
|
|
|
(csp? . -> . (listof (cons/c name? any/c)))
|
|
|
|
|
(for/list ([var (in-vars csp)])
|
|
|
|
|
(match var
|
|
|
|
|
[($var name domain) (cons name (first domain))])))
|
|
|
|
|
|
|
|
|
@ -369,7 +386,7 @@
|
|
|
|
|
#:finish-proc [finish-proc $csp-assocs]
|
|
|
|
|
#:solver [solver (or (current-solver) backtracking-solver)]
|
|
|
|
|
#:count [max-solutions +inf.0])
|
|
|
|
|
(($csp?) (#:finish-proc procedure? #:solver procedure? #:count integer?) . ->* . (listof any/c))
|
|
|
|
|
((csp?) (#:finish-proc procedure? #:solver procedure? #:count integer?) . ->* . (listof any/c))
|
|
|
|
|
(for/list ([solution (in-producer (solver csp) (void))]
|
|
|
|
|
[idx (in-range max-solutions)])
|
|
|
|
|
(finish-proc solution)))
|
|
|
|
@ -377,7 +394,7 @@
|
|
|
|
|
(define/contract (solve csp
|
|
|
|
|
#:finish-proc [finish-proc $csp-assocs]
|
|
|
|
|
#:solver [solver (or (current-solver) backtracking-solver)])
|
|
|
|
|
(($csp?) (#:finish-proc procedure? #:solver procedure?) . ->* . (or/c #false any/c))
|
|
|
|
|
((csp?) (#:finish-proc procedure? #:solver procedure?) . ->* . (or/c #false any/c))
|
|
|
|
|
(match (solve* csp #:finish-proc finish-proc #:solver solver #:count 1)
|
|
|
|
|
[(list solution) solution]
|
|
|
|
|
[else #false]))
|
|
|
|
|