| @@ -1,5 +1,5 @@ | |||||
| [bumpversion] | [bumpversion] | ||||
| current_version = 0.4.13 | |||||
| current_version = 0.4.14 | |||||
| commit = True | commit = True | ||||
| tag = True | tag = True | ||||
| @@ -16,19 +16,25 @@ 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): | |||||
| def __init__(self, nodes=[], deterministic=False, vop="identity"): | |||||
| """ Construct a ``GraphState`` | """ Construct a ``GraphState`` | ||||
| :param nodes: An iterable of nodes used to construct the graph. | |||||
| :param nodes: An iterable of nodes used to construct the graph, or an integer -- the number of nodes. | |||||
| :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`. | |||||
| """ | """ | ||||
| self.adj, self.node = {}, {} | |||||
| self.add_nodes(nodes) | |||||
| self.deterministic = deterministic | 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) | |||||
| def add_node(self, node, **kwargs): | |||||
| """ Add a node. | |||||
| 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. | |||||
| :param node: The name of the node, e.g. ``9``, ``start`` | :param node: The name of the node, e.g. ``9``, ``start`` | ||||
| :type node: Any hashable type | :type node: Any hashable type | ||||
| @@ -42,14 +48,23 @@ class GraphState(object): | |||||
| """ | """ | ||||
| assert not node in self.node, "Node {} already exists".format(v) | assert not node in self.node, "Node {} already exists".format(v) | ||||
| default = kwargs.get("default", "identity") | |||||
| self.adj[node] = {} | self.adj[node] = {} | ||||
| self.node[node] = {"vop": clifford.by_name["hadamard"]} | |||||
| self.node[node] = {} | |||||
| kwargs["vop"] = clifford.by_name[str(kwargs.get("vop", "identity"))] #TODO: ugly | |||||
| self.node[node].update(kwargs) | self.node[node].update(kwargs) | ||||
| def add_nodes(self, nodes): | |||||
| """ Add many nodes in one shot. """ | |||||
| for n in nodes: | |||||
| self.add_node(n) | |||||
| def add_qubit(self, name, **kwargs): | |||||
| """ Add a qubit to the state. | |||||
| :param name: The name of the node, e.g. ``9``, ``start``. | |||||
| :type name: Any hashable type | |||||
| :param kwargs: Any extra node attributes | |||||
| By default, qubits are initialized in the :math:`|0\\rangle` state. Provide the optional ``vop`` argument to set the initial state. | |||||
| """ | |||||
| kwargs["vop"] = clifford.by_name[str(kwargs.get("vop", "hadamard"))] #TODO: ugly | |||||
| self._add_node(name, **kwargs) | |||||
| def act_circuit(self, circuit): | def act_circuit(self, circuit): | ||||
| """ Run many gates in one call. | """ Run many gates in one call. | ||||
| @@ -0,0 +1 @@ | |||||
| _build/html/index.html | |||||
| @@ -81,9 +81,7 @@ The ``abp.GraphState`` class is the main interface to ``abp``. | |||||
| .. automethod:: abp.GraphState.__init__ | .. automethod:: abp.GraphState.__init__ | ||||
| .. automethod:: abp.GraphState.add_node | |||||
| .. automethod:: abp.GraphState.add_nodes | |||||
| .. automethod:: abp.GraphState.add_qubit | |||||
| .. automethod:: abp.GraphState.act_local_rotation | .. automethod:: abp.GraphState.act_local_rotation | ||||
| @@ -6,7 +6,7 @@ STATIC = glob("abp/static/*.*")+glob("abp/static/img/*.*")+glob("abp/static/scri | |||||
| setup( | setup( | ||||
| name = "abp", | name = "abp", | ||||
| version = "0.4.13", | |||||
| version = "0.4.14", | |||||
| packages = ["abp", "abp.static"], | packages = ["abp", "abp.static"], | ||||
| test_suite = "tests", | test_suite = "tests", | ||||
| author = "Pete Shadbolt", | author = "Pete Shadbolt", | ||||
| @@ -52,7 +52,7 @@ class ABPWrapper(GraphState): | |||||
| """ A wrapper for abp, just to ensure determinism """ | """ A wrapper for abp, just to ensure determinism """ | ||||
| def __init__(self, nodes=[]): | def __init__(self, nodes=[]): | ||||
| super(ABPWrapper, self).__init__(nodes, deterministic=True) | |||||
| super(ABPWrapper, self).__init__(nodes, deterministic=True, vop="hadamard") | |||||
| def print_stabilizer(self): | def print_stabilizer(self): | ||||
| print self.to_stabilizer() | print self.to_stabilizer() | ||||
| @@ -15,16 +15,16 @@ def test_json_basic(): | |||||
| 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() | ||||
| g.add_node("string") | |||||
| g.add_node((1, 2, 3)) | |||||
| g.add_qubit("string") | |||||
| g.add_qubit((1, 2, 3)) | |||||
| 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_node(0, position = xyz(10, 0, 0)) | |||||
| g.add_node(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) | ||||
| @@ -7,6 +7,14 @@ from tqdm import tqdm | |||||
| REPEATS = 100 | REPEATS = 100 | ||||
| DEPTH = 100 | DEPTH = 100 | ||||
| def test_initialization(): | |||||
| g = GraphState("abc") | |||||
| assert g.node["a"]["vop"] == clifford.by_name["identity"] | |||||
| g = GraphState("abc", vop="hadamard") | |||||
| assert g.node["c"]["vop"] == clifford.by_name["hadamard"] | |||||
| g = GraphState(5) | |||||
| assert len(g.node) == 5 | |||||
| def test_graph_basic(): | def test_graph_basic(): | ||||
| """ Test that we can construct graphs, delete edges, whatever """ | """ Test that we can construct graphs, delete edges, whatever """ | ||||
| @@ -56,7 +64,7 @@ def test_edgelist(): | |||||
| def test_stress(n=int(1e5)): | def test_stress(n=int(1e5)): | ||||
| """ Testing that making a graph of ten thousand qubits takes less than half a second""" | """ Testing that making a graph of ten thousand qubits takes less than half a second""" | ||||
| import time | import time | ||||
| g = GraphState(range(n + 1)) | |||||
| g = GraphState(range(n + 1), vop="hadamard") | |||||
| t = time.clock() | t = time.clock() | ||||
| for i in xrange(n): | for i in xrange(n): | ||||
| g._add_edge(i, i + 1) | g._add_edge(i, i + 1) | ||||
| @@ -65,7 +73,7 @@ def test_stress(n=int(1e5)): | |||||
| def test_cz(): | def test_cz(): | ||||
| """ Test CZ gate """ | """ Test CZ gate """ | ||||
| g = GraphState([0, 1]) | |||||
| g = GraphState([0, 1], vop="hadamard") | |||||
| g.act_local_rotation(0, clifford.by_name["hadamard"]) | g.act_local_rotation(0, clifford.by_name["hadamard"]) | ||||
| g.act_local_rotation(1, clifford.by_name["hadamard"]) | g.act_local_rotation(1, clifford.by_name["hadamard"]) | ||||
| g.act_local_rotation(1, clifford.by_name["py"]) | g.act_local_rotation(1, clifford.by_name["py"]) | ||||
| @@ -77,7 +85,7 @@ def test_cz(): | |||||
| def test_local_complementation(): | def test_local_complementation(): | ||||
| """ Test that local complementation works okay """ | """ Test that local complementation works okay """ | ||||
| pairs = (0, 1), (0, 3), (1, 3), (1, 2), | pairs = (0, 1), (0, 3), (1, 3), (1, 2), | ||||
| psi = GraphState(range(4)) | |||||
| psi = GraphState(range(4), vop="hadamard") | |||||
| psi.act_circuit([(i, "hadamard") for i in psi.node]) | psi.act_circuit([(i, "hadamard") for i in psi.node]) | ||||
| psi.act_circuit([(pair, "cz") for pair in pairs]) | psi.act_circuit([(pair, "cz") for pair in pairs]) | ||||
| old_edges = psi.edgelist() | old_edges = psi.edgelist() | ||||
| @@ -10,16 +10,16 @@ def test_single_qubit_measurements(): | |||||
| """ Various simple tests of measurements """ | """ Various simple tests of measurements """ | ||||
| # Test that measuring |0> in Z gives 0 | # Test that measuring |0> in Z gives 0 | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| assert g.measure(0, "pz") == 0, "Measuring |0> in Z gives 0" | assert g.measure(0, "pz") == 0, "Measuring |0> in Z gives 0" | ||||
| # Test that measuring |1> in Z gives 1 | # Test that measuring |1> in Z gives 1 | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, "px") | g.act_local_rotation(0, "px") | ||||
| assert g.measure(0, "pz") == 1, "Measuring |1> in Z gives 1" | assert g.measure(0, "pz") == 1, "Measuring |1> in Z gives 1" | ||||
| # Test that measuring |+> in X gives 0 | # Test that measuring |+> in X gives 0 | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, "hadamard") | g.act_local_rotation(0, "hadamard") | ||||
| assert g.measure(0, "px") == 0 | assert g.measure(0, "px") == 0 | ||||
| assert g.measure(0, "px") == 0, "Measuring |+> in X gives 0" | assert g.measure(0, "px") == 0, "Measuring |+> in X gives 0" | ||||
| @@ -30,7 +30,7 @@ def test_single_qubit_measurements(): | |||||
| def test_type(): | def test_type(): | ||||
| """ Test that the output is always an int """ | """ Test that the output is always an int """ | ||||
| for r, m, f in it.product(range(24), ("px", "py", "pz"), (0, 1)): | for r, m, f in it.product(range(24), ("px", "py", "pz"), (0, 1)): | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, r) | g.act_local_rotation(0, r) | ||||
| assert str(g.measure(0, m)) in "01" | assert str(g.measure(0, m)) in "01" | ||||
| assert str(g.measure(0, m, f)) in "01" | assert str(g.measure(0, m, f)) in "01" | ||||
| @@ -41,7 +41,7 @@ def test_random_outcomes(): | |||||
| """ Testing random behaviour """ | """ Testing random behaviour """ | ||||
| ones = 0 | ones = 0 | ||||
| for i in range(1000): | for i in range(1000): | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, "hadamard") | g.act_local_rotation(0, "hadamard") | ||||
| ones += g.measure(0, "pz") | ones += g.measure(0, "pz") | ||||
| assert 400 < ones < 600, "This is a probabilistic test!" | assert 400 < ones < 600, "This is a probabilistic test!" | ||||
| @@ -49,13 +49,13 @@ def test_random_outcomes(): | |||||
| def test_projection(): | def test_projection(): | ||||
| """ Test that projection works correctly """ | """ Test that projection works correctly """ | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, "hadamard") | g.act_local_rotation(0, "hadamard") | ||||
| g.measure(0, "pz", 0) | g.measure(0, "pz", 0) | ||||
| assert np.allclose(g.to_state_vector().state, qi.zero) | assert np.allclose(g.to_state_vector().state, qi.zero) | ||||
| # Now project onto |1> | # Now project onto |1> | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, "hadamard") | g.act_local_rotation(0, "hadamard") | ||||
| g.measure(0, "pz", 1) | g.measure(0, "pz", 1) | ||||
| assert np.allclose(g.to_state_vector().state, qi.one) | assert np.allclose(g.to_state_vector().state, qi.one) | ||||
| @@ -3,7 +3,7 @@ from abp.util import xyz | |||||
| from mock import simple_graph | from mock import simple_graph | ||||
| def linear_cluster(n): | def linear_cluster(n): | ||||
| g = GraphState(range(n)) | |||||
| g = GraphState(range(n), vop="hadamard") | |||||
| g.act_circuit([(i, "hadamard") for i in range(n)]) | g.act_circuit([(i, "hadamard") for i in range(n)]) | ||||
| g.act_circuit([((i, i+1), "cz") for i in range(n-1)]) | g.act_circuit([((i, i+1), "cz") for i in range(n-1)]) | ||||
| return g | return g | ||||
| @@ -23,16 +23,16 @@ def test_single_qubit_measurements(): | |||||
| """ Various simple tests of measurements """ | """ Various simple tests of measurements """ | ||||
| # Test that measuring |0> in Z gives 0 | # Test that measuring |0> in Z gives 0 | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| assert g.measure_z(0) == 0, "Measuring |0> in Z gives 0" | assert g.measure_z(0) == 0, "Measuring |0> in Z gives 0" | ||||
| # Test that measuring |1> in Z gives 1 | # Test that measuring |1> in Z gives 1 | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, "px") | g.act_local_rotation(0, "px") | ||||
| assert g.measure_z(0) == 1, "Measuring |1> in Z gives 1" | assert g.measure_z(0) == 1, "Measuring |1> in Z gives 1" | ||||
| # Test that measuring |+> in X gives 0 | # Test that measuring |+> in X gives 0 | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| g.act_local_rotation(0, "hadamard") | g.act_local_rotation(0, "hadamard") | ||||
| assert g.measure_x(0) == 0 | assert g.measure_x(0) == 0 | ||||
| assert g.measure_x(0) == 0, "Measuring |+> in X gives 0" | assert g.measure_x(0) == 0, "Measuring |+> in X gives 0" | ||||
| @@ -44,7 +44,7 @@ def test_single_qubit_measurements(): | |||||
| def test_is_determinate(): | def test_is_determinate(): | ||||
| """ Test whether asking if an outcome was random or determinate works """ | """ Test whether asking if an outcome was random or determinate works """ | ||||
| g = GraphState([0]) | |||||
| g = GraphState([0], vop="hadamard") | |||||
| assert g.measure_z(0, detail=True)["determinate"] == True | assert g.measure_z(0, detail=True)["determinate"] == True | ||||
| assert g.measure_x(0, detail=True)["determinate"] == False | assert g.measure_x(0, detail=True)["determinate"] == False | ||||
| @@ -104,8 +104,8 @@ def test_dumbness(): | |||||
| def test_to_state_vector_single_qubit(): | def test_to_state_vector_single_qubit(): | ||||
| """ Test some single-qubit stuff """ | """ Test some single-qubit stuff """ | ||||
| g = GraphState() | g = GraphState() | ||||
| g.add_node(0) | |||||
| g.add_node(1) | |||||
| g.add_qubit(0) | |||||
| g.add_qubit(1) | |||||
| g.act_local_rotation(0, "hadamard") | g.act_local_rotation(0, "hadamard") | ||||
| g.act_local_rotation(1, "hadamard") | g.act_local_rotation(1, "hadamard") | ||||
| g.act_cz(0, 1) | g.act_cz(0, 1) | ||||