Diferentes maneiras de executar o Avaliador de Recursos
Neste artigo, você aprenderá a trabalhar com o Avaliador de Recursos do Azure Quantum. O Avaliador de Recursos está disponível no VS Code e online em portal do Azure.
A tabela a seguir mostra as diferentes maneiras de executar o Avaliador de Recursos.
Cenário do usuário | Plataforma | Tutorial |
---|---|---|
Estimar os recursos de um programa Q# | Visual Studio Code | Selecione Q# no VS Code na parte superior da página |
Estimar os recursos de um programa Q# (avançado) | Jupyter Notebook em Visual Studio Code | Selecione Q# em Jupyter Notebook na parte superior da página |
Estimar os recursos de um programa qiskit | Portal do Azure Quantum | Selecione Qiskit em portal do Azure na parte superior da página |
Estimar os recursos de um programa QIR | Portal do Azure Quantum | Enviar QIR |
Usar arquivos FCIDUMP como parâmetros de argumento (avançado) | Visual Studio Code | Enviar um problema de química quântica |
Observação
O Microsoft Quantum Development Kit (QDK Clássico) não terá mais suporte após 30 de junho de 2024. Se você for um desenvolvedor de QDK existente, recomendamos fazer a transição para o novo QDK (Kit de Desenvolvimento Quântico do Azure) para continuar desenvolvendo soluções quânticas. Para obter mais informações, consulte Migrar seu código Q# para o QDK moderno.
Pré-requisitos para o VS Code
- A versão mais recente do Visual Studio Code ou abrir o VS Code na Web.
- A versão mais recente da extensão do Kit de Desenvolvimento do Azure Quantum . Para obter detalhes de instalação, consulte Instalando o QDK moderno no VS Code.
Dica
Você não precisa ter uma conta do Azure para executar o Avaliador de Recursos local.
Criar um novo arquivo Q#
- Abra Visual Studio Code e selecione Arquivo > Novo Arquivo de Texto para criar um novo arquivo.
- Salve o arquivo como
ShorRE.qs
. Esse arquivo conterá o código Q# do programa.
Criar o algoritmo quântico
Copie o seguinte código no arquivo ShorRE.qs
:
namespace Shors {
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Measurement;
open Microsoft.Quantum.Unstable.Arithmetic;
open Microsoft.Quantum.ResourceEstimation;
@EntryPoint()
operation RunProgram() : Unit {
let bitsize = 31;
// When chooseing parameters for `EstimateFrequency`, make sure that
// generator and modules are not co-prime
let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize);
}
// In this sample we concentrate on costing the `EstimateFrequency`
// operation, which is the core quantum operation in Shors algorithm, and
// we omit the classical pre- and post-processing.
/// # Summary
/// Estimates the frequency of a generator
/// in the residue ring Z mod `modulus`.
///
/// # Input
/// ## generator
/// The unsigned integer multiplicative order (period)
/// of which is being estimated. Must be co-prime to `modulus`.
/// ## modulus
/// The modulus which defines the residue ring Z mod `modulus`
/// in which the multiplicative order of `generator` is being estimated.
/// ## bitsize
/// Number of bits needed to represent the modulus.
///
/// # Output
/// The numerator k of dyadic fraction k/2^bitsPrecision
/// approximating s/r.
operation EstimateFrequency(
generator : Int,
modulus : Int,
bitsize : Int
)
: Int {
mutable frequencyEstimate = 0;
let bitsPrecision = 2 * bitsize + 1;
// Allocate qubits for the superposition of eigenstates of
// the oracle that is used in period finding.
use eigenstateRegister = Qubit[bitsize];
// Initialize eigenstateRegister to 1, which is a superposition of
// the eigenstates we are estimating the phases of.
// We first interpret the register as encoding an unsigned integer
// in little endian encoding.
ApplyXorInPlace(1, eigenstateRegister);
let oracle = ApplyOrderFindingOracle(generator, modulus, _, _);
// Use phase estimation with a semiclassical Fourier transform to
// estimate the frequency.
use c = Qubit();
for idx in bitsPrecision - 1..-1..0 {
within {
H(c);
} apply {
// `BeginEstimateCaching` and `EndEstimateCaching` are the operations
// exposed by Azure Quantum Resource Estimator. These will instruct
// resource counting such that the if-block will be executed
// only once, its resources will be cached, and appended in
// every other iteration.
if BeginEstimateCaching("ControlledOracle", SingleVariant()) {
Controlled oracle([c], (1 <<< idx, eigenstateRegister));
EndEstimateCaching();
}
R1Frac(frequencyEstimate, bitsPrecision - 1 - idx, c);
}
if MResetZ(c) == One {
set frequencyEstimate += 1 <<< (bitsPrecision - 1 - idx);
}
}
// Return all the qubits used for oracles eigenstate back to 0 state
// using Microsoft.Quantum.Intrinsic.ResetAll.
ResetAll(eigenstateRegister);
return frequencyEstimate;
}
/// # Summary
/// Interprets `target` as encoding unsigned little-endian integer k
/// and performs transformation |k⟩ ↦ |gᵖ⋅k mod N ⟩ where
/// p is `power`, g is `generator` and N is `modulus`.
///
/// # Input
/// ## generator
/// The unsigned integer multiplicative order ( period )
/// of which is being estimated. Must be co-prime to `modulus`.
/// ## modulus
/// The modulus which defines the residue ring Z mod `modulus`
/// in which the multiplicative order of `generator` is being estimated.
/// ## power
/// Power of `generator` by which `target` is multiplied.
/// ## target
/// Register interpreted as little endian encoded which is multiplied by
/// given power of the generator. The multiplication is performed modulo
/// `modulus`.
internal operation ApplyOrderFindingOracle(
generator : Int, modulus : Int, power : Int, target : Qubit[]
)
: Unit
is Adj + Ctl {
// The oracle we use for order finding implements |x⟩ ↦ |x⋅a mod N⟩. We
// also use `ExpModI` to compute a by which x must be multiplied. Also
// note that we interpret target as unsigned integer in little-endian
// encoding.
ModularMultiplyByConstant(modulus,
ExpModI(generator, power, modulus),
target);
}
/// # Summary
/// Performs modular in-place multiplication by a classical constant.
///
/// # Description
/// Given the classical constants `c` and `modulus`, and an input
/// quantum register |𝑦⟩, this operation
/// computes `(c*x) % modulus` into |𝑦⟩.
///
/// # Input
/// ## modulus
/// Modulus to use for modular multiplication
/// ## c
/// Constant by which to multiply |𝑦⟩
/// ## y
/// Quantum register of target
internal operation ModularMultiplyByConstant(modulus : Int, c : Int, y : Qubit[])
: Unit is Adj + Ctl {
use qs = Qubit[Length(y)];
for (idx, yq) in Enumerated(y) {
let shiftedC = (c <<< idx) % modulus;
Controlled ModularAddConstant([yq], (modulus, shiftedC, qs));
}
ApplyToEachCA(SWAP, Zipped(y, qs));
let invC = InverseModI(c, modulus);
for (idx, yq) in Enumerated(y) {
let shiftedC = (invC <<< idx) % modulus;
Controlled ModularAddConstant([yq], (modulus, modulus - shiftedC, qs));
}
}
/// # Summary
/// Performs modular in-place addition of a classical constant into a
/// quantum register.
///
/// # Description
/// Given the classical constants `c` and `modulus`, and an input
/// quantum register |𝑦⟩, this operation
/// computes `(x+c) % modulus` into |𝑦⟩.
///
/// # Input
/// ## modulus
/// Modulus to use for modular addition
/// ## c
/// Constant to add to |𝑦⟩
/// ## y
/// Quantum register of target
internal operation ModularAddConstant(modulus : Int, c : Int, y : Qubit[])
: Unit is Adj + Ctl {
body (...) {
Controlled ModularAddConstant([], (modulus, c, y));
}
controlled (ctrls, ...) {
// We apply a custom strategy to control this operation instead of
// letting the compiler create the controlled variant for us in which
// the `Controlled` functor would be distributed over each operation
// in the body.
//
// Here we can use some scratch memory to save ensure that at most one
// control qubit is used for costly operations such as `AddConstant`
// and `CompareGreaterThenOrEqualConstant`.
if Length(ctrls) >= 2 {
use control = Qubit();
within {
Controlled X(ctrls, control);
} apply {
Controlled ModularAddConstant([control], (modulus, c, y));
}
} else {
use carry = Qubit();
Controlled AddConstant(ctrls, (c, y + [carry]));
Controlled Adjoint AddConstant(ctrls, (modulus, y + [carry]));
Controlled AddConstant([carry], (modulus, y));
Controlled CompareGreaterThanOrEqualConstant(ctrls, (c, y, carry));
}
}
}
/// # Summary
/// Performs in-place addition of a constant into a quantum register.
///
/// # Description
/// Given a non-empty quantum register |𝑦⟩ of length 𝑛+1 and a positive
/// constant 𝑐 < 2ⁿ, computes |𝑦 + c⟩ into |𝑦⟩.
///
/// # Input
/// ## c
/// Constant number to add to |𝑦⟩.
/// ## y
/// Quantum register of second summand and target; must not be empty.
internal operation AddConstant(c : Int, y : Qubit[]) : Unit is Adj + Ctl {
// We are using this version instead of the library version that is based
// on Fourier angles to show an advantage of sparse simulation in this sample.
let n = Length(y);
Fact(n > 0, "Bit width must be at least 1");
Fact(c >= 0, "constant must not be negative");
Fact(c < 2 ^ n, $"constant must be smaller than {2L ^ n}");
if c != 0 {
// If c has j trailing zeroes than the j least significant bits
// of y won't be affected by the addition and can therefore be
// ignored by applying the addition only to the other qubits and
// shifting c accordingly.
let j = NTrailingZeroes(c);
use x = Qubit[n - j];
within {
ApplyXorInPlace(c >>> j, x);
} apply {
IncByLE(x, y[j...]);
}
}
}
/// # Summary
/// Performs greater-than-or-equals comparison to a constant.
///
/// # Description
/// Toggles output qubit `target` if and only if input register `x`
/// is greater than or equal to `c`.
///
/// # Input
/// ## c
/// Constant value for comparison.
/// ## x
/// Quantum register to compare against.
/// ## target
/// Target qubit for comparison result.
///
/// # Reference
/// This construction is described in [Lemma 3, arXiv:2201.10200]
internal operation CompareGreaterThanOrEqualConstant(c : Int, x : Qubit[], target : Qubit)
: Unit is Adj+Ctl {
let bitWidth = Length(x);
if c == 0 {
X(target);
} elif c >= 2 ^ bitWidth {
// do nothing
} elif c == 2 ^ (bitWidth - 1) {
ApplyLowTCNOT(Tail(x), target);
} else {
// normalize constant
let l = NTrailingZeroes(c);
let cNormalized = c >>> l;
let xNormalized = x[l...];
let bitWidthNormalized = Length(xNormalized);
let gates = Rest(IntAsBoolArray(cNormalized, bitWidthNormalized));
use qs = Qubit[bitWidthNormalized - 1];
let cs1 = [Head(xNormalized)] + Most(qs);
let cs2 = Rest(xNormalized);
within {
for i in IndexRange(gates) {
(gates[i] ? ApplyAnd | ApplyOr)(cs1[i], cs2[i], qs[i]);
}
} apply {
ApplyLowTCNOT(Tail(qs), target);
}
}
}
/// # Summary
/// Internal operation used in the implementation of GreaterThanOrEqualConstant.
internal operation ApplyOr(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
within {
ApplyToEachA(X, [control1, control2]);
} apply {
ApplyAnd(control1, control2, target);
X(target);
}
}
internal operation ApplyAnd(control1 : Qubit, control2 : Qubit, target : Qubit)
: Unit is Adj {
body (...) {
CCNOT(control1, control2, target);
}
adjoint (...) {
H(target);
if (M(target) == One) {
X(target);
CZ(control1, control2);
}
}
}
/// # Summary
/// Returns the number of trailing zeroes of a number
///
/// ## Example
/// ```qsharp
/// let zeroes = NTrailingZeroes(21); // = NTrailingZeroes(0b1101) = 0
/// let zeroes = NTrailingZeroes(20); // = NTrailingZeroes(0b1100) = 2
/// ```
internal function NTrailingZeroes(number : Int) : Int {
mutable nZeroes = 0;
mutable copy = number;
while (copy % 2 == 0) {
set nZeroes += 1;
set copy /= 2;
}
return nZeroes;
}
/// # Summary
/// An implementation for `CNOT` that when controlled using a single control uses
/// a helper qubit and uses `ApplyAnd` to reduce the T-count to 4 instead of 7.
internal operation ApplyLowTCNOT(a : Qubit, b : Qubit) : Unit is Adj+Ctl {
body (...) {
CNOT(a, b);
}
adjoint self;
controlled (ctls, ...) {
// In this application this operation is used in a way that
// it is controlled by at most one qubit.
Fact(Length(ctls) <= 1, "At most one control line allowed");
if IsEmpty(ctls) {
CNOT(a, b);
} else {
use q = Qubit();
within {
ApplyAnd(Head(ctls), a, q);
} apply {
CNOT(q, b);
}
}
}
controlled adjoint self;
}
}
Executar o Avaliador de Recursos
O Avaliador de Recursos oferece seis parâmetros qubit predefinidos, quatro dos quais têm conjuntos de instruções baseados em portão e dois que têm um conjunto de instruções Majorana. Ele também oferece dois códigos surface_code
de correção de erro quântico, e floquet_code
.
Neste exemplo, você executa o Avaliador de Recursos usando o qubit_gate_us_e3
parâmetro qubit e o código de correção de surface_code
erro quântico.
- Selecione Exibir –> Paleta de Comandos ou pressione Ctrl+Shift+P e digite "resource", que deve abrir a opção Q#: Calcular Estimativas de Recursos . Selecione esta opção para abrir a janela Avaliador de Recursos.
- Você pode selecionar um ou mais tipos de código de parâmetro Qubit + Correção de Erro para os quais estimar os recursos. Para este exemplo, selecione qubit_gate_us_e3 e clique em OK.
- Especifique o orçamento de erro ou aceite o valor padrão 0,001. Para este exemplo, deixe o valor padrão e pressione Enter.
- Pressione Enter para aceitar o nome do resultado padrão com base no nome do arquivo, nesse caso, ShorRE.
Exibir os resultados
O Avaliador de Recursos fornece várias estimativas para o mesmo algoritmo, cada uma mostrando compensações entre o número de qubits e o runtime. Entender a compensação entre o runtime e a escala do sistema é um dos aspectos mais importantes da estimativa de recursos.
O resultado da estimativa de recurso é exibido na janela Estimativa do Q# .
A guia Resultados exibe um resumo da estimativa de recurso. Clique no ícone ao lado da primeira linha para selecionar as colunas que você deseja exibir. Você pode selecionar entre nome de execução, tipo de estimativa, tipo qubit, esquema qec, orçamento de erro, qubits lógicos, profundidade lógica, distância de código, estados T, fábricas T, fração de fábrica T, runtime, rQOPS e qubits físicos.
Na coluna Tipo de estimativa da tabela de resultados, você pode ver o número de combinações ideais de {número de qubits, runtime} para seu algoritmo. Essas combinações podem ser vistas no diagrama de espaço-tempo.
O diagrama espaço-tempo mostra as compensações entre o número de qubits físicos e o runtime do algoritmo. Nesse caso, o Avaliador de Recursos localiza 13 combinações ideais diferentes de muitos milhares de possíveis. Você pode passar o mouse sobre cada {número de qubits, runtime} para ver os detalhes da estimativa de recurso nesse ponto.
Para obter mais informações, consulte Diagrama de espaço-tempo.
Observação
Você precisa clicar em um ponto do diagrama de espaço-tempo, que é um par {number of qubits, runtime}, para ver o diagrama de espaço e os detalhes da estimativa de recurso correspondente a esse ponto.
O diagrama Espaço mostra a distribuição de qubits físicos usados para o algoritmo e as fábricas T, correspondendo a um par {number of qubits, runtime}. Por exemplo, se você selecionar o ponto mais à esquerda no diagrama de espaço-tempo, o número de qubits físicos necessários para executar o algoritmo será 427726, 196686 dos quais são qubits de algoritmo e 231040 dos quais são qubits de fábrica T.
Por fim, a guia Estimativas de Recursos exibe a lista completa de dados de saída para o Avaliador de Recursos correspondente a um par {number of qubits, runtime} . Você pode inspecionar os detalhes de custos recolhendo os grupos que têm mais informações. Por exemplo, selecione o ponto mais à esquerda no diagrama de espaço-tempo e recolha o grupo Parâmetros lógicos do qubit .
Parâmetro qubit lógico Valor Esquema de QEC surface_code Distância de código 21 Qubits físicos 882 Tempo de ciclo lógico 13 milissegundos Taxa de erro do qubit lógico 3.00E-13 Pré-fabricado de cruzamento 0.03 Limite de correção de erro 0,01 Fórmula de tempo do ciclo lógico (4 * twoQubitGateTime
+ 2 *oneQubitMeasurementTime
) *codeDistance
Fórmula de qubits físicos 2 * codeDistance
*codeDistance
Dica
Clique em Mostrar linhas detalhadas para exibir a descrição de cada saída dos dados do relatório.
Para obter mais informações, consulte os dados de relatório completos do Avaliador de Recursos.
Alterar os target parâmetros
Você pode estimar o custo para o mesmo programa Q# usando outro tipo de qubit, código de correção de erro e orçamento de erro. Abra a janela Avaliador de Recursos selecionando Exibir –> Paleta de Comandos e digite Q#: Calculate Resource Estimates
.
Selecione qualquer outra configuração, por exemplo, o parâmetro qubit baseado em Majorana, qubit_maj_ns_e6
. Aceite o valor de orçamento de erro padrão ou insira um novo e pressione Enter. O Avaliador de Recursos executa novamente a estimativa com os novos target parâmetros.
Para obter mais informações, consulte Parâmetros de destino para o Avaliador de Recursos.
Executar várias configurações de parâmetros
O Avaliador de Recursos do Azure Quantum pode executar várias configurações de target parâmetros e comparar os resultados da estimativa de recursos.
Selecione Exibir –> Paleta de Comandos ou pressione Ctrl+Shift+P e digite
Q#: Calculate Resource Estimates
.Selecione qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4 + floquet_code e qubit_maj_ns_e6 + floquet_code e clique em OK.
Aceite o valor de orçamento de erro padrão 0,001 e pressione Enter.
Pressione Enter para aceitar o arquivo de entrada, nesse caso, ShorRE.qs.
No caso de várias configurações de parâmetros, os resultados são exibidos em linhas diferentes na guia Resultados .
O diagrama espaço-tempo mostra os resultados de todas as configurações de parâmetros. A primeira coluna da tabela de resultados exibe a legenda de cada configuração de parâmetros. Você pode passar o mouse sobre cada ponto para ver os detalhes da estimativa de recurso nesse ponto.
Clique em um ponto {number of qubits, runtime} do diagrama de espaço-tempo para exibir o diagrama de espaço correspondente e os dados do relatório.
Pré-requisitos para Jupyter Notebook no VS Code
Um ambiente python com Python e Pip instalados.
A versão mais recente do Visual Studio Code ou abrir o VS Code na Web.
VS Code com as extensões do Kit de Desenvolvimento do Azure Quantum, Python e Jupyter instaladas.
O Azure Quantum
qsharp
eqsharp-widgets
os pacotes mais recentes.python -m pip install --upgrade qsharp qsharp-widgets
Dica
Você não precisa ter uma conta do Azure para executar o Estimador de Recursos local.
Criar o algoritmo quântico
No VS Code, selecione Exibir > paleta de comandos e selecione Criar: Novo Jupyter Notebook.
No canto superior direito, o VS Code detectará e exibirá a versão do Python e o ambiente virtual do Python que foi selecionado para o notebook. Se você tiver vários ambientes do Python, talvez seja necessário selecionar um kernel usando o seletor de kernel no canto superior direito. Se nenhum ambiente foi detectado, consulte Jupyter Notebooks no VS Code para obter informações de instalação.
Na primeira célula do notebook, importe o
qsharp
pacote.import qsharp
Adicione uma nova célula e copie o código a seguir.
%%qsharp open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Math; open Microsoft.Quantum.Measurement; open Microsoft.Quantum.Unstable.Arithmetic; open Microsoft.Quantum.ResourceEstimation; operation RunProgram() : Unit { let bitsize = 31; // When choosing parameters for `EstimateFrequency`, make sure that // generator and modules are not co-prime let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize); } // In this sample we concentrate on costing the `EstimateFrequency` // operation, which is the core quantum operation in Shors algorithm, and // we omit the classical pre- and post-processing. /// # Summary /// Estimates the frequency of a generator /// in the residue ring Z mod `modulus`. /// /// # Input /// ## generator /// The unsigned integer multiplicative order (period) /// of which is being estimated. Must be co-prime to `modulus`. /// ## modulus /// The modulus which defines the residue ring Z mod `modulus` /// in which the multiplicative order of `generator` is being estimated. /// ## bitsize /// Number of bits needed to represent the modulus. /// /// # Output /// The numerator k of dyadic fraction k/2^bitsPrecision /// approximating s/r. operation EstimateFrequency( generator : Int, modulus : Int, bitsize : Int ) : Int { mutable frequencyEstimate = 0; let bitsPrecision = 2 * bitsize + 1; // Allocate qubits for the superposition of eigenstates of // the oracle that is used in period finding. use eigenstateRegister = Qubit[bitsize]; // Initialize eigenstateRegister to 1, which is a superposition of // the eigenstates we are estimating the phases of. // We first interpret the register as encoding an unsigned integer // in little endian encoding. ApplyXorInPlace(1, eigenstateRegister); let oracle = ApplyOrderFindingOracle(generator, modulus, _, _); // Use phase estimation with a semiclassical Fourier transform to // estimate the frequency. use c = Qubit(); for idx in bitsPrecision - 1..-1..0 { within { H(c); } apply { // `BeginEstimateCaching` and `EndEstimateCaching` are the operations // exposed by Azure Quantum Resource Estimator. These will instruct // resource counting such that the if-block will be executed // only once, its resources will be cached, and appended in // every other iteration. if BeginEstimateCaching("ControlledOracle", SingleVariant()) { Controlled oracle([c], (1 <<< idx, eigenstateRegister)); EndEstimateCaching(); } R1Frac(frequencyEstimate, bitsPrecision - 1 - idx, c); } if MResetZ(c) == One { set frequencyEstimate += 1 <<< (bitsPrecision - 1 - idx); } } // Return all the qubits used for oracle eigenstate back to 0 state // using Microsoft.Quantum.Intrinsic.ResetAll. ResetAll(eigenstateRegister); return frequencyEstimate; } /// # Summary /// Interprets `target` as encoding unsigned little-endian integer k /// and performs transformation |k⟩ ↦ |gᵖ⋅k mod N ⟩ where /// p is `power`, g is `generator` and N is `modulus`. /// /// # Input /// ## generator /// The unsigned integer multiplicative order ( period ) /// of which is being estimated. Must be co-prime to `modulus`. /// ## modulus /// The modulus which defines the residue ring Z mod `modulus` /// in which the multiplicative order of `generator` is being estimated. /// ## power /// Power of `generator` by which `target` is multiplied. /// ## target /// Register interpreted as little endian encoded which is multiplied by /// given power of the generator. The multiplication is performed modulo /// `modulus`. internal operation ApplyOrderFindingOracle( generator : Int, modulus : Int, power : Int, target : Qubit[] ) : Unit is Adj + Ctl { // The oracle we use for order finding implements |x⟩ ↦ |x⋅a mod N⟩. We // also use `ExpModI` to compute a by which x must be multiplied. Also // note that we interpret target as unsigned integer in little-endian // encoding. ModularMultiplyByConstant(modulus, ExpModI(generator, power, modulus), target); } /// # Summary /// Performs modular in-place multiplication by a classical constant. /// /// # Description /// Given the classical constants `c` and `modulus`, and an input /// quantum register |𝑦⟩, this operation /// computes `(c*x) % modulus` into |𝑦⟩. /// /// # Input /// ## modulus /// Modulus to use for modular multiplication /// ## c /// Constant by which to multiply |𝑦⟩ /// ## y /// Quantum register of target internal operation ModularMultiplyByConstant(modulus : Int, c : Int, y : Qubit[]) : Unit is Adj + Ctl { use qs = Qubit[Length(y)]; for (idx, yq) in Enumerated(y) { let shiftedC = (c <<< idx) % modulus; Controlled ModularAddConstant([yq], (modulus, shiftedC, qs)); } ApplyToEachCA(SWAP, Zipped(y, qs)); let invC = InverseModI(c, modulus); for (idx, yq) in Enumerated(y) { let shiftedC = (invC <<< idx) % modulus; Controlled ModularAddConstant([yq], (modulus, modulus - shiftedC, qs)); } } /// # Summary /// Performs modular in-place addition of a classical constant into a /// quantum register. /// /// # Description /// Given the classical constants `c` and `modulus`, and an input /// quantum register |𝑦⟩, this operation /// computes `(x+c) % modulus` into |𝑦⟩. /// /// # Input /// ## modulus /// Modulus to use for modular addition /// ## c /// Constant to add to |𝑦⟩ /// ## y /// Quantum register of target internal operation ModularAddConstant(modulus : Int, c : Int, y : Qubit[]) : Unit is Adj + Ctl { body (...) { Controlled ModularAddConstant([], (modulus, c, y)); } controlled (ctrls, ...) { // We apply a custom strategy to control this operation instead of // letting the compiler create the controlled variant for us in which // the `Controlled` functor would be distributed over each operation // in the body. // // Here we can use some scratch memory to save ensure that at most one // control qubit is used for costly operations such as `AddConstant` // and `CompareGreaterThenOrEqualConstant`. if Length(ctrls) >= 2 { use control = Qubit(); within { Controlled X(ctrls, control); } apply { Controlled ModularAddConstant([control], (modulus, c, y)); } } else { use carry = Qubit(); Controlled AddConstant(ctrls, (c, y + [carry])); Controlled Adjoint AddConstant(ctrls, (modulus, y + [carry])); Controlled AddConstant([carry], (modulus, y)); Controlled CompareGreaterThanOrEqualConstant(ctrls, (c, y, carry)); } } } /// # Summary /// Performs in-place addition of a constant into a quantum register. /// /// # Description /// Given a non-empty quantum register |𝑦⟩ of length 𝑛+1 and a positive /// constant 𝑐 < 2ⁿ, computes |𝑦 + c⟩ into |𝑦⟩. /// /// # Input /// ## c /// Constant number to add to |𝑦⟩. /// ## y /// Quantum register of second summand and target; must not be empty. internal operation AddConstant(c : Int, y : Qubit[]) : Unit is Adj + Ctl { // We are using this version instead of the library version that is based // on Fourier angles to show an advantage of sparse simulation in this sample. let n = Length(y); Fact(n > 0, "Bit width must be at least 1"); Fact(c >= 0, "constant must not be negative"); Fact(c < 2 ^ n, $"constant must be smaller than {2L ^ n}"); if c != 0 { // If c has j trailing zeroes than the j least significant bits // of y will not be affected by the addition and can therefore be // ignored by applying the addition only to the other qubits and // shifting c accordingly. let j = NTrailingZeroes(c); use x = Qubit[n - j]; within { ApplyXorInPlace(c >>> j, x); } apply { IncByLE(x, y[j...]); } } } /// # Summary /// Performs greater-than-or-equals comparison to a constant. /// /// # Description /// Toggles output qubit `target` if and only if input register `x` /// is greater than or equal to `c`. /// /// # Input /// ## c /// Constant value for comparison. /// ## x /// Quantum register to compare against. /// ## target /// Target qubit for comparison result. /// /// # Reference /// This construction is described in [Lemma 3, arXiv:2201.10200] internal operation CompareGreaterThanOrEqualConstant(c : Int, x : Qubit[], target : Qubit) : Unit is Adj+Ctl { let bitWidth = Length(x); if c == 0 { X(target); } elif c >= 2 ^ bitWidth { // do nothing } elif c == 2 ^ (bitWidth - 1) { ApplyLowTCNOT(Tail(x), target); } else { // normalize constant let l = NTrailingZeroes(c); let cNormalized = c >>> l; let xNormalized = x[l...]; let bitWidthNormalized = Length(xNormalized); let gates = Rest(IntAsBoolArray(cNormalized, bitWidthNormalized)); use qs = Qubit[bitWidthNormalized - 1]; let cs1 = [Head(xNormalized)] + Most(qs); let cs2 = Rest(xNormalized); within { for i in IndexRange(gates) { (gates[i] ? ApplyAnd | ApplyOr)(cs1[i], cs2[i], qs[i]); } } apply { ApplyLowTCNOT(Tail(qs), target); } } } /// # Summary /// Internal operation used in the implementation of GreaterThanOrEqualConstant. internal operation ApplyOr(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { within { ApplyToEachA(X, [control1, control2]); } apply { ApplyAnd(control1, control2, target); X(target); } } internal operation ApplyAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { body (...) { CCNOT(control1, control2, target); } adjoint (...) { H(target); if (M(target) == One) { X(target); CZ(control1, control2); } } } /// # Summary /// Returns the number of trailing zeroes of a number /// /// ## Example /// ```qsharp /// let zeroes = NTrailingZeroes(21); // = NTrailingZeroes(0b1101) = 0 /// let zeroes = NTrailingZeroes(20); // = NTrailingZeroes(0b1100) = 2 /// ``` internal function NTrailingZeroes(number : Int) : Int { mutable nZeroes = 0; mutable copy = number; while (copy % 2 == 0) { set nZeroes += 1; set copy /= 2; } return nZeroes; } /// # Summary /// An implementation for `CNOT` that when controlled using a single control uses /// a helper qubit and uses `ApplyAnd` to reduce the T-count to 4 instead of 7. internal operation ApplyLowTCNOT(a : Qubit, b : Qubit) : Unit is Adj+Ctl { body (...) { CNOT(a, b); } adjoint self; controlled (ctls, ...) { // In this application this operation is used in a way that // it is controlled by at most one qubit. Fact(Length(ctls) <= 1, "At most one control line allowed"); if IsEmpty(ctls) { CNOT(a, b); } else { use q = Qubit(); within { ApplyAnd(Head(ctls), a, q); } apply { CNOT(q, b); } } } controlled adjoint self; }
Estimar o algoritmo quântico
Agora, você estima os recursos físicos para a RunProgram
operação usando as suposições padrão. Adicione uma nova célula e copie o código a seguir.
result = qsharp.estimate("RunProgram()")
result
A qsharp.estimate
função cria um objeto de resultado, que pode ser usado para exibir uma tabela com as contagens gerais de recursos físicos. Você pode inspecionar os detalhes de custos recolhendo os grupos que têm mais informações. Para obter mais informações, consulte os dados de relatório completos do Avaliador de Recursos.
Por exemplo, recolha o grupo Parâmetros de qubit lógico para ver que a distância do código é 21 e o número de qubits físicos é 882.
Parâmetro de qubit lógico | Valor |
---|---|
Esquema de QEC | surface_code |
Distância de código | 21 |
Qubits físicos | 882 |
Tempo de ciclo lógico | 8 milissegundos |
Taxa de erro de qubit lógico | 3.00E-13 |
Pré-refatoração de cruzamento | 0.03 |
Limite de correção de erro | 0,01 |
Fórmula de tempo do ciclo lógico | (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime ) * codeDistance |
Fórmula de qubits físicos | 2 * codeDistance * codeDistance |
Dica
Para uma versão mais compacta da tabela de saída, você pode usar result.summary
.
Diagrama de espaço
A distribuição de qubits físicos usados para o algoritmo e as fábricas T é um fator que pode afetar o design do algoritmo. Você pode usar o qsharp-widgets
pacote para visualizar essa distribuição para entender melhor os requisitos de espaço estimados para o algoritmo.
from qsharp_widgets import SpaceChart, EstimateDetails
SpaceChart(result)
Neste exemplo, o número de qubits físicos necessários para executar o algoritmo são 829766, 196686 dos quais são qubits de algoritmo e 633080 dos quais são qubits de fábrica T.
Alterar os valores padrão e estimar o algoritmo
Ao enviar uma solicitação de estimativa de recursos para seu programa, você pode especificar alguns parâmetros opcionais. Use o jobParams
campo para acessar todos os target parâmetros que podem ser passados para a execução do trabalho e ver quais valores padrão foram assumidos:
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'}}
Você pode ver que o Avaliador de Recursos usa o qubit_gate_ns_e3
modelo qubit, o surface_code
código de correção de erro e o orçamento de erro 0,001 como valores padrão para a estimativa.
Estes são os target parâmetros que podem ser personalizados:
errorBudget
– o orçamento geral de erros permitido para o algoritmoqecScheme
– o esquema de correção de erros quânticos (QEC)qubitParams
– os parâmetros de qubit físicoconstraints
– As restrições no nível do componentedistillationUnitSpecifications
– as especificações para algoritmos de destilação de fábricas TestimateType
- única ou fronteira
Para obter mais informações, consulte Parâmetros de destino para o Avaliador de Recursos.
Alterar o modelo de qubit
Você pode estimar o custo para o mesmo algoritmo usando o parâmetro qubit baseado em Majorana, qubitParams
, "qubit_maj_ns_e6".
result_maj = qsharp.estimate("RunProgram()", params={
"qubitParams": {
"name": "qubit_maj_ns_e6"
}})
EstimateDetails(result_maj)
Alterar o esquema de correção de erros quânticos
Você pode executar novamente o trabalho de estimativa de recursos para o mesmo exemplo nos parâmetros qubit baseados em Majorana com um esquema QEC floqued, qecScheme
.
result_maj = qsharp.estimate("RunProgram()", params={
"qubitParams": {
"name": "qubit_maj_ns_e6"
},
"qecScheme": {
"name": "floquet_code"
}})
EstimateDetails(result_maj)
Alterar o orçamento de erros
Em seguida, execute novamente o mesmo circuito quântico com um errorBudget
de 10%.
result_maj = qsharp.estimate("RunProgram()", params={
"qubitParams": {
"name": "qubit_maj_ns_e6"
},
"qecScheme": {
"name": "floquet_code"
},
"errorBudget": 0.1})
EstimateDetails(result_maj)
Envio em lote com o Avaliador de Recursos
O Avaliador de Recursos do Azure Quantum permite que você execute várias configurações de target parâmetros e compare os resultados. Isso é útil quando você deseja comparar o custo de diferentes modelos de qubit, esquemas QEC ou orçamentos de erro.
Você pode executar uma estimativa de lote passando uma lista de target parâmetros para o
params
parâmetro daqsharp.estimate
função. Por exemplo, execute o mesmo algoritmo com os parâmetros padrão e os parâmetros qubit baseados em Majorana com um esquema QEC floqued.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⁻⁶"])
Modelar Qubits lógicos Profundidade lógica Estados T Distância de código Factories T Fração de factory T Qubits físicos rQOPS Runtime físico ns baseado em porta, 10⁻³ 223 3,64M 4,70M 21 19 76.30 % 829,77k 26,55M 31 segundos ns Majorana, 10⁻⁶ 223 3,64M 4,70M 5 19 63.02 % 79,60k 148,67M 5 segundos Você também pode construir uma lista de parâmetros de estimativa usando a
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)
Modelar Qubits lógicos Profundidade lógica Estados T Distância de código Factories T Fração de factory T Qubits físicos rQOPS Runtime físico µs baseado em porta, 10⁻³ 223 3,64M 4,70M 17 13 40.54 % 216,77k 21,86k 10 horas µs baseado em porta, 10⁻⁴ 223 3,64M 4,70M 9 14 43.17 % 63,57k 41,30k 5 horas ns baseado em porta, 10⁻³ 223 3,64M 4,70M 17 16 69.08 % 416,89k 32,79M 25 segundos ns baseado em porta, 10⁻⁴ 223 3,64M 4,70M 9 14 43.17 % 63,57k 61,94M 13 segundos ns Majorana, 10⁻⁴ 223 3,64M 4,70M 9 19 82.75 % 501,48k 82,59M 10 segundos ns Majorana, 10⁻⁶ 223 3,64M 4,70M 5 13 31.47 % 42,96k 148,67M 5 segundos
Como executar a estimativa de fronteira do Pareto
Ao estimar os recursos de um algoritmo, é importante considerar a compensação entre o número de qubits físicos e o runtime do algoritmo. Você pode considerar a alocação de quantos qubits físicos possível para reduzir o runtime do algoritmo. No entanto, o número de qubits físicos é limitado pelo número de qubits físicos disponíveis no hardware quântico.
A estimativa de fronteira pareto fornece várias estimativas para o mesmo algoritmo, cada uma com uma compensação entre o número de qubits e o runtime.
Para executar o Avaliador de Recursos usando a estimativa de fronteira do Pareto, você precisa especificar o
"estimateType"
target parâmetro como"frontier"
. Por exemplo, execute o mesmo algoritmo com os parâmetros qubit baseados em Majorana com um código de superfície usando a estimativa de fronteira pareto.result = qsharp.estimate("RunProgram()", params= {"qubitParams": { "name": "qubit_maj_ns_e4" }, "qecScheme": { "name": "surface_code" }, "estimateType": "frontier", # frontier estimation } )
Você pode usar a
EstimatesOverview
função para exibir uma tabela com as contagens gerais de recursos físicos. Clique no ícone ao lado da primeira linha para selecionar as colunas que você deseja exibir. Você pode selecionar entre nome de execução, tipo de estimativa, tipo qubit, esquema qec, orçamento de erro, qubits lógicos, profundidade lógica, distância de código, estados T, fábricas T, fração de fábrica T, runtime, rQOPS e qubits físicos.from qsharp_widgets import EstimatesOverview EstimatesOverview(result)
Na coluna Tipo de estimativa da tabela de resultados, você pode ver o número de combinações diferentes de {número de qubits, runtime} para seu algoritmo. Nesse caso, o Avaliador de Recursos localiza 22 combinações ideais diferentes de muitos milhares de possíveis.
Diagrama de espaço-tempo
A EstimatesOverview
função também exibe o diagrama de espaço-tempo do Avaliador de Recursos.
O diagrama de tempo de espaço mostra o número de qubits físicos e o runtime do algoritmo para cada {número de qubits, par de runtime}. Você pode passar o mouse sobre cada ponto para ver os detalhes da estimativa de recurso nesse ponto.
Estimativa da fronteira do Envio em lote com Pareto
Para estimar e comparar várias configurações de target parâmetros com a estimativa de fronteira, adicione
"estimateType": "frontier",
aos parâmetros .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"])
Observação
Você pode definir cores e executar nomes para o diagrama qubit-time usando a
EstimatesOverview
função .Ao executar várias configurações de target parâmetros usando a estimativa de fronteira pareto, você pode ver as estimativas de recursos para um ponto específico do diagrama de espaço-tempo, ou seja, para cada par {número de qubits, runtime}. Por exemplo, o código a seguir mostra o uso de detalhes da estimativa para a segunda execução (estimate index=0) e o quarto (índice de ponto=3) o runtime mais curto.
EstimateDetails(result[1], 4)
Você também pode ver o diagrama de espaço para um ponto específico do diagrama de espaço-tempo. Por exemplo, o código a seguir mostra o diagrama de espaço para a primeira execução de combinações (estimar index=0) e o terceiro runtime mais curto (índice de ponto=2).
SpaceChart(result[0], 2)
Pré-requisitos para Qiskit
- Uma conta do Azure com uma assinatura ativa. Se você não tiver uma conta do Azure, registre-se gratuitamente e inscreva-se em uma assinatura paga conforme o uso.
- Um workspace do Azure Quantum. Para obter mais informações, confira Criar um workspace do Azure Quantum.
Habilitar o Avaliador target de Recursos do Azure Quantum em seu workspace
O Avaliador de Recursos é um target do provedor de Computação Quântica da Microsoft. Se você criou um workspace desde o lançamento do Avaliador de Recursos, o provedor de Computação Quântica da Microsoft foi adicionado automaticamente ao seu workspace.
Se você estiver usando um workspace do Azure Quantum existente :
- Abra seu workspace na portal do Azure.
- No painel esquerdo, em Operações, selecione Fornecedores.
- Selecione + Adicionar fornecedor.
- Selecione + Adicionar para Computação quântica da Microsoft.
- Selecione Aprender & Desenvolver e selecione Adicionar.
Criar um notebook em seu workspace
- Entre no portal do Azure e selecione seu workspace do Azure Quantum.
- Em Operações, selecione Notebooks
- Clique em Meus blocos de anotações e clique em Adicionar Novo
- Em Tipo de Kernel, selecione IPython.
- Digite um nome para o arquivo e clique em Criar arquivo.
Quando o novo notebook é aberto, ele cria automaticamente o código da primeira célula com base na assinatura e nas informações do workspace.
from azure.quantum import Workspace
workspace = Workspace (
resource_id = "", # Your resource_id
location = "" # Your workspace location (for example, "westus")
)
Observação
Salvo indicação em contrário, você deve executar cada célula na ordem em que a cria para evitar problemas de compilação.
Clique no ícone triangular "reproduzir" à esquerda da célula para executar o código.
Carregar as importações necessárias
Primeiro, você precisará importar mais módulos do azure-quantum e qiskit
do .
Clique em + Código para adicionar uma nova célula e, em seguida, adicione e execute o seguinte código:
from azure.quantum.qiskit import AzureQuantumProvider
from qiskit import QuantumCircuit, transpile
from qiskit.circuit.library import RGQFTMultiplier
Conectar ao serviço do Azure Quantum
Em seguida, crie um objeto AzureQuantumProvider usando o workspace
objeto da célula anterior para se conectar ao workspace do Azure Quantum. Você cria uma instância de back-end e define o Avaliador de Recursos como seu target.
provider = AzureQuantumProvider(workspace)
backend = provider.get_backend('microsoft.estimator')
Criar o algoritmo quântico
Neste exemplo, você cria um circuito quântico para um multiplicador com base na construção apresentada em Ruiz-Perez e Garcia-Escartin (arXiv:1411.5949) que usa a Transformação Do Fourier Quântico para implementar a aritmética.
Você pode ajustar o tamanho do multiplicador alterando a bitwidth
variável . A geração de circuito é encapsulada em uma função que pode ser chamada com o bitwidth
valor do multiplicador. A operação terá dois registros de entrada, cada um com o tamanho do especificado bitwidth
e um registro de saída que tem o dobro do tamanho do especificado bitwidth
. A função também imprimirá algumas contagens de recursos lógicos para o multiplicador extraído diretamente do circuito quântico.
def create_algorithm(bitwidth):
print(f"[INFO] Create a QFT-based multiplier with bitwidth {bitwidth}")
# Print a warning for large bitwidths that will require some time to generate and
# transpile the circuit.
if bitwidth > 18:
print(f"[WARN] It will take more than one minute generate a quantum circuit with a bitwidth larger than 18")
circ = RGQFTMultiplier(num_state_qubits=bitwidth, num_result_qubits=2 * bitwidth)
# One could further reduce the resource estimates by increasing the optimization_level,
# however, this will also increase the runtime to construct the algorithm. Note, that
# it does not affect the runtime for resource estimation.
print(f"[INFO] Decompose circuit into intrinsic quantum operations")
circ = transpile(circ, basis_gates=SUPPORTED_INSTRUCTIONS, optimization_level=0)
# print some statistics
print(f"[INFO] qubit count: {circ.num_qubits}")
print("[INFO] gate counts")
for gate, count in circ.count_ops().items():
print(f"[INFO] - {gate}: {count}")
return circ
Observação
Você pode enviar trabalhos de estimativa de recursos físicos para algoritmos que não têm estados T, mas que têm pelo menos uma medida.
Estimar o algoritmo quântico
Crie uma instância do algoritmo usando a create_algorithm
função . Você pode ajustar o tamanho do multiplicador alterando a bitwidth
variável .
bitwidth = 4
circ = create_algorithm(bitwidth)
Estime os recursos físicos para essa operação usando as suposições padrão. Você pode enviar o circuito para o back-end do Avaliador de Recursos usando o run
método e, em seguida, executar job.result()
para aguardar a conclusão do trabalho e retornar os resultados.
job = backend.run(circ)
result = job.result()
result
Isso cria uma tabela que mostra as contagens gerais de recursos físicos. Você pode inspecionar os detalhes de custos recolhendo os grupos que têm mais informações.
Dica
Para uma versão mais compacta da tabela de saída, você pode usar result.summary
.
Por exemplo, se você recolher o grupo parâmetros de qubit lógico , poderá ver com mais facilidade que a distância do código de correção de erro é 15.
Parâmetro de qubit lógico | Valor |
---|---|
Esquema de QEC | surface_code |
Distância de código | 15 |
Qubits físicos | 450 |
Tempo de ciclo lógico | 6us |
Taxa de erro de qubit lógico | 3.00E-10 |
Pré-refatoração de cruzamento | 0.03 |
Limite de correção de erro | 0,01 |
Fórmula de tempo do ciclo lógico | (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime ) * codeDistance |
Fórmula de qubits físicos | 2 * codeDistance * codeDistance |
No grupo Parâmetros de qubit físico , você pode ver as propriedades físicas do qubit que foram assumidas para essa estimativa. Por exemplo, o tempo para realizar uma medição de qubit único e uma porta de qubit único é considerado 100 ns e 50 ns, respectivamente.
Dica
Você também pode acessar a saída do Avaliador de Recursos como um dicionário python usando o método result.data().
Para obter mais informações, consulte a lista completa de dados de saída para o Avaliador de Recursos.
Diagramas de espaço
A distribuição de qubits físicos usados para o algoritmo e as fábricas T é um fator que pode afetar o design do algoritmo. Você pode visualizar essa distribuição para entender melhor os requisitos de espaço estimados para o algoritmo.
result.diagram.space
O diagrama de espaço mostra a proporção de qubits de algoritmo e qubits de fábrica T. Observe que o número de cópias de fábrica T, 28, contribui para o número de qubits físicos para fábricas T como $\text{T factories} \cdot \text{qubit físico por fábrica T}= 28 \cdot 18.000 = 504.000$.
Para obter mais informações, consulte Estimativa física da fábrica T.
Alterar os valores padrão e estimar o algoritmo
Ao enviar uma solicitação de estimativa de recursos para seu programa, você pode especificar alguns parâmetros opcionais. Use o jobParams
campo para acessar todos os valores que podem ser passados para a execução do trabalho e ver quais valores padrão foram assumidos:
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'}}
Estes são os target parâmetros que podem ser personalizados:
errorBudget
– o orçamento geral de erros permitidoqecScheme
– o esquema de correção de erros quânticos (QEC)qubitParams
– os parâmetros de qubit físicoconstraints
– As restrições no nível do componentedistillationUnitSpecifications
– as especificações para algoritmos de destilação de fábricas T
Para obter mais informações, consulte Parâmetros de destino para o Avaliador de Recursos.
Alterar o modelo de qubit
Em seguida, estime o custo do mesmo algoritmo usando o parâmetro qubit baseado em Majorana qubit_maj_ns_e6
job = backend.run(circ,
qubitParams={
"name": "qubit_maj_ns_e6"
})
result = job.result()
result
Você pode inspecionar as contagens físicas programaticamente. Por exemplo, você pode explorar detalhes sobre a fábrica T que foi criada para executar o 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]}
Observação
Por padrão, o runtime é mostrado em nanossegundos.
Você pode usar esses dados para produzir algumas explicações de como as fábricas T produzem os estados T necessários.
data = result.data()
tfactory = data["tfactory"]
breakdown = data["physicalCounts"]["breakdown"]
producedTstates = breakdown["numTfactories"] * breakdown["numTfactoryRuns"] * tfactory["numTstates"]
print(f"""A single T factory produces {tfactory["logicalErrorRate"]:.2e} T states with an error rate of (required T state error rate is {breakdown["requiredLogicalTstateErrorRate"]:.2e}).""")
print(f"""{breakdown["numTfactories"]} copie(s) of a T factory are executed {breakdown["numTfactoryRuns"]} time(s) to produce {producedTstates} T states ({breakdown["numTstates"]} are required by the algorithm).""")
print(f"""A single T factory is composed of {tfactory["numRounds"]} rounds of distillation:""")
for round in range(tfactory["numRounds"]):
print(f"""- {tfactory["numModulesPerRound"][round]} {tfactory["moduleNamePerRound"][round]} unit(s)""")
A single T factory produces 1.68e-10 T states with an error rate of (required T state error rate is 2.77e-08).
23 copies of a T factory are executed 523 time(s) to produce 12029 T states (12017 are required by the algorithm).
A single T factory is composed of 3 rounds of distillation:
- 1368 15-to-1 space efficient physical unit(s)
- 20 15-to-1 RM prep physical unit(s)
- 1 15-to-1 RM prep logical unit(s)
Alterar o esquema de correção de erros quânticos
Agora, execute novamente o trabalho de estimativa de recursos para o mesmo exemplo nos parâmetros qubit baseados em Majorana com um esquema QEC floqued, qecScheme
.
job = backend.run(circ,
qubitParams={
"name": "qubit_maj_ns_e6"
},
qecScheme={
"name": "floquet_code"
})
result_maj_floquet = job.result()
result_maj_floquet
Alterar o orçamento de erros
Vamos executar novamente o mesmo circuito quântico com um errorBudget
de 10%.
job = backend.run(circ,
qubitParams={
"name": "qubit_maj_ns_e6"
},
qecScheme={
"name": "floquet_code"
},
errorBudget=0.1)
result_maj_floquet_e1 = job.result()
result_maj_floquet_e1
Observação
Se você tiver algum problema ao trabalhar com o Avaliador de Recursos, marcar a página Solução de problemas ou entre em contato com AzureQuantumInfo@microsoft.com.
Próximas etapas
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de