prop/
eq.rs

1//! Tactics for Logical EQ.
2
3#![allow(unreachable_code)]
4
5use crate::*;
6
7/// `(a == b) ∧ (b == c) => (a == c)`.
8pub fn transitivity<A: Prop, B: Prop, C: Prop>((f0, f1): Eq<A, B>, (g0, g1): Eq<B, C>) -> Eq<A, C> {
9    (Rc::new(move |x| g0(f0(x))), Rc::new(move |x| f1(g1(x))))
10}
11
12/// `(a == b) ∧ (b == c) ∧ (c == d)  =>  (a == d)`.
13pub fn trans3<A: Prop, B: Prop, C: Prop, D: Prop>(
14    ab: Eq<A, B>,
15    bc: Eq<B, C>,
16    cd: Eq<C, D>
17) -> Eq<A, D> {transitivity(ab, transitivity(bc, cd))}
18
19/// `(a == b) ∧ (b == c) ∧ (c == d) ∧ (d == e)  =>  (a == e)`.
20pub fn trans4<A: Prop, B: Prop, C: Prop, D: Prop, E: Prop>(
21    ab: Eq<A, B>,
22    bc: Eq<B, C>,
23    cd: Eq<C, D>,
24    de: Eq<D, E>
25) -> Eq<A, E> {transitivity(trans3(ab, bc, cd), de)}
26
27/// `(a == b) ∧ (b == c) ∧ (c == d) ∧ (d == e) ∧ (e == f)  =>  (a == f)`.
28pub fn trans5<A: Prop, B: Prop, C: Prop, D: Prop, E: Prop, F: Prop>(
29    ab: Eq<A, B>,
30    bc: Eq<B, C>,
31    cd: Eq<C, D>,
32    de: Eq<D, E>,
33    ef: Eq<E, F>,
34) -> Eq<A, F> {transitivity(trans4(ab, bc, cd, de), ef)}
35
36/// `a => (a == ¬¬a)`.
37pub fn double_neg<A: Prop>(a: A) -> Eq<A, Not<Not<A>>> {
38    let double_neg = a.double_neg();
39    (Rc::new(move |x| not::double(x)), Rc::new(move |x| double_neg(x)))
40}
41
42/// `(a == b) => (b == a)`.
43pub fn symmetry<A: Prop, B: Prop>((f0, f1): Eq<A, B>) -> Eq<B, A> {
44    (f1, f0)
45}
46
47/// `¬(a == b) => ¬(b == a)`.
48pub fn neq_symmetry<A: Prop, B: Prop>(neq: Not<Eq<A, B>>) -> Not<Eq<B, A>> {
49    Rc::new(move |eq| neq(symmetry(eq)))
50}
51
52/// `(a => b) = (¬a ∨ b)`.
53pub fn imply_to_or_da<A: DProp, B: Prop>() -> Eq<Imply<A, B>, Or<Not<A>, B>> {
54    (Rc::new(move |x| imply::to_or_da(x)), Rc::new(move |x| imply::from_or(x)))
55}
56
57/// `(a => b) = (¬a ∨ b)`.
58pub fn imply_to_or_db<A: Prop, B: DProp>() -> Eq<Imply<A, B>, Or<Not<A>, B>> {
59    (Rc::new(move |x| imply::to_or_db(x)), Rc::new(move |x| imply::from_or(x)))
60}
61
62/// `a == a`.
63pub fn refl<A: Prop>() -> Eq<A, A> {
64    (Rc::new(move |x| x), Rc::new(move |x| x))
65}
66
67/// `(a == ¬a) => false`.
68pub fn anti<A: Prop>((f0, f1): Eq<A, Not<A>>) -> False {
69    let na: Not<A> = Rc::new(move |a| f0(a.clone())(a));
70    let a = f1(na.clone());
71    na(a)
72}
73
74/// There is an `a : A` is the same as `A` being true.
75///
76/// With other words, a proof means it is true,
77/// and if it is true then there is a proof.
78pub fn true_eq<A: Prop>(a: A) -> Eq<A, True> {
79    (True.map_any(), Rc::new(move |_| a.clone()))
80}
81
82/// `(a == b) => (¬b == ¬a)`
83pub fn modus_tollens<A: Prop, B: Prop>((f0, f1): Eq<A, B>) -> Eq<Not<B>, Not<A>> {
84    let f02 = imply::modus_tollens(f0);
85    let f12 = imply::modus_tollens(f1);
86    (f02, f12)
87}
88
89/// `(¬a == ¬b) => (b == a)`.
90pub fn rev_modus_tollens<A: DProp, B: DProp>((f0, f1): Eq<Not<A>, Not<B>>) -> Eq<B, A> {
91    let f02 = imply::rev_modus_tollens(f0);
92    let f12 = imply::rev_modus_tollens(f1);
93    (f02, f12)
94}
95
96/// `(¬a == ¬b) ∧ (a ∨ ¬a) ∧ (b ∨ ¬b)  =>  (b == a)`.
97pub fn rev_modus_tollens_excm<A: Prop, B: Prop>(
98    (f0, f1): Eq<Not<A>, Not<B>>,
99    excm_a: ExcM<A>,
100    excm_b: ExcM<B>,
101) -> Eq<B, A> {
102    let f02 = imply::rev_modus_tollens_excm(f0, excm_b.clone(), excm_a.clone());
103    let f12 = imply::rev_modus_tollens_excm(f1, excm_a, excm_b);
104    (f02, f12)
105}
106
107/// `(¬a == ¬b) ∧ ((a ∨ ¬a) == (b ∨ ¬b))  =>  (b == a)`.
108pub fn rev_modus_tollens_eq_excm<A: Prop, B: Prop>(
109    (f0, f1): Eq<Not<A>, Not<B>>,
110    eq_excm_a_excm_b: Eq<ExcM<A>, ExcM<B>>,
111) -> Eq<B, A> {
112    let f02 = imply::rev_modus_tollens_eq_excm(f0, eq::symmetry(eq_excm_a_excm_b.clone()));
113    let f12 = imply::rev_modus_tollens_eq_excm(f1, eq_excm_a_excm_b);
114    (f02, f12)
115}
116
117/// `(¬a == ¬b) ∧ (a => (b ∨ ¬b)) ∧ (b => (b ∨ ¬b))  =>  (b == a)`.
118pub fn rev_modus_tollens_imply_excm<A: Prop, B: Prop>(
119    (f0, f1): Eq<Not<A>, Not<B>>,
120    a_excm_b: Imply<A, ExcM<B>>,
121    b_excm_a: Imply<B, ExcM<A>>,
122) -> Eq<B, A> {
123    let f02 = imply::rev_modus_tollens_imply_excm(f0, b_excm_a);
124    let f12 = imply::rev_modus_tollens_imply_excm(f1, a_excm_b);
125    (f02, f12)
126}
127
128/// `(true == a) => a`.
129pub fn is_true<A: Prop>((f0, _): Eq<True, A>) -> A {
130    f0(True)
131}
132
133/// `(false == a) => ¬a`.
134pub fn is_false<A: Prop>((_, f1): Eq<False, A>) -> Not<A> {
135    f1
136}
137
138/// `¬a => (a == false)`.
139pub fn to_eq_false<A: Prop>(n_a: Not<A>) -> Eq<A, False> {
140    (n_a, imply::absurd())
141}
142
143/// `¬(a == b) ∧ a  =>  ¬b`.
144pub fn contra<A: Prop, B: DProp>(f: Not<Eq<A, B>>, a: A) -> Not<B> {
145    contra_excm(f, a, B::decide())
146}
147
148/// `¬(a == b) ∧ a  =>  ¬b`.
149pub fn contra_excm<A: Prop, B: Prop>(
150    f: Not<Eq<A, B>>,
151    a: A,
152    excm_b: ExcM<B>
153) -> Not<B> {
154    match excm_b {
155        Left(b) => not::absurd(f, and::to_eq_pos((a, b))),
156        Right(not_b) => not_b,
157    }
158}
159
160/// `(a == b) == c  =>  a => (b == c)`
161pub fn assoc_right<A: DProp, B: DProp, C: DProp>((f0, f1): Eq<Eq<A, B>, C>) -> Imply<A, Eq<B, C>> {
162    match (A::decide(), C::decide()) {
163        (Right(not_a), _) => Rc::new(move |x| match not_a.clone()(x) {}),
164        (_, Left(c)) =>
165            Rc::new(move |x| (c.clone().map_any(), f1.clone()(c.clone()).0(x).map_any())),
166        (Left(a), Right(not_c)) => {
167            // `!(a = b)`
168            let g = imply::rev_modus_ponens(f0, not_c.clone());
169            let not_b = eq::contra(g, a);
170            and::to_eq_neg((not_b, not_c)).map_any()
171        }
172    }
173}
174
175/// `(a == b) == c  =>  (b == c) => a`.
176pub fn assoc_left<A: DProp, B: DProp, C: DProp>((f0, f1): Eq<Eq<A, B>, C>) -> Imply<Eq<B, C>, A> {
177    match (A::decide(), B::decide(), C::decide()) {
178        (Left(a), _, _) => a.map_any(),
179        (Right(not_a), Right(not_b), Right(not_c)) =>
180            match not_c(f0(and::to_eq_neg((not_a, not_b)))) {},
181        (_, Left(b), Right(not_c)) =>
182            Rc::new(move |(fb, _)| match not_c.clone()(fb(b.clone())) {}),
183        (_, Right(not_b), Left(c)) =>
184            Rc::new(move |(_, fc)| match not_b.clone()(fc(c.clone())) {}),
185        (Right(not_a), Left(b), Left(c)) => {
186            // `a = b`.
187            let (_, g1) = f1(c);
188            let a = g1(b);
189            match not_a(a) {}
190        }
191    }
192}
193
194/// `(a == b) == c  =>  a == (b == c)`.
195pub fn assoc<A: DProp, B: DProp, C: DProp>(f: Eq<Eq<A, B>, C>) -> Eq<A, Eq<B, C>> {
196    (assoc_right(f.clone()), assoc_left(f))
197}
198
199/// `a == (b == c)  =>  a == (c == b)`.
200pub fn swap_right<A: Prop, B: Prop, C: Prop>((f0, f1): Eq<A, Eq<B, C>>) -> Eq<A, Eq<C, B>> {
201    (Rc::new(move |x| {let (g0, g1) = f0(x); (g1, g0)}),
202     Rc::new(move |(g1, g0)| f1((g0, g1))))
203}
204
205/// `(a == b) == c  =>  (b == a) == c`.
206pub fn swap_left<A: Prop, B: Prop, C: Prop>(f: Eq<Eq<A, B>, C>) -> Eq<Eq<B, A>, C> {
207    symmetry(swap_right(symmetry(f)))
208}
209
210/// `(a == b) ∧ (a == c)  =>  (c == b)`
211pub fn in_left_arg<A: Prop, B: Prop, C: Prop>(f: Eq<A, B>, g: Eq<A, C>) -> Eq<C, B> {
212    symmetry(transitivity(symmetry(f), g))
213}
214
215/// See transitivity.
216pub fn in_right_arg<A: Prop, B: Prop, C: Prop>(f: Eq<A, B>, g: Eq<B, C>) -> Eq<A, C> {
217    transitivity(f, g)
218}
219
220/// Makes it easier to traverse.
221pub fn in_left<A: Prop, B: Prop, C: Prop, F, G>(
222    eq_ab: Eq<A, B>,
223    f: F,
224    g: G,
225) -> Eq<C, B>
226    where F: Fn(A) -> C + 'static,
227          G: Fn(C) -> A + 'static
228{in_left_arg(eq_ab, (Rc::new(f), Rc::new(g)))}
229
230/// Makes it easier to traverse.
231pub fn in_right<A: Prop, B: Prop, C: Prop, F, G>(
232    eq_ab: Eq<A, B>,
233    f: F,
234    g: G,
235) -> Eq<A, C>
236    where F: Fn(B) -> C + 'static,
237          G: Fn(C) -> B + 'static
238{eq::symmetry(in_left(eq::symmetry(eq_ab), f, g))}
239
240/// `(a == b)  =>  (a == c) == (b == c)`.
241pub fn eq_left<A: Prop, B: Prop, C: Prop>(x: Eq<A, B>) -> Eq<Eq<A, C>, Eq<B, C>> {
242    let x2 = symmetry(x.clone());
243    (Rc::new(move |ac| in_left_arg(ac, x.clone())),
244     Rc::new(move |bc| in_left_arg(bc, x2.clone())))
245}
246
247/// `(a == b)  =>  (c == a) == (c == b)`.
248pub fn eq_right<A: Prop, B: Prop, C: Prop>(x: Eq<A, B>) -> Eq<Eq<C, A>, Eq<C, B>> {
249    let x2 = symmetry(x.clone());
250    (Rc::new(move |ac| in_right_arg(ac, x.clone())),
251     Rc::new(move |bc| in_right_arg(bc, x2.clone())))
252}
253
254/// `(a == b) == (b == a)`.
255pub fn symmetry_eq<A: Prop, B: Prop>() -> Eq<Eq<A, B>, Eq<B, A>> {
256    (Rc::new(move |x| eq::symmetry(x)),
257     Rc::new(move |x| eq::symmetry(x)))
258}
259
260/// `((a == b) == c)  ==  (a == (b == c))`.
261pub fn assoc_eq<A: DProp, B: DProp, C: DProp>() -> Eq<Eq<Eq<A, B>, C>, Eq<A, Eq<B, C>>> {
262    (Rc::new(move |x| eq::assoc(x)), Rc::new(move |x| {
263        let x2 = eq::symmetry(x);
264        let x3 = eq::in_left_arg(x2, symmetry_eq());
265        let x4 = eq::assoc(x3);
266        let x5 = eq::symmetry(x4);
267        eq::in_left_arg(x5, symmetry_eq())
268    }))
269}
270
271/// `(a == b) == (c == d)  =>  (a == c) == (b == d)`.
272pub fn transpose<A: DProp, B: DProp, C: DProp, D: DProp>(
273    f: Eq<Eq<A, B>, Eq<C, D>>
274) -> Eq<Eq<A, C>, Eq<B, D>> {
275    let f = eq::in_left_arg(f, eq::symmetry_eq());
276    let f = eq::in_right_arg(f, eq::symmetry_eq());
277    let f = eq::assoc(f);
278    let f = eq::in_right_arg(f, eq::symmetry_eq());
279    let f = eq::in_right_arg(f, eq::assoc_eq());
280    let f = eq::symmetry(f);
281    let f = eq::assoc(f);
282    let f = eq::symmetry(f);
283    let f = eq::assoc(f);
284    eq::in_left_arg(f, eq::symmetry_eq())
285}
286
287/// `(a == b) = (c == b)  =>  (a == c)`.
288pub fn triangle<A: DProp, B: DProp, C: DProp>(f: Eq<Eq<A, B>, Eq<C, B>>) -> Eq<A, C> {
289    let f = eq::transpose(f);
290    f.1(eq::refl())
291}
292
293/// `¬(a == b) = ¬(c == b)  =>  (a == c)`.
294pub fn inv_triangle<A: DProp, B: DProp, C: DProp>(
295    f: Eq<Not<Eq<A, B>>, Not<Eq<C, B>>>
296) -> Eq<A, C> {
297    let f = eq::rev_modus_tollens(f);
298    let f = eq::symmetry(f);
299    eq::triangle(f)
300}
301
302/// `false == false`.
303pub fn absurd() -> Eq<False, False> {
304    (imply::absurd(), imply::absurd())
305}
306
307/// `(a == b) ⋀ ¬(a == c) => ¬(b == c)`.
308pub fn neq_left<A: Prop, B: Prop, C: Prop>(
309    eq_ab: Eq<A, B>,
310    neq_ac: Not<Eq<A, C>>
311) -> Not<Eq<B, C>> {
312    Rc::new(move |eq_bc| neq_ac(transitivity(eq_ab.clone(), eq_bc)))
313}
314
315/// `(a == b) ⋀ ¬(b == c) => ¬(a == c)`.
316pub fn neq_right<A: Prop, B: Prop, C: Prop>(
317    eq_ab: Eq<A, B>,
318    neq_bc: Not<Eq<B, C>>
319) -> Not<Eq<A, C>> {
320    Rc::new(move |eq_ac| neq_bc(transitivity(symmetry(eq_ab.clone()), eq_ac)))
321}
322
323/// `¬(a == b)  =>  ¬(a ⋀ b)`.
324pub fn neq_to_nand<A: Prop, B: Prop>(neq: Not<Eq<A, B>>) -> Not<And<A, B>> {
325    Rc::new(move |(a, b)| neq((b.map_any(), a.map_any())))
326}
327
328/// `¬(a == b)  =>  (a == ¬b)`.
329pub fn neq_to_eq_not<A: DProp, B: DProp>(x: Not<Eq<A, B>>) -> Eq<A, Not<B>> {
330    let x2 = x.clone();
331    (Rc::new(move |a| {
332        let x = x2.clone();
333        Rc::new(move |b| x.clone()((b.map_any(), a.clone().map_any())))
334     }),
335     Rc::new(move |nb| match A::decide() {
336         Left(a) => a,
337         Right(na) => not::absurd(x.clone(), eq::rev_modus_tollens((na.map_any(), nb.map_any()))),
338     }))
339}
340
341/// `(a == ¬b) => ¬(a == b)`.
342pub fn eq_not_to_neq<A: Prop, B: Prop>(f: Eq<A, Not<B>>) -> Not<Eq<A, B>> {
343    Rc::new(move |eq_ab| anti(in_left_arg(f.clone(), eq_ab)))
344}
345
346/// `(a == b) => ((a ⋁ ¬a) == (b ⋁ ¬b))`.
347pub fn eq_to_eq_excm<A: Prop, B: Prop>(x: Eq<A, B>) -> Eq<ExcM<A>, ExcM<B>> {
348    let x2 = x.clone();
349    (
350        Rc::new(move |excm_a| {
351            let x = x2.clone();
352            match excm_a {
353                Left(a) => Left(x.0(a)),
354                Right(na) => Right(eq::modus_tollens(x).1(na)),
355            }
356        }),
357        Rc::new(move |excm_b| {
358            let x = x.clone();
359            match excm_b {
360                Left(b) => Left(x.1(b)),
361                Right(nb) => Right(eq::modus_tollens(x).0(nb)),
362            }
363        })
364    )
365}