Skip to main content

Automatic quantum error mitigation recipe generator for NISQ circuits

Project description

EMRG

CI Open In Colab

Error Mitigation Recipe Generator -- Automatic quantum error mitigation for NISQ circuits.

EMRG analyzes a quantum circuit and generates Mitiq error mitigation code with the right imports, parameters, and rationale. It selects between ZNE, PEC, CDR, and composite ZNE-over-PEC recipes so you only need to connect the generated executor adapter to your simulator or hardware backend.

v0.5.1 -- Benchmark-calibrated default policy + reproducible benchmark/search harness. Roadmap below.


Why EMRG?

No single mitigation technique fits every NISQ circuit. ZNE needs useful noise-scaling behavior, PEC needs a noise model and manageable sampling overhead, CDR needs enough non-Clifford structure to train against, and composite ZNE-over-PEC is only worth its cost on moderate-depth PEC-eligible circuits. EMRG automates that choice: give it a circuit, get back runnable mitigation code with rationale for every parameter choice.

How It Works

Quantum Circuit --> [Analyze] --> [Technique Selection] --> [Code Generator] --> Mitigated Code
                                     Composite / PEC / CDR / ZNE
  1. Parse & Validate -- Load a Qiskit QuantumCircuit or QASM file.
  2. Extract Features -- Depth, gate counts, noise factor, non-Clifford fraction, PEC overhead, layer heterogeneity.
  3. Select Technique -- Use priority rules: composite for eligible moderate-depth circuits, PEC for shallow low-overhead noise-model cases, CDR for non-Clifford-heavy circuits, otherwise ZNE.
  4. Generate Code -- Runnable Python with Mitiq imports, configuration, and inline rationale.

Heuristic Rules (v0.5.1 default policy)

Circuit Profile Technique Configuration Rationale
Depth 15--30 + moderate noise + noise model + combined overhead <= 1000 Composite (ZNE over PEC) ZNE factory over PEC executor PEC corrects each noise-scaled circuit before ZNE extrapolates residual bias
Depth <= 30 + noise model + overhead < 1000 PEC Depolarizing representations Unbiased error cancellation when overhead is manageable
Non-Clifford fraction > 30% + depth 12--40 CDR 6--14 training circuits, linear fit Clifford substitution + regression when non-Clifford content is high enough to justify CDR
Depth < 18, low multi-qubit gates ZNE LinearFactory [1.0, 1.5, 2.0, 2.5, 3.0] + fold_global More extrapolation points for shallow circuits, at bounded overhead
Depth 18--55 ZNE LinearFactory [1.0, 1.5, 2.0, 2.5] + fold_gates_at_random Calibration favored lower-order extrapolation with gate-level folding on the internal corpus
Depth > 55 or high noise ZNE PolyFactory(order=2) [1.0, 1.25, 1.5, 2.0] + fold_global Captures non-linear noise while avoiding unnecessary scale factors

Quick Start

Installation

pip install emrg

For preview mode (noisy simulation comparison):

pip install emrg[preview]

For YAML policy files:

pip install emrg[config]

Or from source:

git clone https://github.com/FedorShind/EMRG.git
cd EMRG
pip install -e ".[dev,preview,config,qasm3]"

Or try it without installing: Open In Colab

CLI Usage

# Generate mitigation recipe from a QASM file
emrg generate circuit.qasm

# With verbose explanation
emrg generate circuit.qasm --explain

# Save to file
emrg generate circuit.qasm -o mitigated.py

# Create and validate a policy file
emrg policy init emrg-policy.json
emrg policy validate emrg-policy.json

# Generate with a policy file
emrg generate circuit.qasm --policy emrg-policy.json

# Force a specific technique
emrg generate circuit.qasm --technique pec --noise-model
emrg generate circuit.qasm --technique composite --noise-model
emrg generate circuit.qasm --technique cdr

# Forced techniques bypass automatic viability checks. EMRG still returns the
# requested recipe, but generated output includes warnings when the circuit
# falls outside the automatic selection criteria.

# Preview: simulate and compare before/after mitigation
emrg generate circuit.qasm --preview

# Preview with custom noise level and observable
emrg generate circuit.qasm --preview --noise-level 0.03 --observable ZZ

# Analyze circuit features
emrg analyze circuit.qasm

