;-----------------------------------------------------------------------------------------
; General Heuristic Search
;
; (depth ?) -- Keeps Track of the Level
; (nodes ?) -- The number of Nodes
; (heuristic ?) -- The current value of the heuristic
;
; Method:
; Only those rules fire which have the same heuristic as:
; (heuristic ?)
; After each rule creates a new fact:
; The node count is incremented
; The heuristic value is calculated
; (heuristic ?) is updated (only if the new fact has a greater heuristic)
;
;-------------------------------------------------------------
; Use of Salience:
; Rules: 500
; To be checked or fired after each new node
; Increment-Node-Count 700
; update-heuristic-value 600
; eliminate-illegal 600
; top=-heuristic 600
; After a node has been expanded
; goal-found 450
; get-best-rule-to-expand 400
; Done with all the nodes with current heuristic
; finished 160
; increment-heuristic 150
; update-depth 100
; As soon as a Solution is found: print path
; Done 2000
; Complete 2000
; Done-Complete 2000
;-------------------------------------------------------------
; The status of the water in the water-jug
; State: water-jug The amount of water in the jug
; Search Info: closed Element on Closed List (t)
; depth Depth in tree
; node The number of the node
; parent The address of the parent
; operation The Operation String (for printing)
; Heuristic Info heuristic The heuristic of this node
;
(deftemplate status
(slot water-jug
(type INTEGER)
(default 0)
(range 0 5))
(slot closed
(type INTEGER)
(default 0)
(range 0 1))
(slot heuristic
(type INTEGER)
(default 0))
(slot depth
(type INTEGER)
(default 0))
(slot node
(type INTEGER)
(default 0))
(slot parent
(type FACT-ADDRESS SYMBOL)
(default no-parent)
(allowed-symbols no-parent))
(slot operation
(type STRING))
)
;-------------------------------------------------------------
; The Heuristic Function
;
(deffunction calculate-heuristic (?amount ?node ?depth)
(if (> ?amount 3) then
-1
else
(- 4 ?amount)))
;-------------------------------------------------------------
; The initial Status
; The heuristic is set low
; Depth is zero
; Node is zero
; Water Jug has no water in it
(defrule Initial-State
?initial <- (initial-fact)
=>
(assert (heuristic 1))
(assert (depth 0 0))
(assert (status (water-jug 0)
(depth 0)
(node 0)
(heuristic 0)
(parent no-parent)))
(assert (nodes 1))
)
;-------------------------------------------------------------
;-------------------------------------------------------------
; The Rules to Create New Facts
;-------------------------------------------------------------
;-------------------------------------------------------------
;-------------------------------------------------------------
; Rule for Adding One Gallon to Water Jug
;
(defrule Add-One-Gallon
(declare (salience 500))
?status <- (status
(closed ?closed)
(water-jug ?amount)
(depth ?depth))
(test (= ?closed 1))
=>
(assert (status (water-jug (+ ?amount 1))
(depth (+ ?depth 1))
(parent ?status)
(operation "Add One Gallon")
))
)
;-------------------------------------------------------------
; Rule for Adding Two Gallons to Water Jug
;
(defrule Add-Two-Gallons
(declare (salience 500))
?status <- (status
(closed ?closed)
(water-jug ?amount)
(depth ?depth))
(test (= ?closed 1))
=>
(assert (status (water-jug (+ ?amount 2))
(depth (+ ?depth 1))
(parent ?status)
(operation "Add Two Gallons")
))
)
;-------------------------------------------------------------
; After a new node (fact) is created, these can be
; activated
;-------------------------------------------------------------
;-------------------------------------------------------------
; A new fact is created and it is assigned a node number
; The node number is then incremented
;
(defrule Increment-Node-Count
(declare (salience 700))
?status <- (status (node ?statusnode))
?nodes <- (nodes ?nodecount)
(test (= ?statusnode 0))
=>
(assert (nodes (+ 1 ?nodecount)))
(modify ?status (node ?nodecount))
(retract ?nodes)
)
;-------------------------------------------------------------
; If the heuristic of the node says it will not lead to a
; solution, then retract it
(defrule eliminate-illegal
(declare (salience 600))
?node <- (status (heuristic ?value))
(test (< ?value 0))
=>
(retract ?node))
;-------------------------------------------------------------
; If a node was created that was better than the
; current heuristic, then update it to this value
(defrule top-heuristic
(declare (salience 600))
?current <- (heuristic ?currentvalue)
?node <- (status (heuristic ?nodevalue) (closed ?closed))
(test (= 0 ?closed))
(test (< ?nodevalue ?currentvalue))
=>
(retract ?current)
(assert (heuristic ?nodevalue)))
;-------------------------------------------------------------
; Rules to govern the selection of new rules to expand
; The salience is such that they are fired after all
; node (facts) from a given node have been created
;-------------------------------------------------------------
;-------------------------------------------------------------
; Start Expansion of a Fact to produce new nodes
;-------------------------------------------------------------
; This moves the rule which has the same value as the
; heuristic to the CLOSED list (i.e. closed set to 1)
; The initial firing activates in usage in the rules
;
(defrule get-best-rule-to-expand
(declare (salience 400))
?status <- (status (closed ?closed)
(heuristic ?value))
(heuristic ?heuristic)
(test (= 0 ?closed))
(test (= ?heuristic ?value))
=>
(modify ?status (closed 1)))
;-------------------------------------------------------------
; Rule for Detecting Done with Task (i.e. the jug has 3 gallons in it)
; Put Salience High so when matched, it is the first rule
;
(defrule goal-found
(declare (salience 450))
?status <- (status
(heuristic ?heuristic)
(water-jug 3))
(test (> ?heuristic 0))
=>
(modify ?status (heuristic -1000)))
;-------------------------------------------------------------
;
;-------------------------------------------------------------
;-------------------------------------------------------------
; Finished is defined when the cost exceeds a given number
(defrule finished
(declare (salience 160))
(heuristic ?heuristic)
(test (> ?heuristic 10))
(nodes ?nodes)
=>
(printout t "A Total of " (- ?nodes 1) " Nodes in the Tree" crlf)
(halt)
)
;-------------------------------------------------------------
; We are not done, but all nodes of current heuristic value
; have been expanded:
; Find a heuristic value where facts match
(defrule increment-heuristic
(declare (salience 150))
?current <- (heuristic ?currentvalue)
=>
(retract ?current)
(assert (heuristic (+ ?currentvalue 1))))
;-------------------------------------------------------------
; Rule to update current depth
; Called only if depth is done for all rules for this level
; (hence the lower salience)
;
(defrule update-depth
(declare (salience 100))
?depth <- (depth ?current ?last)
?node <- (nodes ?nodes)
(test (> ?nodes ?last))
=>
(retract ?depth)
(assert (depth (+ 1 ?current) ?nodes))
)
;-------------------------------------------------------------
; Sequence to print out solution
;-------------------------------------------------------------
;-------------------------------------------------------------
; When a goal is found, its heuristic is set to -1000
; this starts the printout loop
(defrule Done
(declare (salience 2000))
?status <- (status (heuristic ?heuristic))
(test (= ?heuristic -1000))
=>
(assert (complete ?status))
(assert (list "Done")))
(defrule Complete
(declare (salience 2000))
?status <- (status (parent ?parent) (operation ?move))
?complete <- (complete ?status)
?old-list <- (list $?rest)
=>
(assert (list ?move ?rest))
(assert (complete ?parent))
(retract ?complete)
(retract ?old-list)
)
(defrule Done-Complete
(declare (salience 2000))
?complete <- (complete no-parent)
?old-list <- (list ?first $?moves ?last)
(nodes ?nodecount)
=>
(printout t "After " (- ?nodecount 1) " nodes; Solution:" crlf ?moves crlf)
(retract ?complete ?old-list))