logicaffeine_language/semantics/
kripke.rs

1//! Kripke Semantics Lowering Pass
2//!
3//! Transforms modal operators into explicit possible world semantics:
4//! - Diamond P (force <= 0.5) → Exists w'(Accessible(w, w') And P(w'))
5//! - Box P (force > 0.5) → ForAll w'(Accessible(w, w') Implies P(w'))
6
7use logicaffeine_base::Arena;
8use crate::ast::{LogicExpr, ModalDomain, ModalVector, NeoEventData, QuantifierKind, Term};
9use logicaffeine_base::{Interner, Symbol};
10use crate::token::TokenType;
11
12/// Context for tracking world variables during Kripke lowering
13pub struct KripkeContext {
14    world_counter: u32,
15    current_world: Symbol,
16}
17
18impl KripkeContext {
19    pub fn new(interner: &mut Interner) -> Self {
20        Self {
21            world_counter: 0,
22            current_world: interner.intern("w0"),
23        }
24    }
25
26    pub fn fresh_world(&mut self, interner: &mut Interner) -> Symbol {
27        self.world_counter += 1;
28        interner.intern(&format!("w{}", self.world_counter))
29    }
30}
31
32/// Apply Kripke lowering to transform modal operators into explicit world quantification.
33///
34/// This transforms surface modal operators (`◇`, `□`) into explicit First-Order Logic
35/// with possible world semantics, enabling Z3 verification.
36///
37/// ## Example
38/// Surface: `◇Fly(x)` (John can fly)
39/// Deep: `∃w'(Accessible(w₀, w') ∧ Fly(x, w'))` (There exists an accessible world where John flies)
40pub fn apply_kripke_lowering<'a>(
41    expr: &'a LogicExpr<'a>,
42    expr_arena: &'a Arena<LogicExpr<'a>>,
43    term_arena: &'a Arena<Term<'a>>,
44    interner: &mut Interner,
45) -> &'a LogicExpr<'a> {
46    let mut ctx = KripkeContext::new(interner);
47    lower_expr(expr, &mut ctx, expr_arena, term_arena, interner)
48}
49
50fn lower_expr<'a>(
51    expr: &'a LogicExpr<'a>,
52    ctx: &mut KripkeContext,
53    expr_arena: &'a Arena<LogicExpr<'a>>,
54    term_arena: &'a Arena<Term<'a>>,
55    interner: &mut Interner,
56) -> &'a LogicExpr<'a> {
57    match expr {
58        LogicExpr::Modal { vector, operand } => {
59            lower_modal(vector, operand, ctx, expr_arena, term_arena, interner)
60        }
61
62        LogicExpr::Predicate { name, args, world } => {
63            if world.is_none() {
64                // Add current world to predicate
65                expr_arena.alloc(LogicExpr::Predicate {
66                    name: *name,
67                    args: *args,
68                    world: Some(ctx.current_world),
69                })
70            } else {
71                expr
72            }
73        }
74
75        LogicExpr::Quantifier { kind, variable, body, island_id } => {
76            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
77            expr_arena.alloc(LogicExpr::Quantifier {
78                kind: *kind,
79                variable: *variable,
80                body: new_body,
81                island_id: *island_id,
82            })
83        }
84
85        LogicExpr::BinaryOp { left, op, right } => {
86            let new_left = lower_expr(left, ctx, expr_arena, term_arena, interner);
87            let new_right = lower_expr(right, ctx, expr_arena, term_arena, interner);
88            expr_arena.alloc(LogicExpr::BinaryOp {
89                left: new_left,
90                op: op.clone(),
91                right: new_right,
92            })
93        }
94
95        LogicExpr::UnaryOp { op, operand } => {
96            let new_operand = lower_expr(operand, ctx, expr_arena, term_arena, interner);
97            expr_arena.alloc(LogicExpr::UnaryOp {
98                op: op.clone(),
99                operand: new_operand,
100            })
101        }
102
103        LogicExpr::NeoEvent(data) => {
104            // Set the world on the event to the current world
105            if data.world.is_none() {
106                expr_arena.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
107                    event_var: data.event_var,
108                    verb: data.verb,
109                    roles: data.roles,
110                    modifiers: data.modifiers,
111                    suppress_existential: data.suppress_existential,
112                    world: Some(ctx.current_world),
113                })))
114            } else {
115                expr
116            }
117        }
118
119        LogicExpr::Temporal { operator, body } => {
120            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
121            expr_arena.alloc(LogicExpr::Temporal {
122                operator: *operator,
123                body: new_body,
124            })
125        }
126
127        LogicExpr::Aspectual { operator, body } => {
128            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
129            expr_arena.alloc(LogicExpr::Aspectual {
130                operator: *operator,
131                body: new_body,
132            })
133        }
134
135        LogicExpr::Voice { operator, body } => {
136            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
137            expr_arena.alloc(LogicExpr::Voice {
138                operator: *operator,
139                body: new_body,
140            })
141        }
142
143        LogicExpr::Lambda { variable, body } => {
144            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
145            expr_arena.alloc(LogicExpr::Lambda {
146                variable: *variable,
147                body: new_body,
148            })
149        }
150
151        LogicExpr::App { function, argument } => {
152            let new_function = lower_expr(function, ctx, expr_arena, term_arena, interner);
153            let new_argument = lower_expr(argument, ctx, expr_arena, term_arena, interner);
154            expr_arena.alloc(LogicExpr::App {
155                function: new_function,
156                argument: new_argument,
157            })
158        }
159
160        LogicExpr::Intensional { operator, content } => {
161            let new_content = lower_expr(content, ctx, expr_arena, term_arena, interner);
162            expr_arena.alloc(LogicExpr::Intensional {
163                operator: *operator,
164                content: new_content,
165            })
166        }
167
168        LogicExpr::Control { verb, subject, object, infinitive } => {
169            let new_infinitive = lower_expr(infinitive, ctx, expr_arena, term_arena, interner);
170            expr_arena.alloc(LogicExpr::Control {
171                verb: *verb,
172                subject: *subject,
173                object: *object,
174                infinitive: new_infinitive,
175            })
176        }
177
178        LogicExpr::Scopal { operator, body } => {
179            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
180            expr_arena.alloc(LogicExpr::Scopal {
181                operator: *operator,
182                body: new_body,
183            })
184        }
185
186        LogicExpr::Question { wh_variable, body } => {
187            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
188            expr_arena.alloc(LogicExpr::Question {
189                wh_variable: *wh_variable,
190                body: new_body,
191            })
192        }
193
194        LogicExpr::YesNoQuestion { body } => {
195            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
196            expr_arena.alloc(LogicExpr::YesNoQuestion { body: new_body })
197        }
198
199        LogicExpr::Focus { kind, focused, scope } => {
200            let new_scope = lower_expr(scope, ctx, expr_arena, term_arena, interner);
201            expr_arena.alloc(LogicExpr::Focus {
202                kind: *kind,
203                focused: *focused,
204                scope: new_scope,
205            })
206        }
207
208        LogicExpr::Distributive { predicate } => {
209            let new_predicate = lower_expr(predicate, ctx, expr_arena, term_arena, interner);
210            expr_arena.alloc(LogicExpr::Distributive {
211                predicate: new_predicate,
212            })
213        }
214
215        LogicExpr::Counterfactual { antecedent, consequent } => {
216            let new_antecedent = lower_expr(antecedent, ctx, expr_arena, term_arena, interner);
217            let new_consequent = lower_expr(consequent, ctx, expr_arena, term_arena, interner);
218            expr_arena.alloc(LogicExpr::Counterfactual {
219                antecedent: new_antecedent,
220                consequent: new_consequent,
221            })
222        }
223
224        LogicExpr::Event { predicate, adverbs } => {
225            let new_predicate = lower_expr(predicate, ctx, expr_arena, term_arena, interner);
226            expr_arena.alloc(LogicExpr::Event {
227                predicate: new_predicate,
228                adverbs: *adverbs,
229            })
230        }
231
232        LogicExpr::Imperative { action } => {
233            let new_action = lower_expr(action, ctx, expr_arena, term_arena, interner);
234            expr_arena.alloc(LogicExpr::Imperative { action: new_action })
235        }
236
237        LogicExpr::Causal { effect, cause } => {
238            let new_effect = lower_expr(effect, ctx, expr_arena, term_arena, interner);
239            let new_cause = lower_expr(cause, ctx, expr_arena, term_arena, interner);
240            expr_arena.alloc(LogicExpr::Causal {
241                effect: new_effect,
242                cause: new_cause,
243            })
244        }
245
246        LogicExpr::Presupposition { assertion, presupposition } => {
247            let new_assertion = lower_expr(assertion, ctx, expr_arena, term_arena, interner);
248            let new_presupposition = lower_expr(presupposition, ctx, expr_arena, term_arena, interner);
249            expr_arena.alloc(LogicExpr::Presupposition {
250                assertion: new_assertion,
251                presupposition: new_presupposition,
252            })
253        }
254
255        LogicExpr::TemporalAnchor { anchor, body } => {
256            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
257            expr_arena.alloc(LogicExpr::TemporalAnchor {
258                anchor: *anchor,
259                body: new_body,
260            })
261        }
262
263        LogicExpr::GroupQuantifier { group_var, count, member_var, restriction, body } => {
264            let new_restriction = lower_expr(restriction, ctx, expr_arena, term_arena, interner);
265            let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
266            expr_arena.alloc(LogicExpr::GroupQuantifier {
267                group_var: *group_var,
268                count: *count,
269                member_var: *member_var,
270                restriction: new_restriction,
271                body: new_body,
272            })
273        }
274
275        // Leaf nodes that don't need transformation
276        LogicExpr::Identity { .. }
277        | LogicExpr::Metaphor { .. }
278        | LogicExpr::Categorical(_)
279        | LogicExpr::Relation(_)
280        | LogicExpr::Atom(_)
281        | LogicExpr::Superlative { .. }
282        | LogicExpr::Comparative { .. }
283        | LogicExpr::SpeechAct { .. } => expr,
284    }
285}
286
287fn lower_modal<'a>(
288    vector: &ModalVector,
289    operand: &'a LogicExpr<'a>,
290    ctx: &mut KripkeContext,
291    expr_arena: &'a Arena<LogicExpr<'a>>,
292    term_arena: &'a Arena<Term<'a>>,
293    interner: &mut Interner,
294) -> &'a LogicExpr<'a> {
295    let source_world = ctx.current_world;
296    let target_world = ctx.fresh_world(interner);
297
298    // Lower operand with new current world
299    let old_world = ctx.current_world;
300    ctx.current_world = target_world;
301    let lowered_operand = lower_expr(operand, ctx, expr_arena, term_arena, interner);
302    ctx.current_world = old_world;
303
304    // Create accessibility predicate based on modal domain
305    let access_name = match vector.domain {
306        ModalDomain::Alethic => interner.intern("Accessible_Alethic"),
307        ModalDomain::Deontic => interner.intern("Accessible_Deontic"),
308    };
309
310    let accessibility = expr_arena.alloc(LogicExpr::Predicate {
311        name: access_name,
312        args: term_arena.alloc_slice([
313            Term::Variable(source_world),
314            Term::Variable(target_world),
315        ]),
316        world: None, // Accessibility predicate is a meta-level relation
317    });
318
319    if vector.force > 0.5 {
320        // Necessity (Box): ForAll w'(Accessible(w, w') -> P(w'))
321        let implication = expr_arena.alloc(LogicExpr::BinaryOp {
322            left: accessibility,
323            op: TokenType::If,
324            right: lowered_operand,
325        });
326        expr_arena.alloc(LogicExpr::Quantifier {
327            kind: QuantifierKind::Universal,
328            variable: target_world,
329            body: implication,
330            island_id: 0,
331        })
332    } else {
333        // Possibility (Diamond): Exists w'(Accessible(w, w') ∧ P(w'))
334        let conjunction = expr_arena.alloc(LogicExpr::BinaryOp {
335            left: accessibility,
336            op: TokenType::And,
337            right: lowered_operand,
338        });
339        expr_arena.alloc(LogicExpr::Quantifier {
340            kind: QuantifierKind::Existential,
341            variable: target_world,
342            body: conjunction,
343            island_id: 0,
344        })
345    }
346}