Share via


Verschillende manieren om de resource-estimator uit te voeren

In dit artikel leert u werken met de Azure Quantum Resource Estimator. De Resource Estimator is zowel beschikbaar in VS Code als online in Azure Portal.

In de volgende tabel ziet u de verschillende manieren om de Resource Estimator uit te voeren.

Gebruikersscenario Platform Zelfstudie
De resources van een Q#-programma schatten Visual Studio Code Selecteer Q# in VS Code bovenaan de pagina
De resources van een Q#-programma schatten (geavanceerd) Jupyter Notebook in Visual Studio Code Selecteer Q# in Jupyter Notebook boven aan de pagina
De resources van een Qiskit-programma schatten Azure Quantum Portal Selecteer Qiskit in Azure Portal bovenaan de pagina
De resources van een QIR-programma schatten Azure Quantum Portal QIR verzenden
FCIDUMP-bestanden gebruiken als argumentparameters (geavanceerd) Visual Studio Code Een probleem met kwantumchemie indienen

Notitie

De Microsoft Quantum Development Kit (klassieke QDK) wordt na 30 juni 2024 niet meer ondersteund. Als u een bestaande QDK-ontwikkelaar bent, raden we u aan over te stappen op de nieuwe Azure Quantum Development Kit (Moderne QDK) om door te gaan met het ontwikkelen van kwantumoplossingen. Zie Uw Q#-code migreren naar de moderne QDK voor meer informatie.

Vereisten voor VS Code

Tip

U hoeft geen Azure-account te hebben om de lokale resource-estimator uit te voeren.

een nieuw Q#-bestand Creatie

  1. Open Visual Studio Code en selecteer Bestand > Nieuw tekstbestand om een nieuw bestand te maken.
  2. Sla het bestand op als ShorRE.qs. Dit bestand bevat de Q#-code voor uw programma.

het kwantumalgoritmen Creatie

Kopieer de volgende code naar het ShorRE.qs bestand:

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;
    }
}

De resource-estimator uitvoeren

De Resource Estimator biedt zes vooraf gedefinieerde qubitparameters, waarvan er vier op gate gebaseerde instructiesets hebben en twee met een Majorana-instructieset. Het biedt ook twee kwantumfoutcorrectiecodes, surface_code en floquet_code.

In dit voorbeeld voert u de Resource Estimator uit met behulp van de qubit_gate_us_e3 qubitparameter en de surface_code kwantumfoutcorrectiecode.

  1. Selecteer Weergave -> Opdrachtpalet en typ 'resource' om de optie Q#: Resourceschattingen berekenen weer te geven. U kunt ook klikken op Schatting in de lijst met opdrachten hieronder @EntryPoint(). Selecteer deze optie om het venster Resource Estimator te openen.

    Schermopname die laat zien hoe u de opdracht schatting selecteert in de lijst met codelenzen.

  2. U kunt een of meer codetypen qubitparameter + foutcorrectie selecteren om de resources voor te schatten. Selecteer voor dit voorbeeld qubit_gate_us_e3 en klik op OK.

    Schermopname die laat zien hoe u de qubitparameter selecteert in het menu resourceschatting.

  3. Geef het foutbudget op of accepteer de standaardwaarde 0,001. Laat voor dit voorbeeld de standaardwaarde staan en druk op Enter.

  4. Druk op Enter om de standaardresultaatnaam te accepteren op basis van de bestandsnaam, in dit geval ShorRE.

De resultaten bekijken

De Resource Estimator biedt meerdere schattingen voor hetzelfde algoritme, waarbij elk een balans laat zien tussen het aantal qubits en de runtime. Inzicht in de balans tussen runtime en systeemschaal is een van de belangrijkste aspecten van de schatting van resources.

