How to use comparison operators on previous user input in CLIPS? - clips

I'm a beginner to CLIPS. The goal of this program is to return the name of the company that best matches the user's demographics. I ask the user their gender and (might be storing it wrong) store it into input, ethnicity stored into input2, and age into input3. I'm running into errors when trying to do comparisons to return the company name. Eg. if input=1 (man), then compare the demographics of men in both companies and return the name of the company with more men.
(= 1 input) this line in the last rule gives me error "Function '=' expected argument #2 to be of type integer or float." which I thought I've already only allowed responses of integers. Any help would be appreciated, thank you!
(deftemplate company
(slot name)
(slot men)
(slot women)
(slot Asian)
(slot Black)
(slot Latinx)
(slot Indigenous)
(slot White)
(slot Other)
(slot <18)
(slot 18-20)
(slot 21-29)
(slot 30-39)
(slot 40+))
(deffacts demographics
(company (name Google)(men 0.669)(women 0.331)(Asian 0.428)(Black 0.088)(Latinx 0.088)(Indigenous 0.007)(White 0.445)(Other 0)(<18 0.02)(18-20 0.11)(21-29 0.59)(30-39 0.19)(40+ 0.07))
(company (name Apple)(men 0.652)(women 0.348)(Asian 0.279)(Black 0.094)(Latinx 0.148)(Indigenous 0.007)(White 0.438)(Other 0.032)(<18 0.01)(18-20 0.1)(21-29 0.57)(30-39 0.22)(40+ 0.06)))
(defrule begin => (assert (phase select-gender)))
(defrule menu (phase select-gender) =>
(printout t "Do you identify as a (1) man or (2) woman?: ") (assert (userinput (read))))
(defrule selection-okay
?phase <- (phase select-gender)
?input <- (userinput ?select&1|2)
=>
(retract ?phase)
(assert (selection ?select))
(assert (phase select-ethnicity)))
(defrule selection-nokay
?phase <- (phase select-gender)
?input <- (userinput ?select&~1&~2)
=>
(retract ?phase)
(assert (phase select-gender))
(printout t ?select " is not a valid response. Please enter 1 or 2."crlf))
(defrule menu2 (phase select-ethnicity) =>
(printout t "Do you identify as (1)Asian, (2)Black, (3)Latinx, (4)Indigenous, (5)White, or (6)Other?: ") (assert (userinput2 (read))))
(defrule selection-okay2
?phase <- (phase select-ethnicity)
?input2 <- (userinput2 ?select&1|2|3|4|5|6)
=>
(retract ?phase)
(assert (selection ?select))
(assert (phase select-age)))
(defrule selection-nokay2
?phase <- (phase select-ethnicity)
?input2 <- (userinput2 ?select&~1&~2&~3&~4&~5&~6)
=>
(retract ?phase)
(assert (phase select-ethnicity))
(printout t ?select " is not a valid response. Please enter 1 through 6."crlf))
(defrule menu3 (phase select-age) =>
(printout t "You are age: (1)<18, (2)18-20, (3)20-30, (4)30-40, (5)40+?: ") (assert (userinput3 (read))))
(defrule selection-okay3
?phase <- (phase select-age)
?input3 <- (userinput3 ?select&1|2|3|4|5)
=>
(retract ?phase)
(assert (selection ?select))
(assert (phase company-gender-men)))
(defrule selection-nokay3
?phase <- (phase select-age)
?input3 <- (userinput3 ?select&~1&~2&~3&~4&~5)
=>
(retract ?phase)
(assert (phase select-age))
(printout t ?select " is not a valid response. Please enter 1 through 5."crlf))
(defrule get-company-by-gender-men
?phase <- (company-gender-men)
(= 1 input)
(> (fact-slot-value 1 men) (fact-slot-value 2 men))
=>
(retract ?phase)
(printout t (fact-slot-value 1 name) crlf))
;(fact-slot-value 1 name)
;(> (fact-slot-value 1 men) (fact-slot-value 2 men))
I have tried removing some extra code just to see if I can access the previous user input but I'm still not getting an output.
(deftemplate company
(slot name)
(slot men)
(slot women)
(slot Asian)
(slot Black)
(slot Latinx)
(slot Indigenous)
(slot White)
(slot Other)
(slot <18)
(slot 18-20)
(slot 21-29)
(slot 30-39)
(slot 40+))
(deffacts demographics
(company (name Google)(men 0.669)(women 0.331)(Asian 0.428)(Black 0.088)(Latinx 0.088)(Indigenous 0.007)(White 0.445)(Other 0)(<18 0.02)(18-20 0.11)(21-29 0.59)(30-39 0.19)(40+ 0.07))
(company (name Apple)(men 0.652)(women 0.348)(Asian 0.279)(Black 0.094)(Latinx 0.148)(Indigenous 0.007)(White 0.438)(Other 0.032)(<18 0.01)(18-20 0.1)(21-29 0.57)(30-39 0.22)(40+ 0.06)))
(defrule begin => (assert (phase select-gender)))
(defrule menu (phase select-gender) =>
(printout t "Do you identify as a (1) man or (2) woman?: ") (assert (userinput (read)))(assert(phase select-ethnicity)))
(defrule menu2 (phase select-ethnicity) =>
(printout t "Do you identify as (1)Asian, (2)Black, (3)Latinx, (4)Indigenous, (5)White, or (6)Other?: ") (assert (userinput2 (read)))(assert(phase select-age)))
(defrule menu3 (phase select-age) =>
(printout t "You are age: (1)<18, (2)18-20, (3)20-30, (4)30-40, (5)40+?: ") (assert (userinput3 (read)))(assert(phase company-gender-men)))
(defrule get-company-by-gender-men
?phase <- (company-gender-men)
(userinput ?userinput)
=>
(retract ?phase)
(printout t ?userinput "can see user input"crlf))

