pub struct Statevector {
pub num_qubits: usize,
/* private fields */
}Expand description
Quantum statevector representing a pure quantum state.
A statevector describes the quantum state of an N-qubit system as a vector of 2^N complex amplitudes. The state |ψ⟩ = Σᵢ αᵢ|i⟩ is stored with αᵢ as the amplitude for basis state |i⟩ (i in binary representation).
§Memory Layout
The data vector uses contiguous memory layout (compatible with C/NumPy),
where the amplitude at index i corresponds to basis state |i⟩ with
qubit indices mapping to bits from least significant (qubit 0) to most.
§Memory Layout
The data buffer uses a 64-byte aligned allocation so that SIMD kernels
(AVX2, SSE2) can safely use aligned load/store instructions.
§Example
use cqlib_core::qis::Statevector;
// Create a 2-qubit state in |00⟩
let sv = Statevector::new(2);
assert_eq!(sv.num_qubits, 2);
assert_eq!(sv.data().len(), 4); // 2^2 amplitudes
// |00⟩ state: amplitude 1.0 at index 0, 0.0 elsewhere
assert_eq!(sv.data()[0], num_complex::Complex64::new(1.0, 0.0));Fields§
§num_qubits: usizeNumber of qubits in the system.
Implementations§
Source§impl Statevector
impl Statevector
Sourcepub fn data(&self) -> &[Complex64] ⓘ
pub fn data(&self) -> &[Complex64] ⓘ
Returns the complex amplitudes as a shared slice.
Length is 2^num_qubits. The amplitude at index i is the coefficient of basis
state |i⟩ in the computational basis.
§Example
use cqlib_core::qis::Statevector;
let sv = Statevector::new(2); // |00⟩
assert_eq!(sv.data().len(), 4);
assert_eq!(sv.data()[0], num_complex::Complex64::new(1.0, 0.0));Sourcepub fn data_mut(&mut self) -> &mut [Complex64] ⓘ
pub fn data_mut(&mut self) -> &mut [Complex64] ⓘ
Returns the complex amplitudes as a mutable slice.
Mutating the slice can break normalization; callers are responsible for preserving a valid statevector.
Sourcepub fn new(num_qubits: usize) -> Self
pub fn new(num_qubits: usize) -> Self
Creates a new statevector initialized to the |0…0⟩ state.
The statevector represents the quantum state as a vector of 2^N complex amplitudes, where N is the number of qubits. All amplitudes are initialized to zero except the first element (|0…0⟩) which is set to 1.0.
§Arguments
num_qubits- Number of qubits in the system
§Returns
A new Statevector instance in the ground state
§Example
use cqlib_core::qis::Statevector;
let sv = Statevector::new(2); // |00⟩ state
assert_eq!(sv.num_qubits, 2);
assert_eq!(sv.data().len(), 4); // 2^2 amplitudes§Panics
Panics if the dimension is unrepresentable or allocation fails.
Use Self::try_new to receive an error instead.
Sourcepub fn try_new(num_qubits: usize) -> Result<Self, QisError>
pub fn try_new(num_qubits: usize) -> Result<Self, QisError>
Creates the ground state, returning an error for an unrepresentable dimension or a failed allocation.
§Errors
Returns QisError::InvalidParameterValue for an unrepresentable
dimension, or QisError::UnsupportedOperation if allocation fails.
Sourcepub fn from_state(
num_qubits: usize,
initial_state: Vec<Complex64>,
) -> Result<Self, QisError>
pub fn from_state( num_qubits: usize, initial_state: Vec<Complex64>, ) -> Result<Self, QisError>
Creates a statevector from initial amplitudes with normalization check.
§Arguments
num_qubits- Number of qubits in the systeminitial_state- Vector of 2^N complex amplitudes
§Errors
Returns an error if:
initial_statelength doesn’t match 2^num_qubits- State is not normalized (sum of probabilities ≠ 1.0 within a dimension-scaled tolerance)
§Example
use cqlib_core::qis::Statevector;
use num_complex::Complex64;
// Create |+0⟩ = (|00⟩ + |10⟩)/√2
let amps = vec![
Complex64::new(std::f64::consts::FRAC_1_SQRT_2, 0.0), // |00⟩
Complex64::new(0.0, 0.0), // |01⟩
Complex64::new(std::f64::consts::FRAC_1_SQRT_2, 0.0), // |10⟩
Complex64::new(0.0, 0.0), // |11⟩
];
let sv = Statevector::from_state(2, amps);Sourcepub fn from_circuit(circuit: &Circuit) -> Result<Self, QisError>
pub fn from_circuit(circuit: &Circuit) -> Result<Self, QisError>
Constructs a statevector by simulating a quantum circuit.
Executes the circuit gates sequentially to evolve the initial |0…0⟩ state. Complex gates are decomposed before execution.
§Arguments
circuit- The quantum circuit to simulate
§Returns
Ok(Statevector)- The resulting state after circuit executionErr(QisError)- If the circuit contains unsupported operations (control flow gates, symbolic parameters) or decomposition fails
§Supported Instructions
- Standard single and multi-qubit gates
- Controlled gates (CX, CY, CZ, CRX, CRY, CRZ)
- Multi-controlled gates (CCX/Toffoli)
- Unitary gates with matrix representation
- Barriers and delays (ignored)
§Example
use cqlib_core::circuit::{Circuit, Qubit};
use cqlib_core::qis::Statevector;
// Create Bell state: |Φ+⟩ = (|00⟩ + |11⟩)/√2
let mut circuit = Circuit::new(2);
circuit.h(Qubit::new(0)).unwrap();
circuit.cx(Qubit::new(0), Qubit::new(1)).unwrap();
let sv = Statevector::from_circuit(&circuit).unwrap();Sourcepub fn apply_circuit(&mut self, circuit: &Circuit) -> Result<(), QisError>
pub fn apply_circuit(&mut self, circuit: &Circuit) -> Result<(), QisError>
Applies a quantum circuit to this statevector in-place.
The circuit’s resolved global phase is applied, retaining nonzero residuals. Once bound to circuit qubit IDs, subsequent circuits must have the same IDs in the same order. The mapping is committed only on success; gates completed before an error are not rolled back.
As in from_circuit, terminal measurements are ignored. A measured qubit
used by a later gate or Reset is rejected before the state is changed.
Independent gates, repeated measurements, Barrier, Delay, and Store are allowed.
The circuit is first decomposed into basic gates via Circuit::decompose,
then each operation is applied sequentially to the current state.
§Arguments
circuit- The circuit to apply. Must have the same number of qubits as this statevector.
§Returns
Ok(())- If all operations were applied successfullyErr(QisError)- If the circuit cannot be simulated
§Errors
QisError::InvalidStateDimensionifcircuit.num_qubits() != self.num_qubitsQisError::UnsupportedOperationif the circuit contains classical control flowQisError::CircuitErrorif a gate lacks a matrix representation, contains unresolved symbolic parameters, or a referenced qubit is not found
§Supported Instructions
- Standard single and multi-qubit gates
- Controlled gates (CX, CY, CZ, CRX, CRY, CRZ)
- Multi-controlled gates (CCX / Toffoli)
- Unitary gates with an explicit matrix representation
Reset- Barriers and delays (ignored)
- Measurement output declarations from
Circuit::measure*(ignored)
Sourcepub fn apply_standard_gate(
&mut self,
gate: StandardGate,
qubits: &[usize],
params: &[f64],
) -> Result<(), QisError>
pub fn apply_standard_gate( &mut self, gate: StandardGate, qubits: &[usize], params: &[f64], ) -> Result<(), QisError>
Applies a standard gate to the statevector.
Internal dispatcher that routes to specialized implementations based on gate type.
§Arguments
gate- The standard gate to applyqubits- Target qubit indicesparams- Gate parameters (for parameterized gates)
Sourcepub fn probabilities(&self) -> Vec<f64>
pub fn probabilities(&self) -> Vec<f64>
Computes the measurement probability distribution over all basis states.
Returns P(|i⟩) = |αᵢ|² for each basis state |i⟩. Uses parallel iteration for large statevectors.
§Returns
Vector of probabilities summing to 1.0 (within floating-point precision).
§Example
use cqlib_core::qis::Statevector;
let mut sv = Statevector::new(1);
sv.apply_h(0);
let probs = sv.probabilities();
// |+⟩ state: P(|0⟩) = P(|1⟩) = 0.5
assert!((probs[0] - 0.5).abs() < 1e-10);
assert!((probs[1] - 0.5).abs() < 1e-10);Sourcepub fn apply_single_qubit_gate(
&mut self,
qubit: usize,
matrix: [[Complex64; 2]; 2],
) -> Result<(), QisError>
pub fn apply_single_qubit_gate( &mut self, qubit: usize, matrix: [[Complex64; 2]; 2], ) -> Result<(), QisError>
Applies an arbitrary single-qubit gate.
General-purpose method for applying any 2x2 unitary matrix. For standard gates, prefer specialized methods (apply_h, apply_x, etc.) which have optimized implementations.
§Arguments
qubit- Target qubit indexmatrix- 2x2 unitary matrix [[u00, u01], [u10, u11]]
§Errors
Returns QisError::IndexOutOfBounds if qubit is out of bounds.
§Example
use cqlib_core::qis::Statevector;
use num_complex::Complex64;
let mut sv = Statevector::new(1);
// Apply a custom rotation
let matrix = [
[Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0)],
[Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
];
sv.apply_single_qubit_gate(0, matrix); // Equivalent to X gateSourcepub fn apply_two_qubit_gate(
&mut self,
q0: usize,
q1: usize,
matrix: [[Complex64; 4]; 4],
) -> Result<(), QisError>
pub fn apply_two_qubit_gate( &mut self, q0: usize, q1: usize, matrix: [[Complex64; 4]; 4], ) -> Result<(), QisError>
Apply a general two-qubit gate.
§Arguments
q0- First qubit index (logical)q1- Second qubit index (logical)matrix- 4x4 unitary matrix in the standard computational basis ordered as |00⟩, |01⟩, |10⟩, |11⟩ where the bits are (q0, q1). That is, matrix[i][j] is the amplitude of |i⟩ when input is |j⟩, with i = q0*2 + q1 (binary: q0 is MSB, q1 is LSB).
§Example - CNOT with q0 as control and q1 as target:
The CNOT gate flips the target when control is |1⟩: |00⟩ -> |00⟩, |01⟩ -> |01⟩, |10⟩ -> |11⟩, |11⟩ -> |10⟩
This corresponds to the matrix (rows/cols ordered as |00⟩, |01⟩, |10⟩, |11⟩):
[[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0]]Sourcepub fn apply_unitary_gate(
&mut self,
qubits: &[usize],
matrix: &Array2<Complex64>,
) -> Result<(), QisError>
pub fn apply_unitary_gate( &mut self, qubits: &[usize], matrix: &Array2<Complex64>, ) -> Result<(), QisError>
Applies an arbitrary n-qubit unitary gate.
General-purpose method for applying any 2^n × 2^n unitary matrix. Uses block-iteration with bit-manipulation for efficient index calculation. Supports parallel execution for large statevectors.
For standard gates, prefer specialized methods which are more optimized.
§Arguments
qubits- Slice of qubit indices the gate acts on (logical order)matrix- The unitary matrix as a 2^n × 2^n ndarray
§Errors
Returns an error if:
- Qubit indices are out of bounds
- Qubit indices contain duplicates
- Matrix dimensions don’t match 2^n × 2^n
§Example
use cqlib_core::qis::Statevector;
use ndarray::Array2;
use num_complex::Complex64;
let mut sv = Statevector::new(2);
// Create SWAP gate matrix
let swap = Array2::from_shape_vec(
(4, 4),
vec![
Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0),
Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0),
]
).unwrap();
sv.apply_unitary_gate(&[0, 1], &swap);Sourcepub fn apply_pauli_rotation(
&mut self,
pauli: &PauliString,
theta: f64,
) -> Result<(), QisError>
pub fn apply_pauli_rotation( &mut self, pauli: &PauliString, theta: f64, ) -> Result<(), QisError>
Applies a native Pauli-string rotation in place.
The operation is
exp(-i * theta / 2 * P)
where P is a Hermitian PauliString. This fused kernel avoids
decomposing a Pauli exponential into basis changes, a CNOT ladder, and
an RZ gate. It is intended for high-frequency variational workloads.
§Errors
Returns an error if the Pauli string has a different number of qubits or carries an imaginary global phase (and is therefore not Hermitian).
Sourcepub fn apply_x(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_x(&mut self, qubit: usize) -> Result<(), QisError>
Apply Pauli-X gate: bit flip Matrix: [[0, 1], [1, 0]] Cost: 0 muls, 0 adds, just memory swap.
Sourcepub fn apply_y(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_y(&mut self, qubit: usize) -> Result<(), QisError>
Apply Pauli-Y gate Matrix: [[0, -i], [i, 0]] Cost: Manual component swapping (faster than complex mul).
Sourcepub fn apply_z(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_z(&mut self, qubit: usize) -> Result<(), QisError>
Apply Pauli-Z gate: phase flip Matrix: [[1, 0], [0, -1]] Cost: Only processes half the array. 1 negation.
Sourcepub fn apply_h(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_h(&mut self, qubit: usize) -> Result<(), QisError>
Apply Hadamard gate Matrix: 1/sqrt(2) * [[1, 1], [1, -1]] Creates superposition: H|0⟩ = (|0⟩ + |1⟩)/√2, H|1⟩ = (|0⟩ - |1⟩)/√2
Sourcepub fn apply_u(
&mut self,
qubit: usize,
theta: f64,
phi: f64,
lambda: f64,
) -> Result<(), QisError>
pub fn apply_u( &mut self, qubit: usize, theta: f64, phi: f64, lambda: f64, ) -> Result<(), QisError>
Apply U gate (generic single-qubit rotation) Matrix: [[cos(θ/2), -e^(iλ)sin(θ/2)], [e^(iφ)sin(θ/2), e^(i(φ+λ))cos(θ/2)]]
This is the most general single-qubit unitary (up to global phase). Parameters: theta: rotation angle phi: phase of the rotation axis lambda: second phase parameter
Sourcepub fn apply_s(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_s(&mut self, qubit: usize) -> Result<(), QisError>
Apply S gate (Phase gate, Z^1/2) Matrix: [[1, 0], [0, i]]
Sourcepub fn apply_sdg(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_sdg(&mut self, qubit: usize) -> Result<(), QisError>
Apply S† (S-dagger) gate Matrix: [[1, 0], [0, -i]]
Sourcepub fn apply_t(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_t(&mut self, qubit: usize) -> Result<(), QisError>
Apply T gate (Z^1/4) Matrix: [[1, 0], [0, e^(i*pi/4)]]
Sourcepub fn apply_tdg(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_tdg(&mut self, qubit: usize) -> Result<(), QisError>
Apply T† (T-dagger) gate Matrix: [[1, 0], [0, e^(-i*pi/4)]]
Sourcepub fn apply_phase(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
pub fn apply_phase(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
Apply P (Phase) gate Matrix: [[1, 0], [0, e^(i*theta)]]
Sourcepub fn apply_rx(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
pub fn apply_rx(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
Apply Rx(theta) gate Matrix: [[cos(t/2), -isin(t/2)], [-isin(t/2), cos(t/2)]]
Sourcepub fn apply_ry(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
pub fn apply_ry(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
Apply Ry(theta) gate Matrix: [[cos(t/2), -sin(t/2)], [sin(t/2), cos(t/2)]]
Sourcepub fn apply_rz(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
pub fn apply_rz(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
Apply Rz(theta) gate Matrix: [[e^(-itheta/2), 0], [0, e^(itheta/2)]]
Sourcepub fn apply_x2p(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_x2p(&mut self, qubit: usize) -> Result<(), QisError>
Applies X2P gate: Rx(π/2), also known as √X.
Matrix: 1/√2 * [[1, -i], [-i, 1]]
§Optimization
Uses constant factors only, no trigonometric functions.
Sourcepub fn apply_x2m(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_x2m(&mut self, qubit: usize) -> Result<(), QisError>
Applies X2M gate: Rx(-π/2), inverse of √X.
Matrix: 1/√2 * [[1, i], [i, 1]]
Sourcepub fn apply_y2p(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_y2p(&mut self, qubit: usize) -> Result<(), QisError>
Applies Y2P gate: Ry(π/2).
Matrix: 1/√2 * [[1, -1], [1, 1]]
Sourcepub fn apply_y2m(&mut self, qubit: usize) -> Result<(), QisError>
pub fn apply_y2m(&mut self, qubit: usize) -> Result<(), QisError>
Applies Y2M gate: Ry(-π/2).
Matrix: 1/√2 * [[1, 1], [-1, 1]]
Sourcepub fn apply_xy2p(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
pub fn apply_xy2p(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
Applies XY2P gate: Rz(θ - π/2) Ry(π/2) Rz(π/2 - θ).
Matrix: 1/√2 * [[1, -i·e^(-iθ)], [-i·e^(iθ), 1]]
§Arguments
qubit- Target qubit indextheta- Rotation angle
Sourcepub fn apply_xy2m(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
pub fn apply_xy2m(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
Applies XY2M gate: Rz(-θ + π/2) Ry(-π/2) Rz(-π/2 + θ).
Matrix: 1/√2 * [[1, i·e^(-iθ)], [i·e^(iθ), 1]]
§Arguments
qubit- Target qubit indextheta- Rotation angle
Sourcepub fn apply_xy(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
pub fn apply_xy(&mut self, qubit: usize, theta: f64) -> Result<(), QisError>
Applies XY gate.
Matrix: [[0, -i·e^(-iθ)], [-i·e^(iθ), 0]]
This is a single-qubit gate distinct from XY2P/XY2M.
§Arguments
qubit- Target qubit indextheta- Rotation angle
Sourcepub fn apply_rxy(
&mut self,
qubit: usize,
theta: f64,
phi: f64,
) -> Result<(), QisError>
pub fn apply_rxy( &mut self, qubit: usize, theta: f64, phi: f64, ) -> Result<(), QisError>
Apply general rotation R(theta, phi).
Rotates around axis cos(phi)X + sin(phi)Y by angle theta. Matrix: [[cos(t/2), -ie^(-iphi)sin(t/2)], [-ie^(i*phi)*sin(t/2), cos(t/2)]]
§Arguments
qubit- Target qubit indextheta- Rotation anglephi- Rotation axis angle in XY plane
Sourcepub fn apply_swap(&mut self, q0: usize, q1: usize) -> Result<(), QisError>
pub fn apply_swap(&mut self, q0: usize, q1: usize) -> Result<(), QisError>
Applies SWAP gate to exchange two qubits.
Matrix: [[1,0,0,0], [0,0,1,0], [0,1,0,0], [0,0,0,1]]
§Arguments
q0- First qubit indexq1- Second qubit index
§Errors
Returns QisError::IndexOutOfBounds if either qubit is out of bounds,
or QisError::QubitMismatch if q0 == q1.
§Optimization
Uses memory swap without floating-point operations.
Sourcepub fn apply_cx(
&mut self,
control: usize,
target: usize,
) -> Result<(), QisError>
pub fn apply_cx( &mut self, control: usize, target: usize, ) -> Result<(), QisError>
Applies CNOT (CX) gate: controlled-X operation.
Flips the target qubit when the control qubit is |1⟩. Matrix: [[1,0,0,0], [0,1,0,0], [0,0,0,1], [0,0,1,0]]
§Arguments
control- Control qubit indextarget- Target qubit index
§Errors
Returns QisError::IndexOutOfBounds if either qubit is out of bounds,
or QisError::QubitMismatch if control == target.
Sourcepub fn apply_cy(
&mut self,
control: usize,
target: usize,
) -> Result<(), QisError>
pub fn apply_cy( &mut self, control: usize, target: usize, ) -> Result<(), QisError>
Applies controlled-Y (CY) gate.
Applies Y gate to target when control qubit is |1⟩. Y matrix: [[0, -i], [i, 0]]
§Arguments
control- Control qubit indextarget- Target qubit index
§Errors
Returns QisError::IndexOutOfBounds if either qubit is out of bounds,
or QisError::QubitMismatch if control == target.
Sourcepub fn apply_cz(&mut self, q0: usize, q1: usize) -> Result<(), QisError>
pub fn apply_cz(&mut self, q0: usize, q1: usize) -> Result<(), QisError>
Applies controlled-Z (CZ) gate.
Applies phase flip (-1) to |11⟩ component. Leaves |00⟩, |01⟩, |10⟩ unchanged.
§Arguments
q0- First qubit index (acts as control)q1- Second qubit index (acts as control)
§Errors
Returns QisError::IndexOutOfBounds if either qubit is out of bounds,
or QisError::QubitMismatch if q0 == q1.
Sourcepub fn apply_ccx(
&mut self,
c0: usize,
c1: usize,
target: usize,
) -> Result<(), QisError>
pub fn apply_ccx( &mut self, c0: usize, c1: usize, target: usize, ) -> Result<(), QisError>
Apply Toffoli gate (CCX - Controlled-Controlled-X) Two control qubits and one target qubit. Flips the target if and only if both controls are |1⟩.
§Arguments
c0- First control qubit indexc1- Second control qubit indextarget- Target qubit index
Sourcepub fn apply_rxx(
&mut self,
q0: usize,
q1: usize,
theta: f64,
) -> Result<(), QisError>
pub fn apply_rxx( &mut self, q0: usize, q1: usize, theta: f64, ) -> Result<(), QisError>
Applies RXX gate (Ising XX interaction).
Matrix: exp(-i·θ/2 · X⊗X) = cos(θ/2)I - i·sin(θ/2)·X⊗X
§Arguments
q0- First qubit indexq1- Second qubit indextheta- Interaction angle
Sourcepub fn apply_ryy(
&mut self,
q0: usize,
q1: usize,
theta: f64,
) -> Result<(), QisError>
pub fn apply_ryy( &mut self, q0: usize, q1: usize, theta: f64, ) -> Result<(), QisError>
Applies RYY gate (Ising YY interaction).
Matrix: exp(-i·θ/2 · Y⊗Y) = cos(θ/2)I - i·sin(θ/2)·Y⊗Y
§Arguments
q0- First qubit indexq1- Second qubit indextheta- Interaction angle
Sourcepub fn apply_rzz(
&mut self,
q0: usize,
q1: usize,
theta: f64,
) -> Result<(), QisError>
pub fn apply_rzz( &mut self, q0: usize, q1: usize, theta: f64, ) -> Result<(), QisError>
Applies RZZ gate (Ising ZZ interaction).
Matrix: exp(-i·θ/2 · Z⊗Z) - applies phase based on qubit parity
§Arguments
q0- First qubit indexq1- Second qubit indextheta- Interaction angle
Sourcepub fn apply_rzx(
&mut self,
q0: usize,
q1: usize,
theta: f64,
) -> Result<(), QisError>
pub fn apply_rzx( &mut self, q0: usize, q1: usize, theta: f64, ) -> Result<(), QisError>
Applies RZX gate (Ising ZX interaction).
Matrix: exp(-i·θ/2 · Z⊗X)
§Arguments
q0- First qubit index (Z rotation)q1- Second qubit index (X rotation)theta- Interaction angle
Sourcepub fn apply_crx(
&mut self,
control: usize,
target: usize,
theta: f64,
) -> Result<(), QisError>
pub fn apply_crx( &mut self, control: usize, target: usize, theta: f64, ) -> Result<(), QisError>
Applies controlled-RX gate.
Applies RX(θ) to target when control is |1⟩.
§Arguments
control- Control qubit indextarget- Target qubit indextheta- Rotation angle
Sourcepub fn apply_cry(
&mut self,
control: usize,
target: usize,
theta: f64,
) -> Result<(), QisError>
pub fn apply_cry( &mut self, control: usize, target: usize, theta: f64, ) -> Result<(), QisError>
Applies controlled-RY gate.
Applies RY(θ) to target when control is |1⟩.
§Arguments
control- Control qubit indextarget- Target qubit indextheta- Rotation angle
Sourcepub fn apply_crz(
&mut self,
control: usize,
target: usize,
theta: f64,
) -> Result<(), QisError>
pub fn apply_crz( &mut self, control: usize, target: usize, theta: f64, ) -> Result<(), QisError>
Applies controlled-RZ gate.
Applies RZ(θ) to target when control is |1⟩.
§Arguments
control- Control qubit indextarget- Target qubit indextheta- Rotation angle
Sourcepub fn apply_fsim(
&mut self,
q0: usize,
q1: usize,
theta: f64,
phi: f64,
) -> Result<(), QisError>
pub fn apply_fsim( &mut self, q0: usize, q1: usize, theta: f64, phi: f64, ) -> Result<(), QisError>
Applies Fermionic Simulation (fSim) gate.
Native gate for superconducting qubits. Combines iSWAP and controlled-phase.
Matrix: [[1, 0, 0, 0], [0, c, -i·s, 0], [0, -i·s, c, 0], [0, 0, 0, e^(-iφ)]] where c = cos(θ), s = sin(θ)
§Arguments
q0- First qubit indexq1- Second qubit indextheta- iSWAP anglephi- Controlled-phase angle
Sourcepub fn apply_gphase(&mut self, phi: f64) -> Result<(), QisError>
pub fn apply_gphase(&mut self, phi: f64) -> Result<(), QisError>
Applies global phase.
Multiplies the entire statevector by e^(iφ). Physically undetectable but mathematically relevant for circuit composition.
§Arguments
phi- Phase angle
Sourcepub fn expectation(&self, h: &dyn Observable) -> Result<f64, QisError>
pub fn expectation(&self, h: &dyn Observable) -> Result<f64, QisError>
Computes the expectation value of a Hamiltonian observable.
Calculates ⟨ψ|H|ψ⟩ for the current statevector |ψ⟩ and a given Hamiltonian H. The Hamiltonian is represented as a sum of Pauli strings with coefficients.
§Arguments
h- The Hamiltonian observable.
§Returns
The expectation value as a real number (f64), or a QisError if the
qubit counts do not match.
§Errors
Returns QisError::CircuitError if the observable acts on a different
number of qubits than the statevector.
§Example
use cqlib_core::qis::{Statevector, Hamiltonian};
use cqlib_core::qis::pauli::{Pauli, PauliString};
use num_complex::Complex64;
let mut sv = Statevector::new(1);
sv.apply_x(0);
// Create Hamiltonian H = Z (Pauli-Z observable)
let mut ps = PauliString::new(1);
ps.set_pauli(0, Pauli::Z);
let h = Hamiltonian::from_pauli(ps);
let exp = sv.expectation(&h).unwrap();
// For |1⟩ state, ⟨Z⟩ = -1Sourcepub fn measure(&mut self, qubit: usize) -> Result<bool, QisError>
pub fn measure(&mut self, qubit: usize) -> Result<bool, QisError>
Measures qubit qubit in the Z basis, collapsing the statevector.
Returns false for outcome |0⟩ and true for outcome |1⟩.
After measurement the statevector is normalised in the post-measurement subspace.
This is a destructive operation — clone the statevector first if you need to preserve the pre-measurement state.
Sourcepub fn measure_with_rng(
&mut self,
qubit: usize,
rng: &mut impl Rng,
) -> Result<bool, QisError>
pub fn measure_with_rng( &mut self, qubit: usize, rng: &mut impl Rng, ) -> Result<bool, QisError>
Measures qubit qubit using a caller-provided random number generator.
This is useful for reproducible simulations. For one-off non-deterministic
measurements, use measure.
Sourcepub fn reset(&mut self, qubit: usize) -> Result<(), QisError>
pub fn reset(&mut self, qubit: usize) -> Result<(), QisError>
Resets qubit to the |0⟩ state.
Reset is modeled as a Z-basis measurement followed by an X correction when the measured outcome is |1⟩. This is destructive, matching circuit reset semantics.
Sourcepub fn measure_all(&mut self) -> Outcome
pub fn measure_all(&mut self) -> Outcome
Measures all qubits sequentially, returning a bit-packed Outcome.
Equivalent to calling measure(q) for each qubit q in order 0..num_qubits.
The statevector is fully collapsed after this call.
Use Outcome::is_one(q) to read qubit q’s result.
Sourcepub fn measure_all_with_rng(&mut self, rng: &mut impl Rng) -> Outcome
pub fn measure_all_with_rng(&mut self, rng: &mut impl Rng) -> Outcome
Measures all qubits in storage order using the supplied random stream.
Sourcepub fn sample_shots(&self, shots: usize) -> Vec<Outcome>
pub fn sample_shots(&self, shots: usize) -> Vec<Outcome>
Samples shots independent measurement outcomes in parallel.
Each Rayon worker thread reuses a single pre-allocated clone of the
statevector (via reset_from), avoiding per-shot
heap allocation. Returns a Vec<Outcome> of bit-packed results.
§Example
use cqlib_core::qis::Statevector;
let mut sv = Statevector::new(2);
sv.apply_h(0).unwrap();
sv.apply_cx(0, 1).unwrap(); // |Φ⁺⟩ Bell state
let shots = sv.sample_shots(200);
// All outcomes must be |00⟩ or |11⟩
assert!(shots.iter().all(|v| v.is_one(0) == v.is_one(1)));Sourcepub fn sample_shots_with_seed(
&self,
shots: usize,
seed: Option<u64>,
) -> Vec<Outcome>
pub fn sample_shots_with_seed( &self, shots: usize, seed: Option<u64>, ) -> Vec<Outcome>
Samples without changing this state. An explicit seed assigns a random stream to each shot before parallel execution, independent of scheduling.
Sourcepub fn sample(
&self,
measurement: &Measurement,
shots: usize,
) -> Result<ExecutionResult, QisError>
pub fn sample( &self, measurement: &Measurement, shots: usize, ) -> Result<ExecutionResult, QisError>
Samples the state using a circuit Measurement as the output contract.
measurement.qubits()[i] becomes bit i in each Outcome. The returned
ExecutionResult reuses the device result shape, with counts projected
to only the qubits named by the measurement.
Sourcepub fn sample_with_seed(
&self,
measurement: &Measurement,
shots: usize,
seed: Option<u64>,
) -> Result<ExecutionResult, QisError>
pub fn sample_with_seed( &self, measurement: &Measurement, shots: usize, seed: Option<u64>, ) -> Result<ExecutionResult, QisError>
Projects seeded full-state samples onto the requested measurement.
Sourcepub fn probs(
&self,
measurement: &Measurement,
) -> Result<HashMap<Outcome, f64>, QisError>
pub fn probs( &self, measurement: &Measurement, ) -> Result<HashMap<Outcome, f64>, QisError>
Returns the marginal probability distribution selected by a circuit Measurement.
This method does not execute circuit IR. It treats the Measurement as
a self-contained output contract and aggregates the full statevector
computational-basis probabilities over unmeasured qubits.
Trait Implementations§
Source§impl Clone for Statevector
impl Clone for Statevector
Source§impl Debug for Statevector
impl Debug for Statevector
Source§impl StateVisualizationSource for Statevector
impl StateVisualizationSource for Statevector
Source§fn num_qubits(&self) -> usize
fn num_qubits(&self) -> usize
Source§fn density_matrix_data(&self) -> Result<Vec<Complex64>, VisualizationError>
fn density_matrix_data(&self) -> Result<Vec<Complex64>, VisualizationError>
Auto Trait Implementations§
impl Freeze for Statevector
impl RefUnwindSafe for Statevector
impl Send for Statevector
impl Sync for Statevector
impl Unpin for Statevector
impl UnsafeUnpin for Statevector
impl UnwindSafe for Statevector
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T> DistributionExt for Twhere
T: ?Sized,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.impl<T, U> Imply<T> for U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.