다음을 통해 공유


리소스 추정기를 실행하는 다양한 방법

이 문서에서는 Azure Quantum 리소스 추정기를 사용하는 방법을 알아봅니다. 리소스 추정기를 사용하면 양자 컴퓨터에서 양자 프로그램을 실행하는 데 필요한 리소스를 예측할 수 있습니다. 리소스 추정기를 사용하여 양자 프로그램을 실행하는 데 필요한 큐비트 수, 게이트 수 및 회로 깊이를 예측할 수 있습니다.

리소스 추정기는 Quantum 개발 키트 확장을 사용하여 Visual Studio Code에서 사용할 수 있습니다. 자세한 내용은 Quantum Development Kit설치를 참조하세요.

경고

Azure Portal의 리소스 추정기는 더 이상 사용되지 않습니다. Quantum Development Kit에서 제공하는 Visual Studio Code의 로컬 리소스 추정기로 전환할 것을 권장합니다.

VS Code의 필수 구성 요소

리소스 추정기를 실행하기 위해 Azure 계정이 필요하지 않습니다.

새 Q# 파일 만들기

  1. Visual Studio Code를 열고 파일>새 텍스트 파일을 선택하여 새 파일을 만듭니다.
  2. 파일을 ShorRE.qs로 저장합니다. 이 파일에는 프로그램에 대한 Q# 코드가 포함됩니다.

양자 알고리즘 생성

다음 코드를 파일에 복사합니다 ShorRE.qs .


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

리소스 예측 도구 실행

Resource Estimator는 6개의 미리 정의된 큐비트 매개 변수를 제공하며, 그 중 4개에는 게이트 기반 명령 집합이 있고 2개에는 Majorana 명령 집합이 있습니다. 또한 두 개의 surface_code.

이 예제에서는 큐비트 매개 변수 및 qubit_gate_us_e3 양자 오류 수정 코드를 사용하여 surface_code 리소스 추정기를 실행합니다.

  1. 보기 - 명령 팔레트>Q#: 자원 예측 계산 옵션을 표시해야 하는 "리소스"를 입력합니다. 작업 바로 앞에 표시된 명령 목록에서 추정할 수도 있습니다. 자원 추정기 창을 열려면 이 옵션을 선택합니다.

    코드 렌즈 목록에서 추정 명령을 선택하는 방법을 보여 주는 스크린샷.

  2. 하나 이상의 Qubit 매개 변수 + 오류 수정 코드 형식을 선택하여 리소스를 예측할 수 있습니다. 이 예제에서는 qubit_gate_us_e3 선택하고 확인을 클릭합니다.

    리소스 예측 메뉴에서 큐비트 매개 변수를 선택하는 방법을 보여 주는 스크린샷.

  3. 오류 예산을 지정하거나 기본값 0.001을 적용합니다. 이 예제에서는 기본값을 그대로 두고 Enter 키를 누릅니 .

  4. Enter 키를 눌러 파일 이름(이 경우 ShorRE)에 따라 기본 결과 이름을 적용합니다.

결과 보기

리소스 추정기는 동일한 알고리즘에 대한 여러 예상치를 제공하며, 각 알고리즘은 큐비트 수와 런타임 간의 절충을 보여 줍니다. 런타임과 시스템 규모 간의 장단점 이해는 리소스 예측의 더 중요한 측면 중 하나입니다.

