Nota
Esta página foi gerada, a partir do tutorials/simulators/1_aer_provider.ipynb.
Execute interativamente no IBM Quantum lab.
Simuladores¶
Introdução¶
Este notebook mostra como importar o serviço do simulador Qiskit Aer e usá-lo para executar circuitos Qiskit Terra ideais (livre de ruído).
[1]:
import numpy as np
# Import Qiskit
from qiskit import QuantumCircuit
from qiskit import Aer, transpile
from qiskit.tools.visualization import plot_histogram, plot_state_city
import qiskit.quantum_info as qi
O Provedor Aer¶
O provedor Aer
contém uma variedade de backends de simuladores de alta performance para vários métodos de simulação. Os serviços disponíveis no sistema atual podem ser visualizados usando Aer.backends
[2]:
Aer.backends()
[2]:
[AerSimulator('aer_simulator'),
AerSimulator('aer_simulator_statevector'),
AerSimulator('aer_simulator_density_matrix'),
AerSimulator('aer_simulator_stabilizer'),
AerSimulator('aer_simulator_matrix_product_state'),
AerSimulator('aer_simulator_extended_stabilizer'),
AerSimulator('aer_simulator_unitary'),
AerSimulator('aer_simulator_superop'),
QasmSimulator('qasm_simulator'),
StatevectorSimulator('statevector_simulator'),
UnitarySimulator('unitary_simulator'),
PulseSimulator('pulse_simulator')]
O Simulador Aer¶
O principal simulador de serviço do provedor Aer é o backend AerSimulator
. Um backend de simulador novo pode ser criado usando Aer.get_backend('aer_simulator')
.
[3]:
simulator = Aer.get_backend('aer_simulator')
O comportamento padrão do serviço AerSimulator
é simular a execução de um dispositivo real. Se um QuantumCircuit
contendo medições for executado ele retornará um dicionário de contagem contendo os valores finais de quaisquer registradores clássicos no circuito. O circuito pode conter portas, medições, resets, condicionais e outras instruções personalizadas do simulador que serão discutidas em outro notebook.
Simulando um circuito quântico¶
A operação básica executa um circuito quântico e retorna um dicionário de contagem dos resultados das medições. Aqui nós executaremos um circuito simples que prepara um estado de Bell de 2 qubits \(\left|\psi\right\rangle = \frac{1}{2}\left(\left|0,0\right\rangle + \left|1,1 \right\rangle\right)\) e mede ambos os qubits.
[4]:
# Create circuit
circ = QuantumCircuit(2)
circ.h(0)
circ.cx(0, 1)
circ.measure_all()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get counts
result = simulator.run(circ).result()
counts = result.get_counts(circ)
plot_histogram(counts, title='Bell-State counts')
[4]:

Retornando resultados de medição para cada repetição (shot)¶
O QasmSimulator
também suporta retornar uma lista de resultados de medição para cada disparo individual. Isto é habilitado configurando o argumento de memory=True
em run
.
[5]:
# Run and get memory
result = simulator.run(circ, shots=10, memory=True).result()
memory = result.get_memory(circ)
print(memory)
['00', '00', '11', '11', '00', '00', '11', '11', '00', '00']
Opções do Simulador Aer¶
O serviço AerSimulator
suporta uma variedade de opções configuráveis que podem ser atualizadas usando o método set_options
. Veja a documentação da API do AerSimulator
para mais detalhes.
Método de Simulação¶
O AerSimulator
suporta uma variedade de métodos de simulação, dos quais cada um contempla um conjunto diferente de instruções. O método pode ser definido manualmente utilizando a opção simulator.set_option(method=value)
, ou um serviço simulador com um método pré-configurado pode ser obtido diretamente do provedor Aer
utilizando Aer.get_backend
.
Ao simular circuitos ideais, mudar o método dentre os de simulação exata stabilizer
, statevector
, density_matrix
e matrix_product_state
não deve alterar o resultado da simulação (a não ser que ocorra variações, às vezes comuns, de probabilidades de amostragem para resultados de medições)
[6]:
# Increase shots to reduce sampling variance
shots = 10000
# Stabilizer simulation method
sim_stabilizer = Aer.get_backend('aer_simulator_stabilizer')
job_stabilizer = sim_stabilizer.run(circ, shots=shots)
counts_stabilizer = job_stabilizer.result().get_counts(0)
# Statevector simulation method
sim_statevector = Aer.get_backend('aer_simulator_statevector')
job_statevector = sim_statevector.run(circ, shots=shots)
counts_statevector = job_statevector.result().get_counts(0)
# Density Matrix simulation method
sim_density = Aer.get_backend('aer_simulator_density_matrix')
job_density = sim_density.run(circ, shots=shots)
counts_density = job_density.result().get_counts(0)
# Matrix Product State simulation method
sim_mps = Aer.get_backend('aer_simulator_matrix_product_state')
job_mps = sim_mps.run(circ, shots=shots)
counts_mps = job_mps.result().get_counts(0)
plot_histogram([counts_stabilizer, counts_statevector, counts_density, counts_mps],
title='Counts for different simulation methods',
legend=['stabilizer', 'statevector',
'density_matrix', 'matrix_product_state'])
[6]:

