I need to check the existence of a value for an o'bject's property in a LHS.
(defrule check-property
?room <- (object (is-a ROOM))
(integerp (send ?room get-property)) ; #1
=>
(printout ?*debug-print* "Room " ?room " has property" crlf))
But it seems to me that #1 is not valuated in LHS. Instead if I put it in RHS, it returns TRUE.
Where am I wrong?
Thx,
Nic
Use the test conditional element to evaluate an expression in the LHS of a rule:
(defrule check-property
?room <- (object (is-a ROOM))
(test (integerp (send ?room get-property)))
=>
(printout ?*debug-print* "Room " ?room " has property" crlf))
It's better to explicitly retrieve the slot value by matching it rather than using the slot accessor as this will cause the condition to be reevaluated whenever the slot value changes:
(defrule check-property
?room <- (object (is-a ROOM)
(property ?property))
(test (integerp ?property))
=>
(printout ?*debug-print* "Room " ?room " has property" crlf))
Related
this is a clips expert system code to make a diagnosis for a disease so i am trying to find out whats the problem in that code and i really dont know what to do
[CSTRCPSR1]
[CSTRCPSR2]
error
defrule diagnosis
(symptom ?s)
(disease (symptoms ?s) (name ?d))
=>
(printout t "The patient may have " ?d "." crlf))
(defrule ask-symptoms
(not (symptom ?))
=>
(bind ?symptom (read))
(assert (symptom ?symptom)))
(defrule ask-symptoms
(not (symptom ?))
=>
(printout t "What are the patient's symptoms?" crlf)
(bind ?symptom (read))
(assert (symptom ?symptom)))
(defrule ask-symptoms-2
(symptom ?s)
(not (symptom ?))
=>
(printout t "Any other symptom? " crlf)
(bind ?symptom (read))
(assert (symptom ?symptom)))
(defclass disease
(is-a USER)
(role concrete)
(multislot symptoms)
(slot name))
(definstances diseases
(disease (symptoms fever headache) (name "influenza"))
(disease (symptoms fever sorethroat) (name "strep throat"))
(disease (symptoms cough shortness-of-breath) (name "pneumonia"))
(disease (symptoms stomachache nausea) (name "food poisoning")))
i tried everything to fix it but i really dont know where is the problem
The diagnosis defrule is missing an opening parenthesis.
The diagnosis defrule references the disease defclass before the
class is defined.
Classes automatically have a name slot defined.
You have two ask-symptoms rules.
The conditions of the ask-symptoms-2 rule will never be satisfied.
Any fact matching the first pattern will cause the following pattern
to fail.
If you want to read multiple symptoms, use the readline function
along with the explode$ function.
In the diagnosis rule, you need to use the object keyword to match
an instance of a defclass.
In the diagnosis rule, the disease pattern can only be matched by
diseases with exactly one symptom.
For example:
CLIPS (6.4 2/9/21)
CLIPS>
(defclass disease
(is-a USER)
(role concrete)
(multislot symptoms)
(slot text))
CLIPS>
(defrule diagnosis
(object (is-a disease) (name ?name) (text ?d))
(exists
(symptoms $? ?s $?)
(object (is-a disease) (name ?name) (symptoms $? ?s $?)))
=>
(printout t "The patient may have " ?d "." crlf))
CLIPS>
(defrule ask-symptoms
=>
(printout t "What are the patient's symptoms? ")
(bind ?symptoms (readline))
(assert (symptoms (explode$ ?symptoms))))
CLIPS>
(definstances diseases
(influenza of disease (symptoms fever headache) (text "influenza"))
(strep-throat of disease (symptoms fever sorethroat) (text "strep throat"))
(pneumonia of disease (symptoms cough shortness-of-breath) (text "pneumonia"))
(food-poisoning of disease (symptoms stomachache nausea) (text "food poisoning")))
CLIPS> (reset)
CLIPS> (run)
What are the patient's symptoms? cough nausea
The patient may have pneumonia.
The patient may have food poisoning.
CLIPS>
I'm trying to define a rule by this form:
;Plantilla Ficha de paciente
(deftemplate FichaPaciente
(multifield Nombre)
(field Casado)
(field Direccion))
;Plantilla DatosExploración
(deftemplate DatosExploracion
(multifield Nombre)
(multifield Sintomas)
(field GravedadAfeccion))
;Regla para diagnóstico de Eccema
(defrule DiagnosticoEccema
(DatosExploracion
(and
(Nombre $?Nombre)
(or
(Sintomas $? picor $? vesiculas $?)
(Sintomas $? vesiculas $? picor $?)
)
)
)
(FichaPaciente
(Nombre $?Nombre))
=>
(printout t "Posible diagnóstico para el paciente " $?Nombre ": Eccema " crlf)
)
The goal is that it was not important if a DatosExploracion fact has the field Sintomas with values (... picor ... vesicula ...) or (... vesicula ... picor). Vesicula and picor order it's not important.
I'm trying with the "and" and "or" operators, but i receive the error: Invalid slot 'and' not defined in corresponding deftemplate 'DatosExploracion'.
1 - Why CLIPS don't recognize the AND and OR operators like i wanted?
2 - Is there a better or more efficient way of getting that the order of values on field Sintomas it's non important?
Thanks in advance.
Here's one way you can do it:
(defrule DiagnosticoEccema
(DatosExploracion
(Nombre $?Nombre)
(Sintomas $?Sintomas&:(and (member$ picor ?Sintomas)
(member$ vesiculas ?Sintomas))))
(FichaPaciente
(Nombre $?Nombre))
=>
(printout t "Posible diagnóstico para el paciente " $?Nombre ": Eccema " crlf))
And another which uses a helper function to reduce the amount of typing when there are multiple symptoms:
(deffunction all-present (?set1 $?set2)
(foreach ?s ?set2
(if (not (member$ ?s ?set1))
then (return FALSE)))
(return TRUE))
(defrule DiagnosticoEccema
(DatosExploracion
(Nombre $?Nombre)
(Sintomas $?Sintomas&:(all-present ?Sintomas picor vesiculas)))
(FichaPaciente
(Nombre $?Nombre))
=>
(printout t "Posible diagnóstico para el paciente " $?Nombre ": Eccema " crlf))
I've getted the goal on this way
(defrule DiagnosticoEccema
(or (DatosExploracion
(Nombre $?Nombre)
(Sintomas $? picor $? vesiculas $?))
(DatosExploracion
(Nombre $?Nombre)
(Sintomas $? vesiculas $? picor $?))
)
(FichaPaciente
(Nombre $?Nombre))
=>
(printout t "Posible diagnóstico para el paciente " $?Nombre ": Eccema " crlf)
)
But if it was a unordered combination of 3,4 or 5 Values for multifield Sintomas, it would be too tedious. I would like if there is a better way to get this using the connectives | or & in a more efficient way.
I am incrementing the variable inside an clips object by some number on RHS.
The rule is working, but going into infinite loop.
I tried running it without modifying the variable inside the object, it is coming into RHS once, but with modification it is going into loop.
(defrule modify
"modify"
(step 0)
?EA <- (object (is-a ALERT)
(ID ?RID&:(or(eq ?ID "R") (eq ?RID "Q")))
(TIME ?T)
)
=>
(bind ?time (send ?EA get-TIME))
(bind ?newTime (+ 86399 ?time))
(send ?EA put-TIME ?newTime)
(log_info (str-cat "old time is " ?time ", new time is " ?newTime "event time is " (send ?EA get-TIME)))
)
I am expecting the log to be printed once even after modifying the content inside object.
Thanks.
Removing the Slot on the LHS which we are incrementing on RHS fixed this.
(defrule modify
"modify"
(step 0)
?EA <- (object (is-a ALERT)
(ID ?RID&:(or(eq ?ID "R") (eq ?RID "Q")))
)
=>
(bind ?time (send ?EA get-TIME))
(bind ?newTime (+ 86399 ?time))
(send ?EA put-TIME ?newTime)
(log_info (str-cat "old time is " ?time ", new time is " ?newTime "event time is " (send ?EA get-TIME)))
)
If we keep slot TIME in LHS, after the change/increment the rule is getting re-triggered, and it is going in loop.
I know how to search to check whether fact slot exists, I need to know how to obtain the value of other slots in that fact
(deftemplate details
(slot name(type STRING))(slot occ (type STRING))......)
and
(deffacts details
(details (occ "student")(name "mike"))
(details (occ "professor")(name "john"))
.......
)
(defrule search
(userinfo(occ?occ))
(details(occ?occ) )
=>
?????????????????????????
)
Just bind them in the conditions of the rule:
(defrule search
(userinfo (occ ?occ))
(details (occ ?occ) (name ?name))
=>
(printout t "Name is " ?name crlf))
I am new to JESS and I know a little of its functionality. I have a program that asks for a students id-number and the program goes and gets the student's subjects.
The thing is by the end of procedure the program asks the user if he/she wants to get another student's subjects.
If the user wants to input another student, It will go back to the first rule that fired but when I tried that, the rule only activated and did not fire.
What could be the problem? I made sure there was (run) of course.
Here's my code.
(defrule check-subject
?a <- (phase check-back)
?stud <- (lookupID (id ?id))
(student-information (id-number ?id)
(course ?course)
(subjects-taken $?taken)
(year ?year)
(semester ?sem))
(prospectus-information (curriculum-name ?course)
(1st-year-1st-sem-subjects $?subjects1))
=>
(printout t "Student took: " (intersection$ $?taken $?subjects1) crlf)
(printout t "Student flunked: " (complement$ $?taken $?subjects1) crlf)
(assert (back-subject (complement$ $?taken $?subjects1)))
(retract ?a ?stud)
(ask))
And I have the function ask
(deffunction ask ()
(printout t "Consult another? (y/n) ")
(if (eq (read) y)
then (assert (phase choose-student))))
And my defrule when phase choose-student is asserted
(defrule student-select
(phase choose-student)
=>
(printout t "Input Student ID: ")
(assert (lookupID (id (read)))))
The rule student-select, activates but never fires. My program stops there.
It's better to write the control part of an application separate from the rules.
(deffunction ask ()
(printout t "Consult another? (y/n) ")
(if (eq (read) y) then
(printout t "Input Student ID: ")
(assert (lookupID (id (read))))
(return TRUE)
else
(return FALSE)))
Use this in a while function:
(while (ask) do (run))
And you won't need the (phase choose-student) any more.