Skip to main content

PauliEvolution

Trait PauliEvolution 

Source
pub trait PauliEvolution {
    // Required method
    fn pauli_evolution(
        &mut self,
        pauli: &PauliString,
        angle: impl Into<ParameterValue>,
        qubits: &[Qubit],
    ) -> Result<(), CircuitError>;
}
Expand description

Extension trait for Circuit to add Pauli evolution functionality.

This trait provides methods to append Pauli rotation gates to a circuit.

Required Methods§

Source

fn pauli_evolution( &mut self, pauli: &PauliString, angle: impl Into<ParameterValue>, qubits: &[Qubit], ) -> Result<(), CircuitError>

Appends a Pauli evolution gate $e^{-i\theta/2 \cdot P}$ to the circuit.

This method implements the Pauli rotation using the basis transformation and CNOT ladder algorithm.

§Arguments
  • pauli - The Pauli string operator $P$ to exponentiate. Must be Hermitian (i.e., its phase must be $\pm 1$) for the evolution to be unitary.
  • angle - The rotation angle $\theta$ (can be symbolic or fixed)
  • qubits - The qubits to apply the operation on (must match pauli.num_qubits)
§Returns
  • Ok(()) - If the operation was successfully appended
  • Err(CircuitError) - If qubit count mismatch, PauliString has non-Hermitian phase ($\pm i$), or other error occurs
§Algorithm Details

The rotation $e^{-i\theta/2 \cdot P}$ is implemented as follows:

  1. Phase Validation: The PauliString’s internal phase must be $\pm 1$ (Hermitian). If the phase is $\pm i$, an error is returned because such operators cannot generate unitary evolution.

  2. Phase Absorption: The PauliString’s phase ($\pm 1$) is absorbed into the rotation angle: $\theta_{eff} = \theta \cdot \text{phase}$

  3. Basis Transformation: For each qubit $i$ with non-identity Pauli $P_i$:

    • $P_i = X$: Apply $H$ gate (transforms $X$ to $Z$ basis)
    • $P_i = Y$: Apply $S^\dagger$ then $H$ (circuit order: $S^\dagger \to H$, i.e. $S^\dagger$ is applied first, then $H$). This transforms $Y \to Z$: $S^\dagger |y+\rangle = |x+\rangle$, $H |x+\rangle = |z+\rangle$.
    • $P_i = Z$: No transformation needed
  4. CNOT Chain: For non-identity qubits $[i_0, i_1, \ldots, i_{n-1}]$, apply $CNOT(i_0 \to i_1), CNOT(i_1 \to i_2), \ldots$ to accumulate parity.

  5. Core Rotation: Apply $RZ(\theta_{eff})$ on the last non-identity qubit.

  6. Reverse CNOT Ladder: Apply CNOT gates in reverse order.

  7. Inverse Transformation: Apply inverse basis transformations.

§Global Phase

If the Pauli string consists entirely of identity operators (e.g., “III”), the operation reduces to a global phase $e^{-i\theta/2}$, which is added to the circuit’s global phase.

§Examples
use cqlib_core::circuit::Circuit;
use cqlib_core::qis::pauli::PauliString;
use cqlib_core::qis::evolution::PauliEvolution;

let mut circuit = Circuit::new(3);
let qubits = circuit.qubits();

// Create a Pauli string X ⊗ Z ⊗ I
let pauli: PauliString = "XZI".parse().unwrap();

// Apply e^(-i * π/4 * XZI)
circuit.pauli_evolution(&pauli, std::f64::consts::PI / 2.0, &qubits).unwrap();

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§