Incrementing a global variable within a user answered defrule - clips

I'm trying to increment a defglobal variable (symcount) by 1 if the user defines that they have pain by using the (read) function
(defrule QPain
(initial-fact)
=>
(printout t "Are You In Pain? " crlf)
(bind (ans Answer) (read))
)
(defrule AnsInc
(Answ Answer = "y")
=>
(bind ?*symcount* (+ ?*symcount* 1)))
the increment must only happen of the user presses "y"
otherwise the increment must not happen.

CLIPS> (defglobal ?*symcount* = 0)
CLIPS>
(defrule QPain
=>
(printout t "Are You In Pain? ")
(bind ?answer (read))
(if (eq ?answer y)
then
(bind ?*symcount* (+ ?*symcount* 1))))
CLIPS> (reset)
CLIPS> (run)
Are You In Pain? y
CLIPS> ?*symcount*
1
CLIPS> (reset)
CLIPS> (run)
Are You In Pain? n
CLIPS> ?*symcount*
0
CLIPS>

Related

Preventing CLIPS Rule from firing twice

How could I prevent the following rule from firing twice, without retracting the initial facts?
CLIPS>
(defrule cf_calculation
(CF ?cf1)
(CF ?cf2&~?cf1)
=>
(bind ?fCF (+ ?cf1 ?cf2))
(printout t "the final CF is " ?fCF crlf))
CLIPS> (assert (CF 10))
<Fact-1>
CLIPS> (assert (CF 5))
<Fact-2>
CLIPS> (run)
the final CF is 15
the final CF is 15
CLIPS>
Instead of checking for inequality of the two values, check that the first is greater than the second:
CLIPS>
(defrule cf_calculation
(CF ?cf1)
(CF ?cf2&:(> ?cf1 ?cf2))
=>
(bind ?fCF (+ ?cf1 ?cf2))
(printout t "the final CF is " ?fCF crlf))
CLIPS> (assert (CF 10))
<Fact-1>
CLIPS> (assert (CF 5))
<Fact-2>
CLIPS> (run)
the final CF is 15
CLIPS>

how to get the index of facts in RHS of rule?

I'm asking if there is a possibility of accessing a get the index of fact in RHS of defrule ?
It gives me that undefined every time I try to index a fact in a RHS of defrule.
because I have a while loop , I want to be able to modify elevator fact depending on my input data.
(deftemplate elevator
(slot goal))
(deffacts elevator
(elevator (goal 0)))
(defrule read-data
=>
?f1 <- (elevator)
(modify ?f2 (goal 1))
)
this an example of my code , since I can't put all online :
(deftemplate data
(slot data)
)
(deffacts data
(data (data 1))
)
(defrule rule1
?f1 <-(data)
=>
(bind ?value (readline input) )
(while (neq ?value EOF)
do
(bind ?data (fact-slot-value ?f1 data))
(printout t "data " ?data crlf )
(retract ?f1)
(modify ?f1 (data ?value))
(bind ?value (readline input)
)
)
)
this is my input file :
2
3
4
5
6
7
this is what I'm getting :
CLIPS> (run)
data 1
data FALSE
data FALSE
data FALSE
data FALSE
data FALSE
CLIPS>
I want it to print out
data 2
data 3
data 4 ..ect
You can do it this way from the RHS of a rule, but if your rule actually has no LHS conditions, it's pointless to use a rule to change the value of the fact. Just use a function.
CLIPS>
(deftemplate elevator
(slot goal))
CLIPS>
(deffacts elevator
(elevator (goal 0)))
CLIPS>
(defrule read-data
=>
(do-for-fact ((?f elevator)) TRUE
(modify ?f (goal 1))))
CLIPS> (watch facts)
CLIPS> (reset)
<== f-0 (initial-fact)
==> f-0 (initial-fact)
==> f-1 (elevator (goal 0))
CLIPS> (run)
<== f-1 (elevator (goal 0))
==> f-2 (elevator (goal 1))
CLIPS>
Alternately, you can bind the fact you want to modify in the conditions of the rule:
CLIPS> (clear)
CLIPS>
(deftemplate elevator
(slot goal))
CLIPS>
(deffacts elevator
(elevator (goal 0)))
CLIPS>
(defrule read-data
?f <- (elevator (goal 0))
=>
(modify ?f (goal 1)))
CLIPS> (watch facts)
CLIPS> (reset)
<== f-0 (initial-fact)
==> f-0 (initial-fact)
==> f-1 (elevator (goal 0))
CLIPS> (run)
<== f-1 (elevator (goal 0))
==> f-2 (elevator (goal 1))
CLIPS>
Updated:
You can get your original rule to "work" by removing the retract and rebinding ?f1 to the value returned by modify:
CLIPS> (clear)
CLIPS>
(deftemplate data
(slot data))
CLIPS>
(deffacts data
(data (data 1)))
CLIPS>
(defrule rule1
?f1 <- (data)
=>
(bind ?value (readline input))
(while (neq ?value EOF)
(bind ?data (fact-slot-value ?f1 data))
(printout t "data " ?data crlf )
(bind ?f1 (modify ?f1 (data ?value)))
(bind ?value (readline input))))
CLIPS> (reset)
CLIPS> (open input.txt input)
TRUE
CLIPS> (run)
data 1
data 2
data 3
data 4
data 5
data 6
CLIPS> (close input)
TRUE
CLIPS>
It's still suspiciously complicated to be modifying the same fact multiple times on the RHS.

