/* # Qubit Trait This example shows that one can use a trait for qubits instead of a concrete type. It means that qubits are reasoned about using generics in addition to normal arguments. There are both pros and cons to this approach. The reason this design is not used in the library, is because this approach collapses multiple PSQs into a single PSQ. This becomes a problem when multiple PSQs uses incompatible axioms for the qubit operator. Another disadvantage, to use a qubit, a generic parameter must be added, which makes proofs more complex. */ use prop::*; fn main() {} /// Trait implemented by qubits. pub trait Qubit: Prop {} /// Since qubits only depend on their argument, /// we need a way to transport proofs /// from one qubit type to another qubit type. /// pub fn eqv< A: Prop, B1: Qubit, B2: Qubit, >() -> Eq {unimplemented!()} pub trait ConQubit: Qubit {} pub trait CovQubit: Qubit {} pub type Qual = And, And>; pub trait Id: Prop {} impl Id for Eq {} impl IsContr for Eq {} pub type Refl = Eq; #[derive(Clone)] pub struct Sym(A, B, P); impl> Id for Sym {} impl> IsContr for Sym {} #[derive(Clone)] pub struct Trans(A, B, C, P, Q); impl, Q: Id> Id for Trans {} impl, Q: Id> IsContr for Trans {} pub trait IsProp: Prop {} #[derive(Clone)] pub struct PropEqv(A, B, P, Q); impl, Q: Id> Id for PropEqv {} impl, Q: Id> IsContr for PropEqv {} #[derive(Clone)] pub struct PropSym(A, B); impl, Q: Id> Id for PropSym {} impl IsContr for PropSym {} #[derive(Clone)] pub struct PropTrans(A, B, C); impl, Q: Id> Id for PropTrans {} impl IsContr for PropTrans {} pub trait IsContr: IsProp { fn elem() -> Self {unimplemented!()} } impl IsProp for T {} pub fn id_ext< A: IsProp, B: IsProp, P: Id, >() -> Eq {unimplemented!()} pub fn id_eqv< A1: Prop, A2: Prop, B1: Qubit, B2: Qubit, P: Id, >() -> Eq {unimplemented!()} pub fn id_con_eqv< A1: Prop, A2: Prop, B1: ConQubit, B2: ConQubit, C1: ConQubit, C2: ConQubit, P: Id, >() -> Qual {unimplemented!()} pub fn con_eqv< A: Prop, B1: ConQubit, B2: ConQubit, C1: ConQubit, C2: ConQubit, >() -> Qual {unimplemented!()} pub fn id_cov_eqv< A1: Prop, A2: Prop, B1: CovQubit, B2: CovQubit, C1: CovQubit, C2: CovQubit, P: Id, >() -> Qual {unimplemented!()} pub fn cov_eqv< A: Prop, B1: CovQubit, B2: CovQubit, C1: CovQubit, C2: CovQubit, >() -> Qual {unimplemented!()} pub fn test_eqv, B2: Qubit>() -> impl Prop { eqv::() } pub fn test2_eqv>() -> impl Prop { eqv::() } pub fn test3_eqv, B2: Qubit>( q_a1_a2: Qual ) -> Eq { and::to_eq_pos(q_a1_a2.1) } pub fn test4_eqv< A: Prop, B1: ConQubit, B2: ConQubit, C1: ConQubit, C2: ConQubit, >() -> Eq { con_eqv::().0 } pub fn test5_eqv< A: Prop, B: ConQubit, C1: ConQubit, C2: ConQubit, D1: ConQubit, D2: ConQubit, >() -> Qual { con_eqv::() } pub fn test6_eqv< A: Prop, B1: Qubit, B2: Qubit, >() -> Eq { id_eqv::>() } pub fn test7_eqv< A: Prop, B: ConQubit, C1: ConQubit, C2: ConQubit, D1: ConQubit, D2: ConQubit, >() -> Qual { id_con_eqv::>() } pub fn test8_eqv< A: Prop, B: Prop, P: Id, C: Qubit, >() -> Eq { id_eqv::>>() } pub fn test9_eqv< A: IsProp, B: IsProp, P: Id + IsProp, Q: Id + IsProp, >() -> Eq { id_ext::>() } pub fn test10_eqv< A: IsProp, B: IsProp, P: Id + IsProp, Q: Id, >() -> Eq> { id_ext::, PropEqv>>() } pub fn test11_eqv< A: IsProp, B: IsProp, P: Id + IsProp, Q: Id + IsProp, >() -> Eq { id_ext::>() } pub fn test12_eqv< A: IsProp, B: IsProp, C: IsProp, P: Id + IsProp, Q: Id + IsProp, >() -> Eq { id_ext::>() } pub fn test13_eqv< A: IsProp, >() { fn foo>(_e: B) {} let e = id_ext::>(); foo::>(e) } pub fn test14_eqv< A: Prop, B: Prop >(eq_a_b: Eq) { fn foo>(_e: P) {} foo(eq_a_b) } pub fn test15_eqv< A: IsContr, B: IsContr, >() { fn foo>() {} foo::>() } pub fn test16_eqv< A: IsProp, B: IsProp, >() -> Eq { id_ext::>() } pub fn test17_eqv< A: IsProp >() -> impl IsContr { id_ext::>() } pub fn test18_eqv< A: IsProp >() -> impl IsProp { id_ext::>() }