From 183e5010607fb166ab7852b572f230c842ebb38e Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Tue, 10 May 2016 19:29:37 +0100 Subject: [PATCH] Anders & Briegel's CZ table passes my tests But it is not symmetric. I wonder why. Can run with either for now. --- abp/SimpleExampleServer.py | 72 +++ abp/SimpleWebSocketServer.py | 694 +++++++++++++++++++++++ abp/clifford.py | 32 +- static/main.js | 4 +- static/poll.js | 97 ++-- tests/test_against_anders_and_briegel.py | 7 +- tests/test_clifford.py | 6 +- tests/test_cphase_against_anders.py | 50 ++ tests/test_cphase_table.py | 27 + 9 files changed, 917 insertions(+), 72 deletions(-) create mode 100644 abp/SimpleExampleServer.py create mode 100644 abp/SimpleWebSocketServer.py create mode 100644 tests/test_cphase_against_anders.py create mode 100644 tests/test_cphase_table.py diff --git a/abp/SimpleExampleServer.py b/abp/SimpleExampleServer.py new file mode 100644 index 0000000..51b53a9 --- /dev/null +++ b/abp/SimpleExampleServer.py @@ -0,0 +1,72 @@ +''' +The MIT License (MIT) +Copyright (c) 2013 Dave P. +''' + +import signal +import sys +import ssl +from SimpleWebSocketServer import WebSocket, SimpleWebSocketServer, SimpleSSLWebSocketServer +from optparse import OptionParser + +class SimpleEcho(WebSocket): + + def handleMessage(self): + print self.data + self.sendMessage(self.data) + + def handleConnected(self): + pass + + def handleClose(self): + pass + +clients = [] +class SimpleChat(WebSocket): + + def handleMessage(self): + for client in clients: + if client != self: + client.sendMessage(self.address[0] + u' - ' + self.data) + + def handleConnected(self): + print (self.address, 'connected') + for client in clients: + client.sendMessage(self.address[0] + u' - connected') + clients.append(self) + + def handleClose(self): + clients.remove(self) + print (self.address, 'closed') + for client in clients: + client.sendMessage(self.address[0] + u' - disconnected') + + +if __name__ == "__main__": + + parser = OptionParser(usage="usage: %prog [options]", version="%prog 1.0") + parser.add_option("--host", default='', type='string', action="store", dest="host", help="hostname (localhost)") + parser.add_option("--port", default=8000, type='int', action="store", dest="port", help="port (8000)") + parser.add_option("--example", default='echo', type='string', action="store", dest="example", help="echo, chat") + parser.add_option("--ssl", default=0, type='int', action="store", dest="ssl", help="ssl (1: on, 0: off (default))") + parser.add_option("--cert", default='./cert.pem', type='string', action="store", dest="cert", help="cert (./cert.pem)") + parser.add_option("--ver", default=ssl.PROTOCOL_TLSv1, type=int, action="store", dest="ver", help="ssl version") + + (options, args) = parser.parse_args() + + cls = SimpleEcho + if options.example == 'chat': + cls = SimpleChat + + if options.ssl == 1: + server = SimpleSSLWebSocketServer(options.host, options.port, cls, options.cert, options.cert, version=options.ver) + else: + server = SimpleWebSocketServer(options.host, options.port, cls) + + def close_sig_handler(signal, frame): + server.close() + sys.exit() + + signal.signal(signal.SIGINT, close_sig_handler) + + server.serveforever() diff --git a/abp/SimpleWebSocketServer.py b/abp/SimpleWebSocketServer.py new file mode 100644 index 0000000..c505e60 --- /dev/null +++ b/abp/SimpleWebSocketServer.py @@ -0,0 +1,694 @@ +''' +The MIT License (MIT) +Copyright (c) 2013 Dave P. +''' +import sys +VER = sys.version_info[0] +if VER >= 3: + import socketserver + from http.server import BaseHTTPRequestHandler + from io import StringIO, BytesIO +else: + import SocketServer + from BaseHTTPServer import BaseHTTPRequestHandler + from StringIO import StringIO + +import hashlib +import base64 +import socket +import struct +import ssl +import errno +import codecs +from collections import deque +from select import select + +__all__ = ['WebSocket', + 'SimpleWebSocketServer', + 'SimpleSSLWebSocketServer'] + +def _check_unicode(val): + if VER >= 3: + return isinstance(val, str) + else: + return isinstance(val, unicode) + +class HTTPRequest(BaseHTTPRequestHandler): + def __init__(self, request_text): + if VER >= 3: + self.rfile = BytesIO(request_text) + else: + self.rfile = StringIO(request_text) + self.raw_requestline = self.rfile.readline() + self.error_code = self.error_message = None + self.parse_request() + +_VALID_STATUS_CODES = [1000, 1001, 1002, 1003, 1007, 1008, + 1009, 1010, 1011, 3000, 3999, 4000, 4999] + +HANDSHAKE_STR = ( + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: WebSocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: %(acceptstr)s\r\n\r\n" +) + +GUID_STR = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' + +STREAM = 0x0 +TEXT = 0x1 +BINARY = 0x2 +CLOSE = 0x8 +PING = 0x9 +PONG = 0xA + +HEADERB1 = 1 +HEADERB2 = 3 +LENGTHSHORT = 4 +LENGTHLONG = 5 +MASK = 6 +PAYLOAD = 7 + +MAXHEADER = 65536 +MAXPAYLOAD = 33554432 + +class WebSocket(object): + + def __init__(self, server, sock, address): + self.server = server + self.client = sock + self.address = address + + self.handshaked = False + self.headerbuffer = bytearray() + self.headertoread = 2048 + + self.fin = 0 + self.data = bytearray() + self.opcode = 0 + self.hasmask = 0 + self.maskarray = None + self.length = 0 + self.lengtharray = None + self.index = 0 + self.request = None + self.usingssl = False + + self.frag_start = False + self.frag_type = BINARY + self.frag_buffer = None + self.frag_decoder = codecs.getincrementaldecoder('utf-8')(errors='strict') + self.closed = False + self.sendq = deque() + + self.state = HEADERB1 + + # restrict the size of header and payload for security reasons + self.maxheader = MAXHEADER + self.maxpayload = MAXPAYLOAD + + def handleMessage(self): + """ + Called when websocket frame is received. + To access the frame data call self.data. + + If the frame is Text then self.data is a unicode object. + If the frame is Binary then self.data is a bytearray object. + """ + pass + + def handleConnected(self): + """ + Called when a websocket client connects to the server. + """ + pass + + def handleClose(self): + """ + Called when a websocket server gets a Close frame from a client. + """ + pass + + def _handlePacket(self): + if self.opcode == CLOSE: + pass + elif self.opcode == STREAM: + pass + elif self.opcode == TEXT: + pass + elif self.opcode == BINARY: + pass + elif self.opcode == PONG or self.opcode == PING: + if len(self.data) > 125: + raise Exception('control frame length can not be > 125') + else: + # unknown or reserved opcode so just close + raise Exception('unknown opcode') + + if self.opcode == CLOSE: + status = 1000 + reason = u'' + length = len(self.data) + + if length == 0: + pass + elif length >= 2: + status = struct.unpack_from('!H', self.data[:2])[0] + reason = self.data[2:] + + if status not in _VALID_STATUS_CODES: + status = 1002 + + if len(reason) > 0: + try: + reason = reason.decode('utf8', errors='strict') + except: + status = 1002 + else: + status = 1002 + + self.close(status, reason) + return + + elif self.fin == 0: + if self.opcode != STREAM: + if self.opcode == PING or self.opcode == PONG: + raise Exception('control messages can not be fragmented') + + self.frag_type = self.opcode + self.frag_start = True + self.frag_decoder.reset() + + if self.frag_type == TEXT: + self.frag_buffer = [] + utf_str = self.frag_decoder.decode(self.data, final = False) + if utf_str: + self.frag_buffer.append(utf_str) + else: + self.frag_buffer = bytearray() + self.frag_buffer.extend(self.data) + + else: + if self.frag_start is False: + raise Exception('fragmentation protocol error') + + if self.frag_type == TEXT: + utf_str = self.frag_decoder.decode(self.data, final = False) + if utf_str: + self.frag_buffer.append(utf_str) + else: + self.frag_buffer.extend(self.data) + + else: + if self.opcode == STREAM: + if self.frag_start is False: + raise Exception('fragmentation protocol error') + + if self.frag_type == TEXT: + utf_str = self.frag_decoder.decode(self.data, final = True) + self.frag_buffer.append(utf_str) + self.data = u''.join(self.frag_buffer) + else: + self.frag_buffer.extend(self.data) + self.data = self.frag_buffer + + self.handleMessage() + + self.frag_decoder.reset() + self.frag_type = BINARY + self.frag_start = False + self.frag_buffer = None + + elif self.opcode == PING: + self._sendMessage(False, PONG, self.data) + + elif self.opcode == PONG: + pass + + else: + if self.frag_start is True: + raise Exception('fragmentation protocol error') + + if self.opcode == TEXT: + try: + self.data = self.data.decode('utf8', errors='strict') + except Exception as exp: + raise Exception('invalid utf-8 payload') + + self.handleMessage() + + + def _handleData(self): + # do the HTTP header and handshake + if self.handshaked is False: + + data = self.client.recv(self.headertoread) + if not data: + raise Exception('remote socket closed') + + else: + # accumulate + self.headerbuffer.extend(data) + + if len(self.headerbuffer) >= self.maxheader: + raise Exception('header exceeded allowable size') + + # indicates end of HTTP header + if b'\r\n\r\n' in self.headerbuffer: + self.request = HTTPRequest(self.headerbuffer) + + # handshake rfc 6455 + try: + key = self.request.headers['Sec-WebSocket-Key'] + k = key.encode('ascii') + GUID_STR.encode('ascii') + k_s = base64.b64encode(hashlib.sha1(k).digest()).decode('ascii') + hStr = HANDSHAKE_STR % {'acceptstr': k_s} + self.sendq.append((BINARY, hStr.encode('ascii'))) + self.handshaked = True + self.handleConnected() + except Exception as e: + raise Exception('handshake failed: %s', str(e)) + + # else do normal data + else: + data = self.client.recv(8192) + if not data: + raise Exception("remote socket closed") + + if VER >= 3: + for d in data: + self._parseMessage(d) + else: + for d in data: + self._parseMessage(ord(d)) + + def close(self, status = 1000, reason = u''): + """ + Send Close frame to the client. The underlying socket is only closed + when the client acknowledges the Close frame. + + status is the closing identifier. + reason is the reason for the close. + """ + try: + if self.closed is False: + close_msg = bytearray() + close_msg.extend(struct.pack("!H", status)) + if _check_unicode(reason): + close_msg.extend(reason.encode('utf-8')) + else: + close_msg.extend(reason) + + self._sendMessage(False, CLOSE, close_msg) + + finally: + self.closed = True + + + def _sendBuffer(self, buff): + size = len(buff) + tosend = size + already_sent = 0 + + while tosend > 0: + try: + # i should be able to send a bytearray + sent = self.client.send(buff[already_sent:]) + if sent == 0: + raise RuntimeError('socket connection broken') + + already_sent += sent + tosend -= sent + + except socket.error as e: + # if we have full buffers then wait for them to drain and try again + if e.errno in [errno.EAGAIN, errno.EWOULDBLOCK]: + return buff[already_sent:] + else: + raise e + + return None + + def sendFragmentStart(self, data): + """ + Send the start of a data fragment stream to a websocket client. + Subsequent data should be sent using sendFragment(). + A fragment stream is completed when sendFragmentEnd() is called. + + If data is a unicode object then the frame is sent as Text. + If the data is a bytearray object then the frame is sent as Binary. + """ + opcode = BINARY + if _check_unicode(data): + opcode = TEXT + self._sendMessage(True, opcode, data) + + def sendFragment(self, data): + """ + see sendFragmentStart() + + If data is a unicode object then the frame is sent as Text. + If the data is a bytearray object then the frame is sent as Binary. + """ + self._sendMessage(True, STREAM, data) + + def sendFragmentEnd(self, data): + """ + see sendFragmentEnd() + + If data is a unicode object then the frame is sent as Text. + If the data is a bytearray object then the frame is sent as Binary. + """ + self._sendMessage(False, STREAM, data) + + def sendMessage(self, data): + """ + Send websocket data frame to the client. + + If data is a unicode object then the frame is sent as Text. + If the data is a bytearray object then the frame is sent as Binary. + """ + opcode = BINARY + if _check_unicode(data): + opcode = TEXT + self._sendMessage(False, opcode, data) + + + def _sendMessage(self, fin, opcode, data): + + payload = bytearray() + + b1 = 0 + b2 = 0 + if fin is False: + b1 |= 0x80 + b1 |= opcode + + if _check_unicode(data): + data = data.encode('utf-8') + + length = len(data) + payload.append(b1) + + if length <= 125: + b2 |= length + payload.append(b2) + + elif length >= 126 and length <= 65535: + b2 |= 126 + payload.append(b2) + payload.extend(struct.pack("!H", length)) + + else: + b2 |= 127 + payload.append(b2) + payload.extend(struct.pack("!Q", length)) + + if length > 0: + payload.extend(data) + + self.sendq.append((opcode, payload)) + + + def _parseMessage(self, byte): + # read in the header + if self.state == HEADERB1: + + self.fin = byte & 0x80 + self.opcode = byte & 0x0F + self.state = HEADERB2 + + self.index = 0 + self.length = 0 + self.lengtharray = bytearray() + self.data = bytearray() + + rsv = byte & 0x70 + if rsv != 0: + raise Exception('RSV bit must be 0') + + elif self.state == HEADERB2: + mask = byte & 0x80 + length = byte & 0x7F + + if self.opcode == PING and length > 125: + raise Exception('ping packet is too large') + + if mask == 128: + self.hasmask = True + else: + self.hasmask = False + + if length <= 125: + self.length = length + + # if we have a mask we must read it + if self.hasmask is True: + self.maskarray = bytearray() + self.state = MASK + else: + # if there is no mask and no payload we are done + if self.length <= 0: + try: + self._handlePacket() + finally: + self.state = self.HEADERB1 + self.data = bytearray() + + # we have no mask and some payload + else: + #self.index = 0 + self.data = bytearray() + self.state = PAYLOAD + + elif length == 126: + self.lengtharray = bytearray() + self.state = LENGTHSHORT + + elif length == 127: + self.lengtharray = bytearray() + self.state = LENGTHLONG + + + elif self.state == LENGTHSHORT: + self.lengtharray.append(byte) + + if len(self.lengtharray) > 2: + raise Exception('short length exceeded allowable size') + + if len(self.lengtharray) == 2: + self.length = struct.unpack_from('!H', self.lengtharray)[0] + + if self.hasmask is True: + self.maskarray = bytearray() + self.state = MASK + else: + # if there is no mask and no payload we are done + if self.length <= 0: + try: + self._handlePacket() + finally: + self.state = HEADERB1 + self.data = bytearray() + + # we have no mask and some payload + else: + #self.index = 0 + self.data = bytearray() + self.state = PAYLOAD + + elif self.state == LENGTHLONG: + + self.lengtharray.append(byte) + + if len(self.lengtharray) > 8: + raise Exception('long length exceeded allowable size') + + if len(self.lengtharray) == 8: + self.length = struct.unpack_from('!Q', self.lengtharray)[0] + + if self.hasmask is True: + self.maskarray = bytearray() + self.state = MASK + else: + # if there is no mask and no payload we are done + if self.length <= 0: + try: + self._handlePacket() + finally: + self.state = HEADERB1 + self.data = bytearray() + + # we have no mask and some payload + else: + #self.index = 0 + self.data = bytearray() + self.state = PAYLOAD + + # MASK STATE + elif self.state == MASK: + self.maskarray.append(byte) + + if len(self.maskarray) > 4: + raise Exception('mask exceeded allowable size') + + if len(self.maskarray) == 4: + # if there is no mask and no payload we are done + if self.length <= 0: + try: + self._handlePacket() + finally: + self.state = HEADERB1 + self.data = bytearray() + + # we have no mask and some payload + else: + #self.index = 0 + self.data = bytearray() + self.state = PAYLOAD + + # PAYLOAD STATE + elif self.state == PAYLOAD: + if self.hasmask is True: + self.data.append( byte ^ self.maskarray[self.index % 4] ) + else: + self.data.append( byte ) + + # if length exceeds allowable size then we except and remove the connection + if len(self.data) >= self.maxpayload: + raise Exception('payload exceeded allowable size') + + # check if we have processed length bytes; if so we are done + if (self.index+1) == self.length: + try: + self._handlePacket() + finally: + #self.index = 0 + self.state = HEADERB1 + self.data = bytearray() + else: + self.index += 1 + + +class SimpleWebSocketServer(object): + def __init__(self, host, port, websocketclass, selectInterval = 0.1): + self.websocketclass = websocketclass + self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.serversocket.bind((host, port)) + self.serversocket.listen(5) + self.selectInterval = selectInterval + self.connections = {} + self.listeners = [self.serversocket] + + def _decorateSocket(self, sock): + return sock + + def _constructWebSocket(self, sock, address): + return self.websocketclass(self, sock, address) + + def close(self): + self.serversocket.close() + + for desc, conn in self.connections.items(): + conn.close() + conn.handleClose() + + + def serveforever(self): + while True: + writers = [] + for fileno in self.listeners: + if fileno == self.serversocket: + continue + client = self.connections[fileno] + if client.sendq: + writers.append(fileno) + + if self.selectInterval: + rList, wList, xList = select(self.listeners, writers, self.listeners, self.selectInterval) + else: + rList, wList, xList = select(self.listeners, writers, self.listeners) + + for ready in wList: + client = self.connections[ready] + try: + while client.sendq: + opcode, payload = client.sendq.popleft() + remaining = client._sendBuffer(payload) + if remaining is not None: + client.sendq.appendleft((opcode, remaining)) + break + else: + if opcode == CLOSE: + raise Exception('received client close') + + except Exception as n: + client.client.close() + client.handleClose() + del self.connections[ready] + self.listeners.remove(ready) + + for ready in rList: + if ready == self.serversocket: + try: + sock, address = self.serversocket.accept() + newsock = self._decorateSocket(sock) + newsock.setblocking(0) + fileno = newsock.fileno() + self.connections[fileno] = self._constructWebSocket(newsock, address) + self.listeners.append(fileno) + except Exception as n: + if sock is not None: + sock.close() + else: + if ready not in self.connections: + continue + client = self.connections[ready] + try: + client._handleData() + except Exception as n: + client.client.close() + client.handleClose() + del self.connections[ready] + self.listeners.remove(ready) + + for failed in xList: + if failed == self.serversocket: + self.close() + raise Exception('server socket failed') + else: + if failed not in self.connections: + continue + client = self.connections[failed] + client.client.close() + client.handleClose() + del self.connections[failed] + self.listeners.remove(failed) + + +class SimpleSSLWebSocketServer(SimpleWebSocketServer): + + def __init__(self, host, port, websocketclass, certfile, + keyfile, version = ssl.PROTOCOL_TLSv1, selectInterval = 0.1): + + SimpleWebSocketServer.__init__(self, host, port, + websocketclass, selectInterval) + + self.context = ssl.SSLContext(version) + self.context.load_cert_chain(certfile, keyfile) + + def close(self): + super(SimpleSSLWebSocketServer, self).close() + + def _decorateSocket(self, sock): + sslsock = self.context.wrap_socket(sock, server_side=True) + return sslsock + + def _constructWebSocket(self, sock, address): + ws = self.websocketclass(self, sock, address) + ws.usingssl = True + return ws + + def serveforever(self): + super(SimpleSSLWebSocketServer, self).serveforever() diff --git a/abp/clifford.py b/abp/clifford.py index 97a9877..d09b182 100644 --- a/abp/clifford.py +++ b/abp/clifford.py @@ -12,20 +12,12 @@ import qi import numpy as np import tempfile from tqdm import tqdm +import os, sys, json, string decompositions = ("xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz", "xzx", "xzxxx", "xzzzx", "xxxzx", "xzz", "zzx", "xxx", "x", "zzzx", "xxzx", "zx", "zxxx", "xxxz", "xzzz", "xz", "xzxx") - #{"UUUU", "UU", "VVUU", "VV", #"VUU", "V", "VVV", "UUV", - #"UVU", "UVUUU", "UVVVU", "UUUVU", #"UVV", "VVU", "UUU", "U", - #"VVVU", "UUVU", "VU", "VUUU", #"UUUV", "UVVV", "UV", "UVUU"}; - -#string LocCliffOp::get_name (void) const -#{ - #static const char* paulinames[] = {"I", "X", "Y", "Z"}; - #return string (paulinames[op & 0x03]) + (char) ('A' + op / 4); -#} def get_name(i): """ Get the human-readable name of this clifford """ @@ -108,14 +100,15 @@ def get_state_table(unitaries): np.dot(kp, state).T) return state_table +def get_commuters(unitaries): + """ Get the indeces of gates which commute with CZ """ + commuters = (qi.id, qi.px, qi.pz, qi.ph, qi.hermitian_conjugate(qi.ph)) + return [find_clifford(u, unitaries) for u in commuters] def get_cz_table(unitaries): """ Compute the lookup table for the CZ (A&B eq. 9) """ - # This is the set of Cliffords which commute with CZ - commuters = (qi.id, qi.px, qi.pz, qi.ph, qi.hermitian_conjugate(qi.ph)) - commuters = [find_clifford(u, unitaries) for u in commuters] - - # Get a cached state table + # Get a cached state table and a list of gates which commute with CZ + commuters = get_commuters(unitaries) state_table = get_state_table(unitaries) # And now build the CZ table @@ -128,6 +121,14 @@ def get_cz_table(unitaries): cz_table[bond, c2, c1] = [newbond, c2p, c1p] return cz_table +def get_ab_cz_table(): + """ Load anders and briegel's CZ table """ + filename = "anders_briegel/cphase.tbl" + filename = os.path.join(os.path.dirname(sys.path[0]), filename) + with open(filename) as f: + s = f.read().translate(string.maketrans("{}", "[]")) + return np.array(json.loads(s)) + # First try to load tables from cache. If that fails, build them from # scratch and store @@ -136,7 +137,8 @@ try: unitaries = np.load("unitaries.npy") conjugation_table = np.load("conjugation_table.npy") times_table = np.load("times_table.npy") - cz_table = np.load("cz_table.npy") + #cz_table = np.load("cz_table.npy") + cz_table = get_ab_cz_table() with open("by_name.json") as f: by_name = json.load(f) diff --git a/static/main.js b/static/main.js index 51446c4..9d9c06e 100644 --- a/static/main.js +++ b/static/main.js @@ -45,7 +45,7 @@ function loopForever() { function startMainLoop() { scene = makeScene(); controls.addEventListener("change", render); - poll(); + //poll(); loopForever(); } @@ -75,7 +75,7 @@ function init() { camera.position.set(0, 0, 20); // Start polling - setInterval(poll, 1000); + //setInterval(poll, 1000); // Run startMainLoop(); diff --git a/static/poll.js b/static/poll.js index 141d1bd..4122b85 100644 --- a/static/poll.js +++ b/static/poll.js @@ -1,53 +1,46 @@ -var body; - -function poll() { - var xhr = new XMLHttpRequest(); - - xhr.onload = function() { - var state = JSON.parse(xhr.responseText); - updateScene(state); - }; - - xhr.onerror = function(e){ - //soft_console.innerHTML = "\n" + "Lost connection to server"; - }; - - xhr.open("GET", "/state", true); - xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); - xhr.send(); -} - -function updateScene(state) { - var oldState = scene.getObjectByName("graphstate"); - scene.remove(oldState); - oldState = null; - - var geometry = new THREE.Geometry(); - //nodeGeometry.labels = []; - //nodeGeometry.colors = []; - for (var i in state.vops) { - var vop = state.vops[i]; - var pos = state.meta[i].pos; - var vertex = new THREE.Vector3(pos.x, pos.y, pos.z); - geometry.vertices.push(vertex); - //geometry.colors[i] = new THREE.Color(n.color); - //geometry.labels[i] = n.label; - } - - var edges = new THREE.Object3D(); - for (i=0; i < state.edge.length; ++i) { - var edge = state.edge[i]; - var start = state.meta[edge[0]].pos; - var end = state.meta[edge[1]].pos; - var newEdge = makeEdge(start, end); - edges.add(newEdge); - } - - var particles = new THREE.Points(geometry, materials.qubit); - var newState = new THREE.Object3D(); - newState.name = "graphstate"; - newState.add(particles); - newState.add(edges); - scene.add(newState); - render(); +var url = "ws://localhost:8000/"; + +function doConnect() { + websocket = new WebSocket(url); + websocket.onopen = onOpen; + websocket.onclose = onClose; + websocket.onmessage = onMessage; + websocket.onerror = onError; +} + +function onOpen(evt) { + writeToScreen("connected\n"); + doSend("Hello from the browser"); +} + +function onClose(evt) { + writeToScreen("disconnected\n"); +} + +function onMessage(evt) { + writeToScreen("response: " + evt.data + '\n'); +} + +function onError(evt) { + writeToScreen('error: ' + evt.data + '\n'); + websocket.close(); } + +function doSend(message) { + writeToScreen("sent: " + message + '\n'); + websocket.send(message); +} + +function writeToScreen(message) { + console.log(message); +} + +function init() { + doConnect(); +} + +function doDisconnect() { + websocket.close(); +} + +window.addEventListener("load", init, false); diff --git a/tests/test_against_anders_and_briegel.py b/tests/test_against_anders_and_briegel.py index 0da078b..93435de 100644 --- a/tests/test_against_anders_and_briegel.py +++ b/tests/test_against_anders_and_briegel.py @@ -13,6 +13,7 @@ def compare(a, b): except AssertionError: print aa print bb + raise def test_hadamard(): """ Test hadamards """ @@ -51,11 +52,13 @@ def test_cz_table(): b.add_vertex(0) b.add_vertex(1) compare(a, b) - #a.local_op(0, graphsim.LocCliffOp(j)) - #b.act_local_rotation(0, j) + + a.local_op(0, graphsim.LocCliffOp(j)) + b.act_local_rotation(0, j) a.local_op(1, graphsim.LocCliffOp(j)) b.act_local_rotation(1, j) + a.cphase(0, 1) b.act_cz(0, 1) compare(a, b) diff --git a/tests/test_clifford.py b/tests/test_clifford.py index dbc0670..40b102c 100644 --- a/tests/test_clifford.py +++ b/tests/test_clifford.py @@ -67,7 +67,7 @@ def test_times_table(): assert clifford.times_table[0][4] == 4 -def test_cz_table_is_symmetric(): +def _test_cz_table_is_symmetric(): """ Test the CZ table is symmetric """ for bond, (a, b) in it.product([0, 1], it.combinations(xrange(24), 2)): _, a1, a2 = clifford.cz_table[bond, a, b] @@ -82,3 +82,7 @@ def test_cz_table_makes_sense(): assert all(clifford.cz_table[1, 0, 0] == [0, 0, 0]) assert all( clifford.cz_table[0, hadamard, hadamard] == [0, hadamard, hadamard]) + +def test_commuters(): + """ Test that commutation is good """ + print clifford.get_commuters(clifford.unitaries) diff --git a/tests/test_cphase_against_anders.py b/tests/test_cphase_against_anders.py new file mode 100644 index 0000000..d88dd49 --- /dev/null +++ b/tests/test_cphase_against_anders.py @@ -0,0 +1,50 @@ +import json +import numpy as np +from abp import clifford, qi +import sys +import os +import itertools as it +from string import maketrans + + +def get_ab_cz_table(): + """ Load anders and briegel's CZ table """ + filename = "anders_briegel/cphase.tbl" + filename = os.path.join(os.path.dirname(sys.path[0]), filename) + with open(filename) as f: + s = f.read().translate(maketrans("{}", "[]")) + return np.array(json.loads(s)) + + + +def test_cz_table(): + """ Does our clifford code work with anders & briegel's table? """ + state_table = clifford.get_state_table(clifford.unitaries) + ab_cz_table = get_ab_cz_table() + + rows = it.product([0, 1], it.combinations_with_replacement(range(24), 2)) + for bond, (c1, c2) in rows: + + # Pick the input state + input_state = state_table[bond, c1, c2] + + # Go and compute the output + computed_output = np.dot(qi.cz, input_state) + computed_output = clifford.normalize_global_phase(computed_output) + + # Now look up the answer in the table + bondp, c1p, c2p = ab_cz_table[bond, c1, c2] + table_output = state_table[bondp, c1p, c2p] + + assert np.allclose(computed_output, table_output) + + +def test_match(): + """ Tests that they actually match """ + ab_cz_table = get_ab_cz_table() + + rows = it.product([0, 1], it.combinations_with_replacement(range(24), 2)) + for bond, (c1, c2) in rows: + assert np.all(ab_cz_table == clifford.cz_table) + + diff --git a/tests/test_cphase_table.py b/tests/test_cphase_table.py new file mode 100644 index 0000000..d617dc4 --- /dev/null +++ b/tests/test_cphase_table.py @@ -0,0 +1,27 @@ +import numpy as np +from abp import clifford, qi +import itertools as it + +def test_cz_table(): + """ Does the CZ code work good? """ + state_table = clifford.get_state_table(clifford.unitaries) + + rows = it.product([0, 1], it.combinations_with_replacement(range(24), 2)) + + for bond, (c1, c2) in rows: + + # Pick the input state + input_state = state_table[bond, c1, c2] + + # Go and compute the output + computed_output = np.dot(qi.cz, input_state) + computed_output = clifford.normalize_global_phase(computed_output) + + # Now look up the answer in the table + bondp, c1p, c2p = clifford.cz_table[bond, c1, c2] + table_output = state_table[bondp, c1p, c2p] + + assert np.allclose(computed_output, table_output) + + +