CLIPS Error: Illegal use of the module specifier when defrule - rules

I want to define some module-rules to assert module-facts, and then batch get a group of facts list by get-fact-list, but an error occurred!
CLIPS (6.31 6/12/19)
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (M::T (k1 "v1"))))
[MODULDEF1] Illegal use of the module specifier.
ERROR:
(defrule M::T
(testvalue 1)
=>
(assert (M::T
CLIPS>
expected:
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (M::T (k1 "v1"))))
CLIPS> (assert (testvalue 1))
CLIPS> (get-fact-list M)
;; return the facts that M::rulexx assert
Why is the sytax error? How can I do it for the defrule of module?

Don't use M::T in your assert command. Since the defrule is contained in module M, all deftemplates visible to M can be referenced without using a module specifier.
CLIPS (6.31 6/12/19)
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (T (k1 "v1"))))
CLIPS> (assert (testvalue 1))
<Fact-1>
CLIPS> (get-fact-list M)
(<Fact-1>)
CLIPS>

Related

asserting string in clips

I am trying to assert the value of name into a variable but when i assert it the value is coming in quotes and also with an extra space at the end.
(defrule discount_amt_group
(exists (Student (age 14)(marks ?q&:(> ?q 40))))
=>
(bind ?name "")
(do-for-all-facts ((?p Student))
(or (eq ?p:marks 80)
(eq ?p:marks 75)
(eq ?p:marks 90))
(bind ?name (str-cat ?name ?p:name " "))
(bind ?totalMarks (+ ?totalMarks ?p:marks)))
(assert (StudOut(names ?name)))
the expected value will be (name Harry Ron Ginger) but now its coming as (name "Harry Ron Ginger ")
please suggest.
Represent the names as a multifield value rather than a string. You can use the create$ function to initially create an empty multifield value and then again to append values to it.
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate Student
(slot name)
(slot age)
(slot marks))
CLIPS>
(deftemplate StudOut
(multislot names)
(slot totalMarks))
CLIPS>
(deffacts Students
(Student (name Harry) (age 14) (marks 80))
(Student (name Ron) (age 15) (marks 75))
(Student (name Ginger) (age 14) (marks 90))
(Student (name Sally) (age 12) (marks 95)))
CLIPS>
(defrule discount_amt_group
(exists (Student (age 14)(marks ?q&:(> ?q 40))))
=>
(bind ?name (create$))
(bind ?totalMarks 0)
(do-for-all-facts ((?p Student))
(or (eq ?p:marks 80)
(eq ?p:marks 75)
(eq ?p:marks 90))
(bind ?name (create$ ?name ?p:name))
(bind ?totalMarks (+ ?totalMarks ?p:marks)))
(assert (StudOut (names ?name)
(totalMarks ?totalMarks))))
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (Student (name Harry) (age 14) (marks 80))
f-2 (Student (name Ron) (age 15) (marks 75))
f-3 (Student (name Ginger) (age 14) (marks 90))
f-4 (Student (name Sally) (age 12) (marks 95))
f-5 (StudOut (names Harry Ron Ginger) (totalMarks 245))
For a total of 6 facts.
CLIPS>

storing values in clips into variable

I am having a template of
(deftemplate Product
(slot productId (type INTEGER))
(slot uom (default EA))
(slot quantity (type INTEGER))
(slot amount))
I'm using the code for
(defrule sum_of_quantity
(exists (Product (productId 1 | 2 | 3)(amount ?amount)))
=>
(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)))
(if (>= ?amount 5000) then
(printout t "TotalQuantity is " ?totalQuantity crlf)))
Here i am getting an error saying that:
Undefined variable amount referenced in RHS of defrule.
I have to check if the amount of each product is greater than 5000. How do we do that.
A simple fact pattern that can be matched by several different facts can cause multiple activations of a rule:
CLIPS>
(deftemplate product
(slot id)
(slot amount))
CLIPS>
(deffacts products
(product (id 1) (amount 1000))
(product (id 2) (amount 3000))
(product (id 3) (amount 6000)))
CLIPS>
(defrule print-amount
(product (id ?id) (amount ?amount))
=>
(printout t ?id ": " ?amount crlf))
CLIPS> (reset)
CLIPS> (agenda)
0 print-amount: f-3
0 print-amount: f-2
0 print-amount: f-1
For a total of 3 activations.
CLIPS> (run)
3: 6000
2: 3000
1: 1000
CLIPS>
When each activation is allowed to executed, the variable amount is retrieved from the product fact associated with activation. So there are three rule firings where amount is 6000, 3000, and 1000 respectively.
An exists conditional element is matched just once regardless of the number of time the fact patterns it contains are matched:
CLIPS>
(defrule exists
(exists (product (id ?id) (amount ?amount)))
=>)
CLIPS> (agenda)
0 exists: *
For a total of 1 activation.
CLIPS>
When the agenda is listed, an * is displayed indicating that the pattern is matched, but not by a specific fact. If you tried accessing the variable amount in the actions of the rule, you'd get an error. This is because the variable amount has no meaning outside of the pattern because it has no specific value. You'd get unpredictable behavior if one of the facts matching the fact pattern was arbitrarily chosen to provide the value for amount.
The simplest way to rewrite your rule is to move the amount check from the actions of the rule to the exists pattern:
(defrule sum_of_quantity
(exists (Product (productId 1 | 2 | 3)
(amount ?amount&:(>= ?amount 5000))))
=>
(bind ?totalQuantity 0)
(do-for-all-facts ((?p Product))
(or (eq ?p:productId 1)
(eq ?p:productId 2)
(eq ?p:productId 3))
(bind ?totalQuantity (+ ?totalQuantity ?p:quantity)))
(printout t "TotalQuantity is " ?totalQuantity crlf))
Your do-for-all-facts query was also referencing productNumber rather than productId.

