QiliSim Backend
The QiliSim backend is the default CPU simulator developed by Qilimanjaro and written in C++.
It implements every primitive functional natively, supports a noise model on all execution paths,
and is included with the core qilisdk installation — no extra dependency or hardware is required.
Installation
QiliSim is bundled with the core qilisdk installation, so no extra package is required.
Quick start
import numpy as np
from qilisdk.digital import Circuit, H, CNOT
from qilisdk.backends import QiliSim
from qilisdk.functionals import DigitalPropagation
from qilisdk.readout import Readout
# Build a simple circuit
circuit = Circuit(5)
circuit.add(H(0))
circuit.add(CNOT(0, 1))
# Create DigitalPropagation functional
functional = DigitalPropagation(circuit)
# Execute with the QiliSim backend
backend = QiliSim()
result = backend.execute(functional, Readout().with_sampling(nshots=500))
print(result.get_samples())
Functional support
QiliSim natively supports all primitive functionals through dedicated C++ routines:
Functional |
Support |
Notes |
|---|---|---|
✅ |
Statevector-based simulation, configurable via |
|
✅ |
Multiple integration schemes, configurable via |
|
✅ |
Native C++ implementation; supports both Circuit and Schedule reservoir steps. |
|
✅ |
Reuses the primitive functional handlers above for each optimization step. |
Configuration
QiliSim is configured at construction time through three orthogonal sections, all defined in
qilisdk.backends.backend_config:
AnalogMethod— chooses the analog time-evolution scheme and its hyperparameters.DigitalMethod— chooses the digital simulation strategy and its hyperparameters.ExecutionConfig— global execution controls (threads, random seed, Monte Carlo trajectories, measurement-collapse behaviour).
from qilisdk.backends import (
AnalogMethod,
DigitalMethod,
ExecutionConfig,
MonteCarloConfig,
QiliSim,
)
backend = QiliSim(
analog_simulation_method=AnalogMethod.arnoldi(dim=16, num_substeps=2),
digital_simulation_method=DigitalMethod.statevector(
matrix_free=True,
max_cache_size=2_000,
combine_single_qubit_gates=True,
),
execution_config=ExecutionConfig(
num_threads=4,
seed=42,
monte_carlo=MonteCarloConfig(trajectories=200),
measurement_collapse=False,
),
)
If any argument is omitted, QiliSim falls back to:
AnalogMethod.integrator()(matrix-free RK4),a default
ExecutionConfig(all cores, random seed, Monte Carlo disabled).
Analog simulation methods
Use the classmethods of AnalogMethod to choose how the
schedule is integrated:
Constructor |
Underlying scheme |
When to use it |
|---|---|---|
RK4 |
Default. Fixed-step Runge-Kutta 4; matrix-free is faster for sparse Hamiltonians. |
|
Dormand-Prince RK4/5 |
Adaptive step size; |
|
Krylov / Arnoldi |
Can offer decent scaling for large sparse Hamiltonians; tune |
|
Matrix exponential |
Reference scheme for small systems; cost grows quickly with qubit count. |
Example, using the adaptive integrator for a stiffer schedule:
from qilisdk.backends import AnalogMethod, QiliSim
backend = QiliSim(analog_simulation_method=AnalogMethod.adaptive_integrator(tol=1e-2))
Digital simulation methods
Digital execution is currently always state-vector based; the
DigitalMethod configuration tunes its performance
characteristics rather than choosing a different algorithm:
Option |
Meaning |
|---|---|
|
Apply gates directly to the statevector instead of building dense matrices. Default |
|
Maximum number of precomputed gate matrices cached between executions. |
|
Merge adjacent single-qubit gates into a single operation before propagating. Disabled if gate-specific noise is used. |
|
Renormalize the statevector after each gate to mitigate numerical drift, at a runtime cost. |
from qilisdk.backends import DigitalMethod, QiliSim
backend = QiliSim(
digital_simulation_method=DigitalMethod.statevector(
matrix_free=False,
normalize_after_each_gate=True,
),
)
Execution and Monte Carlo
ExecutionConfig controls threading, randomness, and
optional Monte Carlo trajectory sampling for open-system simulations.
num_threads=0(default) lets the simulator use every physical core.seed=None(default) draws a fresh random seed at construction time; pass an integer for reproducibility.monte_carlo=MonteCarloConfig(trajectories=N)enables stochastic trajectory sampling for noise models that admit a Monte Carlo unraveling; leave itNonefor deterministic master-equation evolution.measurement_collapsecontrols whether measurements collapse the statevector in place (relevant for mid-circuit measurement and reservoir computing); defaults toFalse.
from qilisdk.backends import ExecutionConfig, MonteCarloConfig, QiliSim
backend = QiliSim(
execution_config=ExecutionConfig(
num_threads=8,
seed=1234,
monte_carlo=MonteCarloConfig(trajectories=500),
measurement_collapse=True,
),
)
Noise model support
Any NoiseModel accepted by the SDK can be passed directly to the constructor;
QiliSim applies it inside the C++ solver, so digital, analog, and reservoir runs all see the same
noise channels:
from qilisdk.backends import QiliSim
from qilisdk.noise import NoiseModel, Depolarizing
nm = NoiseModel()
nm.add(Depolarizing(probability=1e-3))
backend = QiliSim(noise_model=nm)