Het resultaat van de resourceschatting wordt weergegeven in het venster Q#-schatting .

  1. Op het tabblad Resultaten wordt een samenvatting van de resourceraming weergegeven. Klik op het pictogram naast de eerste rij om de kolommen te selecteren die u wilt weergeven. U kunt kiezen uit runnaam, schattingstype, qubittype, qec-schema, foutbudget, logische qubits, logische diepte, codeafstand, T-statussen, T-factory's, T factory-breuk, runtime, rQOPS en fysieke qubits.

    Schermopname die laat zien hoe u het menu weergeeft om de uitvoer van de resourceschattingen van uw keuze te selecteren.

    In de kolom Schattingstype van de resultatentabel ziet u het aantal optimale combinaties van {aantal qubits, runtime} voor uw algoritme. Deze combinaties zijn te zien in het ruimte-tijddiagram.

  2. In het diagram Ruimte-tijd ziet u de afwegingen tussen het aantal fysieke qubits en de runtime van het algoritme. In dit geval vindt de Resource Estimator 13 verschillende optimale combinaties van vele duizenden mogelijke. U kunt de muisaanwijzer op elk {aantal qubits, runtime} aanwijzen om de details van de resourceraming op dat punt te bekijken.

    Schermopname van het ruimte-tijddiagram van de Resource Estimator.

    Zie Ruimtetijddiagram voor meer informatie.

    Notitie

    U moet op één punt van het ruimte-tijddiagram klikken, dat wil weten een {aantal qubits, runtime}-paar, om het ruimtediagram en de details van de resourceschatting voor dat punt te zien.

  3. Het ruimtediagram toont de verdeling van fysieke qubits die worden gebruikt voor het algoritme en de T-factory's, die overeenkomen met een {aantal qubits, runtime} paar. Als u bijvoorbeeld het meest linkse punt in het ruimte-tijddiagram selecteert, is het aantal fysieke qubits dat nodig is om het algoritme uit te voeren 427726, 196686 waarvan algoritme-qubits en 231040 waarvan T factory-qubits zijn.

    Schermopname van het ruimtediagram van de resource-estimator.

  4. Ten slotte geeft het tabblad Resourceschattingen de volledige lijst met uitvoergegevens weer voor de Resource Estimator die overeenkomt met een {aantal qubits, runtime} paar. U kunt kostendetails controleren door de groepen samen te vouwen, die meer informatie bevatten. Selecteer bijvoorbeeld het meest linkse punt in het ruimte-tijddiagram en vouw de groep Logische qubitparameters samen.

    Logische qubitparameter Waarde
    QEC-schema surface_code
    Codeafstand 21
    Fysieke qubits 882
    Logische cyclustijd 13 milisecs
    Foutfrequentie logische qubit 3.00E-13
    Kruisingsvoorfactor 0.03
    Drempelwaarde voor foutcorrectie 0,01
    Formule voor logische cyclustijd (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
    Formule voor fysieke qubits 2 * codeDistance * codeDistance

    Tip

    Klik op Gedetailleerde rijen weergeven om de beschrijving van elke uitvoer van de rapportgegevens weer te geven.

    Zie de volledige rapportgegevens van de Resource Estimator voor meer informatie.

target De parameters wijzigen

U kunt de kosten voor hetzelfde Q#-programma schatten met behulp van een ander qubittype, foutcorrectiecode en foutbudget. Open het venster Resource Estimator door Weergave -> Opdrachtpalet te selecteren en typ Q#: Calculate Resource Estimates.

Selecteer een andere configuratie, bijvoorbeeld de op Majorana gebaseerde qubitparameter, qubit_maj_ns_e6. Accepteer de standaardwaarde voor het foutbudget of voer een nieuwe in en druk op Enter. De Resource Estimator voert de schatting opnieuw uit met de nieuwe target parameters.

Zie Doelparameters voor de Resource Estimator voor meer informatie.

Meerdere configuraties van parameters uitvoeren

De Azure Quantum Resource Estimator kan meerdere configuraties van parameters uitvoeren en de resultaten van target de resourceraming vergelijken.

  1. Selecteer Beeld -> Opdrachtpalet of druk op Ctrl+Shift+P en typ Q#: Calculate Resource Estimates.

  2. Selecteer qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4 + floquet_code en qubit_maj_ns_e6 + floquet_code en klik op OK.

  3. Accepteer de standaardwaarde voor het foutbudget 0,001 en druk op Enter.

  4. Druk op Enter om het invoerbestand te accepteren, in dit geval ShorRE.qs.

  5. In het geval van meerdere configuraties van parameters worden de resultaten weergegeven in verschillende rijen op het tabblad Resultaten .

  6. Het diagram Ruimte-tijd toont de resultaten voor alle configuraties van parameters. In de eerste kolom van de resultatentabel wordt de legenda voor elke configuratie van parameters weergegeven. U kunt de muisaanwijzer over elk punt bewegen om de details van de resource-schatting op dat punt te bekijken.

    Schermopname van het ruimte-tijddiagram en de tabel met resultaten bij het uitvoeren van meerdere configuraties van parameters in de Resource Estimator.

  7. Klik op een {aantal qubits, runtime} punt van het ruimte-tijddiagram om het bijbehorende ruimtediagram en de rapportgegevens weer te geven.

Vereisten voor Jupyter Notebook in VS Code

Tip

U hoeft geen Azure-account te hebben om de lokale resource-estimator uit te voeren.

het kwantumalgoritmen Creatie

  1. Selecteer in VS Code opdrachtpalet weergeven > en selecteer Creatie: Nieuwe Jupyter Notebook.

  2. In de rechterbovenhoek detecteert VS Code de versie van Python en de virtuele Python-omgeving die voor het notebook is geselecteerd en geeft deze weer. Als u meerdere Python-omgevingen hebt, moet u mogelijk een kernel selecteren met behulp van de kernelkiezer in de rechterbovenhoek. Als er geen omgeving is gedetecteerd, raadpleegt u Jupyter Notebooks in VS Code voor installatie-informatie.

  3. Importeer het pakket in de eerste cel van het qsharp notebook.

    import qsharp
    
  4. Voeg een nieuwe cel toe en kopieer de volgende 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;
    }
    

