Deutsch-Jozsaアルゴリズム
Deutschのアルゴリズムはクエリ問題においてすべての古典アルゴリズムを上回りますが、その優位性は比較的控えめです。クエリ数は1回対2回です。 Deutsch-Jozsaアルゴリズムはこの優位性を拡張します。そして実際に、2種類の異なるクエリ問題を解くために使用できます。
以下はDeutsch-Jozsaアルゴリズムの量子回路の説明です。 解こうとしている具体的な問題によっては、図には示されていない追加の古典後処理ステップも必要になる場合があります。
もちろん、このアルゴリズムがどのような問題を解くかについてはまだ説明していません。これについては続く2つのセクションで説明します。
Deutsch-Jozsa問題
まず、Deutsch-Jozsaアルゴリズムが元々解くことを意図していたクエリ問題、すなわちDeutsch-Jozsa問題から始めます。
この問題の入力関数は、任意の正の整数 に対して という形を取ります。 Deutschの問題と同様に、 が定数であれば を出力し、 が平衡であれば を出力するというタスクです。ここで平衡とは、関数が の値を取る入力文字列の数が、関数が の値を取る入力文字列の数と等しいことを意味します。
が より大きい場合、 という形の関数で、定数でも平衡でもないものが存在することに注意してください。 例えば、次のように定義された関数 は、
これらの2つのカテゴリのいずれにも属しません。 Deutsch-Jozsa問題では、このような関数を単純に考慮しません。これらは「どちらでもよい」入力として扱われます。 すなわち、この問題では が定数か平衡のどちらかであるという約束があります。
1回のクエリによるDeutsch-Jozsaアルゴリズムは、次の意味でこの問題を解きます。 個の測定結果がすべて であれば、関数 は定数です。 そうでなく、測定結果の少なくとも1つが であれば、関数 は平衡です。 別の言い方をすると、上記の回路に続いて、測定結果のORを計算して出力を生成する古典後処理ステップが行われます。
アルゴリズムの解析
Deutsch-Jozsa問題に対するDeutsch-Jozsaアルゴリズムの性能を解析するには、まず1層のアダマールゲートの作用について考えるとよいでしょう。 アダマール演算は通常の方法で行列として表すことができます。
しかし、この演算を標準基底状態への作用として表すこともできます。
これら2つの式は1つの公式にまとめることができます。
これは のどちらの選択に対しても成り立ちます。
次に、1量子ビットだけでなく 個の量子ビットがあり、それぞれにアダマール演算が行われるとします。 個の量子ビットに対する合成演算はテンソル積 ( 回)で記述されます。これを簡潔かつ明確に と書きます。 上記の公式を用い、展開してから簡略化することで、 量子ビットの標準基底状態に対するこの合成演算の作用を次のように表すことができます。
ここで、Qiskitのインデックス規則に従い、長さ の2進数文字列を および と書いていることに注意してください。
この公式は、上記の量子回路を解析するための便利なツールを提供します。 最初のアダマールゲート層が実行された後、 個の量子ビット(残りと別に扱われる最左端/最下部の量子ビットを含む)の状態は次のようになります。
演算が実行されると、Deutschのアルゴリズムの解析で見たのとまったく同じ位相キックバック現象により、この状態は次のように変換されます。
次に、第2層のアダマールゲートが実行されます。(上記の公式により)この状態を次のように変換します。
この式はやや複雑に見え、関数 についてさらに知らなければ、異なる測定結果を得る確率について多くのことを結論づけることはできません。
幸いなことに、私たちが知る必要があるのは、測定結果がすべて になる確率だけです。なぜなら、それがアルゴリズムが を定数と判断する確率だからです。 この確率には簡単な公式があります。
詳しく説明すると、 が定数である場合、すべての文字列 に対して であり、その場合の和の値は となります。あるいはすべての文字列 に対して であり、その場合の和の値は となります。 で割り、絶対値の2乗を取ると が得られます。
一方、 が平衡である場合、 は文字列 の半分で値 を取り、残りの半分で値 を取ります。そのため、和の中の の項と の項が打ち消し合い、値 が残ります。
これにより、約束が満たされている限り、アルゴリズムが正しく動作することが結論づけられます。
古典的な困難性
Deutsch-Jozsaアルゴリズムは毎回確実に動作し、約束が満たされている場合は常に正しい答えを返し、必要なクエリ数は1回です。 Deutsch-Jozsa問題に対する古典的なクエリアルゴリズムと比べてどうでしょうか?
まず、Deutsch-Jozsa問題を正しく解く決定論的な古典アルゴリズムは、指数関数的に多くのクエリを実行しなければなりません。 最悪の場合、 回のクエリが必要です。 その理由は、決定論的アルゴリズムが 以下の異なる文字列に対して にクエリを行い、毎回同じ関数値を得た場合、両方の答えがまだ可能だからです。 関数が定数である可能性も、または平衡だが運悪くすべてのクエリが同じ関数値を返している可能性もあります。
2番目の可能性は可能性が低いように見えますが、決定論的アルゴリ ズムにはランダム性や不確実性がないため、特定の関数に対して系統的に失敗します。 したがって、この点において量子アルゴリズムは古典アルゴリズムに対して大きな優位性を持ちます。
ただし、落とし穴があります。確率的な古典アルゴリズムは、わずかなクエリ数でDeutsch-Jozsa問題を非常に高い確率で解くことができます。 特に、長さ の異なる文字列をいくつかランダムに選んで、それらの文字列に対して にクエリを行うと、 が平衡の場合にすべて同じ関数値を得ることはほとんどありません。
具体的には、 個の入力文字列 を一様ランダムに選び、 を評価し、すべての関数値が同じであれば と答え、そうでなければ と答えるならば、 が定数の場合は常に正解となり、 が平衡の場合に誤答となる確率はわずか です。 例えば とすると、このアルゴリズムは % を超える確率で正しく答えます。
このため、量子アルゴリズムは古典アルゴリズムに対してまだ比較的控えめな優位性を持ちます。しかし、それでも定量化可能な優位性であり、Deutschのアルゴリズムからの改善を示しています。
QiskitによるDeutsch-Jozsa
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np
QiskitでDeutsch-Jozsaアルゴリズムを実装するに は、まず dj_query という関数を定義します。この関数は、Deutsch-Jozsa問題の約束を満たすランダムに選ばれた関数に対して、クエリゲートを実装する量子回路を生成します。
50%の確率で関数は定数となり、50%の確率で関数は平衡となります。
これら2つの可能性それぞれに対して、そのタイプの関数から一様にランダムに関数が選ばれます。
引数は関数の入力ビット数です。
def dj_query(num_qubits):
# Create a circuit implementing for a query gate for a random function
# satisfying the promise for the Deutsch-Jozsa problem.
qc = QuantumCircuit(num_qubits + 1)
if np.random.randint(0, 2):
# Flip output qubit with 50% chance
qc.x(num_qubits)
if np.random.randint(0, 2):
# return constant circuit with 50% chance
return qc
# Choose half the possible input strings
on_states = np.random.choice(
range(2**num_qubits), # numbers to sample from
2**num_qubits // 2, # number of samples
replace=False, # makes sure states are only sampled once
)
def add_cx(qc, bit_string):
for qubit, bit in enumerate(reversed(bit_string)):
if bit == "1":
qc.x(qubit)
return qc
for state in on_states:
qc.barrier() # Barriers are added to help visualize how the functions are created.
qc = add_cx(qc, f"{state:0b}")
qc.mcx(list(range(num_qubits)), num_qubits)
qc = add_cx(qc, f"{state:0b}")
qc.barrier()
return qc
draw メソッドを使って、クエリゲートの量子回路実装を通常どおり表示できます。
display(dj_query(3).draw(output="mpl"))
次に、クエリゲートの量子回路実装を引数として取り、Deutsch-Jozsa回路を作成する関数を定義します。
def compile_circuit(function: QuantumCircuit):
# Compiles a circuit for use in the Deutsch-Jozsa algorithm.
n = function.num_qubits - 1
qc = QuantumCircuit(n + 1, n)
qc.x(n)
qc.h(range(n + 1))
qc.compose(function, inplace=True)
qc.h(range(n))
qc.measure(range(n), range(n))
return qc
最後に、Deutsch-Jozsa回路を1回実行する関数を定義します。
def dj_algorithm(function: QuantumCircuit):
# Determine if a function is constant or balanced.
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
measurements = result.get_memory()
if "1" in measurements[0]:
return "balanced"
return "constant"
関数をランダムに選び、その関数のクエリゲートの量子回路実装を表示してから、その関数に対してDeutsch-Jozsaアルゴリズムを実行することで、実装をテストできます。
f = dj_query(3)
display(f.draw("mpl"))
display(dj_algorithm(f))

