Find facts using multiple values - clips

(defglobal ?*myGlobal* = 0)
(deftemplate myTemp
(slot one)
(slot second)
(slot third)
(slot fourth)
)
(find-fact ((?p myTemp)) (eq ?p:one aValue))
I want to match a fact based on multiple values; the code above matches facts using only one value.

You can just use boolean clauses:
(assert (myTemp (one asd) (second jhg))
(myTemp (one asd) (second kjh))
(myTemp (one bvc) (second jhg))
(myTemp (one bvc) (second jhg) (third qwe)))
(find-fact ((?p myTemp)) (or (eq ?p:one bvc) (eq ?p:third qwe))
(<Fact-4>)
(find-fact ((?p myTemp)) (or (eq ?p:one bvc) (eq ?p:second jhg))
(<Fact-1>)
(find-all-fact ((?p myTemp)) (or (eq ?p:one bvc) (eq ?p:second jhg))
(<Fact-1> <Fact-3> <Fact-4>)

Related

How to stop rule repeating activation on facts that have already been modified?

I have a rule I have made in CLIPS that deletes two values from a multislot field. Even though it does this, the rule repeats itself on the same facts that have now deleted the two values and this goes on infinitely.
Below are my fact templates and the rule
(deftemplate ar-node
(slot group
(type SYMBOL)
(allowed-symbols grp1 grp2 grp3 grp4) )
(slot name
(type SYMBOL)
(allowed-symbols oc nps ef sef yn))
(slot direction
(type SYMBOL)
(allowed-symbols + -))
(slot element
(type INTEGER)
(range 1 3))
(slot trip
(type INTEGER)
(range 1 4))
(multislot allowed-values
(type SYMBOL)
(allowed-symbols D R L A C S nil)
(default D))
(slot value
(type SYMBOL)
(allowed-symbols D R L A C S nil)
(default D)))
(defrule 22_061
(ar-node (group ?group)
(name ?name)
(direction ?direction)
(element ?element)
(trip ?trip)
(value ?value&R))
=>
(do-for-all-facts ((?fact ar-node)) (and (eq ?fact:group ?group)
(eq ?fact:name ?name)
(eq ?fact:direction ?direction)
(eq ?fact:element 1)
(> ?fact:trip 1))
(modify ?fact (allowed-values (delete-member$ ?fact:allowed-values C S))))
)
Here is also some example facts that will cause the rule to execute (the rule would only delete the C and S from the second fact here)
(ar-node (group grp1) (name cool) (direction +) (element 1) (trip 1) (allowed-values L D R A C S) (value R))
(ar-node (group grp1) (name cool) (direction +) (element 1) (trip 2) (allowed-values L D R A C S) (value L))
I have tried using more parameters to only delete values if the values are present such as (eq $member ?fact:allowed-values C S) in the RHS (and) statement or even to the LHS of the rule. However these either doesn't work or the rule won't execute at all.
I think the solution will be some way to check that the fact has C or S in the multifield on the LHS but I don't know how I could search all the facts before hand like I do on the RHS. Also I would prefer not to have to edit the fact template too though if its necessary to store something that.
Any advice or suggestions are welcome and I am new to CLIPS so sorry if this may be trivial but I'm super stumped even after using a bunch of functions from the documentation.
You can modify the query in the RHS to check for the presence of C or S:
(defrule 22_061
(ar-node (group ?group)
(name ?name)
(direction ?direction)
(value R))
=>
(do-for-all-facts ((?fact ar-node)) (and (eq ?fact:group ?group)
(eq ?fact:name ?name)
(eq ?fact:direction ?direction)
(eq ?fact:element 1)
(> ?fact:trip 1)
(or (member$ C ?fact:allowed-values)
(member$ S ?fact:allowed-values)))
(modify ?fact (allowed-values (delete-member$ ?fact:allowed-values C S))))
)
Or you can use pattern matching in the LHS and allow the rule to fire multiple times to modify all the facts:
(defrule 22_061
(ar-node (group ?group)
(name ?name)
(direction ?direction)
(value R))
?fact <- (ar-node (group ?group)
(name ?name)
(direction ?direction)
(element 1)
(trip ?trip&:(> ?trip 1))
(allowed-values $?b C | S $?e))
=>
(modify ?fact (allowed-values (delete-member$ (create$ ?b ?e) C S))))

How to retrieve a handle to facts inside a deffacts construct?

As described by the question, I would somehow try to get an handle to a fact within a deffacts construct. The problem arises because I don't want to redefine the same thing several times in WM (since set-fact-duplication is true) and because I use a structured deftemplate in which a field is a FACT_ADDRESS.
You can't bind a fact address within a deffacts construct. What I would suggest instead is to use a symbolic link between the facts. In your case, if the name of the tourism-type, tourism-resort, and hotel facts is unique among facts of each type, you could use that slot as the symbolic link:
(deftemplate tourism-type
(slot name)
(slot score))
(deftemplate hotel
(slot name)
(slot tr)
(slot stars)
(slot price-per-night))
(deftemplate tourism-resort
(slot name)
(slot region)
(multislot type))
(deffacts the-tourism-type-list
(tourism-type (name culturale) (score 3))
(tourism-type (name enogastronomico) (score 4)))
(deffacts the-tourism-resort-list
(tourism-resort
(name Venezia)
(region Veneto)
(type culturale enogastronomico)))
(deffacts the-hotels-list
(hotel
(name hotel1)
(tr Venezia)
(stars 3)
(price-per-night 100)))
In your rules, you can then use the symbolic link to retrieve the linked fact:
(defrule food-and-wine-hotels
(hotel (name ?hotel)
(tr ?tr-name))
(tourism-resort
(name ?tr-name)
(type $? enogastronomico $?))
=>
(printout t ?hotel crlf))

How to retrive facts asserted by a rule having particular name?

I have certain template defined as follows:
(deftemplate action
(slot name)
(slot field)
(slot value))
I have other rules which will use other facts to assert the action fact.
Now I want to retrieve only the fact with template action.
For now, I am using find-fact to retrieve, but here I have to use query which I do not want to provide.
(find-fact ((?fact action)) (= (str-compare ?fact:name 'Action1') 0))
I want all facts with template action and do not want to write a loop over all names with Action1, Action2 etc..
Thank you in advance.
CLIPS (6.31 4/1/19)
CLIPS>
(deftemplate action
(slot name)
(slot field)
(slot value))
CLIPS>
(deffacts actions
(action (name Action1) (field x) (value 3))
(action (name Action2) (field y) (value 4))
(action (name Action3) (field z) (value 5)))
CLIPS>
(defrule find-Action1
(action (name Action1))
=>)
CLIPS> (reset)
CLIPS> (agenda)
0 find-Action1: f-1
For a total of 1 activation.
CLIPS> (facts)
f-0 (initial-fact)
f-1 (action (name Action1) (field x) (value 3))
f-2 (action (name Action2) (field y) (value 4))
f-3 (action (name Action3) (field z) (value 5))
For a total of 4 facts.
CLIPS>

CLIPS: difference between two lists of facts

If I have a bunch of facts like (example (fact 1)), (example (fact 2)), (example (fact 3)), and have another list of facts like (myfact (number 2)), how can I perform a printout on each item in the first list that is not in the second (based on the number in the fact/number slots)? I suspect I need do-for-all-facts, but I'm not sure exactly how. Here's my incomplete code:
(deffunction difference ()
(do-for-all-facts ((?f1 example)) TRUE
(find-all-facts ((?f2 myfact)) (eq 1 1))
(if (somehow check if ?f1:fact does not equal ANY of number slots in ?f2) then
(printout t "..." crlf))))
CLIPS> (clear)
CLIPS> (deftemplate example (slot fact))
CLIPS> (deftemplate myfact (slot number))
CLIPS>
(deffacts start
(example (fact 1))
(example (fact 2))
(example (fact 3))
(myfact (number 2))
(myfact (number 4)))
CLIPS>
(deffunction difference ()
(do-for-all-facts ((?f1 example))
(not (any-factp ((?f2 myfact)) (eq ?f1:fact ?f2:number)))
(printout t "difference " ?f1:fact crlf)))
CLIPS> (reset)
CLIPS> (difference)
difference 1
difference 3
CLIPS>
(defrule difference
(example (fact ?n))
(not (myfact (number ?n)))
=>
(printout t "difference " ?n crlf))
CLIPS> (run)
difference 3
difference 1
CLIPS>

Finding facts of a template which has something in common with another template

I am using CLIPS for a project.
I am using this template A which has an attribute model and another template B which has an attribute model as well.
So what I want to achieve is based on the attribute model, return those facts of template A which has the same attribute model value as of facts from template B.
I tried using this format
(find-all-facts((?a template_A)(?b template_B))
(and
//condition to be met
)
)
it does give me the results, but it is giving me both the results for A and B which are duplicates.. How do I make it in a way it returns non duplicate values, either A or B?
CLIPS>
(deftemplate template_A
(slot model))
CLIPS>
(deftemplate template_B
(slot model))
CLIPS>
(deffacts start
(template_A (model 1))
(template_A (model 2))
(template_A (model 3))
(template_B (model 2))
(template_B (model 3))
(template_B (model 4)))
CLIPS>
(deffunction extract-every-nth-value (?values ?start ?increment)
(bind ?rv (create$))
(while (<= ?start (length$ ?values))
(bind ?rv (create$ ?rv (nth$ ?start ?values)))
(bind ?start (+ ?start ?increment)))
(return ?rv))
CLIPS> (reset)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (template_A (model 1))
f-2 (template_A (model 2))
f-3 (template_A (model 3))
f-4 (template_B (model 2))
f-5 (template_B (model 3))
f-6 (template_B (model 4))
For a total of 7 facts.
CLIPS>
(find-all-facts ((?a template_A)(?b template_B))
(eq ?a:model ?b:model))
(<Fact-2> <Fact-4> <Fact-3> <Fact-5>)
CLIPS>
(extract-every-nth-value
(find-all-facts ((?a template_A)(?b template_B))
(eq ?a:model ?b:model))
1 2)
(<Fact-2> <Fact-3>)
CLIPS>

Resources