1use logicaffeine_base::Arena;
12use crate::ast::{LogicExpr, NeoEventData, Term, ThematicRole};
13use logicaffeine_base::{Interner, Symbol};
14use crate::lexicon::{lookup_canonical, Polarity};
15use crate::token::TokenType;
16
17use super::{is_privative_adjective, lookup_noun_entailments, lookup_noun_hypernyms, lookup_verb_entailment};
18
19pub fn apply_axioms<'a>(
21 expr: &'a LogicExpr<'a>,
22 expr_arena: &'a Arena<LogicExpr<'a>>,
23 term_arena: &'a Arena<Term<'a>>,
24 interner: &mut Interner,
25) -> &'a LogicExpr<'a> {
26 transform_expr(expr, expr_arena, term_arena, interner)
27}
28
29fn transform_expr<'a>(
30 expr: &'a LogicExpr<'a>,
31 expr_arena: &'a Arena<LogicExpr<'a>>,
32 term_arena: &'a Arena<Term<'a>>,
33 interner: &mut Interner,
34) -> &'a LogicExpr<'a> {
35 match expr {
36 LogicExpr::Predicate { name, args, .. } => {
37 expand_predicate(*name, args, expr_arena, term_arena, interner)
38 }
39
40 LogicExpr::Quantifier { kind, variable, body, island_id } => {
41 let new_body = transform_expr(body, expr_arena, term_arena, interner);
42 expr_arena.alloc(LogicExpr::Quantifier {
43 kind: *kind,
44 variable: *variable,
45 body: new_body,
46 island_id: *island_id,
47 })
48 }
49
50 LogicExpr::BinaryOp { left, op, right } => {
51 let new_left = transform_expr(left, expr_arena, term_arena, interner);
52 let new_right = transform_expr(right, expr_arena, term_arena, interner);
53 expr_arena.alloc(LogicExpr::BinaryOp {
54 left: new_left,
55 op: op.clone(),
56 right: new_right,
57 })
58 }
59
60 LogicExpr::UnaryOp { op, operand } => {
61 let new_operand = transform_expr(operand, expr_arena, term_arena, interner);
62 expr_arena.alloc(LogicExpr::UnaryOp {
63 op: op.clone(),
64 operand: new_operand,
65 })
66 }
67
68 LogicExpr::NeoEvent(data) => {
69 expand_neo_event(data, expr_arena, term_arena, interner)
70 }
71
72 LogicExpr::Modal { vector, operand } => {
73 let new_operand = transform_expr(operand, expr_arena, term_arena, interner);
74 expr_arena.alloc(LogicExpr::Modal {
75 vector: *vector,
76 operand: new_operand,
77 })
78 }
79
80 LogicExpr::Temporal { operator, body } => {
81 let new_body = transform_expr(body, expr_arena, term_arena, interner);
82 expr_arena.alloc(LogicExpr::Temporal {
83 operator: *operator,
84 body: new_body,
85 })
86 }
87
88 LogicExpr::Lambda { variable, body } => {
89 let new_body = transform_expr(body, expr_arena, term_arena, interner);
90 expr_arena.alloc(LogicExpr::Lambda {
91 variable: *variable,
92 body: new_body,
93 })
94 }
95
96 LogicExpr::Question { wh_variable, body } => {
97 let new_body = transform_expr(body, expr_arena, term_arena, interner);
98 expr_arena.alloc(LogicExpr::Question {
99 wh_variable: *wh_variable,
100 body: new_body,
101 })
102 }
103
104 LogicExpr::YesNoQuestion { body } => {
105 let new_body = transform_expr(body, expr_arena, term_arena, interner);
106 expr_arena.alloc(LogicExpr::YesNoQuestion { body: new_body })
107 }
108
109 _ => expr,
110 }
111}
112
113fn expand_predicate<'a>(
114 name: Symbol,
115 args: &'a [Term<'a>],
116 expr_arena: &'a Arena<LogicExpr<'a>>,
117 term_arena: &'a Arena<Term<'a>>,
118 interner: &mut Interner,
119) -> &'a LogicExpr<'a> {
120 let name_str = interner.resolve(name).to_string();
121 let lower_name = name_str.to_lowercase();
122
123 if let Some(mapping) = lookup_canonical(&lower_name) {
126 let canonical_sym = interner.intern(mapping.lemma);
127 let canonical_pred = expr_arena.alloc(LogicExpr::Predicate {
128 name: canonical_sym,
129 args,
130 world: None,
131 });
132
133 return match mapping.polarity {
135 Polarity::Positive => canonical_pred,
136 Polarity::Negative => expr_arena.alloc(LogicExpr::UnaryOp {
137 op: TokenType::Not,
138 operand: canonical_pred,
139 }),
140 };
141 }
142
143 if let Some(hyphen_pos) = name_str.find('-') {
145 let adj_part = name_str[..hyphen_pos].to_string();
146 let noun_part = name_str[hyphen_pos + 1..].to_string();
147
148 if is_privative_adjective(&adj_part) {
149 return expand_privative(&noun_part, args, expr_arena, term_arena, interner);
150 }
151 }
152
153 let entailments = lookup_noun_entailments(&lower_name);
155 if !entailments.is_empty() {
156 return expand_noun_entailments(name, args, entailments, expr_arena, term_arena, interner);
157 }
158
159 let hypernyms = lookup_noun_hypernyms(&lower_name);
161 if !hypernyms.is_empty() {
162 return expand_hypernyms(name, args, hypernyms, expr_arena, term_arena, interner);
163 }
164
165 expr_arena.alloc(LogicExpr::Predicate { name, args, world: None })
167}
168
169fn expand_privative<'a>(
170 noun: &str,
171 args: &'a [Term<'a>],
172 expr_arena: &'a Arena<LogicExpr<'a>>,
173 term_arena: &'a Arena<Term<'a>>,
174 interner: &mut Interner,
175) -> &'a LogicExpr<'a> {
176 let noun_sym = interner.intern(noun);
178 let resembles_sym = interner.intern("Resembles");
179
180 let noun_pred = expr_arena.alloc(LogicExpr::Predicate {
182 name: noun_sym,
183 args,
184 world: None,
185 });
186
187 let negated_noun = expr_arena.alloc(LogicExpr::UnaryOp {
189 op: TokenType::Not,
190 operand: noun_pred,
191 });
192
193 let intension_term = Term::Intension(noun_sym);
195 let mut resembles_args_vec = Vec::with_capacity(args.len() + 1);
196 if !args.is_empty() {
197 resembles_args_vec.push(clone_term(&args[0], term_arena));
198 }
199 resembles_args_vec.push(intension_term);
200 let resembles_args = term_arena.alloc_slice(resembles_args_vec);
201
202 let resembles_pred = expr_arena.alloc(LogicExpr::Predicate {
203 name: resembles_sym,
204 args: resembles_args,
205 world: None,
206 });
207
208 expr_arena.alloc(LogicExpr::BinaryOp {
210 left: negated_noun,
211 op: TokenType::And,
212 right: resembles_pred,
213 })
214}
215
216fn expand_noun_entailments<'a>(
217 base: Symbol,
218 args: &'a [Term<'a>],
219 entailments: &[&str],
220 expr_arena: &'a Arena<LogicExpr<'a>>,
221 term_arena: &'a Arena<Term<'a>>,
222 interner: &mut Interner,
223) -> &'a LogicExpr<'a> {
224 let base_pred = expr_arena.alloc(LogicExpr::Predicate { name: base, args, world: None });
226
227 let mut result: &LogicExpr = base_pred;
228 for entailment in entailments {
229 let ent_sym = interner.intern(entailment);
230 let ent_pred = expr_arena.alloc(LogicExpr::Predicate {
231 name: ent_sym,
232 args,
233 world: None,
234 });
235 result = expr_arena.alloc(LogicExpr::BinaryOp {
236 left: result,
237 op: TokenType::And,
238 right: ent_pred,
239 });
240 }
241
242 result
243}
244
245fn expand_hypernyms<'a>(
246 base: Symbol,
247 args: &'a [Term<'a>],
248 hypernyms: &[&str],
249 expr_arena: &'a Arena<LogicExpr<'a>>,
250 term_arena: &'a Arena<Term<'a>>,
251 interner: &mut Interner,
252) -> &'a LogicExpr<'a> {
253 let base_pred = expr_arena.alloc(LogicExpr::Predicate { name: base, args, world: None });
255
256 let mut result: &LogicExpr = base_pred;
257 for hypernym in hypernyms {
258 let hyp_sym = interner.intern(hypernym);
259 let hyp_pred = expr_arena.alloc(LogicExpr::Predicate {
260 name: hyp_sym,
261 args,
262 world: None,
263 });
264 result = expr_arena.alloc(LogicExpr::BinaryOp {
265 left: result,
266 op: TokenType::And,
267 right: hyp_pred,
268 });
269 }
270
271 result
272}
273
274fn expand_neo_event<'a>(
275 data: &NeoEventData<'a>,
276 expr_arena: &'a Arena<LogicExpr<'a>>,
277 term_arena: &'a Arena<Term<'a>>,
278 interner: &mut Interner,
279) -> &'a LogicExpr<'a> {
280 let verb_str = interner.resolve(data.verb);
281 let lower_verb = verb_str.to_lowercase();
282
283 if let Some(mapping) = lookup_canonical(&lower_verb) {
286 let canonical_sym = interner.intern(mapping.lemma);
287
288 let canonical_event = expr_arena.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
290 event_var: data.event_var,
291 verb: canonical_sym,
292 roles: data.roles,
293 modifiers: data.modifiers,
294 suppress_existential: data.suppress_existential,
295 world: None,
296 })));
297
298 return match mapping.polarity {
300 Polarity::Positive => canonical_event,
301 Polarity::Negative => expr_arena.alloc(LogicExpr::UnaryOp {
302 op: TokenType::Not,
303 operand: canonical_event,
304 }),
305 };
306 }
307
308 if let Some((base_verb, manner_preds)) = lookup_verb_entailment(&lower_verb) {
309 let base_verb_sym = interner.intern(base_verb);
311
312 let original = expr_arena.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
314 event_var: data.event_var,
315 verb: data.verb,
316 roles: data.roles,
317 modifiers: data.modifiers,
318 suppress_existential: data.suppress_existential,
319 world: None,
320 })));
321
322 let entailed_event = expr_arena.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
324 event_var: data.event_var,
325 verb: base_verb_sym,
326 roles: data.roles,
327 modifiers: data.modifiers,
328 suppress_existential: data.suppress_existential,
329 world: None,
330 })));
331
332 let mut result = expr_arena.alloc(LogicExpr::BinaryOp {
334 left: original,
335 op: TokenType::And,
336 right: entailed_event,
337 });
338
339 for manner in manner_preds {
341 let manner_sym = interner.intern(manner);
342
343 let agent_term = data.roles.iter()
345 .find(|(role, _)| *role == ThematicRole::Agent)
346 .map(|(_, term)| term);
347
348 if let Some(agent) = agent_term {
349 let manner_args = term_arena.alloc_slice([clone_term(agent, term_arena)]);
350 let manner_pred = expr_arena.alloc(LogicExpr::Predicate {
351 name: manner_sym,
352 args: manner_args,
353 world: None,
354 });
355 result = expr_arena.alloc(LogicExpr::BinaryOp {
356 left: result,
357 op: TokenType::And,
358 right: manner_pred,
359 });
360 }
361 }
362
363 result
364 } else {
365 expr_arena.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
367 event_var: data.event_var,
368 verb: data.verb,
369 roles: data.roles,
370 modifiers: data.modifiers,
371 suppress_existential: data.suppress_existential,
372 world: None,
373 })))
374 }
375}
376
377fn clone_term<'a>(term: &Term<'a>, arena: &'a Arena<Term<'a>>) -> Term<'a> {
378 match term {
379 Term::Constant(s) => Term::Constant(*s),
380 Term::Variable(s) => Term::Variable(*s),
381 Term::Function(s, args) => {
382 let cloned_args: Vec<Term<'a>> = args.iter().map(|t| clone_term(t, arena)).collect();
383 Term::Function(*s, arena.alloc_slice(cloned_args))
384 }
385 Term::Group(terms) => {
386 let cloned: Vec<Term<'a>> = terms.iter().map(|t| clone_term(t, arena)).collect();
387 Term::Group(arena.alloc_slice(cloned))
388 }
389 Term::Possessed { possessor, possessed } => {
390 let cloned_possessor = arena.alloc(clone_term(possessor, arena));
391 Term::Possessed { possessor: cloned_possessor, possessed: *possessed }
392 }
393 Term::Sigma(s) => Term::Sigma(*s),
394 Term::Intension(s) => Term::Intension(*s),
395 Term::Proposition(e) => Term::Proposition(*e),
396 Term::Value { kind, unit, dimension } => Term::Value {
397 kind: *kind,
398 unit: *unit,
399 dimension: *dimension,
400 },
401 }
402}