# JSON output (for scripting)
emrg analyze circuit.qasm --json

Python API

from qiskit import QuantumCircuit
from emrg import generate_recipe, load_policy

# Create a circuit
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])

# Generate mitigation recipe (one-liner)
result = generate_recipe(qc)
print(result)             # Ready-to-run Python script
print(result.rationale)   # Why these parameters were chosen
print(result.features)    # Circuit analysis details

# With PEC (requires noise model availability)
result = generate_recipe(qc, noise_model_available=True)

# With a policy file
policy = load_policy("emrg-policy.json")
result = generate_recipe(qc, policy=policy)

# Force CDR (requires cirq: pip install emrg[preview])
result = generate_recipe(qc, technique="cdr")

# Force composite ZNE-over-PEC (requires noise model availability)
result = generate_recipe(qc, technique="composite", noise_model_available=True)

# With preview simulation
result = generate_recipe(qc, preview=True, noise_level=0.01)
print(result.preview)     # Simulation comparison results

Policy Files

Policies tune EMRG's existing rule-based heuristics. They can enable or disable techniques, adjust thresholds and overhead budgets, and choose supported Mitiq factory/scaling settings. They do not execute Python, import code, or define arbitrary logic.

JSON policies work with the base install. YAML policies use yaml.safe_load() and require pip install emrg[config].

emrg policy init emrg-policy.json
emrg generate circuit.qasm --policy emrg-policy.json

Python:

from emrg import generate_recipe, load_policy

policy = load_policy("emrg-policy.json")
result = generate_recipe(qc, policy=policy)

Policy excerpt:

version: 1
name: shallow-two-point-zne

techniques:
  zne:
    shallow:
      factory: LinearFactory
      scale_factors: [1.0, 2.0]
      scaling_method: fold_global

Policy files are complete, strict documents. Use emrg policy init to create the full schema, then edit the fields you want to tune.

Without --policy or policy=..., EMRG uses the built-in default policy. Use benchmarks/policies/default-v050.json to reproduce the v0.5.0 calibration baseline.

Example Output

# =============================================================
# EMRG v0.5.1 -- Error Mitigation Recipe
# Circuit: 2 qubits, depth 3, 1 multi-qubit gates
# Noise estimate: 0.011 (low)
# =============================================================
#
# Recommendation: LinearFactory + fold_global
#
# =============================================================

from mitiq.zne import execute_with_zne
from mitiq.zne.inference import LinearFactory
from mitiq.zne.scaling import fold_global

factory = LinearFactory(scale_factors=[1.0, 1.5, 2.0])

def execute(circuit):
    """Execute a circuit and return an expectation value (float)."""
    # Connect this adapter to your simulator or hardware backend.
    raise NotImplementedError("Configure execute() for your backend.")

mitigated_value = execute_with_zne(
    circuit,
    execute,
    factory=factory,
    scale_noise=fold_global,
)

print(f"Mitigated expectation value: {mitigated_value}")

Preview Mode

--preview runs a noisy simulation, applies the recommended mitigation, and displays a before/after comparison. This validates the recipe before spending real hardware shots.

emrg generate circuit.qasm --preview
┌─────────────────────────────────────────────────┐
│  EMRG Preview -- Simulation Comparison         │
├─────────────────────────────────────────────────┤
│  Circuit:    2 qubits, depth 3                 │
│  Noise:      depolarizing p=0.01               │
│  Observable: <Z> on qubit 0                    │
│  Technique:  ZNE                               │
├─────────────────────────────────────────────────┤
│  Ideal:      -1.0000                           │
│  Noisy:      -0.9761  (error: 0.0239)          │
│  Mitigated:  -1.0003  (error: 0.0003)          │
│                                                │
│  Error reduction: 77.5x                        │
└─────────────────────────────────────────────────┘

Uses Cirq's DensityMatrixSimulator with per-gate depolarizing noise. Circuits above 10 qubits are skipped (density matrix cost scales as O(4^n)). PEC preview uses 200 samples; composite preview uses 200 PEC samples inside each ZNE scale evaluation; CDR uses the recipe's training circuit count. These stochastic previews are approximate and vary between runs.

Requires pip install emrg[preview].

Project Structure

