Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The quantum resource estimator in the Microsoft Quantum Development Kit (QDK) produces optimal estimates of the run time and number of qubits required to run a quantum program on a certain type of hardware. For each estimate result, you can get statistics, the instruction set architecture (ISA), magic state factories, and other properties. You can also build and plot custom result properties.
This article shows how to access and analyze results from the resource estimator, and how to customize the results. The code examples are meant to be run in a Jupyter notebook in the order they appear in the article.
For instructions on how to install and use the resource estimator, see How to install and use the Microsoft Quantum resource estimator.
Warning
The resource estimator in the QDK extension for VS Code will be deprecated soon. Use the qdk.qre Python module to perform resource estimation.
Run the resource estimator
To run the resource estimator and work with the estimation results, build an application model, a hardware architecture model, and an error correction model. Then, pass the models to the resource estimator and run an estimate for a given maximum error rate.
Build an application model from a Q# program
For this example, write a Q# program that performs eight parallel 8-bit ripple-carry additions, with a single-qubit rotation that precedes each addition. The rotations introduce T-gate decomposition into the estimation results.
To build an application from the Q# adder program, follow these steps in a Jupyter notebook:
Import the necessary objects.
from qdk import qsharp from qdk.qre.application import QSharpApplicationIn a new cell, write the Q# program.
import Std.Arithmetic.*; import Std.Math.*; import Std.Convert.*; operation EstimateAdder() : Unit { for _ in 1..8 { use a = Qubit[8]; use b = Qubit[8]; for i in 0..7 { Ry(PI() / IntAsDouble(i + 2), a[i]); } RippleCarryCGIncByLE(a, b); } }Build the application model.
from qdk.code import EstimateAdder app = QSharpApplication(EstimateAdder)
Build a hardware architecture model
Build a gate-based architecture model using the default GateBased class. The architecture model has a $10^{-4}$ maximum error rate, 100 ns gate times, and 500 ns measurement times.
from qdk.qre.models import GateBased
arch = GateBased(error_rate=1e-4, gate_time=100, measurement_time=500)
Build an error correction model
For the error correction model, use the default surface QEC code and default round-based factory distillation model. Combine the QEC code and distillation model to create an ISA query that defines the set of architecture ISAs that the resource estimator explores.
from qdk.qre.models import SurfaceCode, RoundBasedFactory
isa_q = SurfaceCode.q() * RoundBasedFactory.q()
Get basic estimation results
To run the resource estimator, pass a maximum error threshold, application model, architecture model, and ISA query to the estimate function. To increase the number of optimal estimation points, also pass an optional trace query that defines the set of application traces that resource estimator explores. For this example, use the PSSPC trace transform and the LatticeSurgery trace transform with a set of slow down factors.
Set a 1% maximum error rate and run the resource estimator. To print the basic results for each Pareto optimal point, use the as_frame method.
from qdk.qre import estimate, PSSPC, LatticeSurgery
results = estimate(
app,
arch,
isa_q,
trace_query=PSSPC.q() * LatticeSurgery.q(slow_down_factor=[1.0, 1.5, 2.0, 3.0, 4.0]),
max_error=0.01
)
print(f"Number of Pareto-optimal results: {len(results)}")
results.as_frame()
The estimate function returns an EstimationTable that contains the following resource estimates for each optimal point:
| Results parameter | Description |
|---|---|
qubits |
The total number of physical qubits required to run the program |
runtime |
The amount of time it takes for the program to finish running |
error |
The overall error rate after error correction |
The basic result from the resource estimator is an optimal set of points for run time and physical qubit requirements within a maximum error threshold. This information helps you choose the best parameters to run your program on real quantum hardware given your constraints on time and physical qubit availability.
Plot the Pareto-optimal results
To view the results as a plot of the number of qubits versus the run time, use the plot method. For example, plot the six Pareto-optimal points with the run time in milliseconds.
results.plot(figsize=(8, 5), runtime_unit="ms")
Get detailed estimation results
The resource estimator produces detailed information about the estimation process and results. To access and display more detailed information about the estimation that you performed, see the following code examples.
Get estimation statistics
The estimation result has a stats attribute that contains the following information about the estimation process:
| Estimation statistic | How to access |
|---|---|
| Number of application traces | stats.num_traces |
| Number of ISAs | stats.num_isas |
| Number of estimation jobs | stats.total_jobs |
| Number of estimates below the error threshold | stats.successful_estimates |
| Number of Pareto-optimal results | stats.pareto_results |
The following code displays this information for the resource estimation that you did:
stats = results.stats
print(f"Traces explored: {stats.num_traces}")
print(f"ISAs explored: {stats.num_isas}")
print(f"Total estimation jobs: {stats.total_jobs}")
print(f"Successful estimates: {stats.successful_estimates}")
print(f"Pareto-optimal results: {stats.pareto_results}")
The total number of possible estimation jobs is the product of the number of traces and the number of ISAs. However, the actual number of estimation jobs is lower because the resource estimator uses a pruning strategy that keeps only the more reasonable combinations.
Get details for individual Pareto-optimal results
The estimation result has an EstimationTableEntry item for each Pareto-optimal point. The table entries contain detailed information about the individual optimal estimates.
To access the estimation table entry for an individual point, use the index for that point. For example, run the following code to get the estimation results for the third optimal point.
entry = results[2]
Basic results
To access the basic estimation results for an individual optimal point, use the qubits, runtime, and error attributes. For example, the following code displays the basic estimation results for the third optimal point.
print(f"Total physical qubits: {entry.qubits}")
print(f"Runtime: {entry.runtime} ns")
print(f"Error: {entry.error:.6f}")
Detailed properties
Each estimation table entry has a properties attribute that contains detailed information on factories and the distribution of qubits. To view all the properties, run the following code:
from qdk.qre import property_name
props = {property_name(k): v for k, v in entry.properties.items()}
for name, value in props.items():
print(f" {name}: {value}")
You can also access each property individually. For example, get only the number of T gates per rotation.
from qdk.qre.property_keys import NUM_TS_PER_ROTATION
print(f"Number of T gates per rotation: {entry.properties.get(NUM_TS_PER_ROTATION, 'N/A')}")
Display qubit partition and factory information
The resource estimator provides tools that let you display more detailed information in the results table. For example, the add_qubit_partition_column method adds columns to the results table that show how the physical qubits are distributed. The add_factory_summary_column shows the number of T factories that each optimal point requires.
results.add_qubit_partition_column()
results.add_factory_summary_column()
results.as_frame()
Analyze the ISA of an estimate
Each optimal estimation result has an instruction source graph that describes how logical instructions are implemented in terms of lower-level operations. To access the instruction source graph for a result, use the source attribute of the EstimationTableEntry for that result.
For example, print the instruction source graph for the third result in the entry variable that you created.
print("Instruction source graph for the third result:\n")
print(entry.source)
The instruction source graph behaves like a Python dictionary where the instruction IDs are the dictionary keys. For example, run the following code to get information about T gate instructions.
from qdk.qre import instruction_name
from qdk.qre.instruction_ids import T
if T in entry.source:
t_node = entry.source[T]
t_inst = t_node.instruction
print("T instruction:")
print(f" ID: {instruction_name(t_inst.id)}")
print(f" Encoding: {'LOGICAL' if t_inst.encoding == 1 else 'PHYSICAL'}")
print(f" Arity: {t_inst.arity}")
print(f" Space: {t_inst.space()} physical qubits")
print(f" Time: {t_inst.time()} ns")
print(f" Error rate: {t_inst.error_rate():.2e}")
if t_node.transform is not None:
print(f" Transform: {t_node.transform}")
Get factory information
Each estimation result entry has a factories attribute, which is a dictionary that contains the following information about the magic-state factories:
- Type of factory
- Number of copies of the factory
- Number of times the factory runs
- Number of magic states that the factory creates
- Error rate after distillation
For example, run the following code to view all the factory information for the third result:
print("Factories in the third result:")
for inst_id, factory in entry.factories.items():
print(f"\n {instruction_name(inst_id)} factory:")
print(f" Copies: {factory.copies}")
print(f" Runs: {factory.runs}")
print(f" States: {factory.states}")
print(f" Error rate: {factory.error_rate:.2e}")
Customize the resource estimator results
You can add custom columns to the EstimationTable output from the resource estimator using the add_property_column and add_columnfunctions.
The add_property_column takes a property key as input and creates a column for that property in the results table. For example, use the NUM_TS_PER_ROTATION property key to add a column for this property.
results.add_property_column(NUM_TS_PER_ROTATION)
results.as_frame()
The add_column function takes a column name and a function as input. The input function gets values from the EstimationTableEntry attributes for each result to populate the new column. For example, create columns for the T gate error rate, logical operation error rate, and number of T states.
from qdk.qre.instruction_ids import LATTICE_SURGERY
results.add_column(
"t_error_rate",
lambda r: r.source[T].instruction.error_rate() if T in r.source else None,
)
results.add_column(
"logical_error_rate",
lambda r: r.source[LATTICE_SURGERY].instruction.error_rate(1) if LATTICE_SURGERY in r.source else None,
)
results.add_column(
"t_states",
lambda r: r.factories[T].states if T in r.factories else 0,
)
results.as_frame()