Simulação exata com primitivas d Qiskit SDK
O código desta página foi desenvolvido usando os seguintes requisitos. Recomendamos o uso dessas versões ou de versões mais recentes.
qiskit[all]~=2.5.0
As primitivas de referência no Qiskit SDK realizam simulações com vetores de estado locais. Essas simulações não permitem
modelar o ruído do dispositivo, mas são úteis para a prototipagem rápida de algoritmos antes de se explorar técnicas de simulação
mais avançadas ( usando o Qiskit Aer ) ou de executá-los em dispositivos reais ( primitivas do Qiskit Runtime ).
A primitiva Estimator pode calcular os valores de expectativa dos circuitos, e a primitiva Sampler pode fazer uma amostragem das distribuições de saída dos circuitos.
As seções a seguir mostram como usar as primitivas de referência para executar seu fluxo de trabalho localmente.
Use o Estimador de referência
A implementação de referência do EstimatorV2 em qiskit.primitives que é executada em um simulador de vetor de estado local é a classe StatevectorEstimator classe. Ele pode receber circuitos, observáveis e parâmetros como entradas e retorna os valores de expectativa computados localmente.
O código a seguir prepara os dados de entrada que serão utilizados nos exemplos a seguir. O tipo de entrada esperado para os
observáveis é qiskit.quantum_info.SparsePauliOp. Observe que
o circuito do exemplo é parametrizado, mas você também pode executar o Estimator em circuitos não parametrizados.
Qualquer circuito passado para um Estimador não deve incluir nenhuma medida.
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
# circuit for which you want to obtain the expected value
circuit = QuantumCircuit(2)
circuit.ry(Parameter("theta"), 0)
circuit.h(0)
circuit.cx(0, 1)
circuit.draw("mpl", style="iqp")Output:
from qiskit.quantum_info import SparsePauliOp
import numpy as np
# observable(s) whose expected values you want to compute
observable = SparsePauliOp(["II", "XX", "YY", "ZZ"], coeffs=[1, 1, -1, 1])
# value(s) for the circuit parameter(s)
parameter_values = [[0], [np.pi / 6], [np.pi / 2]]O fluxo de trabalho das primitivas Qiskit Runtime exige que os circuitos e observáveis sejam transformados para usar somente as instruções compatíveis com a QPU (denominadas circuitos e observáveis da arquitetura do conjunto de instruções (ISA) ). As primitivas de referência ainda aceitam instruções abstratas, pois dependem de simulações de vetores de estado locais, mas a transpilação do circuito ainda pode ser benéfica em termos de otimização do circuito.
# Generate a pass manager without providing a backend
from qiskit.transpiler import generate_preset_pass_manager
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)Inicializar Estimador
Instanciar a qiskit.primitives.StatevectorEstimator.
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()Corra e obtenha resultados
Este exemplo usa apenas um circuito (do tipo QuantumCircuit) e um observável.
Execute a estimativa chamando o método StatevectorEstimator.run que retorna uma instância de um objeto PrimitiveJob objeto. Você pode obter os resultados do trabalho (como um objeto qiskit.primitives.PrimitiveResult objeto) com o método qiskit.primitives.PrimitiveJob.result método.
job = estimator.run([(circuit, observable, parameter_values)])
result = job.result()
print(f" > Result class: {type(result)}")Output:
> Result class: <class 'qiskit.primitives.containers.primitive_result.PrimitiveResult'>
Obtenha o valor esperado do resultado
O resultado das primitivas gera uma matriz de PubResult objetos, em que cada item da matriz é um PubResult objeto que contém em seus dados a matriz de avaliações correspondentes a cada combinação observável do circuito no PUB.
Para recuperar os valores de expectativa e os metadados da primeira (e, neste caso, única) avaliação de circuito, devemos acessar a avaliação data para PUB 0:
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")Output:
> Expectation value: [4. 3.73205081 2. ]
> Metadata: {'target_precision': 0.0, 'circuit_metadata': {}}
Definir opções de execução do Estimador
Por padrão, o Estimador de referência executa um cálculo exato do vetor de estado com base no quantum_info.Statevector classe.
No entanto, isso pode ser modificado para introduzir o efeito da sobrecarga de amostragem (também conhecido como "ruído de disparo").
O Estimator aceita um argumento precision que expressa as barras de erro que a implementação primitiva deve visar para estimativas de valores de expectativa. Essa é a sobrecarga de amostragem e é definida exclusivamente no método .run() . Isso permite que você faça o ajuste fino da opção até o nível PUB.
# Estimate expectation values for two PUBs, both with 0.05 precision.
precise_job = estimator.run(
[(circuit, observable, parameter_values)], precision=0.05
)Para ver um exemplo completo, consulte a página de exemplos do Estimator.
Use o Sampler de referência
A implementação de referência de SamplerV2 em qiskit.primitives é a classe StatevectorSampler classe. Ele usa circuitos e parâmetros como entradas e retorna os resultados da amostragem das distribuições de probabilidade de saída como uma distribuição de quase-probabilidade dos estados de saída.
O código a seguir prepara as entradas utilizadas nos exemplos a seguir. Observe que esses exemplos executam um único circuito parametrizado, mas você também pode executar o Sampler em circuitos não parametrizados.
from qiskit import QuantumCircuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw("mpl", style="iqp")Output:
Qualquer circuito quântico passado para um Sampler deve incluir medições.
O fluxo de trabalho das primitivas Qiskit Runtime exige que os circuitos sejam transformados para usar somente as instruções compatíveis com a QPU (chamadas de circuitos ISA). As primitivas de referência ainda aceitam instruções abstratas, pois dependem de simulações de vetores de estado locais, mas a transpilação do circuito ainda pode ser benéfica em termos de otimização do circuito.
# Generate a pass manager without providing a backend
from qiskit.transpiler import generate_preset_pass_manager
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(qc)Inicializar SamplerV2
Instanciar qiskit.primitives.StatevectorSampler:
from qiskit.primitives import StatevectorSampler
sampler = StatevectorSampler()Corra e obtenha resultados
# execute 1 circuit with Sampler
job = sampler.run([circuit])
pub_result = job.result()[0]
print(f" > Result class: {type(pub_result)}")Output:
> Result class: <class 'qiskit.primitives.containers.sampler_pub_result.SamplerPubResult'>
As primitivas aceitam vários PUBs como entradas, e cada PUB obtém seu próprio resultado. Portanto, você pode executar diferentes circuitos com várias combinações de parâmetros/observáveis e recuperar os resultados PUB :
from qiskit.transpiler import generate_preset_pass_manager
# create two circuits
circuit1 = circuit.copy()
circuit2 = circuit.copy()
# transpile circuits
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit1 = pm.run(circuit1)
isa_circuit2 = pm.run(circuit2)
# execute 2 circuits using Sampler
job = sampler.run([(isa_circuit1), (isa_circuit2)])
pub_result_1 = job.result()[0]
pub_result_2 = job.result()[1]
print(f" > Result class: {type(pub_result)}")Output:
> Result class: <class 'qiskit.primitives.containers.sampler_pub_result.SamplerPubResult'>
Obtenha a distribuição de probabilidade ou o resultado da medição
As amostras de resultados de medição são retornadas como cadeias de bits ou contagens. As cadeias de bits mostram os resultados da medição, preservando a ordem de disparo em que foram medidos. Os objetos de resultado do Sampler organizam os dados em termos dos nomes de registros clássicos dos circuitos de entrada, para compatibilidade com circuitos dinâmicos.
O nome do registro clássico tem como padrão "meas". Esse nome será usado posteriormente para acessar os bitstrings de medição.
# Define quantum circuit with 2 qubits
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw()Output:
┌───┐ ░ ┌─┐
q_0: ┤ H ├──■───░─┤M├───
└───┘┌─┴─┐ ░ └╥┘┌─┐
q_1: ─────┤ X ├─░──╫─┤M├
└───┘ ░ ║ └╥┘
meas: 2/══════════════╩══╩═
0 1
# Transpile circuit
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(circuit)
# Run using Sampler
result = sampler.run([circuit]).result()
# Access result data for PUB 0
data_pub = result[0].data
# Access bitstring for the classical register "meas"
bitstrings = data_pub.meas.get_bitstrings()
print(f"The number of bitstrings is: {len(bitstrings)}")
# Get counts for the classical register "meas"
counts = data_pub.meas.get_counts()
print(f"The counts are: {counts}")Output:
The number of bitstrings is: 1024
The counts are: {'11': 519, '00': 505}
Alterar opções de execução
Por padrão, o Sampler de referência executa um cálculo exato do vetor de estado com base no quantum_info.Statevector classe.
No entanto, isso pode ser modificado para introduzir o efeito da sobrecarga de amostragem (também conhecido como "ruído de disparo"). Para ajudar a gerenciar essa sobrecarga, a interface do Sampler aceita um argumento shots que pode ser definido no nível PUB.
Este exemplo pressupõe que você tenha definido dois circuitos.
# Sample two circuits at 128 shots each.
sampler.run([isa_circuit1, isa_circuit2], shots=128)
# Sample two circuits at different amounts of shots. The "None"s are necessary
# as placeholders
# for the lack of parameter values in this example.
sampler.run([(isa_circuit1, None, 123), (isa_circuit2, None, 456)])Output:
<qiskit.primitives.primitive_job.PrimitiveJob at 0x7fab09442490>
Para ver um exemplo completo, consulte a página de exemplos do Sampler.
Próximas etapas
- Para obter uma simulação de maior desempenho que possa lidar com circuitos maiores ou para incorporar modelos de ruído em sua simulação, consulte Simulação exata e com ruído com primitivas Qiskit Aer.
- Para saber como usar o Quantum Composer para simulação, consulte o guia IBM Quantum Composer.
- Leia a referência da API do Qiskit Estimator.
- Leia a referência da API do Qiskit Sampler.