lay 0.1.0

Traits for quantum computing
Documentation
use std::any::Any;
use std::fmt::Debug;

use crate::Layer;
use crate::gates::{PauliGate, HGate, SGate, TGate, CXGate};
use crate::operations::{Operation, PauliOperation, HOperation, SOperation, TOperation, CXOperation};

pub mod opid {
    pub const INIT: u16 = 1;
    pub const MEAS: u16 = 2;
    pub const X: u16 = 3;
    pub const Y: u16 = 4;
    pub const Z: u16 = 5;
    pub const H: u16 = 6;
    pub const S: u16 = 7;
    pub const SDG: u16 = 8;
    pub const T: u16 = 9;
    pub const TDG: u16 = 10;
    pub const CX: u16 = 11;
    pub const USERDEF: u16 = 256;
}

#[derive(Debug)]
pub enum OpArgs<L: Layer + ?Sized> {
    Empty(u16),
    Q(u16, L::Qubit),
    QQ(u16, L::Qubit, L::Qubit),
    QS(u16, L::Qubit, L::Slot),
    QF(u16, L::Qubit, f32),
    QD(u16, L::Qubit, f64),
    QFF(u16, L::Qubit, f32, f32),
    Var(u16, Box<dyn Any + Send>),
}

impl<L> Operation<L> for OpArgs<L> where L: Layer<Operation=OpArgs<L>> + ?Sized {
    fn initialize() -> OpArgs<L> {
        OpArgs::Empty(opid::INIT)
    }

    fn measure(q: L::Qubit, s: L::Slot) -> OpArgs<L> {
        OpArgs::QS(opid::MEAS, q, s)
    }
}

impl<L> PauliOperation<L> for OpArgs<L> where L: Layer<Operation=OpArgs<L>> + PauliGate + ?Sized {
    fn x(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::X, q)
    }

    fn y(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::Y, q)
    }

    fn z(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::Z, q)
    }
}

impl<L> HOperation<L> for OpArgs<L> where L: Layer<Operation=OpArgs<L>> + HGate + ?Sized {
    fn h(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::H, q)
    }
}

impl<L> SOperation<L> for OpArgs<L> where L: Layer<Operation=OpArgs<L>> + SGate + ?Sized {
    fn s(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::S, q)
    }

    fn sdg(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::SDG, q)
     }
}

impl<L> TOperation<L> for OpArgs<L> where L: Layer<Operation=OpArgs<L>> + TGate + ?Sized {
    fn t(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::T, q)
     }

    fn tdg(q: L::Qubit) -> OpArgs<L> {
        OpArgs::Q(opid::TDG, q)
    }
}

impl<L> CXOperation<L> for OpArgs<L> where L: Layer<Operation=OpArgs<L>> + CXGate + ?Sized {
    fn cx(c: L::Qubit, t: L::Qubit) -> OpArgs<L> {
        OpArgs::QQ(opid::CX, c, t)
    }
}