1

I have two rules in CLIPS which I want to combine if they're both true...not sure how to do it though. I have an attribute which is called grant-eligible....I was thinking if I set it to TRUE then I could read the next rule, and then set the 'grant-eligible' to FALSE....but it seems that my code is getting into an infinite loop when I do this...

So here are my rules:

    (defrule complete "rule for app completeness"
  ?f <- (application (transcript-received Yes) (app-complete FALSE)
    (gpa
                ?v_gpa&:(
                    > ?v_gpa 0)))

  =>
  (modify ?f (app-complete TRUE)))


    (defrule denied "rule for admission - DENIED"
  ?f <- (application (app-complete TRUE) (app-decision FALSE)
    (gpa
                ?v_gpa&:(
                    < ?v_gpa 3.0))

    (ssat
                ?v_ssat&:(
                    >= ?v_ssat 0.0))



        )


  =>
  (modify ?f (app-decision DENIED))

  )

(defrule accepted "rule for admission - ACCEPTED"
  ?f <- (application (app-complete TRUE) (app-decision FALSE)
    (gpa
                ?v_gpa&:(
                    >= ?v_gpa 3.5))

    (ssat
                ?v_ssat&:(
                    >= ?v_ssat 1500))


        )

  =>
  (modify ?f (app-decision ACCEPTED))

  )

This is the ones I am trying to implement now

(defrule female-finaid "rule for finaid applications for female students"
  ?f <- (application (app-decision ACCEPTED) 
    (gender F) (grade-entry Freshman) (country USA)
    (grant-eligible TRUE)
    (grant ?v_grant)
    )

  =>
  (modify ?f
            (grant (+ ?v_grant 5000))
            (grant-eligible TRUE)
        )
    )

    (defrule great-students-finaid "rule for finaid applications for female students"
  ?f <- (application (app-decision ACCEPTED) 
    (country USA)
    (grant-eligible TRUE)
    (grant ?v_grant)
    (gpa
                ?v_gpa&:(
                    >= ?v_gpa 4.0))
    )

  =>
  (modify ?f
            (grant (+ ?v_grant 4500))
            (grant-eligible FALSE)
        )
    )

If both of these rules are true, the grant awarded should be 9500, or it could be 5000 or it could be 4500...Any ideas?

The solution: (where ff-grant-eligible and es-grant-eligible are my control facts...they stand for ff=female finaid, and es=excellent student)

    (defrule female-finaid "rule for finaid applications for female students"
  ?f <- (application (app-decision ACCEPTED) (ff-grant-eligible TRUE)
    (gender F) (grade-entry Freshman) (country USA)

    (grant ?v_grant)
    )

  =>
  (modify ?f
            (grant (+ ?v_grant 5000))
            (ff-grant-eligible FALSE)
        )
    )

    (defrule great-students-finaid "rule for finaid applications for female students"
  ?f <- (application (app-decision ACCEPTED) (es-grant-eligible TRUE)
    (country USA)

    (grant ?v_grant)
    (gpa
                ?v_gpa&:(
                    >= ?v_gpa 4.0))
    )

  =>
  (modify ?f
            (grant (+ ?v_grant 4500))
            (es-grant-eligible FALSE)
        )
    )
engr007
  • 51
  • 4
  • 12

1 Answers1

2

There are numerous ways you can control execution of your program (e.g., control facts, salience, modules). This answer will use control facts (with salience) for the stages of application processing. I am also going to assume that you have a unique id slot associated with each application.

Consider the following fact and rule:

(deffacts application-stages "ordered sequence of stages for an application"
  (stages app-received app-accept-reject app-evaluate-grants
          app-apply-grants app-complete))

(defrule go-to-next-stage "Advances to the next application stage"
  ?stage <- (app-stage ?id ?current-stage)
  (stages $? ?current-stage ?next-stage $?)
  =>
  (retract ?stage)
  (assert (app-stage ?id ?next-stage))
  (printout t "Application " ?id " moved from stage " ?current-stage
              " to " ?next-stage "." crlf))

The application-stages deffact defines the sequence of stages for an application and the go-to-next-stage rule advances the application stage. Since the rule has salience that is lower than the default (0), it will only be executed if there are no other rules corresponding to the current stage. So with no other rules in your program, you would get the following:

CLIPS> (reset)
CLIPS> (assert (app-stage app-001 app-received))
<Fact-2>
CLIPS> (run)
Application app-001 moved from stage app-received to app-accept-reject.
Application app-001 moved from stage app-accept-reject to app-evaluate-grants.
Application app-001 moved from stage app-evaluate-grants to app-apply-grants.
Application app-001 moved from stage app-apply-grants to app-complete.
CLIPS> 

But if you have any rules associated with a particular stage, they will be executed first. So you can add rules to the app-evaluate-grants stage like this:

(defrule female-finaid "rule for finaid applications for female students"
  (app-stage ?id app-evaluate-grants)
  (application (app-decision ACCEPTED) (id ?id)
    (gender F) (grade-entry Freshman) (country USA)
  =>
  (assert (grant ?id female 5000)))

And you would similarly add a great-student-finaid rule. Then, there is a single rule for the app-apply-grants stage:

(defrule apply-grant "Adds the amount of a grant to an application"
  (app-stage ?id app-apply-grants)
  ?grant <- (grant ?id ? ?amount)
  ?app <- (application (id ?id) (grant ?v_grant))
  =>
  (retract ?grant)
  (modify (?app (grant (+ ?v_grant ?amount))))

One of the benefits of modeling it this way is that you don't have to include control facts (e.g., grant-eligible) in the data for an application. That is, your control logic is separate from the data model. Note that you can achieve the same effect as what I've done here by using CLIPS modules (via defmodule) and that is often preferable but it would require a lengthier answer (and this one is already fairly long).

bogatron
  • 18,639
  • 6
  • 53
  • 47
  • Thanks @bogatron for your thorough response...I am a bit unclear. Been learning CLIPS for only the past few weeks. So I don't understand what this means `(assert (grant ?id female 5000)))`...also I don't have an `apply-grants stage`. I was using the `grant-eligible` attribute as a way to stop the rules from firing over and over, but obviously that wasn't working. – engr007 Apr 12 '13 at 16:50
  • The `(assert (grant ?id female 5000)))` is specifying a grant that will be applied to the application. I didn't realize you were using `grant-eligible` as a control fact. Take a look at my updated answer (which removes `grant-eligible`) and see if that makes sense. – bogatron Apr 12 '13 at 20:59
  • Thanks for your answer. I have edited my original question to provide the rules I already have for app-complete and app-decision. So given the fact that the student is ACCEPTED (after application is COMPLETE)...then I want to see if I can give them grants. – engr007 Apr 14 '13 at 13:18
  • I see the update but it wouldn't really change the answer I've provided. Again, I would avoid putting `grant-eligible` into the application because that is a control fact and not part of the application data. The solution I provided doesn't require it because the `app-stage` fact handles the sequential aspect of the process. – bogatron Apr 14 '13 at 19:54
  • Thank you! @bogatron, I read this like 50 times (literally), but I guess with my experience of CLIPS, it was not getting through to my head. lol. What I ended up doing was add 2 separate control facts, 1 for each of the rules...then at the end of the rule I set the fact to `FALSE` so it wouldn't get caught up in the infinite loop. ...Thanks so much for your help...I didn't even know I was using control facts, so your guidance helped a lot. – engr007 Apr 15 '13 at 17:26