Nick97832954
Nick97832954

Reputation: 149

CLIPS How to find facts based on deftemplate relation slots

I'm building a family tree using deftemplates. I declare initial fact base using deffacts family by asserting peoples' mothers and fathers. Then I set a bunch of rules to assert siblings, grandparents, cousins, etc. I want to get two names from the user and then based on the facts, it will tell me what their relation to each other is. I am so stumped on this problem please help.

I've been trying to use find-all-facts, find-fact but I can't figure out how to use the query syntax properly. Do I need a loop to iterate through every fact?

deftemplates I'm using:

(deftemplate father-of   (slot father)  (slot child))
(deftemplate mother-of   (slot mother)  (slot child))
(deftemplate parent-of  (slot parent)   (slot child))
(deftemplate sister-of  (slot sister)   (slot sibling))
(deftemplate brother-of (slot brother)  (slot sibling))
(deftemplate aunt-of    (slot aunt)     (slot nephew-or-niece))
(deftemplate uncle-of   (slot uncle)    (slot nephew-or-niece))
(deftemplate cousin-of  (slot cousin-1) (slot cousin-2))
...

Initial fact base snipped:

(deffacts family
    ;GreatGrandParents
    (father-of (father "Henry") (child "Bob"))
    (father-of (father "Henry") (child "Susie"))
    (father-of (father "Henry") (child "Anton"))
    (mother-of (mother "Georgette") (child "Bob"))
    ...)

What I've been trying:

(defrule get-relationship ""
    =>
    (printout t crlf "Enter a person in the family: ")
    (bind ?p1 (read))
    (printout t crlf "Enter another person in the family: ")
    (bind ?p2 (read))
    (find-all-facts
        ($a?-of ($a? ?p1) ($b? ?p2))               ;any fact that contains both names entered
        ((!= 0 (str-compare ?p1 ?p2))              ;given ?p1 and ?p2 are dissimilar
        (printout t ?p1 "is a" $a? "of" $b? crlf)) ;display the relationship found
)

Upvotes: 0

Views: 997

Answers (1)

Gary Riley
Gary Riley

Reputation: 10757

Using queries:

         CLIPS (6.31 6/12/19)
CLIPS> 
(deftemplate of
   (slot relation)
   (slot p1)
   (slot p2))
CLIPS> 
(deffacts family
   (of (relation father) (p1 "Henry") (p2 "Bob"))
   (of (relation father) (p1 "Henry") (p2 "Susie"))
   (of (relation father) (p1 "Henry") (p2 "Anton"))
   (of (relation mother) (p1 "Georgette") (p2 "Bob")))
CLIPS>    
(defrule get-relationship ""
    =>
    (printout t "Enter a person in the family: ")
    (bind ?p1 (readline))
    (printout t "Enter another person in the family: ")
    (bind ?p2 (readline))
    (do-for-all-facts ((?o of)) 
       (and (eq ?p1 ?o:p1)
            (eq ?p2 ?o:p2))
       (printout t ?p1 " is a " ?o:relation " of " ?p2 crlf)))
CLIPS> (reset)
CLIPS> (run)
Enter a person in the family: Henry
Enter another person in the family: Susie
Henry is a father of Susie
CLIPS>

Using patterns:

CLIPS> (clear)
CLIPS> 
(deftemplate of
   (slot relation)
   (slot p1)
   (slot p2))
CLIPS> 
(deftemplate find
   (slot p1)
   (slot p2))
CLIPS>   
(deffacts family
   (of (relation father) (p1 "Henry") (p2 "Bob"))
   (of (relation father) (p1 "Henry") (p2 "Susie"))
   (of (relation father) (p1 "Henry") (p2 "Anton"))
   (of (relation mother) (p1 "Georgette") (p2 "Bob")))
CLIPS>    
(defrule get-find ""
    =>
    (printout t "Enter a person in the family: ")
    (bind ?p1 (readline))
    (printout t "Enter another person in the family: ")
    (bind ?p2 (readline))
    (assert (find (p1 ?p1) (p2 ?p2))))
CLIPS>     
(defrule get-relationship
   (find (p1 ?p1) (p2 ?p2))
   (of (relation ?relation) (p1 ?p1) (p2 ?p2))
   =>
   (printout t ?p1 " is a " ?relation " of " ?p2 crlf)))
CLIPS> 
(defrule done-find ""
    (declare (salience -10))
    ?f <- (find)
    =>
    (retract ?f))
CLIPS> (reset)
CLIPS> (run)
Enter a person in the family: Georgette
Enter another person in the family: Bob
Georgette is a mother of Bob
CLIPS>

Upvotes: 2

Related Questions