How to make CLIPS program work? - clips

I am new to CLIPS and I thought of looking over existing solved problems for a start and try to figure it backwards. There is the following problem found in Giarratano-Riley: Expert Systems and Programming 3rd edition and it states the following:
Fires are classified according to the principal burning material.
Translate the following information to rules for determining fire
class.
Type A fires involve ordinary combustibles such as paper, wood, and cloth.
Type B fires involve flammable and combustible liquids (such as
oil and gas), greases, and similar materials.
Type C fires involve energized electrical equipment.
Type D fires involve combustible metals such as magnesium, sodium, and potassium.
The type of extinguisher that should be used on a fire depends on the fire class.
Translate the following information to rules.
Class A fires should be extinguished with heat-absorbing or
combustion-retarding extinguishers such as water or water-based
liquids and dry chemicals.
Class B fires should be extinguisher by mexcluding air, inhibiting the release of
combustible vapors, or interrupting the combustion chain reaction. Extinguishers
include dry chemicals, carbon dioxide, foam, and bromotrifluoromethane.
Class C fires should be extinguished with a non conducting agent to prevent
short circuits. If possible the power should be cut. Extinguishers
include dry chemicals, carbon dioxide, and bromotrifluoromethane.
Class D fires should be extinguished with smothering and heat- absorbing chemicals > that do not react with the burning metals. Such chemicals include trimethoxyboroxine
and screened graphitized coke.
Describe the facts used in the rules. The input to the program should be made by asserting the type of burning material as a fact. The output should indicate which extinguishers may be used and other actions that should be taken, such as cutting off the power. Show that your program works for one material form each of the fire classes.
And then it is solved by Berkely and the code is the following. My question is, how do I call these rules and make the program work? I loaded the buffer, reset, run and it only loads the rules into the command-line.
; Define templates used in rules
(deftemplate fire (slot burning-material))
(deftemplate extinguisher-system (multislot function) (multislot extinguisher))
(deftemplate response (multislot actions))
(deftemplate fire-class (slot class))
; Define rules for determining fire classes
(defrule class-A-fire
(fire (burning-material paper | wood | cloth | other-ordinary-combustibles)) =>
(assert (fire-class (class A))))
(defrule class-B-fire
(fire (burning-material oil | gas | greases | other-flammable-combustible-liquids)) =>
(assert (fire-class (class B))))
(defrule class-C-fire
(fire (burning-material energized-electrical-equipment)) =>
(assert (fire-class (class C))))
(defrule class-D-fire
(fire (burning-material magnesium | sodium | potassium | other-combustible-metals)) =>
(assert (fire-class (class D))))
; Define rules for determining the type of extinguisher that should be used on a fire
(defrule class-A-emergency
(fire-class (class A))
=>
(assert (response (actions activate-extinguisher-A)))
(assert (extinguisher-system (function heat-absorbing combustion-retarding) (extinguisher water water-based-liquids dry-chemicals))))
(defrule class-B-emergency
(fire-class (class B))
=>
(assert (response (actions activate-extinguisher-B)))
(assert (extinguisher-system (function excluding-air inhibiting-release-of-combustible-vapors interrupting-combustion-chain-reaction) (extinguisher dry-chemicals carbon-dioxide foam bromotrifluoromethane))))
(defrule class-C-emergency
(fire-class (class C))
=>
(assert (response (actions activate-extinguisher-C power-cut)))
(assert (extinguisher-system (function nonconducting-agent) (extinguisher dry-chemicals carbon-dioxide bromotrifluoromethoane))))
(defrule class-D-emergency
(fire-class (class D))
=>
(assert (response (actions activate-extinguisher-D)))
(assert (extinguisher-system (function smothering-heatabsorbing-chemicals) (extinguisher trimethoxyboroxine screened-graphitized-coke))))