Método de Simulação Automática¶
O método padrão de simulação é o automatic
que selecionará automaticamente um dos outros métodos de simulação para cada circuito baseado nas instruções desses circuitos. Um método de simulação fixo pode ser especificado adicionando o nome do método ao obter o serviço, ou definindo a opção method
no serviço.
Simulação de GPU¶
Os simuladores statevector
, density_matrix
e unitary
suportam execução em GPUs da NVidia. Para estes métodos, o dispositivo de simulação também pode ser configurado manualmente para CPU ou GPU usando a opção simulator.set_options(device='GPU')
do serviço. Se uma GPU não estiver disponível, esta opção gerará uma exceção (ao executar o código envolvendo o simulador).
[7]:
from qiskit.providers.aer import AerError
# Initialize a GPU backend
# Note that the cloud instance for tutorials does not have a GPU
# so this will raise an exception.
try:
simulator_gpu = Aer.get_backend('aer_simulator')
simulator_gpu.set_options(device='GPU')
except AerError as e:
print(e)
"Invalid simulation device GPU. Available devices are: ['CPU']"
O provedor Aer
também conterá serviços de simuladores GPU pré-configurados se o Qiskit Aer foi instalado com suporte à GPU em um sistema compatível:
aer_simulator_statevector_gpu
aer_simulator_density_matrix_gpu
aer_simulator_unitary_gpu
Nota: A versão para GPU do Aer pode ser instalada usando ``pip install qiskit-aer-gpu``.
Precisão da Simulação¶
Uma das opções de simuladores disponíveis permite definir a precisão de ponto flutuante para os métodos statevector
, density_matrix
unitary
e superop
. Isso é feito utilizando a opção set_precision="single"
ou precision="double"
(padrão):
[8]:
# Configure a single-precision statevector simulator backend
simulator = Aer.get_backend('aer_simulator_statevector')
simulator.set_options(precision='single')
# Run and get counts
result = simulator.run(circ).result()
counts = result.get_counts(circ)
print(counts)
{'11': 509, '00': 515}
Definir a precisão da simulação aplica-se tanto a dispositivos de simulação para CPU quanto para GPU. Uma precisão única reduzirá pela metade a memória requerida e poderá proporcionar melhorias de desempenho em certos sistemas.
Instruções de Simulador Personalizadas¶
Salvando o estado do simulador¶
O estado do simulador pode ser salvo em uma variedade de formatos usando instruções do simulador personalizadas.
Método de Circuito |
Descrição |
Métodos Suportados |
---|---|---|
|
Salve o estado do simulador no formato nativo para o método de simulação |
Todos |
|
Salve o estado do simulador como um vetor de estados |
|
|
Salve o estado do simulador como um estabilizador Clifford |
|
|
Salve o estado do simulador como uma matriz de densidade |
|
|
Salve o estado do simulador como uma matriz de estado do produto tensor |
|
|
Salvar o estado do simulador como matriz unitária do circuito executado |
|
|
Salvar o estado do simulador como matriz superoperadora do circuito executado |
|
Observe que essas instruções somente são suportadas pelo simulador Aer e resultarão em um erro se um circuito que as contenha for executado em um serviço não-simulador, como um dispositivo IBM Quantum.
Salvando o statevector final¶
Para salvar o vetor de estado final da simulação podemos anexar o circuito com a instrução save_statevector
. Observe que esta instrução deve ser aplicada antes de quaisquer medições caso não desejemos salvar o estado colapsado pós-medição
[9]:
# Construct quantum circuit without measure
circ = QuantumCircuit(2)
circ.h(0)
circ.cx(0, 1)
circ.save_statevector()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get statevector
result = simulator.run(circ).result()
statevector = result.get_statevector(circ)
plot_state_city(statevector, title='Bell state')
[9]:

