#lang scheme
(require "ontology.ss")
(require "inference-environments.ss")
(require "bindings.ss")
(require "patterns.ss")
(require "facts.ss")
(require "rulesets.ss")
(require "matches.ss")
(require "assertions.ss")
(require "counts.ss")
(require scheme/mpair)
(require (only-in srfi/1 delete! append! list-copy))
(define (mlist-copy mlst)
(if (null? mlst)
'()
(mcons (mcar mlst) (mlist-copy (cdr mlst)))))
(define-namespace-anchor anchor)
(define (assertion-level-2-index fact)
(let ((level-1-index (current-inference-assertion-index))
(level-1-key (fact-first fact)))
(hash-ref level-1-index
level-1-key
(lambda ()
(let ((level-2-index (make-hash)))
(hash-set! level-1-index
level-1-key
level-2-index)
level-2-index)))))
(define (assertion-index-find fact)
(hash-ref (assertion-level-2-index fact) fact #f))
(define (assertion-index-add assertion)
(let ((fact (assertion-fact assertion)))
(hash-set! (assertion-level-2-index fact) fact assertion)))
(define (assertion-index-remove assertion)
(let ((fact (assertion-fact assertion)))
(hash-remove! (assertion-level-2-index fact) fact)))
(define (data-index-find assertion)
(let ((fact (assertion-fact assertion)))
(hash-ref (current-inference-data-index) (fact-first fact) '())))
(define (data-index-find-name name)
(hash-ref (current-inference-data-index) name '()))
(define (goal-index-find assertion)
(let ((fact (assertion-fact assertion)))
(hash-ref (current-inference-goal-index) (fact-first fact) '())))
(define (pragma? fact)
(and (list? fact)
(keyword? (car fact))))
(define (assert fact (reason (current-inference-rule)))
(if (pragma? fact)
(assert-pragma fact)
(let ((assertion (assertion-index-find fact)))
(if assertion
(begin
(set-assertion-reason! assertion reason)
(when (current-inference-trace)
(printf ">>> ~a~n" assertion)))
(begin
(set! assertion (make-assertion fact reason))
(assertion-index-add assertion)
(when (current-inference-trace)
(printf ">>> ~a~n" assertion))
(for* ((name
(if (current-inference-ontology)
(in-list (class-ancestor-names
(ontology-find-class
(current-inference-ontology)
(fact-first fact))))
(list (fact-first fact))))
(match-node (in-list (data-index-find-name name))))
(match-node-assert match-node assertion))
))
assertion)))
(define (assert-pragma pragma)
(case (car pragma)
((#:class)
(unless (current-inference-ontology)
(current-inference-ontology (new-ontology)))
(ontology-assert-class (current-inference-ontology) pragma)
#f)))
(define (retract assertion)
(assertion-index-remove assertion)
(when (current-inference-trace)
(printf "<<< ~s~n" assertion))
(for-each
(lambda (match-node)
(match-node-retract match-node assertion))
(data-index-find assertion)))
(define (replace assertion fact (reason (current-inference-rule)))
(retract assertion)
(set-assertion-fact! assertion fact)
(set-assertion-reason! assertion reason)
(assertion-index-add assertion)
(when (current-inference-trace)
(printf ">>> ~s~n" assertion))
(for-each
(lambda (match-node)
(match-node-assert match-node assertion))
(data-index-find assertion))
assertion)
(define (check fact)
(let/cc return
(let ((assertion (make-assertion fact (current-inference-rule))))
(when (current-inference-trace)
(printf "??? ~s~n" assertion))
(for-each
(lambda (match-node)
(let ((match (match-node-check match-node assertion return)))
(when (not (null? match))
(return match))))
(hash-ref (current-inference-goal-index)
(fact-first fact) (lambda () '()))) '())))
(define (query pattern)
(let ((matches '()))
(hash-for-each
(assertion-level-2-index (list (pattern-first pattern)))
(lambda (fact assertion)
(let* ( (bindings (pattern-unify fact pattern '())))
(when bindings
(set! matches
(mcons (cons assertion bindings)
matches))))))
matches))
(define (assume fact)
(let ((saved (copy-inference-environment (current-inference-environment))))
(assert fact)
(let ((result (start-inference)))
(if result
(current-inference-exit (inference-environment-exit saved))
(current-inference-environment saved))
result)))
(define-struct node
(successors
matches)
#:inspector (make-inspector)
#:mutable)
(define-struct (match-node node)
(assertion-variable
pattern
match-constraint-variables
match-constraints
match-constraint-predicate
(n #:mutable))
#:inspector (make-inspector))
(define-struct (join-node node)
(left
right
join-constraint-variables
join-constraints
join-constraint-predicate
existential?
match-counts)
#:inspector (make-inspector))
(define-struct (rule-node node)
(rule
join
action)
#:inspector (make-inspector))
(define (get-match-node successors
matches
assertion-variable
pattern
match-constraint-variables
match-constraints
match-constraint-predicate
n)
(let/ec return
(for-each
(lambda (match-node)
(when (and (eq? assertion-variable
(match-node-assertion-variable match-node))
(equal? pattern
(match-node-pattern match-node))
(equal? match-constraint-variables
(match-node-match-constraint-variables match-node))
(equal? match-constraints
(match-node-match-constraints match-node)))
(return match-node)))
(hash-ref (current-inference-data-index)
(pattern-first pattern)
(lambda () '())))
(let ((match-node
(make-match-node
successors matches assertion-variable pattern match-constraint-variables match-constraints match-constraint-predicate n))) (hash-set! (current-inference-data-index)
(pattern-first pattern)
(cons match-node
(hash-ref (current-inference-data-index)
(pattern-first pattern)
(lambda () '()))))
match-node)))
(define (get-join-node successors
matches
left
right
join-constraint-variables
join-constraints
join-constraint-predicate
existential?
match-counts)
(let/ec return
(for-each
(lambda (join-node)
(when (and (join-node? join-node)
(eq? left
(join-node-left join-node))
(eq? right
(join-node-right join-node))
(equal? join-constraint-variables
(join-node-join-constraint-variables join-node))
(equal? join-constraints
(join-node-join-constraints join-node))
(eq? existential?
(join-node-existential? join-node)))
(return join-node)))
(node-successors left))
(make-join-node
successors
matches
left
right
join-constraint-variables
join-constraints
join-constraint-predicate
existential?
match-counts)))
(define (link-nodes predecessor successor)
(when (not (memq successor (node-successors predecessor)))
(set-node-successors!
predecessor
(cons successor (node-successors predecessor)))))
(define (add-match-to-node-matches match node)
(when (node-matches node)
(set-node-matches!
node (mcons match (node-matches node)))))
(define (remove-match-from-node-matches match node)
(let/cc exit
(let loop ((previous #f)
(matches (node-matches node)))
(when (not (null? matches))
(when (eq? match (mcar matches))
(if previous
(set-mcdr! previous (mcdr matches))
(set-node-matches! node (mcdr matches)))
(exit (void)))
(loop matches (mcdr matches))))))
(define (get-node-matches node bindings)
(let ((matches (node-matches node)))
(if matches
matches
(if (match-node? node)
(check (pattern-substitute
(match-node-pattern node) bindings))
#f))))
(define (activate ruleset)
(let ((initial-join-node
(make-join-node
'() (mlist '(())) #f #f '() '() #f #f (make-counts)))) (for-each
(lambda (rule)
(activate-rule rule initial-join-node))
(ruleset-rules ruleset)))
(fix-goal-matches))
(define (activate-rule rule initial-node)
(let ((match-node #f)
(join-node #f)
(rule-node #f)
(previous-node initial-node)
(previous-variable-list '()))
(when (not (null? (rule-goals rule)))
(let ((goal-pattern (car (rule-goals rule))))
(set! previous-node
(make-match-node
'() #f #f goal-pattern '() '() #f 0 ))
(hash-set!
(current-inference-goal-index)
(pattern-first goal-pattern)
(cons previous-node
(hash-ref
(current-inference-goal-index)
(pattern-first goal-pattern)
(lambda () '()))))
(set! previous-variable-list
(pattern-variables goal-pattern))))
(for-each
(lambda (clause)
(let ((existential? #f)
(assertion-variable #f)
(pattern #f)
(variable-list '()))
(cond ((and (pair? clause)
(variable? (car clause)))
(set! assertion-variable (car clause))
(set! pattern (caddr clause)))
((and (pair? clause)
(memq (car clause) '(no notany any notall all)))
(set! existential? (car clause))
(set! pattern (cadr clause)))
(else
(set! pattern clause)))
(set! variable-list
(merge-variable-lists
previous-variable-list
(if assertion-variable
(cons assertion-variable (pattern-variables pattern))
(pattern-variables pattern))))
(let ((match-constraints
(pattern-match-constraints
pattern (pattern-variables pattern))))
(set! match-node
(get-match-node
'() '() assertion-variable (pattern-base-pattern pattern) (if assertion-variable (cons assertion-variable (pattern-variables pattern))
(pattern-variables pattern))
match-constraints (if (null? match-constraints) #f
(eval
`(lambda ,(if assertion-variable
(cons assertion-variable
(pattern-variables pattern))
(pattern-variables pattern))
(and ,@match-constraints))
(namespace-anchor->namespace anchor)))
0))) (let ((join-constraints
(pattern-join-constraints
pattern (pattern-variables pattern))))
(set! join-node
(get-join-node
'() (if (null? (rule-goals rule))
(if (or (memq existential? '(no notany))
(eq? existential? 'all))
(node-matches previous-node)
'())
#f) previous-node match-node variable-list join-constraints (if (null? join-constraints) #f
(eval `(lambda ,variable-list
(and ,@join-constraints))
(namespace-anchor->namespace anchor)))
existential? (make-counts)))) (link-nodes match-node join-node)
(link-nodes previous-node join-node)
(set! previous-node join-node)
(when (not existential?)
(set! previous-variable-list variable-list))))
(rule-preconditions rule))
(set! rule-node
(make-rule-node
'() (if (null? (rule-goals rule))
(node-matches previous-node)
#f) rule previous-node (if (not (rule-actions rule))
#f
(eval `(lambda ,previous-variable-list
(begin ,@(rule-actions rule)))
(namespace-anchor->namespace anchor)))
))
(link-nodes previous-node rule-node)
(current-inference-rule-nodes
(append! (current-inference-rule-nodes)
(list rule-node))))
(void))
(define (fix-goal-matches)
(hash-for-each
(current-inference-data-index)
(lambda (key value)
(when (hash-ref (current-inference-goal-index) key
(lambda () #f))
(for-each
(lambda (match-node)
(set-node-matches! match-node #f))
value)
(hash-remove! (current-inference-data-index) key)))))
(define (merge-variable-lists list1 list2)
(cond ((null? list2)
list1)
((memq (car list2) list1)
(merge-variable-lists list1 (cdr list2)))
(else
(merge-variable-lists
(append list1 (list (car list2))) (cdr list2)))))
(define (match-node-assert match-node assertion)
(set-match-node-n! match-node (+ (match-node-n match-node) 1))
(let ((bindings (pattern-unify
(assertion-fact assertion)
(match-node-pattern match-node) (make-bindings))))
(when bindings
(when (match-node-assertion-variable match-node)
(set! bindings
(cons
(cons (match-node-assertion-variable match-node)
assertion)
bindings)))
(when (and (match-node-match-constraint-predicate match-node)
(not (apply (match-node-match-constraint-predicate match-node)
(bindings-values bindings))))
(set! bindings #f)))
(if bindings
(let ((match (cons (list assertion) bindings)))
(add-match-to-node-matches match match-node)
(for-each
(lambda (successor)
(propagate-match-from-match-node match successor))
(node-successors match-node)))
(for-each
(lambda (successor)
(propagate-nonmatch-from-match-node successor))
(node-successors match-node)))))
(define (match-node-retract match-node assertion)
(set-match-node-n! match-node (- (match-node-n match-node) 1))
(let/cc exit
(let loop ((previous #f)
(matches (node-matches match-node)))
(when (not (null? matches))
(let ((match (mcar matches)))
(when (eq? assertion (caar match))
(if previous
(set-mcdr! previous (mcdr matches))
(set-node-matches! match-node (mcdr matches)))
(for-each
(lambda (successor)
(unpropagate-match-from-match-node match successor))
(node-successors match-node))
(exit (void))))
(loop matches (mcdr matches))))
(for-each
(lambda (successor)
(unpropagate-nonmatch-from-match-node successor))
(node-successors match-node))))
(define (match-node-check match-node assertion continuation)
(let/ec exit
(let ((bindings (pattern-unify
(assertion-fact assertion)
(match-node-pattern match-node) '())))
(when bindings
(when (match-node-assertion-variable match-node)
(set! bindings
(cons
(cons (match-node-assertion-variable match-node)
assertion)
bindings)))
(when (and (match-node-match-constraint-predicate match-node)
(not (apply (match-node-match-constraint-predicate match-node)
(bindings-values bindings))))
(exit (void)))
(let ((match (cons (list assertion) bindings)))
(add-match-to-node-matches match match-node)
(for-each
(lambda (successor)
(propagate-match-from-join-node match successor continuation))
(node-successors match-node)))))
'()))
(define (propagate-match-from-match-node match join-node)
(when (node-matches join-node)
(mfor-each
(lambda (left-match)
(let ((joined-match (join left-match match join-node)))
(if (join-node-existential? join-node)
(let ((count (counts-table-value
(join-node-match-counts join-node) left-match)))
(when joined-match
(set! count (+ count 1))
(counts-table-increment!
(join-node-match-counts join-node) left-match))
(case (join-node-existential? join-node)
((no notany)
(when (and joined-match
(= count 1)) (unpropagate-match-to-successors left-match join-node)))
((any)
(when (and joined-match
(= count 1)) (propagate-match-to-successors left-match join-node #f)))
((notall)
(let ((n (match-node-n (join-node-right join-node))))
(when (and (not joined-match)
(= count (- n 1)))
(propagate-match-to-successors left-match join-node #f))))
((all)
(let ((n (match-node-n (join-node-right join-node))))
(when (and (not joined-match)
(= count (- n 1)))
(unpropagate-match-to-successors left-match join-node))))))
(when joined-match
(propagate-match-to-successors joined-match join-node #f)))))
(get-node-matches (join-node-left join-node) (car match)))))
(define (propagate-nonmatch-from-match-node join-node)
(when (node-matches join-node)
(mfor-each
(lambda (left-match)
(when (join-node-existential? join-node)
(let ((count (counts-table-value
(join-node-match-counts join-node) left-match)))
(case (join-node-existential? join-node)
((notall)
(let ((n (match-node-n (join-node-right join-node))))
(when (= count (- n 1))
(propagate-match-to-successors left-match join-node #f))))
((all)
(let ((n (match-node-n (join-node-right join-node))))
(when (= count (- n 1))
(unpropagate-match-to-successors left-match join-node))))))))
(get-node-matches (join-node-left join-node) '()))))
(define (propagate-match-from-join-node match join-node continuation)
(if (join-node-existential? join-node)
(let ((count 0))
(mfor-each
(lambda (right-match)
(let ((joined-match (join match right-match join-node)))
(when joined-match
(set! count (+ count 1)))))
(node-matches (join-node-right join-node)))
(set-counts-table-value!
(join-node-match-counts join-node) match count)
(case (join-node-existential? join-node)
((no notany)
(when (= count 0)
(propagate-match-to-successors match join-node continuation)))
((any)
(when (> count 1)
(propagate-match-to-successors match join-node continuation)))
((notall)
(let ((n (match-node-n (join-node-right join-node))))
(when (< count n)
(propagate-match-to-successors match join-node continuation))))
((all)
(let ((n (match-node-n (join-node-right join-node))))
(when (= count n)
(propagate-match-to-successors match join-node continuation))))))
(mfor-each
(lambda (right-match)
(let ((joined-match (join match right-match join-node)))
(when joined-match
(propagate-match-to-successors joined-match join-node continuation))))
(get-node-matches (join-node-right join-node) (cdr match)))))
(define (propagate-match-to-successors match join-node continuation)
(add-match-to-node-matches match join-node)
(for-each
(lambda (successor)
(if (join-node? successor)
(propagate-match-from-join-node match successor continuation)
(propagate-match-to-rule match successor continuation)))
(node-successors join-node)))
(define (propagate-match-to-rule match rule-node continuation)
(if (node-matches rule-node)
(let ((rule-instance
(make-rule-instance rule-node match 0)))
(agenda-add! rule-instance))
(begin
(when (current-inference-trace)
(printf "<== ~s: ~s~n"
(rule-node-rule rule-node)
(cdr match)))
(when (rule-node-action rule-node)
(current-inference-rule (rule-node-rule))
(apply (rule-node-action rule-node)
(bindings-values match))
(current-inference-rule #f)
(current-inference-rules-fired
(+ (current-inference-rules-fired) 1)))
(continuation (mlist (cons (list (caar match)) (cdr match)))))))
(define (unpropagate-match-from-match-node match join-node)
(if (join-node-existential? join-node)
(mfor-each
(lambda (left-match)
(let ((count (counts-table-value
(join-node-match-counts join-node) left-match))
(joined-match (join left-match match join-node)))
(when joined-match
(set! count (- count 1))
(set-counts-table-value!
(join-node-match-counts join-node) left-match count))
(case (join-node-existential? join-node)
((no notany)
(when (and joined-match
(= count 0)) (propagate-match-to-successors left-match join-node #f)))
((any)
(when (and join-node
(= count 0)) (unpropagate-match-to-successors left-match join-node)))
((notall)
(let ((n (match-node-n (join-node-right join-node))))
(when (and (not joined-match)
(= count n))
(unpropagate-match-to-successors left-match join-node))))
((all)
(let ((n (match-node-n (join-node-right join-node))))
(when (and (not joined-match)
(= count n))
(propagate-match-to-successors left-match join-node #f)))))))
(node-matches (join-node-left join-node)))
(let ((assertion (caar match)))
(mfor-each
(lambda (match)
(when (eq? assertion
(last (car match)))
(unpropagate-match-to-successors match join-node)))
(node-matches join-node)))))
(define (unpropagate-nonmatch-from-match-node join-node)
(when (join-node-existential? join-node)
(mfor-each
(lambda (left-match)
(let ((count (counts-table-value
(join-node-match-counts join-node) left-match)))
(case (join-node-existential? join-node)
((notall)
(let ((n (match-node-n (join-node-right join-node))))
(when (= count n)
(unpropagate-match-to-successors left-match join-node))))
((all)
(let ((n (match-node-n (join-node-right join-node))))
(when (= count n)
(propagate-match-to-successors left-match join-node #f)))))))
(node-matches (join-node-left join-node)))))
(define (unpropagate-match-from-join-node match join-node)
(hash-remove!
(counts-table (join-node-match-counts join-node)) match)
(mfor-each
(lambda (node-match)
(when (match-subset? match node-match)
(unpropagate-match-to-successors node-match join-node)))
(node-matches join-node)))
(define (unpropagate-match-to-successors match join-node)
(remove-match-from-node-matches match join-node)
(for-each
(lambda (successor)
(if (join-node? successor)
(unpropagate-match-from-join-node match successor)
(unpropagate-match-to-rule match successor)))
(node-successors join-node)))
(define (unpropagate-match-to-rule match rule-node)
(agenda-remove! rule-node match))
(define (join left-match right-match join-node)
(let ((left-assertions (car left-match))
(left-bindings (cdr left-match))
(right-assertions (car right-match))
(right-bindings (cdr right-match)))
(let/cc return
(for-each
(lambda (right-binding)
(when (assq (car right-binding) left-bindings)
(when (not (equal? (cdr right-binding)
(cdr (assq (car right-binding) left-bindings))))
(return #f))))
right-bindings)
(let ((bindings left-bindings))
(for-each
(lambda (right-binding)
(when (not (assq (car right-binding) left-bindings))
(set! bindings (append bindings (list right-binding)))))
right-bindings)
(when (and (join-node-join-constraint-predicate join-node)
(not (apply (join-node-join-constraint-predicate join-node)
(bindings-values bindings))))
(return #f))
(cons (append left-assertions right-assertions) bindings)))))
(define-struct rule-instance (rule-node match random) #:mutable)
(define (rule-instance-apply rule-instance)
(let* ((rule-node (rule-instance-rule-node rule-instance))
(rule (rule-node-rule rule-node))
(match (rule-instance-match rule-instance))
(arguments (bindings-values (cdr match))))
(when (current-inference-trace)
(printf "==> ~s: ~s~n"
rule (cdr match)))
(current-inference-rule rule)
(apply (rule-node-action rule-node) arguments)
(current-inference-rule #f)
(current-inference-rules-fired
(+ (current-inference-rules-fired) 1))))
(define (agenda-add! rule-instance)
(let* ((rule-node (rule-instance-rule-node rule-instance))
(rule (rule-node-rule rule-node))
(priority (rule-priority rule)))
(when (eq? (current-inference-strategy) 'random)
(set-rule-instance-random! rule-instance (random)))
(let ((agenda-tail (current-inference-agenda))
(previous #f))
(let loop ()
(when (not (null? agenda-tail))
(let* ((item (mcar agenda-tail))
(item-rule-node (rule-instance-rule-node item))
(item-rule (rule-node-rule item-rule-node))
(item-priority (rule-priority item-rule)))
(cond ((> item-priority priority)
(set! previous agenda-tail)
(set! agenda-tail (mcdr agenda-tail))
(loop))
((and (= item-priority priority)
(or (eq? (current-inference-strategy) 'breadth)
(and (eq? (current-inference-strategy) 'order)
(< (rule-order item-rule)
(rule-order rule)))
(and (eq? (current-inference-strategy) 'simplicity)
(< (rule-specificity item-rule)
(rule-specificity rule)))
(and (eq? (current-inference-strategy) 'complexity)
(> (rule-specificity item-rule)
(rule-specificity rule)))
(and (eq? (current-inference-strategy) 'random)
(< (rule-instance-random item)
(rule-instance-random rule-instance)))))
(set! previous agenda-tail)
(set! agenda-tail (mcdr agenda-tail))
(loop))
(else
(void))))))
(if previous
(set-mcdr! previous (mcons rule-instance agenda-tail))
(current-inference-agenda (mcons rule-instance agenda-tail))))))
(define (agenda-remove! rule-node match)
(let loop ((previous #f)
(agenda-tail (current-inference-agenda)))
(when (not (null? agenda-tail))
(let ((item (mcar agenda-tail)))
(if (and (eq? rule-node (rule-instance-rule-node item))
(eq? match (rule-instance-match item)))
(if previous
(set-mcdr! previous (mcdr agenda-tail))
(current-inference-agenda (mcdr agenda-tail)))
(loop agenda-tail (mcdr agenda-tail)))))))
(define (import pattern)
(when (not (current-inference-parent))
(error 'import
"Current inference environment is not a child environment"))
(let ((matches '()))
(with-inference-environment (current-inference-parent)
(set! matches (query pattern)))
(mfor-each
(lambda (match)
(assert (assertion-fact (car match))))
matches)))
(define (export pattern)
(when (not (current-inference-parent))
(error 'import
"Current inference environment is not a child environment"))
(let ((matches (query pattern)))
(with-inference-environment (current-inference-parent)
(mfor-each
(lambda (match)
(assert (assertion-fact (car match))))
matches))))
(define (copy-inference-environment source)
(let ((target (make-inference-environment))
(hash-table (make-hash)))
(for-each
(lambda (rule-node)
(copy-rule-node rule-node hash-table))
(inference-environment-rule-nodes source))
(let ((target-data-index (inference-environment-data-index target)))
(hash-for-each
(inference-environment-data-index source)
(lambda (key value)
(hash-set!
target-data-index
key (copy-match-node-list value hash-table)))))
(let ((target-goal-index (inference-environment-goal-index target)))
(hash-for-each
(inference-environment-goal-index source)
(lambda (key value)
(hash-set!
target-goal-index
key (copy-match-node-list value hash-table)))))
(set-inference-environment-exit!
target (inference-environment-exit source))
(set-inference-environment-next-assertion-id!
target (inference-environment-next-assertion-id source))
(let ((target-assertion-index
(inference-environment-assertion-index target)))
(hash-for-each
(inference-environment-assertion-index source)
(lambda (key value)
(let ((new-level-2-index (make-hasheq)))
(hash-for-each
value
(lambda (key value)
(hash-set!
new-level-2-index key value)))
(hash-set!
target-assertion-index key new-level-2-index))
)
))
(set-inference-environment-agenda!
target (mlist-copy (inference-environment-agenda source)))
(set-inference-environment-rule!
target (inference-environment-rule source))
(set-inference-environment-strategy!
target (inference-environment-strategy source))
(set-inference-environment-parent!
target (inference-environment-parent source))
target))
(define (copy-node node hash-table)
(cond ((match-node? node)
(copy-match-node node hash-table))
((join-node? node)
(copy-join-node node hash-table))
((rule-node? node)
(copy-rule-node node hash-table))
(else
(error 'copy-node
"~s is not a type of rule network node" node))))
(define (copy-match-node match-node hash-table)
(let ((copied-node (hash-ref hash-table match-node #f)))
(unless copied-node
(set! copied-node
(make-match-node
'()
(if (node-matches match-node)
(mlist-copy (node-matches match-node))
#f)
(match-node-assertion-variable match-node)
(match-node-pattern match-node)
(match-node-match-constraint-variables match-node)
(match-node-match-constraints match-node)
(match-node-match-constraint-predicate match-node)
(match-node-n match-node)))
(hash-set! hash-table match-node copied-node))
copied-node))
(define (copy-join-node join-node hash-table)
(let ((copied-node (hash-ref hash-table join-node #f)))
(unless copied-node
(set! copied-node
(make-join-node
'()
(if (node-matches join-node)
(list-copy (node-matches join-node))
#f)
(copy-node (join-node-left join-node) hash-table)
(copy-node (join-node-right join-node) hash-table)
(join-node-join-constraint-variables join-node)
(join-node-join-constraints join-node)
(join-node-join-constraint-predicate join-node)
(join-node-existential? join-node)
(make-counts)
))
(set-counts-table!
(join-node-match-counts copied-node)
(hash-copy (counts-table join-node)))
(link-nodes (join-node-left copied-node) copied-node)
(link-nodes (join-node-right copied-node) copied-node)
(hash-set! hash-table join-node copied-node))
copied-node))
(define (copy-rule-node rule-node hash-table)
(let ((copied-node (hash-ref hash-table rule-node #f)))
(unless copied-node
(set! copied-node
(make-rule-node
'()
(if (node-matches rule-node)
(list-copy (node-matches rule-node))
#f)
(rule-node-rule rule-node)
(copy-node (rule-node-join rule-node) hash-table)
(rule-node-action rule-node)))
(link-nodes (rule-node-join rule-node) copied-node)
(hash-set! hash-table rule-node copied-node))
copied-node))
(define (copy-match-node-list match-node-list hash-table)
match-node-list)
(define (start-inference #:assert-start (assert-start? #t))
(when assert-start?
(assert '(start)))
(let/cc exit
(current-inference-exit exit)
(let loop ()
(let ((agenda (current-inference-agenda)))
(if (not (null? agenda))
(let ((rule-instance (mcar agenda)))
(current-inference-agenda (mcdr agenda))
(rule-instance-apply rule-instance)
(loop))
#f)))))
(define stop-inference
(case-lambda
((return-value)
((current-inference-exit) return-value))
(()
((current-inference-exit)))))
(define (succeed)
(stop-inference #t))
(define (fail)
(stop-inference '#:fail))
(define (print-rule-network)
(for-each
(lambda (rule-node)
(printf "----------~n")
(printf "Rule: ~a~n~n" (rule-name (rule-node-rule rule-node)))
(print-join-node (rule-node-join rule-node)))
(current-inference-rule-nodes)))
(define (print-join-node join-node)
(when (join-node-left join-node)
(if (join-node? (join-node-left join-node))
(print-join-node (join-node-left join-node))
(print-match-node (join-node-left join-node))))
(when (join-node-right join-node)
(print-match-node (join-node-right join-node)))
(printf "join node: existential? = ~a~n" (join-node-existential? join-node))
(printf "join-node: match-counts = ~a~n" (join-node-match-counts join-node))
(printf "join node: matches = ~a~n~n" (node-matches join-node)))
(define (print-match-node match-node)
(printf "match-node: pattern = ~a~n" (match-node-pattern match-node))
(printf "match-node: matches = ~a~n~n" (node-matches match-node)))
(define the-node-dictionary #f)
(define (node-ref node)
(let ((entry (hash-ref the-node-dictionary node #f)))
(if entry
entry
(let ((ref
(cond ((match-node? node)
(symbol->string (gensym "match")))
((join-node? node)
(symbol->string (gensym "join")))
((rule-node? node)
(format "rule : ~a"
(rule-name (rule-node-rule node)))))))
(hash-set! the-node-dictionary node ref)
ref))))
(define (graph-rule-network)
(set! the-node-dictionary (make-hasheq))
(let ((port (open-output-file "rule-network.dot"
#:mode 'text
#:exists 'replace)))
(fprintf port "digraph \"rule-network\" {~n")
(fprintf port " rankdir=LR;~n")
(for ((rule-node (in-list (current-inference-rule-nodes))))
(let ((rule-node-ref (node-ref rule-node)))
(fprintf port " \"~a\";~n" rule-node-ref)
(graph-join-node port (rule-node-join rule-node) rule-node-ref)))
(fprintf port "}~n")
(close-output-port port)))
(define (graph-join-node port join-node successor-ref)
(let ((join-node-ref (node-ref join-node)))
(fprintf port " \"~a\" [label=\"join~a\\l~a\"];~n"
join-node-ref
(if (join-node-existential? join-node)
(format " : ~a" (join-node-existential? join-node))
"")
(for/fold ((constraints-string ""))
((constraint (in-list (join-node-join-constraints join-node))))
(string-append
constraints-string
(format "~s\\l" constraint))))
(fprintf port " \"~a\" -> \"~a\";~n"
join-node-ref successor-ref)
(when (join-node-right join-node)
(graph-match-node port (join-node-right join-node) join-node-ref))
(when (join-node-left join-node)
(if (join-node? (join-node-left join-node))
(graph-join-node port (join-node-left join-node) join-node-ref)
(graph-match-node port (join-node-left join-node) join-node-ref)))
))
(define (graph-match-node port match-node successor-ref)
(let ((match-node-ref (node-ref match-node)))
(fprintf port " \"~a\" [shape=box,label=\"match : ~a\\l~a\"];~n"
match-node-ref
(match-node-pattern match-node)
(for/fold ((constraints-string ""))
((constraint (in-list (match-node-match-constraints match-node))))
(string-append
constraints-string
(format "~s\\l" constraint))))
(fprintf port " \"~a\" -> \"~a\";~n"
match-node-ref successor-ref)))
(provide (all-defined-out))