КЛИПСЫ - Можно ли изменить значение правила во время выполнения? - PullRequest
1 голос
/ 13 января 2020

Я хочу построить экспертную систему, в которой в случае чрезвычайной ситуации в здании с несколькими этажами (цокольный этаж + три этажа) лифт должен поднимать людей в землю. Идея состоит в том, чтобы спасти людей сначала с самого высокого (третий этаж), а затем со второго этажа и в конце с первого этажа. У меня проблема с выраженностью правил (у меня есть отдельные правила для каждого этажа). Вначале наибольший интерес имеет правило «MoveFloor3» - поднимите лифт на третий этаж (потому что я хочу сначала спасти людей с самого высокого этажа). Когда я спасаю всех людей с третьего этажа, я хочу изменить значение в этом правиле на 0 (или на некоторое число меньше значения для второго и первого этажа), потому что после этого я хочу сохранить людей со второго и первого этажа. Код для этого правила приведен ниже, как изменить этот код, чтобы изменить значение после того, как число людей на этом этаже станет 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 ]

2 голосов
/ 13 января 2020

Вот альтернативное решение, которое обрабатывает любое количество этажей только с двумя правилами и не требует использования значимости:

         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 голос
/ 13 января 2020

Используйте глобальную переменную для установки значимости, которую можно изменить в RHS правила после его запуска. Также см. Использование переменных в декларации значимости в определении правила

0 голосов
/ 13 января 2020

Если у кого-то есть такая же проблема - это было моё решение и оно работает!

**(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)
)
)
...