EMRG/
├── src/emrg/
│   ├── __init__.py      # Public API and generate_recipe()
│   ├── _version.py      # Single source of truth for version
│   ├── analyzer.py      # Circuit feature extraction
│   ├── heuristics.py    # Rule-based decision engine
│   ├── policy.py        # JSON/YAML policy model and validation
│   ├── codegen.py       # Template-based code generation
│   ├── preview.py       # Simulation preview engine
│   ├── cli.py           # Click CLI interface
│   └── py.typed         # PEP 561 type marker
├── tests/               # 486 tests, coverage checked in CI/local validation
├── docs/
│   ├── examples/        # Example circuits (Python + QASM)
│   └── tutorials/       # Jupyter notebooks (VQE, QAOA)
├── benchmarks/          # Automated benchmark suite
└── pyproject.toml       # Package configuration

Benchmarks

EMRG includes a reproducible benchmark harness for v0.5.1 calibration work. It writes machine-readable JSON under benchmarks/results/ and scores runs separately, so default-policy changes can be compared against a fixed baseline instead of tuned by anecdote.

.\.venv\Scripts\python.exe benchmarks\run_benchmark.py --quick --output benchmarks\results\quick.json
.\.venv\Scripts\python.exe benchmarks\score_results.py benchmarks\results\quick.json

.\.venv\Scripts\python.exe benchmarks\run_benchmark.py --policy benchmarks\policies\default-v050.json --output benchmarks\results\baseline-v050.json
.\.venv\Scripts\python.exe benchmarks\score_results.py benchmarks\results\baseline-v050.json

Local v0.5.1 calibration snapshot, using the fixed internal corpus with --seed 1234 --repeats 5 --include-speed --include-quality on Python 3.12.10, Windows 11, Qiskit 2.3.0, Mitiq 0.48.1, NumPy 1.26.4:

Policy Score Quality passed/failed/skipped Median error reduction Median overhead
default-v050.json 0.7872 10 / 0 / 8 2.357x 6.500
default-v051.json 1.8455 10 / 0 / 8 4.779x 5.000

These are benchmark-harness results, not hardware-performance claims. Rerun the commands on your target environment before using the numbers for release notes or comparisons.

See benchmarks/README.md for the benchmark philosophy, external QASM guidance, and candidate-policy comparison workflow.

The numeric tables below are a historical reference snapshot collected by benchmarks/run_benchmark.py on EMRG v0.3.0. Rerun the current benchmark harness before using these numbers for new release claims.

Environment: Python 3.12, Windows 11 | Qiskit 2.3.0, Mitiq 0.48.1

Tool Performance

generate_recipe() uses pure Qiskit introspection (no simulation), so it completes in sub-millisecond time even for large circuits. Median of 100 runs:

Circuit Qubits Depth Gates Multi-Q Het Technique / Config Time Memory
Bell state 2 3 2 1 0.00 LinearFactory + fold_global 0.09 ms 9.4 KB
Bell state (PEC) 2 3 2 1 0.00 PEC 0.09 ms 9.4 KB
GHZ-5 5 6 5 4 0.50 LinearFactory + fold_global 0.14 ms 15.2 KB
GHZ-10 10 11 10 9 0.50 LinearFactory + fold_global 0.24 ms 24.9 KB
Random 10q, 3 layers 10 7 45 15 0.83 LinearFactory + fold_global 0.39 ms 21.2 KB
VQE 10q, 4 layers 10 20 76 36 1.50 CDR (16 training) 0.64 ms 43.8 KB
Hetero 4q, 8 layers 4 17 42 10 1.00 CDR (12 training) 0.40 ms 34.6 KB
T-gate 4q 4 7 12 3 0.50 LinearFactory + fold_global 0.15 ms 16.7 KB
Rz-rot 4q, 4 layers 4 14 28 12 0.50 CDR (12 training) 0.29 ms 29.3 KB
Random 20q, 6 layers 20 13 180 60 0.91 CDR (16 training) 1.06 ms 49.0 KB
Random 30q, 10 layers 30 21 450 150 0.94 CDR (16 training) 2.41 ms 116.3 KB
Random 50q, 15 layers 50 31 1125 375 0.96 CDR (16 training) 5.81 ms 282.0 KB

In this historical snapshot, a 50-qubit, 1125-gate circuit was analyzed and produced a full mitigation recipe in under 6 ms. Several non-Clifford rotation circuits were routed to CDR under the older default policy.

