Browse Source

Merge branch 'pete'

master
Pete Shadbolt 8 years ago
parent
commit
5ef9f18d38
5 changed files with 103 additions and 14 deletions
  1. +3
    -3
      abp/fancy.py
  2. +16
    -7
      abp/graphstate.py
  3. +61
    -0
      abp/lattices.py
  4. +13
    -4
      tests/test_fancy.py
  5. +10
    -0
      tests/test_graphstate.py

+ 3
- 3
abp/fancy.py View File

@@ -1,6 +1,6 @@
import time, atexit, json import time, atexit, json
import sys import sys
import networkx
import networkx as nx
import numpy as np import numpy as np
import websocket import websocket
from socket import error as socket_error from socket import error as socket_error
@@ -8,7 +8,7 @@ import graphstate
import clifford import clifford
import util import util


class GraphState(graphstate.GraphState, networkx.Graph):
class GraphState(graphstate.GraphState, nx.Graph):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
graphstate.GraphState.__init__(self, *args, **kwargs) graphstate.GraphState.__init__(self, *args, **kwargs)
self.connect_to_server() self.connect_to_server()
@@ -50,7 +50,7 @@ class GraphState(graphstate.GraphState, networkx.Graph):


def layout(self): def layout(self):
""" Automatically lay out the graph """ """ Automatically lay out the graph """
pos = networkx.spring_layout(self, dim=3, scale=np.sqrt(self.order()))
pos = nx.spring_layout(self, dim=3, scale=np.sqrt(self.order()))
middle = np.average(pos.values(), axis=0) middle = np.average(pos.values(), axis=0)
pos = {key: value - middle for key, value in pos.items()} pos = {key: value - middle for key, value in pos.items()}
for key, (x, y, z) in pos.items(): for key, (x, y, z) in pos.items():


+ 16
- 7
abp/graphstate.py View File

@@ -16,10 +16,10 @@ class GraphState(object):
Internally it uses the same dictionary-of-dictionaries data structure as ``networkx``. Internally it uses the same dictionary-of-dictionaries data structure as ``networkx``.
""" """


def __init__(self, nodes=[], deterministic=False, vop="identity"):
def __init__(self, data=(), deterministic=False, vop="identity"):
""" Construct a ``GraphState`` """ Construct a ``GraphState``


:param nodes: An iterable of nodes used to construct the graph, or an integer -- the number of nodes.
:param data: An iterable of nodes used to construct the graph, or an integer -- the number of nodes, or a ``nx.Graph``.
:param deterministic: If ``True``, the behaviour of the graph is deterministic up to but not including the choice of measurement outcome. This is slightly less efficient, but useful for testing. If ``False``, the specific graph representation will sometimes be random -- of course, all possible representations still map to the same state vector. :param deterministic: If ``True``, the behaviour of the graph is deterministic up to but not including the choice of measurement outcome. This is slightly less efficient, but useful for testing. If ``False``, the specific graph representation will sometimes be random -- of course, all possible representations still map to the same state vector.
:param vop: The default VOP for new qubits. Setting ``vop="identity"`` initializes qubits in :math:`|+\\rangle`. Setting ``vop="hadamard"`` initializes qubits in :math:`|0\\rangle`. :param vop: The default VOP for new qubits. Setting ``vop="identity"`` initializes qubits in :math:`|+\\rangle`. Setting ``vop="hadamard"`` initializes qubits in :math:`|0\\rangle`.
""" """
@@ -27,11 +27,20 @@ class GraphState(object):
self.deterministic = deterministic self.deterministic = deterministic
self.adj, self.node = {}, {} self.adj, self.node = {}, {}
try: try:
for n in nodes:
self._add_node(n, vop=vop)
except TypeError:
for n in range(nodes):
self._add_node(n, vop=vop)
# Cloning from a networkx graph
self.adj = data.adj.copy()
self.node = data.node.copy()
for key, value in self.node.items():
self.node[key]["vop"] = data.node[key].get("vop", clifford.by_name["identity"])
except AttributeError:
try:
# Provided with a list of node names?
for n in data:
self._add_node(n, vop=vop)
except TypeError:
# Provided with an integer?
for n in range(data):
self._add_node(n, vop=vop)


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.


+ 61
- 0
abp/lattices.py View File

@@ -0,0 +1,61 @@
"""
This is a sketch of a consistent language for defining resource states and lattices.
"""

import networkx as nx
from abp.fancy import GraphState

def union(*graphs):
""" Assumes that all graphs are completely independent and uniquely labelled """
output = nx.Graph()
output.node = dict(i for g in graphs for i in g.node.items())
output.adj = dict(i for g in graphs for i in g.adj.items())
return output