Het kwantumalgoritmen schatten

U maakt nu een schatting van de fysieke resources voor de RunProgram bewerking met behulp van de standaardveronderstellingen. Voeg een nieuwe cel toe en kopieer de volgende code.

result = qsharp.estimate("RunProgram()")
result

Met de qsharp.estimate functie wordt een resultaatobject gemaakt, dat kan worden gebruikt om een tabel weer te geven met het totale aantal fysieke resources. U kunt kostendetails controleren door de groepen samen te vouwen, die meer informatie bevatten. Zie de volledige rapportgegevens van de Resource Estimator voor meer informatie.

Vouw bijvoorbeeld de groep Logische qubitparameters samen om te zien dat de codeafstand 21 is en het aantal fysieke qubits 882.

Logische qubitparameter Waarde
QEC-schema surface_code
Codeafstand 21
Fysieke qubits 882
Logische cyclustijd 8 milisecs
Foutfrequentie logische qubit 3.00E-13
Kruisingsvoorfactor 0.03
Drempelwaarde voor foutcorrectie 0,01
Formule voor logische cyclustijd (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Formule voor fysieke qubits 2 * codeDistance * codeDistance

Tip

Voor een compactere versie van de uitvoertabel kunt u gebruiken result.summary.

Ruimtediagram

De distributie van fysieke qubits die worden gebruikt voor het algoritme en de T-factory's is een factor die van invloed kan zijn op het ontwerp van uw algoritme. U kunt het qsharp-widgets pakket gebruiken om deze distributie te visualiseren om meer inzicht te krijgen in de geschatte ruimtevereisten voor het algoritme.

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

In dit voorbeeld is het aantal fysieke qubits dat nodig is om het algoritme uit te voeren 829766, waarvan 196686 algoritme-qubits zijn en 633080 waarvan T-factory-qubits.

Schermafbeelding van het ruimtediagram van de resource-estimator.

De standaardwaarden wijzigen en het algoritme schatten

Wanneer u een aanvraag voor een resourceschatting voor uw programma indient, kunt u enkele optionele parameters opgeven. Gebruik het jobParams veld voor toegang tot alle target parameters die kunnen worden doorgegeven aan de taakuitvoering en bekijk welke standaardwaarden zijn aangenomen:

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'}}

U kunt zien dat de Resource Estimator het qubit_gate_ns_e3 qubitmodel, de surface_code foutcorrectiecode en het foutbudget 0,001 als standaardwaarden voor de schatting gebruikt.

Dit zijn de target parameters die kunnen worden aangepast:

  • errorBudget - het totale toegestane foutbudget voor het algoritme
  • qecScheme - het schema voor kwantumfoutcorrectie (QEC)
  • qubitParams - de fysieke qubitparameters
  • constraints - de beperkingen op onderdeelniveau
  • distillationUnitSpecifications - de specificaties voor de distillatiealgoritmen van de T-fabrieken
  • estimateType - enkel of grens

Zie Doelparameters voor de Resource Estimator voor meer informatie.

Qubitmodel wijzigen

U kunt de kosten voor hetzelfde algoritme schatten met behulp van de op Majorana gebaseerde qubitparameter , qubitParams'qubit_maj_ns_e6'.

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

Correctieschema voor kwantumfouten wijzigen

U kunt de resourceschattingstaak voor hetzelfde voorbeeld opnieuw uitvoeren op de op Majorana gebaseerde qubitparameters met een floqued QEC-schema, qecScheme.

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

Foutbudget wijzigen

Voer vervolgens hetzelfde kwantumcircuit opnieuw uit met een errorBudget van 10%.

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

Batchverwerking met de resource-estimator

Met de Azure Quantum Resource Estimator kunt u meerdere configuraties van target parameters uitvoeren en de resultaten vergelijken. Dit is handig wanneer u de kosten van verschillende qubitmodellen, QEC-schema's of foutbudgetten wilt vergelijken.

  1. U kunt een batchschatting uitvoeren door een lijst met target parameters door te geven aan de params parameter van de qsharp.estimate functie. Voer bijvoorbeeld hetzelfde algoritme uit met de standaardparameters en de qubitparameters op basis van Majorana met een floqued QEC-schema.

    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⁻⁶"])
    
    Model Logische qubits Logische diepte T-statussen Codeafstand T factory's T fabrieksfractie Fysieke qubits rQOPS Fysieke runtime
    Poort-gebaseerde ns, 10⁻³ 223 3,64 miljoen 4,70m 21 19 76.30 % 829,77k 26,55 min. 31 seconden
    Majorana ns, 10⁻⁶ 223 3,64 miljoen 4,70m 5 19 63.02 % 79,60k 148,67M 5 seconden
  2. U kunt ook een lijst met schattingsparameters maken met behulp van de EstimatorParams klasse .

    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)
    
    Model Logische qubits Logische diepte T-statussen Codeafstand T factory's T-fabrieksfractie Fysieke qubits rQOPS Fysieke runtime
    Poortgebaseerde μs, 10⁻³ 223 3,64m 4,70m 17 13 40.54 % 216,77k 21,86k 10 uur
    Poortgebaseerde μs, 10⁻⁴ 223 3,64 miljoen 4,70m 9 14 43.17 % 63,57k 41,30k 5 uur
    Poort-gebaseerde ns, 10⁻³ 223 3,64m 4,70m 17 16 69.08 % 416,89k 32,79 miljoen 25 seconden
    Op poort gebaseerde ns, 10⁻⁴ 223 3,64m 4,70m 9 14 43.17 % 63,57k 61,94 miljoen 13 seconden
    Majorana ns, 10⁻⁴ 223 3,64m 4,70m 9 19 82.75 % 501,48k 82,59 min. 10 seconden
    Majorana ns, 10⁻⁶ 223 3,64m 4,70m 5 13 31.47 % 42,96k 148,67M 5 seconden

