量子トモグラフィー¶
はじめに¶
量子トモグラフィー ( Quantum tomography ) は、量子系の一部の記述を、特定の実験の測定結果から再構築する実験的な手法である。 Qiskit では、以下の種類のトモグラフィーを実装しています。
量子状態トモグラフィー: 状態にシステムを準備する状態準備回路が与えられています。 システムで得られた実際の状態の密度行列 \(\rho\) を再構築します。
Quantum process tomography: Given a circuit, reconstruct a description of the quantum channel \(\mathcal{E}\) that describes the circuit’s operator when running on the system.
Quantum gate set tomography: Performs process tomography on a set of gates in a self-consistent manner, meaning quantum noises on gates used by the tomography process itself is also taken into account.
このノートブックでは、ignis.verification.tomography
モジュールの使用方法を説明します。
[1]:
# Needed for functions
import numpy as np
import time
from copy import deepcopy
# Import Qiskit classes
import qiskit
import qiskit.quantum_info as qi
from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, Aer
from qiskit.providers.aer import noise
from qiskit.compiler import assemble
# Tomography functions
from qiskit.ignis.verification.tomography import state_tomography_circuits, StateTomographyFitter
from qiskit.ignis.verification.tomography import process_tomography_circuits, ProcessTomographyFitter
from qiskit.ignis.verification.tomography import gateset_tomography_circuits, GatesetTomographyFitter
import qiskit.ignis.mitigation.measurement as mc
# Auxiliary methods
from qiskit.quantum_info import Choi, Kraus
from qiskit.extensions import HGate, XGate
最初の例¶
2量子ビットの状態トモグラフィーの例¶
以下の例では、量子ビット3と5の間の2Qベルの状態トモグラフィーを行います。 参照回路を作るために、qubit 0 と 1 の間に statevector_simulator
を使用して期待される状態ベクトルを生成します。
[2]:
# Create the expected statevector
q2 = QuantumRegister(2)
bell = QuantumCircuit(q2)
bell.h(q2[0])
bell.cx(q2[0], q2[1])
print(bell)
target_state_bell = qi.Statevector.from_instruction(bell)
print(target_state_bell)
┌───┐
q0_0: ┤ H ├──■──
└───┘┌─┴─┐
q0_1: ─────┤ X ├
└───┘
Statevector([0.70710678+0.j, 0. +0.j, 0. +0.j,
0.70710678+0.j],
dims=(2, 2))
[3]:
# Create the actual circuit
q2 = QuantumRegister(6)
bell = QuantumCircuit(q2)
bell.h(q2[3])
bell.cx(q2[3], q2[5])
print(bell)
q1_0: ──────────
q1_1: ──────────
q1_2: ──────────
┌───┐
q1_3: ┤ H ├──■──
└───┘ │
q1_4: ───────┼──
┌─┴─┐
q1_5: ─────┤ X ├
└───┘
ここでは状態トモグラフィー回路を生成して実行します。測定したい2つのレジスタを渡すだけでは、状態トモグラフィは \(2^2\) ヒルベルト空間の縮小版でしか実行されません。しかし、レジスタ全体を渡すと、状態トモグラフィモジュールは \(2^6\) 空間にフィットするように動作します。
[4]:
# Generate circuits and run on simulator
t = time.time()
# Generate the state tomography circuits.
qst_bell = state_tomography_circuits(bell, [q2[3], q2[5]])
# Execute
job = qiskit.execute(qst_bell, Aer.get_backend('qasm_simulator'), shots=5000)
print('Time taken:', time.time() - t)
# Fit result
tomo_fitter_bell = StateTomographyFitter(job.result(), qst_bell)
Time taken: 0.3742101192474365
フィッターは state_tomography_circuits
にレジスタに渡した方法に従って順序付けされた密度行列を出力します。
[5]:
# Perform the tomography fit
# which outputs a density matrix
rho_fit_bell = tomo_fitter_bell.fit(method='lstsq')
F_bell = qi.state_fidelity(rho_fit_bell, target_state_bell)
print('State Fidelity: F = {:.5f}'.format(F_bell))
State Fidelity: F = 0.99796
測定ノイズを入れて上記の例を繰り返します¶
[6]:
#Add measurement noise
noise_model = noise.NoiseModel()
for qubit in range(6):
read_err = noise.errors.readout_error.ReadoutError([[0.75, 0.25],[0.1,0.9]])
noise_model.add_readout_error(read_err,[qubit])
#generate the calibration circuits
meas_calibs, state_labels = mc.complete_meas_cal(qubit_list=[3,5])
backend = Aer.get_backend('qasm_simulator')
job_cal = qiskit.execute(meas_calibs, backend=backend, shots=15000, noise_model=noise_model)
job_tomo = qiskit.execute(qst_bell, backend=backend, shots=15000, noise_model=noise_model)
meas_fitter = mc.CompleteMeasFitter(job_cal.result(),state_labels)
tomo_bell = StateTomographyFitter(job_tomo.result(), qst_bell)
#no correction
rho_bell = tomo_bell.fit(method='lstsq')
F_bell = qi.state_fidelity(rho_bell, target_state_bell)
print('State fidelity (no correction): F = {:.5f}'.format(F_bell))
#correct data
correct_tomo_results = meas_fitter.filter.apply(job_tomo.result(), method='least_squares')
tomo_bell_mit = StateTomographyFitter(correct_tomo_results, qst_bell)
rho_fit_bell_mit = tomo_bell_mit.fit(method='lstsq')
F_bell_mit = qi.state_fidelity(rho_fit_bell_mit, target_state_bell)
print('State fidelity (w/ correction): F = {:.5f}'.format(F_bell_mit))
State fidelity (no correction): F = 0.56463
State fidelity (w/ correction): F = 0.98752
1量子ビットの状態トモグラフィーの例¶
[7]:
# Process tomography of a Hadamard gate
q = QuantumRegister(1)
circ = QuantumCircuit(q)
circ.h(q[0])
# Get the ideal unitary operator
target_unitary = qi.Operator(circ)
# Generate process tomography circuits and run on qasm simulator
qpt_circs = process_tomography_circuits(circ, q)
job = qiskit.execute(qpt_circs, Aer.get_backend('qasm_simulator'), shots=4000)
# Extract tomography data so that counts are indexed by measurement configuration
qpt_tomo = ProcessTomographyFitter(job.result(), qpt_circs)
qpt_tomo.data
[7]:
{(('Zp',), ('X',)): {'0': 4000},
(('Zp',), ('Y',)): {'0': 2013, '1': 1987},
(('Zp',), ('Z',)): {'0': 1973, '1': 2027},
(('Zm',), ('X',)): {'1': 4000},
(('Zm',), ('Y',)): {'0': 1938, '1': 2062},
(('Zm',), ('Z',)): {'0': 1979, '1': 2021},
(('Xp',), ('X',)): {'0': 1991, '1': 2009},
(('Xp',), ('Y',)): {'0': 1998, '1': 2002},
(('Xp',), ('Z',)): {'0': 4000},
(('Yp',), ('X',)): {'0': 1990, '1': 2010},
(('Yp',), ('Y',)): {'1': 4000},
(('Yp',), ('Z',)): {'0': 1997, '1': 2003}}
[8]:
# Tomographic reconstruction
t = time.time()
choi_fit_lstsq = qpt_tomo.fit(method='lstsq')
print('Fit time:', time.time() - t)
print('Average gate fidelity: F = {:.5f}'.format(qi.average_gate_fidelity(choi_fit_lstsq, target=target_unitary)))
Fit time: 0.008244037628173828
Average gate fidelity: F = 0.99722
2量子ビットスワップゲートの 1量子ビットプロセストモグラフィーについて¶
qubit-0 を準備し、 qubit-1 を測定して、再構成されたチャネルが恒等演算になるようにします。
[9]:
# Process tomography of a Hadamard gate
q = QuantumRegister(2)
circ = QuantumCircuit(q)
circ.swap(q[0], q[1])
# Generate process tomography circuits and run on qasm simulator
# We use the optional prepared_qubits kwarg to specify that the prepared qubit was different to measured qubit
qpt_circs = process_tomography_circuits(circ, q[1], prepared_qubits=q[0])
job = qiskit.execute(qpt_circs, Aer.get_backend('qasm_simulator'), shots=2000)
# Extract tomography data so that counts are indexed by measurement configuration
qpt_tomo = ProcessTomographyFitter(job.result(), qpt_circs)
qpt_tomo.data
[9]:
{(('Zp',), ('X',)): {'0': 975, '1': 1025},
(('Zp',), ('Y',)): {'0': 1009, '1': 991},
(('Zp',), ('Z',)): {'0': 2000},
(('Zm',), ('X',)): {'0': 1046, '1': 954},
(('Zm',), ('Y',)): {'0': 989, '1': 1011},
(('Zm',), ('Z',)): {'1': 2000},
(('Xp',), ('X',)): {'0': 2000},
(('Xp',), ('Y',)): {'0': 1016, '1': 984},
(('Xp',), ('Z',)): {'0': 1003, '1': 997},
(('Yp',), ('X',)): {'0': 969, '1': 1031},
(('Yp',), ('Y',)): {'0': 2000},
(('Yp',), ('Z',)): {'0': 992, '1': 1008}}
[10]:
# Tomographic reconstruction
t = time.time()
choi_fit = qpt_tomo.fit(method='lstsq')
print('Fit time:', time.time() - t)
print('Average gate fidelity: F = {:.5f}'.format(qi.average_gate_fidelity(choi_fit)))
Fit time: 0.008944988250732422
Average gate fidelity: F = 0.99541
先進的な例¶
ランダムな状態の生成とフィッティング¶
ここでは、ランダムな1量子ビットのユニタリーu3の層で構成される回路で生成された状態に関する関数をテストします。
[11]:
def random_u_tomo(nq, shots):
def rand_angles():
return tuple(2 * np.pi * np.random.random(3) - np.pi)
q = QuantumRegister(nq)
circ = QuantumCircuit(q)
for j in range(nq):
circ.u(*rand_angles(), q[j])
target_state = qi.Statevector.from_instruction(circ)
qst_circs = state_tomography_circuits(circ, q)
job = qiskit.execute(qst_circs, Aer.get_backend('qasm_simulator'),
shots=shots)
tomo_data = StateTomographyFitter(job.result(), qst_circs)
rho_fit = tomo_data.fit(method='lstsq')
print('F = {:.5f}'.format(qi.state_fidelity(rho_fit, target_state)))
[12]:
for j in range(5):
print('Random single-qubit unitaries: set {}'.format(j))
random_u_tomo(3, 5000)
Random single-qubit unitaries: set 0
F = 0.99913
Random single-qubit unitaries: set 1
F = 0.99580
Random single-qubit unitaries: set 2
F = 0.99601
Random single-qubit unitaries: set 3
F = 0.98930
Random single-qubit unitaries: set 4
F = 0.99547
5量子ビットのベル状態¶
[13]:
# Create a state preparation circuit
q5 = QuantumRegister(5)
bell5 = QuantumCircuit(q5)
bell5.h(q5[0])
for j in range(4):
bell5.cx(q5[j], q5[j + 1])
# Get ideal output state
target_state_bell5 = qi.Statevector.from_instruction(bell5)
# Generate circuits and run on simulator
t = time.time()
qst_bell5 = state_tomography_circuits(bell5, q5)
job = qiskit.execute(qst_bell5, Aer.get_backend('qasm_simulator'), shots=5000)
# Extract tomography data so that counts are indexed by measurement configuration
tomo_bell5 = StateTomographyFitter(job.result(), qst_bell5)
print('Time taken:', time.time() - t)
Time taken: 7.226781845092773
[14]:
t = time.time()
rho_fit_bell5 = tomo_bell5.fit(method='lstsq')
print('Time taken:', time.time() - t)
print('State fidelity: F = {:.5f}'.format(qi.state_fidelity(rho_fit_bell5, target_state_bell5)))
Time taken: 3.6470580101013184
State fidelity: F = 0.99430
2量子ビット条件付き状態トモグラフィー¶
この例では、3量子ビットシステムがあります。1量子ビットは 状態トモグラフィーを実行するための補助となります。 3番目の量子ビットが状態 “1” の場合にのみ、トモグラフィーを行います。 この回路は、条件付きトモグラフィーの後、最初の2量子ビットがベル状態になるように設定されています。
最初に古典的な測定なしで3量子ビットのGHZ状態を作ります。
[15]:
# Create the actual circuit
q2 = QuantumRegister(3)
ghz = QuantumCircuit(q2)
ghz.h(q2[0])
ghz.cx(q2[0], q2[1])
ghz.cx(q2[1], q2[2])
ghz.h(q2[2])
print(ghz)
┌───┐
q11_0: ┤ H ├──■────────────
└───┘┌─┴─┐
q11_1: ─────┤ X ├──■───────
└───┘┌─┴─┐┌───┐
q11_2: ──────────┤ X ├┤ H ├
└───┘└───┘
次に、状態トモグラフィー回路を生成して実行します。状態トモグラフィーを実行したいレジスタだけを渡します。 コードは、それらの測定のための新しい古典レジスタを生成します。
[16]:
qst_ghz = state_tomography_circuits(ghz, [q2[0],q2[1]])
print(qst_ghz[0])
┌───┐ ░ ┌───┐┌─┐
q11_0: ┤ H ├──■─────────────░─┤ H ├┤M├───
└───┘┌─┴─┐ ░ ├───┤└╥┘┌─┐
q11_1: ─────┤ X ├──■────────░─┤ H ├─╫─┤M├
└───┘┌─┴─┐┌───┐ ░ └───┘ ║ └╥┘
q11_2: ──────────┤ X ├┤ H ├─░───────╫──╫─
└───┘└───┘ ░ ║ ║
c10: 2/═════════════════════════════╩══╩═
0 1
次に、この回路のコピーを作成し(フィッターに必要です)、アンシラ測定で新しい回路(これが実行されます)を作成します。
[17]:
#Make a copy without the ancilla register
qst_ghz_no_anc = deepcopy(qst_ghz)
ca = ClassicalRegister(1)
for qst_ghz_circ in qst_ghz:
qst_ghz_circ.add_register(ca)
qst_ghz_circ.measure(q2[2],ca[0])
[18]:
#Run in Aer
job = qiskit.execute(qst_ghz, Aer.get_backend('qasm_simulator'), shots=10000)
raw_results = job.result()
状態トモグラフィーフィッターに結果を送信する前に、Q2測定用にレジスタを取り外し、そのレジスタが1の場合にのみ結果を保持する必要があります。
[19]:
new_result = deepcopy(raw_results)
for resultidx, _ in enumerate(raw_results.results):
old_counts = raw_results.get_counts(resultidx)
new_counts = {}
#change the size of the classical register
new_result.results[resultidx].header.creg_sizes = [new_result.results[resultidx].header.creg_sizes[0]]
new_result.results[resultidx].header.clbit_labels = new_result.results[resultidx].header.clbit_labels[0:-1]
new_result.results[resultidx].header.memory_slots = 2
for reg_key in old_counts:
reg_bits = reg_key.split(' ')
if reg_bits[0]=='1':
new_counts[reg_bits[1]]=old_counts[reg_key]
new_result.results[resultidx].data.counts = new_counts
[20]:
tomo_bell = StateTomographyFitter(new_result, qst_ghz_no_anc)
# Perform the tomography fit
# which outputs a density matrix
rho_fit_bell = tomo_bell.fit(method='lstsq')
[21]:
np.around(rho_fit_bell, 3)
[21]:
array([[ 0.502+0.j , 0. +0.001j, 0.004+0.001j, -0.498-0.006j],
[ 0. -0.001j, 0.001+0.j , -0.001-0.j , -0.002+0.j ],
[ 0.004-0.001j, -0.001+0.j , 0.001+0.j , -0.003+0.001j],
[-0.498+0.006j, -0.002-0.j , -0.003-0.001j, 0.497+0.j ]])
ゲートセット・トモグラフィー¶
1量子ビットのゲートセット・トモグラフィーの例¶
ゲート・セット・トモグラフィーとプロセス・トモグラフィーの主な違いは、ゲート・セット・トモグラフィーにおいて、入力はゲート・セット・ベースで構成されており、これらのゲートのセットは、トモグラフィーの初期化 /測定フェーズで使用され、再構成されています。
Qiskit はデフォルトのゲートセットベースを提供しています。 このゲートセットベースを使って別のゲートを再構築するために、このゲートをゲートセットベースに追加する必要があります。以下の方法を使用してプロセスを簡素化します。
[22]:
from qiskit.ignis.verification.tomography.basis import default_gateset_basis
def collect_tomography_data(shots=10000,
noise_model=None,
gateset_basis='Standard GST'):
backend_qasm = Aer.get_backend('qasm_simulator')
circuits = gateset_tomography_circuits(gateset_basis=gateset_basis)
qobj = assemble(circuits, shots=shots)
result = backend_qasm.run(qobj, noise_model=noise_model).result()
fitter = GatesetTomographyFitter(result, circuits, gateset_basis)
return fitter
def gate_set_tomography(gate, noise_model=None):
basis = default_gateset_basis()
basis.add_gate(gate)
fitter = collect_tomography_data(shots=10000, noise_model=noise_model, gateset_basis=basis)
result_gates = fitter.fit()
result_gate = result_gates[gate.name]
return Choi(result_gate)
ノイズ無しの1量子ビットゲートセット・トモグラフィー¶
[23]:
target_unitary = qi.Operator(HGate())
t = time.time()
channel_fit = gate_set_tomography(HGate())
print('fit time:', time.time() - t)
print('Average gate fidelity: F = {:.5f}'.format(qi.average_gate_fidelity(channel_fit, target_unitary)))
fit time: 2.530395746231079
Average gate fidelity: F = 1.00084
[26]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
/Users/cjwood/anaconda3/envs/qiskit-legacy/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
and should_run_async(code)
/Users/cjwood/anaconda3/envs/qiskit-legacy/lib/python3.7/site-packages/qiskit/tools/jupyter/__init__.py:134: RuntimeWarning: matplotlib can't be found, ensure you have matplotlib and other visualization dependencies installed. You can run '!pip install qiskit-terra[visualization]' to install it from jupyter
"jupyter", RuntimeWarning)
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.22.0 |
Terra | 0.15.2 |
Aer | 0.6.1 |
Ignis | 0.4.0 |
Aqua | 0.7.5 |
IBM Q Provider | 0.10.0 |
System information | |
Python | 3.7.9 (default, Aug 31 2020, 07:22:35) [Clang 10.0.0 ] |
OS | Darwin |
CPUs | 6 |
Memory (Gb) | 32.0 |
Tue Nov 03 13:53:54 2020 EST |
This code is a part of Qiskit
© Copyright IBM 2017, 2020.
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.