Clips not providing answer - clips

So I get the program to say enter name. However, once I enter the name it doesn't output any other information. I'm trying to get it to print out the name, class, magnitude, and distance. Where am I going wrong?
(deftemplate stars
(slot name)
(slot class)
(slot magnitude)
(slot dist)
)
(deffacts star
(stars (name Sirius) (class A) (magnitude 1) (dist 8.8))
(stars (name Canopus) (class F) (magnitude -3) (dist 98))
(stars (name Arcturus) (class K) (magnitude 0) (dist 36))
(stars (name Vega) (class A) (magnitude 1) (dist 26))
(stars (name Capella) (class G) (magnitude -1) (dist 46))
(stars (name Rigel) (class B) (magnitude -7) (dist 880))
(stars (name Procyon) (class F) (magnitude 3) (dist 11))
(stars (name Betelgeuse) (class M) (magnitude -5) (dist 490))
(stars (name Altair) (class A) (magnitude 2) (dist 16))
(stars (name Aldebaran) (class K) (magnitude -1) (dist 68))
(stars (name Spica) (class B) (magnitude -3) (dist 300))
(stars (name Antares) (class M) (magnitude -4) (dist 250))
(stars (name Pollux) (class K) (magnitude 1) (dist 35))
(stars (name Deneb) (class A) (magnitude -7) (dist 1630))
)
(defrule start-up
?i <- (initial-fact)
=>
(printout t "Enter name: ")
(bind ?y (read))
(assert (name ?y))
(retract ?i)
)
(defrule S1
?char <- (stars (name ?n) (class ?c) (magnitude ?m) (dist ?d))
(name ?y)
(test ( eq ?n ?y))
=>
(printout t ?n " " ?c" " ?m " " ?d crlf)
(retract ?char)
(assert (found))
)
I got the initial output of enter name but didn't get the second output of name, class, magnitude, and distance.

Related

Import rules to CLIPS and evaluate its performance

