;;; EGGS is an explanation-based generalizer which is capable of generalizing ;;; proofs returned by the DEDUCE deductive retriever (a PROLOG like theorem prover) ;;; and generating macro-rules from the general proofs. These macro-rules are then ;;; stored and preferentially used in future deductions to increase performance. ;;; The files CUP-DOMAIN and TOY-DOMAIN are sample domain files. ;;;; Copyright (c) 1988 by Raymond Joseph Mooney. This program may be freely ;;;; copied, used, or modified provided that this copyright notice is included ;;;; in each copy of this code and parts thereof. (defvar *trace-eggs* nil "Print out specific and general proofs for EGGS") (defvar *trace-generalizer* nil "Print out updated bindings at each step in generalization") (defvar *learn* t "Generalize proofs and learn operational macro-rules") (defvar *operational-predicates* nil "List of operational predicates") (defvar *save-learned-rules* t "Save learned rules for later use") (defun run-eggs (questions &optional (depth-limit 20)) ;;; Use the EGGS system to process each of the queries in the list of questions ;;; and report total time spent. (let ((deduce-time 0) (learn-time 0)(solve-count 0)) (dolist (question questions) (terpri) (multiple-value-bind (form d-time l-time) (eggs question depth-limit) (incf deduce-time d-time)(incf learn-time l-time)(if form (incf solve-count)))) (format t "~%~%Number solved: ~A (~A%)" solve-count (round (* 100 (/ solve-count (length questions))))) (format t "~%Total Deduce time: ~,2F sec; Learn time: ~,2F sec" deduce-time learn-time))) (defun eggs (form &optional (depth-limit 20)) ;;; First use the retriever to retrieve a fact which matches the given form ;;; If an answer is found, see if its proof structure can be generalized to ;;; produce a new rule. If so, generalize it, create a macro-rule from the ;;; generalized proof and add it to the front of the existing rules so that it is ;;; preferentially used in future deductions (let* ((start-time (get-internal-run-time)) (answer (gfirst (retrieve form depth-limit))) (deduce-time (/ (- (get-internal-run-time) start-time) internal-time-units-per-second)) retrieved-form (learn-time 0)) (format t "~%Deduction time: ~,2F sec" deduce-time) (cond (answer (setf retrieved-form (substitute-vars form (first answer))) (format t "~%Retrieved answer:~A" retrieved-form) (when *trace-eggs* (format t "~%~%Proof:~%~A~%Proof Structure:~%~A" (specific-proof answer)(second answer))) (when *learn* (setf start-time (get-internal-run-time)) (let ((proof (prune-operational (second answer)))) (when (generalize-p proof) (format t "~%~%Generalizing proof") (let* ((general-bindings (generalize-proof proof)) (general-rule (general-rule proof general-bindings))) (when *save-learned-rules* ; Add learned rule to front of existing rules (save-brule general-rule)) (setf learn-time (/ (- (get-internal-run-time) start-time) internal-time-units-per-second)) (when *trace-eggs* (format t "~%~%General proof:~%~A" (instantiate-proof proof general-bindings))) (format t "~%~%Learned rule: ~A" general-rule)))))) (t (format t "~%Not able to retrieve: ~A" form))) (values retrieved-form deduce-time learn-time))) (defun save-brule (general-rule) (push-brule general-rule)) (defun prune-operational (proof) ;;; Prune (i.e. remove from the proof) sub-proofs for predicates which ;;; are known to be operational in order to achieve a more general ;;; rule which is still operational. ;;; TO BE WRITTEN proof) (defun generalize-p (proof) ;;; A proof can be generalized if it has at least two rules (and (rule-proof-p proof) (some #'(lambda (ante-proof) (rule-proof-p (second ante-proof))) (rule-proof-ante-proofs proof)))) (defun generalize-proof (proof &optional (bindings (list t))) ;;; Compute the general binding list for this proof structure by simply updating an ;;; initially empty binding list to account for all unifications between the consequent ;;; of one rule and the antecedent of another. (if (not (rule-proof-p proof)) bindings (dolist (ante-proof (rule-proof-ante-proofs proof) bindings) (let ((ante (first ante-proof))(sub-proof (second ante-proof))) (when (rule-proof-p sub-proof) (setf bindings (unify ante (rule-proof-consequent sub-proof) (generalize-proof sub-proof bindings))) (when *trace-generalizer* (format t "~%~%~A=~A ~%Updated bindings: ~A" ante (rule-proof-consequent sub-proof) bindings))))))) (defun general-rule (proof &optional (general-bindings (generalize-proof proof))) ;;; Extract the macro-rule for this proof by applying the general ;;; bindings to the consequent and leaves of the proof structure. (when (rule-proof-p proof) `(<- ,(substitute-vars (rule-proof-consequent proof) general-bindings) ,@(mapcar #'(lambda (leaf) (substitute-vars leaf general-bindings)) (proof-leaves proof))))) (defun proof-leaves (proof) ;;; Return the leaves of the proof structure (mapcan #'(lambda (ante-proof) (if (rule-proof-p (second ante-proof)) (proof-leaves (second ante-proof)) (list (first ante-proof)))) (rule-proof-ante-proofs proof)))