[rust-020]如何把wme加入到规则引擎的网络

开源rust规则引擎,向引擎加入wme的函数如下:

pub fn add_wme(&mut self, wme: Wme) {
        let log = self.log.new(o!("wme" => format!("{:?}", wme)));
        trace!(log, "add wme");

        observe!(
            log,
            Trace::AddedWme {
                id: wme.0[0],
                attribute: wme.0[1],
                value: wme.0[2],
            }
        );

        //rustfmt是Rust官方出品的统一代码风格组件
        //这个是类似000,001,010,011....的次序排列的,01234567
        //skip的意思是,不要rustfmt对这段代码做修改,https://github.com/rust-lang/rustfmt,
        // “For things you do not want rustfmt to mangle, use #[rustfmt::skip]”

        // 根据WME的三个值,生成8种可能的AlphaTest
        #[rustfmt::skip]
            let tests = [
            AlphaTest([None,           None,           None          ]),
            AlphaTest([None,           None,           Some(wme.0[2])]),
            AlphaTest([None,           Some(wme.0[1]), None          ]),
            AlphaTest([None,           Some(wme.0[1]), Some(wme.0[2])]),
            AlphaTest([Some(wme.0[0]), None,           None          ]),
            AlphaTest([Some(wme.0[0]), None,           Some(wme.0[2])]),
            AlphaTest([Some(wme.0[0]), Some(wme.0[1]), None          ]),
            AlphaTest([Some(wme.0[0]), Some(wme.0[1]), Some(wme.0[2])]),
        ];

        // Ensure we have an entry for this WME, even if no alpha
        // memories contain it.
        //确保当前wme在alpha memory和tokens有对应值:
        // 根据key从hashmap里取value,如果取不到,则把key加进去,对应键值为默认值
        let _ = self.wme_alpha_memories.entry(wme).or_default();
        let _ = self.wme_tokens.entry(wme).or_default();

        for test in &tests {
            let alpha_memory_id = match self.alpha_tests.get(test) {
                Some(id) => id,
                None => continue,
            };

            let alpha_memory = self.alpha_network.get_mut(alpha_memory_id).unwrap();

            let log = log.new(o!("alpha" => alpha_memory.id.0));
            trace!(log, "matched");

            // Activate alpha memory
            //把wme加入到alpha memory
            alpha_memory.wmes.push(wme);
            //把哪些alphpa memory有这个wme也记录下来
            self.wme_alpha_memories
                .entry(wme)
                .or_default()
                .push(alpha_memory.id);
            //再把wem加入到beta network,也就是join node的右侧节点,激活右节点
            for join_node_id in &alpha_memory.successors {
                // right activate join node
                self.pending_activations.push(Activation {
                    node: *join_node_id,
                    kind: ActivationKind::Right(wme),
                });
            }
        }

        self.activate_memories(log);
    }

wme,是规则引擎需要处理的一个“事实”。wme是三元tuple,三个元素都是常量。

规则引擎存放多种规则,比如 “x物体在y物体上”,对应的规则是"( ^on )",其中是变量,以适用不同wme的常量,^on是常量,表示一种状态。“(A ^on B)”是一个wme,其中A和B是常量,那么,这个wme符合规则"( ^on )"。规则也可以有常量,比如"( on B)",表示任意在B上的物体。变量的位置可以是任意的,比如"(A B)","( ^on B)","(A ^on )"都是可以的。

向规则引擎添加wme,为效率起见,1)要舍弃跟所有规则都无关的wme,没有用处,2)把wme做初步的分类,以便后续步骤使用。这两个任务由alpha memory实现。

最简单的实现方式,每条规则对应一个alpha memory,当一个wme被加入到规则引擎的时候,跟所有规则alpha memory逐条对比,如果它符合某个alpha memory,那么就讲它添加到这个alpha meory,可以添加到多条alpha memroy。

这种方式的缺点是计算量太大,如果规则数量大,逐个对比耗时太久。

一种改进方式,是从wme的三个元素出发进行分析,这样,一个wem至多归属到8个alpha memory,时间的复杂度是常数。

比如 (A ^on B),它可以归属到如下8个alpha memory: (A ^on B), (A ^on *), (A * B), (* ^on B), (A * *), (* ^on *), (* * B), (*, *, *)。

实际上可能更少,有些情况可能不存在。

由此,将添加wme的时间复杂度从线性复杂度降低到常数复杂度。也就是说,把一个wme添加到规则引擎,最多只需要判断八次alpha memory即可。这也就是这段代码的意义:

// 根据WME的三个值,生成8种可能的AlphaTest
        #[rustfmt::skip]
            let tests = [
            AlphaTest([None,           None,           None          ]),
            AlphaTest([None,           None,           Some(wme.0[2])]),
            AlphaTest([None,           Some(wme.0[1]), None          ]),
            AlphaTest([None,           Some(wme.0[1]), Some(wme.0[2])]),
            AlphaTest([Some(wme.0[0]), None,           None          ]),
            AlphaTest([Some(wme.0[0]), None,           Some(wme.0[2])]),
            AlphaTest([Some(wme.0[0]), Some(wme.0[1]), None          ]),
            AlphaTest([Some(wme.0[0]), Some(wme.0[1]), Some(wme.0[2])]),
        ];

然后,再一个循环里,逐个比对wme和alpha memory,进行添加操作:

        for test in &tests {
            let alpha_memory_id = match self.alpha_tests.get(test) {
                Some(id) => id,
                None => continue,
            };
            ......
        }

代码里,alpah_tests是个hash,key是 alpha test,value是对应的alpha memory id,在这个函数做取值操作。alpha_tests在add_production函数更新。

alpha_memory.wmes.push(wme);

这里wmes是一个Vector,记录用,常规操作。

self.wme_alpha_memories
    .entry(wme)
    .or_default()
    .push(alpha_memory.id);

这里,wme_alpha_memories是一个hash,HashMap>,记录一个Wme对应那些alpha memory,常规操作。

alpha meory存储在alpha_network,它是一个Hash,HashMap,常规操作,把alpha meory id和alpha memory对应起来。

这一段:

for join_node_id in &alpha_memory.successors {
                // right activate join node
                self.pending_activations.push(Activation {
                    node: *join_node_id,
                    kind: ActivationKind::Right(wme),
                });
            }

alpha memory是第一个处理环节,它处理完后,需要进入下一个处理环节,也就是beta环节。每个alpha memroy的内部,都保存着指向beta节点的指针,称之为successors,一个alapha memory可以指向多个beta节点。beta节点本质上相当于一个产生式规则的condition部分。

那么,当一个wme加入到规则引擎后,它对应的alpha memroy记录下这个wme之后,需要通知successors,有新的wme进来了,以更新beta环节的网络,这就是上面这段代码的意思。

pending_activations是一个Vec,记录要处理的Activation。待所有alpha test处理完成后,一次性执行self.activate_memories(log),统一更新beta环节。

activate_memories本文不做解释,后文会有详细分析。

 

 

你可能感兴趣的:(rust,rust)