wai-quantum 0.3.38

A deterministic quantum stack in pure Rust: byte-exact circuit simulation (statevector / stabilizer / tensor-network MPS / sparse-Pauli backends), sparse Pauli dynamics at utility scale (arbitrary angles, 1024 qubits), belief-propagation tensor networks on the hardware graph, error mitigation, qLDPC decoding, noise learning, circuit-equivalence proofs, a phasor interference-ML layer, information-theoretic limits, noisy channels and state tomography, and signed energy-accounted receipts. No QPU, no cloud, no system libraries — identical results native, in the browser, and as a WASI component at the edge.
Documentation
//! Gates as matrices, shared by the dense state vector and the tensor
//! networks: any unitary on any qubits, and the standard ones by name.
//!
//! Matrices are row-major, rows are outputs and columns inputs, and the first
//! listed qubit is the most significant bit of the local index. Angles enter
//! through the crate's own `sin`/`cos`, so a named gate is the same bits on
//! every machine.

pub use crate::linalg::C;

/// A gate: a unitary on `qubits`, as a `2ᵏ × 2ᵏ` row-major matrix whose rows
/// are outputs and columns inputs, with `qubits[0]` the most significant bit.
#[derive(Clone, Debug)]
pub struct Gate {
    pub qubits: Vec<u32>,
    pub matrix: Vec<C>,
}

/// A complex number for building gates.
pub fn complex(re: f64, im: f64) -> C {
    C { re, im }
}

const Z: C = C { re: 0.0, im: 0.0 };
const O: C = C { re: 1.0, im: 0.0 };
const I: C = C { re: 0.0, im: 1.0 };

fn cis(theta: f64) -> C {
    let (s, c) = crate::repro::sin_cos(theta);
    C { re: c, im: s }
}

fn one(q: u32, m: [C; 4]) -> Gate {
    Gate { qubits: vec![q], matrix: m.to_vec() }
}

fn two(a: u32, b: u32, m: [C; 16]) -> Gate {
    Gate { qubits: vec![a, b], matrix: m.to_vec() }
}