(defrule get-company-by-gender-men
?phase <- (phase company-gender-men)
(userinput 1)
(company (name ?name) (men ?men1))
(company (men ?men2))
(test (> ?men1 ?men2))
=>
(retract ?phase)
(printout t ?name crlf))

Related

Can I have a deptemplate inside a fact

(deftemplate andprop (slot symbol1)(slot symbol2))
(deftemplate orprop (slot symbol1)(slot symbol2))
(deftemplate implies (multislot premise)(multislot
implication))
(deftemplate sentence (multislot sent))
(defrule read-from-user
=>
(printout t "Please enter a value: " crlf)
(bind ?response (read))
(assert (sentence (sent andprop(symbol1 ?response)
(symbol2 ?response)))))
I am writing a CLIPS program to simulate the propsitional logic identities but when I try to run this piece of code i get the following
[EXPRNPSR3] Missing function declaration for 'symbol1'.
ERROR:
(defrule MAIN::read-from-user
=>
(printout t "Please enter a value: " crlf)
(bind ?response (read))
(assert (sentence (sent andprop (symbol1
You can set the value of a slot to another fact:
CLIPS (6.31 2/3/18)
CLIPS>
(deftemplate andprop
(slot symbol1)
(slot symbol2))
CLIPS>
(deftemplate orprop
(slot symbol1)
(slot symbol2))
CLIPS>
(deftemplate implies
(multislot premise)
(multislot implication))
CLIPS>
(deftemplate sentence
(multislot sent))
CLIPS>
(defrule read-from-user
=>
(printout t "Please enter a value: " crlf)
(bind ?response (read))
(bind ?sent (assert (andprop (symbol1 ?response)
(symbol2 ?response))))
(assert (sentence (sent ?sent))))
CLIPS> (run)
Please enter a value:
45678
CLIPS> (facts)
f-0 (initial-fact)
f-1 (andprop (symbol1 45678) (symbol2 45678))
f-2 (sentence (sent <Fact-1>))
For a total of 3 facts.
CLIPS>

correlation between deffunctions and defrules CLIPS

(deftemplate client
(slot idClient (type INTEGER))
(multislot nome)
(multislot birthdate)
(multislot registryCard)
(multislot endOfRegistryCard))
(deffunction reservation(?idfunc)
(build (str-cat"(defrule existsClient
(exists(client(idClient ?idfunc)))
=>
(printout t "exists" ?idfunc crlf))"
))
(run)
)
I made this deffunction and I want to see if exists the client with that idfunc that is received as parameter. what happens is that the defrule inside doesn't process this variable any thoughts how can i resolve?
I think you should set condition (assert your idfunc) and then fire the execution of your "existsClient" rule (defined as rule and not inside your function). That would be a clearer design in my opinion.
Typically you'll directly define your rules rather than using a deffunction, but here's how you can do it both ways:
CLIPS> (clear) ; Create rule and run with deffunction
CLIPS>
(deftemplate client
(slot idClient (type INTEGER))
(multislot nome)
(multislot birthdate)
(multislot registryCard)
(multislot endOfRegistryCard))
CLIPS>
(deffunction reservation (?idfunc)
(build (str-cat
"(defrule existsClient
(exists (client (idClient " ?idfunc ")))
=>
(printout t \"exists " ?idfunc "\" crlf))"))
(assert (client (idClient ?idfunc)))
(run))
CLIPS> (reservation 2)
exists 2
CLIPS> (ppdefrule existsClient)
(defrule MAIN::existsClient
(exists
(client (idClient 2)))
=>
(printout t "exists 2" crlf))
CLIPS> (clear) ; Create rule directly
CLIPS>
(deftemplate client
(slot idClient (type INTEGER))
(multislot nome)
(multislot birthdate)
(multislot registryCard)
(multislot endOfRegistryCard))
CLIPS>
(defrule existsClient
(exists (client (idClient 2)))
=>
(printout t "exists 2" crlf))
CLIPS> (ppdefrule existsClient)
(defrule MAIN::existsClient
(exists
(client (idClient 2)))
=>
(printout t "exists 2" crlf))
CLIPS> (assert (client (idClient 2)))
<Fact-1>
CLIPS> (run)
exists 2
CLIPS>

how to get the index of facts in RHS of rule?

I'm asking if there is a possibility of accessing a get the index of fact in RHS of defrule ?
It gives me that undefined every time I try to index a fact in a RHS of defrule.
because I have a while loop , I want to be able to modify elevator fact depending on my input data.
(deftemplate elevator
(slot goal))
(deffacts elevator
(elevator (goal 0)))
(defrule read-data
=>
?f1 <- (elevator)
(modify ?f2 (goal 1))
)
this an example of my code , since I can't put all online :
(deftemplate data
(slot data)
)
(deffacts data
(data (data 1))
)
(defrule rule1
?f1 <-(data)
=>
(bind ?value (readline input) )
(while (neq ?value EOF)
do
(bind ?data (fact-slot-value ?f1 data))
(printout t "data " ?data crlf )
(retract ?f1)
(modify ?f1 (data ?value))
(bind ?value (readline input)
)
)
)
this is my input file :
2
3
4
5
6
7
this is what I'm getting :
CLIPS> (run)
data 1
data FALSE
data FALSE
data FALSE
data FALSE
data FALSE
CLIPS>
I want it to print out
data 2
data 3
data 4 ..ect
You can do it this way from the RHS of a rule, but if your rule actually has no LHS conditions, it's pointless to use a rule to change the value of the fact. Just use a function.
CLIPS>
(deftemplate elevator
(slot goal))
CLIPS>
(deffacts elevator
(elevator (goal 0)))
CLIPS>
(defrule read-data
=>
(do-for-fact ((?f elevator)) TRUE
(modify ?f (goal 1))))
CLIPS> (watch facts)
CLIPS> (reset)
<== f-0 (initial-fact)
==> f-0 (initial-fact)
==> f-1 (elevator (goal 0))
CLIPS> (run)
<== f-1 (elevator (goal 0))
==> f-2 (elevator (goal 1))
CLIPS>
Alternately, you can bind the fact you want to modify in the conditions of the rule:
CLIPS> (clear)
CLIPS>
(deftemplate elevator
(slot goal))
CLIPS>
(deffacts elevator
(elevator (goal 0)))
CLIPS>
(defrule read-data
?f <- (elevator (goal 0))
=>
(modify ?f (goal 1)))
CLIPS> (watch facts)
CLIPS> (reset)
<== f-0 (initial-fact)
==> f-0 (initial-fact)
==> f-1 (elevator (goal 0))
CLIPS> (run)
<== f-1 (elevator (goal 0))
==> f-2 (elevator (goal 1))
CLIPS>
Updated:
You can get your original rule to "work" by removing the retract and rebinding ?f1 to the value returned by modify:
CLIPS> (clear)
CLIPS>
(deftemplate data
(slot data))
CLIPS>
(deffacts data
(data (data 1)))
CLIPS>
(defrule rule1
?f1 <- (data)
=>
(bind ?value (readline input))
(while (neq ?value EOF)
(bind ?data (fact-slot-value ?f1 data))
(printout t "data " ?data crlf )
(bind ?f1 (modify ?f1 (data ?value)))
(bind ?value (readline input))))
CLIPS> (reset)
CLIPS> (open input.txt input)
TRUE
CLIPS> (run)
data 1
data 2
data 3
data 4
data 5
data 6
CLIPS> (close input)
TRUE
CLIPS>
It's still suspiciously complicated to be modifying the same fact multiple times on the RHS.

How to compare a global variable to a string in Clips?

In my system the user inputs a Y or N to answer simple questions. I call this rule after every question to increment a counter. There are some general problems with my code but i can't see where
(defrule QPain
(initial-fact)
=>
(printout t "Are You In Pain? " crlf)
(bind ?*Answer* (read))
)
(defrule IncSym
(test(=(str-compare (?*Answer*) "y")0))
=>
(bind ?*symcount* (+ ?*symcount* 1))
)
Thanks
The syntactic errors can be corrected as follows:
CLIPS> (clear)
CLIPS> (defglobal ?*Answer* = nil)
CLIPS> (defglobal ?*symcount* = 0)
CLIPS>
(defrule QPain
=>
(printout t "Are you in pain? ")
(bind ?*Answer* (read)))
CLIPS>
(defrule IncSym
(test (eq ?*Answer* y))
=>
(bind ?*symcount* (+ ?*symcount* 1)))
CLIPS> (reset)
CLIPS> (run)
Are you in pain? y
CLIPS> (show-defglobals)
?*Answer* = y
?*symcount* = 0
CLIPS>
This won't produce the behavior you're expecting, however, since ?*symcount* will not be incremented. The behavior of global variables and why you should not be using them in the manner you're attempting has been discussed previously:
How exactly (refresh) works in the clips?
CLIPS: forcing a rule to re-evaluate the value of a global variable?
Number equality test fails in CLIPS pattern matching?
CLIPS constant compiler directive
How can I run the clips with out reset the fact when using CLIPS
Instead of using global variables to track responses and symptoms, you should use facts or instances. Here's one approach:
CLIPS> (clear)
CLIPS>
(deftemplate symptom
(slot id)
(slot response))
CLIPS>
(deftemplate symptom-list
(multislot values))
CLIPS>
(deffacts initial
(symptom-list))
CLIPS>
(defrule QPain
=>
(printout t "Are you in pain? ")
(assert (symptom (id in-pain) (response (read)))))
CLIPS>
(defrule IncSym
(symptom (id ?id) (response y))
?f <- (symptom-list (values $?list))
(test (not (member$ ?id ?list)))
=>
(modify ?f (values ?list ?id)))
CLIPS>
(defrule symptoms-found
(declare (salience -10))
(symptom-list (values $?list))
=>
(printout t "Symptom count: " (length$ ?list) crlf))
CLIPS> (reset)
CLIPS> (run)
Are you in pain? y
Symptom count: 1
CLIPS> (reset)
CLIPS> (run)
Are you in pain? n
Symptom count: 0
CLIPS>
And another:
CLIPS> (clear)
CLIPS>
(deftemplate symptom
(slot id)
(slot response))
CLIPS>
(defrule QPain
=>
(printout t "Are you in pain? ")
(assert (symptom (id in-pain) (response (read)))))
CLIPS>
(defrule symptoms-found
(declare (salience -10))
=>
(bind ?count (find-all-facts ((?f symptom)) (eq ?f:response y)))
(printout t "Symptom count: " (length$ ?count) crlf))
CLIPS> (reset)
CLIPS> (run)
Are you in pain? y
Symptom count: 1
CLIPS> (reset)
CLIPS> (run)
Are you in pain? n
Symptom count: 0
CLIPS>

Create rules in CLIPS to move from unknown to known person facts

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)))
)

Resources