1use crate::env_builder::*;
6use oxilean_kernel::{Declaration, Environment, Expr, Level, Name};
7
8use super::functions::*;
9use std::fmt;
10
11#[derive(Debug, Clone, Default)]
17pub struct EqualityDatabase {
18 entries: Vec<(Name, Name, Expr)>,
19}
20impl EqualityDatabase {
21 pub fn new() -> Self {
23 Self::default()
24 }
25 pub fn register(&mut self, lhs: Name, rhs: Name, proof: Expr) {
27 self.entries.push((lhs, rhs, proof));
28 }
29 pub fn lookup(&self, lhs: &Name, rhs: &Name) -> Option<Expr> {
34 for (l, r, p) in &self.entries {
35 if l == lhs && r == rhs {
36 return Some(p.clone());
37 }
38 if l == rhs && r == lhs {
39 return Some(app(
40 app(app(app(var("Eq.symm"), var("_")), var("_")), var("_")),
41 p.clone(),
42 ));
43 }
44 }
45 None
46 }
47 pub fn lookup_trans(&self, a: &Name, c: &Name) -> Option<Expr> {
49 for (l1, r1, p1) in &self.entries {
50 if l1 == a {
51 for (l2, r2, p2) in &self.entries {
52 if l2 == r1 && r2 == c {
53 return Some(eq_trans(
54 var("_"),
55 var(l1.to_string().as_str()),
56 var(r1.to_string().as_str()),
57 var(r2.to_string().as_str()),
58 p1.clone(),
59 p2.clone(),
60 ));
61 }
62 }
63 }
64 }
65 None
66 }
67 pub fn len(&self) -> usize {
69 self.entries.len()
70 }
71 pub fn is_empty(&self) -> bool {
73 self.entries.is_empty()
74 }
75 pub fn iter(&self) -> impl Iterator<Item = &(Name, Name, Expr)> {
77 self.entries.iter()
78 }
79 pub fn clear(&mut self) {
81 self.entries.clear();
82 }
83}
84#[allow(dead_code)]
86pub struct SetoidMorphism<A, B> {
87 pub func: fn(A) -> B,
89 pub respects: fn(&A, &A, bool) -> bool,
91}
92#[allow(dead_code)]
93impl<A: Clone, B> SetoidMorphism<A, B> {
94 pub fn new(func: fn(A) -> B, respects: fn(&A, &A, bool) -> bool) -> Self {
96 Self { func, respects }
97 }
98 pub fn apply(&self, a: A) -> B {
100 (self.func)(a)
101 }
102 pub fn verify_respects(&self, a1: &A, a2: &A, are_equiv: bool) -> bool {
104 (self.respects)(a1, a2, are_equiv)
105 }
106}
107#[derive(Debug, Clone)]
109pub struct EqRewriteRule {
110 pub name: oxilean_kernel::Name,
112 pub lhs: oxilean_kernel::Expr,
114 pub rhs: oxilean_kernel::Expr,
116 pub reversible: bool,
118}
119impl EqRewriteRule {
120 pub fn new(
122 name: oxilean_kernel::Name,
123 lhs: oxilean_kernel::Expr,
124 rhs: oxilean_kernel::Expr,
125 ) -> Self {
126 Self {
127 name,
128 lhs,
129 rhs,
130 reversible: false,
131 }
132 }
133 pub fn make_reversible(mut self) -> Self {
135 self.reversible = true;
136 self
137 }
138 pub fn reversed(&self) -> Option<Self> {
140 if self.reversible {
141 Some(Self {
142 name: self.name.clone(),
143 lhs: self.rhs.clone(),
144 rhs: self.lhs.clone(),
145 reversible: true,
146 })
147 } else {
148 None
149 }
150 }
151 pub fn matches(&self, expr: &oxilean_kernel::Expr) -> bool {
153 &self.lhs == expr
154 }
155 pub fn apply(&self, expr: &oxilean_kernel::Expr) -> Option<oxilean_kernel::Expr> {
157 if self.matches(expr) {
158 Some(self.rhs.clone())
159 } else {
160 None
161 }
162 }
163}
164#[allow(dead_code)]
168pub struct SetoidInstance<T> {
169 pub carrier: Vec<T>,
171 pub equiv: fn(&T, &T) -> bool,
173}
174#[allow(dead_code)]
175impl<T> SetoidInstance<T> {
176 pub fn new(carrier: Vec<T>, equiv: fn(&T, &T) -> bool) -> Self {
178 Self { carrier, equiv }
179 }
180 pub fn are_equiv(&self, a: &T, b: &T) -> bool {
182 (self.equiv)(a, b)
183 }
184 pub fn check_refl(&self) -> bool {
186 self.carrier.iter().all(|a| (self.equiv)(a, a))
187 }
188 pub fn check_symm(&self) -> bool {
190 for a in &self.carrier {
191 for b in &self.carrier {
192 if (self.equiv)(a, b) && !(self.equiv)(b, a) {
193 return false;
194 }
195 }
196 }
197 true
198 }
199 pub fn check_trans(&self) -> bool {
201 for a in &self.carrier {
202 for b in &self.carrier {
203 for c in &self.carrier {
204 if (self.equiv)(a, b) && (self.equiv)(b, c) && !(self.equiv)(a, c) {
205 return false;
206 }
207 }
208 }
209 }
210 true
211 }
212}
213#[derive(Debug, Clone)]
218pub struct EqChain {
219 pub ty: Expr,
221 pub steps: Vec<PropEq>,
223}
224impl EqChain {
225 pub fn new(ty: Expr) -> Self {
227 Self {
228 ty,
229 steps: Vec::new(),
230 }
231 }
232 pub fn push(&mut self, step: PropEq) {
236 if let Some(last) = self.steps.last() {
237 assert_eq!(last.rhs, step.lhs, "equality chain is not connected");
238 }
239 self.steps.push(step);
240 }
241 pub fn collapse(self) -> Option<PropEq> {
243 let mut iter = self.steps.into_iter();
244 let first = iter.next()?;
245 iter.try_fold(first, |acc, step| acc.trans(step))
246 }
247 pub fn is_empty(&self) -> bool {
249 self.steps.is_empty()
250 }
251 pub fn len(&self) -> usize {
253 self.steps.len()
254 }
255}
256#[derive(Debug, Clone, PartialEq, Eq)]
261pub enum DecisionResult<P> {
262 IsTrue(P),
264 IsFalse(String),
266}
267impl<P> DecisionResult<P> {
268 pub fn is_true(&self) -> bool {
270 matches!(self, DecisionResult::IsTrue(_))
271 }
272 pub fn is_false(&self) -> bool {
274 matches!(self, DecisionResult::IsFalse(_))
275 }
276 pub fn into_option(self) -> Option<P> {
278 match self {
279 DecisionResult::IsTrue(p) => Some(p),
280 DecisionResult::IsFalse(_) => None,
281 }
282 }
283 pub fn map<Q>(self, f: impl FnOnce(P) -> Q) -> DecisionResult<Q> {
285 match self {
286 DecisionResult::IsTrue(p) => DecisionResult::IsTrue(f(p)),
287 DecisionResult::IsFalse(msg) => DecisionResult::IsFalse(msg),
288 }
289 }
290 pub fn and<Q>(self, other: DecisionResult<Q>) -> DecisionResult<(P, Q)> {
292 match (self, other) {
293 (DecisionResult::IsTrue(p), DecisionResult::IsTrue(q)) => {
294 DecisionResult::IsTrue((p, q))
295 }
296 (DecisionResult::IsFalse(msg), _) | (_, DecisionResult::IsFalse(msg)) => {
297 DecisionResult::IsFalse(msg)
298 }
299 }
300 }
301 pub fn or(self, other: DecisionResult<P>) -> DecisionResult<P> {
303 match self {
304 DecisionResult::IsTrue(_) => self,
305 DecisionResult::IsFalse(_) => other,
306 }
307 }
308}
309impl<P: std::fmt::Display> DecisionResult<P> {
310 pub fn display(&self) -> String {
312 match self {
313 DecisionResult::IsTrue(p) => format!("isTrue ({p})"),
314 DecisionResult::IsFalse(msg) => format!("isFalse ({msg})"),
315 }
316 }
317}
318#[allow(dead_code)]
322pub struct LeibnizEq<A, B> {
323 pub coerce: fn(A) -> B,
325}
326#[allow(dead_code)]
327impl<T> LeibnizEq<T, T> {
328 pub fn refl() -> Self {
330 Self { coerce: |x| x }
331 }
332 pub fn apply(&self, a: T) -> T {
334 (self.coerce)(a)
335 }
336}
337#[derive(Debug, Clone, PartialEq, Eq)]
342pub struct EqualityWitness<T> {
343 pub value: T,
345}
346impl<T: PartialEq + Clone> EqualityWitness<T> {
347 pub fn try_new(a: &T, b: &T) -> Option<Self> {
351 if a == b {
352 Some(EqualityWitness { value: a.clone() })
353 } else {
354 None
355 }
356 }
357 pub fn cast<'a>(&self, a: &'a T) -> &'a T {
361 a
362 }
363}
364#[derive(Debug, Clone, PartialEq, Eq)]
369pub struct PropEq {
370 pub ty: Expr,
372 pub lhs: Expr,
374 pub rhs: Expr,
376}
377impl PropEq {
378 pub fn new(ty: Expr, lhs: Expr, rhs: Expr) -> Self {
380 Self { ty, lhs, rhs }
381 }
382 pub fn refl(ty: Expr, a: Expr) -> Self {
384 Self::new(ty, a.clone(), a)
385 }
386 pub fn is_refl(&self) -> bool {
388 self.lhs == self.rhs
389 }
390 pub fn symm(self) -> Self {
392 Self::new(self.ty, self.rhs, self.lhs)
393 }
394 pub fn trans(self, other: Self) -> Option<Self> {
398 if self.rhs == other.lhs && self.ty == other.ty {
399 Some(Self::new(self.ty, self.lhs, other.rhs))
400 } else {
401 None
402 }
403 }
404 pub fn display(&self) -> String {
406 format!("{:?} = {:?}", self.lhs, self.rhs)
407 }
408}
409#[allow(dead_code)]
411pub struct DecidableEqInstance<T> {
412 pub type_name: &'static str,
414 pub decide: fn(&T, &T) -> DecisionResult<()>,
416}
417#[allow(dead_code)]
418impl<T: PartialEq> DecidableEqInstance<T> {
419 pub fn for_type(type_name: &'static str) -> Self {
421 Self {
422 type_name,
423 decide: |a, b| {
424 if a == b {
425 DecisionResult::IsTrue(())
426 } else {
427 DecisionResult::IsFalse("values differ".to_string())
428 }
429 },
430 }
431 }
432 pub fn decide_eq(&self, a: &T, b: &T) -> DecisionResult<()> {
434 (self.decide)(a, b)
435 }
436 pub fn is_eq(&self, a: &T, b: &T) -> bool {
438 self.decide_eq(a, b).is_true()
439 }
440}
441#[derive(Debug, Clone)]
443pub struct EqBuilder {
444 ty: oxilean_kernel::Expr,
445 current: oxilean_kernel::Expr,
446 steps: Vec<(oxilean_kernel::Expr, oxilean_kernel::Expr)>,
447}
448impl EqBuilder {
449 pub fn start(ty: oxilean_kernel::Expr, start: oxilean_kernel::Expr) -> Self {
451 Self {
452 ty,
453 current: start,
454 steps: Vec::new(),
455 }
456 }
457 pub fn step(mut self, next: oxilean_kernel::Expr, proof: oxilean_kernel::Expr) -> Self {
459 self.steps.push((next.clone(), proof));
460 self.current = next;
461 self
462 }
463 pub fn build(self) -> Option<PropEq> {
465 if self.steps.is_empty() {
466 return None;
467 }
468 let first_rhs = self.steps[0].0.clone();
469 let mut chain = PropEq::new(self.ty.clone(), self.current.clone(), first_rhs);
470 for (rhs, _proof) in self.steps.into_iter().skip(1) {
471 let next_eq = PropEq::new(self.ty.clone(), chain.rhs.clone(), rhs);
472 chain = chain.trans(next_eq)?;
473 }
474 Some(chain)
475 }
476 pub fn current(&self) -> &oxilean_kernel::Expr {
478 &self.current
479 }
480 pub fn num_steps(&self) -> usize {
482 self.steps.len()
483 }
484}
485#[derive(Debug, Clone, Default)]
487pub struct RewriteRuleDb {
488 rules: Vec<EqRewriteRule>,
489}
490impl RewriteRuleDb {
491 pub fn new() -> Self {
493 Self::default()
494 }
495 pub fn add(&mut self, rule: EqRewriteRule) {
497 self.rules.push(rule);
498 }
499 pub fn find_match(&self, expr: &oxilean_kernel::Expr) -> Option<&EqRewriteRule> {
501 self.rules.iter().find(|r| r.matches(expr))
502 }
503 pub fn apply_all(&self, expr: &oxilean_kernel::Expr) -> Vec<oxilean_kernel::Expr> {
505 self.rules.iter().filter_map(|r| r.apply(expr)).collect()
506 }
507 pub fn len(&self) -> usize {
509 self.rules.len()
510 }
511 pub fn is_empty(&self) -> bool {
513 self.rules.is_empty()
514 }
515 pub fn remove(&mut self, name: &oxilean_kernel::Name) {
517 self.rules.retain(|r| &r.name != name);
518 }
519}
520#[allow(dead_code)]
522pub struct HeterogeneousEq<A, B> {
523 pub left: A,
525 pub right: B,
527 pub justification: &'static str,
529}
530#[allow(dead_code)]
531impl<A, B> HeterogeneousEq<A, B> {
532 pub fn new(left: A, right: B, justification: &'static str) -> Self {
534 Self {
535 left,
536 right,
537 justification,
538 }
539 }
540}
541#[allow(dead_code)]
542impl<A: Clone + PartialEq> HeterogeneousEq<A, A> {
543 pub fn is_homogeneous_eq(&self) -> bool {
545 self.left == self.right
546 }
547 pub fn to_homogeneous(&self) -> Option<EqualityWitness<A>> {
549 EqualityWitness::try_new(&self.left, &self.right)
550 }
551}