리소스 예측 결과는 Q# 추정 창에 표시됩니다.

  1. 결과 탭에는 리소스 예측에 대한 요약이 표시됩니다. 첫 번째 행 옆의 아이콘 을 클릭하여 표시할 열을 선택합니다. 실행 이름, 예측 형식, 큐비트 유형, qec 체계, 오류 예산, 논리 큐비트, 논리 깊이, 코드 거리, T 상태, T 팩터리, T 팩터리 분수, 런타임, rQOPS 및 실제 큐비트 중에서 선택할 수 있습니다.

    선택한 리소스 예상 출력을 선택하는 메뉴를 표시하는 방법을 보여 주는 스크린샷.

    결과 테이블의 추정 형식 열에서 알고리즘에 대한 {큐비트 수, 런타임}최적 조합 수를 확인할 수 있습니다. 이러한 조합은 시공간 다이어그램에서 볼 수 있습니다.

  2. 시공간 다이어그램실제 큐비트 수와 알고리즘의 런타임 간의 장단점이 표시됩니다. 이 경우 리소스 추정기는 수천 가지 가능한 조합 중 13가지 최적의 조합을 찾습니다. 각 {큐비트 수, 런타임} 지점을 마우스로 가리키면 해당 시점에서 리소스 예측의 세부 정보를 볼 수 있습니다.

    자원 예측 도구의 시공간 다이어그램을 보여 주는 스크린샷

    자세한 내용은 시공간 다이어그램을 참조 하세요.

    참고 항목

    공간 다이어그램과 해당 지점에 해당하는 리소스 예측의 세부 정보를 보려면 {큐비트 수, 런타임} 쌍인 시공간 다이어그램의 한 지점을 클릭해야 합니다.

  3. 공간 다이어그램알고리즘에 사용되는 실제 큐비트와 {수의 큐비트, 런타임} 쌍에 해당하는 T 팩터리 분포를 보여 줍니다. 예를 들어 시공간 다이어그램에서 가장 왼쪽 지점을 선택하는 경우 알고리즘을 실행하는 데 필요한 실제 큐비트 수는 427726 196686 알고리즘 큐비트이고 그 중 231040은 T 팩터리 큐비트입니다.

    Resource Estimator의 공간 다이어그램을 보여 주는 스크린샷.

  4. 마지막으로 자원 예측 탭에는 {수의 큐비트, 런타임} 쌍에 해당하는 자원 예측 도구에 대한 출력 데이터의 전체 목록이 표시됩니다. 더 많은 정보가 있는 그룹을 축소해 비용 세부 정보를 검사할 수 있습니다. 예를 들어 시공간 다이어그램에서 맨 왼쪽 지점을 선택하고 논리 큐비트 매개 변수 그룹을 축소합니다.

    논리적 큐비트 매개 변수
    QEC 체계 surface_code
    코드 거리 21
    물리적 큐비트 882
    논리적 주기 시간 13밀리초
    논리적 큐비트 오류율 3.00E-13
    교차 전인자 0.03
    오류 수정 임계값 0.01
    논리적 주기 시간 수식 (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
    물리적 큐비트 수식 2 * codeDistance * codeDistance

    보고서 데이터의 각 출력에 대한 설명을 표시하려면 자세한 행 표시를 클릭합니다.

    자세한 내용은 리소스 추정기의 전체 보고서 데이터를 참조 하세요.

target 매개 변수 변경

다른 큐비트 유형, 오류 수정 코드 및 오류 예산을 사용하여 동일한 Q# 프로그램의 비용을 예측할 수 있습니다. 보기 -> 명령 팔레트를 선택하여 리소스 추정기 창을 열고 입력Q#: Calculate Resource Estimates합니다.

Majorana 기반 큐비트 매개 변수 qubit_maj_ns_e6와 같은 다른 구성을 선택합니다. 기본 오류 예산 값을 적용하거나 새 예산 값을 입력하고 Enter 키를 누릅니 . 리소스 추정기는 새 target 매개 변수를 사용하여 추정을 다시 실행합니다.

자세한 내용은 리소스 예측 도구에 대한 매개 변수Target 하세요.

매개 변수의 여러 구성 실행

Azure Quantum Resource Estimator는 여러 매개 변수 구성을 target 실행하고 리소스 예측 결과를 비교할 수 있습니다.

  1. 보기 - 명령 팔레트>하거나 Ctrl+Shift+P를 누른 다음 입력합니다.Q#: Calculate Resource Estimates

  2. qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4 + floquet_code 선택하고 qubit_maj_ns_e6 + floquet_code 선택하고 확인을 클릭합니다.

  3. 기본 오류 예산 값 0.001을 적용하고 Enter 키를 누릅니 .

  4. Enter 키를 눌러 입력 파일(이 경우 ShorRE.qs)을 수락합니다.

  5. 여러 매개 변수 구성의 경우 결과는 결과 탭의 다른 행에 표시됩니다.

  6. 시공간 다이어그램매개 변수의 모든 구성에 대한 결과를 보여 줍니다. 결과 테이블의 첫 번째 열에는 매개 변수의 각 구성에 대한 범례가 표시됩니다. 각 지점을 마우스로 가리키면 해당 시점에서 리소스 예측의 세부 정보를 볼 수 있습니다.

    리소스 추정기에서 여러 매개 변수 구성을 실행할 때의 시공간 다이어그램 및 결과 테이블을 보여 주는 스크린샷

  7. 시공간 다이어그램의 {수의 큐비트, 런타임} 지점을 클릭하여 해당 공간 다이어그램을 표시하고 데이터를 보고합니다.

VS Code의 Jupyter Notebook에 대한 필수 구성 요소

리소스 추정기를 실행하기 위해 Azure 계정이 필요하지 않습니다.

양자 알고리즘 생성

  1. VS Code에서 명령 팔레트 보기를 > 선택하고 만들기: 새 Jupyter Notebook을 선택합니다.

  2. 오른쪽 위에서 VS Code는 Notebook에 대해 선택된 Python 및 가상 Python 환경의 버전을 검색하고 표시합니다. 여러 Python 환경이 있는 경우 오른쪽 위에 있는 커널 선택기를 사용하여 커널을 선택해야 할 수 있습니다. 환경이 검색되지 않은 경우 VS Code의 Jupyter Notebook에서 설정 정보를 참조하세요.

  3. Notebook의 첫 번째 셀에서 패키지를 가져옵니다 qsharp .

    import qsharp
    
  4. 새 셀을 추가하고 다음 코드를 복사합니다.

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

양자 알고리즘 예측

이제 기본 가정을 사용하여 작업에 대한 RunProgram 실제 리소스를 예측합니다. 새 셀을 추가하고 다음 코드를 복사합니다.

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

qsharp.estimate 함수는 전체 물리적 리소스 수가 있는 테이블을 표시하는 데 사용할 수 있는 결과 개체를 만듭니다. 추가 정보가 있는 그룹을 확장하여 비용 세부 정보를 검사할 수 있습니다. 자세한 내용은 리소스 추정기의 전체 보고서 데이터를 참조 하세요.

예를 들어 논리 큐비트 매개 변수 그룹을 확장하여 코드 거리가 21이고 실제 큐비트 수가 882인지 확인합니다.

논리적 큐비트 매개 변수
QEC 체계 surface_code
코드 거리 21
물리적 큐비트 882
논리적 주기 시간 8밀리초
논리적 큐비트 오류율 3.00E-13
교차 전인자 0.03
오류 수정 임계값 0.01
논리적 주기 시간 수식 (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
물리적 큐비트 수식 2 * codeDistance * codeDistance

더 간결한 버전의 출력 테이블을 보려면 result.summary를 사용할 수 있습니다.

공간 다이어그램

알고리즘 및 T 팩터리에 사용되는 실제 큐비트의 분포는 알고리즘 디자인에 영향을 미칠 수 있는 요소입니다. 패키지를 사용하여 qsharp-widgets 이 분포를 시각화하여 알고리즘의 예상 공간 요구 사항을 더 잘 이해할 수 있습니다.

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

이 예제에서는 알고리즘을 실행하는 데 필요한 실제 큐비트 수가 829766 196686 알고리즘 큐비트이고 그 중 633080은 T 팩터리 큐비트입니다.

자원 예측 도구의 공간 다이어그램을 보여 주는 스크린샷

기본값 변경 및 알고리즘 예측

프로그램에 대한 리소스 예측 요청을 제출할 때 필요에 따라 몇 가지 매개 변수를 지정할 수 있습니다. 필드를 jobParams 사용하여 작업 실행에 전달할 수 있는 모든 target 매개 변수에 액세스하고 어떤 기본값이 가정되었는지 확인합니다.

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

Resource Estimator에서 qubit_gate_ns_e3 큐비트 모델, surface_code 오류 수정 코드 및 0.001 오류 예산을 예측의 기본값으로 사용하는 것을 볼 수 있습니다.

사용자 지정할 수 있는 매개 변수는 다음과 같습니다 target .

  • errorBudget - 알고리즘에 대해 허용되는 전체 오류 예산
  • qecScheme - QEC(양자 오류 수정) 체계
  • qubitParams - 물리적 큐비트 매개 변수
  • constraints - 구성 요소 수준의 제약 조건
  • distillationUnitSpecifications - T 팩터리 증류 알고리즘에 대한 사양
  • estimateType - 단일 또는 프론티어

자세한 내용은 리소스 예측 도구에 대한 매개 변수Target 하세요.

큐비트 모델 변경

Majorana 기반 큐비트 매개 변수 qubitParams인 "qubit_maj_ns_e6"을 사용하여 동일한 알고리즘에 대한 비용을 예측할 수 있습니다.

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

양자 오류 수정 체계 변경

Floquet QEC 체계 qecScheme을 사용하여 Majorana 기반 큐비트 매개 변수에서 동일한 예에 대한 리소스 예측 작업을 다시 실행할 수 있습니다.

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

오류 예산 변경

다음으로 errorBudget 10%로 동일한 양자 회로를 다시 실행합니다.

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

리소스 추정기를 사용하여 일괄 처리

Azure Quantum 리소스 추정기를 사용하면 여러 매개 변수 구성 target 을 실행하고 결과를 비교할 수 있습니다. 이러한 기능은 다양한 큐비트 모델의 비용, QEC 스키마 또는 오류 예산을 비교하려는 경우에 유용합니다.

  1. 매개 변수 목록을 함수의 target 매개 변수에 전달하여 일괄 처리 추정을 paramsqsharp.estimate 수행할 수 있습니다. 예를 들어 기본 매개 변수와 Floquet QEC 스키마를 사용하여 Majorana 기반 큐비트 매개 변수를 사용하여 동일한 알고리즘을 실행합니다.

    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⁻⁶"])
    
    모델 논리 큐비트 논리 깊이 T 상태 코드 거리 T 팩터리 T 팩터리 분수 물리적 큐비트 rQOPS 물리적 런타임
    게이트 기반 ns, 10⁻³ 223 3.64M 4.70M 21 19 76.30 % 829.77k 26.55M 31초
    Majorana ns, 10⁻⁶ 223 3.64M 4.70M 5 19 63.02 % 79.60k 148.67M 5초
  2. 클래스EstimatorParams 수도 있습니다.

    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)
    
    모델 논리 큐비트 논리 깊이 T 상태 코드 거리 T 팩터리 T 팩터리 분수 물리적 큐비트 rQOPS 물리적 런타임
    게이트 기반 μs, 10⁻5 223 3.64M 4.70M 17 13 40.54% 216.77k 21.86k 10시간
    게이트 기반 µs, 10⁻⁴ 223 3.64M 4.70M 9 14 43.17% 63.57k 41.30k 5시간
    게이트 기반 ns, 10⁻³ 223 3.64M 4.70M 17 16 69.08% 416.89k 32.79M 25초
    게이트 기반 ns, 10⁻⁴ 223 3.64M 4.70M 9 14 43.17% 63.57k 61.94M 13초
    Majorana ns, 10⁻⁴ 223 3.64M 4.70M 9 19 82.75% 501.48k 82.59M 10초
    Majorana ns, 10⁻⁶ 223 3.64M 4.70M 5 13 31.47% 42.96k 148.67M 5초

파레토 프론티어 예측 실행

알고리즘의 리소스를 추정할 때는 실제 큐비트 수와 알고리즘의 런타임 간의 절충을 고려해야 합니다. 알고리즘의 런타임을 줄이기 위해 가능한 한 많은 실제 큐비트를 할당하는 것을 고려할 수 있습니다. 그러나 물리적 큐비트의 수는 양자 하드웨어에서 사용할 수 있는 물리적 큐비트의 수로 제한됩니다.

Pareto 프론티어 예측동일한 알고리즘에 대한 여러 예상치를 제공하며, 각각 큐비트 수와 런타임 간의 장단점이 있습니다.

  1. Pareto 프론티어 추정을 사용하여 리소스 추정기를 실행하려면 매개 변수를 "estimateType"target .로 "frontier"지정해야 합니다. 예를 들어 Pareto 프론티어 추정을 사용하여 표면 코드를 사용하여 Majorana 기반 큐비트 매개 변수를 사용하여 동일한 알고리즘을 실행합니다.

    result = qsharp.estimate("RunProgram()", params=
                                {"qubitParams": { "name": "qubit_maj_ns_e4" },
                                "qecScheme": { "name": "surface_code" },
                                "estimateType": "frontier", # frontier estimation
                                }
                            )
    
  2. 이 함수를 EstimatesOverview 사용하여 전체 실제 리소스 수가 포함된 테이블을 표시할 수 있습니다. 첫 번째 행 옆의 아이콘을 클릭하여 표시할 열을 선택합니다. 실행 이름, 예측 형식, 큐비트 유형, qec 체계, 오류 예산, 논리 큐비트, 논리 깊이, 코드 거리, T 상태, T 팩터리, T 팩터리 분수, 런타임, rQOPS 및 실제 큐비트 중에서 선택할 수 있습니다.

    from qsharp_widgets import EstimatesOverview
    EstimatesOverview(result)
    

결과 테이블의 추정 형식 열에서 알고리즘에 대한 {큐비트 수, 런타임}의 다양한 조합 수를 볼 수 있습니다. 이 경우 리소스 추정기는 수천 가지 가능한 조합 중에서 22가지 최적의 조합을 찾습니다.

시공간 다이어그램

이 함수는 EstimatesOverview 리소스 추정기의 시공간 다이어그램 도 표시합니다.

시공간 다이어그램은 각 {큐비트 수, 런타임} 쌍에 대한 알고리즘의 실제 큐비트 수와 런타임을 보여 줍니다. 각 지점을 마우스로 가리키면 해당 시점에서 리소스 예측의 세부 정보를 볼 수 있습니다.

자원 추정기의 경계 예측값이 있는 시공간 다이어그램을 보여 주는 스크린샷

파레토 프론티어 추정을 사용하여 일괄 처리

  1. 여러 매개 변수 구성을 target 예측하고 비교하려면 매개 변수를 추가 "estimateType": "frontier", 합니다.

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

    Pareto 프론티어 예측 및 여러 매개 변수 구성을 사용하는 경우 리소스 추정기의 시공간 다이어그램을 보여 주는 스크린샷.

    참고 항목

    함수를 사용하여 EstimatesOverview 큐비트 시간 다이어그램의 색을 정의하고 이름을 실행할 수 있습니다.

  2. Pareto 프론티어 추정을 사용하여 여러 매개 변수 구성 target 을 실행하는 경우 각 {큐비트 수, 런타임} 쌍에 해당하는 시공간 다이어그램의 특정 지점에 대한 리소스 예상치를 볼 수 있습니다. 예를 들어 다음 코드는 두 번째(추정 인덱스=0) 실행 및 네 번째(지점 인덱스=3) 최단 런타임에 대한 예상 세부 정보 사용량을 보여 줍니다.

    EstimateDetails(result[1], 4)
    
  3. 시공간 다이어그램의 특정 지점에 대한 공간 다이어그램을 볼 수도 있습니다. 예를 들어 다음 코드는 조합의 첫 번째 실행(인덱스=0 추정) 및 세 번째로 짧은 런타임(점 인덱스=2)에 대한 공간 다이어그램을 보여 줍니다.

    SpaceChart(result[0], 2)
    

Qiskit을 위한 VS Code의 사전 요구사항

  • Python 및 Pip가 설치된 Python 환경

  • 최신 버전의 Visual Studio Code는 웹Visual Studio Code를 또는 엽니다.

  • Quantum Development Kit, PythonJupyter 확장이 설치된 VS Code입니다.

  • 최신 Azure Quantum qsharpqsharp_widgetsqiskit 패키지입니다.

    python -m pip install --upgrade qsharp qsharp_widgets qiskit
    

    또는

    !pip install --upgrade qsharp qsharp_widgets qiskit
    

리소스 추정기를 실행하기 위해 Azure 계정이 필요하지 않습니다.

새 Jupyter Notebook 만들기

  1. VS Code에서 명령 팔레트 보기를 > 선택하고 만들기: 새 Jupyter Notebook을 선택합니다.
  2. 오른쪽 위에서 VS Code는 Notebook에 대해 선택된 Python 및 가상 Python 환경의 버전을 검색하고 표시합니다. 여러 Python 환경이 있는 경우 오른쪽 위에 있는 커널 선택기를 사용하여 커널을 선택해야 할 수 있습니다. 환경이 검색되지 않은 경우 VS Code의 Jupyter Notebook에서 설정 정보를 참조하세요.

양자 알고리즘 생성

이 예제에서는 양자 푸리에 변환을 사용하여 산술을 구현하는 Ruiz-Perez 및 Garcia-Escartin(arXiv:1411.5949)에 제시된 생성을 기반으로 승수에 대한 양자 회로를 만듭니다.

변수를 변경 bitwidth 하여 승수의 크기를 조정할 수 있습니다. 회로 생성은 승수 값으로 호출할 수 있는 함수에 bitwidth 래핑됩니다. 작업에는 지정된 크기의 두 개의 입력 레지스터와 지정된 bitwidth크기의 두 배 bitwidth인 하나의 출력 레지스터가 있습니다. 또한 이 함수는 양자 회로에서 직접 추출된 승수에 대한 몇 가지 논리 리소스 수를 출력합니다.

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

참고 항목

Python 커널을 선택하고 qiskit 모듈이 인식되지 않는 경우 커널 선택기에서 다른 Python 환경을 선택해 보세요.

양자 알고리즘 예측

함수를 사용하여 알고리즘의 인스턴스를 만듭니다 create_algorithm . 변수를 변경 bitwidth 하여 승수의 크기를 조정할 수 있습니다.

bitwidth = 4

circ = create_algorithm(bitwidth)

기본 가정을 사용하여 이 작업의 실제 리소스를 예측합니다. 오버로드된 estimate 호출을 사용하여 Qiskit의 QuantumCircuit 개체를 수락할 수 있습니다.

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

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

또는 ResourceEstimatorBackend 사용하여 기존 백 엔드와 마찬가지로 추정을 수행할 수 있습니다.

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

params = EstimatorParams()
backend = ResourceEstimatorBackend()

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

result 개체에는 리소스 예측 작업의 출력이 포함됩니다. EstimateDetails 함수를 사용하여 결과를 더 읽기 쉬운 형식으로 표시할 수 있습니다.

from qsharp_widgets import EstimateDetails
EstimateDetails(result)

EstimateDetails 함수는 전체 물리적 리소스 수가 있는 테이블을 표시합니다. 추가 정보가 있는 그룹을 확장하여 비용 세부 정보를 검사할 수 있습니다. 자세한 내용은 리소스 추정기의 전체 보고서 데이터를 참조 하세요.

예를 들어 논리 큐비트 매개 변수 그룹을 확장하면 오류 수정 코드 거리가 15임을 더 쉽게 확인할 수 있습니다.

논리적 큐비트 매개 변수
QEC 체계 surface_code
코드 거리 15
물리적 큐비트 450
논리적 주기 시간 6us
논리적 큐비트 오류율 3.00E-10
교차 전인자 0.03
오류 수정 임계값 0.01
논리적 주기 시간 수식 (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
물리적 큐비트 수식 2 * codeDistance * codeDistance

실제 큐비트 매개 변수 그룹에서 이 추정에 대해 가정된 실제 큐비트 속성을 볼 수 있습니다. 예를 들어 단일 큐비트 측정 및 단일 큐비트 게이트를 수행하는 시간이 각각 100ns 및 50ns로 가정됩니다.

result.data() 메서드를 사용하여 리소스 추정기의 출력을 Python 사전으로 액세스할 수도 있습니다. 예를 들어 물리적 수량에 접근하려면 result.data()["physicalCounts"].

공간 다이어그램

알고리즘 및 T 팩터리에 사용되는 실제 큐비트의 분포는 알고리즘 디자인에 영향을 미칠 수 있는 요소입니다. 이 분포를 시각화하여 알고리즘의 예상 공간 요구 사항을 더 잘 이해할 수 있습니다.

from qsharp_widgets import SpaceChart

SpaceChart(result)

알고리즘 큐비트와 T 팩터리 큐비트 간의 총 실제 큐비트 분포를 보여 주는 원형 다이어그램 T 팩터리 복사본 수와 T 팩터리당 실제 큐비트 수를 분석한 테이블이 있습니다.

공간 다이어그램은 알고리즘 큐비트와 T 팩터리 큐비트의 비율을 보여 줍니다. T 팩토리 사본의 수(19)는 T 팩토리의 실제 큐비트 수에 기여합니다. 즉, $\text{T 팩토리} \cdot \text{T 팩토리당 실제 큐비트 수} = 19 \cdot 18,000 = 342,000$입니다.

자세한 내용은 T 팩터리 물리적 추정을 참조 하세요.

기본값 변경 및 알고리즘 예측

프로그램에 대한 리소스 예측 요청을 제출할 때 필요에 따라 몇 가지 매개 변수를 지정할 수 있습니다. 필드를 jobParams 사용하여 작업 실행에 전달할 수 있는 모든 값에 액세스하고 어떤 기본값이 가정되었는지 확인합니다.

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

사용자 지정할 수 있는 매개 변수는 다음과 같습니다 target .

자세한 내용은 리소스 예측 도구에 대한 매개 변수Target 하세요.

큐비트 모델 변경

다음으로 Majorana 기반 큐비트 매개 변수를 사용하여 동일한 알고리즘에 대한 비용을 예측합니다. qubit_maj_ns_e6

qubitParams = {
    "name": "qubit_maj_ns_e6"
}

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

물리적 개수를 프로그래밍 방식으로 검사할 수 있습니다. 예를 들어 알고리즘을 실행하기 위해 만든 T 팩터리에 대한 세부 정보를 탐색할 수 있습니다.

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

참고 항목

기본적으로 런타임은 나노초로 표시됩니다.

이 데이터를 사용하여 T 팩터리에서 필요한 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["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)

양자 오류 수정 체계 변경

이제 Floqued QEC 스키마 qecScheme를 사용하여 Majorana 기반 큐비트 매개 변수에서 동일한 예제에 대한 리소스 예측 작업을 다시 실행합니다.

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

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

오류 예산 변경

10%의 동일한 양자 회로를 errorBudget 다시 실행해 보겠습니다.

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)

참고 항목

리소스 예측 도구로 작업하는 동안 문제가 발생하는 경우 문제 해결 페이지를 확인하거나 문의하세요AzureQuantumInfo@microsoft.com.

다음 단계