Can someone explain me how can I import the WEKA created rules in CLIPS and evaluate its efficience in TRS and TES data?
The data I use
I have written 7 rules out of 20 from WEKA tree. I include also 3 instances from the glass datasheet
small test code
(deftemplate glass
(slot n(type FLOAT))
(slot m(type FLOAT))
(slot a(type FLOAT))
(slot b(type FLOAT))
(slot r(type FLOAT))
(slot s(type FLOAT))
(slot k(type FLOAT))
(slot c(type FLOAT)))
(deftemplate Type
(slot type))
(deffacts instances1
(glass (n 13.00)
(m 2.28)
(a 1.00)
(b 0.00)))
(deffacts instances2
(glass (n 13.70)
(m 1.80)
(a 1.40)
(b 0.00)))
(deffacts instances3
(glass (n 13.70)
(m 1.90)
(a 1.40)
(b 0.00)))
(defrule R1
(glass (b ?b))
(test (<= ?b 0.27))
(glass (m ?m))
(test (<= ?m 2.41))
(glass (n ?n))
(test (<= ?n 13.78))
(glass (a ?a))
(test (<= ?a 1.38))
=>
(assert (Type (type buildwindnonfloat1)))
(printout t "buildwindnonfloat1 detected" crlf))
(defrule R2
(glass (b ?b))
(test (<= ?b 0.27))
(glass (m ?m))
(test (<= ?m 2.41))
(glass (n ?n))
(test (<= ?n 13.78))
(glass (a ?a))
(test (> ?a 1.38))
(glass (m ?m))
(test (<= ?m 1.88))
=>
(assert (Type (type containers2)))
(printout t "containers2 detected" crlf))
(defrule R3
(glass (b ?b))
(test (<= ?b 0.27))
(glass (m ?m))
(test (<= ?m 2.41))
(glass (n ?n))
(test (<= ?n 13.78))
(glass (a ?a))
(test (> ?a 1.38))
(glass (m ?m))
(test (> ?m 1.88))
=>
(assert (Type (type buildwindnonfloat3)))
(printout t "buildwindnonfloat3 detected" crlf))
(defrule R4
(glass (b ?b))
(test (<= ?b 0.27))
(glass (m ?m))
(test (<= ?m 2.41))
(glass (n ?n))
(test (> ?n 13.78))
=>
(assert (Type (type tableware4)))
(printout t "tableware detected" crlf))
(defrule R5
(glass (b ?b))
(test (<= ?b 0.27))
(glass (m ?m))
(test (> ?m 2.41))
(glass (a ?a))
(test (<= ?a 1.4))
(glass (m ?m))
(test (<= ?m 3.34))
(glass (a ?a))
(test (<= ?a 1.25))
=>
(assert (Type (type buildwindnonfloat5)))
(printout t "buildwindnonfloat5 detected" crlf))
(defrule R6
(glass (b ?b))
(test (<= ?b 0.27))
(glass (m ?m))
(test (> ?m 2.41))
(glass (a ?a))
(test (<= ?a 1.4))
(glass (m ?m))
(test (<= ?m 3.34))
(glass (a ?a))
(test (> ?a 1.25))
=>
(assert (Type (type buildwindfloat6)))
(printout t "buildwindfloat6 detected" crlf))
(defrule R7
(glass (b ?b))
(test (<= ?b 0.27))
(glass (m ?m))
(test (> ?m 2.41))
(glass (a ?a))
(test (<= ?a 1.4))
(glass (m ?m))
(test (> ?m 3.34))
(glass (m ?m))
(test (<= ?m 3.82))
(glass (r ?r))
(test (<= ?r 1.51707))
(glass (r ?r))
(test (<= ?r 51596))
=>
(assert (Type (type buildwindfloat7)))
(printout t "buildwindfloat7 detected" crlf))
To convert your data, it's easiest to read the data from the file when your program is running and directly assert the facts. So if your data looks like the following with each entry on its own line
1.5159,13.24,3.34,1.47,73.1,0.39,8.22,0,0,'build wind non-float'
1.5167,13.24,3.57,1.38,72.7,0.56,8.44,0,0.1,'vehic wind float'
then your can read your data by reading each line as a single string, replacing the commas with spaces, and then splitting the string into multiple values. You can then have a separate rule map the values from your file to the appropriate slots in your deftemplate facts.
Store the expected result with each glass fact and then you can compare that value to the value that your rule is proposing.
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate glass
(slot n (type FLOAT))
(slot m (type FLOAT))
(slot a (type FLOAT))
(slot b (type FLOAT))
(slot r (type FLOAT))
(slot s (type FLOAT))
(slot k (type FLOAT))
(slot c (type FLOAT))
(slot f (type FLOAT))
(slot type))
CLIPS>
(deftemplate input
(multislot data))
CLIPS>
(deffunction str-rpl (?str ?find ?replace)
(if (eq ?find "")
then
(return ?str))
(bind ?rs "")
(bind ?fl (str-length ?find))
(bind ?i (str-index ?find ?str))
(while (neq ?i FALSE)
(bind ?rs (str-cat ?rs (sub-string 1 (- ?i 1) ?str) ?replace))
(bind ?str (sub-string (+ ?i ?fl) (str-length ?str) ?str))
(bind ?i (str-index ?find ?str)))
(bind ?rs (str-cat ?rs ?str))
?rs)
CLIPS>
(defrule get-data
=>
(printout t "Input File? ")
(bind ?file (readline))
(if (not (open ?file data))
then
(printout t "Unable to open file" crlf)
(return))
(bind ?line (readline data))
(while (neq ?line EOF)
(bind ?line (str-rpl ?line "," " "))
(bind ?line (str-rpl ?line "'" "\""))
(assert (input (data (explode$ ?line))))
(bind ?line (readline data)))
(close data))
CLIPS>
(defrule convert-data
?i <- (input (data ?r ?n ?m ?a ?s ?k ?c ?b ?f ?type))
=>
(retract ?i)
(assert (glass (r ?r) (n ?n) (m ?m) (a ?a) (s ?s) (k ?k) (c ?c) (b ?b) (f ?f) (type ?type))))
CLIPS>
(defrule R1
(glass (b ?b)
(m ?m)
(n ?n)
(a ?a)
(type ?type))
(test (<= ?b 0.27))
(test (<= ?m 2.41))
(test (<= ?n 13.78))
(test (<= ?a 1.38))
=>
(printout t "buildwindnonfloat1 detected type = " ?type crlf))
CLIPS>
(defrule R2
(glass (b ?b)
(m ?m)
(n ?n)
(a ?a)
(type ?type))
(test (<= ?b 0.27))
(test (<= ?m 2.41))
(test (<= ?n 13.78))
(test (> ?a 1.38))
(test (<= ?m 1.88))
=>
(printout t "containers2 detected type = " ?type crlf))
CLIPS>
(defrule R3
(glass (b ?b)
(m ?m)
(n ?n)
(a ?a)
(type ?type))
(test (<= ?b 0.27))
(test (<= ?m 2.41))
(test (<= ?n 13.78))
(test (> ?a 1.38))
(test (> ?m 1.88))
=>
(printout t "buildwindnonfloat3 detected type = " ?type crlf))
CLIPS>
(defrule R4
(glass (b ?b)
(m ?m)
(n ?n)
(type ?type))
(test (<= ?b 0.27))
(test (<= ?m 2.41))
(test (> ?n 13.78))
=>
(printout t "tableware detected type = " ?type crlf))
CLIPS>
(defrule R5
(glass (b ?b)
(m ?m)
(a ?a)
(type ?type))
(test (<= ?b 0.27))
(test (> ?m 2.41))
(test (<= ?a 1.4))
(test (<= ?m 3.34))
(test (<= ?a 1.25))
=>
(printout t "buildwindnonfloat5 detected type = " ?type crlf))
CLIPS>
(defrule R6
(glass (b ?b)
(m ?m)
(a ?a)
(type ?type))
(test (<= ?b 0.27))
(test (> ?m 2.41))
(test (<= ?a 1.4))
(test (<= ?m 3.34))
(test (> ?a 1.25))
=>
(printout t "buildwindfloat6 detected type = " ?type crlf))
CLIPS>
(defrule R7
(glass (b ?b)
(m ?m)
(a ?a)
(r ?r)
(type ?type))
(test (<= ?b 0.27))
(test (> ?m 2.41))
(test (<= ?a 1.4))
(test (> ?m 3.34))
(test (<= ?m 3.82))
(test (<= ?r 1.51707))
(test (<= ?r 51596))
=>
(printout t "buildwindfloat7 detected type = " ?type crlf))
CLIPS> (reset)
CLIPS> (run)
Input File? weka.txt
buildwindfloat7 detected type = vehic wind float
CLIPS>

