Алгоритм оценки фазы
Этот алгоритм лежит в основе многих других, включая алгоритм Шора. Задача, которую он решает, заключается в следующем.
Пусть дан унитарный оператор \(U\) в виде черного ящика-оракула, и его собственный вектор \(|\psi\rangle)\) в виде состояния, которое невозможно скопировать из-за законов квантовой механики. Поскольку \(U\) является унитарным, все его собственные значения и собственные вектора имеют вид \[ U|\psi\rangle = e^{2\pi i \theta}|\psi\rangle. \] Необходимо вычислить \(n\)-битовую оценку значения \(\theta\).
Алгоритм оценки фазы
Общая идея
Если бы мы могли записать фазу \(\theta\) в \(n\) разных кубитов в базисе Фурье, то для решения было бы достаточно применить обратное преобразование Фурье и измерить регистр. Даже если фаза не целая, как в нашем случае, мы получим какую-то её оценку (может быть показано, что вероятность измерения выше \(4/\pi^2 \approx 40%\)).
Фазовая отдача (phase kickback)
Что получится, если мы выполним операцию \(CU\), поместив в управляющий кубит состояние \(\frac{1}{\sqrt{2}}(|0\rangle + |1\rangle)\), а в управляемый — \(|\psi\rangle\)?
Получим
\begin{align*} CU\Big(\frac{1}{\sqrt{2}}(|0\rangle + |1\rangle) \otimes |\psi\rangle\Big) &= \frac{1}{\sqrt{2}}\Big(|0\rangle \otimes |\psi\rangle + |1\rangle \otimes e^{2\pi i \theta}|\psi\rangle\Big) = \\ &= \frac{1}{\sqrt{2}}(|0\rangle + e^{2\pi i \theta} |1\rangle) \otimes |\psi\rangle. \end{align*}В итоге фаза записалась в управляющий кубит, как будто мы получили отдачу от управляемой операции.
Повышение точности
Повторяя этот процесс с разными кубитами \(j\) и разными степенями \(CU^{2^j}\), получим следующее состояние:
\begin{align*} \vert \psi' \rangle &= \frac{1}{2^{n/2}} \big(|0\rangle + e^{2\pi i\theta 2^{n-1}}|1\rangle\big) \otimes \cdots \otimes \big(|0\rangle + e^{2\pi i\theta 2^1}|1\rangle\big) \otimes \big(|0\rangle + e^{2\pi i\theta 2^0}|1\rangle\big) \otimes |\psi\rangle \\ &= \frac{1}{2^{n/2}} \sum_{k=0}^{2^n-1} e^{2\pi i \theta k}|k\rangle \otimes |\psi\rangle. \end{align*}После обратного квантового преобразования Фурье получаем \[ \vert \psi'' \rangle = \frac{1}{2^{n/2}} \sum_{x=0}^{2^n-1} \sum_{k=0}^{2^n-1} e^{-\frac{2\pi ik}{2^n} (x - 2^n\theta)}|x\rangle \otimes |\psi\rangle. \]
Измерив первый регистр, с большой вероятностью получим \(x = 2^n \theta\). Для большей точности потребуется больше кубитов в этом регистре.
Код
Реализуем описанное выше в виде кода.
import cirq import numpy as np def make_phase_estimation(n, U, u_bit): qubits = cirq.LineQubit.range(n) phase_estimator = cirq.Circuit(cirq.H.on_each(*qubits)) for i, bit in enumerate(qubits): phase_estimator.append(cirq.ControlledGate(U).on(bit, u_bit) ** (2**(n - i - 1))) phase_estimator.append(cirq.qft(*qubits[::-1], without_reverse=True, inverse=True)) phase_estimator.append(cirq.measure(*qubits, key='theta')) return phase_estimator
Если операция \(U\) такова, что \(2^n \theta\) — целое, то измерения дадут точное значение:
n1 = 3 u1 = cirq.NamedQubit('u') pe1 = make_phase_estimation(n1, cirq.T, u1) pe1.insert(0, cirq.X(u1)) print(pe1) sim = cirq.Simulator() res1 = sim.run(pe1, repetitions = 10) print(res1.measurements['theta']) theta1 = np.sum(2 ** np.arange(n1) * res1.measurements['theta'], axis=1) / 2**n1 print(theta1)
0: ───H───@───────────#3──────────────M('theta')─── │ │ │ 1: ───H───┼───@───────#2──────────────M──────────── │ │ │ │ 2: ───H───┼───┼───@───qft[norev]^-1───M──────────── │ │ │ u: ───X───Z───S───T──────────────────────────────── [[1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0 0]] [0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125]
Здесь мы всегда получаем \(\theta = 0.125\) потому что мы находим фазу для оператора \(T = Z^{1/4}\) и собственного значения \(|1\rangle\) (для того, чтобы начать с этого состояния мы и вставили \(X\) в схему): \[ T|1\rangle = e^{2\pi i/8}|1\rangle. \]
Если же \(2^n \theta\) нельзя представить точно в \(n\) битах, то мы получим какое-то приближение:
n2 = 3 u2 = cirq.NamedQubit('u') pe2 = make_phase_estimation(n2, cirq.Z**(1/3), u2) pe2.insert(0, cirq.X(u2)) print(pe2) res2 = sim.run(pe2, repetitions = 10) print(res2.measurements['theta']) theta2 = np.sum(2 ** np.arange(n2) * res2.measurements['theta'], axis=1) / 2**n2 print(theta2) print(res2.histogram(key = 'theta'))
0: ───H───@──────────────────────────────#3──────────────M('theta')─── │ │ │ 1: ───H───┼──────────@───────────────────#2──────────────M──────────── │ │ │ │ 2: ───H───┼──────────┼─────────@─────────qft[norev]^-1───M──────────── │ │ │ u: ───X───Z^(-2/3)───Z^(2/3)───Z^(1/3)──────────────────────────────── [[0 0 1] [1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0 0] [0 1 0] [1 0 0] [0 0 1] [1 0 0]] [0.5 0.125 0.125 0.125 0.125 0.125 0.25 0.125 0.5 0.125] Counter({4: 7, 1: 2, 2: 1})
И чем больше мы используем кубитов, тем точнее результат:
n3 = 4 u3 = cirq.NamedQubit('u') pe3 = make_phase_estimation(n3, cirq.Z**(1/3), u3) pe3.insert(0, cirq.X(u3)) print(pe3) res3 = sim.run(pe3, repetitions = 1000) print(res3.histogram(key = 'theta'))
0: ───H───@────────────────────────────────────────#4──────────────M('theta')─── │ │ │ 1: ───H───┼─────────@──────────────────────────────#3──────────────M──────────── │ │ │ │ 2: ───H───┼─────────┼──────────@───────────────────#2──────────────M──────────── │ │ │ │ │ 3: ───H───┼─────────┼──────────┼─────────@─────────qft[norev]^-1───M──────────── │ │ │ │ u: ───X───Z^(2/3)───Z^(-2/3)───Z^(2/3)───Z^(1/3)──────────────────────────────── Counter({12: 679, 4: 172, 2: 54, 8: 31, 0: 12, 15: 10, 10: 10, 6: 8, 14: 4, 1: 4, 11: 4, 7: 3, 13: 3, 3: 2, 5: 2, 9: 2})
n4 = 5 u4 = cirq.NamedQubit('u') pe4 = make_phase_estimation(n4, cirq.Z**(1/3), u4) pe4.insert(0, cirq.X(u4)) print(pe4) res4 = sim.run(pe4, repetitions = 1000) print(res4.histogram(key = 'theta'))
0: ───H───@───────────────────────────────────────────────────#5──────────────M('theta')─── │ │ │ 1: ───H───┼──────────@────────────────────────────────────────#4──────────────M──────────── │ │ │ │ 2: ───H───┼──────────┼─────────@──────────────────────────────#3──────────────M──────────── │ │ │ │ │ 3: ───H───┼──────────┼─────────┼──────────@───────────────────#2──────────────M──────────── │ │ │ │ │ │ 4: ───H───┼──────────┼─────────┼──────────┼─────────@─────────qft[norev]^-1───M──────────── │ │ │ │ │ u: ───X───Z^(-2/3)───Z^(2/3)───Z^(-2/3)───Z^(2/3)───Z^(1/3)──────────────────────────────── Counter({20: 685, 12: 169, 4: 45, 28: 22, 24: 18, 2: 13, 8: 7, 18: 7, 16: 5, 10: 4, 6: 3, 31: 3, 0: 3, 13: 2, 1: 2, 26: 2, 15: 1, 9: 1, 29: 1, 7: 1, 19: 1, 23: 1, 22: 1, 11: 1, 17: 1, 30: 1})
Стандартная функция histogram
собирает биты в обратном порядке к тому, что мы ожидаем: \(4 = 100_2\), \(12 = 1100_2\), \(20 = 10100_2\). Получаем такие приближения: \(001, 0011, 00101, \ldots\), или \(\theta \approx 0.125, 0.1875, 0.15625, \ldots \) при искомом значении \(\theta = 1/6 = 0.1(6) = 0.1666\ldots = 0.0(01)_2 = 0.00101010101\ldots_2\).