Metadata-Version: 2.4
Name: emrg
Version: 0.5.0
Summary: Automatic quantum error mitigation recipe generator for NISQ circuits
Author-email: Fedor Shind <Shindyalov@proton.me>
License-Expression: MIT
Project-URL: Homepage, https://github.com/FedorShind/EMRG
Project-URL: Repository, https://github.com/FedorShind/EMRG
Project-URL: Issues, https://github.com/FedorShind/EMRG/issues
Keywords: quantum-computing,error-mitigation,zne,nisq,qiskit,mitiq
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: qiskit>=1.0
Requires-Dist: mitiq>=0.48
Requires-Dist: click>=8.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: cirq-core>=1.0; extra == "dev"
Requires-Dist: ply; extra == "dev"
Provides-Extra: preview
Requires-Dist: cirq-core>=1.0; extra == "preview"
Requires-Dist: ply; extra == "preview"
Provides-Extra: config
Requires-Dist: PyYAML>=6.0; extra == "config"
Provides-Extra: qasm3
Requires-Dist: qiskit_qasm3_import; extra == "qasm3"
Dynamic: license-file

# EMRG

[![CI](https://github.com/FedorShind/EMRG/actions/workflows/ci.yml/badge.svg)](https://github.com/FedorShind/EMRG/actions/workflows/ci.yml)
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/FedorShind/EMRG/blob/main/docs/tutorials/vqe_h2_mitigation.ipynb)

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

EMRG analyzes a quantum circuit and generates [Mitiq](https://mitiq.readthedocs.io/) 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.0** -- Policy-configurable heuristics + ZNE, PEC, CDR, Composite, and Preview. [Roadmap](#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.0 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 > 20% + depth 10--40 | **CDR** | 8--16 training circuits, linear fit | Clifford substitution + regression outperforms ZNE on non-Clifford-heavy circuits |
| Depth < 20, low multi-qubit gates | ZNE `LinearFactory` | `[1.0, 1.5, 2.0]` | Conservative for shallow circuits |
| Depth 20--50 | ZNE `RichardsonFactory` | `[1.0, 1.5, 2.0, 2.5]` | Better extrapolation for moderate noise |
| Depth > 50 or high noise | ZNE `PolyFactory` (deg 2--3) | `[1.0, 1.5, 2.0, 2.5, 3.0]` | Handles non-linear noise scaling |

## 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](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/FedorShind/EMRG/blob/main/docs/tutorials/vqe_h2_mitigation.ipynb)

### 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
```python
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:
```python
from emrg import generate_recipe, load_policy

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

Policy excerpt:
```yaml
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 and preserves the existing recommendation behavior.

### Example Output
```
# =============================================================
# EMRG v0.5.0 -- 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/               # 477 tests, 96% coverage
├── docs/
│   ├── examples/        # Example circuits (Python + QASM)
│   └── tutorials/       # Jupyter notebooks (VQE, QAOA)
├── benchmarks/          # Automated benchmark suite
└── pyproject.toml       # Package configuration
```

## Benchmarks

Reference benchmark snapshot collected by [`benchmarks/run_benchmark.py`](benchmarks/run_benchmark.py) on EMRG v0.3.0. Rerun the benchmark script 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 |

A 50-qubit, 1125-gate circuit is analyzed and produces a full mitigation recipe in under 6 ms. Circuits with non-Clifford rotations are automatically routed to CDR.

### 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 |

`fold_global` is more reliable at this scale because `fold_gates_at_random` adds stochastic variation to the extrapolation fit. Layerwise folding shows occasional strong results (12.6x on VQE at low noise) but is not consistent enough to be the default. EMRG defaults to `fold_global` and uses layerwise folding conservatively for high-heterogeneity circuits.

### 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 |

CDR recovers near-ideal expectation values on rotation-heavy circuits and consistently outperforms ZNE on VQE circuits at both low and moderate noise. EMRG auto-selects CDR when the non-Clifford gate fraction exceeds 20% and depth is between 10 and 40.

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

## Roadmap

### Phase 1 -- MVP (complete)

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

### Phase 2 -- Multi-technique support (current)

- [x] Probabilistic Error Cancellation (PEC) support
- [x] Multi-technique selection (ZNE vs PEC)
- [x] PEC code generation template
- [x] `--technique` override and `--noise-model` CLI flags
- [x] Layerwise Richardson integration
- [x] `--preview` mode (noisy simulation + before/after comparison)
- [x] Expanded tutorials (VQE, QAOA)
- [x] 477 tests, 96% coverage, zero lint warnings
- [x] Clifford Data Regression (CDR) support
- [x] 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
- [x] 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](https://github.com/FedorShind/EMRG).

## License

[MIT](LICENSE)

## Acknowledgments

Built on [Mitiq](https://mitiq.readthedocs.io/) by [Unitary Foundation](https://unitary.foundation/).
