CLIPS 巨大的内存占用

CLIPS huge memory usage

我正在使用剪辑框架构建专家系统。但是我在内存使用 atm 方面遇到了麻烦,这会使它不适合我的任务。那么问题来了:

它按预期生成了 144 个 SpinWave 事实,总共大约有 150 个事实。每个事实不应超过一堆整数(大约 15 个)。 CLIPS 消耗了 1GB 的内存,发出了大约 6mio 的内存请求。我有点困惑为什么它分配那么多内存......有人可以指出我正确的方向或给出解释。我正在使用的代码如下。提前致谢!

史蒂夫

; define helicity wave final or initial state template
(deftemplate SpinWaveMultiplet
    (slot unique_id (type INTEGER))
    (slot charge (type INTEGER))
    (slot isospin_num (type INTEGER))
    (slot isospin_denom (type INTEGER))
    (slot isospin_z_num (type INTEGER))
    (slot spin_num (type INTEGER))
    (slot spin_denom (type INTEGER))
    ; we have multislot of spin z to allow for specific components
    ; in the initial or final state
    (multislot spin_z_num)
    (slot parity (type INTEGER))
    (slot cparity (type INTEGER))
)

; define spin wave  
(deftemplate SpinWave
    (slot unique_id (type INTEGER))
    (slot charge (type INTEGER))
    (slot isospin_num (type INTEGER))
    (slot isospin_denom (type INTEGER))
    (slot isospin_z_num (type INTEGER))
    (slot spin_num (type INTEGER))
    (slot spin_denom (type INTEGER))
    (slot spin_z_num (type INTEGER))
    (slot parity (type INTEGER))
    (slot cparity (type INTEGER))
)

; allowed intermediate state spins
(deffacts user-conditions
    (AllowedQN
        (spin_nums 0 1 2) (spin_denom 1 ) (isospin_nums 0 1) (isospin_denom 1)
        (charge 0) (parity -1 1) (cparity -1 1)
    )
)


(deffacts initial-state
    (SpinWaveMultiplet (unique_id 0) (spin_num 1) (spin_denom 1) (spin_z_num -1 1)
        (isospin_num 0) (isospin_denom 1) (isospin_z_num 0)
    )
)

(deffacts final-state-list
    (SpinWaveMultiplet (unique_id 1) (spin_num 1) (spin_denom 1) (spin_z_num -1 1)
        (isospin_num 0) (isospin_denom 1) (isospin_z_num 0)
    )
    (SpinWaveMultiplet (unique_id 2) (spin_num 0) (spin_denom 1) (spin_z_num 0)
        (isospin_num 1) (isospin_denom 1) (isospin_z_num 0)
)
    (SpinWaveMultiplet (unique_id 3) (spin_num 0) (spin_denom 1) (spin_z_num 0)
        (isospin_num 1) (isospin_denom 1) (isospin_z_num 0)
    )
)

; create all spin waves
(defrule create-initial-spin-waves
    (AllowedQN
        (spin_nums $?spin_nums) (spin_denom ?spin_denom) 
        (isospin_nums $?isospin_nums) (isospin_denom ?isospin_denom)
        (charge $?charges)
        (parity $?parities)
        (cparity $?cparities)
    )
    =>
    (foreach ?charge ?charges
    (foreach ?parity ?parities
    (foreach ?cparity ?cparities

    (foreach ?isospin_num ?isospin_nums
        (bind ?isospin_z_num (* -1 ?isospin_num))
        (while (<= ?isospin_z_num ?isospin_num)
            (foreach ?spin_num ?spin_nums
                (bind ?spin_z_num (* -1 ?spin_num))
                (while (<= ?spin_z_num ?spin_num) 
                    (assert
                        (SpinWave (unique_id ?*total_unique_id_counter*) 
                        (spin_num ?spin_num) (spin_denom ?spin_denom) (spin_z_num ?spin_z_num)
                        (isospin_num ?isospin_num) (isospin_denom ?isospin_denom) (isospin_z_num ?isospin_z_num)
                        (charge ?charge) (parity ?parity) (cparity ?cparity)
                        )
                    )
                    (bind ?*total_unique_id_counter* (+ ?*total_unique_id_counter* 1))
                    (bind ?spin_z_num (+ ?spin_z_num ?spin_denom))
                )
            )
            (bind ?isospin_z_num (+ ?isospin_z_num ?isospin_denom))
        )
    )

    )
    )
    )
)

