After quite a long time dealing with Clips I met a surprising behavior (which I finally found in the Basic guide as probably being a feature) ;-)
let's have facts A and B and an action which should be performed IF A or B exist. Natural understanding is that the action should be performed if:
- A is present,
- B is present,
- both A and B are present
and it should be performed ONLY ONCE if at all.
However, CLIPS behavior in the case that BOTH A and B exist is that action is performed twice with identical facts:
(deffacts xxx
(SAD H "AE")
(SAD G "AE")
)
(defrule condition
(SAD H ?x)
(SAD G ?y)
(or (test (eq ?x "AE")) (test (eq ?y "AE")))
=>
(printout t "FIRED " crlf)
)
After the (reset) command, the "conditions" rule is activated twice with identical combinations of facts (and consequently twice fired).
My questions are:
1) is there any correct way to get the "natural" behavior?
2) If not, can it be achieved when executing the rule to scan the agenda (GetNextActivation) and find and delete (DeleteActivation) any other activations with identical list of partial matches as currently fired rule (further questions are:
3) how to determine list of partial matches of currently fired rule
4) how to compare it to agenda enties - is GetActivationPPForm enough)?
Thanks a lot for a hint
Vranoch
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Use a single test conditional function that calls the 'or' function rather than an 'or' conditional element with multiple test conditional elements. The 'or' conditional element works by splitting a single rule into multiple rules and typically you'd have at least one conditional element within it that matches a fact or instance. It's a syntactic shortcut that can be quite convenient, but in this case it's not what you want to do.
(defrule condition
(SAD H ?x)
(SAD G ?y)
(test (or (eq ?x "AE") (eq ?y "AE")))
=>
(printout t "FIRED " crlf)
)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks Gary, this works. However, what is a problem in nesting (test ) functions (e.g.
(test (and (test (< 1 5)) (test (>20 10))))
) ? It says that "test" function is not defined in this case.
I know that the nested (test ) is not necessary in this case but my CLIPS code is generated and it is not so easy to change the generator.
thanks Vranoch
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
test/exists/and/or/not are conditional elements (CEs) that have a specific purpose when used on the LHS of a rule. and/or/not also happen to be functions which can be used in certain places on the LHS of a rule as well as the RHS of a rule and in deffunctions, defmethods, defmessage-handlers, and other constructs. Within a test CE, you can place a function call including other nested function calls. The test and exists conditional elements are not functions so they can't be placed within the test CE. For the test CE you can get around this restriction by defining a deffunction called test, but there is no way to do this for the exists CE without rewriting the CLIPS parser to handle this syntax. In both examples you've listed, the rule would be syntactically correct if you just removed the outermost test CE. In both cases, the inner and/or function would then be interpreted as an and/or CE. Your other option is to generate valid syntax.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for explanation, but when I remove the outermost OR, I get to the initial situation (multiple firing of the rule). I can of course modify my generator, but I have to find out, what should be generated. Can You advice me, how to correctly (i.e. syntactically and semantically - firing only once) rewrite the following condition which I can't omit?
(defrule condition
(SAD H ?x)
(SAD G ?y)
(or (test (or (eq ?x "AE") (eq ?y "AE"))) (exists (SAD X ?ix ?val) (test (> ?val 5))))
=>
(printout t "FIRED " crlf)
)
I already tried many combinations but I did not succeed so far.
thanks a lot Vranoch
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello,
After quite a long time dealing with Clips I met a surprising behavior (which I finally found in the Basic guide as probably being a feature) ;-)
let's have facts A and B and an action which should be performed IF A or B exist. Natural understanding is that the action should be performed if:
- A is present,
- B is present,
- both A and B are present
and it should be performed ONLY ONCE if at all.
However, CLIPS behavior in the case that BOTH A and B exist is that action is performed twice with identical facts:
(deffacts xxx
(SAD H "AE")
(SAD G "AE")
)
(defrule condition
(SAD H ?x)
(SAD G ?y)
(or (test (eq ?x "AE")) (test (eq ?y "AE")))
=>
(printout t "FIRED " crlf)
)
(watch facts)
(watch activations)
(load k)
$*
TRUE
(reset)
<== f-0 (initial-fact)
==> f-0 (initial-fact)
==> f-1 (SAD H "AE")
==> f-2 (SAD G "AE")
==> Activation 0 condition: f-1,f-2
==> Activation 0 condition: f-1,f-2
(run)
FIRED
FIRED
After the (reset) command, the "conditions" rule is activated twice with identical combinations of facts (and consequently twice fired).
My questions are:
1) is there any correct way to get the "natural" behavior?
2) If not, can it be achieved when executing the rule to scan the agenda (GetNextActivation) and find and delete (DeleteActivation) any other activations with identical list of partial matches as currently fired rule (further questions are:
3) how to determine list of partial matches of currently fired rule
4) how to compare it to agenda enties - is GetActivationPPForm enough)?
Thanks a lot for a hint
Vranoch
Use a single test conditional function that calls the 'or' function rather than an 'or' conditional element with multiple test conditional elements. The 'or' conditional element works by splitting a single rule into multiple rules and typically you'd have at least one conditional element within it that matches a fact or instance. It's a syntactic shortcut that can be quite convenient, but in this case it's not what you want to do.
Thanks Gary, this works. However, what is a problem in nesting (test ) functions (e.g.
) ? It says that "test" function is not defined in this case.
I know that the nested (test ) is not necessary in this case but my CLIPS code is generated and it is not so easy to change the generator.
thanks Vranoch
Predefine a test deffunction that uses it's input argument as it's output value:
Yes, that helped, but only for a while. I sometimes have to combine standard CEs with quantifiers (exists ):
… again, it says
is there any way how to work this around? And what is the problem, that some standard functions are not visible within the (test ) function?
thanks Vranoch
test/exists/and/or/not are conditional elements (CEs) that have a specific purpose when used on the LHS of a rule. and/or/not also happen to be functions which can be used in certain places on the LHS of a rule as well as the RHS of a rule and in deffunctions, defmethods, defmessage-handlers, and other constructs. Within a test CE, you can place a function call including other nested function calls. The test and exists conditional elements are not functions so they can't be placed within the test CE. For the test CE you can get around this restriction by defining a deffunction called test, but there is no way to do this for the exists CE without rewriting the CLIPS parser to handle this syntax. In both examples you've listed, the rule would be syntactically correct if you just removed the outermost test CE. In both cases, the inner and/or function would then be interpreted as an and/or CE. Your other option is to generate valid syntax.
Thanks for explanation, but when I remove the outermost OR, I get to the initial situation (multiple firing of the rule). I can of course modify my generator, but I have to find out, what should be generated. Can You advice me, how to correctly (i.e. syntactically and semantically - firing only once) rewrite the following condition which I can't omit?
I already tried many combinations but I did not succeed so far.
thanks a lot Vranoch
(defrule condition
(SAI H ?x)
(SAD G ?y)
(or (and (not (and (SAD X ?ix ?val) (test (> ?val 5))))
(test (or (eq ?x "AE") (eq ?y "AE"))))
(exists (SAD X ?ix ?val) (test (> ?val 5))))
=>
(printout t "FIRED " crlf)
)
A little error :
(defrule condition
(SAD H ?x) ; not SAI !
(SAD G ?y)
(or (and (not (and (SAD X ?ix ?val) (test (> ?val 5))))
(test (or (eq ?x "AE") (eq ?y "AE"))))
(exists (SAD X ?ix ?val) (test (> ?val 5))))
=>
(printout t "FIRED " crlf)
)