Pareto grensschatting uitvoeren

Bij het schatten van de resources van een algoritme is het belangrijk om rekening te houden met de afweging tussen het aantal fysieke qubits en de runtime van het algoritme. U kunt overwegen om zoveel mogelijk fysieke qubits toe te passen om de runtime van het algoritme te verminderen. Het aantal fysieke qubits wordt echter beperkt door het aantal fysieke qubits dat beschikbaar is in de kwantumhardware.

De Pareto frontier-schatting biedt meerdere schattingen voor hetzelfde algoritme, elk met een afweging tussen het aantal qubits en de runtime.

  1. Als u de resource-estimator wilt uitvoeren met behulp van pareto-grensschatting, moet u de "estimateType"target parameter opgeven als "frontier". Voer bijvoorbeeld hetzelfde algoritme uit met de op Majorana gebaseerde qubitparameters met een surface-code met behulp van Pareto frontier-schatting.

    result = qsharp.estimate("RunProgram()", params=
                                {"qubitParams": { "name": "qubit_maj_ns_e4" },
                                "qecScheme": { "name": "surface_code" },
                                "estimateType": "frontier", # frontier estimation
                                }
                            )
    
  2. U kunt de EstimatesOverview functie gebruiken om een tabel weer te geven met het totale aantal fysieke resources. Klik op het pictogram naast de eerste rij om de kolommen te selecteren die u wilt weergeven. U kunt kiezen uit runnaam, schattingstype, qubittype, qec-schema, foutbudget, logische qubits, logische diepte, codeafstand, T-statussen, T-factory's, T factory-breuk, runtime, rQOPS en fysieke qubits.

    from qsharp_widgets import EstimatesOverview
    EstimatesOverview(result)
    

