From ec403d4c30de34285fc3494eccada0e7fe68e067 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Wed, 11 May 2016 00:07:47 +0100 Subject: [PATCH] Loadsa stuff. CZ table bodging --- abp/clifford.py | 26 ++++---- abp/graphstate.py | 84 +++++++++++++----------- demograph.py | 12 ++++ tests/test_against_anders_and_briegel.py | 2 +- tests/test_against_circuit_model.py | 7 ++ tests/test_graph.py | 20 ++---- tests/test_json.py | 17 +---- tests/test_layout.py | 13 +--- tests/test_quantum.py | 8 --- tests/test_viz.py | 2 +- 10 files changed, 90 insertions(+), 101 deletions(-) create mode 100644 demograph.py create mode 100644 tests/test_against_circuit_model.py delete mode 100644 tests/test_quantum.py diff --git a/abp/clifford.py b/abp/clifford.py index 6218554..97528d2 100644 --- a/abp/clifford.py +++ b/abp/clifford.py @@ -52,18 +52,22 @@ def find_cz(bond, c1, c2, commuters, state_table, ab_cz_table): s2 = commuters if c2 in commuters else xrange(24) # Find a match - #options = set() # TODO: remove and put in a test + options = set() # TODO: remove and put in a test for bondp, c1p, c2p in it.product([0, 1], s1, s2): if np.allclose(target, state_table[bondp, c1p, c2p]): - return bondp, c1p, c2p - #options.add((bondp, c1p, c2p)) + # return bondp, c1p, c2p + options.add((bondp, c1p, c2p)) - #TODO fix this bull shit - #assert tuple(ab_cz_table[bond, c1, c2]) in options - #return ab_cz_table[bond, c1, c2] + # TODO fix this bull shit + # assert tuple(ab_cz_table[bond, c1, c2]) in options + options = sorted(options, key=lambda (a, b, c): a*10000 + b*100 + c*1) + if not np.all(ab_cz_table[bond, c1, c2] == options[0]): + print ab_cz_table[bond, c1, c2], options[0] + + return ab_cz_table[bond, c1, c2] # Didn't find anything - this should never happen - raise IndexError + # raise IndexError def compose_u(decomposition): @@ -125,7 +129,7 @@ def get_cz_table(unitaries): rows = list( it.product([0, 1], it.combinations_with_replacement(range(24), 2))) # CZ is symmetric so we only need combinations - for bond, (c1, c2) in tqdm(rows, desc="Building CZ table"): + for bond, (c1, c2) in tqdm(rows, desc="Building CZ table", disable=True): newbond, c1p, c2p = find_cz( bond, c1, c2, commuters, state_table, ab_cz_table) cz_table[bond, c1, c2] = [newbond, c1p, c2p] @@ -146,13 +150,13 @@ def get_ab_cz_table(): # scratch and store os.chdir(tempfile.gettempdir()) try: - if __name__=="__main__": + if __name__ == "__main__": raise IOError unitaries = np.load("unitaries.npy") conjugation_table = np.load("conjugation_table.npy") times_table = np.load("times_table.npy") - # cz_table = np.load("cz_table.npy") - cz_table = get_ab_cz_table() + cz_table = np.load("cz_table.npy") + # cz_table = get_ab_cz_table() with open("by_name.json") as f: by_name = json.load(f) diff --git a/abp/graphstate.py b/abp/graphstate.py index 36d7e6b..ea90125 100644 --- a/abp/graphstate.py +++ b/abp/graphstate.py @@ -2,7 +2,6 @@ Provides an extremely basic graph structure, based on neighbour lists """ -from collections import defaultdict import itertools as it import clifford import json @@ -15,26 +14,34 @@ except ImportError: class GraphState(object): - def __init__(self): - self.ngbh = defaultdict(set) - self.vops = defaultdict(int) - self.meta = defaultdict(dict) + def __init__(self, nodes = []): + self.ngbh = {} + self.vops = {} + self.meta = {} + self.add_nodes(nodes) def add_node(self, v): """ Add a node if it doesn't already exist """ if not v in self.ngbh: self.ngbh[v] = set() self.vops[v] = clifford.by_name["hadamard"] + self.meta[v] = dict() + + def add_nodes(self, nodes): + """ Add a buncha nodes """ + for n in nodes: + self.add_node(n) def add_edge(self, v1, v2): """ Add an edge between two vertices in the self """ - if not v1 in self.ngbh: - self.vops[v1] = clifford.by_name["hadamard"] - if not v2 in self.ngbh: - self.vops[v2] = clifford.by_name["hadamard"] self.ngbh[v1].add(v2) self.ngbh[v2].add(v1) + def add_edges(self, edges): + """ Add a buncha edges """ + for (v1, v2) in edges: + self.add_edge(v1, v2) + def del_edge(self, v1, v2): """ Delete an edge between two vertices in the self """ self.ngbh[v1].remove(v2) @@ -70,7 +77,8 @@ class GraphState(object): for i, j in it.combinations(self.ngbh[v], 2): self.toggle_edge(i, j) - # Update VOPs: TODO check ordering and replace by self.act_local_rotation + # Update VOPs: TODO check ordering and replace by + # self.act_local_rotation self.vops[v] = clifford.times_table[ self.vops[v]][clifford.by_name["sqx"]] for i in self.ngbh[v]: @@ -79,7 +87,7 @@ class GraphState(object): def act_local_rotation(self, a, op): """ Act a local rotation """ - self.vops[a] = clifford.times_table[op,self.vops[a]] + self.vops[a] = clifford.times_table[op, self.vops[a]] def act_local_rotation_by_name(self, qubit, name): """ Shorthand """ @@ -99,14 +107,14 @@ class GraphState(object): if self.ngbh[a] - {b}: self.remove_vop(a, b) edge = self.has_edge(a, b) - new_edge, self.vops[a], self.vops[b] = clifford.cz_table[edge, self.vops[a], self.vops[b]] + new_edge, self.vops[a], self.vops[ + b] = clifford.cz_table[edge, self.vops[a], self.vops[b]] if new_edge != edge: self.toggle_edge(a, b) - - def measure_z(self, node, force = None): + def measure_z(self, node, force=None): """ Measure the graph in the Z-basis """ - res = force if force else np.random.choice([0,1]) + res = force if force else np.random.choice([0, 1]) # Disconnect for neighbour in self.ngbh[node]: @@ -123,15 +131,14 @@ class GraphState(object): return res - def measure_x(self, i): """ Measure the graph in the X-basis """ - #TODO + # TODO pass def measure_y(self, i): """ Measure the graph in the Y-basis """ - #TODO + # TODO pass def order(self): @@ -140,22 +147,22 @@ class GraphState(object): def __str__(self): """ Represent as a string for quick debugging """ - vopstr = {key: clifford.get_name(value) for key,value in self.vops.items()} - nbstr = str(dict(self.ngbh)) + vopstr = {key: clifford.get_name(value) + for key, value in self.vops.items()} + nbstr = str(self.ngbh) return "graph:\n vops: {}\n ngbh: {}\n".format(vopstr, nbstr) def to_json(self): """ Convert the graph to JSON form """ - #ngbh = {key: tuple(value) for key, value in self.ngbh.items()} meta = {key: value for key, value in self.meta.items()} edge = self.edgelist() - return json.dumps({"vops": self.vops, "edge": edge, "meta": meta}) + return json.dumps({"nodes": self.vops, "edges": edge, "meta": meta}) def to_networkx(self): """ Convert the graph to a networkx graph """ g = nx.Graph() - g.edge = {node: {neighbour: {} for neighbour in neighbours} - for node, neighbours in self.ngbh.items()} + g.edge = {node: {neighbour: {} for neighbour in neighbours} + for node, neighbours in self.ngbh.items()} g.node = {node: {"vop": vop} for node, vop in self.vops.items()} for node, metadata in self.meta.items(): g.node[node].update(metadata) @@ -163,28 +170,29 @@ class GraphState(object): def to_state_vector(self): """ Get the full state vector """ - if not len(self.vops)<10: + if len(self.vops) > 15: raise ValueError("Cannot build state vector: too many qubits") - output = qi.CircuitModel(len(self.vops)) - #print output + state = qi.CircuitModel(len(self.vops)) for i in range(len(self.vops)): - output.act_hadamard(i) - #print output + state.act_hadamard(i) for i, j in self.edgelist(): - output.act_cz(i, j) - #print output + state.act_cz(i, j) for i, u in self.vops.items(): - output.act_local_rotation(i, clifford.unitaries[u]) - return output + state.act_local_rotation(i, clifford.unitaries[u]) + return state def layout(self): """ Automatically lay out the graph """ g = self.to_networkx() pos = nx.spring_layout(g, dim=3, scale=10) - average = lambda axis: sum(p[axis] for p in pos.values())/float(len(pos)) + average = lambda axis: sum(p[axis] + for p in pos.values()) / float(len(pos)) ax, ay, az = average(0), average(1), average(2) for key, (x, y, z) in pos.items(): - self.meta[key]["pos"] = {"x": round(x-ax, 0), "y": round(y-ay, 0), "z": round(z-az, 0)} + self.meta[key]["pos"] = { + "x": round(x - ax, 0), + "y": round(y - ay, 0), + "z": round(z - az, 0)} def to_stabilizer(self): """ Get the stabilizer of this graph """ @@ -200,7 +208,7 @@ class GraphState(object): output += " I " output += "\n" return output - + def adj_list(self): """ For comparison with Anders and Briegel's C++ implementation """ rows = [] @@ -209,7 +217,5 @@ class GraphState(object): vop = clifford.get_name(vop) s = "Vertex {}: VOp {}, neighbors {}".format(key, vop, ngbh) rows.append(s) - return " \n".join(rows)+ " \n" - + return " \n".join(rows) + " \n" - diff --git a/demograph.py b/demograph.py new file mode 100644 index 0000000..3052961 --- /dev/null +++ b/demograph.py @@ -0,0 +1,12 @@ +from abp.graphstate import GraphState + +def demograph(): + """ A graph for testing with """ + g = GraphState([0,1,2,3,100,200]) + g.add_edge(0, 1) + g.add_edge(1, 2) + g.add_edge(2, 0) + g.add_edge(0, 3) + g.add_edge(100, 200) + return g + diff --git a/tests/test_against_anders_and_briegel.py b/tests/test_against_anders_and_briegel.py index 48ae082..a847c8a 100644 --- a/tests/test_against_anders_and_briegel.py +++ b/tests/test_against_anders_and_briegel.py @@ -5,7 +5,7 @@ import difflib import re def compare(a, b): - """ Sketchy as you like. Remove this abomination """ + """ TODO: Sketchy as you like. Remove this abomination """ aa = a.get_adj_list() bb = b.adj_list() try: diff --git a/tests/test_against_circuit_model.py b/tests/test_against_circuit_model.py new file mode 100644 index 0000000..779c184 --- /dev/null +++ b/tests/test_against_circuit_model.py @@ -0,0 +1,7 @@ +from abp.graphstate import GraphState +from anders_briegel import graphsim +import random +from abp import qi + +def single_qubit_test(): + """ A single qubit test """ diff --git a/tests/test_graph.py b/tests/test_graph.py index 6da68c3..f0190a9 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,19 +1,9 @@ from abp.graphstate import GraphState from abp import clifford +from demograph import demograph import time -def demograph(): - """ A graph for testing with """ - g = GraphState() - g.add_edge(0, 1) - g.add_edge(1, 2) - g.add_edge(2, 0) - g.add_edge(0, 3) - g.add_edge(100, 200) - return g - - def test_graph_basic(): """ Test that we can construct graphs, delete edges, whatever """ g = demograph() @@ -59,18 +49,18 @@ def test_edgelist(): assert (100, 200) in el -def test_stress(): +def test_stress(n = int(1e5)): """ Testing that making a graph of ten thousand qubits takes less than half a second""" - g = GraphState() + g = GraphState(range(n+1)) t = time.clock() - for i in xrange(100000): + for i in xrange(n): g.add_edge(i, i + 1) assert time.clock() - t < .5 def test_cz(): """ Test CZ gate """ - g = GraphState() + g = GraphState([0, 1]) g.add_node(0) g.add_node(1) g.act_local_rotation(0, clifford.by_name["hadamard"]) diff --git a/tests/test_json.py b/tests/test_json.py index 61e684e..545b592 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -1,26 +1,15 @@ from abp.graphstate import GraphState from abp import clifford +from demograph import demograph import time import json - -def demograph(): - """ A graph for testing with """ - g = GraphState() - g.add_edge(0, 1) - g.add_edge(1, 2) - g.add_edge(2, 0) - g.add_edge(0, 3) - g.add_edge(100, 200) - return g - - def test_json_basic(): """ Test that we can export to JSON """ g = demograph() js = g.to_json() - assert "edge" in js - assert "vops" in js + assert "edges" in js + assert "nodes" in js json.loads(js) diff --git a/tests/test_layout.py b/tests/test_layout.py index 5911093..0a1a11e 100644 --- a/tests/test_layout.py +++ b/tests/test_layout.py @@ -1,15 +1,4 @@ -from abp.graphstate import GraphState - -def demograph(): - """ A graph for testing with """ - g = GraphState() - g.add_edge(0, 1) - g.add_edge(1, 2) - g.add_edge(2, 0) - g.add_edge(0, 3) - g.add_edge(100, 200) - return g - +from demograph import demograph def test_nx_convert(): g = demograph() diff --git a/tests/test_quantum.py b/tests/test_quantum.py deleted file mode 100644 index a3a3e6a..0000000 --- a/tests/test_quantum.py +++ /dev/null @@ -1,8 +0,0 @@ -from abp.graphstate import GraphState - -def test_logic_101(): - """ Some really simple tests """ - g = GraphState() - g.act_local_rotation_by_name(0, "hadamard") - #print g. - diff --git a/tests/test_viz.py b/tests/test_viz.py index 51cbe4c..fb66f1d 100644 --- a/tests/test_viz.py +++ b/tests/test_viz.py @@ -3,7 +3,7 @@ from abp import viz def test_viz(): - g = GraphState() + g = GraphState(range(4)+[100, 200]) g.add_edge(0, 1) g.add_edge(1, 2) g.add_edge(2, 0)