logicaffeine_proof/
lemma_index.rs1use crate::discrimination::DiscTree;
19use crate::unify::{apply_subst_to_expr, match_expr_pattern, Substitution};
20use crate::{ProofExpr, ProofTerm};
21
22#[derive(Debug, Clone)]
25pub struct Suggestion {
26 pub lemma: String,
27 pub tactic_text: String,
28 pub subst: Substitution,
29 pub remaining: Vec<ProofExpr>,
30}
31
32struct CompiledLemma {
34 name: String,
35 conclusion: ProofExpr,
36 premises: Vec<ProofExpr>,
37}
38
39pub struct LemmaIndex {
41 lemmas: Vec<CompiledLemma>,
42 concl_index: DiscTree<usize>,
43}
44
45impl LemmaIndex {
46 pub fn build(named: &[(String, ProofExpr)]) -> Self {
48 let mut lemmas = Vec::new();
49 let mut concl_index = DiscTree::new();
50 for (name, formula) in named {
51 let (premises, conclusion) = peel(formula);
52 let idx = lemmas.len();
53 concl_index.insert_expr(&conclusion, idx);
54 lemmas.push(CompiledLemma { name: name.clone(), conclusion, premises });
55 }
56 LemmaIndex { lemmas, concl_index }
57 }
58
59 pub fn find_exact(&self, goal: &ProofExpr) -> Vec<Suggestion> {
62 let mut out = self.matches(goal, "exact");
63 out.sort_by_key(|s| s.subst.len());
64 out
65 }
66
67 pub fn find_apply(&self, goal: &ProofExpr) -> Vec<Suggestion> {
70 let mut out: Vec<Suggestion> =
71 self.matches(goal, "apply").into_iter().filter(|s| !s.remaining.is_empty()).collect();
72 out.sort_by_key(|s| (s.remaining.len(), s.subst.len()));
73 out
74 }
75
76 pub fn select_premises(&self, goal: &ProofExpr, k: usize) -> Vec<String> {
81 let goal_syms = expr_symbols(goal);
82 let matching: std::collections::HashSet<usize> =
83 self.concl_index.candidates_expr(goal).into_iter().copied().collect();
84
85 let mut scored: Vec<(i64, usize)> = self
86 .lemmas
87 .iter()
88 .enumerate()
89 .filter_map(|(i, lem)| {
90 let overlap = expr_symbols(&lem.conclusion)
91 .intersection(&goal_syms)
92 .count() as i64;
93 if overlap == 0 && !matching.contains(&i) {
94 return None; }
96 let mut score = overlap;
97 if matching.contains(&i) {
98 score += 100; }
100 Some((score, i))
101 })
102 .collect();
103 scored.sort_by(|a, b| b.0.cmp(&a.0));
104 scored.truncate(k);
105 scored.into_iter().map(|(_, i)| self.lemmas[i].name.clone()).collect()
106 }
107
108 fn matches(&self, goal: &ProofExpr, verb: &str) -> Vec<Suggestion> {
109 let mut out = Vec::new();
110 let mut cand: Vec<usize> =
111 self.concl_index.candidates_expr(goal).into_iter().copied().collect();
112 cand.sort_unstable();
113 cand.dedup();
114 for i in cand {
115 let lem = &self.lemmas[i];
116 if let Some(subst) = match_expr_pattern(&lem.conclusion, goal) {
117 let remaining =
118 lem.premises.iter().map(|p| apply_subst_to_expr(p, &subst)).collect();
119 out.push(Suggestion {
120 lemma: lem.name.clone(),
121 tactic_text: format!("{verb} {}", lem.name),
122 subst,
123 remaining,
124 });
125 }
126 }
127 out
128 }
129}
130
131fn peel(formula: &ProofExpr) -> (Vec<ProofExpr>, ProofExpr) {
133 let mut body = formula;
134 while let ProofExpr::ForAll { body: inner, .. } = body {
135 body = inner;
136 }
137 let mut premises = Vec::new();
138 while let ProofExpr::Implies(a, rest) = body {
139 premises.push((**a).clone());
140 body = rest;
141 }
142 (premises, body.clone())
143}
144
145fn expr_symbols(e: &ProofExpr) -> std::collections::HashSet<String> {
148 let mut out = std::collections::HashSet::new();
149 collect_expr_symbols(e, &mut out);
150 out
151}
152
153fn collect_expr_symbols(e: &ProofExpr, out: &mut std::collections::HashSet<String>) {
154 match e {
155 ProofExpr::Predicate { name, args, .. } => {
156 out.insert(format!("p:{name}"));
157 for a in args {
158 collect_term_symbols(a, out);
159 }
160 }
161 ProofExpr::Atom(s) => {
162 out.insert(format!("a:{s}"));
163 }
164 ProofExpr::Identity(l, r) => {
165 out.insert("=".to_string());
166 collect_term_symbols(l, out);
167 collect_term_symbols(r, out);
168 }
169 ProofExpr::And(l, r)
170 | ProofExpr::Or(l, r)
171 | ProofExpr::Implies(l, r)
172 | ProofExpr::Iff(l, r) => {
173 collect_expr_symbols(l, out);
174 collect_expr_symbols(r, out);
175 }
176 ProofExpr::Not(p) => collect_expr_symbols(p, out),
177 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
178 collect_expr_symbols(body, out)
179 }
180 _ => {}
181 }
182}
183
184fn collect_term_symbols(t: &ProofTerm, out: &mut std::collections::HashSet<String>) {
185 match t {
186 ProofTerm::Constant(s) => {
187 out.insert(format!("c:{s}"));
188 }
189 ProofTerm::Function(name, args) => {
190 out.insert(format!("f:{name}"));
191 for a in args {
192 collect_term_symbols(a, out);
193 }
194 }
195 _ => {}
197 }
198}