Browse Source

Merge branch 'pete'

master
Pete Shadbolt 7 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 sys
import networkx
import networkx as nx
import numpy as np
import websocket
from socket import error as socket_error
@@ -8,7 +8,7 @@ import graphstate
import clifford
import util

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

def layout(self):
""" 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)
pos = {key: value - middle for key, value 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``.
"""

def __init__(self, nodes=[], deterministic=False, vop="identity"):
def __init__(self, data=(), deterministic=False, vop="identity"):
""" 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 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.adj, self.node = {}, {}
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):
""" 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 mock import simple_graph


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


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


def networkx_test():
""" Test that fancy graph states really behave like networkx graphs """
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(1)
g.act_cz(0, 1)
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 numpy as np
from tqdm import tqdm
import networkx as nx

REPEATS = 100
DEPTH = 100
@@ -121,3 +122,12 @@ def test_stabilizer_state_multiqubit(n=6):
b = mock.circuit_to_state(mock.CircuitModelWrapper, n, circuit)
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