'balanced'
Bernstein-Vazirani問題
次に、Bernstein-Vazirani問題として知られる問題について説明します。 これはフーリエサンプリング問題とも呼ばれますが、この名前で呼ばれるより一般的な定式化も存在します。
まず、いくつかの記法を導入しましょう。 長さ の任意の2つの2進数文字列 と に対して、次のように定義します。
この演算を二進内積と呼びます。 別の定義方法は次のとおりです。
これは対称な演算であることに注意してください。つまり、 と を入れ替えても結果は変わらないため、都合のよいときにいつでも入れ替えることができます。 二進内積 は、文字列 が を持つ位置における のビットのパリティ、あるいは等価的に、文字列 が を持つ位置における のビットのパリティとして考えると便利な場合があります。
この記法を使って、Bernstein-Vazirani問題を定義できます。
この問題のために新しい量子アルゴリズムは実際には必要ありません。Deutsch-Jozsaアルゴリズムが解いてくれます。 明確にするために、ORを計算する古典後処理ステップを含まない上記の量子回路をDeutsch-Jozsa回路と呼ぶことにします。
アルゴリズムの解析
Bernstein-Vazirani問題の約束を満たす関数に対してDeutsch-Jozsa回路がどのように機能するかを解析するために、簡単な観察から始めましょう。 二進内積を使うと、 個の量子ビットの標準基底状態に対する 個のアダマー ルゲートの作用を次のように代替的に記述できます。
Deutschのアルゴリズムの解析で見たものと同様に、これは任意の整数 に対して の値が が偶数か奇数かにのみ依存するからです。
Deutsch–Jozsa回路に戻ると、最初のアダマールゲート層が実行された後、 個の量子ビットの状態は次のようになります。
次にクエリゲートが実行されます。(位相キックバック現象により)状態が次のように変換されます。
アダマールゲート層の作用の公式を使うと、第2層のアダマールゲートはこの状態を次のように変換することがわかります。
ここで、和の中の の指数部 を簡略化できます。 ある文字列 に対して であると約束されているので、状態を次のように表せます。
と は2進数の値であるため、加算を排他的論理和に置き換えることができます。これも、指数の中の整数にとって重要なのは偶数か奇数かだけだからです。 二進内積の対称性を利用すると、状態に対する次の式が得られます。
(二進内積は排他的論理和より高い優先順位を持つという慣例があるため実際には必要ありませんが、わかりやすくするためにカッコを追加しています。)
この時点で、次の公式を利用します。
この公式は、ビットに対する同様の公式、
および二進内積とビット単位の排他的論理和の展開を組み合わせることで導出できます。
これにより、測定直前の回路の状態を次のように表すことができます。
最後のステップは、すべての2進数文字列 に対して成り立つ、もう一つの公式を利用することです。
ここで、このレッスンで何度か使用する文字列の簡単な記法を使っています。 は長さ のすべて0の文字列です。
この公式が成り立つことを示す簡単な方法は、2つの場合を別々に考えることです。 のとき、すべての文字列 に対して であるため、和の各項の値は となり、和を取って で割ると が得られます。 一方、 のビットのいずれかが に等しい場合、 の可能な選択肢のちょうど半分に対して二進内積 は となり、残りの半分に対して となります。これは、 が を持つ位置 の のビットを反転させると、二進内積 の値が( から へ、または から へ)反転するからです。
この公式を測定前の回路の状態の簡略化に適用すると、次のようになります。
これは であることと であることが同値であるためです。 したがって、測定によって探している文字列 が正確に明らかになります。
古典的な困難性
Deutsch-Jozsa回路は1回のクエリでBernstein-Vazirani問題を解きますが、古典的なクエリアルゴリズムがこの問題を解くには少なくとも 回のクエリが必要です。
これは、この場合非常に単純な情報理論的な議論によって理由づけられます。 各古典クエリは解についての1ビットの情報を明らかにし、明らかにする必要がある情報は ビットです。したがって、少なくとも 回のクエリが必要です。
実際、各可能な位置に が1つあり、他のすべてのビットが である 個の文字列に対して関数をクエリすることで、 のビットを1つずつ明らかにし、Bernstein-Vazirani問題を古典的に解くことが可能です。 したがって、この問題における量子アルゴリズムの古典アルゴリズムに対する優位性は、1回のクエリ対 回のクエリです。
QiskitによるBernstein-Vazirani
上でDeutsch-Jozsa回路を既に実装しました。ここではそれを利用してBernstein-Vazirani問題を解きます。 まず、任意の2進数文字列 に対してBernstein-Vazirani問題のクエリゲートを実装する関数を定義します。
def bv_query(s):
# Create a quantum circuit implementing a query gate for the
# Bernstein-Vazirani problem.
qc = QuantumCircuit(len(s) + 1)
for index, bit in enumerate(reversed(s)):
if bit == "1":
qc.cx(index, len(s))
return qc
display(bv_query("1011").draw(output="mpl"))
次に、以前定義した compile_circuit 関数を使って、その関数に対してDeutsch-Jozsa回路を実行する関数を作成できます。
def bv_algorithm(function: QuantumCircuit):
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
return result.get_memory()[0]
display(bv_algorithm(bv_query("1011")))
'1011'
命名法に関する注記
Bernstein-Vazirani問題の文脈では、Deutsch-Jozsaアルゴリズムが「Bernstein-Vaziranアルゴリズム」と呼ばれることがよくあります。 これはやや誤解を招く表現です。なぜなら、このアルゴリズムはDeutsch-Jozsaアルゴリズムそのものであり、BernsteinとVazirani自身も彼らの研究でそのことを明確に述べているからです。
BernsteinとVaziranがDeutsch-Jozsaアルゴリズムがここで述べたBernstein-Vazirani問題を解くことを示した後に行ったのは、再帰的フーリエサンプリング問題として知られる、はるかに複雑な問題を定義することでした。 これは非常に人工的な問題であり、異なる問題インスタンスの解が木構造に配置された問題の新しいレベルを実質的に解放していきます。 Bernstein-Vazirani問題は本質的に、この複雑な問題の基本ケースにすぎません。
再帰的フーリエサンプリング問題は、量子アルゴリズムが確率的アルゴリズムに対して超多項式的な優位性を持つことが知られた最初のクエリ問題の例でした。これにより、Deutsch-Jozsaアルゴリズムが提供する量子対古典の優位性を超えることができました。 直感的に言えば、問題の再帰版は量子アルゴリズムの1対 の優位性をはるかに大きなものに増幅します。
この優位性を確立する数学的解析の最も困難な側面は、古典的なクエリアルゴリズムが多くのクエリなしに問題を解けないことを示すことです。 これは非常に典型的なことで、多くの問題において、それらを効率的に解く創造的な古典的アプローチを排除することは非常に困難です。
Simonの問題と次のセクションで説明するそのアルゴリズムは、量子アルゴリズムの古典アルゴリズムに対する超多項式的(そして実際には指数関数的)な優位性のはるかに単純な例を提供します。このため、再帰的フーリエサンプリング問題はあまり議論されることがありません。 しかし、それ自体として興味深い計算問題であることに変わりはありません。