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