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.
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>
Am writing a project, my code will be in the form as describe below in the code, Is there any need to include salience and how can I use interface? The software will require the user to answer a question in the form of yes or no. I want to know how to do this in the form of checkboxes, where the user will tick the appropriate symptoms of a disease, then the software will be able to predict the kind of disease. thank you . please help
CLIPS> (defrule bacterial-fruit-blotch-of-watermelon
=>
(print "Is the plant showing a symptom of Oily and water-soaked cotyledons? ")
(assert (OWS (read)))
(print "Is the plant showing a symptom of Yellow halo paralleling veins? ")
(assert (YHP (read)))
(print "Is the plant showing a symptom of Small dark and angled lesion on leaves? ")
(assert (SDA (read)))
(print "Is the plant showing a symptom of Dark green blotch on the upper surface of developing fruit? ")
(assert (DGB (read))))
CLIPS> (defrule check
(OWS yes)
(YHP yes)
(SDA yes)
(DGB yes)
=>
(println "The plant is showing a symptom of bacterial fruit blotch of watermelon disease."))
CLIPS> (defrule bacterial-rind-necrosis
=>
(print " Is the plant showing a symptom of corky, dry necrosis? ")
(assert (corky (read)))
(print " Is the plant showing a symptom of misshapen? ")
(assert (misshaping (read)))
(print " Is the plant showing a symptom of dark ,water-soaked depression? ")
(assert (dark (read))))
CLIPS> (defrule check-two
(corky yes)
(misshaping yes)
(dark yes)
=>
(println "The plant is showing a symptom of bacterial rind necrosis of watermelon disease."))
CLIPS> (reset)
CLIPS> (run)
Is the plant showing a symptom of Oily and water-soaked cotyledons? no
Is the plant showing a symptom of Yellow halo paralleling veins? n
Is the plant showing a symptom of Small dark and angled lesion on leaves? no
Is the plant showing a symptom of Dark green blotch on the upper surface of developing fruit? no
Is the plant showing a symptom of corky, dry necrosis? yes
Is the plant showing a symptom of misshapen? yes
Is the plant showing a symptom of dark ,water-soaked depression? yes
The plant is showing a symptom of bacterial rind necrosis of watermelon disease.
CLIPS>
If you want to provide flexibility in how your program interacts with the user, the best thing to do is to separate the code that reasons about symptoms and diseases from the code that interacts with the user. In your current implementation, these are intermingled.
To reimplement your code, first define a deftemplate for representing the symptoms and their associated questions:
(deftemplate symptom
(slot id)
(slot question)
(slot indicative (default yes)))
The indicative slot represents the response to a question that is indicative of a problem. So if the question is "Are the leaves a sickly yellow?", the indicative response would be yes, and if the question is "Are the leaves a healthy green?", the indicative response would be no.
The symptoms from your rules can now be represented as a group of facts:
(deffacts symptoms
(symptom (id ows)
(question "Is the plant showing a symptom of Oily and water-soaked cotyledons?"))
(symptom (id yhp)
(question "Is the plant showing a symptom of Yellow halo paralleling veins?"))
(symptom (id sda)
(question "Is the plant showing a symptom of Small dark and angled lesion on leaves?"))
(symptom (id dgb)
(question "Is the plant showing a symptom of Dark green blotch on the upper surface of developing fruit?"))
(symptom (id corky)
(question "Is the plant showing a symptom of corky, dry necrosis?"))
(symptom (id misshaping)
(question "Is the plant showing a symptom of misshapen?"))
(symptom (id dark)
(question "Is the plant showing a symptom of dark, water-soaked depression?"))
)
The diseases can be similarly represented as a group of facts:
(deftemplate disease
(slot id)
(multislot symptoms))
(deffacts diseases
(disease (id "bacterial fruit blotch")
(symptoms ows yhp sda dgb))
(disease (id "bacterial rind necrosis")
(symptoms corky misshaping dark))
)
The responses to questions and any disease conclusions will also be represented as facts:
(deftemplate answer
(slot id)
(slot value))
(deftemplate conclusion
(slot id))
With the symptoms and diseases represented as data, we can now add a generic rule which determines if every symptom of a disease is present:
(defrule conclude-disease
;; There is a disease
(disease (id ?disease))
;; For every symptom of that disease
(forall (disease (id ?disease)
(symptoms $? ?symptom $?))
(symptom (id ?symptom)
(indicative ?value))
;; There is a response indicative
;; of a problem
(answer (id ?symptom)
(value ?value)))
=>
;; Conclude the plant has the disease
(assert (conclusion (id ?disease))))
Now we can add code to handle interacting with the user. We'll start with your initial approach of using the keyboard to get responses from the user:
(deffunction ask-question (?question $?allowed-values)
(printout t ?question " " ?allowed-values " ")
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer)))
(while (not (member$ ?answer ?allowed-values)) do
(printout t ?question " " ?allowed-values " ")
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer))))
?answer)
(defrule ask-symptom
;; There is a symptom
(symptom (id ?symptom)
(question ?question))
;; For a disease
(disease (id ?disease)
(symptoms $? ?symptom $?))
;; That we have not determined
(not (answer (id ?symptom)))
;; And there is no prior response to a symptom
;; of that disease that is non-indicative.
(not (and (disease (id ?disease)
(symptoms $? ?other-symptom $?))
(symptom (id ?other-symptom)
(indicative ?value))
(answer (id ?other-symptom)
(value ~?value))))
=>
;; Ask the user the symptom question
(bind ?value (ask-question ?question yes no))
;; And assert the response.
(assert (answer (id ?symptom)
(value ?value))))
The ask-symptom rule improves upon the prior approach by not asking about symptoms for diseases that have a non-indicative response for a symptom. So if the response to necrosis is no, the user will not be asked about misshapen or depression.
Finally, some rules can be added to display the conclusions. These rules are given lower salience so that all of the questions are asked before any conclusion is displayed.
(defrule print-conclusion
(declare (salience -10))
(conclusion (id ?disease))
=>
(println "The plant is showing symptoms of " ?disease " watermelon disease."))
(defrule print-no-conclusion
(declare (salience -10))
(not (conclusion))
=>
(println "The plant is not showing all symptoms of a watermelon disease."))
If you want to use an interface rather than interacting through a console, you'd need to replace the code just added for asking questions and displaying conclusions.
CLIPS provides for querying the fact-list. For example, here's how you'd get a list of all the symptom facts from the CLIPS command prompt:
CLIPS> (find-all-facts ((?s symptom)) TRUE)
(<Fact-1> <Fact-2> <Fact-3> <Fact-4> <Fact-5> <Fact-6> <Fact-7>)
CLIPS>
What you can do in your interface is to query CLIPS for all of the symptom facts and then dynamically create the check boxes to display using the slot values in the facts.
When the user is ready for a response, you could have a diagnose button in your interface. When the user clicks that button, you can assert an answer fact with the appropriate values for each check box. After asserting those facts, you can run CLIPS and then use the query functions to retrieve the conclusion facts and then display the results. Alternately, any time a checkbox is changed you can assert the facts and run CLIPS.
If you download CLIPS from SourceForge, there are examples of integrating CLIPS with GUIs for .NET, Java, and iOS.
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'm trying to get user to input a book name, then test if the book exists in the library. If not the program should ask him to enter the book details. But the program sees all input as a new book. Is my comparing the two values wrong or my readline?
Code so far:
(deftemplate book (slot name) (slot author) (slot code))
(deffacts current-lib
(book (name "Alice in Wonderland") (author Lewis-Carroll) (code CAR))
(book (name "The Bourne Supremacy") (author Robert-Ludlum) (code LUD)))
(defrule readnew "inputs potential new book details"
=>
(printout t "Enter the name of the book:")
(bind ?b_name (readline))
(assert (potential ?b_name)))
(defrule add-book "determine if book already exists otherwise add"
?out <- (potential ?newname)
(and (potential ?newname)
(not (book (name ?b_name&?newname) (author $?))))
=>
(printout t "Book is new, please enter the author's name:" crlf)
(bind ?auth (readline))
(printout t "Please enter a three letter code for the book:" crlf)
(bind ?coode (read))
(assert (book (name ?newname) (author ?auth) (code ?coode)))
(retract ?out))
You provided code, but not the steps you took to run it so I'll have to guess at the cause of your problem. The simplest explanation would be that you did not issue a reset command to assert the facts in your current-lib deffacts.
I made a few changes to your code. In your current-lib deffacts, the author names should be strings since you're using readline in your add-book rule to get the names. There is also unnecessary code in the conditions of your add-book rule.
CLIPS (6.31 2/3/18)
CLIPS>
(deftemplate book
(slot name)
(slot author) (slot code))
CLIPS>
(deffacts current-lib
(book (name "Alice in Wonderland") (author "Lewis Carroll") (code CAR))
(book (name "The Bourne Supremacy") (author "Robert Ludlum") (code LUD)))
CLIPS>
(defrule readnew
=>
(printout t "Enter the name of the book:" crlf)
(bind ?b_name (readline))
(assert (potential ?b_name)))
CLIPS>
(defrule add-book
?out <- (potential ?newname)
(not (book (name ?newname)))
=>
(printout t "Book is new, please enter the author's name:" crlf)
(bind ?auth (readline))
(printout t "Please enter a three letter code for the book:" crlf)
(bind ?coode (read))
(assert (book (name ?newname) (author ?auth) (code ?coode)))
(retract ?out))
CLIPS>
Now, if you add a book that doesn't exist you'll be ask for the additional information.
CLIPS> (reset)
CLIPS> (run)
Enter the name of the book:
Ringworld
Book is new, please enter the author's name:
Larry Niven
Please enter a three letter code for the book:
RNG
CLIPS>
If you try to add a book that doesn't exist, the add-book rule won't execute.
CLIPS> (reset)
CLIPS> (run)
Enter the name of the book:
Alice in Wonderland
CLIPS>
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))