开源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物体上”,对应的规则是"(
向规则引擎添加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
alpha meory存储在alpha_network,它是一个Hash,HashMap
这一段:
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
activate_memories本文不做解释,后文会有详细分析。