Matthew Butterick 6 years ago
parent b7ed47677a
commit eb0c99b9ba

@ -113,6 +113,28 @@
#:unless (hash-has-key? assignment var))
var))
(define current-shuffle (make-parameter #t))
(define/contract (mrv assignment csp)
(assignment? $csp? . -> . any/c)
;; Minimum-remaining-values heuristic.
;; with random tiebreaker.
(define (num_legal_values var)
(if ($csp-curr_domains csp)
(length (hash-ref ($csp-curr_domains csp) var))
;; todo: is this the same as python `count`?
(for/sum ([val (in-list (hash-ref ($csp-domains csp) var))]
#:when (zero? (nconflicts csp var val assignment)))
1)))
(struct $mrv-rec (var num) #:transparent)
(define recs (sort
(for/list ([var (in-list ($csp-variables csp))]
#:unless (hash-has-key? assignment var))
($mrv-rec var (num_legal_values var)))
< #:key $mrv-rec-num))
(first ((if (current-shuffle) shuffle values) (map $mrv-rec-var (takef recs (λ (rec) (= ($mrv-rec-num (first recs))
($mrv-rec-num rec))))))))
;; Value ordering
(define/contract (unordered_domain_values var assignment csp)
@ -120,55 +142,71 @@
;; The default value order.
(choices csp var))
(define/contract (lcv var assignment csp)
(variable? assignment? $csp? . -> . (listof any/c))
;; Least-constraining-values heuristic.
(sort (choices csp var) < #:key (λ (val) (nconflicts csp var val assignment))))
;; Inference
(define/contract (no_inference csp var value assignment removals)
($csp? variable? any/c assignment? (listof removal?) . -> . boolean?)
#true)
(define/contract (forward_checking csp var value assignment removals)
($csp? variable? any/c assignment? (listof removal?) . -> . boolean?)
;; Prune neighbor values inconsistent with var=value.
(support_pruning csp) ;; necessary to set up curr_domains
(for/and ([B (in-list (hash-ref ($csp-neighbors csp) var))]
#:unless (hash-has-key? assignment B))
(for/fold ([removals removals])
([b (in-list (hash-ref ($csp-curr_domains csp) B))]
#:unless (($csp-constraints csp) var value B b))
(prune csp B b removals))
(not (empty? (hash-ref ($csp-curr_domains csp) B)))))
(define current-select-variable (make-parameter first_unassigned_variable))
(define current-order-values (make-parameter unordered_domain_values))
(define current-inference (make-parameter no_inference))
(define/contract (backtracking_search csp
[select_unassigned_variable first_unassigned_variable]
[order_domain_values unordered_domain_values]
[inference no_inference])
(($csp?) (procedure? procedure? procedure?) . ->* . (or/c #f assignment?))
(define (backtrack [assignment (make-hasheq)])
;; todo: convert to generator with `yield`
(let/ec return
(when (all-variables-assigned? csp assignment)
(return assignment))
(define var (select_unassigned_variable assignment csp))
(for ([val (in-list (order_domain_values var assignment csp))]
#:when (zero? (nconflicts csp var val assignment)))
(assign csp var val assignment)
(define removals (suppose csp var val))
(when (inference csp var val assignment removals)
(define result (backtrack assignment))
(when result
(return result))
(restore csp removals)))
(unassign csp var assignment)
(return #false)))
(define result (backtrack))
(unless (or (false? result) (goal_test csp result))
(error 'whut))
result)
;; todo: make multiple results work
[select_unassigned_variable (current-select-variable)]
[order_domain_values (current-order-values)]
[inference (current-inference)])
(($csp?) (procedure? procedure? procedure?) . ->* . generator?)
(generator ()
(let backtrack ([assignment (make-hasheq)])
(cond
[(all-variables-assigned? csp assignment)
(unless (goal_test csp assignment) (error 'whut))
(yield (hash-copy assignment))]
[else
(define var (select_unassigned_variable assignment csp))
(for ([val (in-list (order_domain_values var assignment csp))]
#:when (zero? (nconflicts csp var val assignment)))
(assign csp var val assignment)
(define removals (suppose csp var val))
(when (inference csp var val assignment removals)
(backtrack assignment))
(restore csp removals))
(unassign csp var assignment)]))))
(define/contract (solve* csp [solver backtracking_search] [finish-proc values]
#:count [solution-limit +inf.0])
(($csp?) (procedure? procedure? #:count integer?) . ->* . (or/c #f (non-empty-listof any/c)))
(match (for/list ([solution (in-value (solver csp))] ; needs generator here
[idx (in-range solution-limit)])
(finish-proc solution))
[(? pair? solutions) solutions]
[else #f]))
(begin0
(match (for/list ([solution (in-producer (solver csp) (void))]
[idx (in-range solution-limit)])
(finish-proc solution))
[(? pair? solutions) solutions]
[else #false])
(set-$csp-curr_domains! csp #f)))
(define/contract (solve csp [solver backtracking_search] [finish-proc values])
(($csp?) (procedure? procedure?) . ->* . any/c)
(match (solve* csp solver finish-proc #:count 1)
[(list solution) solution]
[else #f]))
[else #false]))
(require rackunit)
(define vs '(wa nsw t q nt v sa))
@ -217,11 +255,34 @@
(check-equal? (unordered_domain_values 'wa (hash) csp) '(red green))
(set-$csp-curr_domains! csp #f) ; reset current domains
(check-equal? (solve csp)
(make-hasheq '((nsw . green) (nt . green) (q . red) (sa . blue) (t . blue) (v . red) (wa . red))))
(check-equal? (length (solve* csp)) 18)
(set-$csp-curr_domains! csp #f)
(check-equal? (suppose csp 'nsw 'red) '((nsw . green) (nsw . blue)))
(check-equal? (solve csp)
(make-hasheq '((nsw . red) (nt . red) (q . green) (sa . blue) (t . blue) (v . green) (wa . green))))
(check-equal? (suppose csp 'nsw 'red) '((nsw . green) (nsw . blue)))
(check-equal? (length (solve* csp)) 6)
(parameterize ([current-select-variable mrv]
[current-shuffle #f])
(check-equal?
(solve csp)
(make-hasheq '((nsw . green) (nt . green) (q . red) (sa . blue) (t . blue) (v . red) (wa . red)))))
(parameterize ([current-order-values lcv])
(check-equal?
(solve csp)
(make-hasheq '((nsw . green) (nt . green) (q . red) (sa . blue) (t . blue) (v . red) (wa . red)))))
(parameterize ([current-inference forward_checking])
(forward_checking csp 'sa 'blue (make-hasheq) null)
(check-equal? ($csp-curr_domains csp)
(make-hasheq '((nsw . (red green)) (nt . (red green)) (q . (red green)) (sa . (red green blue)) (t . (red green blue)) (v . (red green)) (wa . (red green))))))
(parameterize ([current-inference forward_checking])
(support_pruning csp)
(solve csp))

Loading…
Cancel
Save