As the title suggests, I have a "generate-hotels" rule which, although being in the correct module and having all the facts that are needed in WM, this rule does not occur.
(defrule HOTELS::generate-hotels
(hotel (name ?name) (tr ?tr) (stars ?s) (price-per-night ?ppn))
(tourism-resort (name ?tr) (region ?r) (type $? ?t $?) (score ?s))
(tourism-type ?t)
(attribute (name best-region) (value ?r) (certainty ?certainty-1))
(attribute (name best-city) (value ?city&:(eq ?city (sym-cat (str-cat ?r "-") ?tr))) (certainty ?certainty-2))
(attribute (name best-tourism-type) (value ?t) (certainty ?certainty-3))
=>
(assert (attribute (name hotel) (value ?name)
(certainty (min ?certainty-1 ?certainty-2 ?certainty-3)))))
Related
I am with the following CLIPS programming problem:
New family relationship knowledge base. Please apply the following specification:
use deftemplate to define the person
a person’s attributes are: name, age, sex, children,
each attribute should be defined as a slot except children, that are multi slot
in sex slot use the (allowed-symbols female male)
add data type to each slot
use deffacts to add people from diagram
define rules:
—mother,
—father,
—sister,
—predecessor
—old — giving the difference in age between predecessor and offspring
This is the code I made:
(deftemplate person
(slot name (type SYMBOL))
(slot age (type INTEGER))
(slot sex (type SYMBOL) (allowed-symbols female male))
(multislot children (type SYMBOL))
)
(deffacts init
(person (name Fernando) (age 55) (sex male) (children Jesus Celia))
(person (name Maria) (age 50) (sex female) (children Jesus Celia))
(person (name Jesus) (age 25) (sex male))
(person (name Celia) (age 20) (sex female))
(person (name Antonio) (age 70) (sex male) (children Fernando Ana))
(person (name Ana) (age 38) (sex female))
(person (name Calra) (age 68) (sex female) (children Fernando Ana))
)
(defrule mother
(person (name ?name) (sex female) (children $?before ?child $?after))
=>
(assert (mother ?name ?child))
(printout t ?name " is mother of " $?child crlf))
(defrule father
(person (name ?name) (sex male) (children $?before ?child $?after))
=>
(assert (father ?name ?child))
(printout t ?name " is father of " $?child crlf))
(defrule sister
(children ?z ?x)
(children ?z ?y)
(female ?x)
(not (test (eq ?x ?y)))
=>
(assert sister ?x ?y))
(printout t ?x "is a sister to " ?y crlf))
(defrule predecessor
(or
(children ?x ?y)
(and (children ?x ?z)(predecessor ?z ?y))
)
=>
(assert (predecessor ?x ?y)
(printout t ?x "is a predecessor to " ?y crlf))
(defrule old
?fact_no <- (person (name ?n) (age ?a1 ?a2))
(test (<= ?a1 ?a2))
=>
(assert (result (- ?a1 ?a2)))
(printout t "There are " ?result " years" crlf))
The mother and father relationship is working but not the rest. It gives me the following ERRORS:
CLIPS> Loading Selection...
[CSTRCPSR4] Cannot redefine deftemplate person while it is in use.
ERROR:
(deftemplate MAIN::person
[CSTRCPSR1] WARNING: Redefining deffacts: init
[CSTRCPSR1] WARNING: Redefining defrule: mother +j+j
Defining defrule: father +j+j
[CSTRCPSR1] WARNING: Redefining defrule: sister
[PRNTUTIL2] Syntax Error: Check appropriate syntax for RHS patterns.
ERROR:
(defrule MAIN::sister
(children ?z ?x)
(children ?z ?y)
(female ?x)
(not (test (eq ?x ?y)))
=>
(assert sister
Defining defrule: predecessor
[EXPRNPSR3] Missing function declaration for defrule.
ERROR:
(defrule MAIN::predecessor
(or (children ?x ?y)
(and (children ?x ?z)
(predecessor ?z ?y)))
=>
(assert (predecessor ?x ?y)
(printout t ?x "is a predecessor to " ?y crlf))
(defrule
Thank you so much in advance
If you already have code loaded, issue a clear command before you try to load the same code a second time. That will remove the [CSTRCPSR4] error message.
You have missing parentheses in the sister and predecessor rules. Correcting these will allow the rules to load without errors.
(defrule sister
(children ?z ?x)
(children ?z ?y)
(female ?x)
(not (test (eq ?x ?y)))
=>
(assert (sister ?x ?y))
(printout t ?x "is a sister to " ?y crlf))
(defrule predecessor
(or
(children ?x ?y)
(and (children ?x ?z)(predecessor ?z ?y))
)
=>
(assert (predecessor ?x ?y))
(printout t ?x "is a predecessor to " ?y crlf))
These rules will still not execute with your existing code because they require children and female facts and none of your rules assert these facts.
It's not clear what you're trying to do with your old rule, but since you're trying to match two values in the age slot this rule will generate errors because that slot can only contain one value.
I have a template:
(deftemplate drule
(slot name1)
(slot id)
(multislot field1)
(multislot value1)
(slot name2)
(multislot field2)
(multislot value2))
(deftemplate claim
(slot name)
(multislot field)
(multislot value))
Can I have rule which will
Check whether there are any claims with name same as the one in drule.
Check whether claim:field has value 'EmpName', if found then bind it to ?name.
Currently I have something as follows:
(defrule drule
(drule (id ?id)
(name1 ?name1)
(name2 ?name2))
(claim (name ?name1)
(field $?pf1 'EmpName' $?)
(value $?pv1&:(= (length$ ?pf1) (length$ ?pv1)) ?name $?))
(claim (name ?name2)
(field $?pf2 'EmpName' $?)
(value $?pv2&:(= (length$ ?pf2) (length$ ?pv2)) ?name $?))
...
=>
(assert (success ?name))
But it will bind only if all the selected claims have a field EmpName. I only want to check those claims with name
mentioned in drule. And if any of those claims have field 'EmpName' then it should be bound. If not just continue. My
rule fails if some claims do not have EmpName field at all. Assumption is that some claim will have EmpName field
and value.
Desired input and output:
(assert
(claim (name 'Employee')
(field 'Company')
(value 'ABC'))
(claim (name 'Event')
(field 'EmpName' 'EventName' 'Company')
(value 'Bob' 'Conference' 'ABC'))
(drule (id '001')
(name1 'Employee')
(field1 'Company')
(value1 'ABC')
(name2 'Event')
(field2 'EventName')
(value2 'Conference')))
Output:
(success 'Bob')
Sorry if it is very stupid, I tried using test$ and member$ on field. But could not figure it out. I am self-learning CLIPS in my free time.
CLIPS>
(deftemplate drule
(slot name1)
(slot id)
(multislot field1)
(multislot value1)
(slot name2)
(multislot field2)
(multislot value2))
CLIPS>
(deftemplate claim
(slot name)
(multislot field)
(multislot value))
CLIPS>
(defrule drule
(drule (id ?id)
(name1 ?name1)
(name2 ?name2))
(claim (name ?name1))
(claim (name ?name2))
(claim (name ?name1 | ?name2)
(field $?pf1 'EmpName' $?)
(value $?pv1&:(= (length$ ?pf1) (length$ ?pv1)) ?name $?))
=>
(assert (success ?name)))
CLIPS>
(deffacts initial
(claim (name 'Employee')
(field 'Company')
(value 'ABC'))
(claim (name 'Event')
(field 'EmpName' 'EventName' 'Company')
(value 'Bob' 'Conference' 'ABC'))
(drule (id '001')
(name1 'Employee')
(field1 'Company')
(value1 'ABC')
(name2 'Event')
(field2 'EventName')
(value2 'Conference')))
CLIPS> (reset)
CLIPS> (agenda)
0 drule: f-3,f-1,f-2,f-2
For a total of 1 activation.
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (claim (name 'Employee') (field 'Company') (value 'ABC'))
f-2 (claim (name 'Event') (field 'EmpName' 'EventName' 'Company') (value 'Bob' 'Conference' 'ABC'))
f-3 (drule (name1 'Employee') (id '001') (field1 'Company') (value1 'ABC') (name2 'Event') (field2 'EventName') (value2 'Conference'))
f-4 (success 'Bob')
For a total of 5 facts.
CLIPS>
I have following template:
(deftemplate drule
(slot name1)
(slot id)
(multislot field1)
(multislot value1)
(slot name2)
(multislot field2)
(multislot value2))
(deftemplate claim
(slot name)
(multislot field)
(multislot value))
I have the following rule:
(defrule drule
(drule
(id ?id))
(forall
(drule
(id ?id)
(name1 ?name1)
(field1 $?f11 ?field1 $?)
(value1 $?v11&:(= (length$ ?f11)(length$ ?v11)) ?value1 $?)
(name2 ?name2)
(field2 $?f22 ?field2 $?)
(value2 $?v22&:(= (length$ ?f22)(length$ ?v22)) ?value2 $?))
(claim
(name ?name1)
(field $?f1 ?field1 $?)
(value $?v1&:(= (length$ ?f1)(length$ ?v1)) ?value1 $?))
(claim
(name ?name2)
(field $?f2 ?field2 $?)
(value $?v2&:(= (length$ ?f2)(length$ ?v2)) ?value2 $?))
(not
(claim (field $?f3 ?field1 $?)(value $?v3&:(= (length$ ?f3)(length$ ?v3)) ~?value1 $?)))
(not (claim (field $?f4 ?field2 $?)(value $?v4&:(= (length$ ?f4)(length$ ?v4)) ~?value2 $?))))
(forall
(claim
(field $?f5 ?field5 $?)(value $?v5&:(= (length$ ?f5)(length$ ?v5)) ?value5 $?))
(not
(claim (field $?f6 ?field5 $?)(value $?v6&:(= (length$ ?f6)(length$ ?v6)) ~?value5 $?))))
=>
(assert (success)))
The above rule does the following:
Check whether all fields:value pair in drule are found in claim facts.
Check whether all field:value pair in drule are also the same in other matched claims. (only if field is found
in the claim) answered
Check whether all field:values pairs are same in each selected pair. (Only if field is found).
For example,
(assert
(claim (name 'Employee')
(field 'EmpName' 'Company')
(value 'Bob' 'ABC'))
(claim (name 'Event')
(field 'EmpName' 'EventName' 'Company')
(value 'Bob' 'Conference' 'ABC'))
(drule (id '001')
(name1 'Employee')
(field1 'Company')
(value1 'ABC')
(name2 'Event')
(field2 'EventName')
(value2 'Conference')))
Above should be successful, while the below should fail. Because EmpName mismatched.
(assert
(claim (name 'Employee')
(field 'EmpName' 'Company')
(value 'Bob' 'ABC'))
(claim (name 'Event')
(field 'EmpName' 'EventName' 'Company')
(value 'Adam' 'Conference' 'ABC'))
(drule (id '001')
(name1 'Employee')
(field1 'Company')
(value1 'ABC')
(name2 'Event')
(field2 'EventName')
(value2 'Conference')))
But my rule fails when there is the following assertion
(assert
(claim (name 'Employee')
(field 'EmpName' 'Company')
(value 'Bob' 'ABC'))
(claim (name 'Event')
(field 'EmpName' 'EventName' 'Company')
(value 'Bob' 'Conference' 'ABC'))
(claim (name 'Event')
(field 'EmpName' 'EventName' 'Company')
(value 'Adam' 'Conference' 'ABC'))
(drule (id '001')
(name1 'Employee')
(field1 'Company')
(value1 'ABC')
(name2 'Event')
(field2 'EventName')
(value2 'Conference')))
I want to fire the rule even if there is one claim with same EmpName field. My rule checks all the claims and if there
is any field:value mismatch then it wont fire.
EDIT: Is there a way to retrieve the field EmpName or other field like Company to the RHS? For example, for the last set of facts above, can I get the RHS to (assert (User ?name successfully entered)). I only want the for the claim which was matched in the forall (CLIPS throws me an error).
Thank you.
I'm not sure if this is precisely what you want in satisfying criterion #3 since I don't fully understand your explanation, but it works properly for the examples you've given.
(defrule drule
(drule (id ?id)
(name1 ?name1)
(name2 ?name2))
(forall
(drule (id ?id)
(name1 ?name1)
(field1 $?f11 ?field1 $?)
(value1 $?v11&:(= (length$ ?f11)(length$ ?v11)) ?value1 $?)
(name2 ?name2)
(field2 $?f22 ?field2 $?)
(value2 $?v22&:(= (length$ ?f22)(length$ ?v22)) ?value2 $?))
(claim (name ?name1)
(field $?f1 ?field1 $?)
(value $?v1&:(= (length$ ?f1)(length$ ?v1)) ?value1 $?))
(claim (name ?name2)
(field $?f2 ?field2 $?)
(value $?v2&:(= (length$ ?f2)(length$ ?v2)) ?value2 $?))
(not (claim (field $?f3 ?field1 $?)
(value $?v3&:(= (length$ ?f3)(length$ ?v3)) ~?value1 $?)))
(not (claim (field $?f4 ?field2 $?)
(value $?v4&:(= (length$ ?f4)(length$ ?v4)) ~?value2 $?))))
(forall
(claim (name ?name3&?name1|?name2)
(field $?f5 ?field5 $?)
(value $?v5&:(= (length$ ?f5)(length$ ?v5)) ?value5 $?))
(exists
(claim (name ~?name3&?name1|?name2)
(field $?f6 ?field5 $?)
(value $?v6&:(= (length$ ?f6)(length$ ?v6)) ?value5 $?))))
=>
(assert (success)))
For values you want to use on the RHS, you can retrieve them outside the forall conditional elements by either adding them to the drule pattern (as is done here for name1 and name2) or by adding an additional pattern for retrieving them from a specific claim fact.
Since you've got some complex logic, you might find it easier to debug your code if you split the logic between multiple rules:
(defrule check-1
(drule (id ?id)
(name1 ?name1)
(field1 $?f11 ?field1 $?)
(value1 $?v11&:(= (length$ ?f11)(length$ ?v11)) ?value1 $?)
(name2 ?name2)
(field2 $?f22 ?field2 $?)
(value2 $?v22&:(= (length$ ?f22)(length$ ?v22)) ?value2 $?))
(not (and (claim (name ?name1)
(field $?f1 ?field1 $?)
(value $?v1&:(= (length$ ?f1)(length$ ?v1)) ?value1 $?))
(claim (name ?name2)
(field $?f2 ?field2 $?)
(value $?v2&:(= (length$ ?f2)(length$ ?v2)) ?value2 $?))))
=>
(assert (mismatch ?id)))
(defrule check-2
(drule (id ?id)
(name1 ?name1)
(field1 $?f11 ?field1 $?)
(value1 $?v11&:(= (length$ ?f11)(length$ ?v11)) ?value1 $?)
(name2 ?name2)
(field2 $?f22 ?field2 $?)
(value2 $?v22&:(= (length$ ?f22)(length$ ?v22)) ?value2 $?))
(or (claim (field $?f3 ?field1 $?)
(value $?v3&:(= (length$ ?f3)(length$ ?v3)) ~?value1 $?))
(claim (field $?f4 ?field2 $?)
(value $?v4&:(= (length$ ?f4)(length$ ?v4)) ~?value2 $?)))
=>
(assert (mismatch ?id)))
(defrule check-3
(drule (id ?id)
(name1 ?name1)
(name2 ?name2))
(exists (claim (name ?name3&?name1|?name2)
(field $?f3 ?field3 $?)
(value $?v3&:(= (length$ ?f3) (length$ ?v3)) ?value3 $?))
(not (claim (name ~?name3&?name1|?name2)
(field $?f4 ?field3 $?)
(value $?v4&:(= (length$ ?f4)(length$ ?v4)) ?value3 $?))))
=>
(assert (mismatch ?id)))
(defrule drule
(declare (salience -10))
(drule (id ?id))
(not (mismatch ?id))
=>
(assert (success)))
I am trying to solve a problem, where I have to fill a 5x5 matrix with letters A, B, C, D, and E. Each letter cannot occur more than once in each row and in each column. With some initial letter positions given.
I created every position as separate facts eg. "M 1 1 X".
I am struggling how to loop a defrule in way to assert a fact with correct letter and check the conditions again.
(defrule solveA5
?a <-(M 5 ?c X)
(not (M ?x ?c A))
=>
(retract ?a)
(assert (M 5 ?c A))
)
Code above for example is only to check presence of A in every position of 5th row, but the problem is that conditions are checked at the beginning only and instead of asserting correct fact and checking again it asserts A in every position.
I've tried using deffunction to loop defrule.
(deffunction solve (?letter)
(loop-for-count (?x 1 5) do
(loop-for-count (?y 1 5) do
(build (str-cat"defrule costam
?a <-(M ?x ?y X)
(not (and(M ?x ?a ?letter) (M ?b ?y ?letter))
=>
(retract ?a)
(assert (M ?x ?y ?letter))")
)
)
)
)
Unfortunately running
(solve A)
returns "FALSE" and doesn't modify any facts.
To handle iteration within rules, you must assert the iteration information as facts to allow the rules to match and modify this information. In the placement, it's not essential to do this in any particular order, so you can just assert information containing the rows, columns, and letters to place and allow the rules fire arbitrarily:
CLIPS>
(deftemplate element
(slot row)
(slot column)
(slot value))
CLIPS>
(deftemplate print
(slot row)
(slot column)
(slot end-of-row))
CLIPS>
(deffacts initial
(rows 1 2 3 4 5)
(columns 1 2 3 4 5)
(letters A B C D E))
CLIPS>
(defrule place
(rows $? ?r1 $?)
(columns $? ?c1 $?)
(letters $? ?l $?)
(not (element (row ?r1) (column ?c1)))
(not (and (element (row ?r2)
(column ?c2)
(value ?l))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))))
=>
(assert (element (row ?r1) (column ?c1) (value ?l))))
CLIPS>
(defrule print-start
(declare (salience -10))
(rows ?r $?)
(columns ?c $?rest)
=>
(assert (print (row ?r)
(column ?c)
(end-of-row (= (length$ ?rest) 0)))))
CLIPS>
(defrule print-next-column
(declare (salience -10))
?f <- (print (column ?c))
(columns $? ?c ?nc $?rest)
=>
(modify ?f (column ?nc)
(end-of-row (= (length$ ?rest) 0))))
CLIPS>
(defrule print-next-row
(declare (salience -10))
?f <- (print (column ?c) (row ?r))
(columns $?first ?c)
(rows $? ?r ?nr $?)
=>
(if (= (length$ ?first) 0)
then
(bind ?eor TRUE)
(bind ?nc ?c)
else
(bind ?eor FALSE)
(bind ?nc (nth$ 1 ?first)))
(modify ?f (row ?nr)
(column ?nc)
(end-of-row ?eor)))
CLIPS>
(defrule print-placed
(print (row ?r) (column ?c) (end-of-row ?eor))
(element (row ?r) (column ?c) (value ?l))
=>
(if ?eor
then
(printout t ?l crlf)
else
(printout t ?l " ")))
CLIPS>
(defrule print-unplaced
(print (row ?r) (column ?c) (end-of-row ?eor))
(not (element (row ?r) (column ?c)))
=>
(if ?eor
then
(printout t "?" crlf)
else
(printout t "? ")))
CLIPS> (reset)
CLIPS> (run)
E D C B A
? C D A B
? B A D C
? A B C D
A ? ? ? E
CLIPS>
In this example, the print rules iterate over the rows and columns by storing the iteration information in facts. You can see how much more complicated this is than the place rule which assigns the elements in an arbitrary manner.
Whether you assign the values arbitrarily or in a specific order, it's possible to assign values that prevent a solution, so you must implement backtracking in order to guarantee finding the solution if one exists. In this example, the facts store information about the order of the value placements and the values that have been tried:
CLIPS> (clear)
CLIPS>
(deftemplate element
(slot row)
(slot column)
(slot value (default unset))
(multislot values)
(slot placement))
CLIPS>
(deffacts initial
(placement 0)
(rows 1 2 3 4 5)
(columns 1 2 3 4 5)
(letters A B C D E))
CLIPS>
(defrule prime
(placement ?p)
(rows $? ?r $?)
(columns $? ?c $?)
(letters $?l)
(not (element (placement ?p)))
(not (element (row ?r) (column ?c)))
=>
(assert (element (placement ?p) (values ?l) (row ?r) (column ?c))))
CLIPS>
(defrule place-good
?f1 <- (placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(row ?r1)
(column ?c1)
(values ?v $?rest))
(not (and (element (row ?r2)
(column ?c2)
(value ?v))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))))
=>
(retract ?f1)
(assert (placement (+ ?p 1)))
(modify ?f2 (value ?v) (values ?rest)))
CLIPS>
(defrule place-bad
(placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(row ?r1)
(column ?c1)
(values ?v $?rest))
(element (row ?r2)
(column ?c2)
(value ?v))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))
=>
(modify ?f2 (values ?rest)))
CLIPS>
(defrule backtrack
?f1 <- (placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(values))
?f3 <- (element (placement =(- ?p 1))
(value ~unset))
=>
(retract ?f1)
(assert (placement (- ?p 1)))
(retract ?f2)
(modify ?f3 (value unset)))
CLIPS>
(defrule print
(declare (salience -10))
(rows $?rows)
(columns $?columns)
=>
(progn$ (?r ?rows)
(progn$ (?c ?columns)
(if (not (do-for-fact ((?f element))
(and (= ?r ?f:row) (= ?c ?f:column))
(printout t ?f:value " ")))
then
(printout t "? ")))
(printout t crlf)))
CLIPS> (reset)
CLIPS> (run)
B C D E A
A B C D E
C A E B D
D E A C B
E D B A C
CLIPS>
The print rules have been simplified into a single rule that iterates over the row and columns in the actions of the rule and uses the fact query functions to retrieve values that have been assigned.
The program also works if you preassign some of the values:
CLIPS> (reset)
CLIPS> (assert (element (row 1) (column 1) (value A)))
<Fact-5>
CLIPS> (assert (element (row 3) (column 3) (value C)))
<Fact-6>
CLIPS> (assert (element (row 5) (column 4) (value E)))
<Fact-7>
CLIPS> (run)
A C E D B
B A D C E
D E C B A
E D B A C
C B A E D
CLIPS>
I need your help. I have a facts like
(fact (name1)(value1))
(fact (name2)(value2))
(fact (name3)(value3))
And I wanna ask the question:
(printout t "Which of the fact do you like? " value1 value2 value3)
How can I present facts like string?
CLIPS>
(deftemplate info
(slot name)
(slot value))
CLIPS>
(deffacts initial
(info (name n1) (value v1))
(info (name n2) (value v2))
(info (name n3) (value v3)))
CLIPS>
(defrule query
=>
(bind ?values (create$))
(do-for-all-facts ((?f info)) TRUE
(bind ?values (create$ ?values ?f:value)))
(printout t "Which of the facts do you like? " ?values crlf))
CLIPS> (reset)
CLIPS> (run)
Which of the facts do you like? (v1 v2 v3)
CLIPS>