@@ -1,4 +1,4 @@ | |||
tables.pkl | |||
*.pkl | |||
papers/ | |||
# Project-specific | |||
@@ -32,7 +32,7 @@ def name_of(vop): | |||
return "%s" % get_name[vop] if vop in get_name else "VOP%d" % vop | |||
@cache_to_disk("tables.pkl") | |||
@cache_to_disk("clifford_tables.pkl") | |||
def construct_tables(): | |||
""" Constructs / caches multiplication and conjugation tables """ | |||
by_name = {name: find_up_to_phase(u)[0] for name, u in qi.by_name.items()} | |||
@@ -51,8 +51,3 @@ elements = {"x": qi.sqx, "z": qi.msqz} | |||
unitaries = [compose_u(d) for d in decompositions] | |||
by_name, get_name, conjugation_table, times_table = construct_tables() | |||
if __name__ == '__main__': | |||
print by_name | |||
print get_name | |||
@@ -1,48 +0,0 @@ | |||
from graph import * | |||
import viz | |||
import itertools as it | |||
import clifford | |||
def cphase(g, vops, a, b): | |||
""" Act a controlled-phase gate on two qubits """ | |||
if g[a]-{b}: remove_vop(g, vops, a, b) | |||
if g[b]-{a}: remove_vop(g, vops, b, a) | |||
if g[a]-{b}: remove_vop(g, vops, a, b) | |||
edge = has_edge(g, a, b) | |||
new_edge, vops[a], vops[b] = cphase_table[edge, vops[a], vops[b]] | |||
if new_edge != edge: | |||
toggle_edge(g, a, b) | |||
def remove_vop(g, vops, a, avoid): | |||
""" Reduces VOP[a] to the identity, avoiding (if possible) the use of vertex b as a swapping partner """ | |||
others = g[a] - {avoid} | |||
swap_qubit = others.pop() if others else avoid | |||
for v in reversed(clifford.decompositions[vops[a]]): | |||
local_complementation(g, vops, a if v == "x" else swap_qubit) | |||
def local_complementation(g, vops, v): | |||
""" As defined in LISTING 1 of Anders & Briegel """ | |||
for i, j in it.combinations(g[v], 2): | |||
toggle_edge(g, i, j) | |||
# Update VOPs | |||
vops[v] = clifford.times_table[vops[v]][clifford.by_name["sqx"]] | |||
for i in g[v]: | |||
vops[i] = clifford.times_table[vops[i]][clifford.by_name["msqz"]] | |||
if __name__ == '__main__': | |||
g, vops = graph() | |||
add_edge(g, 0, 1) | |||
add_edge(g, 1, 2) | |||
add_edge(g, 0, 2) | |||
add_edge(g, 0, 3) | |||
add_edge(g, 6, 7) | |||
pos = viz.draw(g, vops, "out.pdf") | |||
remove_vop(g, vops, 0, 1) | |||
remove_vop(g, vops, 1, 2) | |||
cphase(g, vops, 0, 1) | |||
viz.draw(g, vops, "out2.pdf", pos) |
@@ -0,0 +1,14 @@ | |||
""" This part computes the CZ table """ | |||
from util import cache_to_disk | |||
import qi | |||
import numpy as np | |||
from tqdm import tqdm | |||
import clifford | |||
#@cache_to_disk("cz_table.pkl") | |||
def construct_table(): | |||
print "awd" | |||
return "awd" | |||
cz_table = construct_table() |
@@ -3,6 +3,7 @@ Provides an extremely basic graph structure, based on neighbour lists | |||
""" | |||
from collections import defaultdict | |||
import itertools as it | |||
import clifford | |||
def graph(): | |||
@@ -39,3 +40,32 @@ def edgelist(g): | |||
for n in v) | |||
return [tuple(e) for e in edges] | |||
def cphase(g, vops, a, b): | |||
""" Act a controlled-phase gate on two qubits """ | |||
if g[a]-{b}: remove_vop(g, vops, a, b) | |||
if g[b]-{a}: remove_vop(g, vops, b, a) | |||
if g[a]-{b}: remove_vop(g, vops, a, b) | |||
edge = has_edge(g, a, b) | |||
new_edge, vops[a], vops[b] = cphase_table[edge, vops[a], vops[b]] | |||
if new_edge != edge: | |||
toggle_edge(g, a, b) | |||
def remove_vop(g, vops, a, avoid): | |||
""" Reduces VOP[a] to the identity, avoiding (if possible) the use of vertex b as a swapping partner """ | |||
others = g[a] - {avoid} | |||
swap_qubit = others.pop() if others else avoid | |||
for v in reversed(clifford.decompositions[vops[a]]): | |||
local_complementation(g, vops, a if v == "x" else swap_qubit) | |||
def local_complementation(g, vops, v): | |||
""" As defined in LISTING 1 of Anders & Briegel """ | |||
for i, j in it.combinations(g[v], 2): | |||
toggle_edge(g, i, j) | |||
# Update VOPs | |||
vops[v] = clifford.times_table[vops[v]][clifford.by_name["sqx"]] | |||
for i in g[v]: | |||
vops[i] = clifford.times_table[vops[i]][clifford.by_name["msqz"]] | |||
@@ -1,55 +0,0 @@ | |||
cphase (vertex a, vertex b): | |||
if ngbh a\{b} =/= {}: | |||
remove VOP (a, b) | |||
end if | |||
if ngbh b\{a} =/= {}: | |||
remove VOP (b, a) | |||
end if | |||
[It may happen that the condition in line 2 has not been fulfilled then, but is now due to the effect of line 5. So we check again:] | |||
if ngbh a\{b} =/= {}: | |||
remove VOP (a, b) | |||
end if | |||
[Now we can be sure that the the condition (ngbh c\{a, b} = {} or VOP[c] ∈ Z) is fulfilled for c = a, b and we may use the lookup table (cf. Eq. (9)).] | |||
if {a, b} ∈ E : | |||
edge ← true | |||
else: | |||
edge ← false | |||
end if | |||
(edge, VOP[a], VOP[b]) ← cphase_table[edge, VOP[a], VOP[b]] | |||
remove_VOP (vertex a, vertex b): | |||
[This reduces VOP[a] to I, avoiding (if possible) to use b as swapping partner.] | |||
[First, we choose a swapping partner c.] | |||
if ngbh a\{b} = {}: | |||
c ← any element of ngbh a\{b} | |||
else: | |||
c←b | |||
end if | |||
d ← decomposition lookup table [a] | |||
[c contains now a decomposition such as Eq. (7)] | |||
for v from last factor of d to first factor of d | |||
if v = −iX: | |||
local complementation (a) | |||
else: ( this means that v = iZ) | |||
local complementation (b) | |||
end if | |||
[Now, VOP[a] = I.] | |||
local complementation (vertex a) | |||
[performs the operation specified in Definition 4] | |||
nv ← ngbh v | |||
for i ∈ nv : | |||
for j ∈ nv : | |||
if i < j: | |||
if (i, j) ∈ E: | |||
remove edge (i, j) | |||
else: | |||
add edge (i, j) | |||
end if | |||
end if | |||
end for | |||
VOP[i] ← VOP[i]sqrt(−iZ) | |||
VOP[v] ← VOP[v]sqrt(iX) | |||
end for |
@@ -1,6 +1,4 @@ | |||
import cz | |||
from graph import * | |||
import viz | |||
def test_local_complementation(): | |||
""" Test that local complementation works as expected """ | |||
@@ -9,7 +7,7 @@ def test_local_complementation(): | |||
add_edge(g, 0, 2) | |||
add_edge(g, 1, 2) | |||
add_edge(g, 0, 3) | |||
cz.local_complementation(g, vops, 0) | |||
local_complementation(g, vops, 0) | |||
assert has_edge(g, 0, 1) | |||
assert has_edge(g, 0, 2) | |||
assert not has_edge(g, 1, 2) | |||
@@ -1,9 +1,17 @@ | |||
""" | |||
Provides a decorator to cache function output to disk | |||
Useful but messy crap | |||
""" | |||
import cPickle | |||
import networkx as nx | |||
from matplotlib import pyplot as plt | |||
from graph import * | |||
import clifford | |||
import numpy as np | |||
VOP_COLORS = ["red", "green", "blue", "orange", "yellow", "purple", "black", "white"] | |||
def cache_to_disk(file_name): | |||
""" A decorator to cache the output of a function to disk """ | |||
def wrap(func): | |||
def modified(*args, **kwargs): | |||
try: | |||
@@ -15,3 +23,23 @@ def cache_to_disk(file_name): | |||
return output | |||
return modified | |||
return wrap | |||
def draw(graph, vops, filename="out.pdf", pos=None, ns=500): | |||
""" Draw a graph with networkx layout """ | |||
plt.clf() | |||
g = nx.from_edgelist(edgelist(graph)) | |||
pos = nx.spring_layout(g) if pos==None else pos | |||
colors = [VOP_COLORS[vop % len(VOP_COLORS)] for vop in vops] | |||
nx.draw_networkx_nodes(g, pos, node_color="white", node_size=ns) | |||
nx.draw_networkx_nodes(g, pos, node_color=colors, node_size=ns, alpha=.4) | |||
nx.draw_networkx_edges(g, pos, edge_color="gray") | |||
nx.draw_networkx_labels(g, pos, font_family="FreeSans") | |||
labels = {i: clifford.name_of(vops[i]) for i in g.nodes()} | |||
pos = {k: v + np.array([0, -.1]) for k, v in pos.items()} | |||
nx.draw_networkx_labels(g, pos, labels, font_family="FreeSans") | |||
plt.axis('off') | |||
plt.savefig(filename) | |||
return pos | |||
@@ -1,30 +0,0 @@ | |||
""" | |||
Utility function for plotting graphs nicely | |||
""" | |||
import networkx as nx | |||
from matplotlib import pyplot as plt | |||
from graph import * | |||
import clifford | |||
import numpy as np | |||
VOP_COLORS = ["red", "green", "blue", "orange", "yellow", "purple", "black", "white"] | |||
def draw(graph, vops, filename="out.pdf", pos=None, ns=500): | |||
""" Draw a graph with networkx layout """ | |||
plt.clf() | |||
g = nx.from_edgelist(edgelist(graph)) | |||
pos = nx.spring_layout(g) if pos==None else pos | |||
colors = [VOP_COLORS[vop % len(VOP_COLORS)] for vop in vops] | |||
nx.draw_networkx_nodes(g, pos, node_color="white", node_size=ns) | |||
nx.draw_networkx_nodes(g, pos, node_color=colors, node_size=ns, alpha=.4) | |||
nx.draw_networkx_edges(g, pos, edge_color="gray") | |||
nx.draw_networkx_labels(g, pos, font_family="FreeSans") | |||
labels = {i: clifford.name_of(vops[i]) for i in g.nodes()} | |||
pos = {k: v + np.array([0, -.1]) for k, v in pos.items()} | |||
nx.draw_networkx_labels(g, pos, labels, font_family="FreeSans") | |||
plt.axis('off') | |||
plt.savefig(filename) | |||
return pos | |||