So I'm trying to self-learn CLIPS and clipspy for a class assignment and I'm a bit stuck. The code below compiles and runs just fine but the output is a bit strange. I am trying to expand on examples I found in the manual.
import clips
import logging
env = clips.Environment()
logging.basicConfig(level=10, format='%(message)s')
router = clips.LoggingRouter()
router.add_to_environment(env)
env.build("""
(defrule whodunit
(shoot ?hunter ?who)
=>
(printout t ?hunter " shot " ?who crlf)
)""")
env.build("""
(defrule animalGame
(animal ?ani)
(shoot $? ?ani)
=>
(assert (game ?ani))
)""")
env.build("""
(defrule gameAnimal
(game ?ani)
=>
(assert (animal ?ani))
)""")
env.build("""
(defrule isIllegal
(shoot ?a ?b)
(not(game ?b))
=>
(assert (criminal ?a))
)""")
env.assert_string("(animal duck)")
env.assert_string("(animal dog)")
env.assert_string("(shoot Brian duck)")
env.assert_string("(shoot Bob rhino)")
env.assert_string("(game deer)")
env.run()
for fact in env.facts():
print(fact)
This outputs:
(initial-fact)
(animal duck)
(animal dog)
(shoot Brian duck)
(shoot Bob rhino)
(game deer)
(animal deer)
(criminal Bob)
(criminal Brian)
(game duck)
It seems that Brian is labeled a criminal for shooting an animal that is not game despite the animal he is shooting being declared game in the next step. Is there anyway to re-evaluate rules to fix this contradiction?
I figured it out. The answer is salience. I also realized there's some logical flaws/inconsistencies declaring all animals hunted as game and charging shooting animals that are not game as criminal. Anyways:
env.build("""
(defrule animalGame
(declare (salience 100))
(animal ?ani)
(shoot $? ?ani)
=>
(assert (game ?ani))
)""")
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>
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 have an expert system to figure out the corresponding animal. I have inserted all of the facts, however when I try to (run) the Expert System no question is asked, when the first question should be displayed as 'Is the animal big?' Does anyone have any idea please.
Many thanks in advance
(deffacts startup (animal mouse) (animal squirrel) (animal hamster) (animal giraffe) (animal elephant) (animal hippo)
(animal rhino) (animal big) (neck-long giraffe) (nose-long elephant) (swim-alot hippo) (animal-squeak mouse) (tail-bushy squirrel))
=>
(defrule is-animal-big
(not (animal-big ?))
=> (printout t "Is the animal big (yes or no)?")
(assert (animal-big (read))))
(defrule yes-big-check-neck
(animal-big yes)
(not (neck-long ?))
=>
(printout t "Is the animals neck long (yes or no)?")
(assert (neck-long (read))
)
(defrule neck-long-yes
(neck-long yes)
=>
(printout t "your animal is a giraffe" crlf)
(bind ?animal giraffe)
(assert (animal-is ? animal))
)
;;;========================================
(defrule neck-long-no-check-nose
(neck-long no)
(not (nose-long ?))
=>
(printout t "Is the animals nose long (yes or no)?")
(assert (nose-long (read))
)
(defrule nose-long-yes
(nose-long yes)
=>
(printout t "your animal is an elephant" crlf)
(bind ?animal elephant)
(assert (animal-is ? animal))
)
;;;=======================================
(defrule nose-long-no-check-swim
(nose-long no)
(not (swim-alot ?))
=>
(printout t "Does the animal swim a lot (yes or no)?")
(assert swim-alot (read((
)
(defrule swim-alot-yes
(swim-alot yes)
=>
(printout t "your animal is a hippo" crlf)
(bind ?animal hippo)
(assert (animal-is ? animal))
)
;;;=====================================
(defrule swim-alot-no
(swim-alot no)
=>
(printout t "your animal is a rhino" crlf)
(bind ?animal rhino)
(assert (animal-is ? animal))
)
;;;======================================
(defrule no-big-check-squeak
(animal-big no)
(not (animal-squeak ?))
=>
(printout t "Does the animal squeak (yes or no)?")
(assert animal-squeak (read))
)
(defrule animal-squeak-yes
(animal-squeak yes)
=>
(printout t "your animal is a mouse" crlf)
(bind ?animal mouse)
(assert (animal-is ? animal))
)
;;;=======================================
(defrule squeak-no-check-tail
(animal-squeak no)
(not (tail-bushy ?))
=>
(printout t "Is the animals tail bushy (yes or no)?")
(assert tail-bushy (read))
)
(defrule tail-bushy-yes
(tail-bushy yes)
=>
(printout t "your animal is a squirrel" crlf)
(bind ?animal squirrel)
(assert (animal-is ? animal))
)
;;;=======================================
(defrule tail-bushy-no
(tail-bushy no)
=>
(printout t "your animal is a hamster" crlf)
(bind ?animal hamster)
(assert (animal is ? animal)))
;;;==============================
;;;******************************
Your code is riddled with syntax errors, but the startup deffacts and is-animal-big defrule compile without errors. You're probably not issuing a (reset) command to assert the facts within your deffacts before issuing a (run) command.
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>
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>