Verschiedene Möglichkeiten zum Ausführen des Ressourcenschätzungssteuerelements

In diesem Artikel erfahren Sie, wie Sie mit dem Azure Quantum Resource Estimator arbeiten. Die Ressourcenschätzung ist sowohl in VS Code als auch online in Azure-Portal verfügbar.

In der folgenden Tabelle sind die verschiedenen Methoden zum Ausführen des Ressourcenschätzungssteuerelements aufgeführt.

Benutzerszenario Plattform Tutorial
Schätzen der Ressourcen eines Q#-Programms Visual Studio Code Wählen Sie in VS Code oben auf der Seite Q# aus.
Schätzen der Ressourcen eines Q#-Programms (erweitert) Jupyter Notebook in Visual Studio Code Wählen Sie in Jupyter Notebook oben auf der Seite Q# aus.
Schätzen der Ressourcen eines Qiskit-Programms Azure Quantum-Portal Wählen Sie qiskit in Azure-Portal oben auf der Seite aus.
Schätzen der Ressourcen eines QIR-Programms Azure Quantum-Portal Qir übermitteln
Verwenden von FCIDUMP-Dateien als Argumentparameter (erweitert) Visual Studio Code Übermitteln eines Quantenchemieproblems

Hinweis

Das Microsoft Quantum Development Kit (Classic QDK) wird nach dem 30. Juni 2024 nicht mehr unterstützt. Wenn Sie bereits QDK-Entwickler sind, empfehlen wir Ihnen, auf das neue Azure Quantum Development Kit (Modern QDK) umzusteigen, um die Entwicklung von Quantenlösungen fortzusetzen. Weitere Informationen finden Sie unter Migrieren Ihres Q#-Codes zum modernen QDK.

Voraussetzungen für VS Code

Tipp

Sie benötigen kein Azure-Konto, um die lokale Ressourcenschätzung auszuführen.

Create einer neuen Q#-Datei

  1. Öffnen Sie Visual Studio Code, und wählen Sie Datei > Neue Textdatei aus, um eine neue Datei zu erstellen.
  2. Speichern Sie die Datei unter dem Namen ShorRE.qs. Diese Datei enthält den Q#-Code für Ihr Programm.

Create des Quantenalgorithmus

Kopieren Sie den folgenden Code in die Datei ShorRE.qs:

namespace Shors {
    open Microsoft.Quantum.Arrays;
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Diagnostics;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Unstable.Arithmetic;
    open Microsoft.Quantum.ResourceEstimation;

