Functional programming 定理证明者:如何优化包含“a”的向后证明搜索;无用的规则和;

Functional programming 定理证明者:如何优化包含“a”的向后证明搜索;无用的规则和;,functional-programming,ocaml,proof,theorem-proving,proof-system,Functional Programming,Ocaml,Proof,Theorem Proving,Proof System,快速回顾: 推理规则=结论+规则+前提 证明树=结论+规则+子树 反向证明搜索:给定一个输入目标,尝试通过自下而上的方式应用推理规则来构建证明树(例如,目标是最终结论,应用规则后,它将在前提上生成一个新的子目标列表) 问题: 给定一个输入目标(例如A和B,C),假设我们应用规则,首先对A和B,然后得到两个新的子目标,第一个是A,C,第二个是B,C 问题是A和B是无用的,这意味着我们可以只使用C构建一个完整的证明树。然而,我们有两个子目标,然后我们必须两次证明C,所以它确实低效 问题: 例如,

快速回顾:

  • 推理规则=结论+规则+前提
  • 证明树=结论+规则+子树
  • 反向证明搜索:给定一个输入目标,尝试通过自下而上的方式应用推理规则来构建证明树(例如,目标是最终结论,应用规则后,它将在前提上生成一个新的子目标列表)
问题:
给定一个输入目标(例如
A和B,C
),假设我们应用规则,首先对
A和B
,然后得到两个新的子目标,第一个是
A,C
,第二个是
B,C

问题是
A
B
是无用的,这意味着我们可以只使用
C
构建一个完整的证明树。然而,我们有两个子目标,然后我们必须两次证明
C
,所以它确实低效

问题:
例如,我们有
A和B,C和D,E和F,G,H和I
。在这种情况下,我们只需要D和G来构建一个完整的证明树。那么,如何选择正确的规则来应用呢

这是Ocaml中的示例代码:

(* conclusion -> tree *)
let rec prove goal =                                          (* the function builds a proof tree from an input goal *)
  let rule      = get_rule goal in                            (* get the first rule *)
  let sub-goals = apply_rule goal in                          (* apply a rule *)
  let sub-trees = List.map (fun g -> prove g) sub-goals in    (* prove sub-goals recursively *)
  (goal, rule, sub-trees)                                     (* return proof tree *)
如果您想要最短(最浅)的证明,在本例中使用析取引入并避免合取引入,那么您可以考虑以下技术。例如,您可以按如下方式更改代码:

let rec prove n goal =
  if n=0 then failwith "No proof found" else
  let rule      = get_rule goal in
  let sub-goals = apply_rule goal in
  let sub-trees = List.map (fun g -> prove (n-1) g) sub-goals in
  (goal, rule, sub-trees)

let idfs maxn goal =
  let rec aux n =
    if n > maxn then None else
    try 
      Some (prove n goal)
    with Failure _ -> aux (n+1) in
  aux 1
如果你想避免为已经出现的子目标重新做证明,那么你可以使用某种形式的记忆(一种引理推测/应用的狭义形式)。例如,请参阅此问题的答案,尤其是第二个答案,因为
prove
自然是递归的


这些建议并不涉及您如何选择要应用的规则,即
get_rule
的确切编码方式。在实践中,有许多选项可用,您可能希望对它们进行迭代。

您的意思是如何找到最短(最浅)的证明树,还是如何避免对在证明搜索中出现两次的子目标重复进行相同的证明?