Rule does not trigger even having the facts in WM

As the title suggests, I have a "generate-hotels" rule which, although being in the correct module and having all the facts that are needed in WM, this rule does not occur.
(defrule HOTELS::generate-hotels
(hotel (name ?name) (tr ?tr) (stars ?s) (price-per-night ?ppn))
(tourism-resort (name ?tr) (region ?r) (type $? ?t $?) (score ?s))
(tourism-type ?t)
(attribute (name best-region) (value ?r) (certainty ?certainty-1))
(attribute (name best-city) (value ?city&:(eq ?city (sym-cat (str-cat ?r "-") ?tr))) (certainty ?certainty-2))
(attribute (name best-tourism-type) (value ?t) (certainty ?certainty-3))
=>
(assert (attribute (name hotel) (value ?name)
(certainty (min ?certainty-1 ?certainty-2 ?certainty-3)))))

Looping defrule in CLIPS

I am trying to solve a problem, where I have to fill a 5x5 matrix with letters A, B, C, D, and E. Each letter cannot occur more than once in each row and in each column. With some initial letter positions given.
I created every position as separate facts eg. "M 1 1 X".
I am struggling how to loop a defrule in way to assert a fact with correct letter and check the conditions again.
(defrule solveA5
?a <-(M 5 ?c X)
(not (M ?x ?c A))
=>
(retract ?a)
(assert (M 5 ?c A))
)
Code above for example is only to check presence of A in every position of 5th row, but the problem is that conditions are checked at the beginning only and instead of asserting correct fact and checking again it asserts A in every position.
I've tried using deffunction to loop defrule.
(deffunction solve (?letter)
(loop-for-count (?x 1 5) do
(loop-for-count (?y 1 5) do
(build (str-cat"defrule costam
?a <-(M ?x ?y X)
(not (and(M ?x ?a ?letter) (M ?b ?y ?letter))
=>
(retract ?a)
(assert (M ?x ?y ?letter))")
)
)
)
)
Unfortunately running
(solve A)
returns "FALSE" and doesn't modify any facts.
To handle iteration within rules, you must assert the iteration information as facts to allow the rules to match and modify this information. In the placement, it's not essential to do this in any particular order, so you can just assert information containing the rows, columns, and letters to place and allow the rules fire arbitrarily:
CLIPS>
(deftemplate element
(slot row)
(slot column)
(slot value))
CLIPS>
(deftemplate print
(slot row)
(slot column)
(slot end-of-row))
CLIPS>
(deffacts initial
(rows 1 2 3 4 5)
(columns 1 2 3 4 5)
(letters A B C D E))
CLIPS>
(defrule place
(rows $? ?r1 $?)
(columns $? ?c1 $?)
(letters $? ?l $?)
(not (element (row ?r1) (column ?c1)))
(not (and (element (row ?r2)
(column ?c2)
(value ?l))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))))
=>
(assert (element (row ?r1) (column ?c1) (value ?l))))
CLIPS>
(defrule print-start
(declare (salience -10))
(rows ?r $?)
(columns ?c $?rest)
=>
(assert (print (row ?r)
(column ?c)
(end-of-row (= (length$ ?rest) 0)))))
CLIPS>
(defrule print-next-column
(declare (salience -10))
?f <- (print (column ?c))
(columns $? ?c ?nc $?rest)
=>
(modify ?f (column ?nc)
(end-of-row (= (length$ ?rest) 0))))
CLIPS>
(defrule print-next-row
(declare (salience -10))
?f <- (print (column ?c) (row ?r))
(columns $?first ?c)
(rows $? ?r ?nr $?)
=>
(if (= (length$ ?first) 0)
then
(bind ?eor TRUE)
(bind ?nc ?c)
else
(bind ?eor FALSE)
(bind ?nc (nth$ 1 ?first)))
(modify ?f (row ?nr)
(column ?nc)
(end-of-row ?eor)))
CLIPS>
(defrule print-placed
(print (row ?r) (column ?c) (end-of-row ?eor))
(element (row ?r) (column ?c) (value ?l))
=>
(if ?eor
then
(printout t ?l crlf)
else
(printout t ?l " ")))
CLIPS>
(defrule print-unplaced
(print (row ?r) (column ?c) (end-of-row ?eor))
(not (element (row ?r) (column ?c)))
=>
(if ?eor
then
(printout t "?" crlf)
else
(printout t "? ")))
CLIPS> (reset)
CLIPS> (run)
E D C B A
? C D A B
? B A D C
? A B C D
A ? ? ? E
CLIPS>
In this example, the print rules iterate over the rows and columns by storing the iteration information in facts. You can see how much more complicated this is than the place rule which assigns the elements in an arbitrary manner.
Whether you assign the values arbitrarily or in a specific order, it's possible to assign values that prevent a solution, so you must implement backtracking in order to guarantee finding the solution if one exists. In this example, the facts store information about the order of the value placements and the values that have been tried:
CLIPS> (clear)
CLIPS>
(deftemplate element
(slot row)
(slot column)
(slot value (default unset))
(multislot values)
(slot placement))
CLIPS>
(deffacts initial
(placement 0)
(rows 1 2 3 4 5)
(columns 1 2 3 4 5)
(letters A B C D E))
CLIPS>
(defrule prime
(placement ?p)
(rows $? ?r $?)
(columns $? ?c $?)
(letters $?l)
(not (element (placement ?p)))
(not (element (row ?r) (column ?c)))
=>
(assert (element (placement ?p) (values ?l) (row ?r) (column ?c))))
CLIPS>
(defrule place-good
?f1 <- (placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(row ?r1)
(column ?c1)
(values ?v $?rest))
(not (and (element (row ?r2)
(column ?c2)
(value ?v))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))))
=>
(retract ?f1)
(assert (placement (+ ?p 1)))
(modify ?f2 (value ?v) (values ?rest)))
CLIPS>
(defrule place-bad
(placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(row ?r1)
(column ?c1)
(values ?v $?rest))
(element (row ?r2)
(column ?c2)
(value ?v))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))
=>
(modify ?f2 (values ?rest)))
CLIPS>
(defrule backtrack
?f1 <- (placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(values))
?f3 <- (element (placement =(- ?p 1))
(value ~unset))
=>
(retract ?f1)
(assert (placement (- ?p 1)))
(retract ?f2)
(modify ?f3 (value unset)))
CLIPS>
(defrule print
(declare (salience -10))
(rows $?rows)
(columns $?columns)
=>
(progn$ (?r ?rows)
(progn$ (?c ?columns)
(if (not (do-for-fact ((?f element))
(and (= ?r ?f:row) (= ?c ?f:column))
(printout t ?f:value " ")))
then
(printout t "? ")))
(printout t crlf)))
CLIPS> (reset)
CLIPS> (run)
B C D E A
A B C D E
C A E B D
D E A C B
E D B A C
CLIPS>
The print rules have been simplified into a single rule that iterates over the row and columns in the actions of the rule and uses the fact query functions to retrieve values that have been assigned.
The program also works if you preassign some of the values:
CLIPS> (reset)
CLIPS> (assert (element (row 1) (column 1) (value A)))
<Fact-5>
CLIPS> (assert (element (row 3) (column 3) (value C)))
<Fact-6>
CLIPS> (assert (element (row 5) (column 4) (value E)))
<Fact-7>
CLIPS> (run)
A C E D B
B A D C E
D E C B A
E D B A C
C B A E D
CLIPS>

