Algorithms Used to Factor in Qwerty #
Quantum Phase Estimation #
Algorithm (
qpe.py
):from qwerty import *
def qpe(precision, prep_eigvec, op,
n_shots):
@qpu[M,T](prep_eigvec, op)
def kernel(
prep_eigvec: qfunc[0,M],
op: rev_qfunc[M][[...]]) \
-> bit[T]:
return '+'[T] + prep_eigvec() \
| (std[T-1-j]+'1'+std[j]
& op[[j]]
for j in range(T)) \
| fourier[T].measure \
+ discard[M]
k_inst = kernel[[precision]]
for meas in k_inst(shots=n_shots):
yield meas.as_bin_frac()
Driver (
qpe_driver.py
):from qpe import qpe
from qwerty import *
import sys
phi = float(sys.argv[1])
precision = int(sys.argv[2])
@qpu
def prep1() -> qubit:
return '1'
@qpu[J](phi)
@reversible
def rot(phi: angle,
q: qubit) -> qubit:
return q | std >> \
{'0', phase(2*pi*phi*2**J)*'1'}
print('Expected:', phi)
phi_got, = qpe(precision, prep1, rot,
n_shots=1)
print('Actual:', float(phi_got))
Order Finding #
Algorithm (
order_finding.py
):import math
from qwerty import *
from qpe import qpe
def order_finding(epsilon, x, modN):
L = math.ceil(math.log2(modN))
t = 2*L + 1 + math.ceil(
math.log2(2+1/(2*epsilon)))
@qpu[M]
def one() -> qubit[M]:
return '0'[M-1] + '1'
@classical[X,N,M,J]
def xymodN(y: bit[M]) -> bit[M]:
return X**2**J * y % N
x_inv = pow(x, -1, modN)
fwd = xymodN[[x,modN,L,...]]
rev = xymodN[[x_inv,modN,L,...]]
mult = fwd.inplace(rev)
frac1, frac2 = qpe(t, one, mult, 2)
def denom(frac):
cf = cfrac.from_fraction(frac)
for c in reversed(
cf.convergents()):
if c.denominator < modN:
return c.denominator
return math.lcm(denom(frac1),
denom(frac2))
Driver (
order_finding_driver.py
):import math
from qwerty import *
from order_finding import order_finding
import sys
def naive_classical(x, modN):
for r in range(1, modN):
if x**r % modN == 1:
return r
err = 0.2
x = int(sys.argv[1])
modN = int(sys.argv[2])
if math.gcd(x, modN) != 1:
raise ValueError('invalid x, modN')
print('Classical:',
naive_classical(x, modN))
print('Quantum:',
order_finding(err, x, modN))
Shor’s Algorithm #
Algorithm (
shors.py
):import math
import random
from qwerty import *
from order_finding import \
order_finding
def shors(epsilon, num):
if num % 2 == 0:
return 2
x = random.randint(2, num-1)
if (y := math.gcd(x, num)) > 1:
print('Got lucky! Skipping '
'quantum subroutine...')
return y
r = order_finding(epsilon, x, num)
if r % 2 == 0 \
and pow(x, r//2, num) != -1:
if (gcd := math.gcd(x**(r//2)-1,
num)) > 1:
return gcd
if (gcd := math.gcd(x**(r//2)+1,
num)) > 1:
return gcd
raise Exception("Shor's failed")
Driver (
shors_driver.py
):from qwerty import *
from shors import shors
import sys
err = 0.2
num = int(sys.argv[1])
print('Nontrivial factor of', num,
'is', shors(err, num))