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