Primitivas
qiskit.primitives
As primitivas são blocos de construção computacionais a serem usados em aplicativos maiores cujas unidades de entrada, chamadas de blocos unificados primitivos (PUBs), exigem recursos quânticos para produzir saídas com eficiência.
Atualmente, há dois tipos de primitivos cujas abstrações, em suas versões mais recentes, são definidas por BaseSamplerV2 e BaseEstimatorV2. Os amostradores são responsáveis por aceitar circuitos quânticos (ou varreduras de valores sobre circuitos parametrizados) e fazer a amostragem de seus registros de saída clássicos. Os estimadores aceitam combinações de circuitos e observáveis (ou suas varreduras) para estimar os valores de expectativa dos observáveis.
O Qiskit oferece uma implementação de referência para cada uma dessas abstrações na seção StatevectorSampler e StatevectorEstimator classes.
As versões anteriores das abstrações do amostrador e do estimador são definidas por BaseSamplerV1 e BaseEstimatorV1. Essas interfaces seguem um formato de entrada e saída diferente e menos flexível para o método run e foram amplamente substituídas na prática por BaseSamplerV2 e BaseEstimatorV2. No entanto, as definições originais da interface abstrata foram mantidas para fins de compatibilidade com versões anteriores. Consulte a seção de migração desta página para ver mais detalhes sobre a diferença entre V1 e V2.
Visão geral do EstimatorV2
BaseEstimatorV2 é um primitivo que estima os valores de expectativa para o circuito quântico fornecido e as combinações observáveis.
Após a construção, um estimador é usado chamando seu método run() com uma lista de pubs (Primitive Unified Blocs). Cada bar contém três valores que, juntos, definem uma unidade de trabalho de computação para o estimador concluir:
- um único
QuantumCircuit, possivelmente parametrizado, cujo estado final definimos como , - um ou mais observáveis (especificados como qualquer
ObservablesArrayLike, incluindoPauli,SparsePauliOp,str) que especificam quais valores de expectativa devem ser estimados, denotados , e - uma coleção de conjuntos de valores de parâmetros aos quais o circuito deve ser vinculado, .
A execução de um estimador retorna um objeto BasePrimitiveJob onde a chamada do método result() resulta em estimativas de valores de expectativa e metadados para cada pub:
A parte de valores de parâmetros e observáveis de um pub pode ser avaliada em uma matriz com dimensões arbitrárias, onde as regras de transmissão padrão são aplicadas, de modo que, por sua vez, o resultado estimado para cada pub também é, em geral, avaliado em uma matriz. Para obter mais informações, consulte aqui.
Aqui está um exemplo de como um estimador é usado.
from qiskit.primitives import StatevectorEstimator as Estimator
from qiskit.circuit.library import RealAmplitudes
from qiskit.quantum_info import SparsePauliOp
psi1 = RealAmplitudes(num_qubits=2, reps=2)
psi2 = RealAmplitudes(num_qubits=2, reps=3)
H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
H2 = SparsePauliOp.from_list([("IZ", 1)])
H3 = SparsePauliOp.from_list([("ZI", 1), ("ZZ", 1)])
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 1, 2, 3, 5, 8, 13]
theta3 = [1, 2, 3, 4, 5, 6]
estimator = Estimator()
# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
job = estimator.run([(psi1, H1, [theta1])])
job_result = job.result() # It will block until the job finishes.
print(f"The primitive-job finished with result {job_result}")
# calculate [ [<psi1(theta1)|H1|psi1(theta1)>,
# <psi1(theta3)|H3|psi1(theta3)>],
# [<psi2(theta2)|H2|psi2(theta2)>] ]
job2 = estimator.run(
[
(psi1, [H1, H3], [theta1, theta3]),
(psi2, H2, theta2)
],
precision=0.01
)
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")Visão geral do SamplerV2
BaseSamplerV2 é um primitivo que coleta amostras de saídas de circuitos quânticos.
Após a construção, um sampler é usado chamando seu método run() com uma lista de pubs (Primitive Unified Blocs). Cada pub contém valores que, juntos, definem uma unidade computacional de trabalho para o amostrador concluir:
- Um único
QuantumCircuitpossivelmente parametrizado. - Um conjunto de valores de parâmetros de coleção para vincular o circuito se ele for paramétrico.
- Opcionalmente, o número de disparos para amostragem, determinado no método de execução, se não estiver definido.
A execução de um sampler retorna um BasePrimitiveJob objeto, em que a chamada do método result() resulta na geração de amostras de saída e metadados para cada publicação.
Aqui está um exemplo de como um sampler é usado.
from qiskit.primitives import StatevectorSampler as Sampler
from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes
# create a Bell circuit
bell = QuantumCircuit(2)
bell.h(0)
bell.cx(0, 1)
bell.measure_all()
# create two parameterized circuits
pqc = RealAmplitudes(num_qubits=2, reps=2)
pqc.measure_all()
pqc2 = RealAmplitudes(num_qubits=2, reps=3)
pqc2.measure_all()
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 2, 3, 4, 5, 6, 7]
# initialization of the sampler
sampler = Sampler()
# collect 128 shots from the Bell circuit
job = sampler.run([bell], shots=128)
job_result = job.result()
print(f"The primitive-job finished with result {job_result}")
# run a sampler job on the parameterized circuits
job2 = sampler.run([(pqc, theta1), (pqc2, theta2)])
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")Visão geral do EstimatorV1
Atualmente, não há implementações da interface herdada EstimatorV1 no Qiskit. No entanto, a definição da interface abstrata de BaseEstimatorV1 ainda faz parte do pacote para oferecer compatibilidade com versões anteriores para implementações externas.
Uma implementação do EstimatorV1 é inicializada com um conjunto de parâmetros vazio. BaseEstimatorV1 pode ser chamado pelo método .run() com os seguintes parâmetros:
- circuitos quânticos ( ): lista de circuitos quânticos (parametrizados) (uma lista de
QuantumCircuitobjetos). - observáveis ( ): uma lista de
SparsePauliOpobjetos. - parameter values ( ): lista de conjuntos de valores a serem vinculados aos parâmetros dos circuitos quânticos (lista de lista de float).
O método deve retornar um JobV1 objeto. A chamada qiskit.providers.JobV1.result() retorna uma lista de valores esperados, além de metadados opcionais, como intervalos de confiança para a estimativa.
Aqui está um exemplo de como uma implementação do EstimatorV1 seria usada. Observe que atualmente não há implementações da interface herdada EstimatorV1 no Qiskit.
# This is a fictional import path.
# There are currently no EstimatorV1 implementations in Qiskit.
from estimator_v1_location import EstimatorV1
from qiskit.circuit.library import RealAmplitudes
from qiskit.quantum_info import SparsePauliOp
psi1 = RealAmplitudes(num_qubits=2, reps=2)
psi2 = RealAmplitudes(num_qubits=2, reps=3)
H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
H2 = SparsePauliOp.from_list([("IZ", 1)])
H3 = SparsePauliOp.from_list([("ZI", 1), ("ZZ", 1)])
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 1, 2, 3, 5, 8, 13]
theta3 = [1, 2, 3, 4, 5, 6]
estimator = EstimatorV1()
# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
job = estimator.run([psi1], [H1], [theta1])
job_result = job.result() # It will block until the job finishes.
print(f"The primitive-job finished with result {job_result}")
# calculate [ <psi1(theta1)|H1|psi1(theta1)>,
# <psi2(theta2)|H2|psi2(theta2)>,
# <psi1(theta3)|H3|psi1(theta3)> ]
job2 = estimator.run(
[psi1, psi2, psi1],
[H1, H2, H3],
[theta1, theta2, theta3]
)
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")Visão geral do SamplerV1
Atualmente, não há implementações da interface herdada SamplerV1 no Qiskit. No entanto, a definição da interface abstrata de BaseSamplerV1 ainda faz parte do pacote para oferecer compatibilidade com versões anteriores para implementações externas.
As classes de amostradores calculam probabilidades ou quase-probabilidades de cadeias de bits de circuitos quânticos.
O site SamplerV1 é inicializado com um conjunto de parâmetros vazio. BaseSamplerV1 podem ser chamadas por meio do método .run() com os seguintes parâmetros:
- quantum circuits ( ): lista de circuitos quânticos (parametrizados). (uma lista de
QuantumCircuitobjetos) - parameter values ( ): lista de conjuntos de valores de parâmetros a serem vinculados aos parâmetros dos circuitos quânticos. (lista de lista de float)
.run() retornará um objeto JobV1 objeto. Chamada qiskit.providers.JobV1.result() gera um objeto SamplerResult que contém probabilidades ou quase-probabilidades de cadeias de bits, além de metadados opcionais como barras de erro nas amostras.
Aqui está um exemplo de como uma implementação do SamplerV1 seria usada. Observe que atualmente não há implementações da interface herdada SamplerV1 no Qiskit.
# This is a fictional import path.
# There are currently no SamplerV1 implementations in Qiskit.
from sampler_v1_location import Sampler
from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes
# a Bell circuit
bell = QuantumCircuit(2)
bell.h(0)
bell.cx(0, 1)
bell.measure_all()
# two parameterized circuits
pqc = RealAmplitudes(num_qubits=2, reps=2)
pqc.measure_all()
pqc2 = RealAmplitudes(num_qubits=2, reps=3)
pqc2.measure_all()
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 2, 3, 4, 5, 6, 7]
# initialization of the sampler
sampler = SamplerV1()
# Sampler runs a job on the Bell circuit
job = sampler.run(
circuits=[bell], parameter_values=[[]], parameters=[[]]
)
job_result = job.result()
print([q.binary_probabilities() for q in job_result.quasi_dists])
# Sampler runs a job on the parameterized circuits
job2 = sampler.run(
circuits=[pqc, pqc2],
parameter_values=[theta1, theta2],
parameters=[pqc.parameters, pqc2.parameters])
job_result = job2.result()
print([q.binary_probabilities() for q in job_result.quasi_dists])Migração de Primitives V1 para V2
A distinção formal entre as APIs de primitivas V1 e V2 reside nas classes base das quais as implementações de primitivas herdam, todas listadas no final da página. No entanto, em termos conceituais, aqui estão algumas diferenças importantes a serem levadas em conta ao migrar de V1 para V2:
-
As primitivas do V2 favorecem entradas vetorizadas, em que os circuitos individuais podem ser agrupados com especificações de valor vetorial (ou, de modo mais geral, de valor de matriz). Cada grupo é chamado de bloco unificado primitivo (pub), e cada pub obtém seu próprio resultado. Por exemplo, no estimador, você pode comparar as seguintes diferenças:
# Favoured V2 pattern. There is only one pub here, but there could be more. job = estimator_v2.run([(circuit, [obs1, obs2, obs3, obs4])]) evs = job.result()[0].data.evs # V1 equivalent, where the same circuit must be provided four times. job = estimator_v1.run([circuit] * 4, [obs1, obs2, obs3, obs4]) evs = job.result().valuesNão mostrado no exemplo acima, por questões de brevidade, é o fato de que o circuito pode ser paramétrico, com matrizes de conjuntos de valores de parâmetros transmitidos contra a matriz de observáveis. O amostrador é semelhante, mas sem observáveis:
# Favoured V2 pattern. There is only one pub here, but there could be more. job = sampler_v2.run([(circuit, [vals1, vals2, vals3])]) samples = job.result()[0].data # V1 equivalent, where the same circuit must be provided three times. sampler_v1.run([circuit] * 3, [vals1, vals2, vals3]) quasi_dists = job.result().quasi_dists -
O amostrador V2 retorna amostras de resultados clássicos, preservando a ordem de disparo em que foram medidos. Isso contrasta com o amostrador V1 que produz distribuições de quase-probabilidade que, em vez disso, são uma estimativa da distribuição dos resultados clássicos. Além disso, os objetos de resultado do amostrador V2 organizam os dados em termos dos nomes de registros clássicos dos circuitos de entrada, o que proporciona compatibilidade natural com circuitos dinâmicos.
O análogo mais próximo das distribuições de quase-probabilidade na interface V2 é o método
get_counts()mostrado no exemplo abaixo. No entanto, enfatizamos que, para experimentos em escala de utilidade (mais de 100 qubits), as chances de medir a mesma cadeia de bits duas vezes são pequenas, de modo que o agrupamento de contagens semelhantes em um formato de dicionário não será normalmente uma estratégia eficiente de processamento de dados.circuit = QuantumCircuit(QuantumRegister(2, "qreg"), ClassicalRegister(2, "alpha")) circuit.h(0) circuit.cx(0, 1) circuit.measure([0, 1], [0, 1]) # V1 sampler usage result = sampler_v1.run([circuit]).result() quasi_dist = result.quasi_dists[0] # V2 sampler usage result = sampler_v2.run([circuit]).result() # these are the bit values from the alpha register, over all shots bitvals = result[0].data.alpha # we can use it to generate a Counts mapping, which is similar to a quasi prob distribution counts = bitvals.get_counts() # which can in turn be converted to the V1 type through normalization quasi_dist = QuasiDistribution({outcome: freq / shots for outcome, freq in counts.items()}) -
As primitivas do
V2trouxeram o conceito de sobrecarga de amostragem — inerente a todos os sistemas quânticos devido à sua natureza probabilística — para fora das opções e para dentro da própria API. Para o sampler, isso significa que oshotsargumento agora faz parte darun()assinatura e, além disso, que cada pub pode especificar seu próprio valor parashots, o qual tem precedência sobre qualquer valor atribuído ao método. O estimador possui um argumentoprecisionanálogo que especifica as barras de erro que a implementação primitiva deve ter como meta para as estimativas do valor esperado.Esse conceito não está presente na API das primitivas V1, embora todas as implementações das primitivas V1 tenham configurações relacionadas em algum lugar de suas opções.
# Sample two circuits at 128 shots each. sampler_v2.run([circuit1, 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_v2.run([(circuit1, None, 123), (circuit2, None, 456)]) # Estimate expectation values for two pubs, both with 0.05 precision. estimator_v2.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)
API Primitivas
Parâmetros V2
ParameterLike | Representar um tipo de união |
BindingsArray( [dados, forma] ) | Armazena conjuntos de valores de ligação de parâmetros para um qiskit.QuantumCircuit. |
BindingsArrayLike | Alias de `Mapping[ParameterLike |
Estimador V2
BaseEstimatorV2() | Classe básica para implementações de EstimatorV2 . |
StatevectorEstimator(*[, default_precision,...] ) | Implementação simples de BaseEstimatorV2 com simulação completa do vetor de estado. |
BackendEstimatorV2(*, backend[, opções] ) | Avalia os valores de expectativa para o circuito quântico fornecido e as combinações observáveis. |
EstimatorPub(circuito, grandezas observáveis[,...] ) | Bloco unificado primitivo para qualquer primitiva do Estimator. |
ObservablesArray(observáveis[, número de qubits,...] ) | Um conjunto de dimensão n de observáveis hermitianos para uma Estimator primitiva. |
ObservableLike | Representar um tipo de união |
EstimatorPubLike | alias de EstimatorPub |
ObservablesArrayLike | Alias de `ObservableLike |
Amostrador V2
BaseSamplerV2() | Classe básica para implementações de SamplerV2 . |
StatevectorSampler(*[, default_shots, seed] ) | Implementação simples de BaseSamplerV2 usando simulação de vetor de estado completo. |
BackendSamplerV2(*, backend[, opções] ) | Avalia cadeias de bits para circuitos quânticos fornecidos |
SamplerPub(circuito[, valores_dos_parâmetros,...] ) | Pub (Bloco Unificado Primitivo) para um sampler. |
SamplerPubLike | alias de SamplerPub |
Resultados V2
BitArray(matriz, num_bits) | Armazena uma matriz de valores de bits. |
DataBin(*[, forma] ) | Os principais dados retornados de um único pub fora de PubResult. |
PrimitiveResult(pub_results[, metadados] ) | Um contêiner para vários resultados de pubs e metadados globais. |
PubResult(dados[, metadados] ) | O objeto resultado para um único pub (bloco unificado primitivo). |
SamplerPubResult(dados[, metadados] ) | Resultado do Sampler Pub. |
BasePrimitiveJob(job_id, **kwargs) | Classe base abstrata de trabalho primitivo. |
PrimitiveJob(função, *args, **kwargs) | Lide com uma tarefa a partir das implementações de referência das primitivas no Qiskit. |
Estimador V1
BaseEstimatorV1(*[, opções] ) | Classe básica para implementações de EstimatorV1 . |
EstimatorResult(valores, metadados) | Resultado do Estimador V1. |
Amostrador V1
BaseSamplerV1(*[, opções] ) | Sampler V1 classe base |
SamplerResult(quasi_dists, metadados) | Resultado do Sampler V1. |