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 Microsoft Quantum resource estimator has default application support for several quantum programming frameworks, such as Q# and Cirq. The parameters for these supported application types are predefined by the resource estimator. The resource estimator also lets you build custom applications for when you need finer control over the application parameters.
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.
Custom application model parameters
To build your own applications, use the Application subclass. Custom application models consist of two types of parameters:
| Parameter type | Description | Examples |
|---|---|---|
| Instance parameters | Define the problem that the application solves. These parameters are fixed for a given estimation run. | The bit-size of an adder, the key length of an encryption scheme |
| Trace parameters | Algorithmic hyperparameters that control how the application solves the problem. The resource estimator explores all combinations of these parameters during estimation. | Choice of adder circuit, compute-to-memory ratio, eviction strategy |
Example custom application
As an example custom application, build a configurable adder application with the following parameters:
- Instance parameter: Bit-size
- Trace parameters: Adder implementation, compute fraction, memory-management strategy
With a fixed bit-size, the resource estimator produces application traces for each combination of adder implementation, compute fraction, and memory-management strategy. The output is the Pareto-optimal result that minimizes the trade-offs between number of qubits and total run time for the algorithm.
To build the adder in with the custom parameters in Q#, follow these steps:
In VS Code, open the View menu and select Command Palette.
Enter Create: New Jupyter Notebook.
In the first cell, import
qsharpto use the%%qsharpmagic cell.from qdk import qsharpIn a new cell, run the Q# adder function code. Some of the variables, like
adderandstrategy, are defined in subsequent steps.%%qsharp import Std.Arithmetic.*; import Std.Convert.*; import Std.Math.*; import Std.ResourceEstimation.*; // An adder operation that with custom instance and trace parameters for resource estimation operation Adder(n : Int, adder: (Qubit[], Qubit[]) => Unit, computeFraction: Double, strategy: Int) : Unit { use a = Qubit[n]; use b = Qubit[n]; if computeFraction > 0.0 { // Enables an automatic memory/compute architecture with a fixed number of compute qubits // (computed as a fraction of the total number of qubits). The strategy controls how // compute qubits are deallocated if free compute qubits are needed (either least recently // used or least frequently used). EnableMemoryComputeArchitecture(Ceiling(computeFraction * IntAsDouble(n)), strategy); } // Run the adder adder(a, b); // Reset all qubits (if code is used in simulation) ResetAll(a + b); } // Re-export adders and strategies to use in Python, together with strings to display the results function CGAdder(): ((Qubit[], Qubit[]) => Unit, String) { (RippleCarryCGIncByLE, "CG") } function TTKAdder(): ((Qubit[], Qubit[]) => Unit, String) { (RippleCarryTTKIncByLE, "TTK") } function LRU(): (Int, String) { (LeastRecentlyUsed(), "LRU") } function LFU(): (Int, String) { (LeastFrequentlyUsed(), "LFU") }Define the trace parameters as a
dataclasswithkw_only=Truebecause the resource estimator treats only keyword-only fields as variable trace parameters. Other fields are fixed during estimation.from dataclasses import dataclass, field from typing import Any from qdk import code @dataclass(kw_only=True) class AdderParameters: adder: tuple[Any, str] = field(default = code.CGAdder(), metadata={"domain": [code.CGAdder(), code.TTKAdder()]}) compute_fraction: float = field(default=1.0, metadata={"domain": [0.5, 1.0, 1.5, 2.0]}) strategy: tuple[int, str] = field(default=code.LRU(), metadata={"domain": [code.LRU(), code.LFU()]})You need to specify a
"domain"in each keyword's metadata dictionary because the domain tells the resource estimator what trace values to explore during estimation. You also need to specify a default value from the list of domain values for each parameter. The resource estimator evaluates the following trace parameters for the adder program:Parameter Description Values adderAdder implementation Craig Gidney (CG) ripple-carry adder, Takahashi–Tani–Kunihiro (TTK) ripple-carry adder compute_fractionRatio of qubits allocated to active computation versus memory 0.5, 1.0, 1.5, 2.0 strategyEviction policy when compute capacity is exceeded Least Recently Used (LRU), Least Frequently Used (LFU) To bind the trace parameter types, set
Application[AdderParameters]as a subclass toAdderwith the fixed instance parameters. Define instance parameters as regular (non-keyword) dataclass fields. In this case,bitsizeis the only instance parameter.from qdk.qre import Application from qdk.qre.interop import trace_from_entry_expr from qdk.qre.property_keys import custom_properties # Property keys are integers; we can use the custom_properties function to # define custom properties that do not conflict with existing properties. ADDER, COMPUTE_FRACTION, STRATEGY = custom_properties(3) @dataclass class Adder(Application[AdderParameters]): bitsize: int def __post_init__(self): # Disable parallel trace generation since passing the Q# adder operations is not thread-safe. self.disable_parallel_traces() def get_trace(self, parameters: AdderParameters): # obtain the adder function and its name adder_fn, adder_name = parameters.adder # obtain the memory/compute strategy and its name strategy, strategy_name = parameters.strategy # generate a trace from the Q# entry point with the specified parameters trace = trace_from_entry_expr(code.Adder, self.bitsize, adder_fn, parameters.compute_fraction, strategy) # Set trace properties for later analysis and display trace.set_property(ADDER, adder_name) trace.set_property(COMPUTE_FRACTION, parameters.compute_fraction) trace.set_property(STRATEGY, strategy_name) return traceThe
get_tracebuilds an application trace for every combination of variable trace parameter value, with fixed instance parameter values for each trace. Theset_propertymethod sets custom metadata that you can use to filter estimation results.Build an architecture model and physical instruction set (ISA) model for quantum error correction (QEC) and factory distillation protocol. For this example, use a gate-based hardware model and an ISA model that includes a 2D yoked surface code to account for memory qubits.
from qdk.qre.models import GateBased, RoundBasedFactory, SurfaceCode, TwoDimensionalYokedSurfaceCode # Define the target architecture: gate-based with specified timing (ns) arch = GateBased(gate_time=100, measurement_time=500) # Explore surface code distances × round-based magic state factories x 2D yoked surface code distances isa_query = SurfaceCode.q() * RoundBasedFactory.q() * TwoDimensionalYokedSurfaceCode.q(source=SurfaceCode.q())Run the resource estimator and add custom results columns.
from qdk.qre import estimate results = estimate(Adder(64), arch, isa_query, max_error=0.01, name="Configurable adder") # Add results columns using default resource estimator functions results.add_factory_summary_column() results.add_qubit_partition_column() # Add results columns for custom application parameters results.add_property_column(ADDER, "adder") results.add_property_column(COMPUTE_FRACTION, "compute_fraction") results.add_property_column(STRATEGY, "strategy") results.as_frame()Plot the Pareto frontier estimation results.
results.plot()
For more information on how to access results from the resource estimator, see How to work with results from the quantum resource estimator.