
Don't just simulate the circuit. Plan how it should run.
MENOS is a quantum circuit simulation compiler and runtime. It analyzes each workload and selects a feasible execution plan from estimated cost and resource limits, as a native Qiskit BackendV2 and EstimatorV2.
At a glance
- 1.2.0Version
- Apache-2.0License
- ≥ 3.10Python
- Linux x86-64 · Windows x64Verified on
"""Bell state through the Qiskit BackendV2 adapter."""from qiskit import QuantumCircuitfrom menos.qiskit import MENOSBackendqc = QuantumCircuit(2, 2)qc.h(0)qc.cx(0, 1)qc.measure([0, 1], [0, 1])backend = MENOSBackend()result = backend.run(qc, shots=1000, seed_simulator=7).result()counts = result.get_counts()print(counts)# A Bell pair only ever yields 00 or 11, and every shot is accounted for.assert set(counts) <= {"00", "11"}assert sum(counts.values()) == 1000One fixed algorithm is the wrong default.
Circuit analysis & reduction
Before simulation begins, MENOS analyzes the circuit graph, removes operations outside the causal past via light-cone reduction, and identifies independent qubit subgraphs.
Candidate strategy pricing
Evaluates candidate execution strategies across dense, stabilizer, MPS, Pauli propagation, tensor network, and cut plans under a unified cost model.
Feasible plan selection
Selects the cheapest feasible plan within memory and time budgets. Infeasible candidates are recorded with explicit refusal causes rather than being hidden.
Calibrated CPU & CUDA choices
For dense simulation, the planner selects CUDA GPU execution only when estimated end-to-end seconds—including data transfer latency—is lower than CPU execution.
Strict exactness by default
Every engine reachable from Python is exact. MENOS never silently switches to approximate results when an exact run cannot fit within budget; the job is refused, not degraded.
Safe monitoring & replanning
Time budgets are monitored at safe boundaries. On overrun, execution halts cleanly, records the observed runtime floor, and re-invokes the planner to choose an alternative plan.
Plans first, then simulates
Planner illustration
A circuit enters on the left. The planner prices candidate strategies, such as dense, stabilizer, MPS and factorized, and sends the job down the cheapest feasible route.
Hover to nudge the nodes, or click a route to inspect it. This is an explanatory model, not a live execution run.
Analyze, cost, select, execute, and replan on overrun.
Stage 1 of 6
Circuit Analysis
Extract circuit topology, causal light cone, and independent qubit groups.
MENOS converts the circuit into its intermediate representation (KIR), validates structure, drops operations outside the causal past of the requested output (light-cone reduction), and builds an interaction graph to identify independent qubit components.
Six documented execution strategies.
Candidate strategies
Dense simulation
Holds all 2ⁿ state amplitudes and applies unitary gates directly. Exact, supports arbitrary gates, and is the only strategy that can produce a full statevector.
Documented selection criteria
Chosen when arbitrary universal gates or full statevectors are required. For dense execution, the planner uses a calibrated model to choose between CPU and CUDA GPU based on end-to-end seconds.
Automatic Factorization
Simulates non-interacting qubit groups independently and recombines them exactly.
During the circuit analysis phase, MENOS inspects the two-qubit interaction graph to discover connected components. Qubits that never share multi-qubit entangling operations are factorized into separate independent regions. Each region is planned and simulated on its own engine, and results are recombined with zero loss of exactness.
See what a planner would notice.
Click a cell to place H. Click the same gate again to remove it. Illustrative circuit, not MENOS output.
Structural reading
- Gates
- 4 total · 1 CNOT · 2 non-Clifford
- Clifford-only
- No — T is not a Clifford gate, so the stabilizer engine does not apply to this circuit.
- Independent groups
- {q0, q1} {q2} {q3} — qubits that never share a CNOT can be simulated independently and recombined exactly (automatic factorization).
The real planner weighs cost in work units across all engines and your budgets. These two facts are inputs it can use, not its decision.
Three distinct experiments. Kept strictly separate.
Disclaimer: these benchmarks were run on the developer's own machine. Results depend on hardware, drivers and configuration, and may differ on yours.
Experiment A: MENOS versus PennyLane Lightning GPU
Evaluation across register sizes from 4 to 21 qubits on identical circuits (5 repetitions, 1 warm-up, 1,024 shots). MENOS ran on the host CPU with 0 MB dedicated GPU VRAM, while PennyLane lightning.gpu used an NVIDIA RTX 3050 laptop GPU allocating 338.5 MB VRAM. MENOS performs strongly on Bernstein–Vazirani (up to 40.8x faster) and VQE (up to 11.0x faster), while PennyLane GPU gains advantage on deep 20Q QAOA and QFT circuits.
Bernstein-Vazirani @ 21 qubits
Replay of the measured medians. Bar speed is compressed; the times are real.
Circuit: 72 gates, depth 14, identical on both backends. Click a point on the chart to race another size.
- MENOS (Host CPU, median)
- PennyLane lightning.gpu (RTX 3050)
View data table for Bernstein-Vazirani (5–21Q)
| Qubits | Gates | Depth | MENOS (ms) | PL GPU (ms) | Speed Ratio | Faster |
|---|---|---|---|---|---|---|
| 5Q | 16 | 6 | 0.21 | 4.14 | 19.90x | MENOS |
| 9Q | 30 | 8 | 0.45 | 5.26 | 11.58x | MENOS |
| 13Q | 44 | 10 | 0.40 | 5.75 | 14.31x | MENOS |
| 17Q | 58 | 12 | 0.60 | 7.74 | 12.91x | MENOS |
| 21Q | 72 | 14 | 0.93 | 38.07 | 40.80x | MENOS |
Hardware: Host x86_64 CPU (MENOS) vs NVIDIA GeForce RTX 3050 Laptop GPU (4 GB GDDR6 VRAM, lightning.gpu) (Ubuntu 24.04 LTS (WSL2), NVIDIA Driver 592.82, CUDA 13.1, cuStateVec cu12).
Methodology: Median of 5 repetitions, 1 warm-up run, 1,024 shots per configuration. Matched circuit definitions for both backends.
Scope: Evaluates single-node host execution (MENOS) against entry-level laptop GPU acceleration (RTX 3050). Datacenter GPUs (A100/H100) and GPU-accelerated MENOS were not part of this scope.
Budgets are constraints, not hints. Exactness is guaranteed.
Memory budgets
Every plan has a memory constraint (by default 50% of physical RAM). The planner performs pre-execution feasibility checks and refuses any candidate that would exceed the budget before allocating anything.
Time budgets & replanning
Time budgets are strict constraints. Monitored runs check progress at safe boundaries. On overrun, MENOS halts cleanly, records the observed floor, and replans under the original planner.
Cost-based CPU & CUDA selection
The dense engine supports NVIDIA CUDA. The planner compares CPU and GPU execution using a calibrated model of end-to-end seconds including host-device data transfers and kernel launches. Ties go to the CPU.
Strict exactness by default
Every engine reachable from Python is exact. MENOS never silently switches to approximate methods when an exact run cannot fit within budget; the job is refused rather than degraded.
How the Planner Chooses Between CPU and CUDA
MENOS does not assume GPU execution is always faster. GPU acceleration introduces fixed kernel dispatch latency and PCIe host-to-device and device-to-host transfer costs. For the dense engine, MENOS calibrates these constants on your local machine and calculates end-to-end execution time:
When the CPU is Preferred
- Small circuits (< crossover): Launch and transfer overhead outweighs raw gate throughput.
- Sampling counts from large states: The entire statevector must transfer back across PCIe to host memory.
- Non-dense strategies: Stabilizer, MPS, Pauli propagation, and tensor network engines execute on host CPU.
- Ties in cost model: If estimated times are equal, execution remains on the CPU.
When CUDA GPU is Selected
- Dense simulation above crossover: High qubit counts (typically ≥ 14–16Q) where massive parallel streaming multiprocessors dominate latency.
- Deep universal circuits: High gate density amortizes the fixed kernel launch and memory copy costs.
- Calibrated cost model: The dense engine switches to CUDA only when estimated seconds (transfers included) is lower than CPU.
- Bitwise identical: Results produced on CUDA hash identically to CPU statevectors.
Install from PyPI, then run with Qiskit.
pip install menos or uv add menos. Prebuilt wheels cover Linux x86-64 and Windows x64 (CPU-only); source and issues are on GitHub. It plugs into existing Qiskit workflows through standards-conforming BackendV2 and EstimatorV2 adapters.- Python 3.10 or newer
- Linux x86-64 or Windows x64 (CPU wheels)
- Qiskit, for the BackendV2 / EstimatorV2 adapters
- 1
Install with pip
MENOS is available on PyPI. Install it into your active Python environment.
Install from PyPI with pippip install menos - 2
Or add with uv
In a uv-managed project, add it as a dependency.
Or add it to a project with uvuv add menos - 3
Verify installation
Prints the installed version if the package imported correctly.
Verify installationpython -c "import menos; print(menos.__version__)" - 4
Qiskit BackendV2: Sampling & Counts
Use
MENOSBackendto execute standardQuantumCircuitobjects. The planner selects the optimal feasible engine and samples exact results.- What this checks
- Bell pair yields only
00and11states across all 1,000 shots.
backend_v2_bell.py · verified documentation example"""Bell state through the Qiskit BackendV2 adapter."""from qiskit import QuantumCircuitfrom menos.qiskit import MENOSBackendqc = QuantumCircuit(2, 2)qc.h(0)qc.cx(0, 1)qc.measure([0, 1], [0, 1])backend = MENOSBackend()result = backend.run(qc, shots=1000, seed_simulator=7).result()counts = result.get_counts()print(counts)# A Bell pair only ever yields 00 or 11, and every shot is accounted for.assert set(counts) <= {"00", "11"}assert sum(counts.values()) == 1000 - 5
Qiskit EstimatorV2: Expectation Values
MENOSEstimatorimplements Qiskit'sBaseEstimatorV2. Evaluates Primitive Unified Blocs (PUBs) with Pauli observables (SparsePauliOp) without sampling error.- Zero variance
- Because engines are exact by default, returned standard deviations (
stds) are strictly 0.0.
estimator_v2_pub.py · verified documentation example"""Expectation values through the Qiskit EstimatorV2 adapter."""from qiskit import QuantumCircuitfrom qiskit.quantum_info import SparsePauliOpfrom menos.qiskit import MENOSEstimatorqc = QuantumCircuit(2)qc.h(0)qc.cx(0, 1)# Primitive Unified Bloc: (circuit, observables)observables = [SparsePauliOp("ZZ"), SparsePauliOp("XX"), SparsePauliOp("ZI")]estimator = MENOSEstimator()job = estimator.run([(qc, observables)])pub_result = job.result()[0]print("Expectation values:", pub_result.data.evs)# Bell pair exact expectation values: ZZ=1.0, XX=1.0, ZI=0.0assert list(pub_result.data.evs) == [1.0, 1.0, 0.0]assert float(pub_result.data.stds.max()) == 0.0 # Exact by default
All commands and code snippets are verified against the official Installation, Qiskit Integration, and EstimatorV2 documentation.
The documentation has the rest.
Installation guides, the planner and unified cost model, six execution strategies, CPU and CUDA evaluation, and the complete Python API reference.