ZNE Fidelity

End-to-end ZNE on Cirq DensityMatrixSimulator with per-gate depolarizing noise, comparing ⟨Z⟩ on qubit 0:

Circuit Qubits Depth Noise Technique / Config Ideal Noisy Mitigated Error Reduction
X-flip, 2q 2 3 p=0.01 LinearFactory + fold_global -1.0000 -0.9761 -1.0003 77x
X-flip, 3q 3 4 p=0.01 LinearFactory + fold_global -1.0000 -0.9761 -1.0003 77x
X-flip, 2q 2 3 p=0.05 LinearFactory + fold_global -1.0000 -0.8836 -0.9906 12x
X-flip, 3q 3 4 p=0.05 LinearFactory + fold_global -1.0000 -0.8836 -0.9906 12x
VQE 4q, 2 layers 4 8 p=0.01 LinearFactory + fold_global 0.0850 0.0775 0.0794 1.4x
VQE 4q, 4 layers 4 14 p=0.01 LinearFactory + fold_global -0.1915 -0.1766 -0.1850 2.3x
VQE 4q, 2 layers 4 8 p=0.05 LinearFactory + fold_global 0.0850 0.0523 0.0586 1.2x

PEC vs ZNE: Head-to-Head

Same circuits, same noise, both techniques. PEC uses 1000 samples for benchmark accuracy; its results have inherent variance from stochastic sampling. ZNE is deterministic.

Single-qubit observable ⟨Z⟩:

Circuit Noise ZNE Error ZNE Reduction PEC Error PEC Reduction Better
VQE 4q, 2 layers p=0.01 0.0055 1.4x 0.0007 10.4x PEC
VQE 4q, 2 layers p=0.03 0.0162 1.3x 0.0138 1.5x PEC
VQE 4q, 2 layers p=0.05 0.0264 1.2x 0.0176 1.9x PEC
X-flip, 3q p=0.03 0.0024 28.9x 0.0245 2.9x ZNE

Multi-qubit observable ⟨ZZ⟩:

Circuit Noise ZNE Error ZNE Reduction PEC Error PEC Reduction Better
VQE 4q, 2 layers p=0.01 0.0021 5.7x 0.0064 1.9x ZNE
VQE 4q, 2 layers p=0.03 0.0102 3.4x 0.0173 2.0x ZNE
VQE 4q, 2 layers p=0.05 0.0216 2.5x 0.0147 3.6x PEC

ZNE excels on structured circuits where noise scales predictably with folding (X-flip: 28.9x). PEC excels on irregular circuits at higher noise, where ZNE's extrapolation assumptions break down. On ⟨ZZ⟩, PEC overtakes ZNE as noise increases: 3.6x vs 2.5x at p=0.05. EMRG recommends PEC for shallow, noisy circuits with an available noise model, and ZNE otherwise.

Layerwise Folding

fold_gates_at_random targets the noisiest gates in circuits with uneven layer structure, instead of folding uniformly. Benchmarks show mixed results; the heuristic thresholds are being refined.

Circuit Qubits Depth Het Noise Global Layerwise Winner
VQE 10q, 3 reps 10 13 2.50 p=0.01 0.9x 12.6x layerwise
VQE 10q, 3 reps 10 13 2.50 p=0.03 1.1x 1.1x --
QAOA 10q 10 14 2.50 p=0.01 4.2x 0.2x global
QAOA 10q 10 14 2.50 p=0.03 5.9x 0.7x global
Extreme 10q 10 13 2.50 p=0.01 0.5x 0.4x --
Extreme 10q 10 13 2.50 p=0.03 0.5x 0.1x global

This historical snapshot showed mixed results for random gate folding. v0.5.1 uses policy-calibrated ZNE profiles, so the table should not be read as a current universal rule for fold_global or fold_gates_at_random.

CDR vs ZNE

CDR replaces non-Clifford gates with Clifford substitutes to create classically simulable training circuits, then fits a regression model to correct the noisy result. Compared to ZNE on circuits with non-Clifford gates:

