Можем ли мы считать факты с одинаковыми значениями в Jess?

Используя Джесс в качестве механизма правил, мы можем утверждать факт, что какой-то свидетель видел человека в каком-то месте и в определенное время:

(deffacts witnesses
    (witness Batman Gotham 18)
    (witness Hulk NYC 19)
    (witness Batman Gotham 2)
    (witness Superman Chicago 22)
    (witness Batman Gotham 10)
)

Как правило, я хочу знать, видели ли несколько свидетелей одного и того же человека в одном и том же месте, не считая времени.

В документации Jess мы получили этот пример для подсчета сотрудников, получающих зарплату в 100 тысяч и более:

(defrule count-highly-paid-employees
    ?c <- (accumulate (bind ?count 0)                        ;; initializer
    (bind ?count (+ ?count 1))                    ;; action
    ?count                                        ;; result
    (employee (salary ?s&:(> ?s 100000)))) ;; CE
    =>
    (printout t ?c " employees make more than $100000/year." crlf))

Поэтому я основывал свой код на предыдущем примере:

(defrule count-witnesses
    (is-lost ?plost)
    (witness ?pseen ?place ?time)
    ?c <- (accumulate (bind ?count 0)
    (bind ?count (+ ?count 1))
    ?count
    (test ())  ; conditional element of accumulate
    (test (= ?plost ?pseen))
    (test (>= ?count 3))
    =>
    (assert (place-seen ?place))
)

С приведенной выше инструкцией '(defacts)' и правилом, движок должен подтвердить факт

(place-seen Gotham)

потому что Бэтмена мы видели трижды в Готэме.

Я понятия не имею, как использовать часть условного элемента (CE) «накопить». Могу ли я использовать «тест», чтобы сохранить факты об одном и том же человеке и месте?

Есть идеи, как этого добиться?

Спасибо!


Примечание: синтаксис слова «накапливать»

(accumulate <initializer> <action> <result> <conditional element>)

person sgy    schedule 12.02.2012    source источник


Ответы (1)


Я собираюсь опустить материал о ?plost, так как вы не объясняете, что именно; вы можете добавить его обратно в себя, если вам нужно.

Основное правило, которое (почти) делает то, что вы хотите, заключается в следующем. Часть CE, которую вы не получили, — это просто шаблон, который мы хотим накапливать; здесь он сопоставляет факты с тем же лицом, засвидетельствованным в том же месте, что и факт, сопоставленный первым лицом:

(defrule count-witnesses
  ;; Given that some person ?person was seen in place ?place
  (witness ?person ?place ?)  
  ;; Count all the sightings of that person in that place  
  ?c <- (accumulate (bind ?count 0)
                    (bind ?count (+ ?count 1))
                    ?count
                    (witness ?person ?place ?))
  ;; Don't fire unless the count is at least 3
  (test (>= ?c 3))
  =>
  (assert (place-seen ?person ?place))
)

Теперь единственная проблема с этим правилом заключается в том, что оно будет срабатывать три раза для вашего deffacts, по одному разу для каждого из фактов о Бэтмене/Готэме. Мы можем остановить это, изменив первый шаблон так, чтобы он соответствовал только самому раннему увиденному человеку в данном месте:

(defrule count-witnesses
  ;; Given that some person ?person was seen in place ?place, and there is no other 
  ;; sighting of the same person at the same place at an earlier time
  (witness ?person ?place ?t1)    
  (not (witness ?person ?place ?t2&:(< ?t2 ?t1)))
  ;; Count all the sightings of that person in that place  
  ?c <- (accumulate (bind ?count 0)
                    (bind ?count (+ ?count 1))
                    ?count
                    (witness ?person ?place ?))
  ;; Don't fire unless the count is at least 3
  (test (>= ?c 3))
  =>
  (assert (place-seen ?person ?place))
)
person Ernest Friedman-Hill    schedule 12.02.2012