Parcourir la source

Lotsa stuff

master
Pete Shadbolt il y a 8 ans
Parent
révision
f10b5dfc5a
7 fichiers modifiés avec 57 ajouts et 33 suppressions
  1. +10
    -10
      clifford.py
  2. +18
    -13
      cz.py
  3. +5
    -2
      graph.py
  4. +4
    -0
      qi.py
  5. +4
    -5
      tests/test_clifford.py
  6. +6
    -0
      tests/test_cz.py
  7. +10
    -3
      viz.py

+ 10
- 10
clifford.py Voir le fichier

@@ -27,16 +27,21 @@ def compose_u(decomposition):
us = (elements[c] for c in decomposition)
return np.matrix(reduce(np.dot, us), dtype=complex)

def name_of(vop):
""" Get the formatted name of a VOP """
return get_name[vop].title() if vop in get_name else "VOP%d" % vop


@cache_to_disk("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()}
get_name = {v:k for k, v in by_name.items()}
conjugation_table = [find_up_to_phase(u.H)[0]
for i, u in enumerate(unitaries)]
times_table = [[find_up_to_phase(u * v)[0] for v in unitaries]
for u in tqdm(unitaries)]
return conjugation_table, times_table

return by_name, get_name, conjugation_table, times_table

# Various useful tables
decompositions = ("xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz",
@@ -44,15 +49,10 @@ decompositions = ("xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz",
"zzzx", "xxzx", "zx", "zxxx", "xxxz", "xzzz", "xz", "xzxx")
elements = {"x": qi.sqx, "z": qi.msqz}
unitaries = [compose_u(d) for d in decompositions]
conjugation_table, times_table = construct_tables()

# TODO: generate these global names automatically via search
sqx = 15
msqz = 5

by_name, get_name, conjugation_table, times_table = construct_tables()


if __name__ == '__main__':
print find_up_to_phase(qi.sqx)
print find_up_to_phase(qi.msqz)
print by_name
print get_name


+ 18
- 13
cz.py Voir le fichier

@@ -3,6 +3,19 @@ import viz
import itertools as it
import clifford

#def cphase(a, b):
#""" Act a controlled-phase gate on two qubits """
#if g

def remove_vop(g, vops, a, b):
""" Reduces VOP[a] to the identity, avoiding (if possible) the use of vertex b as a swapping partner """
free_neighbours = g[a] - {b}
c = b if len(free_neighbours) == 0 else free_neighbours.pop()
d = clifford.decompositions[a]
for v in reversed(d):
target = a if v == clifford.by_name["msqx"] else b
local_complementation(g, vops, target)


def local_complementation(g, vops, v):
""" As defined in LISTING 1 of Anders & Briegel """
@@ -10,20 +23,11 @@ def local_complementation(g, vops, v):
toggle_edge(g, i, j)

# Update VOPs
vops[v] = clifford.times_table[vops[v]][clifford.sqx]
vops[v] = clifford.times_table[vops[v]][clifford.by_name["sqx"]]
for i in g[v]:
vops[i] = clifford.times_table[vops[i]][clifford.msqz]
vops[i] = clifford.times_table[vops[i]][clifford.by_name["msqz"]]


def remove_vop(g, vops, a, b):
""" Reduces VOP[a] to the identity, avoiding (if possible) the use of vertex b as a swapping partner """
free_neighbours = g[a] - {b}
c = b if len(free_neighbours) == 0 else free_neighbours.pop()
d = clifford.decompositions[a]
for v in reversed(d):
target = a if v == clifford.sqx else b
local_complementation(g, vops, target)


if __name__ == '__main__':
g, vops = graph()
@@ -31,7 +35,8 @@ if __name__ == '__main__':
add_edge(g, 1, 2)
add_edge(g, 0, 2)
add_edge(g, 0, 3)
add_edge(g, 6, 7)

viz.draw(g, vops, "out.pdf")
pos = viz.draw(g, vops, "out.pdf")
local_complementation(g, vops, 0)
viz.draw(g, vops, "out2.pdf")
viz.draw(g, vops, "out2.pdf", pos)

+ 5
- 2
graph.py Voir le fichier

@@ -3,10 +3,13 @@ Provides an extremely basic graph structure, based on neighbour lists
"""

from collections import defaultdict
import clifford

def graph():
""" Generate a graph with Hadamards on each qubit """
return defaultdict(set), defaultdict(int)
#return defaultdict(set), defaultdict(lambda: clifford.by_name["hadamard"])
return [set() for i in range(100)], [clifford.by_name["hadamard"] for i in range(100)]


def add_edge(graph, v1, v2):
""" Add an edge between two vertices in the graph """
@@ -32,7 +35,7 @@ def toggle_edge(graph, v1, v2):
def edgelist(g):
""" Describe a graph as an edgelist """
edges = frozenset(frozenset((i, n))
for i, v in enumerate(g.values())
for i, v in enumerate(g)
for n in v)
return [tuple(e) for e in edges]


+ 4
- 0
qi.py Voir le fichier

@@ -22,3 +22,7 @@ msqz = sqrtm(-1j * pz)
sqx = sqrtm(1j * px)
msqx = sqrtm(-1j * px)
paulis = (px, py, pz)

common_us = id, px, py, pz, ha, ph, sqz, msqz, sqy, msqy, sqx, msqx
names = "identity", "px", "py", "pz", "hadamard", "phase", "sqz", "msqz", "sqy", "msqy", "sqx", "msqx"
by_name = dict(zip(names, common_us))

+ 4
- 5
tests/test_clifford.py Voir le fichier

@@ -1,7 +1,7 @@
import clifford as lc
from numpy import *
from scipy.linalg import sqrtm
from qi import *
import qi
from tqdm import tqdm
import itertools as it

@@ -9,7 +9,7 @@ import itertools as it
def identify_pauli(m):
""" Given a signed Pauli matrix, name it. """
for sign in (+1, -1):
for pauli_label, pauli in zip("xyz", paulis):
for pauli_label, pauli in zip("xyz", qi.paulis):
if allclose(sign * pauli, m):
return sign, pauli_label

@@ -22,7 +22,7 @@ def _test_find_up_to_phase():

def get_action(u):
""" What does this unitary operator do to the Paulis? """
return [identify_pauli(u * p * u.H) for p in paulis]
return [identify_pauli(u * p * u.H) for p in qi.paulis]


def format_action(action):
@@ -37,8 +37,7 @@ def test_we_have_24_matrices():

def test_we_have_all_useful_gates():
""" Check that all the interesting gates are included up to a global phase """
common_us = id, px, py, pz, ha, ph, sqz, msqz, sqy, msqy, sqx, msqx
for u in common_us:
for name, u in qi.by_name.items():
lc.find_up_to_phase(u)




+ 6
- 0
tests/test_cz.py Voir le fichier

@@ -17,3 +17,9 @@ def test_local_complementation():
assert has_edge(g, 3, 1)

# TODO: test VOP conditions

def test_remove_vop():
""" Test that removing VOPs really works """
pass


+ 10
- 3
viz.py Voir le fichier

@@ -5,21 +5,28 @@ 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", ns=500):
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)
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)
nx.draw_networkx_edges(g, pos)

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)
plt.axis('off')
plt.savefig(filename)
return pos

if __name__ == '__main__':
g, vops = graph()


Chargement…
Annuler
Enregistrer