참고
이 페이지는 tutorials/simulators/1_aer_provider.ipynb 에서 생성되었다.
시뮬레이터¶
소개¶
이 노트북은 Qiskit Aer 시뮬레이터 백엔드를 어떻게 가져오고, 이상적인 (잡음이 없는) Qiskit Terra 회로를 실행하는 데 사용할 수 있는지 보여준다.
[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
Aer 공급자¶
Aer
공급자는 각종 시뮬레이터 방법들을 위한 다양한 고성능 시뮬레이터 백엔드들을 포함한다. 현재 시스템에 사용 가능한 백엔드들은 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')]
Aer 시뮬레이터¶
Aer 공급자의 주 시뮬레이터 백엔드는 AerSimulator
백엔드이다. 새로운 시뮬레이터 백엔드는 Aer.get_backend('aer_simulator')
를 사용하여 만들 수 있다.
[3]:
simulator = Aer.get_backend('aer_simulator')
AerSimulator
백엔드의 기본 행동 방식은 실제 장치의 실행 과정을 모방하는 것이다. 만약 측정이 포함된 QuantumCircuit
이 실행된다면 회로의 고전 레지스터들의 최종값들을 포함한 카운트 딕셔너리가 출력될 것이다. 회로는 게이트, 측정, 초기화, 조건, 그리고 다른 맞춤형 시뮬레이터 명령들을 포함할 수 있는데, 이에 관한 더 자세한 내용은 다른 노트북에서 설명될 것이다.
양자 회로 시뮬레이션하기¶
기본 연산은 양자 회로를 실행하고 측정 결과의 카운트를 딕셔너리 형식으로 출력한다. 여기서는 2-큐비트 벨 상태 \(\left|\psi\right\rangle = \frac{1}{2}\left(\left|0,0\right\rangle + \left|1,1 \right\rangle\right)\) 를 준비하고 두 큐비트를 다 측정하는 간단한 회로를 실행한다.
[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]:

매 시행마다 측정의 결과를 반환하기¶
QasmSimulator
도 개별 샷에 대한 측정 결과 목록의 반환을 지원한다. 이는 run
에 키워드 인수 memory=True
를 설정하여 활성화시킬 수 있다.
[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']
Aer 시뮬레이터 속 옵션¶
AerSimulator
백엔드는 set_options
메서드를 사용하여 업데이트할 수 있는 다양한 설정들을 지원한다. 자세한 내용은 AerSimulator
API 문서에서 확인할 수 있다.
시뮬레이션 방법¶
AerSimulator
는 각각 다른 목록의 명령어들을 지원하는 다양한 시뮬레이션 방법들을 지원한다. 이 방법을 simulator.set_option(method=value)
옵션을 통해 수동으로 설정하거나 Aer.get_backend
를 사용해 Aer
제공자에서 바로 시뮬레이션 방법이 다 구성된 시뮬레이터 백엔드를 얻을 수 있다.
이상적인 회로를 시뮬레이션할 때 시뮬레이션 방법을 정확도가 높은 방법들인 stabilizer
, statevector
, density_matrix
, 그리고 matrix_product_state
사이에서 바꾼다면 시뮬레이션 결과는 바뀌지 않을 것이다. (측정 결과에 대한 표본 추출 확률들의 일반적인 변형을 제외한다면)
[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]:

자동 시뮬레이션 방법¶
기본 시뮬레이션 방법은 회로 속 명령어들에 따라 자동으로 시뮬레이션 방법을 선택하는 automatic
이다. 고정 시뮬레이션 방법은 백엔드를 가져올 때 방법 이름을 추가하거나 백엔드에서 method
옵션을 설정하여 지정할 수 있다.
GPU 시뮬레이션¶
statevector
, density_matrix
그리고 unitary
시뮬레이터들은 엔비디아 GPU에서 실행될 수 있다. 이 메서들에 대한 시뮬레이션 장치는 simulator.set_options(device='GPU')
백엔드 옵션을 활용하여 수동으로 CPU나 GPU로 설정할 수 있다. 만약 GPU 장치를 사용할 수 없다면 이러한 옵션은 예외를 발생시킬 것이다.
[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']"
만약 Qiskit Aer가 호환 가능한 시스템에서 GPU 지원이 가능하게 설치된 경우에는 Aer
공급자에 미리 구성된 GPU 시뮬레이터 백엔드들이 포함되어 있을 것이다.
aer_simulator_statevector_gpu
aer_simulator_density_matrix_gpu
aer_simulator_unitary_gpu
참고: Aer의 GPU 버전은 ``pip install qiskit-aer-gpu`` 를 사용하여 설치할 수 있다.
시뮬레이션 정밀도¶
statevector
, density_matrix
, unitary
그리고 superop
방법에 대한 정밀도를 float로 설정하는 옵션도 사용할 수 있다. 이는 set_precision="single"
또는 precision="double"
(기본값) 옵션을 이용해 수행된다:
[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}
시뮬레이션 정밀도를 설정하는 것은 CPU 와 GPU 시뮬레이션 장치 둘 다에 적용된다. 단일 정밀도는 필요한 메모리를 절반으로 줄이고 특정 시스템에 대해 성능을 향상시킬 수 있다.
맞춤형 시뮬레이터 명령들¶
시뮬레이터 상태 저장하기¶
시뮬레이터의 상태는 맞춤형 시뮬레이터 명령들을 사용해 다양한 형식으로 저장될 수 있다.
회로 메서드 |
설명 |
지원되는 메서드들 |
---|---|---|
|
시뮬레이터 상태를 시뮬레이션 방법의 기본 형식으로 저장한다 |
전부 |
|
시뮬레이터 상태를 상태 벡터로 저장한다 |
|
|
시뮬레이터 상태를 Clifford stabilizer로 저장한다 |
|
|
시뮬레이터 상태를 밀도 행렬로 저장한다 |
|
|
시뮬레이터 상태를 행렬 곱 상태 텐서로 저장한다 |
|
|
시뮬레이터 상태를 실행된 회로의 단일 행렬로 저장한다 |
|
|
시뮬레이터 상태를 실행된 회로의 superoperator 행렬로 저장한다 |
|
이러한 명령어들은 Aer 시뮬레이터에서만 지원되고, IBM 양자 장치와 같은 시뮬레이터가 아닌 백엔드에서 이러한 명령어들을 포함한 회로가 실행될 경우 오류가 발생할 것임에 주의하라.
최종 상태 벡터 저장하기¶
시뮬레이션의 최종 상태 벡터를 저장하기 위해서는 회로에 save_statevector
명령어를 추가하면 된다. 측정 후에 붕괴된 상태를 저장하지 않기 위해서는 이 명령어를 꼭 어떠한 측정 전에 적용해야 한다.
[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]:

회로의 단일 행렬 저장하기¶
QuantumCircuit
에 대한 유니터리 행렬을 저장하고 싶다면 회로에 save_unitary
명령어를 추가하면 된다. 다만 이 명령어가 추가된 회로에는 어떠한 측정이나 초기화가 포함될 수 없는데, 이 명령어들은 "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]]
여러 상태 저장하기¶
또한, 명령어 저장은 회로의 여러 장소에 적용될 수 있다. 이렇게 여러 장소에 명령어 저장을 적용할 때에는 각 명령어에 고유한 라벨을 추가해야 결과에서 검색할 수 있다.
[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])}
맞춤형 상태로 시뮬레이터 설정하기¶
AerSimulator
는 몇몇 시뮬레이션 방법을 활용할 때 맞춤 시뮬레이터 명령어를 사용해 맞춤 시뮬레이터 상태를 설정할 수 있게 도와준다.
회로 메서드 |
설명 |
지원되는 메서드들 |
---|---|---|
|
시뮬레이터 상태를 지정된 상태 벡터로 설정한다 |
|
|
시뮬레이터 상태를 지정된 Clifford stabilizer로 설정한다 |
|
|
시뮬레이터 상태를 지정된 밀도 행렬로 설정한다 |
|
|
시뮬레이터 상태를 지정된 단일 행렬로 설정한다 |
|
|
시뮬레이터 상태를 지정된 superoperator 행렬로 설정한다 |
|
유의사항: * 이 명령어들이 회로의 모든 큐비트에 적용되지 않을 경우 예외가 발생한다. * 입력 상태가 유효한 상태가 (상태 벡터, 밀도 행렬, 유니터리 등) 아닐 경우 예외가 발생한다. * 이 명령어들은 회로의 어느 곳에든 적용될 수 있으며, 현재 상태를 지정된 상태로 재정의할 것이다. 이 때 모든 고전 레지스터 값들은 (예: 이전의 측정에서 출력된 값) 영향을 받지 않는다. * 상태 설정 명령어들은 Aer 시뮬레이터에서만 지원되며, 이들을 포함한 회로가 IBM 퀀텀 장치와 같이 시뮬레이터가 아닌 백엔드에서 실행될 경우 오류를 발생시킬 것이다.
맞춤형 상태 벡터 설정하기¶
set_statevector
명령어는 맞춤 Statevector
상태를 설정하기 위해 사용된다. 입력 상태 벡터는 꼭 유효해야 한다 (\(|\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 ])}
초기화 명령어 사용하기¶
initialize
명령어를 활용하여 시뮬레이터를 맞춤 상태 벡터로 초기화할 수도 있다. set_statevector
명령어와는 다르게 이 명령어는 초기화와 기본 게이트 명령어들에 전개되어 적용되기 때문에 실제 장치 백엔드에서도 지원된다.
[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 ])}
맞춤형 밀도 행렬 설정하기¶
set_density_matrix
명령어는 맞춤 DensityMatrix
상태를 설정하기 위해 사용된다. 입력 밀도 행렬은 꼭 유효해야 한다 (\(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]])}
맞춤형 stabilizer 상태 설정하기¶
set_stabilizer
명령어는 맞춤 Clifford
stabilizer 상태를 설정하기 위해 사용된다. 입력 stabilizer는 꼭 유효한 Clifford
여야 한다.
[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']}}
맞춤형 유니터리 설정하기¶
set_unitary
명령어는 맞춤 유니터리 Operator
상태를 설정하기 위해 사용된다. 입력 유니터리 행렬은 꼭 유효해야 한다 (\(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.