How to make fact together in clips

How to make fact in multiple type? like in this code get the same rank fact together.
(P X Y) means X is Y's elder member
i had tried this:
(deffacts people
(P a b)
(P b c)
(P a d)
(P d e)
(P d f)
)
(defrule ranking
(P ?x ?y)
(P ?y ?z)
=>
(assert (R ?x $?y $?z))
)
i want to make a complete seniority in the family,
and get (R a bd cef), but i just get (R a b c) (R a d e) (R a d f)
can u help me?
It's a bit more complicated than what you've attempted, particularly if you want it to work properly for more than 3 generations and/or multiple family groups.
CLIPS>
(defmethod concat$ ((?m1 MULTIFIELD) (?m2 MULTIFIELD (>= (length$ ?m1) (length$ ?m2))))
(bind ?rv (create$))
(loop-for-count (?i 1 (length$ ?m2))
(bind ?rv (create$ ?rv (sym-cat (nth$ ?i ?m1) (nth$ ?i ?m2)))))
(create$ ?rv (mv-subseq (+ 1 (length$ ?m2)) (length$ ?m1) ?m1)))
CLIPS>
(defmethod concat$ ((?m1 MULTIFIELD) (?m2 MULTIFIELD (< (length$ ?m1) (length$ ?m2))))
(bind ?rv (create$))
(loop-for-count (?i 1 (length$ ?m1))
(bind ?rv (create$ ?rv (sym-cat (nth$ ?i ?m1) (nth$ ?i ?m2)))))
(create$ ?rv (mv-subseq (+ 1 (length$ ?m1)) (length$ ?m2) ?m2)))
CLIPS>
(deffacts people
(P a b) ; Family 1
(P b c)
(P a d)
(P d e)
(P d f)
(P g h) ; Family 2
(P h j)
(P h k)
(P k l)
(P k m)
(P k n)
(P j o)
(P j p)
(P j q)
(P q r)
(P q s))
CLIPS>
(defrule copy
(P ?x ?y)
=>
(assert (R ?x ?y)))
CLIPS>
(defrule extend
?f1 <- (R $?b ?x ?ym $?e1)
?f2 <- (R ?y $?z)
(test (str-index ?y ?ym))
=>
(retract ?f1 ?f2)
(assert (R ?b ?x ?ym (concat$ ?e1 ?z))))
CLIPS>
(defrule combine
?f1 <- (R ?x $?b ?y1 $?e1)
?f2 <- (R ?x $?b ?y2&~?y1 $?e2)
=>
(retract ?f1 ?f2)
(assert (R ?x ?b (sym-cat ?y1 ?y2) (concat$ ?e1 ?e2))))
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (P a b)
f-2 (P b c)
f-3 (P a d)
f-4 (P d e)
f-5 (P d f)
f-6 (P g h)
f-7 (P h j)
f-8 (P h k)
f-9 (P k l)
f-10 (P k m)
f-11 (P k n)
f-12 (P j o)
f-13 (P j p)
f-14 (P j q)
f-15 (P q r)
f-16 (P q s)
f-37 (R g h jk opqlmn rs)
f-46 (R a bd cef)
For a total of 19 facts.
CLIPS>

