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).