    @EntryPoint()
    operation RunProgram() : Unit {
        let bitsize = 31;

        // When chooseing 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 des Ressourcenschätzungssteuerelements

Der Resource Estimator bietet sechs vordefinierte Qubitparameter, von denen vier über gatebasierte Befehlssätze und zwei über einen Majorana-Anweisungssatz verfügen. Außerdem werden zwei Quantenfehlerkorrekturcodessurface_code und bereitgestelltfloquet_code.

In diesem Beispiel führen Sie den Resource Estimator mit dem qubit_gate_us_e3 Qubit-Parameter und dem surface_code Quantenfehlerkorrekturcode aus.

  1. Wählen Sie Ansicht –> Befehlspalette aus, und geben Sie "Ressource" ein, um die Option Q#: Ressourcenschätzungen berechnen anzuzeigen. Sie können auch in der Liste der Befehle unter @EntryPoint()auf Schätzen klicken. Wählen Sie diese Option aus, um das Fenster Ressourcenschätzung zu öffnen.

    Screenshot: Auswählen des Befehls

  2. Sie können einen oder mehrere Qubit-Parameter + Fehlerkorrektur-Codetypen auswählen, für die die Ressourcen geschätzt werden sollen. Wählen Sie in diesem Beispiel qubit_gate_us_e3 aus, und klicken Sie auf OK.

    Screenshot: Auswählen des Qubitparameters im Menü

  3. 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.

  4. Drücken Sie die EINGABETASTE , um den Standardergebnisnamen basierend auf dem Dateinamen zu übernehmen, in diesem Fall ShorRE.

Anzeigen der Ergebnisse

Der Ressourcenschätzungsmodul 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 Systemskalierung ist einer der wichtigsten Aspekte der Ressourcenschätzung.

Das Ergebnis der Ressourcenschätzung wird im Fenster Q#-Schätzung angezeigt.

  1. Auf der Registerkarte Ergebnisse wird eine Zusammenfassung der Ressourcenschätzung angezeigt. Klicken Sie auf das Symbol neben der ersten Zeile, um die Anzuzeigenden Spalten auszuwählen. Sie können zwischen Ausführungsname, Schätzungstyp, Qubittyp, qec-Schema, Fehlerbudget, logischen Qubits, logischer Tiefe, Codeabstand, T-Zuständen, T-Factory-Zuständen, T-Factorybruch, Laufzeit, rQOPS und physischen Qubits auswählen.

    Screenshot: Anzeigen des Menüs zum Auswählen der Ressourcenschätzungsausgaben Ihrer Wahl

    In der Spalte Geschätzter Typ der Ergebnistabelle sehen Sie die Anzahl der optimalen Kombinationen von {Anzahl von Qubits, Runtime} für Ihren Algorithmus. Diese Kombinationen sind im Raum-Zeit-Diagramm zu sehen.

  2. Das Raum-Zeit-Diagramm zeigt die Kompromisse zwischen der Anzahl der physischen Qubits und der Laufzeit des Algorithmus. In diesem Fall findet der Resource Estimator 13 verschiedene optimale Kombinationen von vielen Tausend möglichen Kombinationen. Sie können mit dem Mauszeiger auf jeden {Anzahl von Qubits, Runtime}-Punkt zeigen, um die Details der Ressourcenschätzung an diesem Punkt anzuzeigen.

    Screenshot: Raum-Zeit-Diagramm des Ressourcenschätzungssteuerelements.

    Weitere Informationen finden Sie unter Raum-Zeit-Diagramm.

    Hinweis

    Sie müssen auf einen Punkt des Raum-Zeit-Diagramms klicken, d. h. auf ein {Anzahl von Qubits, Runtime}-Paar, um das Raumdiagramm und die Details der entsprechenden Ressourcenschätzung anzuzeigen.

  3. Das Raumdiagramm zeigt die Verteilung der physischen Qubits, die für den Algorithmus und die T-Fabriken verwendet werden, entsprechend einem {Anzahl von Qubits, Runtime}-Paar. Wenn Sie beispielsweise den äußerst linken Punkt im Raum-Zeit-Diagramm auswählen, ist die Anzahl der physischen Qubits, die zum Ausführen des Algorithmus erforderlich sind, 427726, 196686 davon Algorithmus-Qubits und 231040 davon T-Factory-Qubits.

    Screenshot des Raumdiagramms des Ressourcenschätzungssteuerelements.

  4. Schließlich wird auf der Registerkarte Ressourcenschätzungen die vollständige Liste der Ausgabedaten für die Ressourcenschätzung angezeigt, die einem {Anzahl von Qubits, Runtime}- Paar entspricht. Sie können die Kostendetails einsehen, indem Sie die Gruppen, die mehr Informationen enthalten, zuklappen. Wählen Sie beispielsweise den äußersten linken Punkt im Raum-Zeit-Diagramm aus, und reduzieren Sie die Gruppe Logische Qubitparameter .

    Logischer Qubitparameter Wert
    QEC-Schema surface_code
    Codeabstand 21
    Physische Qubits 882
    Logische Zykluszeit 13 Mio.
    Fehlerrate logischer Qubits 3.00E-13
    Überqueren des Präfaktors 0,03
    Fehlerkorrekturschwellenwert 0.01
    Formel für logische Zykluszeit (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
    Formel für physische Qubits 2 * codeDistance * codeDistance

    Tipp

    Klicken Sie auf Detaillierte Zeilen anzeigen , um die Beschreibung der einzelnen Ausgaben der Berichtsdaten anzuzeigen.

    Weitere Informationen finden Sie in den vollständigen Berichtsdaten des Ressourcenschätzungssteuerelements.

Ändern der target Parameter

Sie können die Kosten für dasselbe Q#-Programm mit anderen Qubittypen, Fehlerkorrekturcode und Fehlerbudget schätzen. Öffnen Sie das Fenster Ressourcenschätzung, indem Sie Ansicht –> Befehlspalette auswählen, und geben Sie ein Q#: Calculate Resource Estimates.

Wählen Sie eine beliebige andere Konfiguration aus, z. B. den Majorana-basierten Qubitparameter qubit_maj_ns_e6. Übernehmen Sie den Standardfehlerbudgetwert, oder geben Sie einen neuen Fehler ein, und drücken Sie die EINGABETASTE. Der Ressourcenschätzungs-Wert wird mit den neuen target Parametern erneut ausgeführt.

Weitere Informationen finden Sie unter Zielparameter 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.

  1. Wählen Sie Ansicht –> Befehlspalette aus, oder drücken Sie STRG+UMSCHALT+P, und geben Sie ein Q#: Calculate Resource Estimates.

  2. Wählen Sie qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4 + floquet_code und qubit_maj_ns_e6 + floquet_code aus, und klicken Sie auf OK.

  3. Übernehmen Sie den Standardfehlerbudgetwert 0,001, und drücken Sie die EINGABETASTE.

  4. Drücken Sie die EINGABETASTE , um die Eingabedatei zu akzeptieren, in diesem Fall ShorRE.qs.

  5. Bei mehreren Konfigurationen von Parametern werden die Ergebnisse in verschiedenen Zeilen auf der Registerkarte Ergebnisse angezeigt.

  6. Das Raum-Zeit-Diagramm 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 mit der Maus auf jeden Punkt zeigen, um die Details der Ressourcenschätzung an diesem Punkt anzuzeigen.

    Screenshot des Raum-Zeit-Diagramms und der Ergebnistabelle beim Ausführen mehrerer Konfigurationen des Parameters im Resource Estimator

  7. Klicken Sie auf einen {number of qubits, runtime}-Punkt des Raum-Zeit-Diagramms, um das entsprechende Raumdiagramm und die Berichtsdaten anzuzeigen.

Voraussetzungen für Jupyter Notebook in VS Code

Tipp

Sie benötigen kein Azure-Konto, um die lokale Ressourcenschätzung auszuführen.

Create des Quantenalgorithmus

  1. Wählen Sie in VS Code Befehlspalette anzeigen > und dann Create: Neue Jupyter Notebook aus.

  2. Oben rechts erkennt VS Code die Version von Python und die virtuelle Python-Umgebung, die für das Notebook ausgewählt wurde, und zeigt sie an. Wenn Sie über mehrere Python-Umgebungen verfügen, müssen Sie möglicherweise einen Kernel mithilfe der Kernelauswahl oben rechts auswählen. Wenn keine Umgebung erkannt wurde, finden Sie unter Jupyter Notebooks in VS Code Setupinformationen.

  3. Importieren Sie das qsharp Paket in der ersten Zelle des Notebooks.

    import qsharp
    
  4. Fügen Sie eine neue Zelle hinzu, und kopieren Sie den folgenden Code.

    %%qsharp
    open Microsoft.Quantum.Arrays;
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Diagnostics;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Unstable.Arithmetic;
    open Microsoft.Quantum.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

Nun schätzen Sie die physischen Ressourcen für den RunProgram Vorgang mithilfe 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, das verwendet werden kann, um eine Tabelle mit der Gesamtzahl der physischen Ressourcen anzuzeigen. 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 Ressourcenschätzungssteuerelements.

Reduzieren Sie beispielsweise die Gruppe logische Qubitparameter , um zu sehen, dass der Codeabstand 21 und die Anzahl der physischen Qubits 882 beträgt.

Logischer Qubitparameter Wert
QEC-Schema surface_code
Codeabstand 21
Physische Qubits 882
Logische Zykluszeit 8 Mio.
Fehlerrate logischer Qubits 3.00E-13
Überqueren des Präfaktors 0,03
Fehlerkorrekturschwellenwert 0.01
Formel für 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 verwenden result.summary.

Raumdiagramm

Die Verteilung der physischen Qubits, die für den Algorithmus und die T-Fabriken verwendet werden, ist ein Faktor, der sich auf den Entwurf Ihres Algorithmus auswirken kann. Sie können das qsharp-widgets Paket verwenden, um diese Verteilung zu visualisieren, um die geschätzten Speicherplatzanforderungen für den Algorithmus besser zu verstehen.

from qsharp-widgets import SpaceChart, EstimateDetails
SpaceChart(result)

In diesem Beispiel ist die Anzahl der physischen Qubits, die zum Ausführen des Algorithmus erforderlich sind, 829766, 196686 davon Algorithmus-Qubits und 633080 davon T-Factory-Qubits.

Screenshot des Raumdiagramms des Ressourcenschätzungssteuerelements.

Ändern der Standardwerte und Schätzen des Algorithmus

Wenn Sie eine Ressourcenschätzungsanforderung für Ihr Programm übermitteln, 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 die Ressourcenschätzung das qubit_gate_ns_e3 Qubitmodell, den surface_code Fehlerkorrekturcode und das Fehlerbudget 0,001 als Standardwerte für die Schätzung verwendet.

Dies sind die Parameter, die target angepasst werden können:

  • errorBudget – das insgesamt zulässige Fehlerbudget für den Algorithmus
  • qecScheme – das QEC-Schema (Quantum Error Correction, Quantenfehlerkorrektur)
  • qubitParams – die physischen Qubitparameter
  • constraints – die Einschränkungen auf Komponentenebene
  • distillationUnitSpecifications - die Spezifikationen für T-Factory-Destillationsalgorithmen
  • estimateType - single oder frontier

Weitere Informationen finden Sie unter Zielparameter für die Ressourcenschätzung.

Ändern des Qubitmodells

Sie können die Kosten für denselben Algorithmus mithilfe des Majorana-basierten Qubitparameters 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 den Auftrag für die Ressourcenschätzung für dasselbe Beispiel für die Majorana-basierten Qubitparameter mit einem floqueden QEC-Schema ( qecScheme) erneut ausführen.

result_maj = qsharp.estimate("RunProgram()", params={
                "qubitParams": {
                    "name": "qubit_maj_ns_e6"
                },
                "qecScheme": {
                    "name": "floquet_code"
                }})
EstimateDetails(result_maj)

Ändern des Fehlerbudgets

Führen Sie als Nächstes die gleiche Quantenschaltung 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 Resource Estimator

Mit dem Azure Quantum Resource Estimator können Sie mehrere Konfigurationen von target Parametern ausführen und die Ergebnisse vergleichen. Dies ist nützlich, wenn Sie die Kosten verschiedener Qubitmodelle, QEC-Schemas oder Fehlerbudgets vergleichen möchten.

  1. Sie können eine Batchschätzung durchführen, indem Sie eine Liste von target Parametern an den params Parameter der qsharp.estimate Funktion übergeben. Führen Sie beispielsweise den gleichen Algorithmus mit den Standardparametern und den Majorana-basierten Qubitparametern mit einem floqueden 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.64M 4,70 M 21 19 76.30 % 829,77 Kb 26,55 M 31 Sekunden
    Majorana ns, 10⁻⁶ 223 3.64M 4,70 M 5 19 63.02 % 79,60 k 148,67M 5 Sekunden
  2. 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,64 M 4,70 M 17 13 40.54 % 216,77 Kb 21,86 Kb 10 Stunden
    Gatterbasiert µs, 10⁻⁴ 223 3.64M 4,70 M 9 14 43.17 % 63,57 Kb 41,30 k 5 Stunden
    Gatterbasiert ns, 10⁻³ 223 3,64 M 4,70 M 17 16 69.08 % 416,89 Kb 32,79 M 25 Sekunden
    Gatterbasiert ns, 10⁻⁴ 223 3,64 M 4,70 M 9 14 43.17 % 63,57 Kb 61,94M 13 Sekunden
    Majorana ns, 10⁻⁴ 223 3,64 M 4,70 M 9 19 82.75 % 501,48k 82,59M 10 Sekunden
    Majorana ns, 10⁻⁶ 223 3,64 M 4,70 M 5 13 31.47 % 42,96 Kb 148,67M 5 Sekunden

Ausführen einer Pareto-Grenzschätzung

Beim Schätzen 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 wird jedoch durch die Anzahl der physischen Qubits begrenzt, die in der Quantenhardware verfügbar sind.

Die Pareto-Grenzschätzung bietet mehrere Schätzungen für denselben Algorithmus mit jeweils einem Kompromiss zwischen der Anzahl der Qubits und der Laufzeit.

  1. Um den Resource Estimator mithilfe der Pareto-Grenzschätzung auszuführen, müssen Sie den "estimateType"target Parameter als "frontier"angeben. Führen Sie beispielsweise den gleichen Algorithmus mit den Majorana-basierten Qubitparametern mit einem Oberflächencode mithilfe der Pareto-Grenzschätzung aus.

    result = qsharp.estimate("RunProgram()", params=
                                {"qubitParams": { "name": "qubit_maj_ns_e4" },
                                "qecScheme": { "name": "surface_code" },
                                "estimateType": "frontier", # frontier estimation
                                }
                            )
    
  2. Sie können die EstimatesOverview Funktion verwenden, um eine Tabelle mit der Gesamtzahl der physischen Ressourcen anzuzeigen. Klicken Sie auf das Symbol neben der ersten Zeile, um die anzuzeigenden Spalten auszuwählen. Sie können zwischen Ausführungsname, Schätzungstyp, Qubittyp, qec-Schema, Fehlerbudget, logischen Qubits, logischer Tiefe, Codeabstand, T-Zustände, T-Fabriken, T Factory-Fraktion, Runtime, rQOPS und physischen Qubits auswählen.

    from qsharp_widgets import EstimatesOverview
    EstimatesOverview(result)
    

In der Spalte Schätzungstyp der Ergebnistabelle sehen Sie die Anzahl der verschiedenen Kombinationen von {number of qubits, runtime} für Ihren Algorithmus. In diesem Fall findet der Resource Estimator 22 verschiedene optimale Kombinationen aus vielen Tausend möglichen.

Raum-Zeit-Diagramm

Die EstimatesOverview Funktion zeigt auch das Raum-Zeit-Diagramm des Resource Estimators an.

Das Raumzeitdiagramm zeigt die Anzahl der physischen Qubits und die Laufzeit des Algorithmus für jedes {Anzahl von Qubits, Runtime}-Paar. Sie können mit dem Mauszeiger auf jeden Punkt zeigen, um die Details der Ressourcenschätzung an diesem Punkt anzuzeigen.

Screenshot: Raumzeitdiagramm mit Grenzschätzung des Ressourcenstimators

Batchverarbeitung mit Pareto-Grenzschätzung

  1. Fügen "estimateType": "frontier", Sie die Parameter hinzu, um mehrere Konfigurationen von target Parametern mit der Grenzschätzung zu schätzen und zu 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"])
    

    Screenshot: Raumzeitdiagramm des Resource Estimators bei Verwendung der Pareto-Grenzschätzung und mehrerer Konfigurationen von Parametern

    Hinweis

    Sie können Farben und Ausführungsnamen für das Qubit-Zeitdiagramm mithilfe der EstimatesOverview -Funktion definieren.

  2. 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 Raum-Zeit-Diagramms anzeigen, d. h. für jedes {Anzahl von Qubits, Runtime}-Paar. Der folgende Code zeigt z. B. die Nutzung der Schätzungsdetails für die zweite Ausführung (Schätzungsindex=0) und die vierte (Punktindex=3) kürzeste Laufzeit.

    EstimateDetails(result[1], 4)
    
  3. 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 (estimate index=0) und die dritt kürzeste Laufzeit (Punktindex=2).

    SpaceChart(result[0], 2)
    

Voraussetzungen für Qiskit

Aktivieren des Azure Quantum Resource Estimators target in Ihrem Arbeitsbereich

Der Resource Estimator ist ein target Anbieter von Microsoft Quantum Computing. Wenn Sie seit der Veröffentlichung des Resource Estimators einen Arbeitsbereich erstellt haben, wurde der Microsoft Quantum Computing-Anbieter Ihrem Arbeitsbereich automatisch hinzugefügt.

Wenn Sie einen vorhandenen Azure Quantum-Arbeitsbereich verwenden:

  1. Öffnen Sie Ihren Arbeitsbereich im Azure-Portal.
  2. Wählen Sie im linken Bereich unter Vorgänge die Option Anbieter aus.
  3. Wählen Sie + Anbieter hinzufügen aus.
  4. Wählen Sie + Hinzufügen für Microsoft Quantum Computing aus.
  5. Wählen Sie Lernen & Entwickeln aus, und wählen Sie Hinzufügen aus.

Erstellen eines neuen Notebooks in Ihrem Arbeitsbereich

  1. Melden Sie sich beim Azure-Portal an, und wählen Sie Ihren Azure Quantum-Arbeitsbereich aus.
  2. Wählen Sie unter Vorgängedie Option Notebooks aus.
  3. Klicken Sie auf Meine Notizbücher, und klicken Sie auf Neu hinzufügen.
  4. Wählen Sie unter Kerneltyp die Option IPython aus.
  5. Geben Sie einen Namen für die Datei ein, und klicken Sie auf Create Datei.

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 zusätzliche Module aus azure-quantum und qiskitimportieren.

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 , indem Sie das workspace Objekt aus der vorherigen Zelle verwenden, um eine Verbindung mit Ihrem Azure Quantum-Arbeitsbereich herzustellen. Sie erstellen ein Back-End-instance und legen den Resource Estimator auf Ihr targetfest.

provider = AzureQuantumProvider(workspace)
backend = provider.get_backend('microsoft.estimator')

Create des Quantenalgorithmus

In diesem Beispiel erstellen Sie eine Quantenschaltung für einen Multiplikator basierend auf der in Ruiz-Perez und Garcia-Escartin dargestellten Konstruktion (arXiv:1411.5949), die die Quanten-Fourier-Transformation verwendet, um Arithmetik zu implementieren.

Sie können die Größe des Multiplikators anpassen, indem Sie die bitwidth Variable ändern. Die Leitungsgenerierung wird in eine Funktion umschlossen, die mit dem bitwidth Wert des Multiplikators aufgerufen werden kann. Der Vorgang verfügt über zwei Eingaberegister, jedes die Größe des angegebenen bitwidthund ein Ausgaberegister, das doppelt so groß ist wie der angegebene bitwidth. Die Funktion gibt auch einige logische Ressourcenanzahlen für den direkt aus der Quantenschaltung extrahierten Multiplikator aus.

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 Aufträge zur Schätzung physischer Ressourcen für Algorithmen übermitteln, die keine T-Zustände haben, aber mindestens eine Messung aufweisen.

Schätzen des Quantenalgorithmus

Create mithilfe create_algorithm der Funktion einen instance Ihres Algorithmus. 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 die Verbindung mithilfe run der -Methode an das Resource Estimator-Back-End übermitteln und dann ausführen job.result() , um auf den Abschluss des Auftrags zu warten und die Ergebnisse zurückzugeben.

job = backend.run(circ)
result = job.result()
result

Dadurch wird eine Tabelle erstellt, in der die Gesamtzahl 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 verwenden result.summary.

Wenn Sie beispielsweise die Gruppe logische Qubitparameter reduzieren, können Sie leichter erkennen, dass der Fehlerkorrekturcodeabstand 15 beträgt.

Logischer Qubitparameter Wert
QEC-Schema surface_code
Codeabstand 15
Physische Qubits 450
Logische Zykluszeit 6us
Logische Qubitfehlerrate 3.00E-10
Kreuzen von Präfaktoren 0,03
Fehlerkorrekturschwellenwert 0.01
Formel der Logischen Zykluszeit (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Formel für physische Qubits 2 * codeDistance * codeDistance

In der Gruppe Physische Qubitparameter sehen Sie die physischen Qubiteigenschaften, 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 mit der result.data() -Methode als Python-Wörterbuch auf die Ausgabe des Resource Estimator zugreifen.

Weitere Informationen finden Sie in der vollständigen Liste der Ausgabedaten für den Resource Estimator.

Raumdiagramme

Die Verteilung der physischen 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 den geschätzten Platzbedarf für den Algorithmus besser zu verstehen.

result.diagram.space

Kreisdiagramm, das die Verteilung der gesamten physischen Qubits zwischen Algorithmusqubits und T Factory-Qubits zeigt. Es gibt eine Tabelle mit der Aufschlüsselung der Anzahl der T-Factory-Kopien und der Anzahl der physischen Qubits pro T Factory.

Das Raumdiagramm zeigt den Anteil von Algorithmusqubits und T Factory-Qubits. Beachten Sie, dass die Anzahl der T Factory-Kopien(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 Physische T Factory-Schätzung.

Ändern der Standardwerte und Schätzen des Algorithmus

Wenn Sie eine Ressourcenschätzungsanforderung für Ihr Programm übermitteln, 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 Parameter, die target angepasst werden können:

  • errorBudget - Das zulässige Gesamtbudget für Fehler
  • qecScheme - das QEC-Schema (Quantum Error Correction, Quantenfehlerkorrektur)
  • qubitParams - die physischen Qubitparameter
  • constraints – die Einschränkungen auf Komponentenebene
  • distillationUnitSpecifications - die Spezifikationen für T-Fabriken-Destillationsalgorithmen

Weitere Informationen finden Sie unter Zielparameter für den Resource Estimator.

Ändern des Qubitmodells

Schätzen Sie als Nächstes die Kosten für denselben Algorithmus mithilfe des Majorana-basierten Qubitparameters. qubit_maj_ns_e6

job = backend.run(circ,
    qubitParams={
        "name": "qubit_maj_ns_e6"
    })
result = job.result()
result

Sie können die physischen Anzahlen programmgesteuert überprüfen. Beispielsweise können Sie Details zur T-Factory untersuchen, die zum Ausführen des Algorithmus erstellt wurde.

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 Erklärungen zu erstellen, 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 Qubitparameter mit einem floqueden QEC-Schema( qecSchemeerneut aus.

job = backend.run(circ,
    qubitParams={
        "name": "qubit_maj_ns_e6"
    },
    qecScheme={
        "name": "floquet_code"
    })
result_maj_floquet = job.result()
result_maj_floquet

Ändern des Fehlerbudgets

Führen Wir dieselbe Quantenschaltung mit einer errorBudget von 10 % erneut aus.

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 dem Resource Estimator ein Problem aufgetreten ist, lesen Sie die Seite Problembehandlung, oder wenden Sie sich an AzureQuantumInfo@microsoft.com.

Nächste Schritte