use crate::*;
use univalence::HomEq2;
use qubit::Qu;
use hooo::Theory;
pub type EqQ<A, B> = Imply<Eq<A, B>, Q<A, B>>;
pub type EqAq<A, B> = Imply<Eq<A, B>, Aq<A, B>>;
pub type Seshatic<A, B> = Or<Not<Q<A, A>>, Not<Q<B, B>>>;
pub type Q<A, B> = And<Eq<A, B>, And<Qu<A>, Qu<B>>>;
pub type Aq<A, B> = And<Eq<A, B>, And<Qu<Not<A>>, Qu<Not<B>>>>;
pub fn symmetry<A: Prop, B: Prop>((eq, and_qu): Q<A, B>) -> Q<B, A> {
(eq::symmetry(eq), and::symmetry(and_qu))
}
pub fn eq_q_symmetry<A: Prop, B: Prop>() -> Eq<Q<A, B>, Q<B, A>> {
(Rc::new(symmetry), Rc::new(symmetry))
}
pub fn aq_symmetry<A: Prop, B: Prop>((eq, and_qu): Aq<A, B>) -> Aq<B, A> {
(eq::symmetry(eq), and::symmetry(and_qu))
}
pub fn nq_symmetry<A: Prop, B: Prop>(nq: Not<Q<A, B>>) -> Not<Q<B, A>> {
Rc::new(move |q| nq(symmetry(q)))
}
pub fn naq_symmetry<A: Prop, B: Prop>(naq: Not<Aq<A, B>>) -> Not<Aq<B, A>> {
Rc::new(move |q| naq(aq_symmetry(q)))
}
pub fn transitivity<A: Prop, B: Prop, C: Prop>(
(eq_ab, (qu_a, _)): Q<A, B>,
(eq_bc, (_, qu_c)): Q<B, C>
) -> Q<A, C> {
(eq::transitivity(eq_ab, eq_bc), (qu_a, qu_c))
}
pub fn aq_transitivity<A: Prop, B: Prop, C: Prop>(
(eq_ab, (qu_a, _)): Aq<A, B>,
(eq_bc, (_, qu_c)): Aq<B, C>
) -> Aq<A, C> {
(eq::transitivity(eq_ab, eq_bc), (qu_a, qu_c))
}
pub fn nq_left<A: Prop, B: Prop, C: Prop>(
q_ab: Q<A, B>,
sesh_ac: Not<Q<A, C>>
) -> Not<Q<B, C>> {
Rc::new(move |q_bc| sesh_ac(transitivity(q_ab.clone(), q_bc)))
}
pub fn naq_left<A: Prop, B: Prop, C: Prop>(
q_ab: Aq<A, B>,
sesh_ac: Not<Aq<A, C>>
) -> Not<Aq<B, C>> {
Rc::new(move |q_bc| sesh_ac(aq_transitivity(q_ab.clone(), q_bc)))
}
pub fn nq_right<A: Prop, B: Prop, C: Prop>(
q_ab: Q<A, B>,
sesh_bc: Not<Q<B, C>>
) -> Not<Q<A, C>> {
Rc::new(move |q_ac| sesh_bc(transitivity(symmetry(q_ab.clone()), q_ac)))
}
pub fn naq_right<A: Prop, B: Prop, C: Prop>(
q_ab: Aq<A, B>,
sesh_bc: Not<Aq<B, C>>
) -> Not<Aq<A, C>> {
Rc::new(move |q_ac| sesh_bc(aq_transitivity(aq_symmetry(q_ab.clone()), q_ac)))
}
pub fn eq_maybe_lift<A: Prop, B: Prop>(_: Eq<A, B>) -> Or<Q<A, B>, True> {
Right(True)
}
pub fn to_eq<A: Prop, B: Prop>((eq, _): Q<A, B>) -> Eq<A, B> {
eq
}
pub fn aq_to_eq<A: Prop, B: Prop>((eq, _): Aq<A, B>) -> Eq<A, B> {
eq
}
pub fn to_eq_q<A: Prop, B: Prop>(q: Q<A, B>) -> Eq<Q<A, A>, Q<B, B>> {
(right(q.clone()).map_any(), left(q).map_any())
}
pub fn to_eq_aq<A: Prop, B: Prop>(q: Aq<A, B>) -> Eq<Aq<A, A>, Aq<B, B>> {
(aq_right(q.clone()).map_any(), aq_left(q).map_any())
}
pub fn left<A: Prop, B: Prop>(q_ab: Q<A, B>) -> Q<A, A> {
let q_ba = symmetry(q_ab.clone());
transitivity(q_ab, q_ba)
}
pub fn aq_left<A: Prop, B: Prop>(q_ab: Aq<A, B>) -> Aq<A, A> {
let q_ba = aq_symmetry(q_ab.clone());
aq_transitivity(q_ab, q_ba)
}
pub fn right<A: Prop, B: Prop>(q_ab: Q<A, B>) -> Q<B, B> {
let q_ba = symmetry(q_ab.clone());
transitivity(q_ba, q_ab)
}
pub fn aq_right<A: Prop, B: Prop>(q_ab: Aq<A, B>) -> Aq<B, B> {
let q_ba = aq_symmetry(q_ab.clone());
aq_transitivity(q_ba, q_ab)
}
pub fn sesh_left<A: Prop, B: Prop>(sesh_a: Not<Q<A, A>>) -> Not<Q<A, B>> {
Rc::new(move |q_ab| sesh_a(left(q_ab)))
}
pub fn aq_sesh_left<A: Prop, B: Prop>(sesh_a: Not<Aq<A, A>>) -> Not<Aq<A, B>> {
Rc::new(move |q_ab| sesh_a(aq_left(q_ab)))
}
pub fn sesh_right<A: Prop, B: Prop>(sesh_b: Not<Q<B, B>>) -> Not<Q<A, B>> {
Rc::new(move |q_ab| sesh_b(right(q_ab)))
}
pub fn aq_sesh_right<A: Prop, B: Prop>(sesh_b: Not<Aq<B, B>>) -> Not<Aq<A, B>> {
Rc::new(move |q_ab| sesh_b(aq_right(q_ab)))
}
pub fn neq_to_sesh<A: Prop, B: Prop>(neq: Not<Eq<A, B>>) -> Not<Q<A, B>> {
Rc::new(move |q_ab| neq(to_eq(q_ab)))
}
pub fn neq_to_aq_sesh<A: Prop, B: Prop>(neq: Not<Eq<A, B>>) -> Not<Aq<A, B>> {
Rc::new(move |q_ab| neq(aq_to_eq(q_ab)))
}
pub fn sesh_to_neq<A: Prop, B: Prop>(sesh: Not<Q<A, B>>, eqq_ab: EqQ<A, B>) -> Not<Eq<A, B>> {
imply::modus_tollens(eqq_ab)(sesh)
}
pub fn aq_sesh_to_neq<A: Prop, B: Prop>(sesh: Not<Aq<A, B>>, eqq_ab: EqAq<A, B>) -> Not<Eq<A, B>> {
imply::modus_tollens(eqq_ab)(sesh)
}
pub fn sesh_eq_neq<A: Prop, B: Prop>(eqq_ab: EqQ<A, B>) -> Eq<Not<Q<A, B>>, Not<Eq<A, B>>> {
(
Rc::new(move |nq_ab| sesh_to_neq(nq_ab, eqq_ab.clone())),
Rc::new(move |neq_ab| neq_to_sesh(neq_ab)),
)
}
pub fn aq_sesh_eq_neq<A: Prop, B: Prop>(eqq_ab: EqAq<A, B>) -> Eq<Not<Aq<A, B>>, Not<Eq<A, B>>> {
(
Rc::new(move |nq_ab| aq_sesh_to_neq(nq_ab, eqq_ab.clone())),
Rc::new(move |neq_ab| neq_to_aq_sesh(neq_ab)),
)
}
pub fn hom_in_left_arg<A: Prop, B: Prop, C: Prop>(
(eq_ab, (qa, qb)): Q<A, B>,
(eq_q, (eq_ac, True)): HomEq2<A, C>
) -> Q<C, B> {
let eq2: Eq<C, B> = eq::transitivity(eq::symmetry(qubit::to_eq(eq_ac)), eq_ab);
let qc: Qu<C> = eq_q.0(qa);
(eq2, (qc, qb))
}
pub fn aq_hom_in_left_arg<A: Prop, B: Prop, C: Prop>(
(eq_ab, (qa, qb)): Aq<A, B>,
(eq_q, (eq_ac, True)): HomEq2<A, C>
) -> Aq<C, B> {
let eq2: Eq<C, B> = eq::transitivity(eq::symmetry(qubit::to_eq(eq_ac)), eq_ab);
let qc: Qu<Not<C>> = qubit::eq_to_eq_inv(eq_q).0(qa);
(eq2, (qc, qb))
}
pub fn hom_in_right_arg<A: Prop, B: Prop, C: Prop>(
(eq_ab, (qa, qb)): Q<A, B>,
(eq_q, (eq_bc, True)): HomEq2<B, C>
) -> Q<A, C> {
let eq2: Eq<A, C> = eq::transitivity(eq_ab, qubit::to_eq(eq_bc));
let qc: Qu<C> = eq_q.0(qb);
(eq2, (qa, qc))
}
pub fn aq_hom_in_right_arg<A: Prop, B: Prop, C: Prop>(
(eq_ab, (qa, qb)): Aq<A, B>,
(eq_q, (eq_bc, True)): HomEq2<B, C>
) -> Aq<A, C> {
let eq2: Eq<A, C> = eq::transitivity(eq_ab, qubit::to_eq(eq_bc));
let qc: Qu<Not<C>> = qubit::eq_to_eq_inv(eq_q).0(qb);
(eq2, (qa, qc))
}
pub fn sesh_hom_in_left_arg<A: Prop, B: Prop, C: Prop>(
sesh_ab: Not<Q<A, B>>,
eq_ac: HomEq2<A, C>,
) -> Not<Q<C, B>> {
let eq_ca = univalence::hom_eq_symmetry::<nat::Two, _, _>(eq_ac);
Rc::new(move |q_cb| {
sesh_ab(hom_in_left_arg(q_cb, eq_ca.clone()))
})
}
pub fn aq_sesh_hom_in_left_arg<A: Prop, B: Prop, C: Prop>(
sesh_ab: Not<Aq<A, B>>,
eq_ac: HomEq2<A, C>,
) -> Not<Aq<C, B>> {
let eq_ca = univalence::hom_eq_symmetry::<nat::Two, _, _>(eq_ac);
Rc::new(move |q_cb| {
sesh_ab(aq_hom_in_left_arg(q_cb, eq_ca.clone()))
})
}
pub fn sesh_hom_in_right_arg<A: Prop, B: Prop, C: Prop>(
sesh_ab: Not<Q<A, B>>,
eq_bc: HomEq2<B, C>,
) -> Not<Q<A, C>> {
let eq_cb = univalence::hom_eq_symmetry::<nat::Two, _, _>(eq_bc);
Rc::new(move |q_ac| {
sesh_ab(hom_in_right_arg(q_ac, eq_cb.clone()))
})
}
pub fn aq_sesh_hom_in_right_arg<A: Prop, B: Prop, C: Prop>(
sesh_ab: Not<Aq<A, B>>,
eq_bc: HomEq2<B, C>,
) -> Not<Aq<A, C>> {
let eq_cb = univalence::hom_eq_symmetry::<nat::Two, _, _>(eq_bc);
Rc::new(move |q_ac| {
sesh_ab(aq_hom_in_right_arg(q_ac, eq_cb.clone()))
})
}
pub fn sesh_to_q_inv<A: Prop>(f: Not<Q<A, A>>) -> Q<Not<A>, Not<A>> {
let sesh: Not<Qu<A>> = Rc::new(move |x| f((eq::refl(), (x.clone(), x))));
let qu: Qu<Not<A>> = qubit::sesh_to_inv(sesh);
(eq::refl(), (qu.clone(), qu))
}
pub fn aq_sesh_to_q_inv<A: Prop>(f: Not<Aq<A, A>>) -> Aq<Not<A>, Not<A>> {
let sesh: Not<Qu<Not<A>>> = Rc::new(move |x| f((eq::refl(), (x.clone(), x))));
let qu: Qu<Not<Not<A>>> = qubit::sesh_to_inv(sesh);
(eq::refl(), (qu.clone(), qu))
}
pub fn q_inv_to_sesh<A: Prop>((_, (nqu, _)): Q<Not<A>, Not<A>>) -> Not<Q<A, A>> {
Rc::new(move |q| qubit::inv_to_sesh(nqu.clone())(Qu::from_q(q)))
}
pub fn aq_inv_to_sesh<A: Prop>((_, (nqu, _)): Aq<Not<A>, Not<A>>) -> Not<Aq<A, A>> {
Rc::new(move |q| qubit::inv_to_sesh(nqu.clone())(Qu::from_aq(q)))
}
pub fn theory_eq_to_eqq<A: Prop, B: Prop>(theory: Theory<Eq<A, B>>) -> EqQ<A, B> {
Rc::new(move |eq| hooo::lift_q(eq, theory.clone()))
}
pub fn eqq_to_excm_q<A: DProp, B: DProp>(eqq: EqQ<A, B>) -> ExcM<Q<A, B>> {
eqq_to_excm_q_with_excm_eq(eqq, Eq::<A, B>::decide())
}
pub fn eqq_to_excm_q_with_excm_eq<A: Prop, B: Prop>(
eqq: EqQ<A, B>,
excm_eq: ExcM<Eq<A, B>>
) -> ExcM<Q<A, B>> {
match excm_eq {
Left(eq) => Left(eqq(eq)),
Right(neq) => Right(imply::in_left(neq, |x| to_eq(x))),
}
}
pub fn theory_eq_to_excm_q_with_excm_eq<A: Prop, B: Prop>(
theory_eq: Theory<Eq<A, B>>,
excm_eq: ExcM<Eq<A, B>>
) -> ExcM<Q<A, B>> {
eqq_to_excm_q_with_excm_eq(theory_eq_to_eqq(theory_eq), excm_eq)
}