如何在 CLIPS 中计算具有 2 个相同参数的断言?

How to calculate asserts with 2 same parameters in CLIPS?

我是 CLIPS 的新手。我想用两个相同的参数计算断言的平均值。例如,如果我有这个模板:

(deftemplate quiz
  (slot id (type INTEGER))
  (slot course(type STRING))
  (slot quizname (type STRING))
  (slot userid (type INTEGER))
  (slot firstname (type STRING))
  (slot average (type FLOAT))
  )

这些断言:

(deffacts users
   (quiz (id 1) (course "Math") (quizname "Equations") (userid 1) (firstname "Mike") (average 70.00))
   (quiz (id 2) (course "Math") (quizname "Exercise") (userid 1) (firstname "Mike") (average 20.00))
   (quiz (id 3) (course "Math") (quizname "Sum") (userid 2) (firstname "Ronald") (average 90.00))
   (quiz (id 4) (course "Math") (quizname "Equations") (userid 2) (firstname "Ronald") (average 60.00))
   (quiz (id 9) (course "English") (quizname "Listening") (userid 5) (firstname "Lionel") (average 60.00))
   )

我想建立一个规则来计算具有相同 'userid' 和 'course' 的断言的平均值,并将结果写入文件。我想要的答案是:

Mike 的数学成绩是 45.00;罗纳德的数学成绩为 75.00; Lionel 的英文是 60.00

我试过这个规则。我知道是绝对错误的:

(defrule averageStudent
=>
(bind ?sum 0)
(do-for-all-facts ((?f quiz)) TRUE
(bind ?sum (+ ?sum ?f:average)))
(bind ?sum (/ ?sum (length$ (find-all-facts ((?nFacts quiz)) (eq ?nFacts:userid) (eq ?nFacts:namequiz math)))))
(printout t ?firstname " in math has " ?sum crlf))

您需要构造一些东西来容纳您想要为其生成平均值的所有 firstname/course 组合。在规则的操作中,您必须迭代测验事实并生成一个包含 ("Mike" "Ronald" "Lionel") 和另一个包含 ("Math" "Math" "English") 的多字段变量。然后,您必须使用从 1 到列表长度的索引迭代这些列表,然后使用 nth$ 函数从每个列表中提取名称和课程。然后,您可以使用事实查询函数提取每个 name/course 的平均值并计算总平均值。

您可以编写一条规则来确定需要平均值的所有 name/course 并将其断言为事实:

(deftemplate compute
   (slot course (type STRING))
   (slot firstname (type STRING)))
   
(defrule determine-course-name
   (logical (compute-averages))
   (quiz (course ?course) (firstname ?name))
   (not (compute (course ?course) (firstname ?name)))
   =>  
   (assert (compute (course ?course) (firstname ?name))))

然后你可以写一个规则来计算一个 name/course:

的平均值
(defrule compute-average
   (compute (course ?course) (firstname ?name))
   =>
   (bind ?sum 0)
   (bind ?count 0)
   (do-for-all-facts ((?f quiz))
                     (and (eq ?f:course ?course)
                          (eq ?f:firstname ?name))
      (bind ?sum (+ ?sum ?f:average))
      (bind ?count (+ ?count 1)))
   (format t "%s in %s has %0.2f%n" ?name ?course (/ ?sum ?count)))

determine-course-name 规则最初不会被激活:

         CLIPS (6.4 2/9/21)
CLIPS> 
(deftemplate quiz
  (slot id (type INTEGER))
  (slot course (type STRING))
  (slot quizname (type STRING))
  (slot userid (type INTEGER))
  (slot firstname (type STRING))
  (slot average (type FLOAT)))
CLIPS> 
(deffacts users
   (quiz (id 1) (course "Math") (quizname "Equations") (userid 1) (firstname "Mike") (average 70.00))
   (quiz (id 2) (course "Math") (quizname "Exercise") (userid 1) (firstname "Mike") (average 20.00))
   (quiz (id 3) (course "Math") (quizname "Sum") (userid 2) (firstname "Ronald") (average 90.00))
   (quiz (id 4) (course "Math") (quizname "Equations") (userid 2) (firstname "Ronald") (average 60.00))
   (quiz (id 9) (course "English") (quizname "Listening") (userid 5) (firstname "Lionel") (average 60.00)))
