| @@ -1,12 +1,12 @@ | |||
| var abj = {}; | |||
| abj.vops = {}; | |||
| abj.ngbh = {}; | |||
| abj.meta = {}; | |||
| abj.node = {}; | |||
| abj.adj = {}; | |||
| abj.add_node = function(node, m) { | |||
| abj.ngbh[node] = {}; | |||
| abj.vops[node] = tables.clifford.hadamard; | |||
| abj.meta[node] = m ? m : {}; | |||
| abj.add_node = function(node, meta) { | |||
| abj.adj[node] = {}; | |||
| abj.node[node] = {}; | |||
| abj.node[node].vop = tables.clifford.hadamard; | |||
| Object.assign(abj.node[node], meta); | |||
| }; | |||
| abj.add_nodes = function(nodes) { | |||
| @@ -14,8 +14,8 @@ abj.add_nodes = function(nodes) { | |||
| }; | |||
| abj.add_edge = function(a, b) { | |||
| abj.ngbh[a][b] = true; | |||
| abj.ngbh[b][a] = true; | |||
| abj.adj[a][b] = {}; | |||
| abj.adj[b][a] = {}; | |||
| }; | |||
| abj.add_edges = function(edges) { | |||
| @@ -25,12 +25,12 @@ abj.add_edges = function(edges) { | |||
| }; | |||
| abj.del_edge = function(a, b) { | |||
| delete abj.ngbh[a][b]; | |||
| delete abj.ngbh[b][a]; | |||
| delete abj.adj[a][b]; | |||
| delete abj.adj[b][a]; | |||
| }; | |||
| abj.has_edge = function(a, b) { | |||
| return Object.prototype.hasOwnProperty.call(abj.ngbh[a], b); | |||
| return Object.prototype.hasOwnProperty.call(abj.adj[a], b); | |||
| }; | |||
| abj.toggle_edge = function(a, b) { | |||
| @@ -42,7 +42,7 @@ abj.toggle_edge = function(a, b) { | |||
| }; | |||
| abj.get_swap = function(node, avoid) { | |||
| for (var i in abj.ngbh[node]) { | |||
| for (var i in abj.adj[node]) { | |||
| if (i != avoid) { | |||
| return i; | |||
| } | |||
| @@ -52,7 +52,7 @@ abj.get_swap = function(node, avoid) { | |||
| abj.remove_vop = function(node, avoid) { | |||
| var swap_qubit = get_swap(node, avoid); | |||
| var decomposition = decompositions[abj.vops[node]]; | |||
| var decomposition = decompositions[abj.node[node].vop]; | |||
| for (var i = decomposition.length - 1; i >= 0; --i) { | |||
| var v = decomposition[i]; | |||
| local_complementation(v == "x" ? a : swap_qubit); | |||
| @@ -60,19 +60,19 @@ abj.remove_vop = function(node, avoid) { | |||
| }; | |||
| abj.local_complementation = function(node) { | |||
| var keys = Object.keys(abj.ngbh[node]); | |||
| var keys = Object.keys(abj.adj[node]); | |||
| for (var i = 0; i < keys.length; ++i) { | |||
| for (var j = i + 1; j < keys.length; ++j) { | |||
| toggle_edge(keys[i], keys[j]); | |||
| } | |||
| abj.vops[i] = tables.times_table[abj.vops[keys[i]]][sqz_h]; | |||
| abj.node[i].vop = tables.times_table[abj.node[keys[i]].vop][sqz_h]; | |||
| } | |||
| abj.vops[node] = tables.times_table[abj.vops[node]][msqx_h]; | |||
| abj.node[node].vop = tables.times_table[abj.node[node].vop][msqx_h]; | |||
| }; | |||
| abj.act_local_rotation = function(node, operation) { | |||
| var rotation = tables.clifford[operation]; | |||
| abj.vops[node] = tables.times_table[rotation][abj.vops[node]]; | |||
| abj.node[node].vop = tables.times_table[rotation][abj.node[node].vop]; | |||
| }; | |||
| abj.act_hadamard = function(node) { | |||
| @@ -84,19 +84,19 @@ abj.is_sole_member = function(node, group) { | |||
| }; | |||
| abj.act_cz = function(a, b) { | |||
| if (is_sole_member(abj.ngbh[a], b)) { | |||
| if (is_sole_member(abj.adj[a], b)) { | |||
| remove_vop(a, b); | |||
| } | |||
| if (is_sole_member(abj.ngbh[b], a)) { | |||
| if (is_sole_member(abj.adj[b], a)) { | |||
| remove_vop(b, a); | |||
| } | |||
| if (is_sole_member(abj.ngbh[a], b)) { | |||
| if (is_sole_member(abj.adj[a], b)) { | |||
| remove_vop(a, b); | |||
| } | |||
| var edge = has_edge(a, b); | |||
| var new_state = tables.cz_table[edge ? 1 : 0][abj.vops[a]][abj.vops[b]]; | |||
| abj.vops[a] = new_state[1]; | |||
| abj.vops[b] = new_state[2]; | |||
| 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) { | |||
| toggle_edge(a, b); | |||
| } | |||
| @@ -105,8 +105,8 @@ abj.act_cz = function(a, b) { | |||
| abj.edgelist = function() { | |||
| var seen = {}; | |||
| var output = []; | |||
| for (var i in abj.ngbh) { | |||
| for (var j in abj.ngbh[i]) { | |||
| for (var i in abj.adj) { | |||
| for (var j in abj.adj[i]) { | |||
| if (!Object.prototype.hasOwnProperty.call(seen, j)) { | |||
| output.push([i, j]); | |||
| } | |||
| @@ -117,17 +117,16 @@ abj.edgelist = function() { | |||
| }; | |||
| abj.log_graph_state = function() { | |||
| console.log(JSON.stringify(abj.vops)); | |||
| console.log(JSON.stringify(abj.ngbh)); | |||
| console.log(JSON.stringify(abj.node)); | |||
| console.log(JSON.stringify(abj.adj)); | |||
| }; | |||
| abj.update = function(newState) { | |||
| abj.vops = newState.vops; | |||
| abj.ngbh = newState.ngbh; | |||
| abj.meta = newState.meta; | |||
| abj.node = newState.node; | |||
| abj.adj = newState.adj; | |||
| }; | |||
| abj.order = function(){ | |||
| return Object.keys(abj.vops).length; | |||
| return Object.keys(abj.node).length; | |||
| }; | |||
| @@ -1,26 +1,22 @@ | |||
| var editor = {}; | |||
| var pi2 = Math.PI / 2; | |||
| editor.nearest = undefined; | |||
| editor.selection = undefined; | |||
| editor.orientations = [ | |||
| new THREE.Matrix4(), | |||
| new THREE.Matrix4(), | |||
| new THREE.Matrix4() | |||
| editor.planes = [ | |||
| new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), | |||
| new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), | |||
| new THREE.Plane(new THREE.Vector3(1, 0, 0), 0) | |||
| ]; | |||
| editor.orientation = 0; | |||
| editor.orientations[1].makeRotationX(pi2); | |||
| editor.orientations[2].makeRotationX(pi2); | |||
| editor.orientations[2].makeRotationZ(pi2); | |||
| editor.plane = editor.planes[editor.orientation]; | |||
| editor.onFreeMove = function() { | |||
| var n = editor.nearestNode(mouse.ray); | |||
| if (editor.nearest !== n) { | |||
| editor.nearest = n; | |||
| if (n) { | |||
| gui.nodeMessage("Node " + n + " (VOP:" + abj.vops[n] + ")" + | |||
| var found = editor.findNodeOnRay(mouse.ray); | |||
| if (editor.selection !== found) { | |||
| editor.selection = found; | |||
| if (found) { | |||
| gui.nodeMessage("Node " + found + " (VOP:" + abj.node[found].vop + ")" + | |||
| "<br/>" + "Click to edit neighbourhood"); | |||
| } else { | |||
| gui.hideNodeMessage(); | |||
| @@ -28,29 +24,37 @@ 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 + ""); | |||
| }; | |||
| editor.addQubitAtPoint = function(point) { | |||
| if (point === null) { | |||
| return; | |||
| } | |||
| point.round(); | |||
| abj.add_node(abj.order(), { | |||
| position: point | |||
| }); | |||
| editor.grid.position.copy(point); | |||
| gui.controls.target.copy(point); | |||
| graph.update(); | |||
| gui.serverMessage("Created node at " + JSON.stringify(point)); | |||
| }; | |||
| editor.onClick = function() { | |||
| var n = editor.nearestNode(mouse.ray); | |||
| if (n) { | |||
| var p = abj.meta[n].position; | |||
| editor.grid.position.set(p.x, p.y, p.z); | |||
| gui.controls.target.set(p.x, p.y, p.z); | |||
| gui.hideNodeMessage(); | |||
| editor.nearest = undefined; | |||
| gui.serverMessage("Selected node " + n + ""); | |||
| var found = editor.findNodeOnRay(mouse.ray); | |||
| if (found) { | |||
| editor.focus(found); | |||
| } else { | |||
| //TODO: ghastly | |||
| var intersection = mouse.ray.intersectPlane(editor.plane); | |||
| intersection.x = Math.round(intersection.x, 0); | |||
| intersection.y = Math.round(intersection.y, 0); | |||
| intersection.z = Math.round(intersection.z, 0); | |||
| var newNode = abj.order(); | |||
| abj.add_node(newNode, { | |||
| position: intersection | |||
| }); | |||
| editor.grid.position.set(intersection.x, intersection.y, intersection.z); | |||
| gui.controls.target.set(intersection.x, intersection.y, intersection.z); | |||
| graph.update(); | |||
| gui.serverMessage("Created node " + newNode + " at "); | |||
| if (intersection !== null) { | |||
| editor.addQubitAtPoint(intersection); | |||
| } | |||
| } | |||
| }; | |||
| @@ -64,7 +68,7 @@ editor.prepare = function() { | |||
| editor.onKey = function(evt) { | |||
| if (evt.keyCode == 32) { | |||
| editor.grid.rotation.x += Math.PI / 2; | |||
| editor.orientation = (editor.orientation+1) % 3; | |||
| editor.orientation = (editor.orientation + 1) % 3; | |||
| console.log(editor.orientation); | |||
| var m = editor.orientations[editor.orientation]; | |||
| editor.plane.applyMatrix4(m); | |||
| @@ -79,20 +83,17 @@ editor.makeGrid = function() { | |||
| editor.grid = new THREE.GridHelper(10, 1); | |||
| editor.grid.rotation.x = Math.PI / 2; | |||
| editor.grid.setColors(0xbbbbbb, 0xeeeeee); | |||
| editor.grid.matrixAutoUpdate = false; | |||
| editor.plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); | |||
| editor.grid.matrixAutoUpdate = true; | |||
| gui.scene.add(editor.grid); | |||
| }; | |||
| editor.update = function(){ | |||
| }; | |||
| editor.update = function() {}; | |||
| // Gets a reference to the node nearest to the mouse cursor | |||
| // TODO: get rid of meta{} | |||
| editor.nearestNode = function(ray) { | |||
| for (var j in abj.meta) { | |||
| if (ray.distanceSqToPoint(abj.meta[j].position) < 0.03) { | |||
| return j; | |||
| editor.findNodeOnRay = function(ray) { | |||
| for (var n in abj.node) { | |||
| if (ray.distanceSqToPoint(abj.node[n].position) < 0.03) { | |||
| return n; | |||
| } | |||
| } | |||
| return undefined; | |||
| @@ -14,21 +14,19 @@ graph.update = function(newState) { | |||
| var geometry = new THREE.Geometry(); | |||
| geometry.colors = []; | |||
| for (var i in abj.vops) { | |||
| var vop = abj.vops[i]; | |||
| var pos = abj.meta[i].position; | |||
| var vertex = new THREE.Vector3(pos.x, pos.y, pos.z); | |||
| geometry.vertices.push(vertex); | |||
| geometry.colors.push(new THREE.Color(graph.colors[abj.vops[i] % graph.colors.length])); | |||
| for (var i in abj.node) { | |||
| var color = graph.colors[abj.node[i].vop % graph.colors.length]; | |||
| geometry.vertices.push(abj.node[i].position); | |||
| geometry.colors.push(new THREE.Color(color)); | |||
| } | |||
| var edges = new THREE.Object3D(); | |||
| var my_edges = abj.edgelist(); | |||
| for (i = 0; i < my_edges.length; ++i) { | |||
| var edge = my_edges[i]; | |||
| var start = abj.meta[edge[0]].position; | |||
| var start = abj.node[edge[0]].position; | |||
| var startpos = new THREE.Vector3(start.x, start.y, start.z); | |||
| var end = abj.meta[edge[1]].position; | |||
| var end = abj.node[edge[1]].position; | |||
| var endpos = new THREE.Vector3(end.x, end.y, end.z); | |||
| var newEdge = materials.makeCurve(startpos, endpos); | |||
| edges.add(newEdge); | |||
| @@ -76,15 +76,3 @@ gui.loop = function() { | |||
| requestAnimationFrame(gui.loop); | |||
| }; | |||
| // Try to add a qubit at the current mouse position | |||
| gui.addQubitAtMouse = function(event) { | |||
| this.raycaster.setFromCamera(mouse, camera); | |||
| var intersection = this.raycaster.ray.intersectPlane(this.plane); | |||
| intersection.x = Math.round(intersection.x); | |||
| intersection.y = Math.round(intersection.y); | |||
| abj.add_node(Object.keys(vops).length, { | |||
| "position": intersection | |||
| }); | |||
| graph.update(); | |||
| }; | |||
| @@ -12,9 +12,9 @@ websocket.connect = function(update) { | |||
| ws.onmessage = function(evt) { | |||
| json = JSON.parse(evt.data); | |||
| for (var i in json.meta) { | |||
| var pos = json.meta[i].position; | |||
| json.meta[i].position = new THREE.Vector3(pos.x, pos.y, pos.z); | |||
| for (var i in json.node) { | |||
| var pos = json.node[i].position; | |||
| json.node[i].position = new THREE.Vector3(pos.x, pos.y, pos.z); | |||
| } | |||
| update(json); | |||
| }; | |||