From what I understand in "matching" step several rules might get "enabled" because their conditions are satisfied by the facts in WM. However I thought in conflict resolution step only one of the rules in agenda will be fired.
Now I have a program in which 2 rules are enabled into agenda and in run step both get fired! Isn't it supposed that only one rule be fired?
CLIPS> (defrule testrule1 (declare (salience 1))
(testfact1) (testfact2) => (printout t "testrule1 firing." crlf))
CLIPS> (defrule testrule2
(testfact1) => (printout t "testrule2 firing." crlf))
CLIPS> (assert (testfact1) (testfact2))
==> f-1 (testfact1)
==> Activation 0 testrule2: f-1
==> f-2 (testfact2)
==> Activation 1 testrule1: f-1,f-2
<Fact-2>
CLIPS> (agenda)
1 testrule1: f-1,f-2
0 testrule2: f-1
For a total of 2 activations.
CLIPS> (run)
FIRE 1 testrule1: f-1,f-2
testrule1 firing.
FIRE 2 testrule2: f-1
testrule2 firing.
CLIPS>
Conflict resolution does not prevent both rules from firing - it just determines which is fired first. If you only want one of the two rules to fire, then you should either retract testfact1 in the RHS of the selected rule or remove the other rule from the agenda by some other means (e.g., using a control fact).
Related
I need to create a rule that will check if the list of facts I have entered matches the facts already given. Then the fact / facts corresponding to at least one of the entered ones are displayed.
this is what I have:
(deftemplate rule (multislot problem) (slot cause))
(deffacts info
(rule (problem one) (cause one1))
(rule (problem two) (cause two2))
(rule (problem three) (cause three3))
(defrule reading-input
=>
(printout t "Enter your problems: " )
(assert (problem (read))))
(defrule checking-input
(problem $?problem)
(rule (problem $?problem1) (cause ?cause1))
(test (eq ?problem ?problem1))
=>
(printout t "cause: " ?cause1 crlf))
how this should work:
CLIPS> Enter your problems: one two
CLIPS> cause: one1
cause: two2
Using the read function will retrieve just one value from your input. You need to use the readline function in conjunction with the explode$ function:
CLIPS (6.4 2/9/21)
CLIPS> (assert (problem (read)))
one two
<Fact-1>
CLIPS> (assert (problem (readline)))
one two
<Fact-2>
CLIPS> (assert (problem (explode$ (readline))))
one two
<Fact-3>
CLIPS> (facts)
f-1 (problem one)
f-2 (problem "one two")
f-3 (problem one two)
For a total of 3 facts.
CLIPS>
You can then use multifield wildcards to isolate individual problems within your rule:
CLIPS> (clear)
CLIPS>
(deftemplate rule
(multislot problem)
(slot cause))
CLIPS>
(deffacts info
(rule (problem one) (cause one1))
(rule (problem two four) (cause two2))
(rule (problem one three five) (cause three3)))
CLIPS>
(defrule reading-input
=>
(printout t "Enter your problems: " )
(assert (problem (explode$ (readline)))))
CLIPS>
(defrule checking-input
(problem $? ?problem $?)
(rule (problem $? ?problem $?) (cause ?cause))
=>
(printout t "Problem: " ?problem " cause: " ?cause crlf))
CLIPS> (reset)
CLIPS> (run)
Enter your problems: one two
Problem: one cause: three3
Problem: one cause: one1
Problem: two cause: two2
CLIPS>
Let's say I have some facts (I do not know how many there are) like this: lamp x is off. With a defrule I proggressively turn all lamps on so every fact will be: lamp x is on. How do I check every lamp that is on. I know that if there were three lamps I could write:
(defrule checkAllLamps
(lamp 1 is on)
(lamp 2 is on)
(lamp 3 is on)
=>
(printout t "All lamps are on now")
)
But for x lamps?
Thank you!
You can use fact-set query functions for that (chapter 12.9.12 of the Basic Programming Guide).
(deftemplate lamp
(slot id (type INTEGER))
(slot state (type SYMBOL)))
(defrule all-lamps-are-on
(lamp (state on))
(test (>= (length$ (find-all-facts ((?l lamp)) (eq ?l:state on))) 3))
=>
(printout t "All lamps are on" crlf))
Here's how you can check whether all of the lamps are on. The checkAllLamps rule treats the case where there are no lamps at all as all lamps being on, whereas the checkAllLampsAtLeastOne rule requires that there is at least one lamp that is on.
CLIPS (6.31 2/3/18)
CLIPS>
(defrule checkAllLamps
(not (lamp ? is off))
=>
(printout t "All lamps are on now" crlf))
CLIPS>
(defrule checkAllLampsAtLeastOne
(exists (lamp ? is on))
(not (lamp ? is off))
=>
(printout t "All lamps are on now" crlf))
CLIPS> (agenda)
0 checkAllLamps: *
For a total of 1 activation.
CLIPS> (assert (lamp 1 is on))
<Fact-1>
CLIPS> (agenda)
0 checkAllLampsAtLeastOne: *,*
0 checkAllLamps: *
For a total of 2 activations.
CLIPS> (assert (lamp 2 is off))
<Fact-2>
CLIPS> (agenda)
CLIPS> (retract 2)
CLIPS> (assert (lamp 2 is on))
<Fact-3>
CLIPS> (agenda)
0 checkAllLampsAtLeastOne: *,*
0 checkAllLamps: *
For a total of 2 activations.
CLIPS>
I am new to clips, I found that my retract not really delete the facts.
(defrule test
(select ?select~indoor&~outdoor)
=>
(retract ?select)
)
After the clips run this code, I try to check by using (facts),but I still found that the facts select is still there
You need to bind a variable to the fact matching the pattern. You can't retract the fact by binding a variable to a value inside the fact.
CLIPS (6.31 2/3/18)
CLIPS>
(defrule test
?f <- (select ...)
=>
(retract ?f))
CLIPS> (assert (select ...))
<Fact-1>
CLIPS> (facts)
f-0 (initial-fact)
f-1 (select ...)
For a total of 2 facts.
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
For a total of 1 fact.
CLIPS>
Is it possible to cause CLIPS to re-evaluate the value of a global variable in a defrule? I have this:
(defrule encourage "Do we have a GPA higher than 3.7?"
(test (> (gpa) 3.7))
=>
(printout t "Keep up the excellent work!" crlf))
gpa is function that calculates and returns a number based on two global variables (grade points and number of credits). I read somewhere that changes to global variables do not invoke pattern matching. How do I go about forcing this? I want to print that string every time I do (run) as long as the GPA is higher than 3.7.
Don't attempt to use global variables or function calls in this manner. First, global variables are specifically designed to not trigger pattern matching. Second, it would take a bit of magic for CLIPS to know when a function call needs to be reevaluated as there are any number of changes which could cause a function to return a different value, not just changes to globals. If you want a particular piece of information to trigger pattern matching, then stick it in a fact or instance. It will make your code easier to understand if you parameterize the function calls and bind the values to be used as arguments in the conditions of the rule.
CLIPS> (clear)
CLIPS>
(deffunction gpa (?grade-points ?number-of-credits)
(/ ?grade-points ?number-of-credits))
CLIPS>
(defrule encourage "Do we have a GPA higher than 3.7?"
(grade-points ?gp)
(number-of-credits ?noc)
(test (> (gpa ?gp ?noc) 3.7))
=>
(printout t "Keep up the excellent work!" crlf))
CLIPS> (assert (grade-points 35) (number-of-credits 10))
<Fact-2>
CLIPS> (agenda)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (grade-points 35)
f-2 (number-of-credits 10)
For a total of 3 facts.
CLIPS> (retract 1)
CLIPS> (assert (grade-points 38))
<Fact-3>
CLIPS> (agenda)
0 encourage: f-3,f-2
For a total of 1 activation.
CLIPS>
Alternately, you can use the fact query functions to iterate over a group of facts to dynamically compute the gpa based on facts rather than globals. Each time you modify one of these facts (add or remove), you can also assert a fact indicating the gpa needs to be rechecked to trigger the encourage rule.
CLIPS> (clear)
CLIPS>
(deftemplate grade
(slot class)
(slot grade-points)
(slot credits))
CLIPS>
(deffunction gpa ()
(bind ?grade-points 0)
(bind ?credits 0)
(do-for-all-facts ((?g grade)) TRUE
(bind ?grade-points (+ ?grade-points ?g:grade-points))
(bind ?credits (+ ?credits ?g:credits)))
(if (= ?credits 0)
then 0
else (/ ?grade-points ?credits)))
CLIPS>
(defrule encourage
?f <- (check-gpa)
=>
(retract ?f)
(if (> (gpa) 3.7)
then
(printout t "Keep up the excellent work!" crlf)))
CLIPS> (gpa)
0
CLIPS> (assert (check-gpa))
<Fact-1>
CLIPS> (run)
CLIPS> (assert (grade (class Algebra) (grade-points 12) (credits 3)))
<Fact-2>
CLIPS> (gpa)
4.0
CLIPS> (assert (check-gpa))
<Fact-3>
CLIPS> (run)
Keep up the excellent work!
CLIPS> (assert (grade (class History) (grade-points 6) (credits 2)))
<Fact-4>
CLIPS> (gpa)
3.6
CLIPS> (assert (check-gpa))
<Fact-5>
CLIPS> (run)
CLIPS> (assert (grade (class Science) (grade-points 12) (credits 3)))
<Fact-6>
CLIPS> (gpa)
3.75
CLIPS> (assert (check-gpa))
<Fact-7>
CLIPS> (run)
Keep up the excellent work!
CLIPS>
i am writing an expert system on cheese.
when reset all the facts about various cheese is loaded into the system and by asking question such as texture smell etc this will retract certain facts from the system.
My Question how do you keep track of the amount of rules in the system. I created a count but i was wondering if there was a way to see the amount of facts currently in the system when running a rule.
Any help would be appriciated
You can make a call to get-defrule-list or get-fact-list to determine the number of rules/facts present in the system:
CLIPS> (assert (a) (b) (c) (d))
<Fact-4>
CLIPS> (defrule x =>)
CLIPS> (defrule y =>)
CLIPS> (defrule z =>)
CLIPS> (length$ (get-defrule-list *))
3
CLIPS> (length$ (get-fact-list *))
5
CLIPS> (facts)
f-0 (initial-fact)
f-1 (a)
f-2 (b)
f-3 (c)
f-4 (d)
For a total of 5 facts.
CLIPS> (rules)
x
y
z
For a total of 3 defrules.
CLIPS>