Delen via


Verschillende manieren om de resource-estimator uit te voeren

In dit artikel leert u hoe u kunt werken met de Azure Quantum Resource Estimator. De resource-estimator helpt u bij het schatten van de resources die nodig zijn om een kwantumprogramma uit te voeren op een kwantumcomputer. U kunt de resource-estimator gebruiken om het aantal qubits, het aantal poorten en de diepte van het circuit te schatten dat nodig is om een kwantumprogramma uit te voeren.

De Resource Estimator is beschikbaar in Visual Studio Code met de Quantum Development Kit-extensie. Zie De Quantum Development Kit installerenvoor meer informatie.

Waarschuwing

De Resource Estimator in Azure Portal is niet langer ondersteund. Je wordt aangeraden over te stappen naar de lokale Resource Estimator in Visual Studio Code, die wordt voorzien in de Quantum Development Kit.

Vereisten voor VS Code

Tip

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

Een nieuw Q#-bestand maken

  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 maken

Kopieer de volgende code naar het ShorRE.qs bestand:


    import Std.Arrays.*;
    import Std.Canon.*;
    import Std.Convert.*;
    import Std.Diagnostics.*;
    import Std.Math.*;
    import Std.Measurement.*;
    import Microsoft.Quantum.Unstable.Arithmetic.*;
    import Std.ResourceEstimation.*;

    operation Main() : Unit {
        let bitsize = 31;

        // When choosing parameters for `EstimateFrequency`, make sure that
        // generator and modules are not co-prime
        let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize);
    }

    // In this sample we concentrate on costing the `EstimateFrequency`
    // operation, which is the core quantum operation in Shors algorithm, and
    // we omit the classical pre- and post-processing.

    /// # Summary
    /// Estimates the frequency of a generator
    /// in the residue ring Z mod `modulus`.
    ///
    /// # Input
    /// ## generator
    /// The unsigned integer multiplicative order (period)
    /// of which is being estimated. Must be co-prime to `modulus`.
    /// ## modulus
    /// The modulus which defines the residue ring Z mod `modulus`
    /// in which the multiplicative order of `generator` is being estimated.
    /// ## bitsize
    /// Number of bits needed to represent the modulus.
    ///
    /// # Output
    /// The numerator k of dyadic fraction k/2^bitsPrecision
    /// approximating s/r.
    operation EstimateFrequency(
        generator : Int,
        modulus : Int,
        bitsize : Int
    )
    : Int {
        mutable frequencyEstimate = 0;
        let bitsPrecision =  2 * bitsize + 1;

        // Allocate qubits for the superposition of eigenstates of
        // the oracle that is used in period finding.
        use eigenstateRegister = Qubit[bitsize];

        // Initialize eigenstateRegister to 1, which is a superposition of
        // the eigenstates we are estimating the phases of.
        // We first interpret the register as encoding an unsigned integer
        // in little endian encoding.
        ApplyXorInPlace(1, eigenstateRegister);
        let oracle = ApplyOrderFindingOracle(generator, modulus, _, _);

        // Use phase estimation with a semiclassical Fourier transform to
        // estimate the frequency.
        use c = Qubit();
        for idx in bitsPrecision - 1..-1..0 {
            within {
                H(c);
            } apply {
                // `BeginEstimateCaching` and `EndEstimateCaching` are the operations
                // exposed by Azure Quantum Resource Estimator. These will instruct
                // resource counting such that the if-block will be executed
                // only once, its resources will be cached, and appended in
                // every other iteration.
                if BeginEstimateCaching("ControlledOracle", SingleVariant()) {
                    Controlled oracle([c], (1 <<< idx, eigenstateRegister));
                    EndEstimateCaching();
                }
                R1Frac(frequencyEstimate, bitsPrecision - 1 - idx, c);
            }
            if MResetZ(c) == One {
                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) {
            nZeroes += 1;
            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 vier op poorten gebaseerde instructiesets 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 code voor kwantumfoutcorrectie surface_code .

  1. Selecteer Weergave -> opdrachtpalet en typ 'resource' die de optie Q#: Resourceschattingen berekenen moet worden weergegeven. U kunt ook klikken op Schatting in de lijst met opdrachten die direct vóór de Main bewerking worden weergegeven. Selecteer deze optie om het venster Resource-estimator te openen.

    Schermopname die laat zien hoe u de schattingsopdracht selecteert in de codelenslijst.

  2. U kunt een of meer qubitparameter en foutcodetypen 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 Resource-schatting.

  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, elk met compromissen 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 schatting van de resource wordt weergegeven in het Q#-schattingsvenster .

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

    Schermopname van het weergeven van het menu om de uitvoer van de resourceraming 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 ruimtetijd 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 combinaties. U kunt de muisaanwijzer op elk {aantal qubits, runtime}-punt bewegen om de details van de schatting van de resource op dat moment te bekijken.

    Schermopname van het ruimte-tijddiagram van de resource-estimator.

    Zie het diagram ruimtetijd voor meer informatie.

    Notitie

    U moet op één punt van het tijddiagram klikken, dat een {aantal qubits, runtime}-paar is, om het ruimtediagram en de details van de resourceraming te zien die overeenkomt met dat punt.

  3. In het ruimtediagram ziet u 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 tijddiagram selecteert, zijn het aantal fysieke qubits dat nodig is om het algoritme uit te voeren 427726, 196686 algoritme-qubits zijn en waarvan 231040 T factory-qubits zijn.

    Schermopname van het ruimtediagram van de resource-estimator.

  4. Ten slotte bevat het tabblad Resourceschattingen de volledige lijst met uitvoergegevens voor de Resource-estimator die overeenkomt met een {aantal qubits, runtime} -paar. U kunt kostendetails inspecteren door de groepen samen te vouwen, die meer informatie hebben. Selecteer bijvoorbeeld het meest linkse punt in het ruimtetijddiagram en vouw de groep logische qubitparameters samen.

    Parameter logische qubit Weergegeven als
    QEC-schema surface_code
    Codeafstand 21
    Fysieke qubits 882
    Tijd van logische cyclus 13 millisecs
    Foutpercentage logische qubit 3.00E-13
    Kruising vooraf 0.03
    Drempelwaarde voor foutcorrectie 0,01
    Formule voor tijd van logische cyclus (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>en typ .Q#: Calculate Resource Estimates

Selecteer een andere configuratie, bijvoorbeeld de op Majorana gebaseerde qubitparameter. qubit_maj_ns_e6 Accepteer de standaardwaarde van 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 Target de parameters 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 Weergave -> 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 standaardfoutbudgetwaarde 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. In het diagram Ruimtetijd ziet u de resultaten voor alle configuraties van parameters. In de eerste kolom van de resultatentabel wordt de legenda weergegeven voor elke configuratie van parameters. U kunt de muisaanwijzer op elk punt bewegen om de details van de schatting van de resource op dat moment weer te geven.

    Schermopname van het ruimte-tijddiagram en de tabel met resultaten bij het uitvoeren van meerdere configuraties van de parameter in de resource-estimator.

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

Vereisten voor Jupyter Notebook in VS Code

Tip

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

Het kwantumalgoritmen maken

  1. Selecteer in VS Code het > Weergeven en selecteer Maken: Nieuw Jupyter Notebook.

  2. In de rechterbovenhoek detecteert en geeft VS Code de versie van Python en de virtuele Python-omgeving weer die is geselecteerd voor het notebook. 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 informatie over de installatie.

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

    import qsharp
    
  4. Voeg een nieuwe cel toe en kopieer de volgende code.

    %%qsharp
    import Std.Arrays.*;
    import Std.Canon.*;
    import Std.Convert.*;
    import Std.Diagnostics.*;
    import Std.Math.*;
    import Std.Measurement.*;
    import Microsoft.Quantum.Unstable.Arithmetic.*;
    import Std.ResourceEstimation.*;
    
    operation RunProgram() : Unit {
        let bitsize = 31;
    
        // When choosing parameters for `EstimateFrequency`, make sure that
        // generator and modules are not co-prime
        let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize);
    }
    
    
    // In this sample we concentrate on costing the `EstimateFrequency`
    // operation, which is the core quantum operation in Shors algorithm, and
    // we omit the classical pre- and post-processing.
    
    /// # Summary
    /// Estimates the frequency of a generator
    /// in the residue ring Z mod `modulus`.
    ///
    /// # Input
    /// ## generator
    /// The unsigned integer multiplicative order (period)
    /// of which is being estimated. Must be co-prime to `modulus`.
    /// ## modulus
    /// The modulus which defines the residue ring Z mod `modulus`
    /// in which the multiplicative order of `generator` is being estimated.
    /// ## bitsize
    /// Number of bits needed to represent the modulus.
    ///
    /// # Output
    /// The numerator k of dyadic fraction k/2^bitsPrecision
    /// approximating s/r.
    operation EstimateFrequency(
        generator : Int,
        modulus : Int,
        bitsize : Int
    )
    : Int {
        mutable frequencyEstimate = 0;
        let bitsPrecision =  2 * bitsize + 1;
    
        // Allocate qubits for the superposition of eigenstates of
        // the oracle that is used in period finding.
        use eigenstateRegister = Qubit[bitsize];
    
        // Initialize eigenstateRegister to 1, which is a superposition of
        // the eigenstates we are estimating the phases of.
        // We first interpret the register as encoding an unsigned integer
        // in little endian encoding.
        ApplyXorInPlace(1, eigenstateRegister);
        let oracle = ApplyOrderFindingOracle(generator, modulus, _, _);
    
        // Use phase estimation with a semiclassical Fourier transform to
        // estimate the frequency.
        use c = Qubit();
        for idx in bitsPrecision - 1..-1..0 {
            within {
                H(c);
            } apply {
                // `BeginEstimateCaching` and `EndEstimateCaching` are the operations
                // exposed by Azure Quantum Resource Estimator. These will instruct
                // resource counting such that the if-block will be executed
                // only once, its resources will be cached, and appended in
                // every other iteration.
                if BeginEstimateCaching("ControlledOracle", SingleVariant()) {
                    Controlled oracle([c], (1 <<< idx, eigenstateRegister));
                    EndEstimateCaching();
                }
                R1Frac(frequencyEstimate, bitsPrecision - 1 - idx, c);
            }
            if MResetZ(c) == One {
                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) {
            nZeroes += 1;
            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

Nu maakt u 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

De qsharp.estimate functie maakt een resultaatobject, dat kan worden gebruikt om een tabel weer te geven met het totale aantal fysieke resources. U kunt kostendetails inspecteren door de groepen uit te vouwen, die meer informatie hebben. Zie de volledige rapportgegevens van de resource-estimator voor meer informatie.

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

Parameter logische qubit Weergegeven als
QEC-schema surface_code
Codeafstand 21
Fysieke qubits 882
Tijd van logische cyclus 8 millisecs
Foutpercentage logische qubit 3.00E-13
Kruising vooraf 0.03
Drempelwaarde voor foutcorrectie 0,01
Formule voor tijd van logische cyclus (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * * codeDistance
Formule voor fysieke qubits 2 * codeDistance * codeDistance

Tip

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

Ruimtediagram

De verdeling 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 zijn het aantal fysieke qubits dat nodig is om het algoritme uit te voeren, 829766, waarvan 196686 algoritme-qubits zijn en waarvan 633080 T factory-qubits zijn.

Schermopname van het ruimtediagram van de resource-estimator.

De standaardwaarden wijzigen en het algoritme schatten

Wanneer u een aanvraag voor een resourceraming voor uw programma indient, kunt u enkele optionele parameters opgeven. Gebruik het jobParams veld om toegang te krijgen tot alle target parameters die kunnen worden doorgegeven aan de taakuitvoering en om te zien 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 foutcode en het foutenbudget 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 QEC-schema (kwantumfoutcorrectie)
  • qubitParams - de parameters van de fysieke qubit
  • constraints - de beperkingen op onderdeelniveau
  • distillationUnitSpecifications - de specificaties voor T factory's destillatiealgoritmen
  • estimateType - enkele of grens

Zie Target de parameters 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)

Kwantumfoutcorrectieschema wijzigen

U kunt de resourceramingstaak opnieuw uitvoeren voor hetzelfde voorbeeld op de qubitparameters op basis van Majorana 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 configuratie van target parameters uitvoeren en de resultaten vergelijken. Dit is handig als 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 QEC-schema van floquet.

    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⁻⁶"])
    
    Modelleren Logische qubits Logische diepte T-statussen Codeafstand T-fabrieken T-fabrieksfractie Fysieke qubits rQOPS Fysieke runtime
    Poort-gebaseerde ns, 10⁻³ 223 3,64M 4,70M 21 19 76.30 % 829,77k 26,55M 31 sec.
    Majorana ns, 10⁻⁶ 223 3,64M 4,70M 5 19 63.02 % 79,60k 148,67M 5 sec.
  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)
    
    Modelleren Logische qubits Logische diepte T-statussen Codeafstand T-fabrieken 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,64M 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,79M 25 sec.
    Poortgebaseerde ns, 10⁻⁴ 223 3,64M 4,70M 9 14 43.17 % 63,57k 61,94M 13 sec.
    Majorana ns, 10⁻⁴ 223 3,64M 4,70M 9 19 82.75 % 501.48k 82,59M 10 sec.
    Majorana ns, 10⁻⁶ 223 3,64M 4,70M 5 13 31.47 % 42.96k 148,67M 5 sec.

Schatting van paretogrens wordt uitgevoerd

Bij het schatten van de resources van een algoritme is het belangrijk om rekening te houden met het verschil tussen het aantal fysieke qubits en de runtime van het algoritme. U kunt overwegen om zoveel mogelijk fysieke qubits toe te kennen 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 grensraming 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 pareto grensraming, 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 grensraming.

    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 de uitvoeringsnaam, het schattingstype, het qubittype, het qec-schema, het 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 combinaties.

Diagram met ruimtetijd

De EstimatesOverview functie geeft ook het ruimte-tijddiagram van de resource-estimator weer.

In het diagram met ruimtetijd ziet u het aantal fysieke qubits en de runtime van het algoritme voor elk {aantal qubits, runtime}-paar. U kunt de muisaanwijzer op elk punt bewegen om de details van de schatting van de resource op dat moment weer te geven.

Schermopname van het ruimte-tijddiagram met een grensraming van de resource-estimator.

Batchverwerking met pareto grensraming

  1. Als u meerdere configuraties van target parameters met grensraming wilt schatten en vergelijken, voegt u deze 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 grensraming 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 grensraming, kunt u de resourceramingen voor een specifiek punt van het tijddiagram zien, dat voor elk {aantal qubits, runtime}-paar is. In de volgende code ziet u bijvoorbeeld het gebruik van schattingsgegevens voor de tweede uitvoering (schattingsindex=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 zien. De volgende code toont bijvoorbeeld het ruimtediagram voor de eerste uitvoering van combinaties (schatting van index=0) en de derde kortste runtime (puntindex=2).

    SpaceChart(result[0], 2)
    

Vereisten voor Qiskit in VS Code

Tip

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

Een nieuw Jupyter-notebook maken

  1. Selecteer in VS Code het > Weergeven en selecteer Maken: Nieuw Jupyter Notebook.
  2. In de rechterbovenhoek detecteert en geeft VS Code de versie van Python en de virtuele Python-omgeving weer die is geselecteerd voor het notebook. 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 informatie over de installatie.

Het kwantumalgoritmen maken

In dit voorbeeld maakt u een kwantumcircuit voor een vermenigvuldiger op basis van de constructie die wordt gepresenteerd in Den Haag-Perez en Garcia-Escartin (arXiv:1411.5949) die gebruikmaakt van de Quantum Fourier Transform om rekenkundige bewerkingen 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, elke grootte van de opgegeven bitwidth, en één uitvoerregister die twee keer de grootte van de opgegeven bitwidthis . Met de functie worden ook enkele logische resourceaantallen afgedrukt voor de vermenigvuldiger die rechtstreeks uit het kwantumcircuit is geëxtraheerd.

from qiskit.circuit.library import RGQFTMultiplier 

def create_algorithm(bitwidth):
    print(f"[INFO] Create a QFT-based multiplier with bitwidth {bitwidth}")

    circ = RGQFTMultiplier(num_state_qubits=bitwidth)

    return circ

Notitie

Als u een Python-kernel selecteert en de qiskit module niet wordt herkend, selecteert u een andere Python-omgeving in de kernelkiezer.

Het kwantumalgoritmen schatten

Maak 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 de estimate-aanroep gebruiken, die overbelast is om een QuantumCircuit-object van Qiskit te accepteren.

from qsharp.estimator import EstimatorParams
from qsharp.interop.qiskit import estimate

params = EstimatorParams()
result = estimate(circ, params)

U kunt ook de ResourceEstimatorBackend gebruiken om de schatting uit te voeren zoals de bestaande back-end dat doet.

from qsharp.interop.qiskit import ResourceEstimatorBackend
from qsharp.estimator import EstimatorParams

params = EstimatorParams()
backend = ResourceEstimatorBackend()

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

Het result-object bevat de uitvoer van de resource-schattingstaak. U kunt de functie EstimateDetails gebruiken om de resultaten weer te geven in een beter leesbare indeling.

from qsharp_widgets import EstimateDetails
EstimateDetails(result)

EstimateDetails functie geeft een tabel weer met het totale aantal fysieke resources. U kunt kostendetails inspecteren door de groepen uit te vouwen, die meer informatie hebben. Zie de volledige rapportgegevens van de resource-estimator voor meer informatie.

Als u bijvoorbeeld de Logische qubitparameters groep uitvouwt, kunt u gemakkelijker zien dat de foutcorrectiecode-afstand 15 is.

Parameter logische qubit Weergegeven als
QEC-schema surface_code
Codeafstand 15
Fysieke qubits 450
Tijd van logische cyclus 6us
Foutpercentage logische qubit 3.00E-10
Kruising vooraf 0.03
Drempelwaarde voor foutcorrectie 0,01
Formule voor tijd van logische cyclus (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * * codeDistance
Formule voor fysieke qubits 2 * codeDistance * codeDistance

In de groep parameters voor fysieke qubits kunt u de eigenschappen van de fysieke qubit zien die zijn aangenomen voor deze schatting. 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 ook toegang krijgen tot de uitvoer van de resource-estimator als een Python-woordenlijst met behulp van de methode result.data(). Als u bijvoorbeeld toegang wilt verkrijgen tot de fysieke tellingen result.data()["physicalCounts"].

Ruimtediagrammen

De verdeling 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.

from qsharp_widgets import SpaceChart

SpaceChart(result)

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

In het ruimtediagram ziet u het aandeel van algoritme-qubits en T Factory-qubits. Houd er rekening mee dat het aantal T-fabriekkopieën, 19, bijdraagt aan het aantal fysieke qubits voor T-fabrieken als $\text{T-fabrieken} \cdot \text{fysieke qubits per T-fabriek} = 19 \cdot 18.000 = 342.000$.

Zie de fysieke schatting van T Factory voor meer informatie.

De standaardwaarden wijzigen en het algoritme schatten

Wanneer u een aanvraag voor een resourceraming 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 Target de parameters 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

qubitParams = {
    "name": "qubit_maj_ns_e6"
}

result = backend.run(circ, qubitParams).result()

U kunt de fysieke tellingen 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 enkele uitleg te geven over hoe de T-fabrieken 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["numUnitsPerRound"][round]} {tfactory["unitNamePerRound"][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)

Kwantumfoutcorrectieschema wijzigen

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

params = {
    "qubitParams": {"name": "qubit_maj_ns_e6"},
    "qecScheme": {"name": "floquet_code"}
}

result_maj_floquet = backend.run(circ, params).result()
EstimateDetails(result_maj_floquet)

Foutbudget wijzigen

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

params = {
    "errorBudget": 0.01,
    "qubitParams": {"name": "qubit_maj_ns_e6"},
    "qecScheme": {"name": "floquet_code"},
}
result_maj_floquet_e1 = backend.run(circ, params).result()
EstimateDetails(result_maj_floquet_e1)

Notitie

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

Volgende stappen