Condividi tramite


Diversi modi per eseguire Lo strumento di stima delle risorse

Questo articolo illustra come usare Lo strumento di stima delle risorse di Azure Quantum. Lo strumento di stima delle risorse consente di stimare le risorse necessarie per eseguire un programma quantistico in un computer quantistico. È possibile usare Lo strumento di stima delle risorse per stimare il numero di qubit, il numero di cancelli e la profondità del circuito necessario per eseguire un programma quantistico.

Resource Estimator è disponibile in Visual Studio Code con l'estensione Quantum Development Kit. Per ulteriori informazioni, vedere Installare il Kit di Sviluppo Quantum.

Avvertimento

Lo strumento di stima delle risorse nel portale di Azure è deprecato. È consigliabile passare allo strumento di stima delle risorse locale in Visual Studio Code fornito in Quantum Development Kit.

Prerequisiti per VS Code

Suggerimento

Non è necessario avere un account Azure per eseguire Lo strumento di stima delle risorse.

Creare un nuovo file Q#

  1. Aprire Visual Studio Code e selezionare File > Nuovo file di testo per creare un nuovo file.
  2. Salvare il file come ShorRE.qs. Questo file conterrà il codice Q# per il programma.

Creare l'algoritmo quantistico

Copiare il codice seguente nel ShorRE.qs file :


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

Eseguire lo strumento di stima delle risorse

Resource Estimator offre sei parametri qubit predefiniti, quattro dei quali hanno set di istruzioni basati su gate e due con un set di istruzioni Majorana. Offre anche due codici di correzione degli errori quantistici e surface_codefloquet_code.

In questo esempio si esegue l'oggetto Resource Estimator usando il qubit_gate_us_e3 parametro qubit e il surface_code codice di correzione degli errori quantistici.

  1. Selezionare Visualizza -> Riquadro comandi e digitare "risorsa" che dovrebbe visualizzare l'opzione Q#: Calculate Resource Estimates (Calcola stime risorse). È anche possibile fare clic su Stima nell'elenco dei comandi visualizzati subito prima dell'operazione Main . Selezionare questa opzione per aprire la finestra Stima risorse.

    Screenshot che mostra come selezionare il comando di stima dall'elenco di obiettivo del codice.

  2. È possibile selezionare uno o più tipi di codice Qubit + Correzione errori per stimare le risorse. Per questo esempio, selezionare qubit_gate_us_e3 e fare clic su OK.

    Screenshot che mostra come selezionare il parametro qubit dal menu di stima delle risorse.

  3. Specificare il budget degli errori o accettare il valore predefinito 0,001. Per questo esempio, lasciare il valore predefinito e premere INVIO.

  4. Premere INVIO per accettare il nome del risultato predefinito in base al nome file, in questo caso ShorRE.

Visualizzare i risultati

Lo strumento di stima delle risorse fornisce più stime per lo stesso algoritmo, ognuna delle quali mostra i compromessi tra il numero di qubit e il runtime. Comprendere il compromesso tra runtime e scalabilità di sistema è uno degli aspetti più importanti della stima delle risorse.

