lean_agentic/
level.rs

1//! Universe levels for Lean's predicative type theory
2//!
3//! Implements universe levels: 0, 1, 2, ..., u+1, max(u,v), imax(u,v)
4
5use std::fmt;
6use std::collections::HashMap;
7
8/// Interned universe level ID
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
10pub struct LevelId(u32);
11
12impl LevelId {
13    /// Create a new level ID (internal use only)
14    pub(crate) fn new(id: u32) -> Self {
15        Self(id)
16    }
17
18    /// Get the raw ID value
19    pub fn raw(self) -> u32 {
20        self.0
21    }
22}
23
24/// Universe level expressions
25#[derive(Debug, Clone, PartialEq, Eq, Hash)]
26pub enum Level {
27    /// Zero level (Type 0 = Prop in Lean 4)
28    Zero,
29
30    /// Concrete level n (Type n)
31    Const(u32),
32
33    /// Level parameter (polymorphic universe variable)
34    Param(u32),
35
36    /// Successor level (u + 1)
37    Succ(LevelId),
38
39    /// Maximum of two levels
40    Max(LevelId, LevelId),
41
42    /// Impredicative maximum (like max but Type imax 0 u = Type 0)
43    IMax(LevelId, LevelId),
44}
45
46impl Level {
47    /// Check if this is the zero level
48    pub fn is_zero(&self) -> bool {
49        matches!(self, Level::Zero)
50    }
51
52    /// Check if this is a concrete constant
53    pub fn is_const(&self) -> bool {
54        matches!(self, Level::Const(_))
55    }
56
57    /// Create a concrete level
58    pub fn from_u32(n: u32) -> Self {
59        if n == 0 {
60            Level::Zero
61        } else {
62            Level::Const(n)
63        }
64    }
65}
66
67impl fmt::Display for Level {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        match self {
70            Level::Zero => write!(f, "0"),
71            Level::Const(n) => write!(f, "{}", n),
72            Level::Param(n) => write!(f, "u{}", n),
73            Level::Succ(id) => write!(f, "(succ {})", id.0),
74            Level::Max(a, b) => write!(f, "(max {} {})", a.0, b.0),
75            Level::IMax(a, b) => write!(f, "(imax {} {})", a.0, b.0),
76        }
77    }
78}
79
80/// Arena for interning universe levels
81pub struct LevelArena {
82    levels: Vec<Level>,
83    cache: HashMap<Level, LevelId>,
84}
85
86impl LevelArena {
87    /// Create a new level arena
88    pub fn new() -> Self {
89        let mut arena = Self {
90            levels: Vec::new(),
91            cache: HashMap::new(),
92        };
93        // Pre-intern common levels
94        arena.intern(Level::Zero);
95        arena
96    }
97
98    /// Intern a level and return its ID
99    pub fn intern(&mut self, level: Level) -> LevelId {
100        if let Some(&id) = self.cache.get(&level) {
101            return id;
102        }
103
104        let id = LevelId::new(self.levels.len() as u32);
105        self.levels.push(level.clone());
106        self.cache.insert(level, id);
107        id
108    }
109
110    /// Get a level by its ID
111    pub fn get(&self, id: LevelId) -> Option<&Level> {
112        self.levels.get(id.0 as usize)
113    }
114
115    /// Get the zero level ID
116    pub fn zero(&mut self) -> LevelId {
117        self.intern(Level::Zero)
118    }
119
120    /// Create a concrete level
121    pub fn constant(&mut self, n: u32) -> LevelId {
122        self.intern(Level::from_u32(n))
123    }
124
125    /// Create a parameter level
126    pub fn param(&mut self, n: u32) -> LevelId {
127        self.intern(Level::Param(n))
128    }
129
130    /// Create a successor level
131    pub fn succ(&mut self, id: LevelId) -> LevelId {
132        self.intern(Level::Succ(id))
133    }
134
135    /// Create a max level
136    pub fn max(&mut self, a: LevelId, b: LevelId) -> LevelId {
137        self.intern(Level::Max(a, b))
138    }
139
140    /// Create an imax level
141    pub fn imax(&mut self, a: LevelId, b: LevelId) -> LevelId {
142        self.intern(Level::IMax(a, b))
143    }
144
145    /// Normalize a level (reduce max/imax where possible)
146    pub fn normalize(&mut self, id: LevelId) -> LevelId {
147        let level = self.get(id).unwrap().clone();
148
149        match level {
150            Level::Succ(inner) => {
151                let normalized = self.normalize(inner);
152                if let Some(Level::Const(n)) = self.get(normalized) {
153                    return self.constant(n + 1);
154                }
155                self.succ(normalized)
156            }
157            Level::Max(a, b) => {
158                let a_norm = self.normalize(a);
159                let b_norm = self.normalize(b);
160
161                // max(n, m) = max(n, m) for constants
162                if let (Some(Level::Const(n)), Some(Level::Const(m))) =
163                    (self.get(a_norm), self.get(b_norm))
164                {
165                    return self.constant((*n).max(*m));
166                }
167
168                self.max(a_norm, b_norm)
169            }
170            Level::IMax(a, b) => {
171                let a_norm = self.normalize(a);
172                let b_norm = self.normalize(b);
173
174                // imax(0, u) = 0
175                if let Some(Level::Zero) = self.get(b_norm) {
176                    return self.zero();
177                }
178
179                // imax(n, m) = max(n, m) for constants
180                if let (Some(Level::Const(n)), Some(Level::Const(m))) =
181                    (self.get(a_norm), self.get(b_norm))
182                {
183                    return self.constant((*n).max(*m));
184                }
185
186                self.imax(a_norm, b_norm)
187            }
188            _ => id,
189        }
190    }
191}
192
193impl Default for LevelArena {
194    fn default() -> Self {
195        Self::new()
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202
203    #[test]
204    fn test_level_interning() {
205        let mut arena = LevelArena::new();
206
207        let zero1 = arena.zero();
208        let zero2 = arena.zero();
209        assert_eq!(zero1, zero2);
210
211        let one = arena.constant(1);
212        let succ_zero = arena.succ(zero1);
213        assert_ne!(one, succ_zero); // Not automatically normalized
214    }
215
216    #[test]
217    fn test_level_normalization() {
218        let mut arena = LevelArena::new();
219
220        let zero = arena.zero();
221        let one = arena.constant(1);
222        let two = arena.constant(2);
223
224        let max = arena.max(one, two);
225        let normalized = arena.normalize(max);
226
227        assert_eq!(normalized, two);
228    }
229
230    #[test]
231    fn test_imax_reduction() {
232        let mut arena = LevelArena::new();
233
234        let zero = arena.zero();
235        let one = arena.constant(1);
236
237        let imax = arena.imax(one, zero);
238        let normalized = arena.normalize(imax);
239
240        assert_eq!(normalized, zero);
241    }
242}