Různé způsoby spuštění Nástroje pro posouzení prostředků

V tomto článku se dozvíte, jak pracovat s nástrojem pro posouzení prostředků Azure Quantum. Estimátor prostředků je k dispozici ve VS Code i online v Azure Portal.

Následující tabulka ukazuje různé způsoby spuštění nástroje pro posouzení prostředků.

Uživatelský scénář Platforma Kurz
Odhad prostředků programu q# Visual Studio Code V horní části stránky vyberte Q# ve VS Code .
Odhad prostředků programu q# (pokročilé) Jupyter Notebook v editoru Visual Studio Code Nahoře na stránce vyberte Q# v Jupyter Notebook.
Odhad prostředků programu Qiskit Portál Azure Quantum V horní části stránky vyberte Qiskit v Azure Portal.
Odhad prostředků programu QIR Portál Azure Quantum Odeslat QIR
Použití souborů FCIDUMP jako parametrů argumentu (pokročilé) Visual Studio Code Odeslání problému s kvantovou chemií

Poznámka

Sada Microsoft Quantum Development Kit (Classic QDK) už nebude po 30. červnu 2024 podporována. Pokud jste stávající vývojář sady QDK, doporučujeme přejít na novou sadu Azure Quantum Development Kit (Moderní QDK) a pokračovat ve vývoji kvantových řešení. Další informace najdete v tématu Migrace kódu Q# do moderní sady QDK.

Požadavky pro VS Code

Tip

Ke spuštění místního nástroje pro posouzení prostředků nemusíte mít účet Azure.

Vytvoření nového souboru Q#

  1. Otevřete Visual Studio Code a vyberte Soubor > Nový textový soubor a vytvořte nový soubor.
  2. Uložte soubor jako ShorRE.qs. Tento soubor bude obsahovat kód Q# pro váš program.

Vytvoření kvantového algoritmu

Zkopírujte do ShorRE.qs souboru následující kód:

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

Spuštění estimátoru prostředků

Estimátor prostředků nabízí šest předdefinovaných parametrů qubitu, z nichž čtyři mají sady instrukcí založené na bráně a dva, které mají instrukční sadu Majorana. Nabízí také dva kódy pro opravu kvantových chyb, surface_code a floquet_code.

V tomto příkladu spustíte estimátor prostředků pomocí parametru qubitu qubit_gate_us_e3surface_code a kódu opravy kvantových chyb.

  1. Vyberte Zobrazení –> Paleta příkazů nebo stiskněte Kombinaci kláves Ctrl+Shift+P a zadejte "zdroj", což by mělo vyvolat možnost Q#: Výpočet odhadů zdrojů . Tuto možnost vyberte, pokud chcete otevřít okno Nástroje pro posouzení prostředků.
  2. K odhadu prostředků můžete vybrat jeden nebo více typů kódu Parametr Qubitu + Oprava chyb . V tomto příkladu vyberte qubit_gate_us_e3 a klikněte na OK.
  3. Zadejte rozpočet chyby nebo přijměte výchozí hodnotu 0.001. V tomto příkladu ponechte výchozí hodnotu a stiskněte Enter.
  4. Stisknutím klávesy Enter přijměte výchozí název výsledku na základě názvu souboru, v tomto případě ShorRE.

Zobrazení výsledků

Estimátor prostředků poskytuje několik odhadů pro stejný algoritmus, přičemž každý z nich ukazuje kompromisy mezi počtem qubitů a modulem runtime. Pochopení kompromisu mezi modulem runtime a škálováním systému je jedním z nejdůležitějších aspektů odhadu prostředků.