I guess you made it until here:
CLIPS> Loading Selection...
Defining deftemplate: fire
Defining deftemplate: extinguisher-system
Defining deftemplate: response
Defining deftemplate: fire-class
Defining defrule: class-A-fire +j+j
Defining defrule: class-B-fire +j+j
Defining defrule: class-C-fire +j+j
Defining defrule: class-D-fire +j+j
Defining defrule: class-A-emergency +j+j
Defining defrule: class-B-emergency +j+j
Defining defrule: class-C-emergency +j+j
Defining defrule: class-D-emergency +j+j
CLIPS> (reset)
Now you need to load the problem data. For example, for a wood fire:
CLIPS> (assert (fire (burning-material wood)))
<Fact-1>
CLIPS> (facts)
f-0 (initial-fact)
f-1 (fire (burning-material wood))
And the, run the rules engine
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (fire (burning-material wood))
f-2 (fire-class (class A))
f-3 (response (actions activate-extinguisher-A))
f-4 (extinguisher-system (function heat-absorbing combustion-retarding) (extinguisher water water-based-liquids dry-chemicals))
And clean it to check the next problem
CLIPS> (reset)
CLIPS> (assert (fire (burning-material gas)))
<Fact-1>
CLIPS> (run)
...

Related

hey i have a problem in this clips code can any one please fix it?

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>

CLIPS/clipspy Rule Order

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

CLIPS: reference to ruleName

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>

How to debug "Check appropriate syntax for defrule" in Clips rule engine?

(deftemplate illness
(slot sickness)
(multislot keywords))
(deffacts qestion-refrences
(illness (sickness stunted-Groth)(keywords stunted groth))
(illness (sickness pale-Yellow) (keywords pale yellow))
(illness (sickness reddish-Brown)(keywords reddish brown))
(illness (sickness stunted-Root)(keywords stunted root)))
(deffunction askquestion (?question)
(printout t ?question)
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer)))
?answer)
(defrule determineSickness
(bind ?f (askquestion "whot Does the plant seem to have ? "))
(illness (keywords ?kw) (sickness ?sk))
(while (not (subsetp ?kw ?f ))
(bind ?f (askquestion "whot Does the plant seem to have ? ")))
=>
(assert ?sk))
What I am trying to do is simply ask the user what is wrong with their plant and using the keywords to identify the problem and then assert the problem. However I keep getting the following error.
Defining defrule: determineSickness
[PRNTUTIL2] Syntax Error: Check appropriate syntax for defrule.
ERROR:
(defrule MAIN::determineSickness
(bind ?f (
FALSE
CLIPS>
There's a BNF specification of valid CLIPS syntax in the CLIPS Basic Programming Guide. A relevant portion for defrules is:
<defrule-construct> ::=
(defrule <rule-name> [<comment>]
[<declaration>]
<conditional-element>*
=>
<action>*)
<action> ::= <expression>
<expression> ::= <constant> | <variable> | <function-call>
<function-call> ::= (<function-name> <expression>*)
<conditional-element> ::=
<pattern-CE> |
<assigned-pattern-CE> |
<not-CE> |
<and-CE> |
<or-CE> |
<logical-CE> |
<test-CE> |
<exists-CE> |
<forall-CE>
The when portion of the rule (the part before the =>) consists of conditions that must be matched by facts/instances in order for the rule to be applicable. You can make function calls from the conditions of the rule, but not using the syntax you've attempted. In addition, since conditions can be activated in a non-sequential order, procedural code that must be executed sequentially needs to be specified in the actions of the rule (the part after the =>).
You can make your original code syntactically correct with a few changes:
(defrule determineSickness
(illness (keywords $?kw) (sickness ?sk))
=>
(bind ?f (askquestion "whot Does the plant seem to have ? "))
(while (not (member$ ?f ?kw))
(bind ?f (askquestion "whot Does the plant seem to have ? ")))
(assert (diagnosis ?sk)))
Your rule(s) are still semantically incorrect. This is what they currently do:
For every illness, ask the user to specify one of the symptoms for that illness.
This is what they need to do:
For every symptom specified by the user, find every illness having that symptom.

How to use not condition in CLIPS programming language properly?

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>

Resources