In de kolom Schattingstype van de resultatentabel ziet u het aantal verschillende combinaties van {aantal qubits, runtime} voor uw algoritme. In dit geval vindt de resource-estimator 22 verschillende optimale combinaties van vele duizenden mogelijke.

Ruimte-tijddiagram

Met de EstimatesOverview functie wordt ook het ruimte-tijddiagram van de resource-estimator weergegeven.

Het ruimte-tijddiagram toont het aantal fysieke qubits en de runtime van het algoritme voor elk {aantal qubits, runtime}-paar. U kunt de muisaanwijzer over elk punt bewegen om de details van de resourceschatting op dat moment te bekijken.

Schermopname van het ruimte-tijddiagram met een grensschatting van de Resource Estimator.

Batchverwerking met pareto grensschatting

  1. Als u meerdere configuraties van target parameters wilt schatten en vergelijken met grensschatting, voegt u toe "estimateType": "frontier", aan de parameters.

    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"])
    

    Schermopname van het ruimte-tijddiagram van de Resource Estimator bij het gebruik van Pareto frontier-schatting en meerdere configuraties van parameters.

    Notitie

    U kunt kleuren definiëren en namen uitvoeren voor het qubit-tijddiagram met behulp van de EstimatesOverview functie.

  2. Wanneer u meerdere configuraties van parameters uitvoert met behulp van target de Pareto frontier-schatting, kunt u de resourceschattingen zien voor een specifiek punt van het ruimte-tijddiagram, dat wil gezegd voor elk {aantal qubits, runtime} paar. In de volgende code ziet u bijvoorbeeld de geschatte details van het gebruik voor de tweede uitvoering (schatting van index=0) en de vierde (puntindex=3) kortste runtime.

    EstimateDetails(result[1], 4)
    
  3. U kunt ook het ruimtediagram voor een specifiek punt van het ruimtetijddiagram bekijken. De volgende code toont bijvoorbeeld het ruimtediagram voor de eerste uitvoering van combinaties (schatting van index=0) en de op twee na kortste runtime (puntindex=2).

    SpaceChart(result[0], 2)
    

Vereisten voor Qiskit

De Azure Quantum Resource Estimator target inschakelen in uw werkruimte

De Resource Estimator is een target van de Microsoft Quantum Computing-provider. Als u een werkruimte hebt gemaakt sinds de release van de Resource Estimator, is de Microsoft Quantum Computing-provider automatisch toegevoegd aan uw werkruimte.