Salvando a unidade do circuito¶
Para salvar a matriz unitária de um QuantumCircuit
, podemos acrescentar no circuito a instrução save_unitary
. Observe que este circuito não pode conter medições ou resets, já que estas instruções não são suportadas pelo método de simulação "unitary"
[10]:
# Construct quantum circuit without measure
circ = QuantumCircuit(2)
circ.h(0)
circ.cx(0, 1)
circ.save_unitary()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get unitary
result = simulator.run(circ).result()
unitary = result.get_unitary(circ)
print("Circuit unitary:\n", unitary.round(5))
Circuit unitary:
[[ 0.70711+0.j 0.70711-0.j 0. +0.j 0. +0.j]
[ 0. +0.j 0. +0.j 0.70711+0.j -0.70711+0.j]
[ 0. +0.j 0. +0.j 0.70711+0.j 0.70711-0.j]
[ 0.70711+0.j -0.70711+0.j 0. +0.j 0. +0.j]]
Salvando multiplos estados¶
Também, podemos aplicar instruções de salvar em vários locais de um circuito. Note que ao fazer isso, nós precisamos fornecer um rótulo único para cada instrução a fim de recuperá-la nos resultados
[11]:
# Construct quantum circuit without measure
steps = 5
circ = QuantumCircuit(1)
for i in range(steps):
circ.save_statevector(label=f'psi_{i}')
circ.rx(i * np.pi / steps, 0)
circ.save_statevector(label=f'psi_{steps}')
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get saved data
result = simulator.run(circ).result()
data = result.data(0)
data
[11]:
{'psi_3': array([0.58778525+0.j , 0. -0.80901699j]),
'psi_2': array([0.95105652+0.j , 0. -0.30901699j]),
'psi_5': array([-1.+0.00000000e+00j, 0.-2.77555756e-16j]),
'psi_1': array([1.+0.j, 0.+0.j]),
'psi_4': array([-0.30901699+0.j , 0. -0.95105652j]),
'psi_0': array([1.+0.j, 0.+0.j])}
Configurar o simulador para um estado personalizado¶
O AerSimulator
permite definir um estado personalizado do simulador para vários de seus métodos de simulação, usando instruções personalizadas do simulador
Método de Circuito |
Descrição |
Métodos Suportados |
---|---|---|
|
Definir o estado do simulador para o vetor de estado especificado |
|
|
Definir o estado do simulador para o estabilizador Clifford especificado |
|
|
Definir o estado do simulador para a matriz de densidade especificada |
|
|
Definir o estado do simulador para a matriz unitária especificada |
|
|
Definir o estado do simulador para a matriz de super-operador especificada |
|
Notas: * Estas instruções devem ser aplicadas a todos os qubits de um circuito, caso contrário uma exceção será gerada. * O estado de entrada também deve ser um estado válido (vetor de estado, matriz de densidade, unitária, etc) caso contrário, uma exceção será gerada. * Estas instruções podem ser aplicadas em qualquer local de um circuito e irão substituir o estado atual pelo especificado. Quaisquer valores de registradores clássicos (por exemplo, de medições anteriores) não serão afetados. * Instruções de definição de estado só são suportadas pelo simulador Aer e resultarão em um erro se um circuito que as contêm for executado em um backend não-simulador, como um dispositivo IBM Quantum, por exemplo.
Configurando um vetor de estados personalizado¶
A instrução set_statevector
pode ser usada para configurar um estado personalizado Statevector
. Porém, o vetor de estado de entrada deve ser válido (\(|\langle\psi|\psi\rangle|=1\))
[12]:
# Generate a random statevector
num_qubits = 2
psi = qi.random_statevector(2 ** num_qubits, seed=100)
# Set initial state to generated statevector
circ = QuantumCircuit(num_qubits)
circ.set_statevector(psi)
circ.save_state()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get saved data
result = simulator.run(circ).result()
result.data(0)
[12]:
{'statevector': array([ 0.18572453-0.03102771j, -0.26191269-0.18155865j,
0.12367038-0.47837907j, 0.66510011-0.4200986j ])}
Usar a instrução de inicialização¶
Também, é possível inicializar o simulador em um vetor de estado personalizado, usando a instrução initialize
; ao contrário da instrução set_statevector
, que também é suportada por backends em dispositivos reais, porém é composta por instruções de reset e de portas padrão.
[13]:
# Use initilize instruction to set initial state
circ = QuantumCircuit(num_qubits)
circ.initialize(psi, range(num_qubits))
circ.save_state()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get result data
result = simulator.run(circ).result()
result.data(0)
[13]:
{'statevector': array([ 0.18572453-0.03102771j, -0.26191269-0.18155865j,
0.12367038-0.47837907j, 0.66510011-0.4200986j ])}
Definindo uma matriz de densidade personalizada¶
A instrução set_density_matrix
pode ser usada para definir um estado personalizado de DensityMatrix
. A matriz de densidade de entrada deve ser válida (\(Tr[\rho]=1, \rho \ge 0\))
[14]:
num_qubits = 2
rho = qi.random_density_matrix(2 ** num_qubits, seed=100)
circ = QuantumCircuit(num_qubits)
circ.set_density_matrix(rho)
circ.save_state()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get saved data
result = simulator.run(circ).result()
result.data(0)
[14]:
{'density_matrix': array([[ 0.2075308 -3.11427124e-18j, 0.13161422-1.76084787e-02j,
0.0442826 +7.74270413e-02j, 0.04852053-1.30317117e-02j],
[ 0.13161422+1.76084787e-02j, 0.20106116-2.89376869e-18j,
0.02568549-3.68981173e-02j, 0.0482903 -4.36791212e-02j],
[ 0.0442826 -7.74270413e-02j, 0.02568549+3.68981173e-02j,
0.39731492+6.09745953e-18j, -0.01114025-1.34264228e-01j],
[ 0.04852053+1.30317117e-02j, 0.0482903 +4.36791212e-02j,
-0.01114025+1.34264228e-01j, 0.19409312-8.94195941e-20j]])}
Configurando um estado estabilizador personalizado¶
A instrução set_stabilizer
pode ser usada para definir um estado de estabilizador Clifford
personalizado. O estabilizador de entrada deve ser um Clifford
válido.
[15]:
# Generate a random Clifford C
num_qubits = 2
stab = qi.random_clifford(num_qubits, seed=100)
# Set initial state to stabilizer state C|0>
circ = QuantumCircuit(num_qubits)
circ.set_stabilizer(stab)
circ.save_state()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get saved data
result = simulator.run(circ).result()
result.data(0)
[15]:
{'stabilizer': {'destabilizer': ['-XZ', '-YX'], 'stabilizer': ['+ZZ', '-IZ']}}
Definindo uma unidade personalizada¶
A instrução set_unitary
pode ser usada para definir um estado Operator
unitário personalizado. A matriz unitária de entrada deve ser válida (\(U^\dagger U=\mathbb{1}\))
[16]:
# Generate a random unitary
num_qubits = 2
unitary = qi.random_unitary(2 ** num_qubits, seed=100)
# Set initial state to unitary
circ = QuantumCircuit(num_qubits)
circ.set_unitary(unitary)
circ.save_state()
# Transpile for simulator
simulator = Aer.get_backend('aer_simulator')
circ = transpile(circ, simulator)
# Run and get saved data
result = simulator.run(circ).result()
result.data(0)
[16]:
{'unitary': array([[-0.44885724-0.26721573j, 0.10468034-0.00288681j,
0.4631425 +0.15474915j, -0.11151309-0.68210936j],
[-0.37279054-0.38484834j, 0.3820592 -0.49653433j,
0.14132327-0.17428515j, 0.19643043+0.48111423j],
[ 0.2889092 +0.58750499j, 0.39509694-0.22036424j,
0.49498355+0.2388685j , 0.25404989-0.00995706j],
[ 0.01830684+0.10524311j, 0.62584001+0.01343146j,
-0.52174025-0.37003296j, 0.12232823-0.41548904j]])}
[17]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.25.0 |
Terra | 0.17.0 |
Aer | 0.8.0 |
Ignis | 0.6.0 |
Aqua | 0.9.0 |
IBM Q Provider | 0.12.2 |
System information | |
Python | 3.7.7 (default, May 6 2020, 04:59:01) [Clang 4.0.1 (tags/RELEASE_401/final)] |
OS | Darwin |
CPUs | 6 |
Memory (Gb) | 32.0 |
Fri Apr 02 11:48:23 2021 EDT |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.