[1]:
!pip install qiskit numpy qiskit-aer scipy matplotlib git+https://github.com/quantum-programming/pygridsynth.git pylatexenc
Collecting git+https://github.com/quantum-programming/pygridsynth.git
Cloning https://github.com/quantum-programming/pygridsynth.git to /tmp/pip-req-build-yed1508h
Running command git clone --filter=blob:none --quiet https://github.com/quantum-programming/pygridsynth.git /tmp/pip-req-build-yed1508h
Resolved https://github.com/quantum-programming/pygridsynth.git to commit 5868c650ce819227adcd80eaa8d8e065f4001022
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: qiskit in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (2.1.0)
Requirement already satisfied: numpy in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (2.3.1)
Requirement already satisfied: qiskit-aer in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (0.17.1)
Requirement already satisfied: scipy in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (1.16.0)
Requirement already satisfied: matplotlib in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (3.10.3)
Requirement already satisfied: pylatexenc in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (2.10)
Requirement already satisfied: mpmath in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from pygridsynth==1.1.0) (1.3.0)
Requirement already satisfied: rustworkx>=0.15.0 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from qiskit) (0.16.0)
Requirement already satisfied: dill>=0.3 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from qiskit) (0.4.0)
Requirement already satisfied: stevedore>=3.0.0 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from qiskit) (5.4.1)
Requirement already satisfied: typing-extensions in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from qiskit) (4.14.0)
Requirement already satisfied: psutil>=5 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from qiskit-aer) (7.0.0)
Requirement already satisfied: python-dateutil>=2.8.0 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from qiskit-aer) (2.9.0.post0)
Requirement already satisfied: contourpy>=1.0.1 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from matplotlib) (1.3.2)
Requirement already satisfied: cycler>=0.10 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from matplotlib) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from matplotlib) (4.58.4)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from matplotlib) (1.4.8)
Requirement already satisfied: packaging>=20.0 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from matplotlib) (25.0)
Requirement already satisfied: pillow>=8 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from matplotlib) (11.2.1)
Requirement already satisfied: pyparsing>=2.3.1 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from matplotlib) (3.2.3)
Requirement already satisfied: six>=1.5 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from python-dateutil>=2.8.0->qiskit-aer) (1.17.0)
Requirement already satisfied: pbr>=2.0.0 in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from stevedore>=3.0.0->qiskit) (6.1.1)
Requirement already satisfied: setuptools in /home/mitarai/miniconda3/envs/benkyokai/lib/python3.11/site-packages (from pbr>=2.0.0->stevedore>=3.0.0->qiskit) (78.1.1)
期待値の推定#
ここでは簡単に 1 量子ビットの量子回路で Z 演算子の期待値を推定してみます。
[2]:
from qiskit_aer import AerSimulator
from qiskit import QuantumCircuit
import numpy as np
qc = QuantumCircuit(1)
qc.rx(np.pi/3, 0)
qc.save_statevector()
qc.measure_all()
simulator = AerSimulator(method='statevector')
result = simulator.run(qc, shots=1000).result()
vec = np.asarray(result.get_statevector())
print(vec)
counts = result.get_counts()
print(counts)
print("exact:", vec.conj() @ np.diag([1, -1]) @ vec)
print("estimated:", (counts.get('0', 0) - counts.get('1', 0)) / 1000)
[0.8660254+0.j 0. -0.5j]
{'1': 270, '0': 730}
exact: (0.5000000000000002+0j)
estimated: 0.46
基本的なゲート間の変換をみる#
行列成分を1行で簡単にみれるように関数定義しておきます。
[3]:
from qiskit_aer import AerSimulator
import numpy as np
def get_unitary_from_circuit(qc):
simulator = AerSimulator(method='unitary')
result = simulator.run(qc).result()
return result.get_unitary(qc).data
import matplotlib.pyplot as plt
def display_complex_matrix(matrix, title=None):
fig, ax = plt.subplots(1, 2, figsize=(6, 3)) # Set the figure size to be larger and create two subplots
# Plot the angle of the matrix elements with a fixed color scale
cax1 = ax[0].matshow(np.angle(matrix), cmap='hsv', vmin=-np.pi, vmax=np.pi)
fig.colorbar(cax1, ax=ax[0])
ax[0].set_title('Angle')
# Plot the absolute value of the matrix elements
cax2 = ax[1].matshow(np.abs(matrix), cmap='viridis', vmin=0, vmax=1)
fig.colorbar(cax2, ax=ax[1])
ax[1].set_title('Absolute Value')
if title is not None:
fig.suptitle(title)
plt.show()
\(\mathrm{CNOT} = (I\otimes H) \mathrm{CZ} (I\otimes H)\)
[4]:
from qiskit import QuantumCircuit
# Create a quantum circuit
cnot = QuantumCircuit(2)
cnot.cx(1, 0)
cnot.save_unitary()
# cz
cnot2 = QuantumCircuit(2)
cnot2.h(0)
cnot2.cz(0, 1)
cnot2.h(0)
cnot2.save_unitary()
# Use the AerSimulator to get the unitary matrix
display_complex_matrix(get_unitary_from_circuit(cnot), title="CNOT")
display_complex_matrix(get_unitary_from_circuit(cnot2), title="CZ")


SWAP <-> CNOT
[ ]:
CY <-> CNOT
[ ]:
Rz <-> Rx
[ ]:
CNOT + 1量子ビットゲートの万能性#
色々理屈をこねて証明することはできるが、qiskit には Isometry という名前で任意のユニタリを実現できる関数が実装されているのでそれを使うと万能性を実感できる。原論文は https://arxiv.org/abs/1501.06911 。Qiskit の U3 gate は任意の1量子ビットユニタリに対応する。
[5]:
from scipy.stats import unitary_group
from qiskit.circuit.library.generalized_gates import Isometry
from qiskit import transpile
from qiskit import QuantumCircuit
random_unitary = unitary_group.rvs(2**3)
qc = QuantumCircuit(3)
qc.append(Isometry(random_unitary, 0, 0), qc.qubits)
qc_transpiled = transpile(qc, basis_gates=['u3', 'cx', 'cz'])
print(qc_transpiled.global_phase)
qc_transpiled.draw("mpl")
0.17734088262078984
[5]:

実際に回路を実行してみると、以下のようにしっかり実現できていることが確認できる。
[6]:
qc_transpiled.save_unitary()
display_complex_matrix(get_unitary_from_circuit(qc_transpiled), title="Unitary of circuit")
display_complex_matrix(random_unitary, title="Target unitary")


1 量子ビットゲートを H, T, S だけで表現する#
FTQC では誤り耐性の代償として、離散的なゲートセットのみを実行できる。利用する誤り訂正符号によるが、例えば表面符号では1量子ビットゲートとして利用できるのは H, T, S のみとすることが多い。このような制約下で任意の1量子ビットユニタリを表現する方法を考える。
と言っても先人の知恵を借りるだけでよい。ここでは quantum-programming/pygridsynth を利用する。pip install pygridsynth
でインストールできる。原論文は https://arxiv.org/abs/1403.2975 であり 彼らは Haskell 実装のみを提供しているが、Python に移植したものが pygridsynth である。pygridsynth は体感 1/2 くらいの確率でうまく行かない。本家はそんなことはない。
[ ]:
import pygridsynth
from qiskit.circuit.library import HGate, RZGate
# generate string consisting of {T,H,S,W} which corresponds to Rz(theta) with precision epsilon
# W corresponds to global phase shift of pi/4
theta = np.random.rand()
gates = pygridsynth.gridsynth_gates(theta, epsilon=1e-5)
print(gates)
qc = QuantumCircuit(1)
for gate in gates[::-1]:
if gate == 'T':
qc.t(0)
elif gate == 'H':
qc.h(0)
elif gate == 'S':
qc.s(0)
elif gate == 'W':
qc.global_phase += np.pi/4
qc.save_unitary()
unitary = get_unitary_from_circuit(qc)
print("error: ", np.linalg.norm(get_unitary_from_circuit(qc) - RZGate(theta).to_matrix()))
display_complex_matrix(get_unitary_from_circuit(qc), title="Unitary of circuit")
display_complex_matrix(RZGate(theta).to_matrix(), title="Exact Rz")
2量子ビットパウリによる回転ゲート#
\(exp(i\theta ZZ)\) のような 2 量子ビットのパウリ演算子による回転ゲートは、CNOT と 1 量子ビットゲートを組み合わせることで実現できることを見ます:
[10]:
# exp(-i\theta ZZ) gate
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.quantum_info import SparsePauliOp
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
p = SparsePauliOp('ZZ', 1.0)
qc.append(PauliEvolutionGate(p, time=0.5), [0, 1])
qc = transpile(qc, basis_gates=['u3', 'cx', 'cz'])
qc.save_unitary()
display_complex_matrix(get_unitary_from_circuit(qc), title="ZZGate(0.5)")
# exp ZZ gate can be composed of CNOT and CZ gates
qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.rz(1.0, 1)
qc.cx(0, 1)
qc = transpile(qc, basis_gates=['u3', 'cx', 'cz'])
qc.save_unitary()
display_complex_matrix(get_unitary_from_circuit(qc), title="CNOT + RZ + CNOT")


\(exp(i\theta XX), exp(i\theta YY)\) も同様に実現できます。やってみましょう。