|
@@ -6,6 +6,10 @@ from collections import defaultdict |
|
|
import itertools as it |
|
|
import itertools as it |
|
|
import clifford |
|
|
import clifford |
|
|
import json |
|
|
import json |
|
|
|
|
|
try: |
|
|
|
|
|
import networkx as nx |
|
|
|
|
|
except ImportError: |
|
|
|
|
|
print "Could not import networkx: layout will not work" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GraphState(object): |
|
|
class GraphState(object): |
|
@@ -13,6 +17,7 @@ class GraphState(object): |
|
|
def __init__(self): |
|
|
def __init__(self): |
|
|
self.ngbh = defaultdict(set) |
|
|
self.ngbh = defaultdict(set) |
|
|
self.vops = defaultdict(int) |
|
|
self.vops = defaultdict(int) |
|
|
|
|
|
self.meta = defaultdict(dict) |
|
|
|
|
|
|
|
|
def add_vertex(self, v): |
|
|
def add_vertex(self, v): |
|
|
""" Add a vertex if it doesn't already exist """ |
|
|
""" Add a vertex if it doesn't already exist """ |
|
@@ -84,7 +89,6 @@ class GraphState(object): |
|
|
if self.ngbh[a] - {b}: |
|
|
if self.ngbh[a] - {b}: |
|
|
self.remove_vop(a, b) |
|
|
self.remove_vop(a, b) |
|
|
edge = self.has_edge(a, b) |
|
|
edge = self.has_edge(a, b) |
|
|
# TODO put this in a new function for diff hook |
|
|
|
|
|
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: |
|
|
if new_edge != edge: |
|
|
self.toggle_edge(a, b) |
|
|
self.toggle_edge(a, b) |
|
@@ -97,22 +101,24 @@ class GraphState(object): |
|
|
def to_json(self): |
|
|
def to_json(self): |
|
|
""" Convert the graph to JSON form """ |
|
|
""" Convert the graph to JSON form """ |
|
|
ngbh = {key: tuple(value) for key, value in self.ngbh.items()} |
|
|
ngbh = {key: tuple(value) for key, value in self.ngbh.items()} |
|
|
return json.dumps({"vops": self.vops, "ngbh": ngbh}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DiffedGraphState(GraphState): |
|
|
|
|
|
""" Just like a graph state, but tracks changes for rendering purposes """ |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
GraphState.__init__(self) |
|
|
|
|
|
self.diff = [] |
|
|
|
|
|
|
|
|
|
|
|
def add_vertex(self, v): |
|
|
|
|
|
GraphState.add_vertex(self, v) |
|
|
|
|
|
self.diff.append("add_vertex {}".format(v)) |
|
|
|
|
|
|
|
|
|
|
|
def add_edge(self, v1, v2): |
|
|
|
|
|
GraphState.add_edge(self, v1, v2) |
|
|
|
|
|
self.diff.append("add_edge {} {}".format(v1, v2)) |
|
|
|
|
|
|
|
|
meta = {key: value for key, value in self.meta.items()} |
|
|
|
|
|
return json.dumps({"vops": self.vops, "ngbh": ngbh, "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.node = {node: {"vop": vop} for node, vop in self.vops.items()} |
|
|
|
|
|
for node, metadata in self.meta.items(): |
|
|
|
|
|
g.node[node].update(metadata) |
|
|
|
|
|
return g |
|
|
|
|
|
|
|
|
|
|
|
def layout(self): |
|
|
|
|
|
""" Automatically lay out the graph """ |
|
|
|
|
|
g = self.to_networkx() |
|
|
|
|
|
pos = nx.spring_layout(g, dim=3, scale=10) |
|
|
|
|
|
for key, (x, y, z) in pos.items(): |
|
|
|
|
|
self.meta[key]["pos"] = {"x": round(x, 0), "y": round(y, 0), "z": round(z, 0)} |
|
|
|
|
|
|
|
|
|
|
|
|