Recursive call to a rule

I have this rule that fires thousands of other same rule:
(defrule calculate-temperature
?zone <- (object (is-a ZONE) (id ?id-zone) (dew-temperature ?dew-temperature) (delta-R ?delta-R))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
What I want to do is to modify my zone's supply-temperature when I can calculate it, i.e. when inside zone are defined delta-R and dew-temperature.
But the modification of the object keeps on firing in a recursice neverendless cycle.
What are best practices to avoid these annoying loops, please?
Thank you
Nicola
By itself this rule doesn't loop:
CLIPS> (clear)
CLIPS>
(defclass ZONE
(is-a USER)
(slot id)
(slot dew-temperature)
(slot supply-temperature)
(slot delta-R))
CLIPS>
(definstances start-instances
(z1 of ZONE (id 1) (dew-temperature 100) (delta-R 10)))
CLIPS>
(deftemplate process-action
(slot is))
CLIPS>
(deffacts start-facts
(process-action (is cooling)))
CLIPS> (defglobal ?*debug-print* = nil)
CLIPS>
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(dew-temperature ?dew-temperature)
(delta-R ?delta-R))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
CLIPS> (watch slots)
CLIPS> (reset)
::= local slot id in instance z1 <- 1
::= local slot dew-temperature in instance z1 <- 100
::= local slot delta-R in instance z1 <- 10
::= local slot supply-temperature in instance z1 <- nil
CLIPS> (run)
::= local slot supply-temperature in instance z1 <- 110
CLIPS>
So it's the interactions between your rules that are causing the loop.
There are three general techniques to prevent rule looping. First, you can remove one of the facts/instances matching the conditions of the rule. For example, the process-action fact:
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(dew-temperature ?dew-temperature)
(delta-R ?delta-R))
?p <- (process-action (is cooling))
=>
(retract ?p)
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
Second, you can modify a fact/instance slot value to prevent a pattern from matching. For example, delta-R:
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(dew-temperature ?dew-temperature)
(delta-R ?delta-R&~0))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature) (delta-R 0))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
Third (and this is only applicable for object pattern matching), rules are only triggered by changes to slots that are explicitly matched in the conditions of the rules. So if you want changes to delta-R to trigger the rule, but not changes to dew-temperature, you'd write the rule like this:
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(delta-R ?delta-R))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R (send ?zone get-dew-temperature)))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))

Get facts and print parameters in CLIPS