Als u een bestaande Azure Quantum-werkruimte gebruikt:

  1. Open uw werkruimte in de Azure Portal.
  2. Selecteer in het linkerdeelvenster onder Bewerkingen de optie Providers.
  3. Selecteer + Een provider toevoegen.
  4. Selecteer + Toevoegen voor Microsoft Quantum Computing.
  5. Selecteer Learn & Develop en selecteer Add.

een nieuw notitieblok in uw werkruimte Creatie

  1. Meld u aan bij de Azure Portal en selecteer uw Azure Quantum-werkruimte.
  2. Selecteer onder Bewerkingen de optie Notebooks
  3. Klik op Mijn notitieblokken en klik op Nieuwe toevoegen
  4. Selecteer in Kerneltypede optie IPython.
  5. Typ een naam voor het bestand en klik op Creatie bestand.

Wanneer uw nieuwe notitieblok wordt geopend, wordt automatisch de code voor de eerste cel gemaakt op basis van uw abonnement en werkruimtegegevens.

from azure.quantum import Workspace
workspace = Workspace ( 
    resource_id = "", # Your resource_id 
    location = ""  # Your workspace location (for example, "westus") 
)

Notitie

Tenzij anders vermeld, moet u elke cel tijdens het maken in de juiste volgorde uitvoeren om compilatieproblemen te voorkomen.

Klik op het driehoekige pictogram 'afspelen' links van de cel om de code uit te voeren.

De vereiste importbewerkingen laden

Eerst moet u extra modules importeren uit azure-quantum en qiskit.

Klik op + Code om een nieuwe cel toe te voegen en voeg vervolgens de volgende code toe en voer deze uit:

from azure.quantum.qiskit import AzureQuantumProvider
from qiskit import QuantumCircuit, transpile
from qiskit.circuit.library import RGQFTMultiplier

Verbinding maken met de Azure Quantum-service

Maak vervolgens een AzureQuantumProvider-object met behulp van het workspace object uit de vorige cel om verbinding te maken met uw Azure Quantum-werkruimte. U maakt een back-endexemplaar en stelt de Resource Estimator in als uw target.

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

het kwantumalgoritmen Creatie

In dit voorbeeld maakt u een kwantumcircuit voor een vermenigvuldigingsfunctie op basis van de constructie die wordt weergegeven inÉs-Perez en Garcia-Escartin (arXiv:1411.5949), waarbij de Quantum Fourier-transformatie wordt gebruikt om rekenkundige berekeningen te implementeren.

U kunt de grootte van de vermenigvuldiger aanpassen door de bitwidth variabele te wijzigen. Het genereren van het circuit wordt verpakt in een functie die kan worden aangeroepen met de bitwidth waarde van de vermenigvuldiger. De bewerking heeft twee invoerregisters, elk de grootte van de opgegeven bitwidth, en één uitvoerregister dat tweemaal zo groot is als de opgegeven bitwidth. Met de functie worden ook enkele logische resourcetellingen afgedrukt voor de vermenigvuldigingsfunctie die rechtstreeks uit het kwantumcircuit is geëxtraheerd.

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

Notitie

U kunt schattingstaken voor fysieke resources indienen voor algoritmen die geen T-status hebben, maar die ten minste één meting hebben.

Het kwantumalgoritmen schatten

Creatie een exemplaar van uw algoritme met behulp van de create_algorithm functie. U kunt de grootte van de vermenigvuldiger aanpassen door de bitwidth variabele te wijzigen.

bitwidth = 4

circ = create_algorithm(bitwidth)

Maak een schatting van de fysieke resources voor deze bewerking met behulp van de standaardveronderstellingen. U kunt het circuit verzenden naar de resource-schattingsback-end met behulp van de run methode en vervolgens uitvoeren job.result() om te wachten tot de taak is voltooid en de resultaten retourneert.

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