Il risultato della stima delle risorse viene visualizzato nella finestra Stima Q#.

  1. Nella scheda Risultati viene visualizzato un riepilogo della stima delle risorse. Fare clic sull'icona accanto alla prima riga per selezionare le colonne da visualizzare. È possibile scegliere tra nome di esecuzione, tipo di stima, tipo di qubit, schema qec, budget degli errori, qubit logici, profondità logica, distanza del codice, stati T, T factory, frazione di T factory, runtime, rQOPS e qubit fisici.

    Screenshot che mostra come visualizzare il menu per selezionare gli output di stima delle risorse desiderati.

    Nella colonna Tipo di stima della tabella dei risultati è possibile visualizzare il numero di combinazioni ottimali di {numero di qubit, runtime} per l'algoritmo. Queste combinazioni possono essere visualizzate nel diagramma dello spazio-tempo.

  2. Il diagramma spazio-tempo mostra i compromessi tra il numero di qubit fisici e il runtime dell'algoritmo. In questo caso, lo strumento di stima delle risorse trova 13 diverse combinazioni ottimali su molte migliaia di possibili. È possibile passare il puntatore del mouse su ogni {numero di qubit, runtime} per visualizzare i dettagli della stima delle risorse in quel punto.

    Screenshot che mostra il diagramma spazio-tempo dell'oggetto Resource Estimator.

    Per altre informazioni, vedere Diagramma spazio-tempo.

    Nota

    È necessario fare clic su un punto del diagramma spaziale, ovvero una coppia {numero di qubit, runtime} per visualizzare il diagramma spaziale e i dettagli della stima delle risorse corrispondente a tale punto.

  3. Il diagramma spaziale mostra la distribuzione dei qubit fisici usati per l'algoritmo e le factory T, corrispondenti a una coppia {numero di qubit, runtime}. Ad esempio, se si seleziona il punto più a sinistra nel diagramma dello spazio-tempo, il numero di qubit fisici necessari per eseguire l'algoritmo è 427726, 196686 di cui sono qubit di algoritmo e 231040 di cui sono qubit di T factory.

    Screenshot che mostra il diagramma spaziale dello strumento di stima delle risorse.

  4. Infine, nella scheda Stime risorse viene visualizzato l'elenco completo dei dati di output per l'oggetto Resource Estimator corrispondente a una coppia di {numero di qubit, runtime} . È possibile controllare i dettagli dei costi comprimendo i gruppi, che includono altre informazioni. Ad esempio, selezionare il punto più a sinistra nel diagramma spazio-tempo e comprimere il gruppo di parametri qubit logici .

    Parametro qubit logico Valore
    Schema Correzione degli errori quantistici surface_code
    Distanza di codice 21
    Qubit fisici 882
    Tempo ciclo logico 13 millisecs
    Frequenza di errore del qubit logico 3.00E-13
    Attraversamento del prefactoring 0.03
    Soglia di correzione degli errori 0,01
    Formula tempo del ciclo logico (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
    Formula qubit fisici 2 * codeDistance * codeDistance

    Suggerimento

    Fare clic su Mostra righe dettagliate per visualizzare la descrizione di ogni output dei dati del report.

    Per altre informazioni, vedere i dati completi del report di Resource Estimator.

Modificare i target parametri

È possibile stimare il costo per lo stesso programma Q# usando altri tipi di qubit, codice di correzione degli errori e budget degli errori. Aprire la finestra Stima risorse selezionando Visualizza -> Riquadro comandi e digitare Q#: Calculate Resource Estimates.

Selezionare qualsiasi altra configurazione, ad esempio il parametro qubit basato su Majorana, qubit_maj_ns_e6. Accettare il valore predefinito del budget degli errori o immetterne uno nuovo e premere INVIO. Lo strumento di stima delle risorse esegue nuovamente la stima con i nuovi target parametri.

Per altre informazioni, vedere Target parametri per Lo strumento di stima delle risorse.

Eseguire più configurazioni di parametri

Azure Quantum Resource Estimator può eseguire più configurazioni di target parametri e confrontare i risultati della stima delle risorse.

  1. Selezionare Visualizza -> Riquadro comandi oppure premere CTRL+MAIUSC+P e digitare Q#: Calculate Resource Estimates.

  2. Selezionare qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4 + floquet_code e qubit_maj_ns_e6 + floquet_code e fare clic su OK.

  3. Accettare il valore predefinito del budget di errore 0,001 e premere INVIO.

  4. Premere INVIO per accettare il file di input, in questo caso ShorRE.qs.

  5. Nel caso di più configurazioni di parametri, i risultati vengono visualizzati in righe diverse nella scheda Risultati .

  6. Il diagramma Spazio-tempo mostra i risultati per tutte le configurazioni dei parametri. La prima colonna della tabella dei risultati visualizza la legenda per ogni configurazione dei parametri. È possibile passare il puntatore del mouse su ogni punto per visualizzare i dettagli della stima delle risorse in quel punto.

    Screenshot che mostra il diagramma spazio-tempo e la tabella dei risultati durante l'esecuzione di più configurazioni di parametro in Resource Estimator.

  7. Fare clic su un punto {number of qubits, runtime} (Numero di qubit, runtime) del diagramma spazio-tempo per visualizzare i dati corrispondenti del diagramma spaziale e del report.

Prerequisiti per Jupyter Notebook in VS Code

Suggerimento

Non è necessario avere un account Azure per eseguire Lo strumento di stima delle risorse.

Creare l'algoritmo quantistico

  1. In VS Code, selezionare Visualizza > Riquadro comandi e selezionare Crea: Nuovo Jupyter Notebook.

  2. In alto a destra VS Code rileverà e visualizzerà la versione di Python e l'ambiente Python virtuale selezionato per il notebook. Se si dispone di più ambienti Python, potrebbe essere necessario selezionare un kernel usando la selezione kernel in alto a destra. Se non è stato rilevato alcun ambiente, vedere Jupyter Notebooks in VS Code per informazioni sull'installazione.

  3. Nella prima cella del notebook importare il pacchetto qsharp.

    import qsharp
    
  4. Aggiungere una nuova cella e copiare il codice seguente.

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

Stimare l'algoritmo quantistico

Stimare ora le risorse fisiche per l'operazione RunProgram usando i presupposti predefiniti. Aggiungere una nuova cella e copiare il codice seguente.

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

La funzione qsharp.estimate crea un oggetto risultato, che può essere usato per visualizzare una tabella con il conto complessivo delle risorse fisiche. È possibile esaminare i dettagli dei costi espandendo i gruppi che contengono altre informazioni. Per altre informazioni, vedere i dati completi del report di Resource Estimator.

Ad esempio, espandi il gruppo dei parametri qubit logici per verificare che la distanza del codice sia 21 e il numero di qubit fisici sia 882.

Parametro qubit logico Valore
Schema Correzione degli errori quantistici surface_code
Distanza di codice 21
Qubit fisici 882
Tempo ciclo logico 8 millisecs
Frequenza di errore del qubit logico 3.00E-13
Attraversamento del prefactoring 0.03
Soglia di correzione degli errori 0,01
Formula tempo del ciclo logico (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Formula qubit fisici 2 * codeDistance * codeDistance

Suggerimento

Per una versione più compatta della tabella di output, è possibile usare result.summary.

Diagramma spaziale

La distribuzione dei qubit fisici usati per l'algoritmo e le factory T è un fattore che può influire sulla progettazione dell'algoritmo. È possibile usare il pacchetto qsharp-widgets per visualizzare questa distribuzione per comprendere meglio i requisiti di spazio stimati per l'algoritmo.

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

In questo esempio, il numero di qubit fisici necessari per eseguire l'algoritmo è 829766, di cui 196686 sono qubit di algoritmo e 633080 sono qubit di T factory.

Screenshot che mostra il diagramma dello spazio dello strumento di stima delle risorse.

Modificare i valori predefiniti e stimare l'algoritmo

Quando si invia una richiesta di stima delle risorse per il programma, è possibile specificare alcuni parametri facoltativi. Usare il jobParams campo per accedere a tutti i target parametri che possono essere passati all'esecuzione del processo e verificare quali valori predefiniti sono stati presupposti:

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

È possibile notare che l'oggetto Strumento di stima delle risorse accetta il modello qubit qubit_gate_ns_e3, il codice di correzione degli errori surface_code e il budget degli errori 0,001 come valori predefiniti per la stima.

Questi sono i target parametri che è possibile personalizzare:

  • errorBudget: il budget complessivo degli errori consentito per l'algoritmo
  • qecScheme: schema di correzione degli errori quantistici (QEC)
  • qubitParams: parametri qubit fisici
  • constraints: i vincoli a livello di componente
  • distillationUnitSpecifications: le specifiche per gli algoritmi di crittografia delle factory T
  • estimateType: singola o frontiera

Per altre informazioni, vedere Target parametri per Lo strumento di stima delle risorse.

Modificare il modello qubit

È possibile stimare il costo per lo stesso algoritmo usando il parametro qubit basato su Majorana, qubitParams, "qubit_maj_ns_e6".

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

Modificare lo schema di correzione degli errori quantistici

È possibile rieseguire il processo di stima delle risorse per lo stesso esempio nei parametri qubit basati su Majorana con uno schema QEC floqued, qecScheme.

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

Modificare il budget degli errori

Eseguire quindi di nuovo lo stesso circuito quantistico con un valore errorBudget pari al 10%.

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

Invio in batch con lo strumento di stima delle risorse

Azure Quantum Resource Estimator consente di eseguire più configurazioni di target parametri e confrontare i risultati. Ciò è utile quando si vuole confrontare il costo di modelli qubit diversi, schemi QEC o budget di errore.

  1. È possibile eseguire una stima batch passando un elenco di target parametri al params parametro della qsharp.estimate funzione. Ad esempio, eseguire lo stesso algoritmo con i parametri predefiniti e i parametri qubit basati su Majorana con uno schema QEC 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⁻⁶"])
    
    Modello Qubit logici Profondità logica T states Distanza di codice T factory Frazione T factory Qubit fisici rQOPS Runtime fisico
    Basato su gate ns 10⁻³ 223 3,64 M 4.70M 21 19 76.30 % 829.77k 26,55 M 31 sec
    Majorana ns 10⁻⁶ 223 3,64 M 4.70M 5 19 63.02 % 79.60k 148.67M 5 sec
  2. È anche possibile costruire un elenco di parametri di stima usando la EstimatorParams classe .

    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)
    
    Modello Qubit logici Profondità logica T states Distanza di codice T factory Frazione T factory Qubit fisici rQOPS Runtime fisico
    Basato su gate µs 10⁻³ 223 3,64M 4.70M 17 13 40.54 % 216.77k 21,86 k 10 ore
    Basato su gate µs 10⁻⁴ 223 3,64 M 4.70M 9 14 43.17 % 63,57 k 41.30k 5 ore
    Basato su gate ns 10⁻³ 223 3,64M 4.70M 17 16 69.08 % 416.89k 32,79M 25 sec
    Basato su gate ns 10⁻⁴ 223 3,64M 4.70M 9 14 43.17 % 63,57 k 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

Esecuzione della stima della frontiera Pareto

Quando si stimano le risorse di un algoritmo, è importante considerare il compromesso tra il numero di qubit fisici e il runtime dell'algoritmo. È possibile considerare l'allocazione del maggior numero possibile di qubit fisici per ridurre il runtime dell'algoritmo. Tuttavia, il numero di qubit fisici è limitato dal numero di qubit fisici disponibili nell'hardware quantistico.

La stima della frontiera Pareto fornisce più stime per lo stesso algoritmo, ognuna con un compromesso tra il numero di qubit e il runtime.

  1. Per eseguire Lo strumento di stima delle risorse usando la stima della frontiera Pareto, è necessario specificare il "estimateType"target parametro come "frontier". Ad esempio, eseguire lo stesso algoritmo con i parametri qubit basati su Majorana con un codice di superficie usando la stima della frontiera Pareto.

    result = qsharp.estimate("RunProgram()", params=
                                {"qubitParams": { "name": "qubit_maj_ns_e4" },
                                "qecScheme": { "name": "surface_code" },
                                "estimateType": "frontier", # frontier estimation
                                }
                            )
    
  2. È possibile usare la EstimatesOverview funzione per visualizzare una tabella con i conteggi complessivi delle risorse fisiche. Fare clic sull'icona accanto alla prima riga per selezionare le colonne da visualizzare. È possibile scegliere tra nome di esecuzione, tipo di stima, tipo di qubit, schema qec, budget degli errori, qubit logici, profondità logica, distanza del codice, stati T, T factory, frazione di T factory, runtime, rQOPS e qubit fisici.

    from qsharp_widgets import EstimatesOverview
    EstimatesOverview(result)
    

Nella colonna Tipo di stima della tabella dei risultati è possibile visualizzare il numero di combinazioni diverse di {numero di qubit, runtime} per l'algoritmo. In questo caso, Lo strumento di stima delle risorse trova 22 combinazioni ottimali diverse tra molte migliaia di possibili.

Diagramma spazio-tempo

La EstimatesOverview funzione visualizza anche il diagramma spazio-tempo di Stima risorse.

Il diagramma dello spazio-tempo mostra il numero di qubit fisici e il runtime dell'algoritmo per ogni coppia {numero di qubit, runtime}. È possibile passare il puntatore del mouse su ogni punto per visualizzare i dettagli della stima delle risorse in quel punto.

Screenshot che mostra il diagramma dello spazio-tempo con la stima della frontiera dello strumento di stima delle risorse.

Invio in batch con stima della frontiera Pareto

  1. Per stimare e confrontare più configurazioni di target parametri con la stima della frontiera, aggiungere "estimateType": "frontier", ai parametri .

    result = qsharp.estimate(
        "RunProgram()",
        [
            {
            "qubitParams": { "name": "qubit_maj_ns_e4" },
            "qecScheme": { "name": "surface_code" },
            "estimateType": "frontier", # Pareto frontier estimation
            },
            {
            "qubitParams": { "name": "qubit_maj_ns_e6" },
            "qecScheme": { "name": "floquet_code" },
            "estimateType": "frontier", # Pareto frontier estimation
            },
        ]
    )
    
    EstimatesOverview(result, colors=["#1f77b4", "#ff7f0e"], runNames=["e4 Surface Code", "e6 Floquet Code"])
    

    Screenshot che mostra il diagramma dello spazio-tempo dello strumento di stima delle risorse quando si usa la stima della frontiera Pareto e più configurazioni di parametri.

    Nota

    È possibile definire i colori ed eseguire i nomi per il diagramma di qubit-time usando la EstimatesOverview funzione .

  2. Quando si eseguono più configurazioni di target parametri usando la stima della frontiera Pareto, è possibile visualizzare le stime delle risorse per un punto specifico del diagramma dello spazio-tempo, vale a dire per ogni coppia {numero di qubit, runtime}. Ad esempio, il codice seguente mostra l'utilizzo dei dettagli della stima per la seconda esecuzione (stima index=0) e il quarto runtime (indice punto=3) più breve.

    EstimateDetails(result[1], 4)
    
  3. È anche possibile visualizzare il diagramma spaziale per un punto specifico del diagramma dello spazio-tempo. Ad esempio, il codice seguente mostra il diagramma spaziale per la prima esecuzione di combinazioni (stima index=0) e il terzo runtime più breve (indice punto=2).

    SpaceChart(result[0], 2)
    

Prerequisiti per Qiskit in VS Code

Suggerimento

Non è necessario avere un account Azure per eseguire Lo strumento di stima delle risorse.

Creare un nuovo notebook di Jupyter

  1. In VS Code, selezionare Visualizza > Riquadro comandi e selezionare Crea: Nuovo Jupyter Notebook.
  2. In alto a destra VS Code rileverà e visualizzerà la versione di Python e l'ambiente Python virtuale selezionato per il notebook. Se si dispone di più ambienti Python, potrebbe essere necessario selezionare un kernel usando la selezione kernel in alto a destra. Se non è stato rilevato alcun ambiente, vedere Jupyter Notebooks in VS Code per informazioni sull'installazione.

Creare l'algoritmo quantistico

In questo esempio viene creato un circuito quantistico per un moltiplicatore in base alla costruzione presentata in Conversion-Perez e Garcia-Escartin (arXiv:1411.5949) che usa la trasformazione Quantum Fourier per implementare l'aritmetica.

È possibile modificare le dimensioni del moltiplicatore modificando la bitwidth variabile. La generazione del circuito viene sottoposta a wrapping in una funzione che può essere chiamata con il bitwidth valore del moltiplicatore. L'operazione avrà due registri di input, ognuna delle dimensioni dell'oggetto specificato bitwidthe un registro di output che corrisponde al doppio delle dimensioni dell'oggetto specificato bitwidth. La funzione stampa anche alcuni conteggi delle risorse logiche per il moltiplicatore estratto direttamente dal circuito quantistico.

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

Nota

Se si seleziona un kernel Python e il modulo qiskit non viene riconosciuto, provare a selezionare un ambiente Python diverso nel selettore di kernel.

Stimare l'algoritmo quantistico

Creare un'istanza dell'algoritmo usando la create_algorithm funzione . È possibile modificare le dimensioni del moltiplicatore modificando la bitwidth variabile.

bitwidth = 4

circ = create_algorithm(bitwidth)

Stimare le risorse fisiche per questa operazione usando i presupposti predefiniti. È possibile utilizzare la chiamata estimate, che è sovraccaricata per accettare un oggetto QuantumCircuit da Qiskit.

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

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

In alternativa, è possibile usare il ResourceEstimatorBackend per eseguire la stima come fa il back-end esistente.

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

params = EstimatorParams()
backend = ResourceEstimatorBackend()

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

L'oggetto result contiene l'output del processo di stima delle risorse. È possibile usare la funzione EstimateDetails per visualizzare i risultati in un formato più leggibile.

from qsharp_widgets import EstimateDetails
EstimateDetails(result)

La funzione EstimateDetails visualizza una tabella con i conteggi complessivi delle risorse fisiche. È possibile esaminare i dettagli dei costi espandendo i gruppi che contengono altre informazioni. Per altre informazioni, vedere i dati completi del report di Resource Estimator.

Ad esempio, se espandi il gruppo parametri qubit logici, è possibile vedere più facilmente che la distanza del codice di correzione degli errori è 15.

Parametro qubit logico Valore
Schema Correzione degli errori quantistici surface_code
Distanza di codice 15
Qubit fisici 450
Tempo ciclo logico 6us
Frequenza di errore del qubit logico 3.00E-10
Attraversamento del prefactoring 0.03
Soglia di correzione degli errori 0,01
Formula tempo del ciclo logico (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Formula qubit fisici 2 * codeDistance * codeDistance

Nel gruppo Parametri qubit fisici è possibile visualizzare le proprietà qubit fisiche che sono state considerate per questa stima. Ad esempio, il tempo per eseguire una misurazione a qubit singolo e un controllo a qubit singolo vengono considerati rispettivamente 100 ns e 50 ns.

Suggerimento

È anche possibile accedere all'output di Resource Estimator come dizionario Python usando il metodo result.data(). Ad esempio, per accedere ai conteggi fisici result.data()["physicalCounts"].

Diagrammi spazi

La distribuzione dei qubit fisici usati per l'algoritmo e le factory T è un fattore che può influire sulla progettazione dell'algoritmo. È possibile visualizzare questa distribuzione per comprendere meglio i requisiti di spazio stimati per l'algoritmo.

from qsharp_widgets import SpaceChart

SpaceChart(result)

Diagramma a torta che mostra la distribuzione dei qubit fisici totali tra qubit di algoritmo e qubit di T factory. È disponibile una tabella con la suddivisione del numero di copie factory T e il numero di qubit fisici per ogni factory T.

Il diagramma spaziale mostra la proporzione di qubit di algoritmo e qubit di T factory. Si noti che il numero di copie di fabbriche T, 19, contribuisce al numero di qubit fisici per le fabbriche T secondo l'equazione: $\text{fabbriche T} \cdot \text{qubit fisici per fabbrica T}= 19 \cdot 18.000 = 342.000$.

Per altre informazioni, vedere Stima fisica della factory T.

Modificare i valori predefiniti e stimare l'algoritmo

Quando si invia una richiesta di stima delle risorse per il programma, è possibile specificare alcuni parametri facoltativi. Usare il jobParams campo per accedere a tutti i valori che possono essere passati all'esecuzione del processo e verificare quali valori predefiniti sono stati considerati:

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

Questi sono i target parametri che è possibile personalizzare:

Per altre informazioni, vedere Target parametri per Lo strumento di stima delle risorse.

Modificare il modello qubit

Successivamente, stimare il costo per lo stesso algoritmo usando il parametro qubit basato su Majorana qubit_maj_ns_e6

qubitParams = {
    "name": "qubit_maj_ns_e6"
}

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

È possibile esaminare i conteggi fisici a livello di codice. Ad esempio, è possibile esplorare i dettagli sulla factory T creata per eseguire l'algoritmo.

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

Nota

Per impostazione predefinita, il runtime viene visualizzato in nanosecondi.

È possibile usare questi dati per produrre alcune spiegazioni del modo in cui le factory T producono gli stati T necessari.

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)

Modificare lo schema di correzione degli errori quantistici

Eseguire di nuovo il processo di stima delle risorse per lo stesso esempio sui parametri qubit basati su Majorana con uno schema QEC floqued, qecScheme.

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

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

Modificare il budget degli errori

Eseguire di nuovo lo stesso circuito quantistico con un valore errorBudget pari al 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)

Nota

Se si verifica un problema durante l'uso dello strumento di stima delle risorse, consultare la pagina Risoluzione dei problemi o contattare AzureQuantumInfo@microsoft.com.

Passaggi successivi