diff --git a/abp/fancy.py b/abp/fancy.py index 8ec95db..94185ff 100644 --- a/abp/fancy.py +++ b/abp/fancy.py @@ -43,7 +43,7 @@ class GraphState(graphstate.GraphState, nx.Graph): time.sleep(delay) except websocket._exceptions.WebSocketTimeoutException: print "Timed out ... you might be pushing a bit hard" - sys.exit(0) + time.sleep(delay) #self.ws.close() #self.connect_to_server() diff --git a/abp/graphstate.py b/abp/graphstate.py index f443e0d..417d61f 100644 --- a/abp/graphstate.py +++ b/abp/graphstate.py @@ -42,6 +42,21 @@ class GraphState(object): for n in range(data): self._add_node(n, vop=vop) + def add_node(self, *args, **kwargs): + """ Add a node """ + self._add_node(self, *args, **kwargs) + + + def _del_node(self, node): + """ Remove a node. TODO: this is a hack right now! """ + if not node in self.node: + return + del self.node[node] + for k in self.adj[node]: + del self.adj[k][node] + del self.adj[node] + + def _add_node(self, node, **kwargs): """ Add a node. By default, nodes are initialized with ``vop=``:math:`I`, i.e. they are in the :math:`|+\\rangle` state. @@ -56,7 +71,10 @@ class GraphState(object): fred """ - assert not node in self.node, "Node {} already exists".format(v) + if node in self.node: + print "Warning: node {} already exists".format(node) + return + default = kwargs.get("default", "identity") self.adj[node] = {} self.node[node] = {} @@ -405,9 +423,6 @@ class GraphState(object): >>> with open("graph.json") as f: json.dump(graph.to_json(True), f) - .. todo:: - Implement ``from_json()``! - """ if stringify: node = {str(key): value for key, value in self.node.items()} @@ -417,6 +432,13 @@ class GraphState(object): else: return {"node": self.node, "adj": self.adj} + def from_json(self, data): + """ Construct the graph from JSON data + :param data: JSON data to be read. + """ + self.node = data["node"] + self.adj = data["adj"] + def to_state_vector(self): """ Get the full state vector corresponding to this stabilizer state. Useful for debugging, interface with other simulators. This method becomes very slow for more than about ten qubits! diff --git a/abp/static/index.html b/abp/static/index.html index e0f3148..4f6529d 100644 --- a/abp/static/index.html +++ b/abp/static/index.html @@ -29,16 +29,14 @@
diff --git a/abp/static/main.css b/abp/static/main.css index 8614b3a..4e17bb9 100644 --- a/abp/static/main.css +++ b/abp/static/main.css @@ -26,6 +26,9 @@ html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-fam font-size: 9pt; } +#node_name { + font-size: 12pt; +} #node_data { background-color: black; diff --git a/abp/static/scripts/anders_briegel.js b/abp/static/scripts/anders_briegel.js index c1fe54b..e514ca9 100644 --- a/abp/static/scripts/anders_briegel.js +++ b/abp/static/scripts/anders_briegel.js @@ -41,80 +41,19 @@ abj.has_edge = function(a, b) { return Object.prototype.hasOwnProperty.call(abj.adj[a], b); }; -abj.toggle_edge = function(a, b) { - if (abj.has_edge(a, b)) { - abj.del_edge(a, b); - } else { - abj.add_edge(a, b); - } -}; - -abj.get_swap = function(node, avoid) { - for (var i in abj.adj[node]) { - if (i != avoid) { - return i; - } - } - return avoid; -}; - -abj.remove_vop = function(node, avoid) { - var swap_qubit = abj.get_swap(node, avoid); - var decomposition = tables.decompositions[abj.node[node].vop]; - for (var i = decomposition.length - 1; i >= 0; --i) { - var v = decomposition[i]; - abj.local_complementation(v == "x" ? node : swap_qubit); - } -}; - -abj.local_complementation = function(node) { - // TODO: inefficient - var done = {}; - for (var i in abj.adj) { - for (var j in abj.adj[i]) { - var name = i>j ? [i,j] : [j,i]; - if (done[name]===false){ - abj.toggle_edge(i, j); - done[name] = true; - } - } - abj.node[i].vop = tables.times_table[abj.node[i].vop][6]; - } - abj.node[node].vop = tables.times_table[abj.node[node].vop][14]; -}; - -abj.act_local_rotation = function(node, operation) { - var rotation = tables.clifford[operation]; - abj.node[node].vop = tables.times_table[rotation][abj.node[node].vop]; -}; - -abj.act_hadamard = function(node) { - abj.act_local_rotation(node, 10); -}; - abj.is_sole_member = function(group, node) { // TODO: this is slow as heck var keys = Object.keys(group); return keys.length == 1 && keys[0] == node; }; -abj.act_cz = function(a, b) { - if (abj.is_sole_member(abj.adj[a], b)) { - abj.remove_vop(a, b); - } - if (abj.is_sole_member(abj.adj[b], a)) { - abj.remove_vop(b, a); - } - if (abj.is_sole_member(abj.adj[a], b)) { - abj.remove_vop(a, b); - } - var edge = abj.has_edge(a, b); - var new_state = tables.cz_table[edge ? 1 : 0][abj.node[a].vop][abj.node[b].vop]; - abj.node[a].vop = new_state[1]; - abj.node[b].vop = new_state[2]; - if (new_state[0] != edge) { - abj.toggle_edge(a, b); - } +abj.update = function(newState) { + abj.node = newState.node; + abj.adj = newState.adj; +}; + +abj.order = function(){ + return Object.keys(abj.node).length; }; abj.edgelist = function() { @@ -131,18 +70,4 @@ abj.edgelist = function() { return output; }; -abj.log_graph_state = function() { - console.log(JSON.stringify(abj.node)); - console.log(JSON.stringify(abj.adj)); -}; - -abj.update = function(newState) { - abj.node = newState.node; - abj.adj = newState.adj; -}; - -abj.order = function(){ - return Object.keys(abj.node).length; -}; - diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index 173ce79..3e240f5 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -32,14 +32,10 @@ editor.onFreeMove = function() { }; editor.focus = function(node) { - editor.grid.position.copy(abj.node[node].position); - gui.controls.target.copy(abj.node[node].position); gui.hideNodeMessage(); editor.selection = node; - gui.serverMessage("Selected node " + node + "."); - node_name.innerHTML = "Node " + node; - node_data.className = "visible"; - node_vop.innerHTML = "VOP: " + abj.node[node].vop; + + //gui.serverMessage("Selected node " + node + "."); }; editor.addQubitAtPoint = function(point) { @@ -47,19 +43,13 @@ editor.addQubitAtPoint = function(point) { return; } point.round(); - - // Check for clashes - for (var node in abj.node) { - var delta = new THREE.Vector3(); - delta.subVectors(abj.node[node].position, point); - if (delta.length()<0.1){ return; } + var new_node = Math.floor(point.x) + "," + Math.floor(point.y) + "," + Math.floor(point.z); + if (Object.prototype.hasOwnProperty.call(abj.node, new_node)) { + gui.serverMessage("Node " + new_node +" already exists."); + return; } - - // TODO: This SUCKS - var new_node = point.x + "." + point.y + "." + point.z; - abj.add_node(new_node, { position: point, vop:0 }); + websocket.edit({action:"create", name:new_node, position: point}); editor.focus(new_node); - graph.update(); gui.serverMessage("Created node " + new_node +"."); }; @@ -67,6 +57,12 @@ editor.onClick = function() { var found = editor.findNodeOnRay(mouse.ray); if (found) { editor.focus(found); + var node=found; + editor.grid.position.copy(abj.node[node].position); + gui.controls.target.copy(abj.node[node].position); + node_name.innerHTML = "Node " + node; + node_data.className = "visible"; + node_vop.innerHTML = "VOP: " + abj.node[node].vop; } else { var intersection = mouse.ray.intersectPlane(editor.plane); if (intersection !== null) { @@ -80,10 +76,10 @@ editor.onShiftClick = function() { if (found === undefined){ return; } if (editor.selection === undefined){ return; } if (found === editor.selection){ return; } - abj.act_cz(found, editor.selection); - editor.focus(found); + //abj.act_cz(found, editor.selection); + websocket.edit({action:"cz", start:found, end:editor.selection}); gui.serverMessage("Acted CZ between " + found + " & " + editor.selection + "."); - graph.update(); + editor.focus(found); }; editor.onCtrlClick = function() { @@ -91,9 +87,8 @@ editor.onCtrlClick = function() { if (found === undefined){ return; } if (editor.selection === undefined){ return; } editor.focus(found); - abj.act_hadamard(found); + websocket.edit({action:"hadamard", node:found}); gui.serverMessage("Acted H on node " + found + "."); - graph.update(); }; @@ -147,16 +142,47 @@ editor.findNodeOnRay = function(ray) { editor.deleteNode = function() { if (editor.selection === undefined){ return; } - abj.del_node(editor.selection); - graph.update(); + websocket.edit({action:"delete", node:editor.selection}); gui.serverMessage("Deleted node " + editor.selection + "."); editor.selection = undefined; node_data.className = "hidden"; }; +//TODO: loadsa space for DRY here + +editor.hadamard = function() { + if (editor.selection === undefined){ return; } + websocket.edit({action:"hadamard", node:editor.selection}); + gui.serverMessage("Acted Hadamard on node " + editor.selection + "."); +}; + +editor.phase = function() { + if (editor.selection === undefined){ return; } + websocket.edit({action:"phase", node:editor.selection}); + gui.serverMessage("Acted phase on node " + editor.selection + "."); +}; + +editor.measureX = function() { + if (editor.selection === undefined){ return; } + websocket.edit({action:"measure", node:editor.selection, basis:"x"}); + gui.serverMessage("Measured node " + editor.selection + " in X."); +}; + +editor.measureY = function() { + if (editor.selection === undefined){ return; } + websocket.edit({action:"measure", node:editor.selection, basis:"y"}); + gui.serverMessage("Measured node " + editor.selection + " in Y."); +}; + +editor.measureZ = function() { + if (editor.selection === undefined){ return; } + websocket.edit({action:"measure", node:editor.selection, basis:"z"}); + gui.serverMessage("Measured node " + editor.selection + " in z."); +}; + editor.localComplementation = function() { if (editor.selection === undefined){ return; } + websocket.edit({action:"localcomplementation", node:editor.selection}); abj.local_complementation(editor.selection); - graph.update(); gui.serverMessage("Inverted neighbourhood of " + editor.selection + "."); }; diff --git a/abp/static/scripts/graph.js b/abp/static/scripts/graph.js index 98bd51b..9cf6a00 100644 --- a/abp/static/scripts/graph.js +++ b/abp/static/scripts/graph.js @@ -47,6 +47,23 @@ graph.update = function(newState) { edges.add(newEdge); } + if (editor.selection) { + console.log(editor.selection); + var node = editor.selection; + if (Object.prototype.hasOwnProperty.call(abj.node, node)) { + editor.grid.position.copy(abj.node[node].position); + gui.controls.target.copy(abj.node[node].position); + node_name.innerHTML = "Node " + node; + node_data.className = "visible"; + node_vop.innerHTML = "VOP: " + abj.node[node].vop; + } else { + editor.selection = undefined; + node_data.className = "hidden"; + } + } else { + node_data.className = "hidden"; + } + var particles = new THREE.Points(geometry, materials.qubit); var object = new THREE.Object3D(); object.name = "graphstate"; @@ -54,5 +71,6 @@ graph.update = function(newState) { object.add(edges); gui.scene.add(object); gui.render(); + }; diff --git a/abp/static/scripts/materials.js b/abp/static/scripts/materials.js index 12fe02a..a6d0f5d 100644 --- a/abp/static/scripts/materials.js +++ b/abp/static/scripts/materials.js @@ -1,7 +1,7 @@ var materials = {}; var curveProperties = { - splineDensity: 1, + splineDensity: 10, curvature: 20 }; diff --git a/abp/static/scripts/tests.js b/abp/static/scripts/tests.js deleted file mode 100644 index 8b9c738..0000000 --- a/abp/static/scripts/tests.js +++ /dev/null @@ -1,4 +0,0 @@ -QUnit.test( "Adding nodes", function( assert ) { - abj.add_node(0); - assert.ok(abj.node[0].vop === 10, JSON.stringify(abj.node)); -}); diff --git a/abp/static/scripts/websocket.js b/abp/static/scripts/websocket.js index e40c1b6..919b9d2 100644 --- a/abp/static/scripts/websocket.js +++ b/abp/static/scripts/websocket.js @@ -1,16 +1,20 @@ var websocket = {}; +websocket.update = undefined; websocket.connect = function(update) { - var ws = new WebSocket("ws://localhost:5000"); - ws.onopen = function(evt) { + websocket.ws = new WebSocket("ws://localhost:5000"); + if (update){ + websocket.update = update; + } + websocket.ws.onopen = function(evt) { gui.serverMessage("Connected to server."); }; - ws.onerror = function(err) { + websocket.ws.onerror = function(err) { gui.serverMessage("Could not connect to server."); }; - ws.onmessage = function(evt) { + websocket.ws.onmessage = function(evt) { json = JSON.parse(evt.data); for (var i in json.node) { var pos = json.node[i].position; @@ -19,10 +23,14 @@ websocket.connect = function(update) { json.node[i].vop = 0; } } - update(json); + websocket.update(json); }; - ws.onclose = function(evt) { + websocket.ws.onclose = function(evt) { gui.serverMessage("No connection to server. Reconnect.", true); }; }; + +websocket.edit = function (data) { + websocket.ws.send("edit:"+JSON.stringify(data)); +}; diff --git a/bin/abpserver b/bin/abpserver index 2f0321d..63f7030 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -12,17 +12,55 @@ import os, sys, threading import webbrowser import argparse import abp +import json from pkg_resources import resource_filename +from pprint import pprint +import time clients = [] +local_state = abp.GraphState() + +def process_edit(edit, client, server): + action = edit["action"] + + pprint(edit) + + if action == "create": + local_state.add_qubit(edit["name"], position=edit["position"], vop=0) + elif action == "cz": + local_state.act_cz(edit["start"], edit["end"]) + elif action == "hadamard": + local_state.act_hadamard(edit["node"]) + elif action == "phase": + local_state.act_local_rotation(edit["node"], "phase") + elif action == "delete": + local_state._del_node(edit["node"]) + elif action == "localcomplementation": + local_state.local_complementation(edit["node"]) + elif action == "measure": + local_state.measure(edit["node"], "p"+edit["basis"]) + else: + pass + + #server.send_message(client, json.dumps(local_state.to_json())) + server.send_message_to_all(json.dumps(local_state.to_json())) def new_message(client, server, message): - print "Received update from client {}.".format(client["id"]) - server.send_message_to_all(message) + if message.startswith("edit:"): + edit = json.loads(message[5:]) + process_edit(edit, client, server) + else: + print "Received update from python {}.".format(client["id"]) + print message + local_state.from_json(json.loads(message)) + print local_state + server.send_message_to_all(message) def new_client(client, server): print "Client {} connected.".format(client["id"]) clients.append(client) + print "Sent state of {} nodes to client {}".format(local_state.order(), client["id"]) + server.send_message(client, json.dumps(local_state.to_json())) def client_left(client, server): print "Client {} disconnected.".format(client["id"]) diff --git a/examples/visualization/grid_2d.py b/examples/visualization/grid_2d.py index 6a88d40..63298ca 100644 --- a/examples/visualization/grid_2d.py +++ b/examples/visualization/grid_2d.py @@ -2,13 +2,22 @@ from abp.fancy import GraphState from abp.util import xyz import itertools -psi = GraphState() -grid = itertools.product(range(10), range(10)) -for i, (x, y) in enumerate(grid): - psi.add_qubit(i, position=xyz(x, y, 0), vop=0) +def grid_2d(width, height): + """ Make a 2D grid """ + psi = GraphState() + grid = list(itertools.product(range(width), range(height))) -for i in range(50): - psi.act_cz(i, i+1) + for x, y in grid: + psi.add_qubit((x, y), position=xyz(x, y, 0), vop=0) -psi.update() + for x, y in grid: + if x