Clips- small routine program

I have 10 sensor that watch an environment. The sensor is 1 if OK and 0 if not.
I need to create a functional that will print out a Warning message to the terminal if there are at least 3 sensor that are on 0, and the message warning to be showed only once. This I need to do in clips.
Thank you.
(deffacts listaSenzor
(sensor L1 0)
(sensor L2 0)
(sensor L3 1)
(sensor L4 1)
(sensor L5 1)
(sensor L6 1)
(sensor L7 0)
(sensor L8 1)
(sensor L9 0)
)
(defrule rr
(sensor ?a 0 )
(sensor ?b 0 )
(sensor ?c 0 )
=>
printout t ?a ?b ?c "==>WARNING" crlf)
)
There are two issues you need to deal with. The first is that the patterns you defined can match the same fact multiple times (e.g., sensor L1 will be bound to a, b, and c). To get around this, you need to ensure that a, b, and c are unique. One way to do this is as follows (note that I also added a missing "(" in front of your printout statement):
(deffacts listaSenzor
(sensor L1 0)
(sensor L2 0)
(sensor L3 1)
(sensor L4 1)
(sensor L5 1)
(sensor L6 1)
(sensor L7 0)
(sensor L8 1)
(sensor L9 0))
(defrule rr
(sensor ?a 0)
(sensor ?b 0)
(sensor ?c 0)
(test (neq ?a ?b))
(test (neq ?a ?c))
(test (neq ?b ?c))
=>
(printout t ?a ?b ?c "==>WARNING" crlf))
Running this rule against your facts gives:
CLIPS> (reset)
CLIPS> (run)
L9L7L2==>WARNING
L9L7L1==>WARNING
L9L2L7==>WARNING
...
L1L2L7==>WARNING
L2L1L7==>WARNING
The warning is now only generated when there are three or more not-OK sensors; however, the output presents the second issue, which is that your warning is being generated multiple times (once for every unique combination of three not-OK sensors). To get around this, you probably want a control fact to prevent the rule from firing multiple times. To achieve this, you could modify the rule with the following:
(defrule rr
(not (sensor-warning))
(sensor ?a 0)
(sensor ?b 0)
(sensor ?c 0)
(test (neq ?a ?b))
(test (neq ?a ?c))
(test (neq ?b ?c))
=>
(assert (sensor-warning))
(printout t ?a ?b ?c "==>WARNING" crlf))
This ensures that the rule will only fire once (unless you retract the sensor-warning fact). Running with the updated rule:
CLIPS> (reset)
CLIPS> (run)
L9L7L2==>WARNING
CLIPS>
This is a simple solution to your problem. If you are likely to change the number of not-OK sensors that should trigger the rule, then you should probably replace the "hardwired" sensor name comparisons with more general logic (e.g., you could compute the total number of not-OK sensors and compare that to your threshold).
Here's another way to do it:
(deftemplate sensor
(slot id)
(slot value))
(deffacts listaSenzor
(sensor (id L1) (value 0))
(sensor (id L2) (value 0))
(sensor (id L3) (value 1))
(sensor (id L4) (value 1))
(sensor (id L5) (value 1))
(sensor (id L6) (value 1))
(sensor (id L7) (value 0))
(sensor (id L8) (value 1))
(sensor (id L9) (value 0)))
(defrule rr
(exists
(sensor (id ?id1) (value 0))
(sensor (id ?id2&~?id1) (value 0))
(sensor (id ?id3&~?id2&~?id1) (value 0)))
=>
(bind ?sensors (create$))
(do-for-all-facts ((?f sensor)) (eq ?f:value 0)
(bind ?sensors (create$ ?sensors ?f:id)))
(printout t (str-implode ?sensors) " ==> WARNING" crlf))
This will print all of the sensors if there are more than 3 that have a value of 0.
CLIPS> (reset)
CLIPS> (run)
L1 L2 L7 L9 ==> WARNING
CLIPS>

Resources