This merge updates abpserver to support a full set of operations including creation / deletion, gates, local complementation, and measurements through the web interface. So now you can click on qubits and measure them in X or whatever. I've tested it but I bet there are bugs -- please raise an issue if you find one. Conflicts: examples/visualization/grid_2d.pymaster
@@ -43,7 +43,7 @@ class GraphState(graphstate.GraphState, nx.Graph): | |||||
time.sleep(delay) | time.sleep(delay) | ||||
except websocket._exceptions.WebSocketTimeoutException: | except websocket._exceptions.WebSocketTimeoutException: | ||||
print "Timed out ... you might be pushing a bit hard" | print "Timed out ... you might be pushing a bit hard" | ||||
sys.exit(0) | |||||
time.sleep(delay) | |||||
#self.ws.close() | #self.ws.close() | ||||
#self.connect_to_server() | #self.connect_to_server() | ||||
@@ -42,6 +42,21 @@ class GraphState(object): | |||||
for n in range(data): | for n in range(data): | ||||
self._add_node(n, vop=vop) | 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): | 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. | """ 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 | 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") | default = kwargs.get("default", "identity") | ||||
self.adj[node] = {} | self.adj[node] = {} | ||||
self.node[node] = {} | self.node[node] = {} | ||||
@@ -405,9 +423,6 @@ class GraphState(object): | |||||
>>> with open("graph.json") as f: | >>> with open("graph.json") as f: | ||||
json.dump(graph.to_json(True), f) | json.dump(graph.to_json(True), f) | ||||
.. todo:: | |||||
Implement ``from_json()``! | |||||
""" | """ | ||||
if stringify: | if stringify: | ||||
node = {str(key): value for key, value in self.node.items()} | node = {str(key): value for key, value in self.node.items()} | ||||
@@ -417,6 +432,13 @@ class GraphState(object): | |||||
else: | else: | ||||
return {"node": self.node, "adj": self.adj} | 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): | def to_state_vector(self): | ||||
""" Get the full state vector corresponding to this stabilizer state. Useful for debugging, interface with other simulators. | """ 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! | This method becomes very slow for more than about ten qubits! | ||||
@@ -29,16 +29,14 @@ | |||||
<div id=node_name></div> | <div id=node_name></div> | ||||
<ul> | <ul> | ||||
<li id=node_vop></li> | <li id=node_vop></li> | ||||
<!--<li><a href="#">Measure in X</a></li>--> | |||||
<!--<li><a href="#">Measure in Y</a></li>--> | |||||
<!--<li><a href="#">Measure in Z</a></li>--> | |||||
<!--<li><a href="#">Act Hadamard</a></li>--> | |||||
<!--<li><a href="#">Act Phase</a></li>--> | |||||
<!--<li><a href="#" onclick="editor.localComplementation()">Invert neighbourhood</a></li>--> | |||||
<!--<li>--> | |||||
<!--<a href="#">IA</a>--> | |||||
<!--<a href="#">IB</a>--> | |||||
<!--</li>--> | |||||
<li>Measure in | |||||
<a href="#" onclick="editor.measureX()">X</a> / | |||||
<a href="#" onclick="editor.measureY()">Y</a> / | |||||
<a href="#" onclick="editor.measureZ()">Z</a></li> | |||||
<li>Act | |||||
<a href="#" onclick="editor.hadamard()">Hadamard</a> / | |||||
<a href="#" onclick="editor.phase()">Phase</a></li> | |||||
<li><a href="#" onclick="editor.localComplementation()">Invert neighbourhood</a></li> | |||||
<li><a href="#" onclick="editor.deleteNode()">Delete</a></li> | <li><a href="#" onclick="editor.deleteNode()">Delete</a></li> | ||||
</ul> | </ul> | ||||
</div> | </div> | ||||
@@ -26,6 +26,9 @@ html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-fam | |||||
font-size: 9pt; | font-size: 9pt; | ||||
} | } | ||||
#node_name { | |||||
font-size: 12pt; | |||||
} | |||||
#node_data { | #node_data { | ||||
background-color: black; | background-color: black; | ||||
@@ -41,80 +41,19 @@ abj.has_edge = function(a, b) { | |||||
return Object.prototype.hasOwnProperty.call(abj.adj[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) { | abj.is_sole_member = function(group, node) { | ||||
// TODO: this is slow as heck | // TODO: this is slow as heck | ||||
var keys = Object.keys(group); | var keys = Object.keys(group); | ||||
return keys.length == 1 && keys[0] == node; | 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() { | abj.edgelist = function() { | ||||
@@ -131,18 +70,4 @@ abj.edgelist = function() { | |||||
return output; | 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; | |||||
}; | |||||
@@ -32,14 +32,10 @@ editor.onFreeMove = function() { | |||||
}; | }; | ||||
editor.focus = function(node) { | editor.focus = function(node) { | ||||
editor.grid.position.copy(abj.node[node].position); | |||||
gui.controls.target.copy(abj.node[node].position); | |||||
gui.hideNodeMessage(); | gui.hideNodeMessage(); | ||||
editor.selection = node; | 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) { | editor.addQubitAtPoint = function(point) { | ||||
@@ -47,19 +43,13 @@ editor.addQubitAtPoint = function(point) { | |||||
return; | return; | ||||
} | } | ||||
point.round(); | 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); | editor.focus(new_node); | ||||
graph.update(); | |||||
gui.serverMessage("Created node " + new_node +"."); | gui.serverMessage("Created node " + new_node +"."); | ||||
}; | }; | ||||
@@ -67,6 +57,12 @@ editor.onClick = function() { | |||||
var found = editor.findNodeOnRay(mouse.ray); | var found = editor.findNodeOnRay(mouse.ray); | ||||
if (found) { | if (found) { | ||||
editor.focus(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 { | } else { | ||||
var intersection = mouse.ray.intersectPlane(editor.plane); | var intersection = mouse.ray.intersectPlane(editor.plane); | ||||
if (intersection !== null) { | if (intersection !== null) { | ||||
@@ -80,10 +76,10 @@ editor.onShiftClick = function() { | |||||
if (found === undefined){ return; } | if (found === undefined){ return; } | ||||
if (editor.selection === undefined){ return; } | if (editor.selection === undefined){ return; } | ||||
if (found === editor.selection){ 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 + "."); | gui.serverMessage("Acted CZ between " + found + " & " + editor.selection + "."); | ||||
graph.update(); | |||||
editor.focus(found); | |||||
}; | }; | ||||
editor.onCtrlClick = function() { | editor.onCtrlClick = function() { | ||||
@@ -91,9 +87,8 @@ editor.onCtrlClick = function() { | |||||
if (found === undefined){ return; } | if (found === undefined){ return; } | ||||
if (editor.selection === undefined){ return; } | if (editor.selection === undefined){ return; } | ||||
editor.focus(found); | editor.focus(found); | ||||
abj.act_hadamard(found); | |||||
websocket.edit({action:"hadamard", node:found}); | |||||
gui.serverMessage("Acted H on node " + found + "."); | gui.serverMessage("Acted H on node " + found + "."); | ||||
graph.update(); | |||||
}; | }; | ||||
@@ -147,16 +142,47 @@ editor.findNodeOnRay = function(ray) { | |||||
editor.deleteNode = function() { | editor.deleteNode = function() { | ||||
if (editor.selection === undefined){ return; } | 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 + "."); | gui.serverMessage("Deleted node " + editor.selection + "."); | ||||
editor.selection = undefined; | editor.selection = undefined; | ||||
node_data.className = "hidden"; | 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() { | editor.localComplementation = function() { | ||||
if (editor.selection === undefined){ return; } | if (editor.selection === undefined){ return; } | ||||
websocket.edit({action:"localcomplementation", node:editor.selection}); | |||||
abj.local_complementation(editor.selection); | abj.local_complementation(editor.selection); | ||||
graph.update(); | |||||
gui.serverMessage("Inverted neighbourhood of " + editor.selection + "."); | gui.serverMessage("Inverted neighbourhood of " + editor.selection + "."); | ||||
}; | }; |
@@ -47,6 +47,23 @@ graph.update = function(newState) { | |||||
edges.add(newEdge); | 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 particles = new THREE.Points(geometry, materials.qubit); | ||||
var object = new THREE.Object3D(); | var object = new THREE.Object3D(); | ||||
object.name = "graphstate"; | object.name = "graphstate"; | ||||
@@ -54,5 +71,6 @@ graph.update = function(newState) { | |||||
object.add(edges); | object.add(edges); | ||||
gui.scene.add(object); | gui.scene.add(object); | ||||
gui.render(); | gui.render(); | ||||
}; | }; | ||||
@@ -1,7 +1,7 @@ | |||||
var materials = {}; | var materials = {}; | ||||
var curveProperties = { | var curveProperties = { | ||||
splineDensity: 1, | |||||
splineDensity: 10, | |||||
curvature: 20 | curvature: 20 | ||||
}; | }; | ||||
@@ -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)); | |||||
}); |
@@ -1,16 +1,20 @@ | |||||
var websocket = {}; | var websocket = {}; | ||||
websocket.update = undefined; | |||||
websocket.connect = function(update) { | 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."); | gui.serverMessage("Connected to server."); | ||||
}; | }; | ||||
ws.onerror = function(err) { | |||||
websocket.ws.onerror = function(err) { | |||||
gui.serverMessage("Could not connect to server."); | gui.serverMessage("Could not connect to server."); | ||||
}; | }; | ||||
ws.onmessage = function(evt) { | |||||
websocket.ws.onmessage = function(evt) { | |||||
json = JSON.parse(evt.data); | json = JSON.parse(evt.data); | ||||
for (var i in json.node) { | for (var i in json.node) { | ||||
var pos = json.node[i].position; | var pos = json.node[i].position; | ||||
@@ -19,10 +23,14 @@ websocket.connect = function(update) { | |||||
json.node[i].vop = 0; | 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. <a href='#' onclick='javascript:websocket.connect()'>Reconnect</a>.", true); | gui.serverMessage("No connection to server. <a href='#' onclick='javascript:websocket.connect()'>Reconnect</a>.", true); | ||||
}; | }; | ||||
}; | }; | ||||
websocket.edit = function (data) { | |||||
websocket.ws.send("edit:"+JSON.stringify(data)); | |||||
}; |
@@ -12,17 +12,55 @@ import os, sys, threading | |||||
import webbrowser | import webbrowser | ||||
import argparse | import argparse | ||||
import abp | import abp | ||||
import json | |||||
from pkg_resources import resource_filename | from pkg_resources import resource_filename | ||||
from pprint import pprint | |||||
import time | |||||
clients = [] | 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): | 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): | def new_client(client, server): | ||||
print "Client {} connected.".format(client["id"]) | print "Client {} connected.".format(client["id"]) | ||||
clients.append(client) | 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): | def client_left(client, server): | ||||
print "Client {} disconnected.".format(client["id"]) | print "Client {} disconnected.".format(client["id"]) | ||||
@@ -2,13 +2,22 @@ from abp.fancy import GraphState | |||||
from abp.util import xyz | from abp.util import xyz | ||||
import itertools | 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<width-1: psi.act_cz((x, y), (x+1, y)) | |||||
if y<height-1: psi.act_cz((x, y), (x, y+1)) | |||||
return psi | |||||
if __name__ == '__main__': | |||||
psi = grid_2d(5, 5) | |||||
psi.update() | |||||
@@ -34,10 +34,11 @@ nodes, edges = lattice(square_unit_cell, (10, 10)) | |||||
psi = GraphState() | psi = GraphState() | ||||
for node in nodes: | 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.act_hadamard(str(node)) | ||||
psi.update(0.1) | psi.update(0.1) | ||||
for edge in edges: | for edge in edges: | ||||
psi.act_cz(str(edge[0]), str(edge[1])) | psi.act_cz(str(edge[0]), str(edge[1])) | ||||
psi.update(0.1) | |||||
@@ -45,9 +45,10 @@ nodes, edges = lattice(threedee_unit_cell, (3, 3, 3)) | |||||
psi = GraphState() | psi = GraphState() | ||||
for node in nodes: | 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)) | psi.act_hadamard(str(node)) | ||||
for edge in edges: | for edge in edges: | ||||
psi.act_cz(str(edge[0]), str(edge[1])) | psi.act_cz(str(edge[0]), str(edge[1])) | ||||
psi.update() | |||||
@@ -131,3 +131,10 @@ def test_from_nx(): | |||||
psi = GraphState(nx.Graph(((0, 1),))) | 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 | |||||
@@ -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 | |||||