impl Gate {
    pub fn h(q: u32) -> Gate {
        let r = core::f64::consts::FRAC_1_SQRT_2;
        one(q, [complex(r, 0.0), complex(r, 0.0), complex(r, 0.0), complex(-r, 0.0)])
    }
    pub fn x(q: u32) -> Gate {
        one(q, [Z, O, O, Z])
    }
    pub fn y(q: u32) -> Gate {
        one(q, [Z, complex(0.0, -1.0), I, Z])
    }
    pub fn z(q: u32) -> Gate {
        one(q, [O, Z, Z, complex(-1.0, 0.0)])
    }
    pub fn s(q: u32) -> Gate {
        one(q, [O, Z, Z, I])
    }
    pub fn sdg(q: u32) -> Gate {
        one(q, [O, Z, Z, complex(0.0, -1.0)])
    }
    pub fn t(q: u32) -> Gate {
        let r = core::f64::consts::FRAC_1_SQRT_2;
        one(q, [O, Z, Z, complex(r, r)])
    }
    pub fn tdg(q: u32) -> Gate {
        let r = core::f64::consts::FRAC_1_SQRT_2;
        one(q, [O, Z, Z, complex(r, -r)])
    }
    /// √X = ½[[1+i, 1−i], [1−i, 1+i]].
    pub fn sqrt_x(q: u32) -> Gate {
        let (p, m) = (complex(0.5, 0.5), complex(0.5, -0.5));
        one(q, [p, m, m, p])
    }
    /// √Y = ½[[1+i, −1−i], [1+i, 1+i]].
    pub fn sqrt_y(q: u32) -> Gate {
        let p = complex(0.5, 0.5);
        one(q, [p, complex(-0.5, -0.5), p, p])
    }
    /// √W, with W = (X + Y)/√2: √X conjugated by diag(1, e^{iπ/4}).
    pub fn sqrt_w(q: u32) -> Gate {
        let (p, m) = (complex(0.5, 0.5), complex(0.5, -0.5));
        let (e, ec) = (cis(core::f64::consts::FRAC_PI_4), cis(-core::f64::consts::FRAC_PI_4));
        let mul = |a: C, b: C| complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re);
        one(q, [p, mul(m, ec), mul(m, e), p])
    }
    /// `exp(−iθX/2)`.
    pub fn rx(q: u32, theta: f64) -> Gate {
        let (s, c) = crate::repro::sin_cos(theta / 2.0);
        one(q, [complex(c, 0.0), complex(0.0, -s), complex(0.0, -s), complex(c, 0.0)])
    }
    /// `exp(−iθY/2)`.
    pub fn ry(q: u32, theta: f64) -> Gate {
        let (s, c) = crate::repro::sin_cos(theta / 2.0);
        one(q, [complex(c, 0.0), complex(-s, 0.0), complex(s, 0.0), complex(c, 0.0)])
    }
    /// `exp(−iθZ/2)`.
    pub fn rz(q: u32, theta: f64) -> Gate {
        one(q, [cis(-theta / 2.0), Z, Z, cis(theta / 2.0)])
    }
    /// `diag(1, e^{iθ})`.
    pub fn phase(q: u32, theta: f64) -> Gate {
        one(q, [O, Z, Z, cis(theta)])
    }
    /// Controlled X, control first.
    pub fn cx(c: u32, t: u32) -> Gate {
        two(c, t, [O, Z, Z, Z, Z, O, Z, Z, Z, Z, Z, O, Z, Z, O, Z])
    }
    pub fn cz(a: u32, b: u32) -> Gate {
        two(a, b, [O, Z, Z, Z, Z, O, Z, Z, Z, Z, O, Z, Z, Z, Z, complex(-1.0, 0.0)])
    }
    pub fn swap(a: u32, b: u32) -> Gate {
        two(a, b, [O, Z, Z, Z, Z, Z, O, Z, Z, O, Z, Z, Z, Z, Z, O])
    }
    pub fn iswap(a: u32, b: u32) -> Gate {
        two(a, b, [O, Z, Z, Z, Z, Z, I, Z, Z, I, Z, Z, Z, Z, Z, O])
    }
    /// `diag(1, 1, 1, e^{iφ})`.
    pub fn cphase(a: u32, b: u32, phi: f64) -> Gate {
        two(a, b, [O, Z, Z, Z, Z, O, Z, Z, Z, Z, O, Z, Z, Z, Z, cis(phi)])
    }
    /// `exp(−iθ Z⊗Z / 2)`.
    pub fn rzz(a: u32, b: u32, theta: f64) -> Gate {
        let (m, p) = (cis(-theta / 2.0), cis(theta / 2.0));
        two(a, b, [m, Z, Z, Z, Z, p, Z, Z, Z, Z, p, Z, Z, Z, Z, m])
    }
    /// The fermionic simulation gate: an iSWAP-like rotation by `θ` and a
    /// conditional phase `e^{−iφ}` on `|11⟩`.
    pub fn fsim(a: u32, b: u32, theta: f64, phi: f64) -> Gate {
        let (s, c) = crate::repro::sin_cos(theta);
        let (cc, ms) = (complex(c, 0.0), complex(0.0, -s));
        two(a, b, [O, Z, Z, Z, Z, cc, ms, Z, Z, ms, cc, Z, Z, Z, Z, cis(-phi)])
    }

    /// Whether the matrix is diagonal (exactly zero off the diagonal).
    pub fn is_diagonal(&self) -> bool {
        let d = 1usize << self.qubits.len();
        (0..d).all(|r| (0..d).all(|c| r == c || (self.matrix[r * d + c].re == 0.0 && self.matrix[r * d + c].im == 0.0)))
    }
}