Construct `max(a, b)` with Lean-style simplifications: - `max(k₁, k₂) = max(k₁, k₂)` when both are explicit numerals - `max(a, a) = a` - `max(0, a) = a`, `max(a, 0) = a` - `max(a, max(a, b)) = max(a, b)` (absorption) - `max(max(a, b), b) = max(a, b)` (absorption) - `max(succ^n(base), succ^m(base)) = succ^max(n,m)(base)` (same-base offset) Matches Lean's `mk_max` in `kernel/level.cpp:81-103`.
(a: KUniv<M>, b: KUniv<M>)
| 151 | } |
| 152 | |
| 153 | impl<M: KernelMode> KUniv<M> { |
| 154 | pub fn zero() -> Self { |
| 155 | KUniv::new(UnivData::Zero(super::expr::fresh_uid())) |
| 156 | } |
| 157 | |
| 158 | pub fn succ(inner: KUniv<M>) -> Self { |
| 159 | KUniv::new(UnivData::Succ(inner, super::expr::fresh_uid())) |
| 160 | } |
| 161 | |
| 162 | /// Construct `max(a, b)` with Lean-style simplifications: |
| 163 | /// |
| 164 | /// - `max(k₁, k₂) = max(k₁, k₂)` when both are explicit numerals |
| 165 | /// - `max(a, a) = a` |
| 166 | /// - `max(0, a) = a`, `max(a, 0) = a` |
| 167 | /// - `max(a, max(a, b)) = max(a, b)` (absorption) |
| 168 | /// - `max(max(a, b), b) = max(a, b)` (absorption) |
| 169 | /// - `max(succ^n(base), succ^m(base)) = succ^max(n,m)(base)` (same-base offset) |
| 170 | /// |
| 171 | /// Matches Lean's `mk_max` in `kernel/level.cpp:81-103`. |
| 172 | pub fn max(a: KUniv<M>, b: KUniv<M>) -> Self { |
| 173 | // Both explicit numerals (Succ^n(Zero)): take the larger. |
| 174 | if a.is_explicit() && b.is_explicit() { |
| 175 | let (_, na) = a.offset(); |
| 176 | let (_, nb) = b.offset(); |
| 177 | return if na >= nb { a } else { b }; |
| 178 | } |
| 179 | // Structural equality. |
| 180 | if a == b { |
| 181 | return a; |
| 182 | } |
| 183 | // Zero absorption. |
| 184 | if a.is_zero() { |
| 185 | return b; |
| 186 | } |
| 187 | if b.is_zero() { |
| 188 | return a; |
| 189 | } |
| 190 | // max(a, max(a, b')) = max(a, b'), max(a, max(b', a)) = max(b', a) |
| 191 | if let UnivData::Max(bl, br, _) = b.data() |
| 192 | && (*bl == a || *br == a) |
| 193 | { |
| 194 | return b; |
no test coverage detected