clips rule incongruent matching with several conditional elements - clips

I have this rule:
(defrule tio-varon
(hermano-de (persona1 ?tio)(persona2 ?padremadre));
(or
(padre-de (padre ?padremade)(hijo ?hijo))
(madre-de (madre ?padremade)(hijo ?hijo))
)
(varon (persona ?tio))
(not (tio-de(tio ?tio)(sobrino ?hijo)))
=>
(assert (tio-de(tio ?tio)(sobrino ?hijo)))
)
This rule is matching with facts like these:
(hermano-de (persona1 <b>John</b>)(persona2 Maria))
(padre-de (padre <b>John</b>)(hijo Michael))
(varon John)
giving as result the fact
(tio-de (John)(Michael))
Why, if John and Maria are matching with ?tio and ?padremade respectively over the (hermano-de) fact, later it's John the value that acts like ?padremadre over the (padre-de) fact? I hoped it was the value Maria the matched value with the fact (madre-de) or
(padre-de)

Your variable names don't match. You use ?padremadre in the hermano-de fact, but ?padremade in the padre-de and padre-me facts. The second 'r' is missing.
When you load your code, you can see that there's an unexpected activation.
CLIPS (6.4 2/9/21)
CLIPS>
(deftemplate hermano-de
(slot persona1)
(slot persona2))
CLIPS>
(deftemplate padre-de
(slot padre)
(slot hijo))
CLIPS>
(deftemplate madre-de
(slot madre)
(slot hijo))
CLIPS>
(deftemplate varon
(slot persona))
CLIPS>
(deftemplate tio-de
(slot tio)
(slot sobrino))
CLIPS>
(deffacts initial
(hermano-de (persona1 John) (persona2 Maria))
(padre-de (padre John) (hijo Michael))
(varon (persona John)))
CLIPS>
(defrule tio-varon
(hermano-de (persona1 ?tio)(persona2 ?padremadre))
(or (padre-de (padre ?padremade)(hijo ?hijo))
(madre-de (madre ?padremade)(hijo ?hijo)))
(varon (persona ?tio))
(not (tio-de(tio ?tio)(sobrino ?hijo)))
=>
(assert (tio-de(tio ?tio)(sobrino ?hijo))))
CLIPS> (reset)
CLIPS> (agenda)
0 tio-varon: f-1,f-2,f-3,*
For a total of 1 activation.
CLIPS> (facts)
f-1 (hermano-de (persona1 John) (persona2 Maria))
f-2 (padre-de (padre John) (hijo Michael))
f-3 (varon (persona John))
For a total of 3 facts.
CLIPS>
For the padre-de disjunct of the rule, you can see from the matches command that f-1 and f-2 are successfully matching the first two patterns of the rule, which should not be happening. So excluding a bug in the CLIPS pattern matching algorithm, there must be something wrong in the first two patterns of the rule. The ?padremadre variable is the only variable shared by the first two patterns, so that's the one to examine since it should be preventing a match for the first two patterns.
CLIPS> (matches tio-varon)
Matches for Pattern 1
f-1
Matches for Pattern 2
f-2
Matches for Pattern 3
f-3
Matches for Pattern 4
None
Partial matches for CEs 1 - 2
f-1,f-2
Partial matches for CEs 1 - 3
f-1,f-2,f-3
Partial matches for CEs 1 - 4
f-1,f-2,f-3,*
Matches for Pattern 1
f-1
Matches for Pattern 2
None
Matches for Pattern 3
f-3
Matches for Pattern 4
None
Partial matches for CEs 1 - 2
None
Partial matches for CEs 1 - 3
None
Partial matches for CEs 1 - 4
None
Activations
f-1,f-2,f-3,*
(5 3 1)
CLIPS>

Related

CLIPS. How can I check if a list of facts matching facts already given?

