1
votes

I want to build an expert system in which in a case of emergency at a building with some floors (ground floor + three floors), the elevator should take the people into the ground. Idea is to save people firstly from the highest one (third floor), and after that from second floor, and at the end from first floor. I have problem with salience of rules (I have separate rules for each floor). At the beginning the highest salience is for rule "MoveFloor3" - move elevator to third floor (because I want to save firstly people from the highest floor). When I save all people from third floor I want to change salience in this rule to 0 (or some number smaller than salience for second and first floor), because after that I want to save people from second and first floor. Code for this rule is bellow, how to modify this code in order to change salience after the number of people on this floor becomes 0.

(defrule moveFloor3
(declare (salience 50))
?j<-(lastJob ?t&~moveFloor3)
?e<-(elevator ?peopleInElevator)
?f<-(floor3 ?peopleInFloor)
(capacityElevator ?capacityElevator)

=>
(bind ?newPeopleInElevator (+ ?peopleInElevator (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
(bind ?newPeopleInFloor (- ?peopleInFloor (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
(retract ?e ?f ?s ?j)
(assert (elevator ?newPeopleInElevator))
(assert (floor3 ?newPeopleInFloor))
(assert (lastJob moveFloor3))
(printout t "Elevator moved to third floor" crlf)
)
3

3 Answers

2
votes

Here's an alternate solution that handles any number of floors with just two rules and does not require the use of salience:

         CLIPS (6.31 6/12/19)
CLIPS> 
(deftemplate floor
   (slot #)
   (slot people))
CLIPS> 
(deftemplate elevator
   (slot capacity)
   (slot occupants))
CLIPS>       
(deffacts initial
   (elevator (capacity 8) 
             (occupants 0))
   (floor (# ground) (people 0))
   (floor (# 1) (people 4))    
   (floor (# 2) (people 8))    
   (floor (# 3) (people 13)))  
CLIPS> 
(defrule pick-up-people
   ;; The elevator is not full
   ?e <- (elevator (capacity ?c)
                   (occupants ?o&~?c))
   ;; There's a floor with people on it
   ?f <- (floor (# ?f1&~ground) (people ?p&~0))
   ;; There's not a higher floor with people
   (not (floor (# ?f2&~ground&:(> ?f2 ?f1)) (people ~0)))
   =>
   ;; The number of people that can enter the elevator is
   ;; the minimum of the remaining occupancy of the elevator
   ;; and the number of people on the floor
   (bind ?added-people (min (- ?c ?o) ?p))
   ;; Print a message 
   (printout t "Elevator moves to floor " ?f1
               " and picks up " ?added-people " "
               (if (= ?added-people 1) then person else people)
               crlf)
   ;; Update  the number of people in the elevator and on the floor
   (modify ?e (occupants (+ ?o ?added-people)))
   (modify ?f (people (- ?p ?added-people))))
CLIPS> 
(defrule drop-off-people
   ;; Determine the number of people on the ground floor
   ?f <- (floor (# ground) (people ?p))
   ;; There must be people in the elevator
   ?e <- (elevator (occupants ?o&~0)
                   (capacity ?c))
   ;; There are no remaining people on any of the floors
   ;; or the elevator is at full occupancy
   (or (not (floor (# ~ground) (people ~0)))
       (test (= ?c ?o)))
   =>
   ;; Print a message
   (printout t "Elevator moves to ground floor and drops off " 
               ?o " " (if (= ?o 1) then person else people) crlf)
   ;; Update the number of people on the ground floor and 
   ;; in the elevator
   (modify ?f (people (+ ?o ?p)))
   (modify ?e (occupants 0)))
CLIPS> (reset)
CLIPS> (run)
Elevator moves to floor 3 and picks up 8 people
Elevator moves to ground floor and drops off 8 people
Elevator moves to floor 3 and picks up 5 people
Elevator moves to floor 2 and picks up 3 people
Elevator moves to ground floor and drops off 8 people
Elevator moves to floor 2 and picks up 5 people
Elevator moves to floor 1 and picks up 3 people
Elevator moves to ground floor and drops off 8 people
Elevator moves to floor 1 and picks up 1 person
Elevator moves to ground floor and drops off 1 person
CLIPS> 
1
votes

Use a global variable for setting the salience, which can be changed in the RHS of the rule once it has fired. Also see Using variables in salience declaration in a rule definition

0
votes

If someone has same problem - this was my solution and it is working!

**(defglobal ?*floor3* = 0)**
(defrule moveFloor3
**(declare (salience (+ ?*floor3* 40)))**
?j<-(lastJob ?t&~moveFloor3)
?e<-(elevator ?peopleInElevator)
?f<-(floor3 ?peopleInFloor)
(capacityElevator ?capacityElevator)

=>
(if (eq ?peopleInFloor 0)
    then
    **(bind ?*floor3* -40)**
    else
    (bind ?newPeopleInElevator (+ ?peopleInElevator (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
    (bind ?newPeopleInFloor (- ?peopleInFloor (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
    (retract ?e ?f ?j)
    (assert (elevator ?newPeopleInElevator))
    (assert (floor3 ?newPeopleInFloor))
    (assert (lastJob moveFloor3))
    (printout t "Elevator moved to third floor" crlf)
)
)