How to compare a global variable to a string in Clips?

In my system the user inputs a Y or N to answer simple questions. I call this rule after every question to increment a counter. There are some general problems with my code but i can't see where
(defrule QPain
(initial-fact)
=>
(printout t "Are You In Pain? " crlf)
(bind ?*Answer* (read))
)
(defrule IncSym
(test(=(str-compare (?*Answer*) "y")0))
=>
(bind ?*symcount* (+ ?*symcount* 1))
)
Thanks
The syntactic errors can be corrected as follows:
CLIPS> (clear)
CLIPS> (defglobal ?*Answer* = nil)
CLIPS> (defglobal ?*symcount* = 0)
CLIPS>
(defrule QPain
=>
(printout t "Are you in pain? ")
(bind ?*Answer* (read)))
CLIPS>
(defrule IncSym
(test (eq ?*Answer* y))
=>
(bind ?*symcount* (+ ?*symcount* 1)))
CLIPS> (reset)
CLIPS> (run)
Are you in pain? y
CLIPS> (show-defglobals)
?*Answer* = y
?*symcount* = 0
CLIPS>
This won't produce the behavior you're expecting, however, since ?*symcount* will not be incremented. The behavior of global variables and why you should not be using them in the manner you're attempting has been discussed previously:
How exactly (refresh) works in the clips?
CLIPS: forcing a rule to re-evaluate the value of a global variable?
Number equality test fails in CLIPS pattern matching?
CLIPS constant compiler directive
How can I run the clips with out reset the fact when using CLIPS
Instead of using global variables to track responses and symptoms, you should use facts or instances. Here's one approach:
CLIPS> (clear)
CLIPS>
(deftemplate symptom
(slot id)
(slot response))
CLIPS>
(deftemplate symptom-list
(multislot values))
CLIPS>
(deffacts initial
(symptom-list))
CLIPS>
(defrule QPain
=>
(printout t "Are you in pain? ")
(assert (symptom (id in-pain) (response (read)))))
CLIPS>
(defrule IncSym
(symptom (id ?id) (response y))
?f <- (symptom-list (values $?list))
(test (not (member$ ?id ?list)))
=>
(modify ?f (values ?list ?id)))
CLIPS>
(defrule symptoms-found
(declare (salience -10))
(symptom-list (values $?list))
=>
(printout t "Symptom count: " (length$ ?list) crlf))
CLIPS> (reset)
CLIPS> (run)
Are you in pain? y
Symptom count: 1
CLIPS> (reset)
CLIPS> (run)
Are you in pain? n
Symptom count: 0
CLIPS>
And another:
CLIPS> (clear)
CLIPS>
(deftemplate symptom
(slot id)
(slot response))
CLIPS>
(defrule QPain
=>
(printout t "Are you in pain? ")
(assert (symptom (id in-pain) (response (read)))))
CLIPS>
(defrule symptoms-found
(declare (salience -10))
=>
(bind ?count (find-all-facts ((?f symptom)) (eq ?f:response y)))
(printout t "Symptom count: " (length$ ?count) crlf))
CLIPS> (reset)
CLIPS> (run)
Are you in pain? y
Symptom count: 1
CLIPS> (reset)
CLIPS> (run)
Are you in pain? n
Symptom count: 0
CLIPS>

Obtain ID of fact I just asserted

Is there a way for me to get the fact ID of a fact that I just asserted in the RHS of a rule? Something along the lines of
?f <- (assert (new-fact))
CLIPS>
(defrule example
=>
(bind ?f (assert (new-fact)))
(bind ?i (fact-index ?f))
(printout t "The fact index is " ?i crlf))
CLIPS> (reset)
CLIPS> (run)
The fact index is 1
CLIPS> (facts)
f-0 (initial-fact)
f-1 (new-fact)
For a total of 2 facts.
CLIPS>

Using less than on CLIPS program

I am trying to return a message if the user types in a value within certain range. Is this possible on CLIPS? In addition the system should only accept values in increments of 10.
If the user types in a number less or equal to 10 it should say "A"
If the user types in a number greater than 10 and less than 40 it should say "B"
- so it should only accept values 10,20,30,40
This is the code I have so far:
(defrule b-a1
(b-a "a")
=>
(bind ?reply (get-text-from-user "How many points did you achieve?"))
(assert (b-a1 ?reply )))
(defrule b-a2
(b-a1 <= 10)
=>
(assert (conclusion "A")))
(defrule b-a2
(10 < b-a1 < 40)
=>
(assert (conclusion "B")))
Any ideas on how I can get this working?
CLIPS>
(defrule b-a1
(b-a "a")
=>
(printout t "How many points did you achieve? ")
(bind ?reply (read))
(assert (b-a1 ?reply )))
CLIPS>
(defrule b-a2
(b-a1 ?v&:(<= ?v 10))
=>
(assert (conclusion "A")))
CLIPS>
(defrule b-a2
(b-a1 ?v&:(< 10 ?v)&:(< ?v 40))
=>
(assert (conclusion "B")))
CLIPS> (assert (b-a "a"))
<Fact-1>
CLIPS> (run)
How many points did you achieve? 24
CLIPS> (facts)
f-0 (initial-fact)
f-1 (b-a "a")
f-2 (b-a1 24)
f-3 (conclusion "B")
For a total of 4 facts.
CLIPS>

Resources