CLIPS>    
(deftemplate compute
   (slot course (type STRING))
   (slot firstname (type STRING)))
CLIPS>    
(defrule determine-course-name
   (logical (compute-averages))
   (quiz (course ?course) (firstname ?name))
   (not (compute (course ?course) (firstname ?name)))
   =>  
   (assert (compute (course ?course) (firstname ?name))))
CLIPS>    
(defrule compute-average
   (compute (course ?course) (firstname ?name))
   =>
   (bind ?sum 0)
   (bind ?count 0)
   (do-for-all-facts ((?f quiz))
                     (and (eq ?f:course ?course)
                          (eq ?f:firstname ?name))
      (bind ?sum (+ ?sum ?f:average))
      (bind ?count (+ ?count 1)))
    
   (format t "%s in %s has %0.2f%n" ?name ?course (/ ?sum ?count)))
CLIPS> (reset)
CLIPS> (facts)
f-1     (quiz (id 1) (course "Math") (quizname "Equations") (userid 1) (firstname "Mike") (average 70.0))
f-2     (quiz (id 2) (course "Math") (quizname "Exercise") (userid 1) (firstname "Mike") (average 20.0))
f-3     (quiz (id 3) (course "Math") (quizname "Sum") (userid 2) (firstname "Ronald") (average 90.0))
f-4     (quiz (id 4) (course "Math") (quizname "Equations") (userid 2) (firstname "Ronald") (average 60.0))
f-5     (quiz (id 9) (course "English") (quizname "Listening") (userid 5) (firstname "Lionel") (average 60.0))
For a total of 5 facts.
CLIPS> (agenda)
CLIPS> 

一旦您断言 (compute-averages),规则就可以计算平均值:

CLIPS> (assert (compute-averages))
<Fact-6>
CLIPS> (agenda)
0      determine-course-name: f-6,f-5,*
0      determine-course-name: f-6,f-4,*
0      determine-course-name: f-6,f-3,*
0      determine-course-name: f-6,f-2,*
0      determine-course-name: f-6,f-1,*
For a total of 5 activations.
CLIPS> (run)
Lionel in English has 60.00
Ronald in Math has 75.00
Mike in Math has 45.00
CLIPS>

中间计算事实仍然存在,但由于它们在逻辑上依赖于 (compute-averages) 事实,如果您需要清理它们,可以通过撤回该事实来删除它们:

CLIPS> (facts)
f-1     (quiz (id 1) (course "Math") (quizname "Equations") (userid 1) (firstname "Mike") (average 70.0))
f-2     (quiz (id 2) (course "Math") (quizname "Exercise") (userid 1) (firstname "Mike") (average 20.0))
f-3     (quiz (id 3) (course "Math") (quizname "Sum") (userid 2) (firstname "Ronald") (average 90.0))
f-4     (quiz (id 4) (course "Math") (quizname "Equations") (userid 2) (firstname "Ronald") (average 60.0))
f-5     (quiz (id 9) (course "English") (quizname "Listening") (userid 5) (firstname "Lionel") (average 60.0))
f-6     (compute-averages)
f-7     (compute (course "English") (firstname "Lionel"))
f-8     (compute (course "Math") (firstname "Ronald"))
f-9     (compute (course "Math") (firstname "Mike"))
For a total of 9 facts.
CLIPS> (retract 6)
CLIPS> (facts)
f-1     (quiz (id 1) (course "Math") (quizname "Equations") (userid 1) (firstname "Mike") (average 70.0))
f-2     (quiz (id 2) (course "Math") (quizname "Exercise") (userid 1) (firstname "Mike") (average 20.0))
f-3     (quiz (id 3) (course "Math") (quizname "Sum") (userid 2) (firstname "Ronald") (average 90.0))
f-4     (quiz (id 4) (course "Math") (quizname "Equations") (userid 2) (firstname "Ronald") (average 60.0))
f-5     (quiz (id 9) (course "English") (quizname "Listening") (userid 5) (firstname "Lionel") (average 60.0))
For a total of 5 facts.
CLIPS>