📄 electrnc.clp
字号:
;;;======================================================
;;; 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))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -