⚛️

Deutsch-Jozsaのアルゴリズムを実装してみた

2025/01/20に公開
2

Zenn初投稿です。
よろしくお願いします。

Deutsch-Jozsaのアルゴリズムについて

量子コンピュータのアルゴリズムの1つです。このアルゴリズムは、実用性は低いものの、ある種の問題においては量子コンピュータが古典コンピュータよりも有利であることを示したという点で重要です。[1]

問題設定


図1. 入力が(n+1)量子ビットのDeutschのゲート
図1のような量子ゲートを考えます。入力は、xn量子ビット)、y(1量子ビット)の2つです。この量子ゲートの入出力は、次のようになっています。

\ket{xy} \stackrel{U}{\to} \ket{x \;y\oplus f(x)}

ここで、\ket{xy} = \ket{x}\otimes\ket{y},\; \ket{x}=\ket{x_{n-1}\,...\,x_0}=\ket{x_{n-1}}\otimes\cdots\otimes\ket{x_0}です。
f(x)は、次のいずれかになります。

  • 定値型(すべてのxに対して、一定の値をとる。その値は、0と1のいずれか。)
  • 分布型(xに対して、0と1の出る頻度が等しい。)
    f(x)が2つのどちらかが分からない場合に、どちらであるか当てる、という問題を考えます。

古典計算機の場合

例えば、y=0と固定したうえで、x=0,1,2,3,\cdotsと代入していって、都度f(x)の出力を見る方法が考えられます。考えうる最悪の場合は、x=2^{n-1}まで代入しても分からなかった場合です。x=2^{n-1}+1まで代入すれば、答えが確定します。つまり、このアルゴリズムでの計算時間のオーダーは、O(2^n)となります。

量子計算機の場合(Deutsch-Jozsaのアルゴリズム)


図2Deutsch-Jozsaのアルゴリズムの量子ゲートの配置

量子ゲートを図2のように配置します。ただし、量子ビットは全て\ket{0}で初期化されています。
バリア(縦線)上での量子状態を、左から順に\ket{\psi_0},\ket{\psi_1},\ket{\psi_2}とします。
まず、\ket{\psi_0}は次のように計算できます。

\begin{aligned} \ket{\psi_0} &= \underbrace{\frac{\ket{0}+\ket{1}}{\sqrt{2}}\otimes\cdots\otimes\frac{\ket{0}+\ket{1}}{\sqrt{2}}}_{n\,\mathrm{qubits}}\otimes\frac{\ket{0}-\ket{1}}{\sqrt{2}}\\ &= \left(\sum_{x\in\{0,1,\cdots,2^n-1\}}\frac{\ket{x}}{2^{n/2}} \right)\otimes \frac{\ket{0}-\ket{1}}{\sqrt{2}}\\ &= \sum_{x\in\{0,1,\cdots,2^n-1\}}\left(\frac{\ket{x}}{2^{n/2}}\otimes \frac{\ket{0}-\ket{1}}{\sqrt{2}}\right) \end{aligned}

\ket{\psi_1}について考える前に、次の式変形を見ておきます。

\begin{aligned} \ket{x}\otimes\frac{\ket{0}-\ket{1}}{\sqrt{2}} &= \frac{\ket{x\,0\oplus f(x)}-\ket{x\,1\oplus f(x)}}{\sqrt{2}}\\ &= \left\{ \begin{array}{ll} \displaystyle\frac{\ket{x\,0}-\ket{x\,1}}{\sqrt{2}}\;\;\;(f(x)=0)\\ \displaystyle-\frac{\ket{x\,0}-\ket{x\,1}}{\sqrt{2}}\;\;\;(f(x)=1) \end{array} \right. \\ &= (-1)^{f(x)}\frac{\ket{x\,0}-\ket{x\,1}}{\sqrt{2}}\\ &= (-1)^{f(x)}\ket{x}\otimes\frac{\ket{0}-\ket{1}}{\sqrt{2}} \end{aligned}

よって、

\begin{aligned} \ket{\psi_1} &= \sum_{x\in\{0,1,\cdots,2^n-1\}}\left(\frac{(-1)^{f(x)}\ket{x}}{2^{n/2}} \otimes \frac{\ket{0}-\ket{1}}{\sqrt{2}}\right)\\ &= \left(\sum_{x\in\{0,1,\cdots,2^n-1\}}\frac{(-1)^{f(x)}\ket{x}}{2^{n/2}}\right) \otimes \frac{\ket{0}-\ket{1}}{\sqrt{2}} \end{aligned}

\psi_2について考える前に、Hadamardゲートについて考えます。まず、1量子ビットに対して作用させたときは、次のようになります。

\begin{aligned} H\ket{x} &= \left\{ \begin{array}{ll} \displaystyle\frac{\ket{0}+\ket{1}}{\sqrt{2}}\;\;\;(\ket{x}=\ket{0})\\ \displaystyle\frac{\ket{0}-\ket{1}}{\sqrt{2}}\;\;\;(\ket{x}=\ket{1}) \end{array} \right.\\ &=\sum_{z=0,1}\frac{(-1)^{xz}}{\sqrt{2}}\ket{z} \end{aligned}

n量子ビットに作用させることをH^{(n)}と表すとすると、H^{(n)}の作用は、次のように書けます。

H^{(n)}\ket{x} = \sum_{z_{n-1}=0,1}\frac{(-1)^{x_{n-1}z_{n-1}}}{\sqrt{2}}\ket{z_{n-1}}\otimes \cdots\otimes\sum_{z_0=0,1}\frac{(-1)^{x_0z_0}}{\sqrt{2}}\ket{z_0}

\ket{0...00}の係数は(-1)^0(-1)^0\cdots(-1)^0\ket{0...01}の係数は(-1)^0(-1)^0\cdots(-1)^{x_0}、と考えていくと、H^{(n)}は次のようにも表せます。

H^{(n)}\ket{x} = \sum_{z\in\{0,1,\cdots,2^n-1\}}\frac{(-1)^{x_{n-1}z_{n-1}+\cdots +x_0z_0}}{2^{n/2}}\ket{z}

よって、

\begin{aligned} \ket{\psi_2} &= \left(\sum_{x\in\{0,1,\cdots,2^n-1\}}\frac{(-1)^{f(x)}}{2^{n/2}}H^{(n)}\ket{x}\right) \otimes \frac{\ket{0}-\ket{1}}{\sqrt{2}}\\ &= \left[\sum_{x\in\{0,1,\cdots,2^n-1\}}\frac{(-1)^{f(x)}}{2^{n/2}}\left( \sum_{z\in\{0,1,\cdots,2^n-1\}}\frac{(-1)^{x_{n-1}z_{n-1}+\cdots +x_0z_0}}{2^{n/2}}\ket{z} \right)\right] \otimes \frac{\ket{0}-\ket{1}}{\sqrt{2}}\\ \end{aligned}

ここで、上位n量子ビットと下位1量子ビットがテンソル積で分解できていることから、上位n量子ビットの状態を\ket{\psi'_2}とおけます。\ket{\psi'_2}から\ket{0...00}の複素振幅を取り出すと、以下のようになります。

\ket{0...00}\braket{0...00|\psi'_2} = \sum_{x\in\{0,1,\cdots,2^n-1\}}\frac{(-1)^{f(x)}}{2^{n/2}}\ket{0...00}

f(x)が定値型であったならば、この係数は\pm 1のいずれかになります。また、f(x)が分布型であったならば、この係数は0となります。
よって、上位n量子ビットを観測した際に状態\ket{\psi'_2}\ket{0...00}に収束する確率は、次のようになります。

|\braket{0...00|\psi'_2}|^2 = \left\{ \begin{array}{ll} 1\;\;\; (f(x)\mathrm{が定値型})\\ 0\;\;\; (f(x)\mathrm{が分布型}) \end{array} \right.

つまり、量子ビットの数が増えても、理想的には1回のみの試行でf(x)が定値型か分布型か当てることができます。

Qiskitで実装する

xが4量子ビットとなるような入力の量子回路を実装します。

必要モジュールのインポート

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.circuit.library import CCXGate, C3XGate, C4XGate, MCXGate

定値型

今回は、f(x)=1となるような定値型の関数を考えます。この場合のDeutschのゲートを、U_1としましょう。他の回路からは、inst_u_1という手続きとして使えるようにします。ここで、w_quregは、分布型の回路を考えるときに使う作業用ビットです。今は気にする必要はありません。

x_qureg = QuantumRegister(4, name="x")
y_qureg = QuantumRegister(1, name="y")
w_qureg = QuantumRegister(5, name="w")

qc_u_1 = QuantumCircuit(x_qureg, y_qureg, w_qureg, name="u_1")

qc_u_1.barrier()
qc_u_1.x(4)
qc_u_1.barrier()

inst_u_1 = qc_u_1.to_instruction()

qc_u_1.draw("mpl")


図3.U_1の中身

分布型

適当に0から15の間で8個乱数を生成してみて、5, 13, 4, 11, 2, 1, 0, 8という値が得られました。そこで、次のようなf(x)を用いたDeutschのゲートを考えます。

f(x)= \begin{array}{ll} 0\;\;\;(x=0, 1, 2, 4, 5, 8, 11, 13)\\ 1\;\;\;(x=3, 6, 7, 9, 10, 12, 14, 15) \end{array}

カルノー図を用いて最小積和形を求めると、次のようになります。

f(x)=x_2x_1 + x_3x_1\overline{x_0} + x_3x_2\overline{x_0} + \overline{x_3}x_1x_0 + x_3\overline{x_2}\,\overline{x_1}x_0

量子回路において、ANDはToffoliゲート(QiskitではCCX、C3X、C4X、MCXゲート)として表現できますし、ORはToffoliゲートの制御ビットの前にXゲートを、作用ビットの後にXゲートを置くことで表現できます。以上のことから、次のような量子ゲートU_2を考えてみます。作業用の5量子ビットも利用します。他の回路からは、inst_u_2として利用できます。

ccx = CCXGate()
c3x = C3XGate()
c4x = C4XGate()
c5x = MCXGate(5)

qc_u_2 = QuantumCircuit(x_qureg, y_qureg, w_qureg, name="u_2")

# x1 && x2
qc_u_2.append(ccx, [1, 2, 5])

qc_u_2.x(0)
# !x0 && x1 && x3
qc_u_2.append(c3x, [0, 1, 3, 6])
# !x0 && x2 && x3
qc_u_2.append(c3x, [0, 2, 3, 7])
qc_u_2.x(0)

qc_u_2.x(3)
# x0 && x1 && !x3
qc_u_2.append(c3x, [0, 1, 3, 8])
qc_u_2.x(3)

qc_u_2.x([1, 2])
# x0 && !x1 && !x2 & x3
qc_u_2.append(c4x, [0, 1, 2, 3, 9])
qc_u_2.x([1, 2])

qc_u_2.barrier()
# w0 || w1 || w2 || w3 || w4
qc_u_2.x([5, 6, 7, 8, 9])
qc_u_2.append(c5x, [5, 6, 7, 8, 9, 4])
qc_u_2.x(4)

qc_u_2.barrier()

inst_u_2 = qc_u_2.to_instruction()

qc_u_2.draw("mpl")


図4.U_2の中身

長くなってしまいましたが、w_0からw_4にそれぞれf(x)の最小積和形の第1項から第5項を順に代入して、それのORをとっているだけです。

AerSimulatorで実行してみる

AerSimulatorは、IBMがメンテナンスを行っている量子コンピュータのシミュレータです。[2]

必要モジュールのインポート

from qiskit import ClassicalRegister
from qiskit_aer.primitives import SamplerV2
from qiskit.visualization import plot_histogram

定値型

回路の準備

x_meas = ClassicalRegister(4, name="c")
qc1 = QuantumCircuit(x_qureg, y_qureg, w_qureg, x_meas)

qc1.x(4)
qc1.h([0, 1, 2, 3, 4])
qc1.append(inst_u_1, list(range(10)))
qc1.h([0, 1, 2, 3])
qc1.measure([3, 2, 1, 0], [3, 2, 1, 0])

qc1.draw("mpl")


図5.U_1に対してDeutsch-Jozsaのアルゴリズムを適用する回路

ちなみに、この例でも行っているように、measure()中の数字の並び方は逆にしておくとplot_histogram()の出力との対応が分かりやすくておすすめです。

実行(成功)

sampler = SamplerV2()
job1 = sampler.run([qc1.decompose()])

result1 = job1.result()

plot_histogram(result1[0].data.c.get_counts())

ここで、decompose()は回路を分解するためのメソッドで、ここではinst_u_1を分解させています。これを実行すると、図6のようなヒストグラムが得られます。

図6.qc1のシミュレーション実行結果
確率1で状態が確率1で\ket{0...00}に収束していることから、f(x)が定値型であることを予言できています!

分布型

回路等の準備は、上の例のinst_u_1inst_u_2に変えるだけなので省略します。

実行(失敗)


図7.inst_u_2を用いた場合のシミュレーション実行結果
計算上は\ket{0...00}の複素振幅が0となるはずなのに、かなりの高確率で\ket{0...00}に収束しています。Deutsch-Jozsaのアルゴリズムが、適切に実行できていないようです。

分布型の入出力を確かめてみる

f(x)が出力されているかどうか、以下のような回路を用いて確かめてみます。

test_register = ClassicalRegister(5, name="c")
qc2 = QuantumCircuit(x_qureg, y_qureg, w_qureg, test_register)

qc2.h([0, 1, 2, 3])
qc2.append(inst_u_2, list(range(10)))
qc2.measure([3, 2, 1, 0, 4], [4, 3, 2, 1, 0])
qc2.draw("mpl")


図8.U_2の入出力を確かめる回路

図9.シミュレーション結果
シミュレーション結果のビットは、左から順にx_3,\cdots x_0, yです。問題なく計算されているように見えます。

(分布型)何がいけなかったのか

作業用量子ビットが、入出力量子ビットと量子もつれの状態にあったことが原因です。
分布型の回路においては作業用ビットを用いて計算していました。その際に入出力量子ビットと作業用量子ビットがもつれ合ってしまい、適切な結果を得られませんでした。

もつれ合いをほどく

例えば、単純化して図9のような量子回路を考えましょう。

図9.CNOTを2回施す量子回路
問題は「\gammaに計算結果が取り出せていて、かつ\betaが他の量子ビットともつれていない状態とすること」と考えられます。ちなみに、「計算結果」というのは今回の場合は、f(x)=xという分布型の関数の出力ですね。
具体的にどのようにしてもつれ合いをほどくかというと、計算結果を\gammaに取り出した後、\alpha\betaに施した操作の逆順のものを、\alpha\betaにもう一度施します。 今回の場合、\alpha\betaに施したのはCNOTですから、そのままCNOTをもう一度作用させればいいことが分かります。

図10.\alpha\betaにもう一度CNOTを施す回路
最初の量子状態を\ket{\psi_0}、左からi番目のCNOTを通った後の量子状態を\ket{\psi_i}としましょう。また、説明の都合上、量子状態を\ket{\beta\alpha\gamma}の順番に書きます。
まず、最初の状態は以下のように書けます。

\ket{\psi_0} = \ket{\beta}\otimes\ket{\alpha\gamma}

次のように、射影演算子の和を文字でおきます。

\begin{aligned} P_0 = \ket{00}\bra{00} + \ket{01}\bra{01}\\ P_1 = \ket{10}\bra{10} + \ket{11}\bra{11} \end{aligned}

\alpha1のときに\betaXを作用させることを考えて、\ket{\psi_1}は次のように書けます。

\ket{\psi_1} = \ket{\beta}\otimes P_0\ket{\alpha\,\gamma} + X\ket{\beta}\otimes P_1\ket{\alpha\,\gamma}

X1との排他的論理和であることを考えると、\ket{\psi_2}は以下のように書けます。

\begin{aligned} \ket{\psi_2} = &\ket{0}\braket{0|\beta} &\otimes &P_0\ket{\alpha\,\gamma}\\ &+ \ket{1}\braket{1|\beta} &\otimes &P_0\ket{\alpha\,\gamma\oplus 1}\\ &+ \ket{0}\bra{0}X\ket{\beta} &\otimes &P_1\ket{\alpha\,\gamma}\\ &+ \ket{1}\bra{1}X\ket{\beta} &\otimes &P_1\ket{\alpha\,\gamma\oplus 1} \end{aligned}

さきほどのU_2の例でうまくいかなかった原因は、このように作業用ビットが入出力ビットに複雑に絡み合ってしまっていたことです。
\ket{\psi_2}にもう一度CNOTゲートを作用させてみて\ket{\psi_3}としてみます。

\begin{aligned} \ket{\psi_3} = &\ket{0}\braket{0|\beta} &\otimes &P_0\ket{\alpha\,\gamma}\\ &+ \ket{1}\braket{1|\beta} &\otimes &P_0\ket{\alpha\,\gamma\oplus 1}\\ &+ X\ket{0}\bra{0}X\ket{\beta} &\otimes &P_1\ket{\alpha\,\gamma}\\ &+ X\ket{1}\bra{1}X\ket{\beta} &\otimes &P_1\ket{\alpha\,\gamma\oplus 1} \end{aligned}

ここで、次の等式が成り立ちます。

\begin{aligned} X\ket{0}\bra{0}X &= (\ket{0}\bra{1}+\ket{1}\bra{0})\ket{0}\bra{0}(\ket{0}\bra{1}+\ket{0}\bra{1})\\ &= \ket{1}\bra{1}\\ X\ket{1}\bra{1}X &= \ket{0}\bra{0} \end{aligned}

よって、\ket{\psi_3}は、次のように変形できます。

\begin{aligned} \ket{\psi_3} = &\ket{0}\braket{0|\beta} &\otimes &P_0\ket{\alpha\,\gamma}\\ &+ \ket{1}\braket{1|\beta} &\otimes &P_0\ket{\alpha\,\gamma\oplus 1}\\ &+ \ket{1}\braket{1|\beta} &\otimes &P_1\ket{\alpha\,\gamma}\\ &+ \ket{0}\braket{0|\beta} &\otimes &P_1\ket{\alpha\,\gamma\oplus 1}\\ = & \ket{0}\braket{0|\beta}&\otimes &(P_0\ket{\alpha\,\gamma} + P_1\ket{\alpha\,\gamma\oplus 1})\\ &+ \ket{1}\braket{1|\beta}&\otimes &(P_0\ket{\alpha\,\gamma\oplus 1} + P_1\ket{\alpha\,\gamma}) \end{aligned}

このように、一義的に異なる量子ビット状態に分離できました。
\gamma=0とすれば、テンソル積で分解された、もつれていない状態になります。

もつれ合いのほどきを実装する

図4の回路(U_2)から最後のMCXゲートを取り除いたものをU_{3f}とし、inst_u_3fで他の回路から利用できるようにします。inst_u_3_fを実装するソースコードを、以下に示します。

qc_u_3_f = QuantumCircuit(x_qureg, y_qureg, w_qureg, name="u_3_f")

# x1 && x2
qc_u_3_f.append(ccx, [1, 2, 5])

qc_u_3_f.x(0)
# !x0 && x1 && x3
qc_u_3_f.append(c3x, [0, 1, 3, 6])
# !x0 && x2 && x3
qc_u_3_f.append(c3x, [0, 2, 3, 7])
qc_u_3_f.x(0)

qc_u_3_f.x(3)
# x0 && x1 && !x3
qc_u_3_f.append(c3x, [0, 1, 3, 8])
qc_u_3_f.x(3)

qc_u_3_f.x([1, 2])
# x0 && !x1 && !x2 & x3
qc_u_3_f.append(c4x, [0, 1, 2, 3, 9])
qc_u_3_f.x([1, 2])

qc_u_3_f.barrier()
qc_u_3_f.x([5, 6, 7, 8, 9])

qc_u_3_f.barrier()

inst_u_3_f = qc_u_3_f.to_instruction()

qc_u_3_f.draw("mpl")


図.inst_u_3_fの中身
その後、次の回路U_3を実装します。

図11.計算して、その後作業ビットのもつれ合いをほどく回路
ソースコードは、以下のとおりです。

qc_u_3 = QuantumCircuit(x_qureg, y_qureg, w_qureg)

qc_u_3.append(inst_u_3_f, list(range(10)))
qc_u_3.append(c5x, [5, 6, 7, 8, 9, 4])
qc_u_3.append(inst_u_3_f.inverse(), list(range(10)))

inst_u_3 = qc_u_3.to_instruction()
qc_u_3.draw("mpl")

ゲートUに対してinverse()メソッドを用いることで、随伴ゲートのU^{\dagger}とすることができ、Uの逆の作用をさせることができます。

分布型で実行(成功)

qc3 = QuantumCircuit(x_qureg, y_qureg, w_qureg, x_meas, name="u_3")
qc3.x(4)
qc3.h([0, 1, 2, 3, 4])
qc3.append(inst_u_3, list(range(10)))
qc3.h([0, 1, 2, 3])
qc3.measure([3, 2, 1, 0], [3, 2, 1, 0])


図12.U_3にDeutsch-Jozsaのアルゴリズムを適用する回路

job3 = sampler.run([qc3.decompose(reps=2)])
result3 = job3.result()
plot_histogram(result3[0].data.c.get_counts())


図13.qc3のシミュレーション実行結果
\ket{0...00}の確率が0となっていて、分布型であることを予言できています!

IBM Runtimeでも実行してみる

qiskit_ibm_runtimeを使用すれば、IBMの量子コンピュータを利用できます。公式サイトの記述[3]に基づいて、アカウントの設定がされているものとします。

必要モジュールのインポート

SamplerV2はAerSimulatorのものと名前が衝突してしまうので、RuntimeSamplerV2としてインポートします。

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as RuntimeSamplerV2
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

backend、PM(Pass Manager)の取得

backend(実行する量子コンピュータ)を取得します。また、量子コンピュータに回路の情報を渡すためにISA回路に変換する必要があります。PM(Pass Manager)の機能で、ISA回路に変換できます。

service = QiskitRuntimeService()
backend = service.least_busy(simulator=False, operational=True)
print(f">>> selected service: {backend}")
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
実行結果
>>> selected service: <IBMBackend('ibm_kyiv')>

ウクライナはキーウのサーバーが選択されました。

定値型

ISA回路に変換

isa_circ1 = pm.run(qc1)
isa_circ1.draw("mpl", idle_wires=False)


図14.ISA回路への変換結果
Hadamardゲートが分解されています。

実行

sampler = RuntimeSamplerV2(backend)

job1 = sampler.run([isa_circ1], shots=1024)
print(f">>> backend: {backend}")
print(f">>> Job ID: {job1.job_id()}")
print(f">>> Job Status: {job1.status()}")

result1 = job1.result()
print(f">>> Job Status: {job1.status()}")
plot_histogram(result1[0].data.c.get_counts())
実行結果
>>> backend: <IBMBackend('ibm_kyiv')>
>>> Job ID: cy6tbsqcw2k0008k02zg
>>> Job Status: QUEUED
>>> Job Status: DONE


図15.U_1にDeutsch-Jozsaのアルゴリズムを適用(実機)
ほとんど1の確率で、状態が\ket{0...00}に収束しており、定値型であることが分かりました!

分布型

ISA回路に変換

isa_circ3 = pm.run(qc3)
isa_circ3.draw("mpl", idle_wires=False)

(ISA回路は恐ろしく長くなったので省略します・・・)

実行


図16.U_3にDeutsch-Jozsaのアルゴリズムを適用(実機)
ほぼほぼランダムみたいになってしまいました。

図17.U_3に最適化を施し、Deutsch-Jozsaのアルゴリズムを適用(実機)
最適化レベルを3にして、バリアも全てなくしてISA回路に変換し、実行した結果を図17に示しました。やはり、ほぼランダムになってしまっています。実際に使うためには、ゲート数を減らすための工夫が必要なようです。
なお、試しに3量子ビット入力でも行ってみましたが、やはりほぼランダムになってしまいました。ヒストグラムを図18に示します。なお、

f(x) = \left\{ \begin{array}{ll} 0 \;\;\;(x=0,2,3,7)\\ 1 \;\;\;(x=1,4,5,6) \end{array} \right.

という関数f(x)を用いています。


図18. 3量子ビットの場合の結果

3量子ビットの場合はCCXゲート、C3Xゲートを用いました。C3Xゲートの入出力を図19のような回路で確かめてみたところ、図20のような結果が得られました。C3Xゲート単体で、確率振幅のみ見ると、入出力は、正しくできているようです。


図19. C3Xゲートの入出力を確かめる量子回路


図20. C3Xゲートの入出力

Deutsch-Jozsaのアルゴリズムは、本質的には制御ビットの位相反転を用いているので、位相反転エラーが強く現れているものと考えられます。

おわりに

Deutsch-Jozsaのアルゴリズムは量子アルゴリズムの中で最も早くからあったものの1つですが、実際に実装してみると様々な学びがありました。
あと、IBM Runtimeは日本では日中に動かしたほうが良いです。夜だと、欧米の方々が積極的に利用している様子で、全然繋がりません。日中だと数十秒でつながるのに、夜中だと1時間以上待ちというケースが多々ありました。

最後までお読みいただき、ありがとうございました。

脚注
  1. 宮野、古澤(2016)「量子コンピュータ入門(第2版)」(日本評論社) ↩︎

  2. IBM(アクセス日:2025年1月19日)「Qiskit ecosystem」https://www.ibm.com/quantum/ecosystem ↩︎

  3. IBM(アクセス日:2025年1月19日)「IBM Quantum Documentation」https://docs.quantum.ibm.com/guides/setup-channel#set-up-to-use-ibm-quantum-platform ↩︎

Discussion

nyaonyao

こんにちは。貴重な記事を投稿していただきありがとうございます。

さて、図11の下のソースコード中の、

qc_u_3.append(inst_u_3_f, list(range(10)))

の inst_u_3_f は、どこで作成していますか?
qc_u_3やqc2 から取得してみましたが、結果が、図13の通りになりません。

宜しければ、ご教授ください。

meet4580meet4580

コメントありがとうございます。
「もつれ合いのほどきを実装する」の項に、inst_u_3_fの実装を追記しました。