Skip to main content

Crate paulimer

Crate paulimer 

Source
Expand description

Pauli and Clifford algebra for quantum computing.

paulimer provides efficient implementations of Pauli operators and Clifford unitaries, the building blocks for stabilizer quantum mechanics and quantum error correction.

Implementations are based on data structures and algorithms described in arXiv:2309.08676.

§Overview

This crate offers:

  • Pauli operators: Dense (DensePauli) and sparse (SparsePauli) representations with phase tracking
  • Pauli groups: Subgroup representation (PauliGroup) for stabilizer groups and code analysis
  • Clifford unitaries: Efficient representation (CliffordUnitary) enabling fast conjugation

All types support efficient operations on quantum error correction codes, stabilizer circuit simulation, and Clifford circuit analysis.

§Quick Start

use paulimer::{DensePauli, SparsePauli, commutes_with};
use paulimer::{CliffordUnitary, Clifford};

// Create Pauli operators from strings
let pauli1: DensePauli = "XII".parse().unwrap();  // X ⊗ I ⊗ I
let pauli2: SparsePauli = "Z0".parse().unwrap(); // Sparse: Z₀ ⊗ I ⊗ I

// Check commutation (X and Z anticommute)
assert!(!commutes_with(&pauli1, &pauli2));

// Create and apply Clifford gates
let clifford = CliffordUnitary::identity(3);
let image = clifford.image(&pauli1);

§Pauli Operators

Pauli operators are tensor products of single-qubit Paulis {I, X, Y, Z} with phases {±1, ±i}. Two complementary representations optimize for different use cases:

  • DensePauli: Bit vectors storing X and Z components for all qubits.

    • Best for: operators on most qubits, small to moderate system sizes
    • Memory: O(n) for n qubits
    • String format: "XYZI" (one character per qubit)
  • SparsePauli: Index sets storing only non-identity positions.

    • Best for: operators on few qubits in large systems, weight << n
    • Memory: O(k) for weight k
    • String format: "X0 Z5 Y100" (positioned Paulis)

Both representations share a common trait-based interface (Pauli, PauliBinaryOps) enabling generic code that works with either type.

§Pauli Groups

The PauliGroup struct represents a subgroup of the Pauli group generated by a set of Pauli operators:

  • Membership testing: Check if an operator is in the group
  • Factorization: Decompose elements into generators
  • Enumeration: Iterate over all group elements
  • Structure queries: Abelian, stabilizer, and rank properties

PauliGroup is essential for:

  • Representing stabilizer groups for quantum error correcting codes
  • Checking code properties (distance, logical operators, normalizers)
  • Analyzing symmetries and logical equivalence of quantum circuits
  • Computing with discrete Pauli subgroups efficiently

§Clifford Unitaries

CliffordUnitary represents Clifford gates as the images of Pauli basis elements. A Clifford on n qubits is stored as a 2n×2n binary matrix plus phase information, enabling O(n²) Pauli conjugation instead of naive O(2ⁿ).

Key capabilities:

  • Conjugation: Propagate Paulis forward and backward through gates
  • Composition: Build gate sequences (O(n³))
  • Standard gates: Apply via CliffordMutable methods or UnitaryOp enum
  • Construction: Build from Pauli basis images or gate sequences

This representation is the foundation for efficient stabilizer simulation and Clifford circuit verification.

§Performance

Built on binar for efficient bit matrix operations:

  • SIMD acceleration where available
  • Cache-aligned data structures
  • Optimized Gaussian elimination
  • Binary symplectic representation enabling O(n²) Clifford conjugation

The algorithms in this crate support efficient verification and characterization of stabilizer circuits, including equivalence checking and logical action analysis.

§Features

  • python: Python bindings via PyO3
  • serde: Serialization support
  • schemars: JSON schema generation

§Examples

§Pauli Group Operations

use paulimer::{DensePauli, commutes_with, Pauli, PauliBinaryOps};

let x: DensePauli = "XII".parse().unwrap();
let z: DensePauli = "ZII".parse().unwrap();

// Anticommutation
assert!(!commutes_with(&x, &z));

// Multiplication: XZ = iY
let mut y = x.clone();
y.mul_assign_right(&z);
assert_eq!(y.weight(), 1);

§Clifford Propagation

use paulimer::{CliffordUnitary, CliffordMutable, Clifford};
use paulimer::{DensePauli, Pauli, UnitaryOp};

let mut clifford = CliffordUnitary::identity(2);

// Apply CNOT: maps X₀ → X₀ ⊗ X₁
clifford.left_mul_cx(0, 1);

let x0: DensePauli = "XI".parse().unwrap();
let image = clifford.image(&x0);
let expected: DensePauli = "XX".parse().unwrap();
assert_eq!(image, expected);

Re-exports§

pub use clifford::Clifford;
pub use clifford::CliffordMutable;
pub use clifford::CliffordUnitary;
pub use operations::UnitaryOp;
pub use pauli::DensePauli;
pub use pauli::Pauli;
pub use pauli::PauliBinaryOps;
pub use pauli::PauliMutable;
pub use pauli::Phase;
pub use pauli::SparsePauli;
pub use pauli::anti_commutes_with;
pub use pauli::commutes_with;
pub use pauli_group::PauliGroup;
pub use core::Axis;
pub use core::DirectedAxis;
pub use core::PauliMatrix;
pub use core::PauliObservable;
pub use core::PositionedPauliObservable;

Modules§

binar_impls
clifford
core
operations
pauli
pauli_group
setwise
traits

Macros§

assert_1q_gate
assert_2q_gate

Constants§

CLIFFORD_BIT_ALIGNMENT
SUB_CHARS

Functions§

subscript_digits