Oracle-Based Algorithms Written in Qwerty #
Deutsch’s Algorithm #
Algorithm (
deutsch.py
):from qwerty import *
def deutsch(f):
@qpu(f)
def kernel(f: cfunc) -> bit:
return '+' | f.phase | pm.measure
return kernel()
@classical
def balanced(x: bit) -> bit:
return ~x
@classical
def constant(x: bit) -> bit:
return bit[1](0b1)
Driver (
deutsch_driver.py
):from qwerty import *
from deutsch import deutsch, \
balanced, \
constant
def naive_classical(f):
return f(bit[1](0b0)) \
^ f(bit[1](0b1))
print('Balanced f:')
print('Classical: f(0) xor f(1) =',
naive_classical(balanced))
print('Quantum: f(0) xor f(1) =',
deutsch(balanced))
print('\nConstant f:')
print('Classical: f(0) xor f(1) =',
naive_classical(constant))
print('Quantum: f(0) xor f(1) =',
deutsch(constant))
Deutsch–Jozsa Algorithm #
Algorithm (
dj.py
):from qwerty import *
def deutsch_jozsa(f):
@qpu[N](f)
def kernel(f: cfunc[N,1]) \
-> bit[N]:
return '+'[N] | f.phase \
| pm[N].measure
if int(kernel()) == 0:
return 'constant'
else:
return 'balanced'
@classical
def constant(x: bit[4]) -> bit:
# f(x) = 1
return bit[1](0b1)
@classical
def balanced(x: bit[4]) -> bit:
# f(x) = 1 for half the inputs
# and f(x) = 0 for the other half
return x.xor_reduce()
Driver (
dj_driver.py
):from qwerty import *
from dj import deutsch_jozsa, \
constant, balanced
def naive_classical(f, n_bits):
answers = [0, 0]
for i in range(2**(n_bits-1)+1):
answer = int(f(bit[n_bits](i)))
answers[answer] += 1
if 0 in answers:
return 'constant'
else:
return 'balanced'
print('Constant test:')
print('Classical:',
naive_classical(constant, 4))
print('Quantum:',
deutsch_jozsa(constant))
print('\nBalanced test:')
print('Classical:',
naive_classical(balanced, 4))
print('Quantum:',
deutsch_jozsa(balanced))
Bernstein–Vazirani Algorithm #
Algorithm (
bv.py
):from qwerty import *
def bv(f):
@qpu[N](f)
def kernel(f: cfunc[N,1]) \
-> bit[N]:
return '+'[N] | f.phase \
| pm[N] >> std[N] \
| std[N].measure
return kernel()
def get_black_box(secret_string):
@classical[N](secret_string)
def f(secret_string: bit[N],
x: bit[N]) -> bit:
return (secret_string & x) \
.xor_reduce()
return f
Driver (
bv_driver.py
):from qwerty import *
from bv import bv, get_black_box
import sys
def naive_classical(f, n_bits):
secret_found = bit[n_bits](0b0)
x = bit[n_bits](0b1 << (n_bits-1))
for i in range(n_bits):
secret_found[i] = f(x)
x = x >> 1
return secret_found
secret_str = \
bit.from_str(sys.argv[1])
n_bits = len(secret_str)
black_box = get_black_box(secret_str)
print('Classical:',
naive_classical(black_box,
n_bits))
print('Quantum:', bv(black_box))
Period Finding #
Algorithm (
period.py
):import math
from qwerty import *
def period_finding(black_box):
@qpu[M,N](black_box)
def kernel(black_box: cfunc[M,N]) \
-> bit[M]:
return '+'[M] + '0'[N] \
| black_box.xor_embed \
| fourier[M].measure \
+ discard[N]
result1, result2 = kernel(shots=2)
l_over_r1 = result1.as_bin_frac()
l_over_r2 = result2.as_bin_frac()
r = math.lcm(l_over_r1.denominator,
l_over_r2.denominator)
return r
def get_black_box(n_bits_in,
n_bits_out,
n_mask_bits):
@classical[M,N,K]
def f(x: bit[M]) -> bit[N]:
return bit[N-K](0b0), x[M-K:]
return f[[n_bits_in,
n_bits_out,
n_mask_bits]]
Driver (
period_driver.py
):import sys
from period import period_finding, \
get_black_box
n_bits_in = int(sys.argv[1])
n_bits_out = int(sys.argv[2])
n_masked = int(sys.argv[3])
black_box = get_black_box(n_bits_in,
n_bits_out,
n_masked)
if period_finding(black_box) \
== 2**n_masked:
print('success!')
else:
print('oops...')
Simon’s Algorithm #
Algorithm (
simon.py
):from qwerty import *
from simon_post import simon_post, \
Retry
def simon(f):
@qpu[N](f)
def kernel(f: cfunc[N]) -> bit[N]:
return '+'[N] + '0'[N] \
| f.xor_embed \
| (std[N] >> pm[N]) \
+ id[N] \
| std[N].measure \
+ discard[N]
while True:
rows = []
while True:
row = kernel()
if int(row) != 0:
rows.append(row)
if len(rows) >= row.n_bits-1:
break
try:
return simon_post(rows)
except Retry:
print('retrying...')
continue
@classical
def black_box(q: bit[3]) -> bit[3]:
return \
(~q[0]& q[2]|q[0]&~q[2]|~q[1],
~q[0]&~q[2]|q[0]& q[2],
~q[0]&~q[2]|q[0]& q[2]|~q[1])
Driver (
simon_driver.py
):from qwerty import *
from simon import simon, black_box
def naive_classical(f, n_bits):
out_to_x = {}
for i in range(2**n_bits):
x = bit[n_bits](i)
out = f(x)
if out in out_to_x:
return x ^ out_to_x[out]
out_to_x[out] = x
print('Classical:',
naive_classical(black_box, 3))
print('Quantum:', simon(black_box))