
Expert Systems. 上課用書 Expert Systems: Principles and Programming (4th Edition), Giarratano and Riley, ISBN 0534384471 ( 開發圖書代理 ) 上課內容 0. Introduction to Artificial Intelligence 1. Introduction to Expert Systems 2. The Representation of Knowledge 3. Methods of Inference
Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.
0. Introduction to Artificial Intelligence
1. Introduction to Expert Systems
2. The Representation of Knowledge
3. Methods of Inference
6. Design of Expert Systems
7. Introduction to CLIPS
8. Advanced Pattern Matching
9. Modular Design, Execution Control, and Rule Efficiency
A. Fuzzy CLIPS
-- Ben Coppin
“An expert system is a computer system that emulates with the decision-making capabilities of a human expert.”
“An intelligent computer program that uses knowledge and inference procedures to solve problems that are difficult enough to require significant human expertise for their solutions”.
Professor Edward Feigenbaum
Stanford University
eats(Bob,Cheese) chases(Fido,Fang) chases(Fang,Mise)
eat(Mice,Cheese)
infer
new
data
infer
new
data
infer
‧‧‧
conclusion
known data or facts
infer
infer
infer
known goal
subgoals
solution
subgoals
‧‧‧
Expert Systems: Principles and Programming, Fourth Edition
“An expert system is a computer system that emulates with the decision-making capabilities of a human expert.”
“An intelligent computer program that uses knowledge and inference procedures to solve problems that are difficult enough to require significant human expertise for their solutions”.
Professor Edward Feigenbaum
Stanford University
IF you are hungry THEN eat
The process of building an expert system:
Expert Systems: Principles and Programming, Fourth Edition
A number of knowledge-representation techniques have been devised:
mother(becky,heather)
means that becky is the mother of heather
p is called the rule’s head and the pi represents the subgoals
mother(x,y) :- parent(x,y) , female(x)
grandparent(X,Y) :- parent(X,Z) , parent(Z,Y)
[Man: John] (agent) [Eat] (obj) [Pie]
$x$y(Man(John) Ùagent(x,John) ÙEat(x) Ùobj(x,y) ÙPie(y))
[Number: *x]
[Number: *z]
<plus>
[Number: *y]
[Wood] <<burns>> [Ashes]
Expert Systems: Principles and Programming, Fourth Edition
Premise: Anyone who can program is intelligent
Premise: John can program
Conclusion: John is intelligent
IF Anyone who can program is intelligent and
John can program
THENJohn is intelligent.
Premises and conclusions are defined using categorical statements of the four forms:
AAA mood
All M is P
All S is M
All S is P
mood: defined by three letters that gives the form of the major premise,
minor premise, and conclusion, respectively.
All M is P
All S is M
AAA-1 syllogism type
All S is P
All P is M
No M is S
AEE-4 syllogism type
No S is P
All microcomputers are computers
No mainframe is a microcomputer
No mainframe is a computer
All M is P
No S is M
No S is P
P
S
S
P
S
P
M
M
M
After Minor Premise
Venn Diagram
After Major Premise
* The shaded section of M indicates there are no elements in that portion.
No M is P
All S is M
No S is P
P
S
S
P
S
P
M
M
M
After Minor Premise
Venn Diagram
After Major Premise
Some computers are laptops
All laptops are transportable
Some transportables are computers
Some P is M
All M is S
Some S is P
P
P
S
S
S
P
*
M
M
M
Some P is M
All M is S
Venn Diagram
A → B
A
B
If there is power, the computer will work
There is power
The computer will work
p → q
p
q
p
q
r
man(Socrates)
mortal(Socrates) <Modus Ponens>
where p= All men are mortal
q = Socrates is a man
r = Socrates is mortal
backward chaining facilitates a
depth-first search (a narrow
and deep tree is applicable)
forward chaining facilitates a
breadth-first search (a broad
and not deep tree is applicable)
Expert Systems: Principles and Programming, Fourth Edition
Each circuit of the spiral adds some functional capability to the system.
The linear model has been successfully used in a number of expert system projects.
The purpose of this stage is to produce a formal work plan for the expert system development – documents to guide and evaluate the development.
The objective of this stage is to define the knowledge requirements of the expert system, which consists of two main tasks:
The objective is to produce the detailed design for an expert system and involves:
The objective here is to determine the correctness, completeness, and consistency of the system.
This stage is for summarizing what has been learned with recommendations for improvements and corrections.
Expert Systems: Principles and Programming, Fourth Edition
Inference Engine
Solution
Rules
What is CLIPS?CLIPS>(+ 3 4) value 7 would be returned.
Peter 12 140 40
John 30 175 65
Deftemplate & Facts(person (name John) (age 30) (height 175) (weight 65))
CLIPS>(retract 2)
(deffacts <deffacts name> <facts>* )
IFthe emergency is a fire
THENthe response is to activate the sprinkler system
(deftemplate emergency (slot type))
-- type would be fire, flood, etc.
(deftemplate response (slot action))
-- action would be “activate the sprinkler”
(defrule fire-emergency “An example rule”
(emergency (type fire))
=>
(assert (response (action activate-sprinkler-system))))
<patterns>* ------LHS
=>
<actions>* ) ------RHS
(emergency (type fire))
=>
(assert (response (action sprinkle))))
(emergency (type fire))
(fired-object (material oil))
=>
(printout t “The fire should be excluded from air.” crlf))
CLIPS>(run [<limit>])
-- the optional argument <limit> is the maximum number of rules to be fired – if omitted, rules will fire until the agenda is empty.
agenda
agenda
0 fire-emergency-2 :f-1,f-4
-10 find-height-175 :f-2
-10 find-name-John :f-3,f-5
:
(run 1)
10 fire-emergency-1 :f-1
0 fire-emergency-2 :f-1,f-4
-10 find-height-175 :f-2
-10 find-name-John :f-3,f-5
:
CLIPS>(agenda)
Reset
Run
Execute a CLIPS Program1. Edit a CLIPS program file in text format
2. Open CLIPS system and load the program file
3. Reset the CLIPS system
4. Execute
5. Clear the CLIPS system
extinguisher
(fire (type A))
=>
(printout t “general extinguisher or water” crlf))
(fire (type B))
=>
(printout t “foam extinguisher or carbon dioxide extinguisher” crlf))
(fire (type C))
=>
(printout t “dry chemicals extinguisher or carbon dioxide extinguisher” crlf))
(fire (type D))
=>
(printout t “graphitized coke” crlf))
(person (name ?name) (age ?) (height 175) (weight ?w))
=>
(printout t ?name “is 175 cm tall and “ ?w “ kg weight.”))
(person (name ?name) (age ?) (height 175) (weight ?w))
(father-child (father ?name) (child $?))
=>
(printout t ?name “is 175 cm tall and “ ?w “ kg weight.”))
(person (name $?name) (children $?children))
=>
(printout t ?name “ has children “ ?children crlf))
?data <- (data (item ?value))
?old-total <- (total ?total)
=>
(retract ?old-total ?data)
(assert (total (+ ?total ?value))))
(defrule process-moved-information
(moved (name ?name) (address ?address))
?f2 <- (person (name ?name) (address ?))
=>
(modify ?f2 (address ?address)))
D
A
C
E
B
E
D
F
A
C
B
F
(Initial State)
(Goal State)
(deffacts initial-state
(block A)
(block B)
(block C)
(block D)
(block E)
(block F)
(on-top-of (upper nothing) (lower A))
(on-top-of (upper A) (lower B))
(on-top-of (upper B) (lower C))
(on-top-of (upper C) (lower floor))
(on-top-of (upper nothing) (lower D))
(on-top-of (upper D) (lower E))
(on-top-of (upper E) (lower F))
(on-top-of (upper F) (lower floor))
(goal (move C) (on-top-of E))
)
(deftemplate on-top-of (slot upper) (slot lower))
(deftemplate goal (slot move) (slot on-top-of))
(defrule move-directly
?goal <- (goal (move ?b1) (on-top-of ?b2))
(block ?b1)
(block ?b2)
(on-top-of (upper nothing) (lower ?b1))
?stack1 <- (on-top-of (upper nothing) (lower ?b2))
?stack2 <- (on-top-of (upper ?b1) (lower ?b3))
=>
(retract ?goal ?stack1 ?stack2)
(assert (on-top-of (upper ?b1) (lower ?b2)))
(assert (on-top-of (upper nothing) (lower ?b3)))
(printout t ?b1 “ move on top of “ ?b2 “.” crlf)
)
(defrule move-to-floor
?goal <- (goal (move ?b1) (on-top-of floor))
(block ?b1)
(on-top-of (upper nothing) (lower ?b1))
?stack <- (on-top-of (upper ?b1) (lower ?b2))
=>
(retract ?goal ?stack)
(assert (on-top-of (upper ?b1) (lower floor)))
(assert (on-top-of (upper nothing) (lower ?b2)))
(printout t ?b1 “ move on top of floor.” crlf)
)
(defrule clear-place-block
(goal (move ?) (on-top-of ?b1))
(block ?b1)
(block ?b2)
(on-top-of (upper ?b2) (lower ?b1))
=>
(assert (goal (move ?b2) (on-top-of floor)))
)
Results:
(defrule clear-move-block
(goal (move ?b1) (on-top-of ?))
(block ?b1)
(block ?b2)
(on-top-of (upper ?b2) (lower ?b1))
=>
(assert (goal (move ?b2) (on-top-of floor)))
)
A move on top of floor.
B move on top of floor.
D move on top of floor.
C move on top of E.
Cycle
Stack-2
Rule
Goal
Stack-1
initial
DEF
C→E
ABC
clear-move-block
clear-place-block
B→Floor
D→Floor
1
2
A→Floor
clear-move-block
ABC
A, BC
A→Floor
move-to-floor
3
BC
B, C
B→Floor
move-to-floor
4
DEF
D, EF
move-to-floor
D→Floor
5
EF
CEF
C→E
C
move-directly
6
(deftemplate goal (slot move) (slot on-top-of))
(deffacts initial-state
(stack A B C)
(stack D E F)
(goal (move C) (on-top-of E))
)
(defrule move-directly
?goal <- (goal (move ?block1) (on-top-of ?block2))
?stack-1 <- (stack ?block1 $?rest1)
?stack-2 <- (stack ?block2 $?rest2)
=>
(retract ?goal ?stack-1 ?stack-2)
(assert (stack $?rest1))
(assert (stack ?block1 ?block2 $?rest2))
(printout t ?block1 “ move on top of “ ?block2 “.” crlf))
(defrule move-to-floor
?goal <- (goal (move ?block1) (on-top-of floor))
?stack-1 <- (stack ?block1 $?rest)
=>
(retract ?goal ?stack-1)
(assert (stack ?block1))
(assert (stack $?rest))
(printout t ?block1 “ move on top of floor.” crlf))
(defrule clear-move-block
(goal (move ?block1))
(stack ?top $? ?block1 $?)
=>
(assert (goal (move ?top) (on-top-of floor))))
(defrule clear-place-block
(goal (on-top-of ?block1))
(stack ?top $? ?block1 $?)
=>
(assert (goal (move ?top) (on-top-of floor))))
Expert Systems: Principles and Programming, Fourth Edition
(person (name ?name) (hair ?color))
(test (neq ?color brown))
=>
(printout t ?name “ does not have brown hair.” crlf))
(person (name ?name) (hair ~brown))
=>
(printout t ?name “ does not have brown hair.” crlf))
(person (name ?name) (hair black | red))
=>
(printout t ?name “ has black or red hair.” crlf))
(person (name ?name) (hair ?color&~black&~red))
=>
(printout t ?name “ has “ ?color “ hair.” crlf))
(person (name ?name1) (eyes ?eyes1& blue|green)(hair ?hair1&~black))
(person (name ?name2&~?name1) (eyes ?eyes2&~?eyes1) (hair ?hair2&red | ?hair1))
=>
(printout t ?name1 “ has “ ?eyes1 “ eyes and “ ?hair1 “ hair.” crlf)
(printout t ?name2 “ has “ ?eyes2 “ eyes and “ ?hair2 “ hair.” crlf))
5 + 8 (infix form) + 5 8 (prefix form)
(infix) (y2 – y1) / (x2 – x1) > 0
(prefix) (> (/ (- y2 y1 ) (- x2 x1 ) ) 0)
CLIPS>(- 3 5 7) returns3 - 5 =-2 - 7 = -9
(deftemplate rectangle (slot height) (slot width))
(sum 20)
(deffacts initial-information
(rectangle (height 10) (width 6))
(rectangle (height 7) (width 5)
(rectangle (height 6) (width 8))
(rectangle (height 2) (width 5))
(sum 0))
(deftemplate rectangle (slot height) (slot width))
(deffacts initial-rectangles
(rectangle (height 10) (width 6))
(rectangle (height 8) (width 5))
(rectangle (height 3) (width 7))
(sum 0))
(defrule compute-area
(rectangle (height ?height) (width ?width))
=>
(assert (add-to-sum (* ?height ?width) ) ) )
(defrule sum-1
?sum <- (sum ?total)
?new-area <- (add-to-sum ?area)
=>
(retract ?sum ?new-area)
(assert (sum (+ ?total ?area) ) )
(printout t "The new sum is " (+ ?total ?area) crlf))
(rectangle (height ?height) (width ?width))
?sum <- (sum ?total)
=>
(retract ?sum)
(assert (sum (+ ?total (* ?height ?width) ) ) )
(printout t "The new sum is " (+ ?total (* ?height ?width) ) crlf))
?rect <- (rectangle (height ?height) (width ?width))
?sum <- (sum ?total)
=>
(retract ?rect ?sum)
(assert (sum (+ ?total (* ?height ?width) ) ) )
(printout t "The new sum is " (+ ?total (* ?height ?width) ) crlf))
What happen??
Compare with sum-1
(bind <variable> <value>)
?rect <- (rectangle (height ?height) (width ?width))
?sum <- (sum ?total)
=>
(retract ?rect ?sum)
(bind ?new (+ ?total (* ?height ?width) ) )
(assert (sum ?new) )
(printout t "The new sum is " ?new crlf))
bind
John K. Smith
Example:
(open “c:\\datafile.dat” mydata “r”)
(open “c:\\datafile.dat” mydata “r”)
(close [<logical-name>])
(format <logical-name> <control-string> <parameters>*)
(format nil “Name: %-15s Age: %3d” “Bob Green” 35)
Produces the results and returns:
“Name: Bob green Age: 35”
%-m.Nx
(readline [<logical-name>])
(defrule get-name
=>
(printout t “What is your name? “
(bind ?response (readline))
(assert (user’s-name ?response)))
(defrule get-name
=>
(printout t “What is your name? “
(bind ?response (explode$ (readline)))
(assert (user’s-name ?response)))
(test <predicate-function>)
Example:
(test (> ?value 1))
(person (name ?name) (age ?) (height ?height) (weight ?))
(test (> ?height 170))
=>
(printout t ?name “‘s height is larger than 170 cm.” crlf))
(person (name ?name) (age ?age) (height ?height) (weight ?weight))
(test (and (>= ?height 170)
(or (> ?weight 60)
(< ?age 30))))
=>
(printout t ?name “ is the person we seek.” crlf))
f-5 (person (name Peter) (age 35) (height 175) (weight 60))
f-6 (person (name David) (age 25) (height 170) (weight 55))
(defrule find-height-larger-than-170
(person (name ?name) (age ?) (height ?height&:(> ?height 170)) (weight ?))
=>
(printout t ?name “‘s height is larger than 170 cm.” crlf))
f-5 (person (name Peter) (age 35) (height 175) (weight 60))
f-6 (person (name David) (age 25) (height 170) (weight 55))
f-7 (person (name John) (age 12) (height 145) (weight 40))
f-8 (person (name Kevin) (age 31) (height 200) (weight 98))
(person (name ?name1) (age ?) (height ?height) (weight ?))
(person (name ?name2) (age ?) (height =(+ ?height 30)) (weight ?))
=>
(printout t ?name2 “ is 30 cm taller than ” ?name1 crlf))
f-5 (person (name Peter) (age 35) (height 175) (weight 60))
f-6 (person (name David) (age 25) (height 170) (weight 55))
f-7 (person (name John) (age 12) (height 145) (weight 40))
f-8 (person (name Kevin) (age 31) (height 200) (weight 98))
These two rules can be combined into one rule – or CE requires only one CE be satisfied:
The and CE is opposite in concept to the or CE – requiring all the CEs be satisfied:
When it is advantageous to activate a rule based on the absence of a particular fact in the list, CLIPS allows the specification of the absence of the fact in the LHS of a rule using the not conditional element:
We can implement this as follows:
(query ?person)
(not (or (driving-license (id ?) (country Taiwan) (name ?person))
(and (driving-license (id ?) (country ?else) (name ?person))
(DL-accepted-in-Taiwan ?else) ) ) ) )
=>
(printout t ?person “ can not drive a car in Taiwan.” crlf))
f-3 (query John)
f-4 (query Kevin)
f-5 (query Joe)
f-6 (driving-license (id 85346) (country Twain) (name Kevin))
f-7 (driving-license (id 53861) (country America) (name John))
f-8 (DL-accepted-in-Taiwan America)
(defrule operator-alert-for-emergency
(exists (emergency))
=>
(printout t “Emergency: Operator Alert” crlf)
(assert (operator-alert))))
(not (and <remaining-CEs>+ ) ) ) )
(forall (emergency (type fire) (location ?where))
(fire-squad (location ?where))
(evacuated (building ?where)))
=>
(printout t “All buildings that are on fire “ crlf
“have been evacuated and “ crlf
“have firefighters on location” crlf))
(logical <dominate-fact>+)
<remaining-fact>+
=>
(assert <dependent-fact>))
(declare (salience 50))
(person (name ?name) (age 20))
=>
(printout t ?name “ is young.” crlf))
(defrule rule-02
(declare (salience 20))
(person (name ?name) (age 20))
=>
(printout t ?name “ is 20 years old.” crlf))
f-5 (person (name Peter) (age 20))
f-6 (person (name David) (age 20))
(deftemplate choose (slot get) (slot remainder))
(deffacts initial
(choose (get 1) (remainder 1))
(choose (get 1) (remainder 2))
(choose (get 2) (remainder 3))
(choose (get 3) (remainder 0)))
(defrule choose-total-number
(declare (salience 1000))
=>
(printout t “How many sticks in the pile? “)
(assert (total (read))))
(defrule player-select
(declare (salience 900))
=>
(printout t “Who moves first (Computer:c Human: h)? “)
(assert (player-get (read))))
(defrule computer-get
(declare (salience 800))
?player <- (player-get c)
?total <- (total ?num)
(test (>= ?num 1))
(choose (get ?get) (remainder =(mod ?num 4)))
=>
(retract ?player ?total)
(printout t ?num “ sticks in the pile.” crlf)
(assert (total (- ?num ?get)))
(printout t “Computer take “ ?get “ sticks.” crlf)
(assert (player-get h)))
(defrule human-get
(declare (salience 800))
?player <- (player-get h)
?total <- (total ?num)
(test (>= ?num 1))
=>
(retract ?player ?total)
(printout t “There are “ ?num “ sticks in the pile.” crlf)
(printout t “How many sticks do you wish to take? (1~3) “)
(assert (total (- ?num (read))))
(assert (player-get c)))
(defrule computer-win
(declare (salience 700))
(player-get c)
(total ?num)
(test (< ?num 1))
=>
(printout t “You lose!” crlf))
(defrule Human-win
(declare (salience 700))
(player-get h)
(total ?num)
(test (< ?num 1))
=>
(printout t “You win!” crlf))
(deftemplate choose (slot get) (slot remainder))
(deffacts initial
(phase choose-total)
(choose (get 1) (remainder 1))
(choose (get 1) (remainder 2))
(choose (get 2) (remainder 3))
(choose (get 3) (remainder 0)))
(defrule choose-total
(phase choose-total)
=>
(printout t “How many sticks in the pile? “)
(assert (total (read))))
(defrule choose-total-right
?phase <- (phase choose-total)
(total ?total)
(test (integerp ?total))
(test (> ?total 0))
=>
(retract ?phase)
(assert (phase choose-player)))
(defrule choose-total-wrong
?phase <- (phase choose-total)
?total <- (total ?num&:(or (not (integerp ?num))
(<= ?num 0)))
=>
(retract ?phase ?total)
(assert (phase choose-total))
(printout t “Please input a positive integer!!” crlf))
(defrule player-select
(phase choose-player)
=>
(printout t “Who moves first (Computer:c Human: h)? “)
(assert (player-get (read))))
(defrule player-select-right
?phase <- (phase choose-player)
(player-get ?player& c | h)
=>
(retract ?phase)
(assert (phase play-game)))
(defrule player-select-wrong
?phase <- (phase choose-player)
?p-get <- (player-get ?player& ~c & ~h)
=>
(retract ?phase ?p-get)
(assert (phase choose-player))
(printout t “Please input c or h!!” crlf))
(defrule human-get
(phase play-game)
(player-get h)
(total ?num)
(test (>= ?num 1))
=>
(printout t “There are “ ?num “ sticks in the pile.” crlf)
(printout t “How many sticks do you wish to take? (1~3) “)
(assert (human-take (read))))
(defrule human-get-right
(phase play-game)
?player <- (player-get h)
?h-take <- (human-take ?take)
?total <- (total ?num)
(test (and (integerp ?take)
(>= ?take 1)
(<= ?take 3)
(<= ?take ?num)))
=>
(retract ?player ?h-take ?total)
(assert (total (- ?num ?take)))
(assert (player-get c)))
(defrule human-get-wrong
(phase play-game)
?player <- (player-get h)
?h-take <- (human-take ?take)
(total ?num)
(test (or (not (integerp ?take)) (< ?take 1) (> ?take 3) (> ?take ?num)))
=>
(retract ?player ?h-take)
(assert (player-get h))
(printout t “Please input a number (1~3)!!” crlf))
(defrule computer-win
(player-get c)
(total ?num)
(test (< ?num 1))
=>
(printout t “You lose!” crlf))
(defrule computer-get
(phase play-game)
?player <- (player-get c)
?total <- (total ?num)
(test (>= ?num 1))
(choose (get ?get) (remainder =(mod ?num 4)))
=>
(retract ?player ?total)
(printout t ?num “ sticks in the pile.” crlf)
(assert (total (- ?num ?get)))
(printout t “Computer take “ ?get “ sticks.” crlf)
(assert (player-get h)))
(defrule Human-win
(player-get h)
(total ?num)
(test (< ?num 1))
=>
(printout t “You win!” crlf))
Expert Systems: Principles and Programming, Fourth Edition
(deftemplate person
(multislot name (type SYMBOL))
(slot age (type INTEGER)))
name – must store symbols
age – must store integers
(multislot name (type SYMBOL))
(slot age (type INTEGER))
(slot gender (type SYMBOL) (allowed-symbols male female)))
(deftemplate person
(multislot name (type SYMBOL))
(slot age (type INTEGER) (range 0 120)))
(deftemplate volleyball-team
(slot name (type STRING))
(multislot players (type STRING) (cardinality 6 6))
(multislot alternates (type STRING) (cardinality 0 2)))
(multislot cc (default red green blue)))
?f <- (data (value ?) (creation-time ?t1))
?c <- (current-time ?t2)
(test (> (- ?t2 ?t1) 60))
=>
(retract ?f ?c))
?c <- (current-time ?t)
=>
(retract ?c)
(assert (current-time (time))))
Isolation
Recovery
An Example: Electronic Device ProblemExpert Knowledge
Detection
Rules
Isolation
Rules
Recovery
Rules
salience
Control Knowledge
Control Rules
Constraint Rules
Expert Rules
salience
Query Rules
Control Rules
(defmodule <module-name> [<comment>])
By default, CLIPS defines a MAIN module as seen below:
CLIPS> (clear)
CLIPS> (deftemplate sensor (slot name))
CLIPS> (ppdeftemplate sensor)
(deftemplate MAIN::sensor (slot name))
CLIPS>
The symbol :: is called the module separator
CLIPS>(defmodule DETECTION)
CLIPS>(defmodule ISOLATION)
CLIPS>(defmodule RECOVERY)
CLIPS>(defrule ISOLATION::example2 =>)
CLIPS>(ppdefrule example2)
(defruleISOLATION::example2 =>)
CLIP>
CLIPS>(get-current-module)
CLIPS>(set-current-module DETECTION)
CLIPS>(list-defrules RECOVERY)
CLIPS>(list-deffacts ISOLATION)
CLIPS>(list-deftemplates *)
(facts [<module-name>])
CLIPS>(agenda)
CLIPS>(agenda DETECTION)
CLIPS>(focus <module-name>+)
CLIPS>(focus DETECTION)
TRUE
CLIPS>(run)
CLIPS provides several commands for manipulating the current focus and stack:
(defmodule DETECTION)
(defmodule ISOLATION)
(defmodule RECOVERY)
(defrule MAIN::change-phase
=>
(focus DETECTION ISOLATION RECOVERY))
(defrule MAIN::change-phase
=>
(focus RECOVERY)
(focus ISOLATION)
(focus DETECTION))
OR