ppvm-traits 0.1.1

Core traits, the `Config` bundle and the single-qubit Pauli alphabet shared by the ppvm crates.
Documentation
// SPDX-FileCopyrightText: 2026 The PPVM Authors
// SPDX-License-Identifier: Apache-2.0

use crate::config::Config;

macro_rules! def_rotation {
    ($name:ident, $batch:ident, $x_a:expr, $z_a:expr, $x_b:expr, $z_b:expr, $doc:literal) => {
        #[doc = $doc]
        fn $name(&mut self, a: usize, b: usize, theta: impl Into<T::Coeff>) {
            self.rotate_2([$x_a, $z_a], [$x_b, $z_b], a, b, theta.into())
        }

        #[doc = concat!("Explicit batched form of [`", stringify!($name), "`].")]
        fn $batch(&mut self, pairs: &[(usize, usize)], theta: impl Into<T::Coeff>) {
            let theta = theta.into();
            for &(a, b) in pairs {
                self.$name(a, b, theta.clone())
            }
        }
    };
}

/// Two-qubit Pauli rotations, generated by `P_a ⊗ P_b` for any pair of
/// non-identity Paulis. Provides the named convenience methods
/// `rxx`, `rxy`, …, `rzz` on top of the generic [`rotate_2`].
///
/// [`rotate_2`]: RotationTwo::rotate_2
pub trait RotationTwo<T: Config> {
    /// Two-qubit Pauli rotation: `exp(-i * theta/2 * P_a ⊗ P_b)`.
    ///
    /// Each axis is encoded as `[x, z]` bits:
    /// `[0,0]` = I, `[1,0]` = X, `[0,1]` = Z, `[1,1]` = Y.
    fn rotate_2(&mut self, axis_a: [u8; 2], axis_b: [u8; 2], a: usize, b: usize, theta: T::Coeff);

    //                 x, z, x, z
    def_rotation!(rxx, rxx_many, 1, 0, 1, 0, "`exp(-i θ/2 · X_a X_b)`.");
    def_rotation!(rxy, rxy_many, 1, 0, 1, 1, "`exp(-i θ/2 · X_a Y_b)`.");
    def_rotation!(rxz, rxz_many, 1, 0, 0, 1, "`exp(-i θ/2 · X_a Z_b)`.");

    def_rotation!(ryx, ryx_many, 1, 1, 1, 0, "`exp(-i θ/2 · Y_a X_b)`.");
    def_rotation!(ryy, ryy_many, 1, 1, 1, 1, "`exp(-i θ/2 · Y_a Y_b)`.");
    def_rotation!(ryz, ryz_many, 1, 1, 0, 1, "`exp(-i θ/2 · Y_a Z_b)`.");

    def_rotation!(rzx, rzx_many, 0, 1, 1, 0, "`exp(-i θ/2 · Z_a X_b)`.");
    def_rotation!(rzy, rzy_many, 0, 1, 1, 1, "`exp(-i θ/2 · Z_a Y_b)`.");
    def_rotation!(rzz, rzz_many, 0, 1, 0, 1, "`exp(-i θ/2 · Z_a Z_b)`.");
}