Sophie

Sophie

distrib > Fedora > 13 > x86_64 > by-pkgid > b935a2b65501208cb2c31e83c68a477b > files > 14

clips-doc-6.30.0-0.1.20090722svn.fc12.noarch.rpm

;;;======================================================
;;;   Circuit Input/Output Simplification Expert System
;;;
;;;     This program simplifies the boolean decision 
;;;     table for a circuit consisting of inputs (SOURCES) 
;;;     and outputs (LEDs). 
;;;
;;;     The simplification procedure works as follows:
;;;     1) The connections between components of the
;;;        circuit are initialized.
;;;     2) The response of the circuit when all SOURCEs
;;;        are set to zero is determined.
;;;     3) Source input values are changed one at a time
;;;        and the response of the circuit is determined.
;;;        All possible input combinations are iterated
;;;        through using a gray code (a number representation
;;;        system using binary digits in which successive
;;;        integers differ by exactly one binary digit).
;;;        For example, the gray code for the numbers 0 to 7
;;;        is 0 = 000, 1 = 001, 2 = 011, 3 = 010, 4 = 110,
;;;        5 = 111, 6 = 101, 7 = 100. By using a gray code,
;;;        only one SOURCE has to be changed at a time to
;;;        determine the next response in the decision 
;;;        table (minimizing execution time).
;;;     4) As responses are determined, a rule checks to
;;;        see if any two sets of inputs with the same
;;;        response differ if a single input. If so, then
;;;        the single input can be replaced with a * 
;;;        (indicating that it does not matter what the
;;;        value of the input is given the other inputs).
;;;        For example,  if the input 0 1 0 gave a response
;;;        of 1 0 and the input 0 0 0 gave the same response,
;;;        then the decision table can be simplified by
;;;        indicating that 0 * 0 gives a response of 1 0.
;;;     5) Once all responses and simplifications have been
;;;        determined, the decision table for the circuit is
;;;        printed.
;;;        
;;;     This example illustrates the use of most of the
;;;     constructs available in CLIPS 6.0 and also shows how
;;;     COOL can be effectively integrated with rules.
;;;     Generic functions are used to connect the components
;;;     of the circuit during initialization. Classes,
;;;     message-handlers, and deffunctions are used to
;;;     determine the response of the circuit to a set of
;;;     inputs. Rules, deffunctions, and global variables
;;;     are used to control execution, iterate through all
;;;     possible input combinations, simplify the boolean
;;;     decision tree, and print out the simplified decision
;;;     tree.
;;;
;;;     CLIPS Version 6.0 Example
;;; 
;;;     To execute, load this file, load one of the circuit
;;;     files (circuit1.clp, circuit2.clp, or circuit3.clp), 
;;;     reset, and run.
;;;======================================================


;;;***********
;;; DEFCLASSES
;;;***********

