So I'm trying to build a program that takes user's input by displaying a message on the screen “Enter your subject”.
In the second rule, I'm to mention subject names “artificial intelligence”, “operating system” and “compiler construction” and check that entered subject from the first rule matches with the mentioned subjects by displaying this message on the screen.
“Your entered subject is true”.
Here is the code:
(deftemplate subject
(slot subject)
(slot artificial intelligence)
(slot operating system)
(slot compiler construction))
(defrule reading-input
(printout t "Enter your subject:")
(assert(var(read))))
(defrule checking-input
(var? artificial intelligence)
(var? operating system)
(var? compiler construction)
(com(artificial intelligence ? artificial intelligence))
(test(=?artificial intelligence ? artificial intelligence))
(test(=?operating system ? operating system))
(test(=? compiler construction ? compiler construction))
(=>
printout t "Your entered subject is true:"))
CLIPS (6.31 6/12/19)
CLIPS>
(defrule reading-input
=>
(printout t "Enter your subject: ")
(assert (var (readline))))
CLIPS>
(defrule checking-input
(var "artificial intelligence" |
"operating system" |
"compiler construction")
=>
(printout t "Your entered subject is true." crlf))
CLIPS> (reset)
CLIPS> (run)
Enter your subject: operating system
Your entered subject is true.
CLIPS> (reset)
CLIPS> (run)
Enter your subject: algorithms
CLIPS>
Related
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.
So here's my CLIPS code
CLIPS> (deftemplate animal
(slot name)
(slot favourite-food)
(slot habitat)
(slot main-prey)
(multislot predators)
(slot distinctive-features))
CLIPS> (deffacts animal
(animal (name Sumatran-Elephant)
(favourite-food grass)
(habitat "Rainforest and tropical woodland")
(main-prey "grass, fruit, roots")
(predators Human Tiger)
(distinctive-features "Long trunk and large feet"))
(animal (name Monkey)
(favourite-food fruit)
(habitat "Tropical forests, grasslands and mountainous plains")
(main-prey "Fruit, Seeds, Insects")
(predators Birds Snakes Wildcats)
(distinctive-features "Long, agile tail and loud vocal calls"))
(animal (name Magpie)
(favourite-food fruit)
(habitat "Open woodland, grasslands and savannas")
(main-prey "Fruit, Nuts, Seeds, Insects")
(predators Foxes Cats Coyote)
(distinctive-features "Black and white markings and long wedge-shaped tail")))
CLIPS> (deftemplate find-predators(slot predators))
CLIPS> (defrule find-predators
(find-predators(predators ?predator_name))
(animal(name ?name)
(predators $?other1 ?predator_name $?other2))
=> (printout t ?predator_name " is the predator of " ?name crlf
"Other predators are " ?other1 ?other2 crlf))
CLIPS> (reset)
CLIPS> (assert(find-predators(predators Human)))
<Fact-4>
CLIPS> (run)
Human is the predator of Sumatran-Elephant
Other predators are ()(Tiger)
CLIPS> (assert(find-predators(predators Coyote)))
<Fact-5>
CLIPS> (run)
Coyote is the predator of Magpie
Other predators are (Foxes Cats)()
But the answer should be like this
Coyote is the predator of Magpie
Other predators are (Foxes) (Cats)
How do I split the facts for the multi slots above?
Need helps if anyone know the best default that can be replaced from the above code
Combine the multifield values in the variables $?other and $?other2 into a single multifield value and then use the implode$ function to convert that value into a string with spaces between the predator names.
(defrule find-predators
(find-predators (predators ?predator_name))
(animal (name ?name)
(predators $?other1 ?predator_name $?other2))
=>
(printout t ?predator_name " is the predator of " ?name crlf
"Other predators are " (implode$ (create$ ?other1 ?other2)) crlf))
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>
is there a way to output the name of the fired rule in CLIPS?
Example:
(defrule this-is-my-rule
...
=>
(printout t "this-is-my-rule: and these are the outputs" crlf) ;;#1
)
Instead of writing manually the name of the rule in #1, I'd like to use a psecific command (if any).
Is it possible, please?
Thank
Nicola
There isn't a mechanism for programmatically determining the name of the currently executing rule, but you can use the watch debugging command to print the name of each rule as it is executed:
CLIPS> (defrule rule-1 =>)
CLIPS> (defrule rule-2 =>)
CLIPS> (defrule rule-3 =>)
CLIPS> (watch rules)
CLIPS> (run)
FIRE 1 rule-3: *
FIRE 2 rule-2: *
FIRE 3 rule-1: *
CLIPS>
Here is my code
(deffacts startup
(bird canary)
(colour-canary yellow)
(bird ostrich)
(can-not-fly ostrich)
)
(defrule r-bird-test
(bird ?var)
(not (bird ostrich))
=>
(printout t ?var " ****" crlf)
)
Now, when i (reset) and (run) it doesn't print "canary ****". Am i not using the not condition properly? Can anyone point out what i am missing here? Thanks.
As written the not conditional element prevents the rule from executing if the fact (bird ostrich) is present. Since that fact is present once you perform a (reset), the rule does not execute. If you want the rule to execute for each bird fact where ?var is not ostrich, you need to write the rule this way:
CLIPS>
(deffacts startup
(bird canary)
(colour-canary yellow)
(bird ostrich)
(can-not-fly ostrich))
CLIPS>
(defrule r-bird-test
(bird ?var&~ostrich)
=>
(printout t ?var " ****" crlf))
CLIPS> (reset)
CLIPS> (run)
canary ****
CLIPS>