I would like to print all the datas of the facts with a rule. Here are the facts :
(deffacts datas
(pile name 1 blocks A B C A B)
(pile name 2 blocks B A)
(pile name 3 blocks A B)
(pile name 4 blocks A))
And here are the printing I want to see :
pile 1 : A B C A B
pile 2 : B A
pile 3 : A B
pile 4 : A
Does somebody has an idea how to do it ?
Thank you for your help !
If the order in which the piles are printed doesn't matter, you can do it this way:
CLIPS> (clear)
CLIPS>
(deffacts datas
(pile name 1 blocks A B C A B)
(pile name 2 blocks B A)
(pile name 3 blocks A B)
(pile name 4 blocks A))
CLIPS>
(defrule print
(pile name ?name blocks $?blocks)
=>
(printout t pile " " ?name " : " (implode$ ?blocks) crlf))
CLIPS> (reset)
CLIPS> (run)
pile 4 : A
pile 3 : A B
pile 2 : B A
pile 1 : A B C A B
CLIPS> (clear)
CLIPS>
(deftemplate pile
(slot name)
(multislot blocks))
CLIPS>
(deffacts datas
(pile (name 1) (blocks A B C A B))
(pile (name 2) (blocks B A))
(pile (name 3) (blocks A B))
(pile (name 4) (blocks A)))
CLIPS>
(defrule print
(pile (name ?name) (blocks $?blocks))
=>
(printout t pile " " ?name " : " (implode$ ?blocks) crlf))
CLIPS> (reset)
CLIPS> (run)
pile 4 : A
pile 3 : A B
pile 2 : B A
pile 1 : A B C A B
CLIPS>
If the order is important, you can do it using facts in the following manners, but this is either destructive in the first case or requires cleanup in the second case:
CLIPS> (clear)
CLIPS>
(deftemplate pile
(slot name)
(multislot blocks))
CLIPS>
(deffacts datas
(pile (name 1) (blocks A B C A B))
(pile (name 2) (blocks B A))
(pile (name 3) (blocks A B))
(pile (name 4) (blocks A)))
CLIPS>
(defrule print
?pile <- (pile (name ?name) (blocks $?blocks))
(not (pile (name ?name2&:(< ?name2 ?name))))
=>
(retract ?pile)
(printout t pile " " ?name " : " (implode$ ?blocks) crlf))
CLIPS> (reset)
CLIPS> (run)
pile 1 : A B C A B
pile 2 : B A
pile 3 : A B
pile 4 : A
CLIPS> (facts)
f-0 (initial-fact)
For a total of 1 fact.
CLIPS> (clear)
CLIPS>
(deftemplate pile
(slot name)
(multislot blocks))
CLIPS>
(deffacts datas
(pile (name 1) (blocks A B C A B))
(pile (name 2) (blocks B A))
(pile (name 3) (blocks A B))
(pile (name 4) (blocks A)))
CLIPS>
(defrule print
(pile (name ?name) (blocks $?blocks))
(not (and (pile (name ?name2&:(< ?name2 ?name)))
(not (pile-printed ?name2))))
=>
(assert (pile-printed ?name))
(printout t pile " " ?name " : " (implode$ ?blocks) crlf))
CLIPS> (reset)
CLIPS> (run)
pile 1 : A B C A B
pile 2 : B A
pile 3 : A B
pile 4 : A
CLIPS> (facts)
f-0 (initial-fact)
f-1 (pile (name 1) (blocks A B C A B))
f-2 (pile (name 2) (blocks B A))
f-3 (pile (name 3) (blocks A B))
f-4 (pile (name 4) (blocks A))
f-5 (pile-printed 1)
f-6 (pile-printed 2)
f-7 (pile-printed 3)
f-8 (pile-printed 4)
For a total of 9 facts.
CLIPS>
Finally, you can use the fact query functions to retrieve all the piles facts and then sort them to get the desired order:
CLIPS> (clear)
CLIPS>
(deffunction pile-sort (?f1 ?f2)
(> (fact-slot-value ?f1 name)
(fact-slot-value ?f2 name)))
CLIPS>
(deftemplate pile
(slot name)
(multislot blocks))
CLIPS>
(deffacts datas
(pile (name 1) (blocks A B C A B))
(pile (name 2) (blocks B A))
(pile (name 3) (blocks A B))
(pile (name 4) (blocks A)))
CLIPS>
(defrule print
=>
(bind ?facts (find-all-facts ((?f pile)) TRUE))
(bind ?facts (sort pile-sort ?facts))
(progn$ (?f ?facts)
(printout t pile " " (fact-slot-value ?f name) " : "
(implode$ (fact-slot-value ?f blocks)) crlf)))
CLIPS> (reset)
CLIPS> (run)
pile 1 : A B C A B
pile 2 : B A
pile 3 : A B
pile 4 : A
CLIPS>

CLIPS: asserting facts from within a function does not respect template constraints

I have a single-slot deftemplate definition with a constraint on the allowed symbols. If I directly assert a fact from the top level, the constraints work as expected (i.e. I can only use one of the allowed symbols). However, if I do it from within a deffunction, the constraint is effectively non-existent (see code output below). How do I enforce the constraint from within my function?
CLIPS> (clear)
CLIPS> (deftemplate test-template (slot myslot (type SYMBOL) (allowed-symbols A B C)))
CLIPS> (deffunction test-function (?s) (assert (test-template (myslot ?s))))
CLIPS> (assert (test-template (myslot X)))
[CSTRNCHK1] A literal slot value found in the assert command
does not match the allowed values for slot myslot.
CLIPS> (test-function X)
<Fact-1>
CLIPS> (facts)
f-0 (initial-fact)
f-1 (test-template (myslot X))
For a total of 2 facts.
CLIPS>
Static constraint checking (which occurs during parsing) is enabled by default. Dynamic constraint checking (which occurs during code execution) is not (see section 11 of the Basic Programming Guide). If you enable it you'll get a constraint violation in your example (although you need to assert a fact with a slot value other than X--duplicate facts are not allowed and during execution this check will occur before the constraint check).
CLIPS> (clear)
CLIPS> (deftemplate test-template (slot myslot (type SYMBOL) (allowed-symbols A B C)))
CLIPS> (deffunction test-function (?s) (assert (test-template (myslot ?s))))
CLIPS> (assert (test-template (myslot X)))
[CSTRNCHK1] A literal slot value found in the assert command
does not match the allowed values for slot myslot.
CLIPS> (test-function Y)
<Fact-1>
CLIPS> (set-dynamic-constraint-checking TRUE)
FALSE
CLIPS> (test-function Z)
[CSTRNCHK1] Slot value Z found in fact f-2
does not match the allowed values for slot myslot.
[PRCCODE4] Execution halted during the actions of deffunction test-function.
<Fact-2>
CLIPS>

Resources