0

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.

yha
  • 13
  • 2

1 Answers1

1

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>
Gary Riley
  • 10,130
  • 2
  • 19
  • 34
  • Thanks, but how do I accumulate stuff into these facts? I don't want to manually retract and re-assert the grade-points and number-of-credits facts. I have a function "take" that takes a class code and a grade and asserts a "grade" record (it also retracts any previously recorded grade for this class code). I'm having a difficult time resetting grade-points and number-of-credits to 0 ONCE and then using a defrule to accumulate grade-points and number-of-credits based on my "grade" records. How can I use "?fact <- (grade-points ?gp)" inside a deffunction? – yha May 04 '15 at 12:13
  • Or, in other words, how do I sum all of the grade points and numbers of credits in my "grade" records and have that reflected in my grade-points and number-of-credits facts at all times? – yha May 04 '15 at 13:37
  • Updated the answer to include a different approach. – Gary Riley May 04 '15 at 19:32