I need to create a rule that will check if the list of facts I have entered matches the facts already given. Then the fact / facts corresponding to at least one of the entered ones are displayed.
this is what I have:
(deftemplate rule (multislot problem) (slot cause))
(deffacts info
(rule (problem one) (cause one1))
(rule (problem two) (cause two2))
(rule (problem three) (cause three3))
(defrule reading-input
=>
(printout t "Enter your problems: " )
(assert (problem (read))))
(defrule checking-input
(problem $?problem)
(rule (problem $?problem1) (cause ?cause1))
(test (eq ?problem ?problem1))
=>
(printout t "cause: " ?cause1 crlf))
how this should work:
CLIPS> Enter your problems: one two
CLIPS> cause: one1
cause: two2
Using the read function will retrieve just one value from your input. You need to use the readline function in conjunction with the explode$ function:
CLIPS (6.4 2/9/21)
CLIPS> (assert (problem (read)))
one two
<Fact-1>
CLIPS> (assert (problem (readline)))
one two
<Fact-2>
CLIPS> (assert (problem (explode$ (readline))))
one two
<Fact-3>
CLIPS> (facts)
f-1 (problem one)
f-2 (problem "one two")
f-3 (problem one two)
For a total of 3 facts.
CLIPS>
You can then use multifield wildcards to isolate individual problems within your rule:
CLIPS> (clear)
CLIPS>
(deftemplate rule
(multislot problem)
(slot cause))
CLIPS>
(deffacts info
(rule (problem one) (cause one1))
(rule (problem two four) (cause two2))
(rule (problem one three five) (cause three3)))
CLIPS>
(defrule reading-input
=>
(printout t "Enter your problems: " )
(assert (problem (explode$ (readline)))))
CLIPS>
(defrule checking-input
(problem $? ?problem $?)
(rule (problem $? ?problem $?) (cause ?cause))
=>
(printout t "Problem: " ?problem " cause: " ?cause crlf))
CLIPS> (reset)
CLIPS> (run)
Enter your problems: one two
Problem: one cause: three3
Problem: one cause: one1
Problem: two cause: two2
CLIPS>

How can I get the sum of items in a multislot

I have a template like the one shown bellow. How can I get the sum of items in the multislot grades?
(deftemplate student
(multislot name)
(multislot grades)
)
Here's one way to do it. In the reg6 rule, the + function is given two arguments of 0 in addition to the grades to insure that the + function allows has at least 2 arguments; otherwise, if there were zero or one grades for the student you'd get an error.
CLIPS (6.31 2/3/18)
CLIPS>
(deftemplate student
(multislot name)
(multislot grades))
CLIPS>
(deftemplate sum
(multislot name)
(slot grade))
CLIPS>
(defrule reg6
(student (name $?name)
(grades $?grades))
=>
(assert (sum (name ?name)
(grade (+ 0 0 (expand$ ?grades))))))
CLIPS>
(assert (student (name David Green) (grades))
(student (name Sue Brown) (grades 90))
(student (name Frank Black) (grades 85 75)))
<Fact-3>
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (student (name David Green) (grades))
f-2 (student (name Sue Brown) (grades 90))
f-3 (student (name Frank Black) (grades 85 75))
f-4 (sum (name Frank Black) (grade 160))
f-5 (sum (name Sue Brown) (grade 90))
f-6 (sum (name David Green) (grade 0))
For a total of 7 facts.
CLIPS>
You can use the expand$ function. Check in the Basic Programming Guide the Multifield Expansion Function chapter to know more.
(deftemplate student
(multislot name)
(multislot grades))
(defrule grades-sum
(student (grades $?grades))
=>
(printout t "Student grades sum is " (+ (expand$ ?grades))))
(assert (student (grades (create$ 1 2 3 4 5))))
(student (name) (grades 1 2 3 4 5))
(run)
Student grades sum is 15

Check multiple facts in CLIPS

Let's say I have some facts (I do not know how many there are) like this: lamp x is off. With a defrule I proggressively turn all lamps on so every fact will be: lamp x is on. How do I check every lamp that is on. I know that if there were three lamps I could write:
(defrule checkAllLamps
(lamp 1 is on)
(lamp 2 is on)
(lamp 3 is on)
=>
(printout t "All lamps are on now")
)
But for x lamps?
Thank you!
You can use fact-set query functions for that (chapter 12.9.12 of the Basic Programming Guide).
(deftemplate lamp
(slot id (type INTEGER))
(slot state (type SYMBOL)))
(defrule all-lamps-are-on
(lamp (state on))
(test (>= (length$ (find-all-facts ((?l lamp)) (eq ?l:state on))) 3))
=>
(printout t "All lamps are on" crlf))
Here's how you can check whether all of the lamps are on. The checkAllLamps rule treats the case where there are no lamps at all as all lamps being on, whereas the checkAllLampsAtLeastOne rule requires that there is at least one lamp that is on.
CLIPS (6.31 2/3/18)
CLIPS>
(defrule checkAllLamps
(not (lamp ? is off))
=>
(printout t "All lamps are on now" crlf))
CLIPS>
(defrule checkAllLampsAtLeastOne
(exists (lamp ? is on))
(not (lamp ? is off))
=>
(printout t "All lamps are on now" crlf))
CLIPS> (agenda)
0 checkAllLamps: *
For a total of 1 activation.
CLIPS> (assert (lamp 1 is on))
<Fact-1>
CLIPS> (agenda)
0 checkAllLampsAtLeastOne: *,*
0 checkAllLamps: *
For a total of 2 activations.
CLIPS> (assert (lamp 2 is off))
<Fact-2>
CLIPS> (agenda)
CLIPS> (retract 2)
CLIPS> (assert (lamp 2 is on))
<Fact-3>
CLIPS> (agenda)
0 checkAllLampsAtLeastOne: *,*
0 checkAllLamps: *
For a total of 2 activations.
CLIPS>

Is it possible to set allowed-integers in a slot with a variable?

I want to constrain my allowed integers in a slot with a multifieldvariable.
So instead of:
CLIPS> (deftemplate foo (slot constr-integers (allowed-integers 1 3 4 7)))
I wanted do do something like this:
CLIPS> (bind ?multifieldvariable (create$ 1 3 4 7))
(1 3 4 7)
CLIPS> (deftemplate bar (slot constr-integers (allowed-integers ?multifieldvariable)))
[PRNTUTIL2] Syntax Error: Check appropriate syntax for allowed-integers attribute.
ERROR:
(deftemplate MAIN::bar
(slot constr-integers (allowed-integers ?multifieldvariable
I know how to work around this issue, but maybe there is a way to do it in a more elegant way.
Best regards,
Sebastian
You can only do it by dynamically creating the deftemplate with a build function call:
CLIPS> (bind ?multifieldvariable (create$ 1 3 4 7))
(1 3 4 7)
CLIPS>
(build (str-cat "(deftemplate bar (slot constr-integers (allowed-integers "
(implode$ ?multifieldvariable)
")))"))
TRUE
CLIPS> (ppdeftemplate bar)
(deftemplate MAIN::bar
(slot constr-integers (allowed-integers 1 3 4 7)))
CLIPS>

How to printout all matches facts in a rule

I have a rule like below and I want to print all facts(here objct) that are compatible to this rule. I have a fact objct and there are some of these "objct"s that follow the rule. how I can do it? The printout below just prints the latest objct that player got. However I want to printout all of them. Any idea?
(defrule have_objcts
?input <- (input have|possession)
(objct (name ?n) (location player) (used 0))
=>
;WHAT SHOULD I WRITE HERE TO PRINTOUT those OBJCT's BELONG TO
PALYER???????????
(printout t crlf ?n)
(retract ?input))
Use the matches command:
CLIPS>
(deftemplate objct
(slot name)
(slot location)
(slot used))
CLIPS>
(deffacts initial
(objct (name x) (location player) (used 0))
(objct (name y) (location elsewhere) (used 1))
(objct (name z) (location player) (used 0))
(input have)
(input want)
(input possession)
(input thing))
CLIPS>
(defrule have_objcts
?input <- (input have|possession)
(objct (name ?n) (location player) (used 0))
=>
(retract ?input))
CLIPS> (reset)
CLIPS> (matches have_objcts)
Matches for Pattern 1
f-4
f-6
Matches for Pattern 2
f-1
f-3
Partial matches for CEs 1 - 2
f-6,f-3
f-6,f-1
f-4,f-3
f-4,f-1
Activations
f-6,f-3
f-6,f-1
f-4,f-3
f-4,f-1
(4 4 4)
CLIPS> (run)
CLIPS> (matches have_objcts)
Matches for Pattern 1
None
Matches for Pattern 2
f-1
f-3
Partial matches for CEs 1 - 2
None
Activations
None
(2 0 0)
CLIPS>

Resources