1use crate::ast::logic::{
16 LogicExpr, ModalDomain, ModalFlavor, QuantifierKind, TemporalOperator, Term, ThematicRole,
17};
18use crate::intern::Interner;
19use crate::lexicon::get_canonical_noun;
20use logicaffeine_proof::{ProofExpr, ProofTerm};
21use crate::token::TokenType;
22
23pub fn logic_expr_to_proof_expr<'a>(expr: &LogicExpr<'a>, interner: &Interner) -> ProofExpr {
32 match expr {
33 LogicExpr::Predicate { name, args, world } => {
35 let name_str = interner.resolve(*name);
40 let normalized = get_canonical_noun(&name_str.to_lowercase())
41 .map(|lemma| lemma.to_lowercase())
42 .unwrap_or_else(|| name_str.to_lowercase());
43
44 ProofExpr::Predicate {
45 name: normalized,
46 args: args.iter().map(|t| term_to_proof_term(t, interner)).collect(),
47 world: world.map(|w| interner.resolve(w).to_string()),
48 }
49 }
50
51 LogicExpr::Identity { left, right } => ProofExpr::Identity(
52 term_to_proof_term(left, interner),
53 term_to_proof_term(right, interner),
54 ),
55
56 LogicExpr::Atom(s) => ProofExpr::Atom(interner.resolve(*s).to_string()),
57
58 LogicExpr::Quantifier {
60 kind,
61 variable,
62 body,
63 ..
64 } => {
65 let var_name = interner.resolve(*variable).to_string();
66 let body_expr = Box::new(logic_expr_to_proof_expr(body, interner));
67
68 match kind {
69 QuantifierKind::Universal => ProofExpr::ForAll {
70 variable: var_name,
71 body: body_expr,
72 },
73 QuantifierKind::Existential => ProofExpr::Exists {
74 variable: var_name,
75 body: body_expr,
76 },
77 QuantifierKind::Most => ProofExpr::Unsupported("Most quantifier".into()),
79 QuantifierKind::Few => ProofExpr::Unsupported("Few quantifier".into()),
80 QuantifierKind::Many => ProofExpr::Unsupported("Many quantifier".into()),
81 QuantifierKind::Generic => ProofExpr::ForAll {
82 variable: var_name,
83 body: body_expr,
84 },
85 QuantifierKind::Cardinal(n) => {
86 ProofExpr::Exists {
88 variable: format!("{}_{}", var_name, n),
89 body: body_expr,
90 }
91 }
92 QuantifierKind::AtLeast(_) | QuantifierKind::AtMost(_) => {
93 ProofExpr::Unsupported("Counting quantifier".into())
94 }
95 }
96 }
97
98 LogicExpr::BinaryOp { left, op, right } => {
100 let l = Box::new(logic_expr_to_proof_expr(left, interner));
101 let r = Box::new(logic_expr_to_proof_expr(right, interner));
102
103 match op {
104 TokenType::And => ProofExpr::And(l, r),
105 TokenType::Or => ProofExpr::Or(l, r),
106 TokenType::If | TokenType::Then => ProofExpr::Implies(l, r),
107 TokenType::Iff => ProofExpr::Iff(l, r),
108 _ => ProofExpr::Unsupported(format!("Binary operator {:?}", op)),
109 }
110 }
111
112 LogicExpr::UnaryOp { op, operand } => {
113 let inner = Box::new(logic_expr_to_proof_expr(operand, interner));
114 match op {
115 TokenType::Not => ProofExpr::Not(inner),
116 _ => ProofExpr::Unsupported(format!("Unary operator {:?}", op)),
117 }
118 }
119
120 LogicExpr::Modal { vector, operand } => {
122 let body = Box::new(logic_expr_to_proof_expr(operand, interner));
123 let domain = match vector.domain {
124 ModalDomain::Alethic => "Alethic",
125 ModalDomain::Deontic => "Deontic",
126 };
127 let flavor = match vector.flavor {
128 ModalFlavor::Root => "Root",
129 ModalFlavor::Epistemic => "Epistemic",
130 };
131 ProofExpr::Modal {
132 domain: domain.to_string(),
133 force: vector.force,
134 flavor: flavor.to_string(),
135 body,
136 }
137 }
138
139 LogicExpr::Temporal { operator, body } => {
141 let body_expr = Box::new(logic_expr_to_proof_expr(body, interner));
142 let op_name = match operator {
143 TemporalOperator::Past => "Past",
144 TemporalOperator::Future => "Future",
145 };
146 ProofExpr::Temporal {
147 operator: op_name.to_string(),
148 body: body_expr,
149 }
150 }
151
152 LogicExpr::Lambda { variable, body } => ProofExpr::Lambda {
154 variable: interner.resolve(*variable).to_string(),
155 body: Box::new(logic_expr_to_proof_expr(body, interner)),
156 },
157
158 LogicExpr::App { function, argument } => ProofExpr::App(
159 Box::new(logic_expr_to_proof_expr(function, interner)),
160 Box::new(logic_expr_to_proof_expr(argument, interner)),
161 ),
162
163 LogicExpr::NeoEvent(data) => {
165 let roles: Vec<(String, ProofTerm)> = data
166 .roles
167 .iter()
168 .map(|(role, term)| {
169 let role_name = match role {
170 ThematicRole::Agent => "Agent",
171 ThematicRole::Patient => "Patient",
172 ThematicRole::Theme => "Theme",
173 ThematicRole::Recipient => "Recipient",
174 ThematicRole::Goal => "Goal",
175 ThematicRole::Source => "Source",
176 ThematicRole::Instrument => "Instrument",
177 ThematicRole::Location => "Location",
178 ThematicRole::Time => "Time",
179 ThematicRole::Manner => "Manner",
180 };
181 (role_name.to_string(), term_to_proof_term(term, interner))
182 })
183 .collect();
184
185 ProofExpr::NeoEvent {
186 event_var: interner.resolve(data.event_var).to_string(),
187 verb: interner.resolve(data.verb).to_string(),
188 roles,
189 }
190 }
191
192 LogicExpr::Counterfactual {
194 antecedent,
195 consequent,
196 } => {
197 ProofExpr::Implies(
199 Box::new(logic_expr_to_proof_expr(antecedent, interner)),
200 Box::new(logic_expr_to_proof_expr(consequent, interner)),
201 )
202 }
203
204 LogicExpr::Categorical(_) => ProofExpr::Unsupported("Categorical (legacy)".into()),
206 LogicExpr::Relation(_) => ProofExpr::Unsupported("Relation (legacy)".into()),
207 LogicExpr::Metaphor { .. } => ProofExpr::Unsupported("Metaphor".into()),
208 LogicExpr::Question { .. } => ProofExpr::Unsupported("Question".into()),
209 LogicExpr::YesNoQuestion { .. } => ProofExpr::Unsupported("YesNoQuestion".into()),
210 LogicExpr::Intensional { .. } => ProofExpr::Unsupported("Intensional".into()),
211 LogicExpr::Event { .. } => ProofExpr::Unsupported("Event (legacy)".into()),
212 LogicExpr::Imperative { .. } => ProofExpr::Unsupported("Imperative".into()),
213 LogicExpr::SpeechAct { .. } => ProofExpr::Unsupported("SpeechAct".into()),
214 LogicExpr::Causal { .. } => ProofExpr::Unsupported("Causal".into()),
215 LogicExpr::Comparative { .. } => ProofExpr::Unsupported("Comparative".into()),
216 LogicExpr::Superlative { .. } => ProofExpr::Unsupported("Superlative".into()),
217 LogicExpr::Scopal { .. } => ProofExpr::Unsupported("Scopal".into()),
218 LogicExpr::Control { .. } => ProofExpr::Unsupported("Control".into()),
219 LogicExpr::Presupposition { .. } => ProofExpr::Unsupported("Presupposition".into()),
220 LogicExpr::Focus { .. } => ProofExpr::Unsupported("Focus".into()),
221 LogicExpr::TemporalAnchor { .. } => ProofExpr::Unsupported("TemporalAnchor".into()),
222 LogicExpr::Distributive { .. } => ProofExpr::Unsupported("Distributive".into()),
223 LogicExpr::GroupQuantifier { .. } => ProofExpr::Unsupported("GroupQuantifier".into()),
224 LogicExpr::Aspectual { body, .. } => logic_expr_to_proof_expr(body, interner),
228 LogicExpr::Voice { .. } => ProofExpr::Unsupported("Voice".into()),
229 }
230}
231
232pub fn term_to_proof_term<'a>(term: &Term<'a>, interner: &Interner) -> ProofTerm {
234 match term {
235 Term::Constant(s) => ProofTerm::Constant(interner.resolve(*s).to_string()),
236
237 Term::Variable(s) => ProofTerm::Variable(interner.resolve(*s).to_string()),
238
239 Term::Function(name, args) => ProofTerm::Function(
240 interner.resolve(*name).to_string(),
241 args.iter().map(|t| term_to_proof_term(t, interner)).collect(),
242 ),
243
244 Term::Group(terms) => {
245 ProofTerm::Group(terms.iter().map(|t| term_to_proof_term(t, interner)).collect())
246 }
247
248 Term::Possessed { possessor, possessed } => {
249 ProofTerm::Function(
251 "has".to_string(),
252 vec![
253 term_to_proof_term(possessor, interner),
254 ProofTerm::Constant(interner.resolve(*possessed).to_string()),
255 ],
256 )
257 }
258
259 Term::Sigma(s) => {
260 ProofTerm::Variable(interner.resolve(*s).to_string())
262 }
263
264 Term::Intension(s) => {
265 ProofTerm::Constant(format!("^{}", interner.resolve(*s)))
267 }
268
269 Term::Proposition(expr) => {
270 let proof_expr = logic_expr_to_proof_expr(expr, interner);
273 ProofTerm::Constant(format!("[{}]", proof_expr))
274 }
275
276 Term::Value { kind, unit, .. } => {
277 use crate::ast::logic::NumberKind;
279 match kind {
280 NumberKind::Integer(n) => {
281 if let Some(u) = unit {
282 ProofTerm::Constant(format!("{}{}", n, interner.resolve(*u)))
283 } else {
284 ProofTerm::Constant(n.to_string())
285 }
286 }
287 NumberKind::Real(f) => {
288 if let Some(u) = unit {
289 ProofTerm::Constant(format!("{}{}", f, interner.resolve(*u)))
290 } else {
291 ProofTerm::Constant(f.to_string())
292 }
293 }
294 NumberKind::Symbolic(s) => ProofTerm::Constant(interner.resolve(*s).to_string()),
295 }
296 }
297 }
298}
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303 use crate::arena::Arena;
304
305 #[test]
306 fn test_convert_predicate() {
307 let mut interner = Interner::new();
308 let name = interner.intern("Man");
309 let arg = interner.intern("socrates");
310
311 let arena: Arena<Term> = Arena::new();
312 let args = arena.alloc_slice([Term::Constant(arg)]);
313
314 let expr = LogicExpr::Predicate {
315 name,
316 args,
317 world: None,
318 };
319
320 let result = logic_expr_to_proof_expr(&expr, &interner);
321
322 match result {
323 ProofExpr::Predicate { name, args, world } => {
324 assert_eq!(name, "man");
326 assert_eq!(args.len(), 1);
327 assert!(matches!(&args[0], ProofTerm::Constant(s) if s == "socrates"));
329 assert!(world.is_none());
330 }
331 _ => panic!("Expected Predicate, got {:?}", result),
332 }
333 }
334
335 #[test]
336 fn test_convert_universal() {
337 let mut interner = Interner::new();
338 let var = interner.intern("x");
339 let pred = interner.intern("P");
340
341 let arena: Arena<LogicExpr> = Arena::new();
342 let term_arena: Arena<Term> = Arena::new();
343
344 let body = arena.alloc(LogicExpr::Predicate {
345 name: pred,
346 args: term_arena.alloc_slice([Term::Variable(var)]),
347 world: None,
348 });
349
350 let expr = LogicExpr::Quantifier {
351 kind: QuantifierKind::Universal,
352 variable: var,
353 body,
354 island_id: 0,
355 };
356
357 let result = logic_expr_to_proof_expr(&expr, &interner);
358
359 match result {
360 ProofExpr::ForAll { variable, body } => {
361 assert_eq!(variable, "x");
362 assert!(matches!(*body, ProofExpr::Predicate { .. }));
363 }
364 _ => panic!("Expected ForAll, got {:?}", result),
365 }
366 }
367
368 #[test]
369 fn test_convert_implication() {
370 let mut interner = Interner::new();
371 let p = interner.intern("P");
372 let q = interner.intern("Q");
373
374 let arena: Arena<LogicExpr> = Arena::new();
375
376 let left = arena.alloc(LogicExpr::Atom(p));
377 let right = arena.alloc(LogicExpr::Atom(q));
378
379 let expr = LogicExpr::BinaryOp {
380 left,
381 op: TokenType::If,
382 right,
383 };
384
385 let result = logic_expr_to_proof_expr(&expr, &interner);
386
387 match result {
388 ProofExpr::Implies(l, r) => {
389 assert!(matches!(*l, ProofExpr::Atom(ref s) if s == "P"));
390 assert!(matches!(*r, ProofExpr::Atom(ref s) if s == "Q"));
391 }
392 _ => panic!("Expected Implies, got {:?}", result),
393 }
394 }
395}