Verschiedene Möglichkeiten zum Ausführen der Ressourcenstimator
In diesem Artikel erfahren Sie, wie Sie mit dem Azure Quantum Resource Estimator arbeiten. Die Resource Estimator ist Teil des Quantum Development Kit und steht auf verschiedenen Plattformen und IDEs zur Verfügung.
Wenn Sie ein Q#-Programm ausführen, ist der Resource Estimator in Visual Studio Code mit der Quantum Development Kit-Erweiterung verfügbar. Sie haben kein Azure-Abonnement, um den Ressourcen-Estimator in Visual Studio Code zu verwenden.
Wenn Sie ein Qiskit- oder QIR-Programm ausführen, steht der Resource Estimator im Azure-Portal zur Verfügung, und Sie benötigen ein Azure-Abonnement, um es zu verwenden.
In der folgenden Tabelle sind die verschiedenen Methoden zum Ausführen der Ressourcenschätzung aufgeführt.
Benutzerszenario | Plattform | Tutorial |
---|---|---|
Schätzen der Ressourcen eines Q#-Programms | Visual Studio Code | Wählen Sie "Q#" im VS-Code oben auf der Seite aus. |
Schätzen der Ressourcen eines Q#-Programms (erweitert) | Jupyter-Notizbuch in Visual Studio Code | Wählen Sie "Q#" im Jupyter-Notizbuch oben auf der Seite aus. |
Schätzen der Ressourcen eines Qiskit-Programms | Azure-Portal | Wählen Sie Qiskit in Azure-Portal oben auf der Seite aus. |
Schätzen der Ressourcen eines QIR-Programms | Azure-Portal | Qir übermitteln |
Verwenden von FCIDUMP-Dateien als Argumentparameter (erweitert) | Visual Studio Code | Übermitteln eines Quantenchemieproblems |
Voraussetzungen für VS-Code
- Die neueste Version von Visual Studio Code oder öffnen Sie VS Code im Web.
- Die neueste Version der Azure Quantum Development Kit-Erweiterung. Installationsdetails finden Sie unter Installieren des QDK unter VS Code.
Tipp
Sie müssen nicht über ein Azure-Konto verfügen, um den lokalen Ressourcen-Estimator auszuführen.
Erstellen einer neuen Q#-Datei
- Öffnen Sie Visual Studio Code und wählen Sie Datei > Neue Textdatei aus, um eine neue Datei zu erstellen.
- Speichern Sie die Datei unter dem Namen
ShorRE.qs
. Diese Datei enthält den Q#-Code für Ihr Programm.
Erstellen des Quantenalgorithmus
Kopieren Sie den folgenden Code in die Datei ShorRE.qs
:
import Std.Arrays.*;
import Std.Canon.*;
import Std.Convert.*;
import Std.Diagnostics.*;
import Std.Math.*;
import Std.Measurement.*;
import Microsoft.Quantum.Unstable.Arithmetic.*;
import Std.ResourceEstimation.*;
operation Main() : Unit {
let bitsize = 31;
// When choosing parameters for `EstimateFrequency`, make sure that
// generator and modules are not co-prime
let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize);
}
// In this sample we concentrate on costing the `EstimateFrequency`
// operation, which is the core quantum operation in Shors algorithm, and
// we omit the classical pre- and post-processing.
/// # Summary
/// Estimates the frequency of a generator
/// in the residue ring Z mod `modulus`.
///
/// # Input
/// ## generator
/// The unsigned integer multiplicative order (period)
/// of which is being estimated. Must be co-prime to `modulus`.
/// ## modulus
/// The modulus which defines the residue ring Z mod `modulus`
/// in which the multiplicative order of `generator` is being estimated.
/// ## bitsize
/// Number of bits needed to represent the modulus.
///
/// # Output
/// The numerator k of dyadic fraction k/2^bitsPrecision
/// approximating s/r.
operation EstimateFrequency(
generator : Int,
modulus : Int,
bitsize : Int
)
: Int {
mutable frequencyEstimate = 0;
let bitsPrecision = 2 * bitsize + 1;
// Allocate qubits for the superposition of eigenstates of
// the oracle that is used in period finding.
use eigenstateRegister = Qubit[bitsize];
// Initialize eigenstateRegister to 1, which is a superposition of
// the eigenstates we are estimating the phases of.
// We first interpret the register as encoding an unsigned integer
// in little endian encoding.
ApplyXorInPlace(1, eigenstateRegister);
let oracle = ApplyOrderFindingOracle(generator, modulus, _, _);
// Use phase estimation with a semiclassical Fourier transform to
// estimate the frequency.
use c = Qubit();
for idx in bitsPrecision - 1..-1..0 {
within {
H(c);
} apply {
// `BeginEstimateCaching` and `EndEstimateCaching` are the operations
// exposed by Azure Quantum Resource Estimator. These will instruct
// resource counting such that the if-block will be executed
// only once, its resources will be cached, and appended in
// every other iteration.
if BeginEstimateCaching("ControlledOracle", SingleVariant()) {
Controlled oracle([c], (1 <<< idx, eigenstateRegister));
EndEstimateCaching();
}
R1Frac(frequencyEstimate, bitsPrecision - 1 - idx, c);
}
if MResetZ(c) == One {
set frequencyEstimate += 1 <<< (bitsPrecision - 1 - idx);
}
}
// Return all the qubits used for oracles eigenstate back to 0 state
// using Microsoft.Quantum.Intrinsic.ResetAll.
ResetAll(eigenstateRegister);
return frequencyEstimate;
}
/// # Summary
/// Interprets `target` as encoding unsigned little-endian integer k
/// and performs transformation |k⟩ ↦ |gᵖ⋅k mod N ⟩ where
/// p is `power`, g is `generator` and N is `modulus`.
///
/// # Input
/// ## generator
/// The unsigned integer multiplicative order ( period )
/// of which is being estimated. Must be co-prime to `modulus`.
/// ## modulus
/// The modulus which defines the residue ring Z mod `modulus`
/// in which the multiplicative order of `generator` is being estimated.
/// ## power
/// Power of `generator` by which `target` is multiplied.
/// ## target
/// Register interpreted as little endian encoded which is multiplied by
/// given power of the generator. The multiplication is performed modulo
/// `modulus`.
internal operation ApplyOrderFindingOracle(
generator : Int, modulus : Int, power : Int, target : Qubit[]
)
: Unit
is Adj + Ctl {
// The oracle we use for order finding implements |x⟩ ↦ |x⋅a mod N⟩. We
// also use `ExpModI` to compute a by which x must be multiplied. Also
// note that we interpret target as unsigned integer in little-endian
// encoding.
ModularMultiplyByConstant(modulus,
ExpModI(generator, power, modulus),
target);
}
/// # Summary
/// Performs modular in-place multiplication by a classical constant.
///
/// # Description
/// Given the classical constants `c` and `modulus`, and an input
/// quantum register |𝑦⟩, this operation
/// computes `(c*x) % modulus` into |𝑦⟩.
///
/// # Input
/// ## modulus
/// Modulus to use for modular multiplication
/// ## c
/// Constant by which to multiply |𝑦⟩
/// ## y
/// Quantum register of target
internal operation ModularMultiplyByConstant(modulus : Int, c : Int, y : Qubit[])
: Unit is Adj + Ctl {
use qs = Qubit[Length(y)];
for (idx, yq) in Enumerated(y) {
let shiftedC = (c <<< idx) % modulus;
Controlled ModularAddConstant([yq], (modulus, shiftedC, qs));
}
ApplyToEachCA(SWAP, Zipped(y, qs));
let invC = InverseModI(c, modulus);
for (idx, yq) in Enumerated(y) {
let shiftedC = (invC <<< idx) % modulus;
Controlled ModularAddConstant([yq], (modulus, modulus - shiftedC, qs));
}
}
/// # Summary
/// Performs modular in-place addition of a classical constant into a
/// quantum register.
///
/// # Description
/// Given the classical constants `c` and `modulus`, and an input
/// quantum register |𝑦⟩, this operation
/// computes `(x+c) % modulus` into |𝑦⟩.
///
/// # Input
/// ## modulus
/// Modulus to use for modular addition
/// ## c
/// Constant to add to |𝑦⟩
/// ## y
/// Quantum register of target
internal operation ModularAddConstant(modulus : Int, c : Int, y : Qubit[])
: Unit is Adj + Ctl {
body (...) {
Controlled ModularAddConstant([], (modulus, c, y));
}
controlled (ctrls, ...) {
// We apply a custom strategy to control this operation instead of
// letting the compiler create the controlled variant for us in which
// the `Controlled` functor would be distributed over each operation
// in the body.
//
// Here we can use some scratch memory to save ensure that at most one
// control qubit is used for costly operations such as `AddConstant`
// and `CompareGreaterThenOrEqualConstant`.
if Length(ctrls) >= 2 {
use control = Qubit();
within {
Controlled X(ctrls, control);
} apply {
Controlled ModularAddConstant([control], (modulus, c, y));
}
} else {
use carry = Qubit();
Controlled AddConstant(ctrls, (c, y + [carry]));
Controlled Adjoint AddConstant(ctrls, (modulus, y + [carry]));
Controlled AddConstant([carry], (modulus, y));
Controlled CompareGreaterThanOrEqualConstant(ctrls, (c, y, carry));
}
}
}
/// # Summary
/// Performs in-place addition of a constant into a quantum register.
///
/// # Description
/// Given a non-empty quantum register |𝑦⟩ of length 𝑛+1 and a positive
/// constant 𝑐 < 2ⁿ, computes |𝑦 + c⟩ into |𝑦⟩.
///
/// # Input
/// ## c
/// Constant number to add to |𝑦⟩.
/// ## y
/// Quantum register of second summand and target; must not be empty.
internal operation AddConstant(c : Int, y : Qubit[]) : Unit is Adj + Ctl {
// We are using this version instead of the library version that is based
// on Fourier angles to show an advantage of sparse simulation in this sample.
let n = Length(y);
Fact(n > 0, "Bit width must be at least 1");
Fact(c >= 0, "constant must not be negative");
Fact(c < 2 ^ n, $"constant must be smaller than {2L ^ n}");
if c != 0 {
// If c has j trailing zeroes than the j least significant bits
// of y won't be affected by the addition and can therefore be
// ignored by applying the addition only to the other qubits and
// shifting c accordingly.
let j = NTrailingZeroes(c);
use x = Qubit[n - j];
within {
ApplyXorInPlace(c >>> j, x);
} apply {
IncByLE(x, y[j...]);
}
}
}
/// # Summary
/// Performs greater-than-or-equals comparison to a constant.
///
/// # Description
/// Toggles output qubit `target` if and only if input register `x`
/// is greater than or equal to `c`.
///
/// # Input
/// ## c
/// Constant value for comparison.
/// ## x
/// Quantum register to compare against.
/// ## target
/// Target qubit for comparison result.
///
/// # Reference
/// This construction is described in [Lemma 3, arXiv:2201.10200]
internal operation CompareGreaterThanOrEqualConstant(c : Int, x : Qubit[], target : Qubit)
: Unit is Adj+Ctl {
let bitWidth = Length(x);
if c == 0 {
X(target);
} elif c >= 2 ^ bitWidth {
// do nothing
} elif c == 2 ^ (bitWidth - 1) {
ApplyLowTCNOT(Tail(x), target);
} else {
// normalize constant
let l = NTrailingZeroes(c);
let cNormalized = c >>> l;
let xNormalized = x[l...];
let bitWidthNormalized = Length(xNormalized);
let gates = Rest(IntAsBoolArray(cNormalized, bitWidthNormalized));
use qs = Qubit[bitWidthNormalized - 1];
let cs1 = [Head(xNormalized)] + Most(qs);
let cs2 = Rest(xNormalized);
within {
for i in IndexRange(gates) {
(gates[i] ? ApplyAnd | ApplyOr)(cs1[i], cs2[i], qs[i]);
}
} apply {
ApplyLowTCNOT(Tail(qs), target);
}
}
}
/// # Summary
/// Internal operation used in the implementation of GreaterThanOrEqualConstant.
internal operation ApplyOr(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
within {
ApplyToEachA(X, [control1, control2]);
} apply {
ApplyAnd(control1, control2, target);
X(target);
}
}
internal operation ApplyAnd(control1 : Qubit, control2 : Qubit, target : Qubit)
: Unit is Adj {
body (...) {
CCNOT(control1, control2, target);
}
adjoint (...) {
H(target);
if (M(target) == One) {
X(target);
CZ(control1, control2);
}
}
}
/// # Summary
/// Returns the number of trailing zeroes of a number
///
/// ## Example
/// ```qsharp
/// let zeroes = NTrailingZeroes(21); // = NTrailingZeroes(0b1101) = 0
/// let zeroes = NTrailingZeroes(20); // = NTrailingZeroes(0b1100) = 2
/// ```
internal function NTrailingZeroes(number : Int) : Int {
mutable nZeroes = 0;
mutable copy = number;
while (copy % 2 == 0) {
set nZeroes += 1;
set copy /= 2;
}
return nZeroes;
}
/// # Summary
/// An implementation for `CNOT` that when controlled using a single control uses
/// a helper qubit and uses `ApplyAnd` to reduce the T-count to 4 instead of 7.
internal operation ApplyLowTCNOT(a : Qubit, b : Qubit) : Unit is Adj+Ctl {
body (...) {
CNOT(a, b);
}
adjoint self;
controlled (ctls, ...) {
// In this application this operation is used in a way that
// it is controlled by at most one qubit.
Fact(Length(ctls) <= 1, "At most one control line allowed");
if IsEmpty(ctls) {
CNOT(a, b);
} else {
use q = Qubit();
within {
ApplyAnd(Head(ctls), a, q);
} apply {
CNOT(q, b);
}
}
}
controlled adjoint self;
}
Ausführen von Resource Estimator
Der Ressourcen-Estimator bietet sechs vordefinierte Qubit-Parameter, von denen vier gatebasierte Anweisungssätze und zwei über einen Majorana-Anweisungssatz verfügen. Es bietet auch zwei Quantenfehlerkorrekturcodes und surface_code
floquet_code
.
In diesem Beispiel führen Sie Resource Estimator mithilfe des qubit_gate_us_e3
-Quantenparameters und des Codes surface_code
zur Korrektur von Quantenfehlern aus.
Wählen Sie "Ansicht " - Befehlspalette" aus, und geben Sie "Ressource" ein, die die Option "Q#: Ressourcenschätzungen berechnen" anzeigen soll.> Sie können auch in der Liste der Befehle, die direkt vor dem
Main
Vorgang angezeigt werden, auf "Schätzen" klicken. Wählen Sie diese Option aus, um das Fenster „Resource Estimator“ zu öffnen.Sie können einen oder mehrere Typen für Qubitparameter und Codes zur Fehlerkorrektur auswählen, um die Ressourcen zu schätzen. Wählen Sie in diesem Beispiel qubit_gate_us_e3 aus, und klicken Sie auf OK.
Geben Sie das Fehlerbudget an, oder übernehmen Sie den Standardwert 0,001. Behalten Sie in diesem Beispiel den Standardwert bei, und drücken Sie die EINGABETASTE.
Drücken Sie die EINGABETASTE , um den Standardergebnisnamen basierend auf dem Dateinamen zu akzeptieren, in diesem Fall ShorRE.
Ergebnisse anzeigen
Der Ressourcen-Estimator stellt mehrere Schätzungen für denselben Algorithmus bereit, wobei jeweils Kompromisse zwischen der Anzahl der Qubits und der Laufzeit angezeigt werden. Das Verständnis des Kompromisses zwischen Laufzeit und Systemmaßstab ist einer der wichtigeren Aspekte der Ressourcenschätzung.
Das Ergebnis der Ressourcenschätzung wird im Fenster Q#-Schätzung angezeigt.
Auf der Registerkarte Ergebnisse wird eine Zusammenfassung der Ressourcenschätzung angezeigt. Klicken Sie auf das Symbol neben der ersten Zeile, um die Spalten auszuwählen, die Sie anzeigen möchten. Sie können unter Ausführungsname, Schätzungstyp, Qubittyp, qec-Schema, Fehlerbudget, logische Qubits, logische Tiefe, Codeabstand, T-Zustände, T-Fabriken, T-Factorybruch, Laufzeit, rQOPS und physische Qubits auswählen.
In der Spalte "Schätzungstyp " der Ergebnistabelle können Sie die Anzahl der optimalen Kombinationen von {Anzahl von Qubits, Runtime} für Ihren Algorithmus sehen. Diese Kombinationen werden im Raumzeitdiagramm angezeigt.
Das Raumzeitdiagramm zeigt die Kompromisse zwischen der Anzahl der physischen Qubits und der Laufzeit des Algorithmus. In diesem Fall findet der Ressourcen-Estimator 13 verschiedene optimale Kombinationen aus vielen tausend möglichen Kombinationen. Sie können auf jede {Anzahl von Qubits, Laufzeit}-Punkt zeigen, um die Details der Ressourcenschätzung zu diesem Zeitpunkt anzuzeigen.
Weitere Informationen finden Sie unter Raumzeitdiagramm.
Hinweis
Sie müssen auf einen Punkt des Raumzeitdiagramms klicken, bei dem es sich um ein {Anzahl von Qubits, Laufzeit}-Paar handelt, um das Raumdiagramm und die Details der Ressourcenschätzung anzuzeigen, die diesem Punkt entspricht.
Das Raumdiagramm zeigt die Verteilung physischer Qubits, die für den Algorithmus und die T-Fabriken verwendet werden, die einem {Anzahl von Qubits, Runtime}-Paar entsprechen. Wenn Sie z. B. den äußerst linken Punkt im Raumzeitdiagramm auswählen, sind die zum Ausführen des Algorithmus erforderlichen physischen Qubits 427726, 196686 von denen Algorithmus-Qubits und 231040 T-Factory-Qubits sind.
Schließlich zeigt die Registerkarte "Ressourcenschätzungen " die vollständige Liste der Ausgabedaten für den Ressourcen-Estimator an, der einem {Anzahl von Qubits, Laufzeit} -Paar entspricht. Sie können die Kostendetails einsehen, indem Sie die Gruppen, die mehr Informationen enthalten, zuklappen. Wählen Sie z. B. den äußerst linken Punkt im Raumzeitdiagramm aus, und reduzieren Sie die Gruppe " Logische Qubit-Parameter ".
Logischer Qubitparameter Wert QEC-Schema surface_code Codeabstand 21 Physische Qubits 882 Logische Zykluszeit 13 Millisekunden Logische Qubit-Fehlerrate 3.00E-13 Crossing Prefactor 0,03 Schwellenwert für die Fehlerkorrektur 0.01 Formel für die logische Zykluszeit (4 × twoQubitGateTime
× 2 ×oneQubitMeasurementTime
) ×codeDistance
Formel für physische Qubits 2 × codeDistance
*codeDistance
Tipp
Klicken Sie auf Detailzeilen anzeigen, um die Beschreibung der einzelnen Ausgaben der Berichtdaten anzuzeigen.
Weitere Informationen finden Sie in den vollständigen Berichtsdaten des Ressourcenstimators.
Ändern der target Parameter
Sie können die Kosten für dasselbe Q#-Programm mit einem anderen Qubit-Typ, Fehlerkorrekturcode und Fehlerbudget schätzen. Öffnen Sie das Fenster "Ressource schätzen", indem Sie "Ansicht -> Befehlspalette" auswählen und "Eingabe" eingebenQ#: Calculate Resource Estimates
.
Wählen Sie eine beliebige andere Konfiguration aus, z. B. den Parameter Majorana-basiertes Qubit, qubit_maj_ns_e6
. Übernehmen Sie den Standardfehlerbudgetwert, oder geben Sie einen neuen ein, und drücken Sie die EINGABETASTE. Der Ressourcenschätzungs-Schätzwert wird mit den neuen target Parametern erneut ausgeführt.
Weitere Informationen finden Sie unter Target Parameter für die Ressourcenschätzung.
Ausführen mehrerer Konfigurationen von Parametern
Der Azure Quantum Resource Estimator kann mehrere Konfigurationen von target Parametern ausführen und die Ergebnisse der Ressourcenschätzung vergleichen.
Wählen Sie "Ansicht"> aus– Befehlspalette, oder drücken Sie STRG+UMSCHALT+P, und geben Sie ein
Q#: Calculate Resource Estimates
.Wählen Sie qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4 + floquet_code aus, und qubit_maj_ns_e6 + floquet_code, und klicken Sie auf OK.
Übernehmen Sie den Standardfehlerbudgetwert 0,001, und drücken Sie die EINGABETASTE.
Drücken Sie die EINGABETASTE , um die Eingabedatei zu akzeptieren, in diesem Fall ShorRE.qs.
Bei mehreren Konfigurationen von Parametern werden die Ergebnisse in verschiedenen Zeilen auf der Registerkarte "Ergebnisse " angezeigt.
Das Raumzeitdiagramm zeigt die Ergebnisse für alle Konfigurationen von Parametern. In der ersten Spalte der Ergebnistabelle wird die Legende für jede Konfiguration von Parametern angezeigt. Sie können auf jeden Punkt zeigen, um die Details der Ressourcenschätzung zu diesem Zeitpunkt anzuzeigen.
Klicken Sie auf eine {Anzahl von Qubits, Laufzeit}-Punkt des Raumzeitdiagramms, um das entsprechende Raumdiagramm und Berichtsdaten anzuzeigen.
Voraussetzungen für das Jupyter-Notizbuch im VS-Code
Eine Python-Umgebung mit installiertem Python und Pip.
Die neueste Version von Visual Studio Code oder öffnen Sie VS Code im Web.
VS Code mit installierten Azure Quantum Development Kit-, Python- und Jupyter-Erweiterungen .
Die neuesten Azure Quantum
qsharp
undqsharp-widgets
Pakete.python -m pip install --upgrade qsharp qsharp-widgets
Tipp
Sie müssen nicht über ein Azure-Konto verfügen, um den lokalen Ressourcen-Estimator auszuführen.
Erstellen des Quantenalgorithmus
Wählen Sie in VS Code die Optionen Ansicht > Befehlspalette und dann Erstellen aus: Verwenden von Jupyter Notebook.
In der oberen rechten Ecke erkennt und zeigt VS Code die Version von Python und die virtuelle Python-Umgebung an, die für das Notizbuch ausgewählt wurde. Wenn Sie über mehrere Python-Umgebungen verfügen, müssen Sie möglicherweise einen Kernel mit der Kernelauswahl oben rechts auswählen. Wenn keine Umgebung erkannt wurde, finden Sie Informationen zum Einrichten unter Jupyter-Notizbücher in VS Code .
Importieren Sie das
qsharp
-Paket in der ersten Zelle des Notebooks.import qsharp
Fügen Sie eine neue Zelle hinzu und kopieren Sie den folgenden Code.
%%qsharp import Std.Arrays.*; import Std.Canon.*; import Std.Convert.*; import Std.Diagnostics.*; import Std.Math.*; import Std.Measurement.*; import Microsoft.Quantum.Unstable.Arithmetic.*; import Std.ResourceEstimation.*; operation RunProgram() : Unit { let bitsize = 31; // When choosing parameters for `EstimateFrequency`, make sure that // generator and modules are not co-prime let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize); } // In this sample we concentrate on costing the `EstimateFrequency` // operation, which is the core quantum operation in Shors algorithm, and // we omit the classical pre- and post-processing. /// # Summary /// Estimates the frequency of a generator /// in the residue ring Z mod `modulus`. /// /// # Input /// ## generator /// The unsigned integer multiplicative order (period) /// of which is being estimated. Must be co-prime to `modulus`. /// ## modulus /// The modulus which defines the residue ring Z mod `modulus` /// in which the multiplicative order of `generator` is being estimated. /// ## bitsize /// Number of bits needed to represent the modulus. /// /// # Output /// The numerator k of dyadic fraction k/2^bitsPrecision /// approximating s/r. operation EstimateFrequency( generator : Int, modulus : Int, bitsize : Int ) : Int { mutable frequencyEstimate = 0; let bitsPrecision = 2 * bitsize + 1; // Allocate qubits for the superposition of eigenstates of // the oracle that is used in period finding. use eigenstateRegister = Qubit[bitsize]; // Initialize eigenstateRegister to 1, which is a superposition of // the eigenstates we are estimating the phases of. // We first interpret the register as encoding an unsigned integer // in little endian encoding. ApplyXorInPlace(1, eigenstateRegister); let oracle = ApplyOrderFindingOracle(generator, modulus, _, _); // Use phase estimation with a semiclassical Fourier transform to // estimate the frequency. use c = Qubit(); for idx in bitsPrecision - 1..-1..0 { within { H(c); } apply { // `BeginEstimateCaching` and `EndEstimateCaching` are the operations // exposed by Azure Quantum Resource Estimator. These will instruct // resource counting such that the if-block will be executed // only once, its resources will be cached, and appended in // every other iteration. if BeginEstimateCaching("ControlledOracle", SingleVariant()) { Controlled oracle([c], (1 <<< idx, eigenstateRegister)); EndEstimateCaching(); } R1Frac(frequencyEstimate, bitsPrecision - 1 - idx, c); } if MResetZ(c) == One { set frequencyEstimate += 1 <<< (bitsPrecision - 1 - idx); } } // Return all the qubits used for oracle eigenstate back to 0 state // using Microsoft.Quantum.Intrinsic.ResetAll. ResetAll(eigenstateRegister); return frequencyEstimate; } /// # Summary /// Interprets `target` as encoding unsigned little-endian integer k /// and performs transformation |k⟩ ↦ |gᵖ⋅k mod N ⟩ where /// p is `power`, g is `generator` and N is `modulus`. /// /// # Input /// ## generator /// The unsigned integer multiplicative order ( period ) /// of which is being estimated. Must be co-prime to `modulus`. /// ## modulus /// The modulus which defines the residue ring Z mod `modulus` /// in which the multiplicative order of `generator` is being estimated. /// ## power /// Power of `generator` by which `target` is multiplied. /// ## target /// Register interpreted as little endian encoded which is multiplied by /// given power of the generator. The multiplication is performed modulo /// `modulus`. internal operation ApplyOrderFindingOracle( generator : Int, modulus : Int, power : Int, target : Qubit[] ) : Unit is Adj + Ctl { // The oracle we use for order finding implements |x⟩ ↦ |x⋅a mod N⟩. We // also use `ExpModI` to compute a by which x must be multiplied. Also // note that we interpret target as unsigned integer in little-endian // encoding. ModularMultiplyByConstant(modulus, ExpModI(generator, power, modulus), target); } /// # Summary /// Performs modular in-place multiplication by a classical constant. /// /// # Description /// Given the classical constants `c` and `modulus`, and an input /// quantum register |𝑦⟩, this operation /// computes `(c*x) % modulus` into |𝑦⟩. /// /// # Input /// ## modulus /// Modulus to use for modular multiplication /// ## c /// Constant by which to multiply |𝑦⟩ /// ## y /// Quantum register of target internal operation ModularMultiplyByConstant(modulus : Int, c : Int, y : Qubit[]) : Unit is Adj + Ctl { use qs = Qubit[Length(y)]; for (idx, yq) in Enumerated(y) { let shiftedC = (c <<< idx) % modulus; Controlled ModularAddConstant([yq], (modulus, shiftedC, qs)); } ApplyToEachCA(SWAP, Zipped(y, qs)); let invC = InverseModI(c, modulus); for (idx, yq) in Enumerated(y) { let shiftedC = (invC <<< idx) % modulus; Controlled ModularAddConstant([yq], (modulus, modulus - shiftedC, qs)); } } /// # Summary /// Performs modular in-place addition of a classical constant into a /// quantum register. /// /// # Description /// Given the classical constants `c` and `modulus`, and an input /// quantum register |𝑦⟩, this operation /// computes `(x+c) % modulus` into |𝑦⟩. /// /// # Input /// ## modulus /// Modulus to use for modular addition /// ## c /// Constant to add to |𝑦⟩ /// ## y /// Quantum register of target internal operation ModularAddConstant(modulus : Int, c : Int, y : Qubit[]) : Unit is Adj + Ctl { body (...) { Controlled ModularAddConstant([], (modulus, c, y)); } controlled (ctrls, ...) { // We apply a custom strategy to control this operation instead of // letting the compiler create the controlled variant for us in which // the `Controlled` functor would be distributed over each operation // in the body. // // Here we can use some scratch memory to save ensure that at most one // control qubit is used for costly operations such as `AddConstant` // and `CompareGreaterThenOrEqualConstant`. if Length(ctrls) >= 2 { use control = Qubit(); within { Controlled X(ctrls, control); } apply { Controlled ModularAddConstant([control], (modulus, c, y)); } } else { use carry = Qubit(); Controlled AddConstant(ctrls, (c, y + [carry])); Controlled Adjoint AddConstant(ctrls, (modulus, y + [carry])); Controlled AddConstant([carry], (modulus, y)); Controlled CompareGreaterThanOrEqualConstant(ctrls, (c, y, carry)); } } } /// # Summary /// Performs in-place addition of a constant into a quantum register. /// /// # Description /// Given a non-empty quantum register |𝑦⟩ of length 𝑛+1 and a positive /// constant 𝑐 < 2ⁿ, computes |𝑦 + c⟩ into |𝑦⟩. /// /// # Input /// ## c /// Constant number to add to |𝑦⟩. /// ## y /// Quantum register of second summand and target; must not be empty. internal operation AddConstant(c : Int, y : Qubit[]) : Unit is Adj + Ctl { // We are using this version instead of the library version that is based // on Fourier angles to show an advantage of sparse simulation in this sample. let n = Length(y); Fact(n > 0, "Bit width must be at least 1"); Fact(c >= 0, "constant must not be negative"); Fact(c < 2 ^ n, $"constant must be smaller than {2L ^ n}"); if c != 0 { // If c has j trailing zeroes than the j least significant bits // of y will not be affected by the addition and can therefore be // ignored by applying the addition only to the other qubits and // shifting c accordingly. let j = NTrailingZeroes(c); use x = Qubit[n - j]; within { ApplyXorInPlace(c >>> j, x); } apply { IncByLE(x, y[j...]); } } } /// # Summary /// Performs greater-than-or-equals comparison to a constant. /// /// # Description /// Toggles output qubit `target` if and only if input register `x` /// is greater than or equal to `c`. /// /// # Input /// ## c /// Constant value for comparison. /// ## x /// Quantum register to compare against. /// ## target /// Target qubit for comparison result. /// /// # Reference /// This construction is described in [Lemma 3, arXiv:2201.10200] internal operation CompareGreaterThanOrEqualConstant(c : Int, x : Qubit[], target : Qubit) : Unit is Adj+Ctl { let bitWidth = Length(x); if c == 0 { X(target); } elif c >= 2 ^ bitWidth { // do nothing } elif c == 2 ^ (bitWidth - 1) { ApplyLowTCNOT(Tail(x), target); } else { // normalize constant let l = NTrailingZeroes(c); let cNormalized = c >>> l; let xNormalized = x[l...]; let bitWidthNormalized = Length(xNormalized); let gates = Rest(IntAsBoolArray(cNormalized, bitWidthNormalized)); use qs = Qubit[bitWidthNormalized - 1]; let cs1 = [Head(xNormalized)] + Most(qs); let cs2 = Rest(xNormalized); within { for i in IndexRange(gates) { (gates[i] ? ApplyAnd | ApplyOr)(cs1[i], cs2[i], qs[i]); } } apply { ApplyLowTCNOT(Tail(qs), target); } } } /// # Summary /// Internal operation used in the implementation of GreaterThanOrEqualConstant. internal operation ApplyOr(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { within { ApplyToEachA(X, [control1, control2]); } apply { ApplyAnd(control1, control2, target); X(target); } } internal operation ApplyAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { body (...) { CCNOT(control1, control2, target); } adjoint (...) { H(target); if (M(target) == One) { X(target); CZ(control1, control2); } } } /// # Summary /// Returns the number of trailing zeroes of a number /// /// ## Example /// ```qsharp /// let zeroes = NTrailingZeroes(21); // = NTrailingZeroes(0b1101) = 0 /// let zeroes = NTrailingZeroes(20); // = NTrailingZeroes(0b1100) = 2 /// ``` internal function NTrailingZeroes(number : Int) : Int { mutable nZeroes = 0; mutable copy = number; while (copy % 2 == 0) { set nZeroes += 1; set copy /= 2; } return nZeroes; } /// # Summary /// An implementation for `CNOT` that when controlled using a single control uses /// a helper qubit and uses `ApplyAnd` to reduce the T-count to 4 instead of 7. internal operation ApplyLowTCNOT(a : Qubit, b : Qubit) : Unit is Adj+Ctl { body (...) { CNOT(a, b); } adjoint self; controlled (ctls, ...) { // In this application this operation is used in a way that // it is controlled by at most one qubit. Fact(Length(ctls) <= 1, "At most one control line allowed"); if IsEmpty(ctls) { CNOT(a, b); } else { use q = Qubit(); within { ApplyAnd(Head(ctls), a, q); } apply { CNOT(q, b); } } } controlled adjoint self; }
Schätzen des Quantenalgorithmus
Schätzen Sie nun die physischen Ressourcen für den RunProgram
-Vorgang unter Verwendung der Standardannahmen. Fügen Sie eine neue Zelle hinzu und kopieren Sie den folgenden Code.
result = qsharp.estimate("RunProgram()")
result
Die qsharp.estimate
-Funktion erstellt ein Ergebnisobjekt, mit dem eine Tabelle mit der Gesamtanzahl der physischen Ressourcen angezeigt werden kann. Sie können die Kostendetails einsehen, indem Sie die Gruppen, die mehr Informationen enthalten, zuklappen. Weitere Informationen finden Sie in den vollständigen Berichtsdaten des Ressourcenstimators.
Reduzieren Sie beispielsweise die Gruppe der logischen Qubit-Parameter, um festzustellen, ob der Codeabstand 21 und die Anzahl der physischen Qubits 882 ist.
Logischer Qubit-Parameter | Wert |
---|---|
QEC-Schema | surface_code |
Codeabstand | 21 |
Physische Qubits | 882 |
Logische Zykluszeit | 8 Millisekunden |
Logische Qubit-Fehlerrate | 3.00E-13 |
Crossing Prefactor | 0,03 |
Schwellenwert für die Fehlerkorrektur | 0.01 |
Formel für die logische Zykluszeit | (4 × twoQubitGateTime × 2 × oneQubitMeasurementTime ) × codeDistance |
Formel für physische Qubits | 2 × codeDistance * codeDistance |
Tipp
Für eine kompaktere Version der Ausgabetabelle können Sie result.summary
verwenden.
Raumdiagramm
Die Verteilung physischer Qubits, die für den Algorithmus und die T-Fabriken verwendet werden, ist ein Faktor, der sich auf das Design Ihres Algorithmus auswirken kann. Sie können das qsharp-widgets
-Paket verwenden, um diese Verteilung zu visualisieren, um die geschätzten Platzanforderungen für den Algorithmus besser zu verstehen.
from qsharp-widgets import SpaceChart, EstimateDetails
SpaceChart(result)
In diesem Beispiel ist die Anzahl der zum Ausführen des Algorithmus erforderlichen physischen Qubits 829766, von denen 196686 Algorithmus-Qubits und 633080 T-Factory-Qubits sind.
Ändern der Standardwerte und Schätzen des Algorithmus
Beim Übermitteln einer Ressourcenschätzungsanforderung für Ihr Programm können Sie einige optionale Parameter angeben. Verwenden Sie das jobParams
Feld, um auf alle Parameter zuzugreifen, die target an die Auftragsausführung übergeben werden können, und sehen Sie, welche Standardwerte angenommen wurden:
result['jobParams']
{'errorBudget': 0.001,
'qecScheme': {'crossingPrefactor': 0.03,
'errorCorrectionThreshold': 0.01,
'logicalCycleTime': '(4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance',
'name': 'surface_code',
'physicalQubitsPerLogicalQubit': '2 * codeDistance * codeDistance'},
'qubitParams': {'instructionSet': 'GateBased',
'name': 'qubit_gate_ns_e3',
'oneQubitGateErrorRate': 0.001,
'oneQubitGateTime': '50 ns',
'oneQubitMeasurementErrorRate': 0.001,
'oneQubitMeasurementTime': '100 ns',
'tGateErrorRate': 0.001,
'tGateTime': '50 ns',
'twoQubitGateErrorRate': 0.001,
'twoQubitGateTime': '50 ns'}}
Sie können sehen, dass der Ressourcen-Estimator das qubit_gate_ns_e3
- Qubit-Modell, den surface_code
-Fehlerkorrekturcode und das Fehlerbudget 0,001 als Standardwerte für die Schätzung verwendet.
Dies sind die target Parameter, die angepasst werden können:
errorBudget
- das zulässige Gesamtfehlerbudget für den AlgorithmusqecScheme
- das QEC-Schema (Quantum Error Correction, Quantenfehlerkorrektur)qubitParams
- die physischen Qubit-Parameterconstraints
– die Einschränkungen auf KomponentenebenedistillationUnitSpecifications
- die Spezifikationen für die Destillationsalgorithmen der T-FabrikenestimateType
- einfach oder grenzüberschreitend
Weitere Informationen finden Sie unter Target Parameter für die Ressourcenschätzung.
Qubit-Modell ändern
Sie können die Kosten für denselben Algorithmus mithilfe des Majorana-basierten Qubit-Parameters, qubitParams
, "qubit_maj_ns_e6" schätzen.
result_maj = qsharp.estimate("RunProgram()", params={
"qubitParams": {
"name": "qubit_maj_ns_e6"
}})
EstimateDetails(result_maj)
Ändern des Quantenfehlerkorrekturschemas
Sie können die Ressourcenabschätzung für dasselbe Beispiel mit den Majorana-basierten QEC-Parametern und einem Floqued-QEC-Schema, qecScheme
, wiederholen.
result_maj = qsharp.estimate("RunProgram()", params={
"qubitParams": {
"name": "qubit_maj_ns_e6"
},
"qecScheme": {
"name": "floquet_code"
}})
EstimateDetails(result_maj)
Fehlerbudget ändern
Führen Sie als Nächstes den gleichen Quantenkreis mit einem errorBudget
-Wert von 10 % erneut aus.
result_maj = qsharp.estimate("RunProgram()", params={
"qubitParams": {
"name": "qubit_maj_ns_e6"
},
"qecScheme": {
"name": "floquet_code"
},
"errorBudget": 0.1})
EstimateDetails(result_maj)
Batchverarbeitung mit dem Ressourcen-Estimator
Mit dem Azure Quantum Resource Estimator können Sie mehrere Parameterkonfigurationen target ausführen und die Ergebnisse vergleichen. Dies ist nützlich, wenn Sie die Kosten verschiedener Qubit-Modelle, QEC-Schemas oder Fehlerbudgets vergleichen möchten.
Sie können eine Batchschätzung durchführen, indem Sie eine Liste von target Parametern an den
params
Parameter derqsharp.estimate
Funktion übergeben. Führen Sie beispielsweise denselben Algorithmus mit den Standardparametern und den Majorana-basierten Qubit-Parametern mit einem Floquet-QEC-Schema aus.result_batch = qsharp.estimate("RunProgram()", params= [{}, # Default parameters { "qubitParams": { "name": "qubit_maj_ns_e6" }, "qecScheme": { "name": "floquet_code" } }]) result_batch.summary_data_frame(labels=["Gate-based ns, 10⁻³", "Majorana ns, 10⁻⁶"])
Modell Logische Qubits Logische Tiefe T-Zustände Codeabstand T-Factorys T-Factoryanteil Physische Qubits rQOPS Physische Ausführungszeit Gatterbasiert ns, 10⁻³ 223 3,64 M 4,70 M 21 19 76.30 % 829,77k 26,55 M 31 Sek. Majorana ns, 10⁻⁶ 223 3,64 M 4,70 M 5 19 63.02 % 79,60k 148,67 M 5 s Sie können auch eine Liste von Schätzungsparametern mithilfe der
EstimatorParams
Klasse erstellen.from qsharp.estimator import EstimatorParams, QubitParams, QECScheme, LogicalCounts labels = ["Gate-based µs, 10⁻³", "Gate-based µs, 10⁻⁴", "Gate-based ns, 10⁻³", "Gate-based ns, 10⁻⁴", "Majorana ns, 10⁻⁴", "Majorana ns, 10⁻⁶"] params = EstimatorParams(num_items=6) params.error_budget = 0.333 params.items[0].qubit_params.name = QubitParams.GATE_US_E3 params.items[1].qubit_params.name = QubitParams.GATE_US_E4 params.items[2].qubit_params.name = QubitParams.GATE_NS_E3 params.items[3].qubit_params.name = QubitParams.GATE_NS_E4 params.items[4].qubit_params.name = QubitParams.MAJ_NS_E4 params.items[4].qec_scheme.name = QECScheme.FLOQUET_CODE params.items[5].qubit_params.name = QubitParams.MAJ_NS_E6 params.items[5].qec_scheme.name = QECScheme.FLOQUET_CODE
qsharp.estimate("RunProgram()", params=params).summary_data_frame(labels=labels)
Modell Logische Qubits Logische Tiefe T-Zustände Codeabstand T-Factorys T-Factoryanteil Physische Qubits rQOPS Physische Ausführungszeit Gatterbasiert µs, 10⁻³ 223 3,64M 4,70 M 17 13 40,54 % 216,77 k 21,86 k 10 Stunden Gatterbasiert µs, 10⁻⁴ 223 3,64 M 4,70 M 9 14 43,17 % 63,57 k 41,30 k 5 Stunden Gatterbasiert ns, 10⁻³ 223 3,64M 4,70 M 17 16 69,08 % 416,89 k 32,79 M 25 Sek. Gatterbasiert ns, 10⁻⁴ 223 3,64M 4,70 M 9 14 43,17 % 63,57 k 61,94 M 13 Sek. Majorana ns, 10⁻⁴ 223 3,64M 4,70 M 9 19 82,75 % 501,48 k 82,59 M 10 Sek. Majorana ns, 10⁻⁶ 223 3,64M 4,70 M 5 13 31,47 % 42,96 k 148,67 M 5 s
Berechnung der Pareto-Grenze
Bei der Schätzung der Ressourcen eines Algorithmus ist es wichtig, den Kompromiss zwischen der Anzahl der physischen Qubits und der Laufzeit des Algorithmus zu berücksichtigen. Sie könnten die Zuordnung von so vielen physischen Qubits wie möglich in Betracht ziehen, um die Laufzeit des Algorithmus zu reduzieren. Die Anzahl der physischen Qubits ist jedoch durch die Anzahl der physischen Qubits begrenzt, die in der Quantenhardware verfügbar sind.
Die Pareto-Grenzschätzung liefert mehrere Schätzungen für denselben Algorithmus, jeweils mit einem Kompromiss zwischen der Anzahl der Qubits und der Laufzeit.
Um den Ressourcen-Estimator mithilfe der Pareto-Grenzschätzung auszuführen, müssen Sie den
"estimateType"
target Parameter als"frontier"
angeben. Führen Sie z. B. den gleichen Algorithmus mit den Majorana-basierten Qubit-Parametern mit einem Oberflächencode aus, indem Sie die Grenze von Pareto verwenden.result = qsharp.estimate("RunProgram()", params= {"qubitParams": { "name": "qubit_maj_ns_e4" }, "qecScheme": { "name": "surface_code" }, "estimateType": "frontier", # frontier estimation } )
Sie können die
EstimatesOverview
Funktion verwenden, um eine Tabelle mit der Gesamtanzahl der physischen Ressourcen anzuzeigen. Klicken Sie auf das Symbol neben der ersten Zeile, um die Spalten auszuwählen, die Sie anzeigen möchten. Sie können unter Ausführungsname, Schätzungstyp, Qubittyp, qec-Schema, Fehlerbudget, logische Qubits, logische Tiefe, Codeabstand, T-Zustände, T-Fabriken, T-Factorybruch, Laufzeit, rQOPS und physische Qubits auswählen.from qsharp_widgets import EstimatesOverview EstimatesOverview(result)
In der Spalte "Geschätzter Typ " der Ergebnistabelle können Sie die Anzahl der verschiedenen Kombinationen von {Anzahl von Qubits, Runtime} für Ihren Algorithmus sehen. In diesem Fall findet der Ressourcen-Estimator 22 verschiedene optimale Kombinationen aus vielen tausend möglichen Kombinationen.
Raumzeitdiagramm
Die EstimatesOverview
Funktion zeigt auch das Raumzeitdiagramm des Ressourcenstimators an.
Das Raumzeitdiagramm zeigt die Anzahl der physischen Qubits und die Laufzeit des Algorithmus für jedes {Anzahl von Qubits, Runtime}-Paaren. Sie können auf jeden Punkt zeigen, um die Details der Ressourcenschätzung zu diesem Zeitpunkt anzuzeigen.
Batchverarbeitung mit Pareto-Grenzschätzung
Fügen Sie die Parameter hinzu, um mehrere Konfigurationen von target Parametern mit der Grenzschätzung zu schätzen und zu
"estimateType": "frontier",
vergleichen.result = qsharp.estimate( "RunProgram()", [ { "qubitParams": { "name": "qubit_maj_ns_e4" }, "qecScheme": { "name": "surface_code" }, "estimateType": "frontier", # Pareto frontier estimation }, { "qubitParams": { "name": "qubit_maj_ns_e6" }, "qecScheme": { "name": "floquet_code" }, "estimateType": "frontier", # Pareto frontier estimation }, ] ) EstimatesOverview(result, colors=["#1f77b4", "#ff7f0e"], runNames=["e4 Surface Code", "e6 Floquet Code"])
Hinweis
Sie können Farben definieren und Namen für das Qubit-Zeitdiagramm mithilfe der
EstimatesOverview
Funktion ausführen.Wenn Sie mehrere Konfigurationen von target Parametern mithilfe der Pareto-Grenzschätzung ausführen, können Sie die Ressourcenschätzungen für einen bestimmten Punkt des Raumzeitdiagramms anzeigen, d. h. für jede {Anzahl von Qubits, Laufzeit}-Paaren. Der folgende Code zeigt z. B. die Geschätzte Detailnutzung für die zweite Ausführung (Schätzungsindex=0) und die vierte (Punktindex=3) kürzeste Laufzeit.
EstimateDetails(result[1], 4)
Sie können auch das Raumdiagramm für einen bestimmten Punkt des Raumzeitdiagramms anzeigen. Der folgende Code zeigt z. B. das Leerzeichendiagramm für die erste Ausführung von Kombinationen (Schätzungsindex=0) und die dritte kürzeste Laufzeit (Punktindex=2).
SpaceChart(result[0], 2)
Voraussetzungen für Qiskit
- Ein Azure-Konto mit einem aktiven Abonnement. Wenn Sie nicht über ein Azure-Konto verfügen, registrieren Sie sich kostenlos, und registrieren Sie sich für ein Kostenpflichtiges Abonnement.
- Azure Quantum-Arbeitsbereich Weitere Informationen finden Sie unter Erstellen eines Azure Quantum-Arbeitsbereichs.
Aktivieren der Azure Quantum Resource Estimator target in Ihrem Arbeitsbereich
Der Resource Estimator ist ein target Microsoft Quantum Computing-Anbieter. Wenn Sie seit der Veröffentlichung des Resource Estimator einen Arbeitsbereich erstellt haben, wurde der Microsoft Quantum Computing-Anbieter automatisch zu Ihrem Arbeitsbereich hinzugefügt.
Wenn Sie einen vorhandenen Azure Quantum-Arbeitsbereich verwenden:
- Öffnen Sie Ihren Arbeitsbereich im Azure-Portal.
- Wählen Sie im linken Bereich unter Vorgänge die Option Anbieter aus.
- Wählen Sie + Anbieter hinzufügen aus.
- Wählen Sie + Hinzufügen für Microsoft Quantum Computing aus.
- Wählen Sie "Lernen und Entwickeln" und dann "Hinzufügen" aus.
Erstellen eines neuen Notebooks in Ihrem Arbeitsbereich
- Melden Sie sich beim Azure-Portal an, und wählen Sie Ihren Azure Quantum-Arbeitsbereich aus.
- Wählen Sie unter "Vorgänge" die Option "Notizbücher" aus .
- Klicken Sie auf "Meine Notizbücher ", und klicken Sie auf " Neu hinzufügen".
- Wählen Sie unter Kerneltyp die Option IPython aus.
- Geben Sie einen Namen für die Datei ein, und klicken Sie auf " Datei erstellen".
Wenn Ihr neues Notebook geöffnet wird, wird der Code für die erste Zelle automatisch auf der Grundlage Ihrer Abonnement- und Arbeitsbereichsinformationen erstellt.
from azure.quantum import Workspace
workspace = Workspace (
resource_id = "", # Your resource_id
location = "" # Your workspace location (for example, "westus")
)
Hinweis
Sofern nicht anders angegeben, müssen Sie die einzelnen Zellen in der Reihenfolge ihrer Erstellung ausführen, um Kompilierungsprobleme zu vermeiden.
Klicken Sie links neben der Zelle auf das dreieckige Wiedergabesymbol, um den Code auszuführen.
Laden der erforderlichen Importe
Zunächst müssen Sie ein zusätzliches Modul aus Azure-Quantum und qiskit
.
Klicken Sie auf + Code, um eine neue Zelle hinzuzufügen, fügen Sie dann den folgenden Code hinzu, und führen Sie ihn aus:
from azure.quantum.qiskit import AzureQuantumProvider
from qiskit import QuantumCircuit, transpile
from qiskit.circuit.library import RGQFTMultiplier
Herstellen einer Verbindung mit dem Azure Quantum-Dienst
Erstellen Sie als Nächstes ein AzureQuantumProvider-Objekt mithilfe des workspace
Objekts aus der vorherigen Zelle, um eine Verbindung mit Ihrem Azure Quantum-Arbeitsbereich herzustellen. Sie erstellen eine Back-End-Instanz und legen den Ressourcenstimator als Ihre target.
provider = AzureQuantumProvider(workspace)
backend = provider.get_backend('microsoft.estimator')
Erstellen des Quantenalgorithmus
In diesem Beispiel erstellen Sie einen Quantenkreis für einen Multiplikator basierend auf der Konstruktion in Ruiz-Perez und Garc-Escartin (arXiv:1411.5949), die die Quantum Fourier Transform verwendet, um Arithmetik zu implementieren.
Sie können die Größe des Multiplikators anpassen, indem Sie die bitwidth
Variable ändern. Die Schaltkreisgenerierung wird in eine Funktion umschlossen, die mit dem bitwidth
Wert des Multiplikators aufgerufen werden kann. Der Vorgang verfügt über zwei Eingaberegister, jede Größe des angegebenen bitwidth
Werts und ein Ausgaberegister, das doppelt so groß ist wie die angegebene bitwidth
. Die Funktion druckt auch einige logische Ressourcenanzahlen für den Multiplizierer, der direkt aus dem Quantenkreis extrahiert wird.
def create_algorithm(bitwidth):
print(f"[INFO] Create a QFT-based multiplier with bitwidth {bitwidth}")
# Print a warning for large bitwidths that will require some time to generate and
# transpile the circuit.
if bitwidth > 18:
print(f"[WARN] It will take more than one minute generate a quantum circuit with a bitwidth larger than 18")
circ = RGQFTMultiplier(num_state_qubits=bitwidth, num_result_qubits=2 * bitwidth)
# One could further reduce the resource estimates by increasing the optimization_level,
# however, this will also increase the runtime to construct the algorithm. Note, that
# it does not affect the runtime for resource estimation.
print(f"[INFO] Decompose circuit into intrinsic quantum operations")
circ = transpile(circ, basis_gates=SUPPORTED_INSTRUCTIONS, optimization_level=0)
# print some statistics
print(f"[INFO] qubit count: {circ.num_qubits}")
print("[INFO] gate counts")
for gate, count in circ.count_ops().items():
print(f"[INFO] - {gate}: {count}")
return circ
Hinweis
Sie können physische Ressourcenschätzungsaufträge für Algorithmen übermitteln, die keine T-Zustände aufweisen, aber mindestens eine Messung aufweisen.
Schätzen des Quantenalgorithmus
Erstellen Sie eine Instanz Ihres Algorithmus mithilfe der create_algorithm
Funktion. Sie können die Größe des Multiplikators anpassen, indem Sie die bitwidth
Variable ändern.
bitwidth = 4
circ = create_algorithm(bitwidth)
Schätzen Sie die physischen Ressourcen für diesen Vorgang mithilfe der Standardannahmen. Sie können den Schaltkreis mithilfe der run
Methode an das Resource Estimator-Back-End übermitteln und dann ausführen job.result()
, bis der Auftrag abgeschlossen ist, und die Ergebnisse zurückgeben.
job = backend.run(circ)
result = job.result()
result
Dadurch wird eine Tabelle erstellt, in der die Gesamtanzahl der physischen Ressourcen angezeigt wird. Sie können die Kostendetails einsehen, indem Sie die Gruppen, die mehr Informationen enthalten, zuklappen.
Tipp
Für eine kompaktere Version der Ausgabetabelle können Sie result.summary
verwenden.
Wenn Sie beispielsweise die Gruppe "Logische Qubit-Parameter " reduzieren, können Sie leichter erkennen, dass der Entfernung des Fehlerkorrekturcodes 15 ist.
Logischer Qubitparameter | Wert |
---|---|
QEC-Schema | surface_code |
Codeabstand | 15 |
Physische Qubits | 450 |
Logische Zykluszeit | 6us |
Fehlerrate logischer Qubits | 3.00E-10 |
Vorfaktor der Kreuzung | 0,03 |
Schwellenwert für die Fehlerkorrektur | 0.01 |
Formel für die logische Zykluszeit | (4 × twoQubitGateTime × 2 × oneQubitMeasurementTime ) × codeDistance |
Formel für physische Qubits | 2 × codeDistance * codeDistance |
In der Gruppe "Physische Qubitparameter " können Sie die physikalischen Qubiteigenschaften sehen, die für diese Schätzung angenommen wurden. So beträgt beispielsweise die Zeit für die Durchführung der Messung eines einzelnen Qubits und eines einzelnen Qubitgatters 100 ns bzw. 50 ns.
Tipp
Sie können auch auf die Ausgabe des Resource Estimator als Python-Wörterbuch mithilfe der Result.data()- Methode zugreifen.
Weitere Informationen finden Sie in der vollständigen Liste der Ausgabedaten für den Ressourcen-Estimator.
Raumdiagramme
Die Verteilung physischer Qubits, die für den Algorithmus und die T-Fabriken verwendet werden, ist ein Faktor, der sich auf das Design Ihres Algorithmus auswirken kann. Sie können diese Verteilung visualisieren, um die geschätzten Platzanforderungen für den Algorithmus besser zu verstehen.
result.diagram.space
Das Raumdiagramm zeigt den Anteil von Algorithmus-Qubits und T-Factory-Qubits. Beachten Sie, dass die Anzahl der T Factorykopien, 28, zur Anzahl der physischen Qubits für T-Fabriken als $\text{T factories} \cdot \text{physical qubit per T factory}= 28 \cdot 18.000 = 504.000$ beiträgt.
Weitere Informationen finden Sie unter T factory physical estimation.
Ändern der Standardwerte und Schätzen des Algorithmus
Beim Übermitteln einer Ressourcenschätzungsanforderung für Ihr Programm können Sie einige optionale Parameter angeben. Verwenden Sie das jobParams
Feld, um auf alle Werte zuzugreifen, die an die Auftragsausführung übergeben werden können, und sehen Sie, welche Standardwerte angenommen wurden:
result.data()["jobParams"]
{'errorBudget': 0.001,
'qecScheme': {'crossingPrefactor': 0.03,
'errorCorrectionThreshold': 0.01,
'logicalCycleTime': '(4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance',
'name': 'surface_code',
'physicalQubitsPerLogicalQubit': '2 * codeDistance * codeDistance'},
'qubitParams': {'instructionSet': 'GateBased',
'name': 'qubit_gate_ns_e3',
'oneQubitGateErrorRate': 0.001,
'oneQubitGateTime': '50 ns',
'oneQubitMeasurementErrorRate': 0.001,
'oneQubitMeasurementTime': '100 ns',
'tGateErrorRate': 0.001,
'tGateTime': '50 ns',
'twoQubitGateErrorRate': 0.001,
'twoQubitGateTime': '50 ns'}}
Dies sind die target Parameter, die angepasst werden können:
errorBudget
- das gesamt zulässige FehlerbudgetqecScheme
- das QEC-Schema (Quantum Error Correction, Quantenfehlerkorrektur)qubitParams
- die physischen Qubit-Parameterconstraints
– die Einschränkungen auf KomponentenebenedistillationUnitSpecifications
- die Spezifikationen für die Destillationsalgorithmen der T-Fabriken
Weitere Informationen finden Sie unter Target Parameter für die Ressourcenschätzung.
Qubit-Modell ändern
Als Nächstes schätzen Sie die Kosten für denselben Algorithmus mithilfe des Majorana-basierten Qubit-Parameters. qubit_maj_ns_e6
job = backend.run(circ,
qubitParams={
"name": "qubit_maj_ns_e6"
})
result = job.result()
result
Sie können die physischen Zählungen programmgesteuert prüfen. Beispielsweise können Sie Details zur T-Factory untersuchen, die erstellt wurde, um den Algorithmus auszuführen.
result.data()["tfactory"]
{'eccDistancePerRound': [1, 1, 5],
'logicalErrorRate': 1.6833177305222897e-10,
'moduleNamePerRound': ['15-to-1 space efficient physical',
'15-to-1 RM prep physical',
'15-to-1 RM prep logical'],
'numInputTstates': 20520,
'numModulesPerRound': [1368, 20, 1],
'numRounds': 3,
'numTstates': 1,
'physicalQubits': 16416,
'physicalQubitsPerRound': [12, 31, 1550],
'runtime': 116900.0,
'runtimePerRound': [4500.0, 2400.0, 110000.0]}
Hinweis
Standardmäßig wird die Laufzeit in Nanosekunden angezeigt.
Sie können diese Daten verwenden, um einige Erläuterungen darüber zu erzeugen, wie die T-Fabriken die erforderlichen T-Zustände erzeugen.
data = result.data()
tfactory = data["tfactory"]
breakdown = data["physicalCounts"]["breakdown"]
producedTstates = breakdown["numTfactories"] * breakdown["numTfactoryRuns"] * tfactory["numTstates"]
print(f"""A single T factory produces {tfactory["logicalErrorRate"]:.2e} T states with an error rate of (required T state error rate is {breakdown["requiredLogicalTstateErrorRate"]:.2e}).""")
print(f"""{breakdown["numTfactories"]} copie(s) of a T factory are executed {breakdown["numTfactoryRuns"]} time(s) to produce {producedTstates} T states ({breakdown["numTstates"]} are required by the algorithm).""")
print(f"""A single T factory is composed of {tfactory["numRounds"]} rounds of distillation:""")
for round in range(tfactory["numRounds"]):
print(f"""- {tfactory["numModulesPerRound"][round]} {tfactory["moduleNamePerRound"][round]} unit(s)""")
A single T factory produces 1.68e-10 T states with an error rate of (required T state error rate is 2.77e-08).
23 copies of a T factory are executed 523 time(s) to produce 12029 T states (12017 are required by the algorithm).
A single T factory is composed of 3 rounds of distillation:
- 1368 15-to-1 space efficient physical unit(s)
- 20 15-to-1 RM prep physical unit(s)
- 1 15-to-1 RM prep logical unit(s)
Ändern des Quantenfehlerkorrekturschemas
Führen Sie nun den Ressourcenschätzungsauftrag für dasselbe Beispiel für die Majorana-basierten Qubit-Parameter mit einem floqued QEC-Schema erneut aus. qecScheme
job = backend.run(circ,
qubitParams={
"name": "qubit_maj_ns_e6"
},
qecScheme={
"name": "floquet_code"
})
result_maj_floquet = job.result()
result_maj_floquet
Fehlerbudget ändern
Lassen Sie uns den gleichen Quantenkreis mit einem errorBudget
Wert von 10 % erneut ausführen.
job = backend.run(circ,
qubitParams={
"name": "qubit_maj_ns_e6"
},
qecScheme={
"name": "floquet_code"
},
errorBudget=0.1)
result_maj_floquet_e1 = job.result()
result_maj_floquet_e1
Hinweis
Wenn beim Arbeiten mit der Ressourcenschätzung probleme auftreten, schauen Sie sich die Seite "Problembehandlung" an, oder wenden Sie sich an den Kontakt AzureQuantumInfo@microsoft.com.