I'm trying to implement a basic expert system in the Clips programming language. I have a knowledge base of children with their respective parents. I want to set up a rule so that if two children have the same parents then it asserts the fact that they are siblings.
(deftemplate person "family tree"
(slot name)
(slot father)
(slot mother))
(assert
(person
(name "William")
(father "John")
(mother "Megan")))
(assert
(person (name "David")
(father "John")
(mother "Megan")))
(defrule sibling
(person
(name ?name1)
(father ?x)
(mother ?x))
(person
(name ?name2)
(father ?y)
(mother ?y)))
and when I define the rule I get a syntax error:
Syntax Error: Check appropriate syntax for defrule.
The correct syntax for your rule is:
(defrule sibling
(person (name ?name1) (father ?x) (mother ?x))
(person (name ?name2) (father ?y) (mother ?y))
=>
...)
Within a rule, a template is referred as:
(template_name (slot_name value) (slot_name value))
A rule is divided in two sides: the LHS (Left-Hand Side) where you define the conditions satisfying such rule and the RHS (Right-Hand Side) where you define the consequent actions.
In CLIPS, the => operator separates the two sides.
Example:
(defrule animal-is-a-duck
(animal ?name)
(quacks)
(two legs)
(lay eggs)
=>
(assert (animal ?name is a duck)))
You can read more about CLIPS syntax in the basic programming guide.
Your rule should be something like this:
(defrule sibling
(person
(name ?name1)
(father ?x)
(mother ?y))
(person
(name ?name2)
(father ?x)
(mother ?y))
(test (neq ?name1 ?name2))
=>
(assert (siblings ?name1 ?name2)))
The original rule could be satisfied only if the father and the mother were the same person in each fact being matched.
This rule permits duplicates:
f-3 (siblings "David" "William")
f-4 (siblings "William" "David")
so you can either catch that in another rule or you can write a more complex rule (or another rule) also matching against currently generated matched siblings facts.
Related
I have some family tree and want to get granfather from that tree via defrule. Also would be perfect if we can get brother-in-law.
(deftemplate person
(slot name)
(slot gender)
(slot father)
(slot wife))
(deffacts people
(person (name Vasya) (gender male) (wife Liza))
(person (name Liza) (gender female))
(person (name Vladimir) (gender male) (father Vasya))
(person (name Natasha) (gender female) (father Vasya))
(person (name Viktor) (gender male) (father Vasya))
(person (name Misha) (gender male) (wife Natasha))
(person (name Kostya) (gender male) (father Misha) (wife Liza))
(person (name Masha) (gender female) (father Misha)))
(deftemplate mother
(slot namel)
(slot name2))
(deftemplate brother
(slot namel)
(slot name2))
(defrule Brother
(person (name ?x) (gender male) (father ?y&~nil))
(person (name ?z&~?x) (gender male) (father ?y&~nil))
(not (brother (namel ?x) (name2 ?z)))
(not (brother (namel ?z) (name2 ?x)))
=>
(printout t ?x " brother of " ?z crlf)
(assert (brother (namel ?x) (name2 ?z))))
Assuming that you're treating half-brothers as brothers, there are two issues with your existing Brother rule. First, it's requiring that a brother have a male sibling, so Masha and Natasha are not identified as having brothers. Second, half-brothers can also share mothers, not just fathers.
Modify your person deftemplate to include a mother and change the wife slot to a spouse:
(deftemplate person
(slot name)
(slot gender)
(slot mother)
(slot father)
(slot spouse))
Create a new deftemplate for representing relationships between person facts:
(deftemplate relation
(slot p1)
(slot is)
(slot p2))
Modify your deffacts to reflect the updated deftemplate:
(deffacts people
(person (name Vasya) (gender male) (spouse Liza))
(person (name Liza) (gender female))
(person (name Vladimir) (gender male) (father Vasya))
(person (name Natasha) (gender female) (father Vasya))
(person (name Viktor) (gender male) (father Vasya))
(person (name Misha) (gender male) (spouse Natasha))
(person (name Kostya) (gender male) (father Misha) (spouse Liza))
(person (name Masha) (gender female) (father Misha)))
You can then update the brother rule:
(defrule brother
(person (name ?name)
(mother ?mother)
(father ?father))
(or (person (name ?brother&~?name)
(gender male)
(father ?father&~nil))
(person (name ?brother&~?name)
(gender male)
(mother ?mother&~nil)))
=>
(assert (relation (p1 ?brother)
(is brother-of)
(p2 ?name))))
and add new rules for grandfather and brother-in-law:
(defrule grandfather
(person (name ?name)
(mother ?mother)
(father ?father))
(person (name ?mother | ?father)
(father ?grandfather&~nil))
=>
(assert (relation (p1 ?grandfather)
(is grandfather-of)
(p2 ?name))))
(defrule brother-in-law
(person (name ?name)
(spouse ?spouse))
(relation (p1 ?brother-in-law)
(is brother-of)
(p2 ?spouse))
=>
(assert (relation (p1 ?brother-in-law)
(is brother-in-law-of)
(p2 ?name))))
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.
Introduction
I am trying to implement a rule in CLIPS language - the relation that a person is an ancestor of other person.
The constraint is that such rule must be derived only from the following premises:
(male ?x) ("x is a male")
(female ?y) ("y is a female")
(mother-of ?x ?y) ("x is a mother of y")
(father-of ?x ?y) ("x is a father of y")
My attempt
I wrote the following code:
(deftemplate father-of
(slot father)
(slot child)
)
(deftemplate mother-of
(slot mother)
(slot child)
)
(deftemplate male
(slot person)
)
(deftemplate female
(slot person)
)
(deffacts family
(father-of (father John) (child Mark))
(father-of (father John) (child Mary))
(mother-of (mother Alice) (child Mark))
(mother-of (mother Alice) (child Mary))
(male (person John))
(male (person Mark))
(female (person Alice))
(female (person Mary))
)
(defrule ancestor
(or
(mother-of (mother ?x) (child ?w))
(father-of (father ?x) (child ?w))
(and
(mother-of (mother ?x) (child ?y))
(or
(mother-of (mother ?y) (child ?w))
(father-of (father ?y) (child ?w))
)
)
(and
(father-of (father ?x) (child ?y))
(or
(mother-of (mother ?y) (child ?w))
(father-of (father ?y) (child ?w))
)
)
)
=>
(printout t ?x " is an ancestor of " ?w crlf)
(assert (ancestor ?x ?w))
)
The gist of the problem
The above code compiles and returns "true"(in other words, the construced rule is logically correct) and outputs expected results in the case of such list of facts.
However, there is a subtle problem:
This codes works for determining first and second generation of ancestors only.
In other words, it works only in the case if someone is a father/mother of someone or a grandfather/grandmother of someone, but not for checking if someone is a great grandfather/great grandmother or great great grandfather/great great grandmother of someone, etc.
The above code does not handle this issue.
How to overcome this problem?
CLIPS>
(deftemplate father-of
(slot father)
(slot child))
CLIPS>
(deftemplate mother-of
(slot mother)
(slot child))
CLIPS>
(deffacts family
(father-of (father Bob) (child Frank))
(mother-of (mother Linda) (child Frank))
(father-of (father Frank) (child John))
(mother-of (mother Susan) (child John))
(father-of (father John) (child Mark))
(mother-of (mother Alice) (child Mark)))
CLIPS>
(defrule ancestor
(or (mother-of (mother ?x) (child ?w))
(father-of (father ?x) (child ?w))
(and (ancestor ?x ?y)
(ancestor ?y ?w)))
(not (ancestor ?x ?w))
=>
(printout t ?x " is an ancestor of " ?w crlf)
(assert (ancestor ?x ?w)))
CLIPS> (reset)
CLIPS> (run)
Alice is an ancestor of Mark
John is an ancestor of Mark
Susan is an ancestor of John
Susan is an ancestor of Mark
Frank is an ancestor of John
Frank is an ancestor of Mark
Linda is an ancestor of Frank
Linda is an ancestor of Mark
Linda is an ancestor of John
Bob is an ancestor of Frank
Bob is an ancestor of Mark
Bob is an ancestor of John
CLIPS>
I am struggling with the following CLIPS programming problem:
Problem: write a set of rules to define family relations like:
(brother ?x ?y) (i.e. "x is a brother of y")
(sister ?x ?y) (i.e. "x is a sister of y")
(son ?x ?y) (i.e. "x is a son of y")
(daughter ?x ?y) (i.e. "x is a daughter of y")
The constraint in this task is that the rules can be constructed only from the following premises:
(father ?x ?y) (i.e. "x is a father of y")
(mother ?x ?y) (i.e. "x is a mother of y")
(male ?x) (i.e. "x is a male")
(female ?y) (i.e. "y is a female")
The task also assumes that there must be some initial facts provided and that to check the correctness there should be an implementation of displaying information about derived conclusions.
My attempt
I created templates and initial facts as follows:
(deftemplate father-of
(slot father)
(slot child)
)
(deftemplate mother-of
(slot mother)
(slot child)
)
(deftemplate male
(slot person)
)
(deftemplate female
(slot person)
)
(deffacts family
(mother-of(mother Anna) (child Tracy)
(mother-of(mother Anna) (child Cindy)
(female Anna)
(female Tracy)
(female Cindy)
)
My attempt in writing a rule for checking if certain person is a sister of other person was as follows:
(defrule sister-of
(and
(female (person ?x))
(female (person ?y))
(female (person ?z))
(mother-of (mother ?x) (child ?y))
(mother-of (mother ?x) (child ?z))
)
=>
(assert (sister ?y ?z))
(printout t ?y " is a sister of " ?z crlf)
)
Output error
Once I load .clp file I consistenly obtain the following error message of such form:
CLIPS (6.30 3/17/15)
CLIPS> (reset)
CLIPS> (clear)
CLIPS> (load family.clp)
Defining deftemplate: father-of
Defining deftemplate: mother-of
Defining deftemplate: male
Defining deftemplate: female
Defining deffacts: family
[PRNTUTIL2] Syntax Error: Check appropriate syntax for deftemplate pattern.
ERROR:
(deffacts MAIN::family
(mother-of (mother Anna) (child Markus))
(female Anna
FALSE
CLIPS>
My attempts
I checked CLIPS guides regarding basic programming, googled error message, but I did not make any progress.
Help will be greatly appreciated!!! For me it suffices to see how this stuff works in the case of the case of writing a rule (sister ?x ?y) with all the templates and facts provided above.
If you define a deftemplate for a fact, you must include the slot names when specifying the slot values.
(deffacts family
(mother-of(mother Anna) (child Tracy))
(mother-of(mother Anna) (child Cindy))
(female (person Anna))
(female (person Tracy))
(female (person Cindy))
)
Assume that you are given a set of 'person' facts that are defined according to the following construct:
(deftemplate person (slot name) (slot sex) (allowed-values male female) (multislot children))
Write rules to do the following:
Create a fact of the form (unknown-person ) for each name that appears in the children multislot of a person fact but not in the name slot of any person fact (it is assumed that no two people have the same name)
For each fact of the form (unknown-person ) ask the user for the sex of the person, retract the fact and assert a new fact of the form (unknown-person ).
For each fact of the form (unknown-person ), retract the fact and create a new person fact for the person (it is assumed that the person has no children).
Your rules should do data validation to ensure that only an allowed value for is supplied by the user
Define the template in CLIPS:
(deftemplate person
(slot name)
(slot sex)
(slot gender (allowed-values male female))
(multislot children))
Start with the unknown-person creation (caveat: this may not be completely correct as it still creates a person without checking to see if they exist).
(defrule childrencataloguer "First layer of unknown person resolution"
(person (children $?ch))
=>
(progn$ (?term ?ch)
(assert (unknown-person ?term))
))
Deal with the caveat above
(defrule removeunknownswithpersonsalready
(person (name ?n))
?up <-(unknown-person ?n)
=>
(retract ?up))
Now, get the gender:
(defrule getgender
?up-nogen <-(unknown-person ?n)
=>
(retract ?up-nogen)
(printout t crlf "Please enter male or female to indicate " ?n "'s gender" crlf )
(assert (unknown-person ?n (read)))
)
There are other ways you can do the gender confirmation, I would have liked to use the deftemplate itself, so that the allowed-values would have fed into the validation. But I don't know how yet.
(assert (gender male))
(assert (gender female))
Now, do validation:
(defrule checkgender
?p <- (unknown-person ?n ?s)
(not (gender ?s))
=>
(retract ?p)
(assert (unknown-person ?n))
)
Finally, graduate from unknown
(defrule graduatefromunknown
(declare (salience -10))
?up <- (unknown-person ?n ?s)
=>
(retract ?up)
(assert (person (name ?n) (sex ?s)))
)