您发布的代码片段不会占用大量内存(小于 17 MB)。 CLIPS 使用 rete 算法保存规则部分匹配的状态,所以很可能你有一个或多个规则匹配生成大量部分匹配的 SpinWave 事实。

您可以使用 matches 命令获取每条规则使用的部分匹配数量的快照,并使用 join-activity 命令获取可能存在性能问题的规则的整体快照。

例如,在 运行 礼仪基准测试之后,我可以使用这些命令看到 find_seating 和 make_path 规则是我应该检查性能问题的规则。

CLIPS> (batch "manners128.bat")
TRUE
CLIPS> (clear)
CLIPS> (unwatch compilations)
CLIPS> (watch statistics)
CLIPS> (set-strategy depth)
depth
CLIPS> (load manners.clp)
:%%%%%%%********
TRUE
CLIPS> (reset)
CLIPS> (load-facts manners128.fct)
TRUE
CLIPS> (run)
8639 rules fired        Run time is 2.39572899999621 seconds.
3606.00051174973 rules per second.
4762 mean number of facts (8953 maximum).
1 mean number of instances (1 maximum).
138 mean number of activations (9490 maximum).
CLIPS> 
(progn$ 
   (?r (get-defrule-list)) 
   (printout t ?r ": " (join-activity ?r terse) crlf))
assign_first_seat: (1314 1315 1315)
find_seating: (5847660 7067211 7067211)
make_path: (49549 16510 16510)
path_done: (127 254 254)
are_we_done: (128 255 255)
continue: (0 127 127)
print_results: (257 258 128)
all_done: (0 1 0)
CLIPS> 
(progn$ 
   (?r (get-defrule-list)) 
   (printout t ?r ": " (matches ?r terse) crlf))
assign_first_seat: (439 0 0)
find_seating: (9260 0 0)
make_path: (16256 0 0)
path_done: (0 0 0)
are_we_done: (129 0 0)
continue: (0 0 0)
print_results: (8258 129 0)
all_done: (1 0 0)
CLIPS> 

根据您的评论,这是您提到的导致问题的规则之一:

(defrule check-charge 
   ?mymother <- (SpinWave (charge ?charge_mother)) 
   ?mydaughter1 <- (SpinWave (charge ?charge_daughter1)) 
   ?mydaughter2 <- (SpinWave (charge ?charge_daughter2)) 
   =>)

None 的模式具有限制匹配其他模式的事实数量的条件,因此基本上这个规则匹配三个 SpinWave 事实的所有组合。由于有 144 个事实与三个模式中的每一个匹配,因此将有 2,985,984 (144 * 144 * 144) 次规则激活。因此,即使 CLIPS 没有为前两个模式生成部分匹配,仍然会有数百万个消耗内存的激活,这些内存最终会随着每个规则激活被允许执行而被释放。

在不知道规则应该做什么或 SpinWave 事实之间的关系的情况下,很难具体说明如何使规则更有效,但通常您希望模式受限于事实的数量通过前面模式中的变量绑定匹配它们。

因此,如果事实之间存在 parent/child 关系,您可以为 SpinWave 事实添加并填充父槽,并使用它来减少部分 matches/activations 生成的数量:

(defrule check-charge 
   ?mymother <- (SpinWave (charge ?charge_mother) (unique_id ?id)) 
   ?mydaughter1 <- (SpinWave (charge ?charge_daughter1) (parent ?id)) 
   ?mydaughter2 <- (SpinWave (charge ?charge_daughter2) (parent ?id)) 
   =>)