实战:用Cirq实现量子因式分解算法
前面的“量子因式分解系列”讨论了Shor算法和它的量子电路,今天切换到编程模式,用谷歌的Cirq框架来实现Shor算法,并用它来解决简单的因式分解问题。 导入依赖包 首先还是导入需要的包: import fractions import math import random import sympy import cirq from cirq.contrib.svg import SVGCircuit from typing import Callable, List, Optional, Sequence, Union %matplotlib inline 指数取模运算 还记得Shor算法的量子电路吗? 首先,我们需要一个“指数取模”的量子变换 \(U_f\) : \begin{matrix} U_f |x\rangle|y\rangle \rightarrow |x\rangle|ya^x \mod N\rangle \end{matrix} 它的输入 \(|x\rangle|y\rangle\) ,输出是 \(|x\rangle|ya^x \mod N\rangle\) 。 在Cirq里面怎么实现这个变换呢?一种办法是按照我之前的文章《聊聊量子因式分解算法的实现》,从加法器和乘法器开始,逐层往上实现。这个工程量就大了,我们也没有真的量子计算机可以跑不是?另一种方法是,利用Cirq框架提供的ArithmeticOperation接口,用经典计算来模拟这个变换: def mod_pow(a:int, x:int, N:int, y:int=1) -> int: p = y for i in range(x): p = (p * a) % N return p class ModularExp(cirq.ArithmeticOperation): def __init__( self, y: Sequence[cirq.Qid], x: Union[int, Sequence[cirq.Qid]], a: int, N: int, ) -> None: if len(y) < N.bit_length(): raise ValueError( f'Register with {len(y)} qubits is too small for N {N}' ) self.y = y self.x = x self.a = a self.N = N def registers(self) -> Sequence[Union[int, Sequence[cirq.Qid]]]: return self.y, self.x, self.a, self.N def with_registers( self, *new_registers: Union[int, Sequence['cirq.Qid']], ) -> 'ModularExp': if len(new_registers) != 4: raise ValueError( f'Expected 4 registers (y, x, a, ' f'N), but got {len(new_registers)}' ) y, x, a, N = new_registers if not isinstance(y, Sequence): raise ValueError(f'y must be a qubit register, got {type(y)}') if not isinstance(a, int): raise ValueError(f'a must be a classical constant, got {type(a)}') if not isinstance(N, int): raise ValueError(f'N must be a classical constant, got {type(N)}') return ModularExp(y, x, a, N) def apply(self, *register_values: int) -> int: assert len(register_values) == 4 y, x, a, N = register_values if y >= N: return y # return (y * a ** x) % N return mod_pow(a=a, x=x, N=N, y=y) def _circuit_diagram_info_( self, args: cirq.CircuitDiagramInfoArgs, ) -> cirq.CircuitDiagramInfo: assert args.known_qubits is not None wire_symbols: List[str] = [] t, e = 0, 0 for qubit in args.known_qubits: if qubit in self.y: if t == 0: if isinstance(self.x, Sequence): e_str = 'e' else: e_str = str(self.x) wire_symbols.append(f'ModularExp(t*{self.a}**{e_str} % {self.N})') else: wire_symbols.append('t' + str(t)) t += 1 if isinstance(self.x, Sequence) and qubit in self.x: wire_symbols.append('e' + str(e)) e += 1 return cirq.CircuitDiagramInfo(wire_symbols=tuple(wire_symbols)) 利用cirq.ArithmeticOperation接口,模拟实现一个指数取模变换ModularExp,这其中的核心就是apply函数: ...