-
Notifications
You must be signed in to change notification settings - Fork 208
QREv3
qsharp.estimateis deprecated. Useqdk.qrefor all new resource estimation work. This document explains the key differences and shows how to achieve the same results with the new API.
The original qsharp.estimate function treats resource estimation as a
single-shot black box: you hand it a Q# program plus a fixed parameter
dictionary, and it returns one result (or one result per batch item).
The new Quantum Resource Estimator (qdk.qre) rethinks estimation as a
compositional, exploratory process. Instead of a single opaque call, you
assemble an estimation pipeline from modular, swappable pieces (application
models, hardware architectures, error-correction codes, and magic-state
factories), and the estimator systematically explores the combinatorial design
space, returning a Pareto-optimal frontier of results that trade off qubit
count against runtime.
A central design goal is that the estimator itself makes barely any assumptions about the underlying hardware or protocols. In the old estimator, concepts like the QEC scheme, the distillation strategy, and the qubit model were built-in parameters with a fixed structure. In the new estimator, all of these have been moved into flexible, extensible models that are provided as input. Architecture descriptions can be composed from independent layers, for example stacking multiple rounds of distillation factories, choosing separate memory codes, or even estimating without error correction entirely. Because each layer is an independent, composable transform, you can model hardware stacks that the old estimator could not express at all.
| Aspect |
qsharp.estimate (old) |
qdk.qre (new) |
Learn more |
|---|---|---|---|
| Input | Q# expression string + JSON parameter dict | Separate Application, Architecture, ISA query, trace query |
Getting Started |
| Hardware model | Predefined names ("qubit_gate_ns_e4") or flat parameter dict |
GateBased(...) / Majorana(...) objects with typed fields |
Building Your Own Models |
| QEC scheme |
"surface_code" / "floquet_code" or custom dict |
SurfaceCode.q(), TwoDimensionalYokedSurfaceCode.q(), etc., composed as transforms |
Building Your Own Models |
| Magic-state factories | Implicit (part of the QEC scheme) | Explicit and composable: RoundBasedFactory.q(), Litinski19Factory.q(), custom factories |
Building Your Own Models |
| Error budget | Single float or {logical, tStates, rotations} partition |
max_error float; budget allocation is automatic |
Getting Started |
| Constraints |
maxDuration, maxPhysicalQubits, maxTFactories
|
Pareto frontier replaces hard constraints; filter the results table instead | Analysing Results |
| Result | Single JSON blob or batch list |
EstimationTable of Pareto-optimal entries with built-in plotting |
Analysing Results |
| Exploration | Manual batching (EstimatorParams(num_items=N)) |
Automatic: queries enumerate all combinations | Getting Started |
| Supported inputs | Q#, OpenQASM, logical counts | Q#, QIR, Cirq, OpenQASM, logical counts, or custom Application subclass |
Importing Quantum Programs |
pip install qdk[qre]The qdk package re-exports everything through qdk.qre.
Old:
import qsharp
qsharp.init(project_root="./my_project")
result = qsharp.estimate("RunAlgorithm()")
print(result)New:
import qdk
from qdk import qsharp
from qdk.qre import estimate
from qdk.qre.application import QSharpApplication
from qdk.qre.models import GateBased, SurfaceCode, RoundBasedFactory
# Load your Q# project
qsharp.init(project_root="./my_project")
# Wrap the Q# entry point as an Application
app = QSharpApplication(qdk.code.RunAlgorithm)
# Choose a hardware architecture (gate-based, 1e-4 error rate)
arch = GateBased(error_rate=1e-4, gate_time=100, measurement_time=500)
# Run the estimator: explores surface code distances × factory protocols
results = estimate(app, arch, isa_query=SurfaceCode.q() * RoundBasedFactory.q(), max_error=0.01)
# View the Pareto frontier
results.as_frame()Why is this longer? The new API does not provide default architectures or QEC schemes, because resource estimates are only meaningful relative to explicit hardware assumptions. By requiring you to spell out the architecture, error-correction code, and factory protocol, the new API makes every assumption visible and reproducible. In return, it explores the full design space automatically and returns a table of Pareto-optimal results, not a single point. Each row is a configuration where no other configuration is simultaneously better in both qubits and runtime.
Old:
from qsharp.estimator import EstimatorParams, QubitParams
params = EstimatorParams()
params.qubit_params.name = QubitParams.GATE_NS_E4 # gate-based, ns timescale, 1e-4
result = qsharp.estimate("RunAlgorithm()", params)New:
from qdk.qre.models import GateBased
# Equivalent to QubitParams.GATE_NS_E4
arch = GateBased(error_rate=1e-4, gate_time=50, measurement_time=100)
# Or for Majorana-based hardware:
from qdk.qre.models import Majorana
arch = Majorana(error_rate=1e-4, measurement_time=100)Key difference: Instead of selecting a named preset string, you construct a typed architecture object with explicit physical parameters. This makes the hardware assumptions transparent and easy to sweep over.
Old:
params.qec_scheme.name = "surface_code"New:
from qdk.qre.models import SurfaceCode, RoundBasedFactory
# SurfaceCode is an ISA transform; compose it with a factory
isa_query = SurfaceCode.q() * RoundBasedFactory.q()Key difference: QEC codes and magic-state factories are separate, composable transforms. You can mix and match them freely and the estimator will explore all valid combinations automatically.
Old:
from qsharp.estimator import EstimatorParams, QubitParams
params = EstimatorParams(num_items=3)
params.items[0].qubit_params.name = QubitParams.GATE_NS_E3
params.items[1].qubit_params.name = QubitParams.GATE_NS_E4
params.items[2].qubit_params.name = QubitParams.GATE_US_E3
result = qsharp.estimate("RunAlgorithm()", params)New:
from qdk.qre import estimate, plot_estimates
from qdk.qre.models import GateBased, SurfaceCode, RoundBasedFactory
results = []
for error_rate in [1e-3, 1e-4, 1e-5]:
arch = GateBased(error_rate=error_rate, gate_time=100, measurement_time=500)
r = estimate(app, arch, isa_query=SurfaceCode.q() * RoundBasedFactory.q(),
max_error=0.01, name=f"p = {error_rate:.0e}")
results.append(r)
# Overlay multiple runs on a single Pareto plot
plot_estimates(results, runtime_unit="ms")Key difference: Instead of index-based batch items, you simply loop over the parameters you want to sweep. Each
estimatecall already explores the full design space internally (code distances, factory protocols, etc.). Useplot_estimatesto compare runs visually.
Old:
params.error_budget = 0.01
# or fine-grained:
from qsharp.estimator import ErrorBudgetPartition
params.error_budget = ErrorBudgetPartition(logical=0.003, t_states=0.003, rotations=0.004)New:
results = estimate(app, arch, isa_query=..., max_error=0.01)Key difference: The new estimator takes a single
max_errorparameter. The budget allocation across logical errors, T-state distillation, and rotation synthesis is handled automatically as part of the optimization. Unlike the old estimator, which hard-codes exactly three error sources (logical, T-states, rotations), the new estimator derives error contributions from the actual instructions in the trace and ISA. This means it naturally accounts for additional sources of error (e.g., different types of magic states or custom operations) without requiring a manual budget partition.
Old:
params.constraints.max_physical_qubits = 50_000
params.constraints.max_duration = "1s"New:
The new estimator returns the full Pareto frontier, so instead of asking for a single point subject to hard constraints, you filter the results after estimation:
results = estimate(app, arch, isa_query=..., max_error=0.01)
# Filter to results that fit in 50k qubits
df = results.as_frame()
df[df["qubits"] <= 50_000]This approach is more flexible: you see the full trade-off landscape and can apply any combination of filters after the fact.
Old:
result = qsharp.estimate("RunAlgorithm()")
print(result.data()) # raw JSON
print(result.logical_counts) # logical gate counts
result.summary # HTML summary
result.diagram # space-time diagramNew:
results = estimate(app, arch, isa_query=..., max_error=0.01)
# Pareto frontier as a pandas DataFrame
results.as_frame()
# Access individual results
entry = results[0]
print(entry.qubits, entry.runtime, entry.error)
# Add detail columns
results.add_qubit_partition_column() # compute / factory / memory breakdown
results.add_factory_summary_column() # e.g. "20×T"
# Plot the frontier
from qdk.qre import plot_estimates
plot_estimates(results, runtime_unit="ms")The new estimator supports additional input formats through specialized application classes:
from qdk.qre.application import (
QSharpApplication, # Q# programs
QIRApplication, # QIR bitcode files
CirqApplication, # Cirq circuits
OpenQASMApplication, # OpenQASM programs
)You can also subclass Application to implement a fully custom application
model that generates traces programmatically.
| Old concept | New equivalent | Notes |
|---|---|---|
qsharp.estimate(expr, params) |
estimate(app, arch, isa_query, ...) |
Separate application from hardware |
EstimatorQubitParams |
GateBased(...) / Majorana(...)
|
Typed architecture objects |
EstimatorQecScheme |
SurfaceCode, TwoDimensionalYokedSurfaceCode, etc. |
Composable ISA transforms |
DistillationUnitSpecification |
RoundBasedFactory, Litinski19Factory, etc. |
Composable ISA transforms |
ErrorBudgetPartition |
max_error parameter |
Automatic budget allocation |
EstimatorConstraints |
Filter EstimationTable results |
Pareto frontier replaces hard constraints |
EstimatorParams(num_items=N) |
Loop + plot_estimates([...])
|
Each call already explores internally |
EstimatorResult (JSON dict) |
EstimationTable / EstimationTableEntry
|
Structured, extensible results |
result.diagram |
plot_estimates(results) |
Interactive Pareto frontier plot |
result.summary |
results.as_frame() |
Tabular summary with custom columns |
result.data() |
entry.qubits, entry.runtime, entry.error, entry.properties
|
Typed access to result data |
-
Getting started notebook:
samples/qre/0_getting_started.ipynb -
Importing quantum programs:
samples/qre/1_qre_input.ipynb -
Analysing results:
samples/qre/2_analysing_results.ipynb -
Building custom models:
samples/qre/3_building_your_own_models.ipynb
Q# Wiki
Overview
Q# language & features
- Q# Structs
- Q# External Dependencies (Libraries)
- Differences from the previous QDK
- V1.3 features
- Curated list of Q# libraries
- Advanced Topics and Configuration
- QDK Profile Selection
OpenQASM support
VS Code
Python
- Invoking Q# callables from Python
- Working with Jupyter Notebooks
- Qiskit Interop
- Windows on ARM64
- QDK Python Simulators
Circuit diagrams
Azure Quantum
For contributors