Hiermee maakt u een tabel met het totale aantal fysieke resources. U kunt kostendetails controleren door de groepen samen te vouwen, die meer informatie bevatten.

Tip

Voor een compactere versie van de uitvoertabel kunt u gebruiken result.summary.

Als u bijvoorbeeld de parametergroep Logische qubit samenvouwt, kunt u gemakkelijker zien dat de afstand van de foutcode 15 is.

Parameter logische qubit Waarde
QEC-schema surface_code
Codeafstand 15
Fysieke qubits 450
Logische cyclustijd 6us
Foutfrequentie logische qubit 3.00E-10
Kruisingsvoorfactor 0.03
Drempelwaarde voor foutcorrectie 0,01
Formule voor logische cyclustijd (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Formule voor fysieke qubits 2 * codeDistance * codeDistance

In de groep Fysieke qubitparameters ziet u de fysieke qubiteigenschappen die voor deze schatting zijn uitgegaan. De tijd voor het uitvoeren van een meting met één qubit en een poort met één qubit wordt bijvoorbeeld uitgegaan van respectievelijk 100 ns en 50 ns.

Tip

U kunt de uitvoer van de Resource Estimator ook openen als een Python-woordenlijst met behulp van de methode result.data().

Zie de volledige lijst met uitvoergegevens voor de resource-estimator voor meer informatie.

Ruimtediagrammen

De distributie van fysieke qubits die worden gebruikt voor het algoritme en de T-factory's is een factor die van invloed kan zijn op het ontwerp van uw algoritme. U kunt deze distributie visualiseren om meer inzicht te krijgen in de geschatte ruimtevereisten voor het algoritme.

result.diagram.space

Cirkeldiagram met de verdeling van het totale aantal fysieke qubits tussen algoritme-qubits en T-factory-qubits. Er is een tabel met de uitsplitsing van het aantal T-factory-kopieën en het aantal fysieke qubits per T-factory.

In het ruimtediagram ziet u het aandeel algoritme-qubits en T-factory-qubits. Merk op dat het aantal T-factory-kopieën, 28, bijdraagt aan het aantal fysieke qubits voor T-factory's als $\text{T factorys} \cdot \text{fysieke qubit per T-factory}= 28 \cdot 18.000 = 504.000$.

Zie Fysieke schatting van de T-fabriek voor meer informatie.

De standaardwaarden wijzigen en het algoritme schatten

Wanneer u een aanvraag voor een resourceschatting voor uw programma indient, kunt u enkele optionele parameters opgeven. Gebruik het jobParams veld om toegang te krijgen tot alle waarden die kunnen worden doorgegeven aan de taakuitvoering en om te zien welke standaardwaarden zijn aangenomen:

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'}}

Dit zijn de target parameters die kunnen worden aangepast:

Zie Doelparameters voor de resource-estimator voor meer informatie.

Qubitmodel wijzigen

Maak vervolgens een schatting van de kosten voor hetzelfde algoritme met behulp van de op Majorana gebaseerde qubitparameter qubit_maj_ns_e6

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

U kunt de fysieke aantallen programmatisch inspecteren. U kunt bijvoorbeeld details verkennen over de T-factory die is gemaakt om het algoritme uit te voeren.

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]}

Notitie

Runtime wordt standaard weergegeven in nanoseconden.

U kunt deze gegevens gebruiken om uitleg te geven over hoe de T-factory's de vereiste T-statussen produceren.

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)

Correctieschema voor kwantumfouten wijzigen

Voer nu de resourceschattingstaak opnieuw uit voor hetzelfde voorbeeld op de qubitparameters op basis van Majorana met een floqued QEC-schema, qecScheme.

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

Foutbudget wijzigen

Laten we hetzelfde kwantumcircuit opnieuw uitvoeren met een errorBudget van 10%.

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

Notitie

Als u een probleem ondervindt tijdens het werken met de resource-estimator, gaat u naar de pagina Probleemoplossing of neemt u contact op met AzureQuantumInfo@microsoft.com.

Volgende stappen