Reputation: 25
I wanted to add and print the total quantity of three Products from facts. Also i need to perform a check too, on product 1 if the quantity is greater than 1.
(defrule sum_of_quantity
(or
(Product (productNumber 1)(quantity ?quantity0))
(Product (productNumber 2)(quantity ?quantity1))
(Product (productNumber 3)(quantity ?quantity2)))
=>
(bind ?totalQuantity (integer(+ ?quantity0 ?quantity1 ?quantity2)))
(printout t "TotalQuantity is " ?totalQuantity crlf))
I am actually new to clips and is finding it difficult to write rules
Upvotes: 0
Views: 896
Reputation: 10757
The or conditional element works by creating multiple rules, one for each permutation of all possible combinations of the conditional elements found within the or conditional elements in the conditions of the rule. Each of the generated rules use the same actions as the original rule. Thus your sum_of_quantity rule is translated to the following three rules (which share the same name):
(defrule sum_of_quantity
(Product (productNumber 1)(quantity ?quantity0))
=>
(bind ?totalQuantity (integer(+ ?quantity0 ?quantity1 ?quantity2)))
(printout t "TotalQuantity is " ?totalQuantity crlf))
(defrule sum_of_quantity
(Product (productNumber 2)(quantity ?quantity1))
=>
(bind ?totalQuantity (integer(+ ?quantity0 ?quantity1 ?quantity2)))
(printout t "TotalQuantity is " ?totalQuantity crlf))
(defrule sum_of_quantity
(Product (productNumber 3)(quantity ?quantity2)))
=>
(bind ?totalQuantity (integer(+ ?quantity0 ?quantity1 ?quantity2)))
(printout t "TotalQuantity is " ?totalQuantity crlf))
Looking at the generated rules you can see that there are variables in the actions of the rules that are not bound in the conditions of the rules. So when using the or conditional element, any variables referenced in the actions of the rule must be bound in each permutation.
Some rule-based language provide a "collect" conditional element that allows to easily compute summations in the conditions of a rule, but unfortunately CLIPS does not provide this functionality. You can however use the do-for-all-facts query function to iterate over a group of facts in the actions of a rule:
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate Product
(slot productNumber)
(slot quantity))
CLIPS>
(defrule sum_of_quantity
(exists (Product (productNumber 1 | 2 | 3)))
=>
(bind ?totalQuantity 0)
(do-for-all-facts ((?p Product))
(or (eq ?p:productNumber 1)
(eq ?p:productNumber 2)
(eq ?p:productNumber 3))
(bind ?totalQuantity (+ ?totalQuantity ?p:quantity)))
(printout t "TotalQuantity is " ?totalQuantity crlf))
CLIPS>
(assert (Product (productNumber 1) (quantity 10))
(Product (productNumber 2) (quantity 20))
(Product (productNumber 3) (quantity 30))
(Product (productNumber 4) (quantity 40)))
<Fact-4>
CLIPS> (run)
TotalQuantity is 60
CLIPS>
In this example, the exists conditional element is used in the conditions of the rule so that there is only one activation regardless of how many Product facts exists. This rule will activate if there is any Product fact with a productNumber of 1, 2, or 3. If you wanted all productNumbers to be required, you'd write the patterns like this:
(exists (Product (productNumber 1))
(Product (productNumber 2))
(Product (productNumber 3)))
The actions of the rule use the do-for-all-facts function to iterate over each Product fact and add the quantity slot to a running total.
Upvotes: 1
Reputation: 15060
The sum_of_quantity
rule is expressing the need of at least one product between products 1, 2, 3. Nevertheless, it's trying to sum the quantity of all three of them. This is logically incorrect.
This is what the engine is trying to tell you. The Right Hand Side (RHS) is referring to a variable (quantity1
) which might not be defined once you run the rule. This is because your rule will activate even if just productNumber 1
is asserted in.
Simply remove the or
condition in your rule and it will work. To see the rule activating, just assert all the missing products with quantity 0
.
Upvotes: 0