qitesse is a high-throughput CPU backend for repeated evaluation of parameterized quantum circuits.
qitesse is built upon qitesse-sim, the high-performance CPU-based state-vector execution engine for quantum circuits, fully built in Rust.
This PyPI module provides a Python interface designed for hybrid quantum algorithms, repeated circuit evaluation, backend integration, and low-overhead CPU execution from Python.
- Rust-based CPU statevector simulator with a Python API
- One-off circuit execution through
GateandCircuit - Compiled parameterized circuits through
CircuitSpec,Parameter, andCompiledCircuit - Reusable zero-copy parameter buffers through
ParamBufferandParamBatchBuffer - Expectation-value workflows for Pauli observables and Hamiltonians
- Batch expectation execution for parameter sweeps and optimizer loops
- Gradient APIs for compiled circuits via parameter-shift evaluation
- Reusable
ExecutionContextbuffers for repeated scalar execution - Full statevector output for both one-off and compiled execution paths
- Mid-circuit
measure,reset, andbarrieroperations - Custom unitary operations with
Gate.unitary(...) - Controlled custom unitaries with
Gate.controlled_unitary(...) - Common single-, two-, and multi-qubit gates
- Read the Docs documentation with autogenerated API reference pages
qitesse requires Python 3.8+. Install it via pip:
pip install qitesseOr install from source:
git clone https://github.com/OsamaMIT/qitesse.git
pip install maturin
maturin develop --releaseTo run examples:
python examples/h_example.py
python examples/qft._example.py
python examples/custom_unitary.py
The documentation is now set up for Read the Docs with automatic API generation.
- Entry point: docs/index.rst
- Current features: docs/current_features.rst
- Compiled execution guide: docs/guides/compiled_execution.rst
- Generated API reference root: docs/api/index.rst
- Read the Docs config: .readthedocs.yaml
To add a new public class to the API docs, add it once in docs/api/index.rst. Sphinx will generate the class page and include its methods and attributes automatically.
qitesse currently has two main usage modes:
- General-purpose simulation with
GateandCircuitfor one-off execution. - Compiled execution with
CircuitSpecandCompiledCircuitfor repeated parameterized workloads.
The compiled path currently supports:
- reusable zero-copy parameter buffers
- scalar expectation evaluation
- batched expectation evaluation
- scalar gradients
- batched gradients
- reusable execution contexts
- statevector inspection when needed
The simulator path currently supports:
- standard single-qubit gates
- controlled and multi-qubit gates
- custom unitaries
- measurement, reset, and barrier operations
import numpy as np
import qitesse
spec = qitesse.CircuitSpec(2)
theta = spec.param("theta")
spec.ry(0, theta)
spec.cx(0, 1)
compiled = spec.compile()
observable = qitesse.Observable.pauli_z(1)
value = compiled.expectation(np.array([0.4], dtype=np.float32), observable)
gradient = compiled.gradient(np.array([0.4], dtype=np.float32), observable)
value_again, grad_again = compiled.value_and_gradient(
np.array([0.4], dtype=np.float32),
observable,
)
state = compiled.statevector(np.array([0.4], dtype=np.float32))
params_batch = np.array([[0.1], [0.2], [0.3]], dtype=np.float32)
values = compiled.batch_expectation(params_batch, observable)
grads = compiled.batch_gradient(params_batch, observable)
context = compiled.execution_context()
value_again = context.expectation(compiled, np.array([0.5], dtype=np.float32), observable)
grad_again = context.gradient(compiled, np.array([0.5], dtype=np.float32), observable)This execution path is intended for repeated evaluation of the same circuit structure with different parameter values.
The compiled execution path is the primary integration surface for higher-level libraries.
The intended backend pattern is:
- Translate a framework circuit into
CircuitSpec - Compile once per circuit structure
- Keep parameters in contiguous
numpy.float32arrays - Call
expectation,batch_expectation,gradient, orvalue_and_gradient
For sequential scalar calls, reuse compiled.execution_context() to keep internal buffers alive.
For sweeps, minibatches, or optimizer batches, prefer batch_expectation(...) and batch_gradient(...) instead of looping in Python.
Single-qubit gates:
ixyzhssdgttdgrxryrzp/phaseu
Two-qubit gates:
cnot/cxcyczchswapiswapcrxcrycrzcp/cphasecu
Three-qubit and larger:
ccx/toffolicswap/fredkinmcxmczmcp/mcphasecontrolled_unitary
Circuit operations:
measureresetbarrier
Custom unitaries:
import numpy as np
import qitesse
hadamard = np.array([[1, 1], [1, -1]], dtype=np.complex64) / np.sqrt(2)
circuit = qitesse.Circuit([
qitesse.Gate.unitary([0], hadamard),
qitesse.Gate.controlled_unitary([0], [1], hadamard),
])
state = circuit.run(2)Use run_with_measurements(num_qubits) if the circuit contains measurement gates and you want the observed bit values back.
- Additional simulation backends
Contributions are welcome! To contribute:
- Fork the repository
- Create a new branch (feature-branch)
- Commit your changes and open a pull request
This project is licensed under the MIT License. See the LICENSE file for details.