;;; -*- Mode: Lisp; Syntax: Common-lisp; -*-
;;;;  Modified: forbus on Wed Feb 5 21:37:20 1997

;;;; Dependency-directed search facility
;;;; Last Edited 4/27/94, by KDF

;;; Copyright (c) 1993, Kenneth D. Forbus, Northwestern University,
;;; and Johan de Kleer, the Xerox Corporation.
;;; All rights reserved.

;;; See the file legal.txt for a paragraph stating scope of permission
;;; and disclaimer of warranty.  The above copyright notice and that
;;; paragraph must be included in any separate copy of this file.

(in-package :COMMON-LISP-USER)

(defvar *debug-dds* nil)

(defmacro debug-dds (str &rest args)
  `(if *debug-dds* (format t ,str ,@ args)))

(defun DD-Search (choice-sets end &aux answer marker choices)
  (when (null choice-sets)
    (debug-dds "~%    DDS: Found solution.")
    (eval end)
    (return-from DD-Search nil))
  (setq marker (list 'DDS (car choice-sets)))
  (setq choices (car choice-sets))
  (dolist (choice choices)
    (debug-dds "~%    DDS: Considering ~A..." choice)
    (cond ((false? choice) ;skip if known loser
	   (debug-dds "~%    DDS: ~A already known nogood." choice))
	  ((true? choice) ;continue if known
	   (debug-dds "~%    DDS: ~A true by implication." choice)
	   (DD-Search (cdr choice-sets) end)
	   (return nil))
          (t (debug-dds "~%    DDS: Assuming ~A." choice)
             (with-Contradiction-Handler (ltre-ltms *ltre*)
              #'(lambda (clauses ltms &aux asns)
                   (debug-dds "~%    DDS: Entering handler for ~A with ~A~A."
                    choice clauses
                    (mapcar #'(lambda (c) (violated-clause? c))
                       clauses))
                   (dolist (cl clauses)
                      (setq asns (assumptions-of-clause cl))
                      (debug-dds "~%    DDS: Assumptions are: ~A"
                        asns)
                      (dolist (asn asns)
                         (when (or (equal choice (view-node asn))
                                   (and (listp choice) (eq (car choice) :NOT)
                                        (equal (cadr choice) (view-node asn))))
                            (throw marker
                               (cons :LOSERS ;; Assign labels before any retraction
                                  ;; Failure to do so can result in incorrect nogoods.
                                  (mapcar #'signed-view-node
                                     (delete asn asns))))))))
              (setq answer (catch marker
                              (Assuming (list choice) *ltre*
                               (run-rules *ltre*)
                               (DD-Search (cdr choice-sets) end))))
              (when (and (listp answer)
                         (eq (car answer) :LOSERS))
                 (debug-dds "~%    DDS: ~A inconsistent with ~A."
                  choice (cdr answer))
                 (assert! `(:NOT (:AND ,choice
                                  ,@ (cdr answer)))
                  :DD-SEARCH-NOGOOD)))))))

;;;; A familiar example

(defun Test-DD-search (&optional (debugging? t))
  (in-LTRE (create-ltre "DDS Test" :DEBUGGING debugging?))
  (eval '(rule ((:TRUE A) (:TRUE C))
	       (rassert! (:NOT (:AND A C)) :DOMAIN-NOGOOD)))
  (eval '(rule ((:TRUE B) (:TRUE E))
	       (rassert! (:NOT (:AND B E)) :DOMAIN-NOGOOD)))
  (DD-Search '((A B) (C D) (E F)) 
	     '(show-DD-test-solution)))
	    
(defun show-DD-test-solution (&aux result)
  (dolist (var '(F E D C B A))
    (when (true? var *ltre*) (push var result)))
  (format t "~% Consistent solution: (~A)." result))
