From b163e8582b2883f64b540986a94ef6d76a52d617 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Mon, 19 Sep 2016 13:34:35 +0100 Subject: [PATCH 01/20] Don't give up on network timeout --- abp/fancy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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() From 826a8b26d379d21acc308903a7619e7b74ae19d6 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Thu, 3 Nov 2016 17:56:05 +0000 Subject: [PATCH 02/20] Starting to work on stripping out abp.js --- abp/static/scripts/websocket.js | 10 +++++----- bin/abpserver | 10 ++++++++-- examples/visualization/grid_2d.py | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 examples/visualization/grid_2d.py diff --git a/abp/static/scripts/websocket.js b/abp/static/scripts/websocket.js index e40c1b6..438c1ca 100644 --- a/abp/static/scripts/websocket.js +++ b/abp/static/scripts/websocket.js @@ -1,16 +1,16 @@ var websocket = {}; websocket.connect = function(update) { - var ws = new WebSocket("ws://localhost:5000"); - ws.onopen = function(evt) { + websocket.ws = new WebSocket("ws://localhost:5000"); + 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; @@ -22,7 +22,7 @@ websocket.connect = function(update) { update(json); }; - ws.onclose = function(evt) { + websocket.ws.onclose = function(evt) { gui.serverMessage("No connection to server. Reconnect.", true); }; }; diff --git a/bin/abpserver b/bin/abpserver index 2f0321d..e6b1f1a 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -12,13 +12,19 @@ import os, sys, threading import webbrowser import argparse import abp +import json from pkg_resources import resource_filename clients = [] 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:]) + print "Received update from javascript." + print edit + else: + print "Received update from python {}.".format(client["id"]) + server.send_message_to_all(message) def new_client(client, server): print "Client {} connected.".format(client["id"]) diff --git a/examples/visualization/grid_2d.py b/examples/visualization/grid_2d.py new file mode 100644 index 0000000..63298ca --- /dev/null +++ b/examples/visualization/grid_2d.py @@ -0,0 +1,23 @@ +from abp.fancy import GraphState +from abp.util import xyz +import itertools + +def grid_2d(width, height): + """ Make a 2D grid """ + psi = GraphState() + grid = list(itertools.product(range(width), range(height))) + + for x, y in grid: + psi.add_qubit((x, y), position=xyz(x, y, 0), vop=0) + + for x, y in grid: + if x Date: Thu, 3 Nov 2016 18:08:03 +0000 Subject: [PATCH 03/20] Can message abpserver from JavaScript --- abp/static/scripts/editor.js | 13 +------------ abp/static/scripts/websocket.js | 4 ++++ bin/abpserver | 3 ++- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index 173ce79..4b33f76 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -48,18 +48,7 @@ editor.addQubitAtPoint = function(point) { } 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; } - } - - // TODO: This SUCKS - var new_node = point.x + "." + point.y + "." + point.z; - abj.add_node(new_node, { position: point, vop:0 }); - editor.focus(new_node); - graph.update(); + websocket.edit({test:"test"}); gui.serverMessage("Created node " + new_node +"."); }; diff --git a/abp/static/scripts/websocket.js b/abp/static/scripts/websocket.js index 438c1ca..91c8825 100644 --- a/abp/static/scripts/websocket.js +++ b/abp/static/scripts/websocket.js @@ -26,3 +26,7 @@ websocket.connect = function(update) { 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 e6b1f1a..48d10d0 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -18,7 +18,8 @@ from pkg_resources import resource_filename clients = [] def new_message(client, server, message): - if message.startswith("edit"): + if message.startswith("edit:"): + print message[5:] edit = json.loads(message[5:]) print "Received update from javascript." print edit From d6b5f540df6908b5b924db9186aa70d3dec34201 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Thu, 3 Nov 2016 18:44:01 +0000 Subject: [PATCH 04/20] Add & test GraphState.from_json We needed to implement `GraphState.from_json` so that the server can track a copy of the client's state. That's a useful byproduct of this work! --- abp/graphstate.py | 10 +++++++--- bin/abpserver | 1 + tests/test_json.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/test_json.py diff --git a/abp/graphstate.py b/abp/graphstate.py index f443e0d..1444fc2 100644 --- a/abp/graphstate.py +++ b/abp/graphstate.py @@ -405,9 +405,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 +414,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/bin/abpserver b/bin/abpserver index 48d10d0..08069e1 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -16,6 +16,7 @@ import json from pkg_resources import resource_filename clients = [] +local_state = abp.GraphState() def new_message(client, server, message): if message.startswith("edit:"): diff --git a/tests/test_json.py b/tests/test_json.py new file mode 100644 index 0000000..9c0053b --- /dev/null +++ b/tests/test_json.py @@ -0,0 +1,31 @@ +import mock +import abp + +def test_json(): + """ Test to_json and from_json """ + a = mock.named_node_graph() + j = a.to_json() + + b = abp.GraphState() + b.from_json(j) + assert a == b + + +def test_json_again(): + """ Test to_json and from_json """ + # Make a random graph + a = abp.GraphState(10) + a.act_circuit(mock.random_graph_circuit()) + + # Dump it to JSON + j = a.to_json() + + # Reconstruct from JSON + b = abp.GraphState() + b.from_json(j) + + # Check equality + assert a == b + + + From 352a1d4325316fd6cb60f21ed8567669e7d2d977 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Thu, 3 Nov 2016 18:55:05 +0000 Subject: [PATCH 05/20] `add_node` is a constant annoyance :rage4: NetworkX provides `add_node`, we don't, leads to missing `graph.node["vop"]`. Does this fix it? --- abp/graphstate.py | 5 +++++ bin/abpserver | 3 +++ 2 files changed, 8 insertions(+) diff --git a/abp/graphstate.py b/abp/graphstate.py index 1444fc2..a62c888 100644 --- a/abp/graphstate.py +++ b/abp/graphstate.py @@ -42,6 +42,11 @@ 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 _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. diff --git a/bin/abpserver b/bin/abpserver index 08069e1..67be3dc 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -26,6 +26,9 @@ def new_message(client, server, message): print edit 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): From 899b20281010e8cfaf521e2e7a7e3f95b4ee6ddc Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Fri, 4 Nov 2016 21:09:35 +0000 Subject: [PATCH 06/20] Closed the loop - JS -> Python -> JS --- abp/static/scripts/editor.js | 4 ++-- bin/abpserver | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index 4b33f76..71f1610 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -47,8 +47,8 @@ editor.addQubitAtPoint = function(point) { return; } point.round(); - - websocket.edit({test:"test"}); + var new_node = Math.floor(point.x*1000000 + point.y*1000 + point.z); + websocket.edit({action:"create", name:new_node, position: point}); gui.serverMessage("Created node " + new_node +"."); }; diff --git a/bin/abpserver b/bin/abpserver index 67be3dc..ccf545d 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -18,12 +18,19 @@ from pkg_resources import resource_filename clients = [] local_state = abp.GraphState() +def process_edit(edit, server): + action = edit["action"] + if action == "create": + local_state.add_qubit(edit["name"], position=edit["position"]) + server.send_message_to_all(json.dumps(local_state.to_json())) + + def new_message(client, server, message): if message.startswith("edit:"): print message[5:] edit = json.loads(message[5:]) print "Received update from javascript." - print edit + process_edit(edit, server) else: print "Received update from python {}.".format(client["id"]) print message From 5567258c53407594c93d455e3011d2c68023b7f3 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Fri, 4 Nov 2016 21:30:24 +0000 Subject: [PATCH 07/20] Now I can do CZ gates. Focus sucks though. --- abp/static/scripts/editor.js | 6 ++++-- bin/abpserver | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index 71f1610..29dcedd 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -47,8 +47,9 @@ editor.addQubitAtPoint = function(point) { return; } point.round(); - var new_node = Math.floor(point.x*1000000 + point.y*1000 + point.z); + var new_node = Math.floor(point.x) + "," + Math.floor(point.y) + "," + Math.floor(point.z); websocket.edit({action:"create", name:new_node, position: point}); + editor.focus(new_node); gui.serverMessage("Created node " + new_node +"."); }; @@ -69,7 +70,8 @@ editor.onShiftClick = function() { if (found === undefined){ return; } if (editor.selection === undefined){ return; } if (found === editor.selection){ return; } - abj.act_cz(found, editor.selection); + //abj.act_cz(found, editor.selection); + websocket.edit({action:"cz", start:found, end:editor.selection}); editor.focus(found); gui.serverMessage("Acted CZ between " + found + " & " + editor.selection + "."); graph.update(); diff --git a/bin/abpserver b/bin/abpserver index ccf545d..a78a6eb 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -20,9 +20,19 @@ local_state = abp.GraphState() def process_edit(edit, server): action = edit["action"] + + print edit + + print local_state.node.keys() + if action == "create": - local_state.add_qubit(edit["name"], position=edit["position"]) - server.send_message_to_all(json.dumps(local_state.to_json())) + print type(edit["name"]) + local_state.add_qubit(edit["name"], position=edit["position"], vop=0) + if action == "cz": + local_state.act_cz(edit["start"], edit["end"]) + + server.send_message_to_all(json.dumps(local_state.to_json())) + def new_message(client, server, message): From 1c80b1f3941ae996ab89cc6d32b990efb806f07a Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Fri, 4 Nov 2016 21:49:28 +0000 Subject: [PATCH 08/20] Selection now works - pretty hacky though. --- abp/static/scripts/editor.js | 6 +----- abp/static/scripts/graph.js | 12 ++++++++++++ bin/abpserver | 13 ++++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index 29dcedd..f5bc9e7 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -32,14 +32,9 @@ 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; }; editor.addQubitAtPoint = function(point) { @@ -136,6 +131,7 @@ editor.findNodeOnRay = function(ray) { return undefined; }; + editor.deleteNode = function() { if (editor.selection === undefined){ return; } abj.del_node(editor.selection); diff --git a/abp/static/scripts/graph.js b/abp/static/scripts/graph.js index 98bd51b..1f09aaa 100644 --- a/abp/static/scripts/graph.js +++ b/abp/static/scripts/graph.js @@ -47,6 +47,17 @@ graph.update = function(newState) { edges.add(newEdge); } + if (editor.selection) { + var node = editor.selection; + 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 { + node_data.className = "hidden"; + } + var particles = new THREE.Points(geometry, materials.qubit); var object = new THREE.Object3D(); object.name = "graphstate"; @@ -54,5 +65,6 @@ graph.update = function(newState) { object.add(edges); gui.scene.add(object); gui.render(); + }; diff --git a/bin/abpserver b/bin/abpserver index a78a6eb..15ed0f7 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -25,11 +25,14 @@ def process_edit(edit, server): print local_state.node.keys() - if action == "create": - print type(edit["name"]) - local_state.add_qubit(edit["name"], position=edit["position"], vop=0) - if action == "cz": - local_state.act_cz(edit["start"], edit["end"]) + try: + if action == "create": + print type(edit["name"]) + local_state.add_qubit(edit["name"], position=edit["position"], vop=0) + if action == "cz": + local_state.act_cz(edit["start"], edit["end"]) + except Exception as e: + print e server.send_message_to_all(json.dumps(local_state.to_json())) From 37dd9265ce95dff7b08402e7a4769b6471540224 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sat, 5 Nov 2016 16:34:36 +0000 Subject: [PATCH 09/20] Can now sketchily delete nodes. Needs work. --- abp/graphstate.py | 10 ++++++++++ abp/static/scripts/editor.js | 4 ++-- bin/abpserver | 28 +++++++++++++--------------- tests/test_graphstate.py | 7 +++++++ 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/abp/graphstate.py b/abp/graphstate.py index a62c888..b8f4fde 100644 --- a/abp/graphstate.py +++ b/abp/graphstate.py @@ -47,6 +47,16 @@ class GraphState(object): 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. diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index f5bc9e7..6d0ca91 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -77,7 +77,7 @@ 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(); }; @@ -134,7 +134,7 @@ editor.findNodeOnRay = function(ray) { editor.deleteNode = function() { if (editor.selection === undefined){ return; } - abj.del_node(editor.selection); + websocket.edit({action:"delete", node:editor.selection}); graph.update(); gui.serverMessage("Deleted node " + editor.selection + "."); editor.selection = undefined; diff --git a/bin/abpserver b/bin/abpserver index 15ed0f7..25786d5 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -18,32 +18,28 @@ from pkg_resources import resource_filename clients = [] local_state = abp.GraphState() -def process_edit(edit, server): +def process_edit(edit, client, server): action = edit["action"] print edit - print local_state.node.keys() - - try: - if action == "create": - print type(edit["name"]) - local_state.add_qubit(edit["name"], position=edit["position"], vop=0) - if action == "cz": - local_state.act_cz(edit["start"], edit["end"]) - except Exception as e: - print e - - server.send_message_to_all(json.dumps(local_state.to_json())) - + if action == "create": + local_state.add_qubit(edit["name"], position=edit["position"], vop=0) + if action == "cz": + local_state.act_cz(edit["start"], edit["end"]) + if action == "hadamard": + local_state.act_cz(edit["start"], edit["end"]) + if action == "delete": + local_state._del_node(edit["node"]) + server.send_message(client, json.dumps(local_state.to_json())) def new_message(client, server, message): if message.startswith("edit:"): print message[5:] edit = json.loads(message[5:]) print "Received update from javascript." - process_edit(edit, server) + process_edit(edit, client, server) else: print "Received update from python {}.".format(client["id"]) print message @@ -54,6 +50,8 @@ def new_message(client, server, 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/tests/test_graphstate.py b/tests/test_graphstate.py index 7c09f05..5670507 100644 --- a/tests/test_graphstate.py +++ b/tests/test_graphstate.py @@ -131,3 +131,10 @@ def test_from_nx(): psi = GraphState(nx.Graph(((0, 1),))) +def test_del_node(): + """ Test deleting nodes """ + g = GraphState(10) + g.act_circuit(mock.random_stabilizer_circuit()) + g._del_node(0) + assert g.order() == 9 + From 209209c71d295de1a07b7cc2e5c1c1adc0ed5bde Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sat, 5 Nov 2016 16:50:50 +0000 Subject: [PATCH 10/20] Increased robustness. Some DRY crimes. --- abp/static/scripts/editor.js | 11 +++++++++-- abp/static/scripts/graph.js | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index 6d0ca91..0605dbe 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -34,7 +34,8 @@ editor.onFreeMove = function() { editor.focus = function(node) { gui.hideNodeMessage(); editor.selection = node; - gui.serverMessage("Selected node " + node + "."); + + //gui.serverMessage("Selected node " + node + "."); }; editor.addQubitAtPoint = function(point) { @@ -52,6 +53,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) { @@ -67,8 +74,8 @@ editor.onShiftClick = function() { if (found === editor.selection){ return; } //abj.act_cz(found, editor.selection); websocket.edit({action:"cz", start:found, end:editor.selection}); - editor.focus(found); gui.serverMessage("Acted CZ between " + found + " & " + editor.selection + "."); + editor.focus(found); graph.update(); }; diff --git a/abp/static/scripts/graph.js b/abp/static/scripts/graph.js index 1f09aaa..b507ff5 100644 --- a/abp/static/scripts/graph.js +++ b/abp/static/scripts/graph.js @@ -48,6 +48,7 @@ graph.update = function(newState) { } if (editor.selection) { + console.log(editor.selection); var node = editor.selection; editor.grid.position.copy(abj.node[node].position); gui.controls.target.copy(abj.node[node].position); From bdf7e456068cf8daa014d6e2f71b4b7d92ed8848 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sat, 5 Nov 2016 17:10:23 +0000 Subject: [PATCH 11/20] Now we can do the complete set of operations. --- abp/static/index.html | 18 ++++++++--------- abp/static/main.css | 3 +++ abp/static/scripts/editor.js | 38 +++++++++++++++++++++++++++++++----- bin/abpserver | 16 +++++++++++---- 4 files changed, 56 insertions(+), 19 deletions(-) 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/editor.js b/abp/static/scripts/editor.js index 0605dbe..b22c00d 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -76,7 +76,6 @@ editor.onShiftClick = function() { websocket.edit({action:"cz", start:found, end:editor.selection}); gui.serverMessage("Acted CZ between " + found + " & " + editor.selection + "."); editor.focus(found); - graph.update(); }; editor.onCtrlClick = function() { @@ -86,7 +85,6 @@ editor.onCtrlClick = function() { editor.focus(found); websocket.edit({action:"hadamard", node:found}); gui.serverMessage("Acted H on node " + found + "."); - graph.update(); }; @@ -138,19 +136,49 @@ editor.findNodeOnRay = function(ray) { return undefined; }; - editor.deleteNode = function() { if (editor.selection === undefined){ return; } websocket.edit({action:"delete", node:editor.selection}); - graph.update(); 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/bin/abpserver b/bin/abpserver index 25786d5..f50419d 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -25,12 +25,20 @@ def process_edit(edit, client, server): if action == "create": local_state.add_qubit(edit["name"], position=edit["position"], vop=0) - if action == "cz": + elif action == "cz": local_state.act_cz(edit["start"], edit["end"]) - if action == "hadamard": - local_state.act_cz(edit["start"], edit["end"]) - if action == "delete": + 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())) From d6aefcdee82c80132caef62c45d41a86a5b7d526 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sat, 5 Nov 2016 17:19:21 +0000 Subject: [PATCH 12/20] More robust reconnect on server restart. --- abp/static/scripts/websocket.js | 6 +++++- bin/abpserver | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/abp/static/scripts/websocket.js b/abp/static/scripts/websocket.js index 91c8825..919b9d2 100644 --- a/abp/static/scripts/websocket.js +++ b/abp/static/scripts/websocket.js @@ -1,7 +1,11 @@ var websocket = {}; +websocket.update = undefined; websocket.connect = function(update) { websocket.ws = new WebSocket("ws://localhost:5000"); + if (update){ + websocket.update = update; + } websocket.ws.onopen = function(evt) { gui.serverMessage("Connected to server."); }; @@ -19,7 +23,7 @@ websocket.connect = function(update) { json.node[i].vop = 0; } } - update(json); + websocket.update(json); }; websocket.ws.onclose = function(evt) { diff --git a/bin/abpserver b/bin/abpserver index f50419d..585cd25 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -14,6 +14,7 @@ import argparse import abp import json from pkg_resources import resource_filename +import time clients = [] local_state = abp.GraphState() From e5ad12cdb1257049fb72c15bc6e09a48f4dc0330 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 09:43:59 +0000 Subject: [PATCH 13/20] Reduced node-already-exists to a warning --- abp/graphstate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/abp/graphstate.py b/abp/graphstate.py index b8f4fde..417d61f 100644 --- a/abp/graphstate.py +++ b/abp/graphstate.py @@ -71,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] = {} From f1a7498f9c1f177058e127a33365ff44710ca918 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 09:49:19 +0000 Subject: [PATCH 14/20] Test in JS for nodes which already exists. --- abp/static/scripts/editor.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/abp/static/scripts/editor.js b/abp/static/scripts/editor.js index b22c00d..3e240f5 100644 --- a/abp/static/scripts/editor.js +++ b/abp/static/scripts/editor.js @@ -44,6 +44,10 @@ editor.addQubitAtPoint = function(point) { } point.round(); 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; + } websocket.edit({action:"create", name:new_node, position: point}); editor.focus(new_node); gui.serverMessage("Created node " + new_node +"."); From 3edf1643e4d1de00bc11cb82691e5b7cb74acf2d Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 09:54:24 +0000 Subject: [PATCH 15/20] Remove tests.js --- abp/static/scripts/tests.js | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 abp/static/scripts/tests.js 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)); -}); From 6c42ca2b3c5cc74ce51e93ac78eab533ad34602c Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 09:55:28 +0000 Subject: [PATCH 16/20] Remove useless functions from anders_briegel.js --- abp/static/scripts/anders_briegel.js | 89 ---------------------------- 1 file changed, 89 deletions(-) diff --git a/abp/static/scripts/anders_briegel.js b/abp/static/scripts/anders_briegel.js index c1fe54b..c504182 100644 --- a/abp/static/scripts/anders_briegel.js +++ b/abp/static/scripts/anders_briegel.js @@ -41,101 +41,12 @@ 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.edgelist = function() { - var seen = {}; - var output = []; - for (var i in abj.adj) { - for (var j in abj.adj[i]) { - if (!Object.prototype.hasOwnProperty.call(seen, j)) { - output.push([i, j]); - } - } - seen[i] = true; - } - 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; From fed7813eb3fe14f41ea9e33a8b341a77a6d1075f Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 09:59:07 +0000 Subject: [PATCH 17/20] We did need one of those functions. --- abp/static/scripts/anders_briegel.js | 14 ++++++++++++++ bin/abpserver | 5 ++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/abp/static/scripts/anders_briegel.js b/abp/static/scripts/anders_briegel.js index c504182..e514ca9 100644 --- a/abp/static/scripts/anders_briegel.js +++ b/abp/static/scripts/anders_briegel.js @@ -56,4 +56,18 @@ abj.order = function(){ return Object.keys(abj.node).length; }; +abj.edgelist = function() { + var seen = {}; + var output = []; + for (var i in abj.adj) { + for (var j in abj.adj[i]) { + if (!Object.prototype.hasOwnProperty.call(seen, j)) { + output.push([i, j]); + } + } + seen[i] = true; + } + return output; +}; + diff --git a/bin/abpserver b/bin/abpserver index 585cd25..71ebca5 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -14,6 +14,7 @@ import argparse import abp import json from pkg_resources import resource_filename +from pprint import pprint import time clients = [] @@ -22,7 +23,7 @@ local_state = abp.GraphState() def process_edit(edit, client, server): action = edit["action"] - print edit + pprint(edit) if action == "create": local_state.add_qubit(edit["name"], position=edit["position"], vop=0) @@ -45,9 +46,7 @@ def process_edit(edit, client, server): def new_message(client, server, message): if message.startswith("edit:"): - print message[5:] edit = json.loads(message[5:]) - print "Received update from javascript." process_edit(edit, client, server) else: print "Received update from python {}.".format(client["id"]) From f94d3eabd311c928f9c44cb2ff9f963f3f028848 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 10:07:50 +0000 Subject: [PATCH 18/20] Multiple clients viewing / editing same state. --- bin/abpserver | 3 ++- examples/visualization/lattice_2d.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/abpserver b/bin/abpserver index 71ebca5..63f7030 100755 --- a/bin/abpserver +++ b/bin/abpserver @@ -42,7 +42,8 @@ def process_edit(edit, client, server): else: pass - server.send_message(client, json.dumps(local_state.to_json())) + #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): if message.startswith("edit:"): diff --git a/examples/visualization/lattice_2d.py b/examples/visualization/lattice_2d.py index 677fc9a..2d42016 100644 --- a/examples/visualization/lattice_2d.py +++ b/examples/visualization/lattice_2d.py @@ -34,7 +34,7 @@ nodes, edges = lattice(square_unit_cell, (10, 10)) psi = GraphState() for node in nodes: - psi.add_node(str(node), position=xyz(node[0], node[1])) + psi.add_qubit(str(node), position=xyz(node[0], node[1])) psi.act_hadamard(str(node)) psi.update(0.1) From 6b3cb8bc378bfe299c5c1e02a4c1b735797b7993 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 10:27:37 +0000 Subject: [PATCH 19/20] Re-enable curved lines. --- abp/static/scripts/materials.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 }; From 6a8b1a9ceb86a36c9b31cc2645f5b2b89738dea7 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Sun, 6 Nov 2016 10:34:51 +0000 Subject: [PATCH 20/20] Fix examples, improve robustness. --- abp/static/scripts/graph.js | 15 ++++++++++----- examples/visualization/lattice_2d.py | 1 + examples/visualization/lattice_3d.py | 3 ++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/abp/static/scripts/graph.js b/abp/static/scripts/graph.js index b507ff5..9cf6a00 100644 --- a/abp/static/scripts/graph.js +++ b/abp/static/scripts/graph.js @@ -50,11 +50,16 @@ graph.update = function(newState) { if (editor.selection) { console.log(editor.selection); var node = editor.selection; - 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; + 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"; } diff --git a/examples/visualization/lattice_2d.py b/examples/visualization/lattice_2d.py index 2d42016..cd4450c 100644 --- a/examples/visualization/lattice_2d.py +++ b/examples/visualization/lattice_2d.py @@ -40,4 +40,5 @@ for node in nodes: for edge in edges: psi.act_cz(str(edge[0]), str(edge[1])) +psi.update(0.1) diff --git a/examples/visualization/lattice_3d.py b/examples/visualization/lattice_3d.py index e4a229b..a4db00e 100644 --- a/examples/visualization/lattice_3d.py +++ b/examples/visualization/lattice_3d.py @@ -45,9 +45,10 @@ nodes, edges = lattice(threedee_unit_cell, (3, 3, 3)) psi = GraphState() for node in nodes: - psi.add_node(str(node), position=xyz(*node)) + psi.add_qubit(str(node), position=xyz(*node)) psi.act_hadamard(str(node)) for edge in edges: psi.act_cz(str(edge[0]), str(edge[1])) +psi.update()