(defclass COMPONENT
  (is-a USER)
  (slot ID# (create-accessor write)))

(defclass NO-OUTPUT
  (is-a USER)
  (slot number-of-outputs (access read-only) 
                          (default 0)
                          (create-accessor read)))

(defmessage-handler NO-OUTPUT compute-output ())

(defclass ONE-OUTPUT
  (is-a NO-OUTPUT)
  (slot number-of-outputs (access read-only) 
                          (default 1)
                          (create-accessor read))
  (slot output-1 (default UNDEFINED) (create-accessor write))
  (slot output-1-link (default GROUND) (create-accessor write))
  (slot output-1-link-pin (default 1) (create-accessor write)))

(defmessage-handler ONE-OUTPUT put-output-1 after (?value)
   (send ?self:output-1-link 
         (sym-cat put-input- ?self:output-1-link-pin)
         ?value))

(defclass TWO-OUTPUT
  (is-a ONE-OUTPUT)
  (slot number-of-outputs (access read-only) 
                          (default 2)
                          (create-accessor read))
  (slot output-2 (default UNDEFINED) (create-accessor write))
  (slot output-2-link (default GROUND) (create-accessor write))
  (slot output-2-link-pin (default 1) (create-accessor write)))

(defmessage-handler TWO-OUTPUT put-output-1 after (?value)
   (send ?self:output-2-link 
         (sym-cat put-input- ?self:output-2-link-pin)
         ?value))

(defclass NO-INPUT
  (is-a USER)
  (slot number-of-inputs (access read-only) 
                         (default 0)
                         (create-accessor read)))

(defclass ONE-INPUT
  (is-a NO-INPUT)
  (slot number-of-inputs (access read-only) 
                         (default 1)
                         (create-accessor read))
  (slot input-1 (default UNDEFINED) 
                (visibility public)
                (create-accessor read-write))
  (slot input-1-link (default GROUND) (create-accessor write))
  (slot input-1-link-pin (default 1) (create-accessor write)))

(defmessage-handler ONE-INPUT put-input-1 after (?value)
   (send ?self compute-output))

(defclass TWO-INPUT
  (is-a ONE-INPUT)
  (slot number-of-inputs (access read-only) 
                         (default 2)
                         (create-accessor read))
  (slot input-2 (default UNDEFINED) 
                (visibility public)
                (create-accessor write))
  (slot input-2-link (default GROUND) (create-accessor write))
  (slot input-2-link-pin (default 1) (create-accessor write)))

(defmessage-handler TWO-INPUT put-input-2 after (?value)
   (send ?self compute-output))
 
(defclass SOURCE
  (is-a NO-INPUT ONE-OUTPUT COMPONENT)
  (role concrete)
  (slot output-1 (default UNDEFINED) (create-accessor write)))

(defclass SINK
  (is-a ONE-INPUT NO-OUTPUT COMPONENT)
  (role concrete)
  (slot input-1 (default UNDEFINED) (create-accessor read-write)))

;;;*******************
;;; NOT GATE COMPONENT
;;;*******************

(defclass NOT-GATE
  (is-a ONE-INPUT ONE-OUTPUT COMPONENT)
  (role concrete))

(deffunction not# (?x) (- 1 ?x))

(defmessage-handler NOT-GATE compute-output ()
   (if (integerp ?self:input-1) then
       (send ?self put-output-1 (not# ?self:input-1))))

;;;*******************
;;; AND GATE COMPONENT
;;;*******************

(defclass AND-GATE
  (is-a TWO-INPUT ONE-OUTPUT COMPONENT)
  (role concrete))

(deffunction and# (?x ?y) 
  (if (and (<> ?x 0) (<> ?y 0)) then 1 else 0))

(defmessage-handler AND-GATE compute-output ()
   (if (and (integerp ?self:input-1) 
            (integerp ?self:input-2)) then
       (send ?self put-output-1 (and# ?self:input-1 ?self:input-2))))

;;;******************
;;; OR GATE COMPONENT
;;;******************

(defclass OR-GATE
  (is-a TWO-INPUT ONE-OUTPUT COMPONENT)
  (role concrete))

(deffunction or# (?x ?y) 
  (if (or (<> ?x 0) (<> ?y 0)) then 1 else 0))

(defmessage-handler OR-GATE compute-output ()
   (if (and (integerp ?self:input-1) 
            (integerp ?self:input-2)) then
       (send ?self put-output-1 (or# ?self:input-1 ?self:input-2))))

;;;********************
;;; NAND GATE COMPONENT
;;;********************

(defclass NAND-GATE
  (is-a TWO-INPUT ONE-OUTPUT COMPONENT)
  (role concrete))

(deffunction nand# (?x ?y) 
  (if (not (and (<> ?x 0) (<> ?y 0))) then 1 else 0))

(defmessage-handler NAND-GATE compute-output ()
   (if (and (integerp ?self:input-1) 
            (integerp ?self:input-2)) then
       (send ?self put-output-1 (nand# ?self:input-1 ?self:input-2))))

;;;*******************
;;; XOR GATE COMPONENT
;;;*******************

(defclass XOR-GATE
  (is-a TWO-INPUT ONE-OUTPUT COMPONENT)
  (role concrete))

(deffunction xor# (?x ?y) 
  (if (or (and (= ?x 1) (= ?y 0))
          (and (= ?x 0) (= ?y 1))) then 1 else 0))

(defmessage-handler XOR-GATE compute-output ()
   (if (and (integerp ?self:input-1) 
            (integerp ?self:input-2)) then
       (send ?self put-output-1 (xor# ?self:input-1 ?self:input-2))))

;;;*******************
;;; SPLITTER COMPONENT
;;;*******************

(defclass SPLITTER
  (is-a ONE-INPUT TWO-OUTPUT COMPONENT)
  (role concrete))

(defmessage-handler SPLITTER compute-output ()
   (if (integerp ?self:input-1) then
       (send ?self put-output-1 ?self:input-1)
       (send ?self put-output-2 ?self:input-1)))

;;;**************
;;; LED COMPONENT
;;;**************

(defclass LED
  (is-a ONE-INPUT NO-OUTPUT COMPONENT)
  (role concrete))

;;; Returns the current value of each LED 
;;; instance in a multifield value.
(deffunction LED-response ()
   (bind ?response (create$))
   (do-for-all-instances ((?led LED)) TRUE
      (bind ?response (create$ ?response (send ?led get-input-1))))
   ?response)

;;;***************************
;;; DEFGENERICS AND DEFMETHODS
;;;***************************

(defgeneric connect)

;;; Connects a one output component to a one input component.
(defmethod connect ((?out ONE-OUTPUT) (?in ONE-INPUT)) 
   (send ?out put-output-1-link ?in) 
   (send ?out put-output-1-link-pin 1)
   (send ?in  put-input-1-link ?out)
   (send ?in  put-input-1-link-pin 1))

;;; Connects a one output component to one pin of a two input component.
(defmethod connect ((?out ONE-OUTPUT) (?in TWO-INPUT) (?in-pin INTEGER)) 
   (send ?out put-output-1-link ?in)
   (send ?out put-output-1-link-pin ?in-pin)
   (send ?in  (sym-cat put-input- ?in-pin -link) ?out)
   (send ?in  (sym-cat put-input- ?in-pin -link-pin) 1))

;;; Connects one pin of a two output component to a one input component.
(defmethod connect ((?out TWO-OUTPUT) (?out-pin INTEGER) (?in ONE-INPUT)) 
   (send ?out (sym-cat put-output- ?out-pin -link) ?in)
   (send ?out (sym-cat put-output- ?out-pin -link-pin) 1)
   (send ?in put-input-1-link ?out)
   (send ?in put-input-1-link-pin ?out-pin))

;;; Connects one pin of a two output component 
;;; to one pin of a two input component.
(defmethod connect ((?out TWO-OUTPUT) (?out-pin INTEGER)
                    (?in TWO-INPUT) (?in-pin INTEGER)) 
   (send ?out (sym-cat put-output- ?out-pin -link) ?in)
   (send ?out (sym-cat put-output- ?out-pin -link-pin) ?in-pin)
   (send ?in  (sym-cat put-input- ?in-pin -link) ?out)
   (send ?in  (sym-cat put-input- ?in-pin -link-pin) ?out-pin))

;;;****************************
;;; DEFGLOBALS AND DEFFUNCTIONS 
;;;****************************

(defglobal ?*gray-code* = (create$)
           ?*sources* = (create$)
           ?*max-iterations* = 0)

;;; Given the current iteration, determines the next 
;;; bit in the gray code to change. 
;;; Algorithm courtesy of John R. Kennedy (The BitMan).
(deffunction change-which-bit (?x)
   (bind ?i 1)
   (while (and (evenp ?x) (<> ?x 0)) do 
      (bind ?x (div ?x 2))
      (bind ?i (+ ?i 1)))
   ?i)

;;; Forward declaration since the initial configuration
;;; is stored in a separate file.
(deffunction connect-circuit ())

;;;*********
;;; DEFRULES
;;;*********

(defrule startup
  =>
  ;; Initialize the circuit by connecting the components
  (connect-circuit) 
  ;; Setup the globals. 
  (bind ?*sources* (find-all-instances ((?x SOURCE)) TRUE))
  (do-for-all-instances ((?x SOURCE)) TRUE
     (bind ?*gray-code* (create$ ?*gray-code* 0)))
  (bind ?*max-iterations* (round (** 2 (length ?*sources*))))
  ;; Do the first response.
  (assert (current-iteration 0)))

(defrule compute-response-1st-time
   ?f <- (current-iteration 0)
   =>
   ;; Set all of the sources to zero.
   (do-for-all-instances ((?source SOURCE)) TRUE (send ?source put-output-1 0))
   ;; Determine the initial LED response.
   (assert (result ?*gray-code* =(str-implode (LED-response))))
   ;; Begin the iteration process of looping through the gray code combinations.
   (retract ?f)
   (assert (current-iteration 1)))

(defrule compute-response-other-times
   ?f <- (current-iteration ?n&~0&:(< ?n ?*max-iterations*))
   =>
   ;; Change the gray code, saving the changed bit value.
   (bind ?pos (change-which-bit ?n))
   (bind ?nv (- 1 (nth ?pos ?*gray-code*)))
   (bind ?*gray-code* (replace$ ?*gray-code* ?pos ?pos ?nv))
   ;; Change the single changed source
   (send (nth ?pos ?*sources*) put-output-1 ?nv)   
   ;; Determine the LED response to the input.
   (assert (result ?*gray-code* =(str-implode (LED-response))))
   ;; Assert the new iteration fact
   (retract ?f)
   (assert (current-iteration =(+ ?n 1))))

(defrule merge-responses
   (declare (salience 10))
   ?f1 <- (result $?b  ?x $?e ?response)
   ?f2 <- (result $?b ~?x $?e ?response)
   =>
   (retract ?f1 ?f2)
   (assert (result $?b * $?e ?response)))

(defrule print-header
   (declare (salience -10))
   =>
   (assert (print-results))
   (do-for-all-instances ((?x SOURCE)) TRUE (format t " %3s " (sym-cat ?x)))
   (printout t " | ")
   (do-for-all-instances ((?x LED)) TRUE (format t " %3s " (sym-cat ?x)))
   (format t "%n")
   (do-for-all-instances ((?x SOURCE)) TRUE (printout t "-----"))
   (printout t "-+-")
   (do-for-all-instances ((?x LED)) TRUE (printout t "-----"))
   (format t "%n"))
      
(defrule print-result
   (print-results)
   ?f <- (result $?input ?response)
   (not (result $?input-2 ?response-2&:(< (str-compare ?response-2 ?response) 0)))
   =>
   (retract ?f)
   ;; Print the input from the sources.
   (while (neq ?input (create$)) do
      (printout t "  " (nth 1 ?input) "  ")
      (bind ?input (rest$ ?input)))
   ;; Print the output from the LEDs.
   (printout t " | ")
   (bind ?response (str-explode ?response))
   (while (neq ?response (create$)) do
      (printout t "  " (nth 1 ?response) "  ")
      (bind ?response (rest$ ?response)))
   (printout t crlf))