问题
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)
)
)
回答1:
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).
来源:https://stackoverflow.com/questions/15963202/how-to-combine-these-two-rules-with-clips