为什么先读这个?
Reasoner 类里有三个最重要的成员:CGraph(完工图)、curNode(当前节点)和 TODO(待办清单)。如果不先搞清楚"节点"长什么样、"图"怎么存,后面所有的 createOneNeighbour 和 addToDoEntry 都是空中楼阁。
在 Tableau 算法里,节点最核心的职责就是装着它所属的概念集合(比如,这个个体属于 A,也属于 ∃R.B)。在 FaCT++ 里,这个概念集合通常叫 Label 或 CGLabel。
核心成员变量:
1 | CGLabel Label; // 概念标签集合(所有断言的集合) |
对应 Tableau 概念:
| 成员 | 对应 Tableau 概念 | 说明 |
|---|---|---|
Label |
节点上的概念集合 | 如 {A, ∃R.B, ¬C},Tableau 算法的所有规则都围绕它展开 |
Neighbour |
角色边 R(x, y) |
存储该节点的所有角色边,是处理 ∀ 和 ∃ 规则的依据 |
Blocker / pBlocked / dBlocked |
阻塞机制 | 保证算法终止。Blocker 指向阻塞者节点,pBlocked 表示被"净化"(间接阻塞),dBlocked 表示直接阻塞 |
cached |
模型缓存 | 缓存该节点代表的模型片段,加速包含关系测试 |
nominalLevel |
名义节点标记 | 区分名义节点(OWL 中指名道姓的个体)与普通块节点,名义节点不能随意合并 |
这个文件定义了 DlCompletionTreeArc 类。在 Tableau 算法的 ABox(断言盒)里,它代表的就是 R(x, y)(个体间的角色关系)。
核心成员变量:
1 | protected: |
对应 Tableau 概念的关键点:
Reverse)在 Tableau 推理中,经常需要知道**“谁指向了我”**。如果只存单向的 x -> y,当算法在处理 y 时,就不知道是谁带来了它。
FaCT++ 采用双向边设计(存了 Reverse 反向指针),这使得无论从哪一头都能快速找到另一头,避免在庞大的图中进行低效的全局搜索。
isIBlocked 检查)1 | bool isIBlocked ( void ) const { return (Role == nullptr); } |
在 Tableau 算法的 ≤-规则(至多限制) 中,为了满足"最多 n 个邻居"的约束,如果多了一个,需要把两个节点合并(Merge)。合并时,其中一条边会被"删除"。
在 FaCT++ 里,删除边不是真的删掉指针(那样太耗时且容易内存泄漏),而是把这条边上的 Role 直接置为 nullptr!这就好比这条铁路虽然还在,但我把铁轨抽掉了,逻辑上它就不通了。
isIBlocked() 返回 true 就代表"这是一条废弃的边"。这种操作非常快,是性能优化的高招。
DepSet)depSet 记录了这条边是由哪些**“非确定性分支”(例如 ⊔-规则的选择)产生的。如果这条边导致了冲突,推理机就能通过这个依赖集判断应该回溯到哪个分支点**,而不是从头开始。
1 | bool DlSatTester :: checkSatisfiability ( void ) |
| Tableau 概念 | 代码中的体现 |
|---|---|
| ABox | DlCompletionGraph 管理所有 DlCompletionTree 节点和边 |
| 个体节点 | DlCompletionTree 对象,每个节点存储概念标签 |
| 概念标签 | 节点的 Label 成员,存储所有断言的概念 |
| 待处理队列 | ToDoList,按优先级存储待展开的概念 |
⊓-规则(合取) |
commonTacticBodyAnd 拆分合取,将子概念加入 TODO |
⊔-规则(析取) |
commonTacticBodyOr 创建分支上下文,尝试两个选项 |
∃-规则(存在) |
commonTacticBodySome 创建新节点和边 |
∀-规则(全称) |
commonTacticBodyAll 沿边传播概念 |
| 冲突检测 | tryAddConcept / checkAddedConcept 检查 A 与 ¬A |
| 阻塞(Blocking) | isIBlocked() / isPBlocked() 跳过被阻塞节点的扩展 |
| 回溯 | tunedRestore() 配合 Stack 和 SaveState |
| 设计亮点 | 说明 |
|---|---|
| 优先级驱动的 TODO 队列 | FaCT++ 区别于标准 Tableau 的重要优化,通过优先级调度提升搜索效率 |
| 双向边设计 | 通过 Reverse 指针实现双向查找,避免全局搜索 |
| 逻辑删除 | 合并边时将 Role 置为 nullptr,而非真正删除指针,高效且安全 |
| 依赖集回溯 | DepSet 记录分支决策,实现智能回溯(Backjumping)而非简单回溯 |
| 阻塞机制 | 通过 Blocker / pBlocked / dBlocked 实现算法终止保证 |
| 模型缓存 | cached 标记加速包含关系测试 |
AI 参与声明:本文档在撰写过程中使用了 AI 辅助工具进行内容整理、格式优化与润色。所有核心概念与代码分析均基于 FaCT++ 源码与公开学术文献,并经人工校验与补充。