use crate::*;
use hooo::Tauto;
use nat::{Nat, Z, S};
use quality::{Aq, Q};
#[derive(Copy, Clone)]
pub struct Qubit<N, A>(N, A);
pub type Qu<A> = Qubit<S<Z>, A>;
impl<A: DProp> Decidable for Qu<A> {fn decide() -> ExcM<Qu<A>> {decide()}}
impl<A: Prop> Qubit<Z, A> {
pub fn to(self) -> A {self.1}
pub fn from(a: A) -> Self {Qubit(Z, a)}
}
impl<A: Prop> Qubit<S<Z>, A> {
pub fn to_q(self) -> Q<A, A> {(eq::refl(), (self.clone(), self))}
pub fn from_q((_, (x, _)): Q<A, A>) -> Self {x}
}
impl<A: Prop> Qubit<S<Z>, Not<A>> {
pub fn to_aq(self) -> Aq<A, A> {(eq::refl(), (self.clone(), self))}
pub fn from_aq((_, (x, _)): Aq<A, A>) -> Self {x}
}
pub fn decide<A: DProp>() -> ExcM<Qu<A>> {decide_tauto_excm(tauto!(A::decide()))}
pub fn decide_tauto_excm<A: Prop>(_: Tauto<ExcM<A>>) -> ExcM<Qu<A>> {unimplemented!()}
pub fn normalize<A: Prop, N: Nat>(x: Qubit<S<Z>, Qubit<N, A>>) -> Qubit<S<N>, A> {
Qubit(S(x.1.0), x.1.1)
}
pub fn rev_normalize<A: Prop, N: Nat>(x: Qubit<S<N>, A>) -> Qubit<S<Z>, Qubit<N, A>> {
Qubit(S(Z), Qubit(x.0.0, x.1))
}
pub fn sesh_to_inv<A: Prop>(_: Not<Qu<A>>) -> Qu<Not<A>> {unimplemented!()}
pub fn inv_to_sesh<A: Prop>(_: Qu<Not<A>>) -> Not<Qu<A>> {unimplemented!()}
pub fn eq_sesh_inv<A: Prop>() -> Eq<Not<Qu<A>>, Qu<Not<A>>> {
(Rc::new(sesh_to_inv), Rc::new(inv_to_sesh))
}
pub fn to_eq<A: Prop, B: Prop>(x: Eq<Qubit<Z, A>, Qubit<Z, B>>) -> Eq<A, B> {
let x2 = x.clone();
(
Rc::new(move |a| x2.0(Qubit::from(a)).to()),
Rc::new(move |b| x.1(Qubit::from(b)).to()),
)
}
pub fn from_eq<A: Prop, B: Prop>(x: Eq<A, B>) -> Eq<Qubit<Z, A>, Qubit<Z, B>> {
let x2 = x.clone();
(
Rc::new(move |a| Qubit::from(x2.0(a.to()))),
Rc::new(move |b| Qubit::from(x.1(b.to())))
)
}
pub fn to_eq_q<A: Prop, B: Prop>(x: Eq<Qubit<S<Z>, A>, Qubit<S<Z>, B>>) -> Eq<Q<A, A>, Q<B, B>> {
let x2 = x.clone();
(
Rc::new(move |qa| x2.0(Qubit::from_q(qa)).to_q()),
Rc::new(move |qb| x.1(Qubit::from_q(qb)).to_q())
)
}
pub fn from_eq_q<A: Prop, B: Prop>(x: Eq<Q<A, A>, Q<B, B>>) -> Eq<Qubit<S<Z>, A>, Qubit<S<Z>, B>> {
let x2 = x.clone();
(
Rc::new(move |qa| Qubit::from_q(x2.0(qa.to_q()))),
Rc::new(move |qb| Qubit::from_q(x.1(qb.to_q())))
)
}
pub fn eq_to_eq_inv<A: Prop, B: Prop>(eq_q: Eq<Qu<A>, Qu<B>>) -> Eq<Qu<Not<A>>, Qu<Not<B>>> {
let eq_q = eq::symmetry(eq::modus_tollens(eq_q));
let eq_q = eq::in_left_arg(eq_q, (
Rc::new(move |x| qubit::sesh_to_inv(x)),
Rc::new(move |x| qubit::inv_to_sesh(x))
));
let eq_q = eq::in_right_arg(eq_q, (
Rc::new(move |x| qubit::sesh_to_inv(x)),
Rc::new(move |x| qubit::inv_to_sesh(x))
));
eq_q
}
pub fn in_arg<A: Prop, B: Prop, N>(x: Qubit<N, A>, y: Tauto<Eq<A, B>>) -> Qubit<N, B> {
Qubit(x.0, y(True).0(x.1))
}
pub fn eq_qu_q<A: Prop>() -> Eq<Qu<A>, Q<A, A>> {(Rc::new(Qu::to_q), Rc::new(Qu::from_q))}
pub fn eq_q_qu<A: Prop>() -> Eq<Q<A, A>, Qu<A>> {eq::symmetry(eq_qu_q())}