Quick review:
- Inference rule = conclusion + rule + premises
- Proof tree = conclusion + rule + sub-trees
- Backward proof search: given an input goal, try to build a proof tree by applying inference rules in bottom-up way (for example, the goal is the final conclusion, after applying a rule, it will generate a list of new sub-goals on the premises)
Problem:
Given an input goal (e.g. A AND B,C
), assume that we apply the rule AND firstly on A AND B
, then get two new sub-goals, the first one is A,C
, the second one is B,C
.
The problem is that A
and B
are useless, which means we can build a complete proof tree using only C
. However, we have two sub-goals, then we have to prove C
two times, so it is really inefficient.
Question:
For example, we have A AND B,C AND D,E AND F,G,H AND I
. In this case, we only need D and G to build a complete proof tree. So how to choose the right rules to apply?
This is an example code in 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 *)
If you want the shortest (shallowest) proof, which in this case uses disjunction introduction and avoids conjunction introduction, then you can look at techniques like iterative deepening. For instance you could change your code as follows:
If you want to avoid re-doing the proof for a sub-goal that has already appeared, then you can use some form of memoization (a narrow form of lemma speculation/application really). See for instance the answers to this question, especially the second answer since
prove
is naturally recursive.These suggestions do not touch the subject of how you pick the rules to apply, that is how exactly
get_rule
is coded. In practice, many options will be available and you would want to iterate through them.