Circuit Noise ZNE Error ZNE Reduction CDR Error CDR Reduction Better
Rz-rot 4q p=0.01 0.0253 2.8x ~0.0000 >1000x CDR
Rz-rot 4q p=0.03 0.0866 2.3x ~0.0000 >1000x CDR
VQE 4q, 2 layers p=0.01 0.0055 1.4x 0.0036 2.1x CDR
VQE 4q, 2 layers p=0.03 0.0162 1.3x 0.0108 1.9x CDR

This historical snapshot favored CDR on the listed rotation-heavy and VQE circuits. In v0.5.1, EMRG auto-selects CDR when the non-Clifford gate fraction exceeds 30% and depth is between 12 and 40; otherwise the policy may select ZNE if the benchmark-calibrated profile is a better fit.

Reproduce

pip install -e ".[dev]" qiskit-aer
python benchmarks/run_benchmark.py

Roadmap

Phase 1 -- MVP (complete)

  • Project structure and packaging
  • Circuit analyzer (feature extraction)
  • Heuristic engine (ZNE: Linear + Richardson + Poly)
  • Code generator (template-based)
  • CLI with generate and analyze commands
  • Public Python API (generate_recipe())
  • Example circuits (Python + QASM) and documentation

Phase 2 -- Multi-technique support (current)

  • Probabilistic Error Cancellation (PEC) support
  • Multi-technique selection (ZNE vs PEC)
  • PEC code generation template
  • --technique override and --noise-model CLI flags
  • Layerwise Richardson integration
  • --preview mode (noisy simulation + before/after comparison)
  • Expanded tutorials (VQE, QAOA)
  • 486 tests, coverage checked in CI/local validation, zero lint warnings
  • Clifford Data Regression (CDR) support
  • Composite recipes -- combine ZNE + PEC for circuits that benefit from both
  • Real hardware benchmarks (IBM Quantum devices)

Phase 3 -- Multi-framework support

  • Cirq, PennyLane, and Amazon Braket input support
  • Noise model import from Qiskit Aer / real device calibration data
  • Configurable heuristics via YAML/JSON
  • Jupyter widget for interactive recipe exploration
  • Web/Colab interface

Phase 4 -- Data-driven selection

  • Train on benchmark data to predict optimal mitigation strategy
  • Circuit similarity search against known-good configurations
  • Auto-tuning via internal --preview iterations before output
  • Cost-aware optimization within user-specified shot budgets

Phase 5 -- Ecosystem integration

  • Qiskit Runtime integration
  • Mitiq Calibration API integration
  • VS Code extension for inline circuit analysis
  • CI/CD integration for quantum testing pipelines

Tech Stack

  • Python 3.11+
  • Qiskit >= 1.0 -- circuit representation and introspection
  • Mitiq >= 0.48 -- error mitigation primitives
  • Click >= 8.0 -- CLI framework
  • Cirq >= 1.0 -- simulation backend (optional, for preview and CDR)

Contributing

Open an issue or PR on GitHub.

License

MIT

Acknowledgments

Built on Mitiq by Unitary Foundation.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

emrg-0.5.1.tar.gz (77.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

emrg-0.5.1-py3-none-any.whl (46.0 kB view details)

Uploaded Python 3

File details

Details for the file emrg-0.5.1.tar.gz.

File metadata

  • Download URL: emrg-0.5.1.tar.gz
  • Upload date:
  • Size: 77.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for emrg-0.5.1.tar.gz
Algorithm Hash digest
SHA256 4443e29e267fb3596cc07f643c6ed5fb4db6b54ab2cba900f8a33d0beed60c72
MD5 e11b36fa0cdd1a29c8f5128842a4f6f2
BLAKE2b-256 e20b40503bdf5e499e8274e1dace5e6a05e8b483f681f509c78bed82a0332415

See more details on using hashes here.

Provenance

The following attestation bundles were made for emrg-0.5.1.tar.gz:

Publisher: publish.yml on FedorShind/EMRG

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file emrg-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: emrg-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 46.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for emrg-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 46afe2e7f2781f233c227fe4fb1fffe071d436d65293209c59dc51c520a73bc6
MD5 214bcdb155ca731f569a2b60889331a3
BLAKE2b-256 1cb3b588e0195938d2c075451e218387ed6127833883d7305c348ceb952cced0

See more details on using hashes here.

Provenance

The following attestation bundles were made for emrg-0.5.1-py3-none-any.whl:

Publisher: publish.yml on FedorShind/EMRG

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page