def relabel(g, label):
""" Shorthand relabel """
return nx.relabel_nodes(g, lambda x: (label, x))

def fuse(psi, na, nb):
""" Deterministic fusion for testing purposes """
neighbors_a, neighbors_b = psi.neighbors(na), psi.neighbors(nb)
new_edges = ((i, j) for i in neighbors_a for j in neighbors_b if i != j)
psi.add_edges_from(new_edges)
psi.remove_nodes_from((na, nb))
return psi

def ghz(label):
""" A 3-GHZ state """
psi = nx.Graph(((0, 1), (1, 2)))
return relabel(psi, label)

def microcluster(label):
""" A microcluster """
psi = union(ghz(0), ghz(1), ghz(2))
psi = fuse(psi, (0, 1), (1, 0))
psi = fuse(psi, (1, 2), (2, 1))
return relabel(psi, label)

def unit_cell(label):
""" A simple ring-like unit cell """
psi = union(microcluster(0), microcluster(1), microcluster(2), microcluster(3))
psi = fuse(psi, (0, (0, 2)), (1, (2, 2)))
psi = fuse(psi, (1, (0, 2)), (2, (2, 2)))
psi = fuse(psi, (2, (0, 2)), (3, (2, 2)))
psi = fuse(psi, (3, (0, 2)), (0, (2, 2)))
return relabel(psi, label)

def position(node):
print node
return {}

def annotate(g, f):
""" Annotate a graph """
for node in g.nodes():
g.node[node].update(f(node))

if __name__ == '__main__':
psi = union(unit_cell((0, 0)), unit_cell((2, 0)))
annotate(psi, position)
g = GraphState(psi)


+ 13
- 4
tests/test_fancy.py View File

@@ -5,6 +5,7 @@ from abp import clifford
from abp.util import xyz from abp.util import xyz
from mock import simple_graph from mock import simple_graph



def test_json_basic(): def test_json_basic():
""" Test that we can export to JSON """ """ Test that we can export to JSON """
g = simple_graph() g = simple_graph()
@@ -12,6 +13,7 @@ def test_json_basic():
assert "adj" in js assert "adj" in js
assert "node" in js assert "node" in js



def test_tuple_keys(): def test_tuple_keys():
""" Test that we can use tuple-ish keys """ """ Test that we can use tuple-ish keys """
g = fancy.GraphState() g = fancy.GraphState()
@@ -20,17 +22,24 @@ def test_tuple_keys():
g.add_edge((1, 2, 3), "string") g.add_edge((1, 2, 3), "string")
json.dumps(g.to_json(True)) json.dumps(g.to_json(True))



def networkx_test(): def networkx_test():
""" Test that fancy graph states really behave like networkx graphs """ """ Test that fancy graph states really behave like networkx graphs """
g = fancy.GraphState() g = fancy.GraphState()
g.add_qubit(0, position = xyz(10, 0, 0))
g.add_qubit(1, position = xyz(1, 0, 0))
g.add_qubit(0, position=xyz(10, 0, 0))
g.add_qubit(1, position=xyz(1, 0, 0))
g.act_hadamard(0) g.act_hadamard(0)
g.act_hadamard(1) g.act_hadamard(1)
g.act_cz(0, 1) g.act_cz(0, 1)
g.copy() g.copy()


# TODO: more tests here!



def test_from_nx():
""" Test that making graphs from networkx objects goes smoothly """
g = nx.random_geometric_graph(100, 2)
psi = fancy.GraphState(g)
assert psi.node[0]["vop"] == 0
assert len(psi.edges()) > 0
psi.measure(0, "px", detail=True)


psi = fancy.GraphState(nx.Graph(((0, 1),)))

+ 10
- 0
tests/test_graphstate.py View File

@@ -3,6 +3,7 @@ import mock
import random import random
import numpy as np import numpy as np
from tqdm import tqdm from tqdm import tqdm
import networkx as nx


REPEATS = 100 REPEATS = 100
DEPTH = 100 DEPTH = 100
@@ -121,3 +122,12 @@ def test_stabilizer_state_multiqubit(n=6):
b = mock.circuit_to_state(mock.CircuitModelWrapper, n, circuit) b = mock.circuit_to_state(mock.CircuitModelWrapper, n, circuit)
assert a.to_state_vector() == b assert a.to_state_vector() == b



def test_from_nx():
""" Creating from a networkx graph """
g = nx.random_geometric_graph(100, 2)
psi = GraphState(g)
assert len(psi.node) == 100

psi = GraphState(nx.Graph(((0, 1),)))


Loading…
Cancel
Save