Výsledek odhadu prostředků se zobrazí v okně Odhad Q # .

  1. Na kartě Výsledky se zobrazí souhrn odhadu prostředků. Kliknutím na ikonu vedle prvního řádku vyberte sloupce, které chcete zobrazit. Můžete si vybrat z názvu spuštění, typu odhadu, typu qubitu, schématu qec, rozpočtu chyb, logických qubitů, logické hloubky, vzdálenosti kódu, stavů T, T factory, zlomku T factory, modulu runtime, rQOPS a fyzických qubitů.

    Snímek obrazovky znázorňující, jak zobrazit nabídku pro výběr výstupů odhadu prostředků podle vašeho výběru

    Ve sloupci Typ odhadu tabulky výsledků vidíte počet optimálních kombinací {počet qubitů, modul runtime} pro váš algoritmus. Tyto kombinace jsou vidět v prostoroprostorovém diagramu.

  2. Prostoročasový diagram znázorňuje kompromisy mezi počtem fyzických qubitů a modulem běhu algoritmu. V tomto případě nástroj pro posouzení prostředků najde 13 různých optimálních kombinací z mnoha tisíců možných. Když najedete myší na každý bod {počet qubitů, modul runtime}, zobrazí se podrobnosti o odhadu prostředků v tomto bodě.

    Snímek obrazovky znázorňující prostorový diagram nástroje pro posouzení prostředků

    Další informace najdete v tématu Prostoročasový diagram.

    Poznámka

    Pokud chcete zobrazit prostorový diagram a podrobnosti odhadu prostředků odpovídající danému bodu, musíte kliknout na jeden bod prostorového diagramu, kterým je dvojice {počet qubitů, modul runtime}.

  3. Prostorový diagram znázorňuje rozdělení fyzických qubitů použitých pro algoritmus a T factory, které odpovídají {počtu qubitů, modulu runtime}. Pokud například vyberete bod nejvíce vlevo v časoprostorovém diagramu, počet fyzických qubitů potřebných ke spuštění algoritmu se 427726, z nichž 196686 jsou qubity algoritmu a 231040 jsou qubity T factory.

    Snímek obrazovky znázorňující prostorový diagram nástroje pro posouzení prostředků

  4. Nakonec se na kartě Odhady prostředků zobrazí úplný seznam výstupních dat pro estimátor prostředků odpovídající páru {počet qubitů, modul runtime} . Podrobnosti o nákladech můžete zkontrolovat tak, že sbalíte skupiny, které obsahují další informace. Vyberte například v prostoroprostorovém diagramu bod úplně vlevo a sbalte skupinu Parametry logického qubitu .

    Logický parametr qubitu Hodnota
    Schéma QEC surface_code
    Vzdálenost kódu 21
    Fyzické qubity 882
    Čas logického cyklu 13 milisecs
    Míra chyb logického qubitu 3.00E-13
    Překračování předfaktorem 0.03
    Prahová hodnota opravy chyb 0,01
    Vzorec času logického cyklu (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
    Vzorec fyzických qubitů 2 * codeDistance * codeDistance

    Tip

    Kliknutím na Zobrazit podrobné řádky zobrazíte popis každého výstupu dat sestavy.

    Další informace najdete v úplných datech sestavy nástroje Pro posouzení prostředků.

target Změna parametrů

Náklady na stejný program v Q# můžete odhadnout pomocí jiného typu qubitu, kódu opravy chyb a rozpočtu chyb. Otevřete okno Resource Estimator (Estimátor prostředků) tak, že vyberete View - Command Palette (Zobrazit –> paleta příkazů) a zadáteQ#: Calculate Resource Estimates .

Vyberte jakoukoli jinou konfiguraci, například parametr qubitu založený na majoraně qubit_maj_ns_e6. Přijměte výchozí chybovou hodnotu rozpočtu nebo zadejte novou a stiskněte Enter. Estimátor prostředků znovu spustí odhad s novými target parametry.

Další informace najdete v tématu Cílové parametry pro nástroj pro posouzení prostředků.

Spuštění více konfigurací parametrů

Azure Quantum Resource Estimator může spustit několik konfigurací target parametrů a porovnat výsledky odhadu prostředků.

  1. Vyberte Zobrazení –> Paleta příkazů nebo stiskněte Ctrl+Shift+P a zadejte Q#: Calculate Resource Estimates.

  2. Vyberte qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4 + floquet_code a qubit_maj_ns_e6 + floquet_code a klikněte na OK.

  3. Přijměte výchozí hodnotu rozpočtu chyby 0,001 a stiskněte Enter.

  4. Stisknutím klávesy Enter přijměte vstupní soubor, v tomto případě ShorRE.qs.

  5. V případě více konfigurací parametrů se výsledky zobrazí v různých řádcích na kartě Výsledky .

  6. Prostoročasový diagram zobrazuje výsledky pro všechny konfigurace parametrů. V prvním sloupci tabulky výsledků se zobrazí legenda pro každou konfiguraci parametrů. Když najedete myší na jednotlivé body, zobrazí se podrobnosti o odhadu prostředků v daném bodě.

    Snímek obrazovky znázorňující prostoročasový diagram a tabulku výsledků při spuštění více konfigurací parametru v nástroji Pro posouzení prostředků

  7. Kliknutím na {počet qubitů, modul runtime} v časoprostorovém diagramu zobrazíte odpovídající prostorový diagram a data sestavy.

Požadavky na Jupyter Notebook v editoru VS Code

Tip

Ke spuštění místního nástroje pro posouzení prostředků nemusíte mít účet Azure.

Vytvoření kvantového algoritmu

  1. Ve VS Code vyberte Zobrazit > paletu příkazů a vyberte Vytvořit: Nový Jupyter Notebook.

  2. V pravém horním rohu nástroj VS Code rozpozná a zobrazí verzi Pythonu a virtuální prostředí Pythonu vybrané pro poznámkový blok. Pokud máte více prostředí Pythonu, možná budete muset vybrat jádro pomocí nástroje pro výběr jádra v pravém horním rohu. Pokud se žádné prostředí nezjistilo, informace o nastavení najdete v tématu Poznámkové bloky Jupyter ve VS Code .

  3. V první buňce poznámkového bloku naimportujte qsharp balíček.

    import qsharp
    
  4. Přidejte novou buňku a zkopírujte následující kód.

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

Odhad kvantového algoritmu

Teď pomocí výchozích předpokladů odhadnete fyzické prostředky pro RunProgram operaci. Přidejte novou buňku a zkopírujte následující kód.

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

Funkce qsharp.estimate vytvoří objekt výsledku, který lze použít k zobrazení tabulky s celkovými počty fyzických prostředků. Podrobnosti o nákladech můžete zkontrolovat tak, že sbalíte skupiny, které obsahují další informace. Další informace najdete v úplných datech sestavy nástroje Pro posouzení prostředků.

Například sbalte skupinu logických parametrů qubitu , abyste viděli, že vzdálenost kódu je 21 a počet fyzických qubitů je 882.

Logický parametr qubitu Hodnota
Schéma QEC surface_code
Vzdálenost kódu 21
Fyzické qubity 882
Čas logického cyklu 8 milisecs
Míra chyb logického qubitu 3.00E-13
Překračování předfaktorem 0.03
Prahová hodnota opravy chyb 0,01
Vzorec času logického cyklu (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Vzorec fyzických qubitů 2 * codeDistance * codeDistance

Tip

Pro kompaktnější verzi výstupní tabulky můžete použít result.summary.

Diagram prostoru

Rozdělení fyzických qubitů používaných pro algoritmus a T factory je faktor, který může mít vliv na návrh vašeho algoritmu. Balíček můžete použít qsharp-widgets k vizualizaci této distribuce, abyste lépe pochopili odhadované požadavky na místo pro algoritmus.

from qsharp_widgets import SpaceChart, EstimateDetails
SpaceChart(result)

V tomto příkladu je počet fyzických qubitů potřebných ke spuštění algoritmu 829766, 196686 z nichž jsou qubity algoritmů a 633080 jsou qubity T factory.

Snímek obrazovky znázorňující prostorový diagram nástroje pro posouzení prostředků

Změna výchozích hodnot a odhad algoritmu

Při odesílání žádosti o odhad prostředků pro váš program můžete zadat některé volitelné parametry. Pomocí pole jobParams získáte přístup ke všem parametrům target , které je možné předat spuštění úlohy, a zjistíte, které výchozí hodnoty se předpokládaly:

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

Vidíte, že estimátor prostředků přebírá qubit_gate_ns_e3 jako výchozí hodnoty pro odhad model qubitu, surface_code kód opravy chyb a rozpočet chyby 0,001.

Tyto parametry je target možné přizpůsobit:

  • errorBudget – celkový povolený rozpočet chyb pro algoritmus
  • qecScheme – schéma oprav kvantových chyb (QEC)
  • qubitParams – parametry fyzického qubitu
  • constraints – omezení na úrovni komponent
  • distillationUnitSpecifications - specifikace algoritmů destilace v továrnách T
  • estimateType - jediná nebo hraniční

Další informace najdete v tématu Cílové parametry pro nástroj pro posouzení prostředků.

Změna modelu qubitu

Náklady na stejný algoritmus můžete odhadnout pomocí parametru qubitu založeného na majoraně qubitParams, "qubit_maj_ns_e6".

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

Změna schématu oprav kvantových chyb

Pro stejný příklad můžete znovu spustit úlohu odhadu prostředků u parametrů qubitu založených na majora s floqued QEC schématem qecScheme.

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

Změna rozpočtu chyb

Pak znovu spusťte stejný kvantový obvod s hodnotou errorBudget 10 %.

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

Dávkování pomocí estimátoru prostředků

Estimátor prostředků Azure Quantum umožňuje spustit více konfigurací target parametrů a porovnat výsledky. To je užitečné, když chcete porovnat náklady na různé modely qubitů, schémata QEC nebo rozpočty chyb.

  1. Odhad dávky můžete provést předáním seznamu target parametrů parametru paramsqsharp.estimate funkce. Například spusťte stejný algoritmus s výchozími parametry a parametry qubitu na bázi majorany s floqued QEC schématem.

    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⁻⁶"])
    
    Modelování Logické qubity Logická hloubka Stavy T Vzdálenost kódu T factory T factory zlomek Fyzické qubity rQOPS Fyzický modul runtime
    Ns založené na hradlach, 10⁻³ 223 3,64M 4,70M 21 19 76.30 % 829,77 tisíc 26,55M 31 sekund
    Majorana ns, 10⁻⁶ 223 3,64M 4,70M 5 19 63.02 % 79,60 tisíc 148,67M 5 sekund
  2. Pomocí třídy můžete také vytvořit seznam parametrů odhaduEstimatorParams.

    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)
    
    Modelování Logické qubity Logická hloubka Stavy T Vzdálenost kódu T factory T factory zlomek Fyzické qubity rQOPS Fyzický modul runtime
    μs na bázi hradla, 10⁻³ 223 3,64M 4,70M 17 13 40.54 % 216,77 tisíc 21,86 tisíc 10 hodin
    μs na bázi hradla, 10⁻⁴ 223 3,64M 4,70M 9 14 43.17 % 63,57 tisíc 41,30 tisíc 5 hodin
    Ns na bázi hradla, 10⁻³ 223 3,64M 4,70M 17 16 69.08 % 416.89 tisíc 32,79M 25 sekund
    Brána ns, 10⁻⁴ 223 3,64M 4,70M 9 14 43.17 % 63,57 tisíc 61,94M 13 sekund
    Majorana ns, 10⁻⁴ 223 3,64M 4,70M 9 19 82.75 % 501,48 tisíc 82,59M 10 sekund
    Majorana ns, 10⁻⁶ 223 3,64M 4,70M 5 13 31.47 % 42,96 tisíc 148,67M 5 sekund

Spuštění paretovského odhadu hranice

Při odhadování prostředků algoritmu je důležité zvážit kompromis mezi počtem fyzických qubitů a modulem runtime algoritmu. Můžete zvážit přidělení co největšího počtu fyzických qubitů, abyste snížili běh algoritmu. Počet fyzických qubitů je však omezený počtem fyzických qubitů dostupných na kvantovém hardwaru.

Paretův odhad hranice poskytuje více odhadů pro stejný algoritmus, z nichž každý má kompromis mezi počtem qubitů a modulem runtime.

  1. Pokud chcete spustit Nástroj pro odhad prostředků pomocí Paretova odhadu hranice, musíte zadat "estimateType"target parametr jako "frontier". Například spusťte stejný algoritmus s parametry qubitu založenými na Majoraně s kódem povrchu pomocí Paretova odhadu hranice.

    result = qsharp.estimate("RunProgram()", params=
                                {"qubitParams": { "name": "qubit_maj_ns_e4" },
                                "qecScheme": { "name": "surface_code" },
                                "estimateType": "frontier", # frontier estimation
                                }
                            )
    
  2. Pomocí funkce můžete EstimatesOverview zobrazit tabulku s celkovým počtem fyzických prostředků. Kliknutím na ikonu vedle prvního řádku vyberte sloupce, které chcete zobrazit. Můžete vybírat z názvu spuštění, typu odhadu, typu qubitu, schématu qec, rozpočtu chyb, logických qubitů, logických qubitů, logické hloubky, vzdálenosti kódu, stavů T, T factory, T factory, zlomku továrny T, modulu runtime, rQOPS a fyzických qubitů.

    from qsharp_widgets import EstimatesOverview
    EstimatesOverview(result)
    

Ve sloupci Typ odhadu tabulky výsledků vidíte počet různých kombinací {number of qubits, runtime} pro váš algoritmus. V tomto případě nástroj Resource Estimator najde 22 různých optimálních kombinací z mnoha tisíců možných kombinací.

Prostoročasový diagram

Funkce EstimatesOverview také zobrazí prostorový diagram nástroje Pro posouzení prostředků.

Diagram časoprostoru znázorňuje počet fyzických qubitů a modul runtime algoritmu pro každou dvojici {number of qubits, runtime}. Když najedete myší na každý bod, zobrazí se podrobnosti o odhadu prostředků v daném bodě.

Snímek obrazovky znázorňující prostoročasový diagram s odhadem hranice nástroje Pro posouzení prostředků

Dávkování s paretovým odhadem hranice

  1. Pokud chcete odhadnout a porovnat více konfigurací target parametrů s odhadem hranice, přidejte "estimateType": "frontier", k parametrům .

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

    Snímek obrazovky znázorňující prostorový diagram estimátoru prostředků při použití odhadu paretovské hranice a více konfigurací parametrů

    Poznámka

    Pomocí funkce můžete definovat barvy a názvy spuštění pro qubitový časový diagram EstimatesOverview .

  2. Při spouštění více konfigurací parametrů pomocí paretova target odhadu hranice můžete zobrazit odhady prostředků pro konkrétní bod prostoročasového diagramu, tj. pro každou dvojici {počet qubitů, modul runtime}. Následující kód například ukazuje podrobnosti o využití odhadu pro druhý (odhad index=0) a čtvrtý (index bodu=3) nejkratší běh.

    EstimateDetails(result[1], 4)
    
  3. Můžete si také prohlédnout prostorový diagram pro konkrétní bod prostoroprostorového diagramu. Následující kód například ukazuje prostorový diagram pro první spuštění kombinací (odhad index=0) a třetí nejkratší běh (bodový index=2).

    SpaceChart(result[0], 2)
    

Předpoklady pro Qiskit

Povolení nástroje Pro posouzení target prostředků Azure Quantum ve vašem pracovním prostoru

Estimátor prostředků je target poskytovatelem služby Microsoft Quantum Computing. Pokud jste vytvořili pracovní prostor od vydání nástroje pro posouzení prostředků, automaticky se do vašeho pracovního prostoru přidal poskytovatel Microsoft Quantum Computing.

Pokud používáte existující pracovní prostor Azure Quantum:

  1. Otevřete pracovní prostor v Azure Portal.
  2. Na levém panelu v části Operace vyberte Poskytovatelé.
  3. Vyberte + Přidat poskytovatele.
  4. Vyberte + Přidat pro Microsoft Quantum Computing.
  5. Vyberte Learn & Vývoj a vyberte Přidat.

Vytvoření nového poznámkového bloku v pracovním prostoru

  1. Přihlaste se k Azure Portal a vyberte svůj pracovní prostor Azure Quantum.
  2. V části Operace vyberte Poznámkové bloky.
  3. Klikněte na Moje poznámkové bloky a klikněte na Přidat nový.
  4. V části Typ jádra vyberte IPython.
  5. Zadejte název souboru a klikněte na Vytvořit soubor.

Když se nový poznámkový blok otevře, automaticky vytvoří kód pro první buňku na základě informací o vašem předplatném a pracovním prostoru.

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

Poznámka

Pokud není uvedeno jinak, měli byste každou buňku spouštět v pořadí, v jakém je vytváříte, aby nedocházelo k problémům s kompilací.

Kliknutím na trojúhelníkové ikony "přehrát" nalevo od buňky spusťte kód.

Načtení požadovaných importů

Nejprve budete muset importovat další moduly z azure-quantum a qiskit.

Kliknutím na + Kód přidejte novou buňku a pak přidejte a spusťte následující kód:

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

Připojení ke službě Azure Quantum

Dále pomocí objektu workspace z předchozí buňky vytvořte objekt AzureQuantumProvider pro připojení k pracovnímu prostoru Azure Quantum. Vytvoříte instanci back-endu a nastavíte resource Estimator jako .target

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

Vytvoření kvantového algoritmu

V tomto příkladu vytvoříte kvantový obvod pro násobitel na základě konstrukce uvedené v tématu Ruiz-Perez a Garcia-Escartin (arXiv:1411.5949), který k implementaci aritmetiky používá kvantovou Fourierovou transformaci.

Velikost násobitele můžete upravit změnou bitwidth proměnné. Generování okruhu je zabaleno do funkce, kterou lze volat s bitwidth hodnotou násobitele. Operace bude mít dva vstupní registry, každý velikost zadaného bitwidtha jeden výstupní registr, který je dvakrát větší než zadaný bitwidthregistr . Funkce také vytiskne některé logické počty prostředků pro násobitel extrahovaný přímo z kvantového okruhu.

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

Poznámka

Úlohy odhadu fyzických prostředků můžete odeslat pro algoritmy, které nemají žádné stavy T, ale mají alespoň jedno měření.

Odhad kvantového algoritmu

Vytvořte instanci algoritmu pomocí create_algorithm funkce . Velikost násobitele můžete upravit změnou bitwidth proměnné.

bitwidth = 4

circ = create_algorithm(bitwidth)

Odhadněte fyzické prostředky pro tuto operaci pomocí výchozích předpokladů. Okruh můžete odeslat do back-endu estimátoru run prostředků pomocí metody a pak spuštěním příkazu job.result() počkat na dokončení úlohy a vrácení výsledků.

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

Tím se vytvoří tabulka, která zobrazuje celkový počet fyzických prostředků. Podrobnosti o nákladech můžete zkontrolovat tak, že sbalíte skupiny, které obsahují další informace.

Tip

Pro kompaktnější verzi výstupní tabulky můžete použít result.summary.

Pokud například sbalíte skupinu parametrů logického qubitu , snadněji uvidíte, že vzdálenost kódu opravy chyb je 15.

Logický parametr qubitu Hodnota
Schéma QEC surface_code
Vzdálenost kódu 15
Fyzické qubity 450
Čas logického cyklu 6us
Míra chyb logického qubitu 3,00E-10
Překračování předfaktorem 0.03
Prahová hodnota opravy chyb 0,01
Vzorec času logického cyklu (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Vzorec fyzických qubitů 2 * codeDistance * codeDistance

Ve skupině Parametry fyzického qubitu můžete vidět vlastnosti fyzického qubitu, které byly pro tento odhad převzaty. Například doba potřebná k provedení měření jednoho qubitu a brány s jedním qubitem se předpokládá jako 100 ns a 50 ns.

Tip

K výstupu Nástroje pro posouzení prostředků můžete přistupovat také jako ke slovníku Pythonu pomocí metody result.data().

Další informace najdete v úplném seznamu výstupních dat pro Nástroj pro posouzení prostředků.

Diagramy prostorů

Rozdělení fyzických qubitů používaných pro algoritmus a T factory je faktor, který může mít vliv na návrh vašeho algoritmu. Tuto distribuci můžete vizualizovat, abyste lépe pochopili odhadované požadavky na místo pro algoritmus.

result.diagram.space

Výsečový diagram znázorňující rozdělení celkového počtu fyzických qubitů mezi qubity algoritmů a qubity T factory K dispozici je tabulka s rozpisem počtu kopií T factory a počtu fyzických qubitů na T factory.

Prostorový diagram znázorňuje poměr qubitů algoritmů a qubitů továrny T. Všimněte si, že počet kopií T factory, 28, přispívá k počtu fyzických qubitů pro továrny T jako $\text{T factory} \cdot \text{fyzický qubit na T factory}= 28 \cdot 18 000 = 504 000$.

Další informace najdete v tématu Fyzický odhad T factory.

Změna výchozích hodnot a odhad algoritmu

Při odesílání žádosti o odhad prostředků pro váš program můžete zadat některé volitelné parametry. Pomocí pole jobParams získáte přístup ke všem hodnotám, které lze předat provádění úlohy, a zjistíte, které výchozí hodnoty se předpokládaly:

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

Tyto parametry je target možné přizpůsobit:

Další informace najdete v tématu Cílové parametry pro nástroj pro posouzení prostředků.

Změna modelu qubitu

Dále pomocí parametru qubitu založeného na Majoraně odhadněte náklady na stejný algoritmus. qubit_maj_ns_e6

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

Fyzické počty můžete kontrolovat programově. Můžete například prozkoumat podrobnosti o objektu pro vytváření T, který byl vytvořen pro spuštění algoritmu.

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

Poznámka

Ve výchozím nastavení se modul runtime zobrazuje v nanosekundách.

Tato data můžete použít k vytvoření některých vysvětlení toho, jak továrny T vytvářejí požadované stavy T.

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)

Změna schématu oprav kvantových chyb

Teď znovu spusťte úlohu odhadu prostředků pro stejný příklad pro parametry qubitu založeného na Majoraně s floqued QEC schématem qecScheme.

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

Změna rozpočtu chyb

Pojďme znovu spustit stejný kvantový obvod s errorBudget 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

Poznámka

Pokud při práci s nástrojem pro posouzení prostředků narazíte na nějaký problém, podívejte se na stránku Řešení potíží nebo se obraťte na AzureQuantumInfo@microsoft.com.

Další kroky