diff --git a/README.md b/README.md index f618caa..491ecaf 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ $ pip install --user abp Or clone and install: ```shell -$ git clone https://github.com/peteshadbolt/abp +$ git clone https://github.com/peteshadbolt/abp.git $ python setup.py install --user ``` diff --git a/abp/graphstate.py b/abp/graphstate.py index 736873e..31b2d3e 100644 --- a/abp/graphstate.py +++ b/abp/graphstate.py @@ -15,7 +15,7 @@ class GraphState(object): """ def __init__(self, nodes=[], deterministic=False): - """ Construct a GraphState. + """ Construct a ``GraphState`` :param nodes: An iterable of nodes used to construct the 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. @@ -26,10 +26,18 @@ class GraphState(object): self.deterministic = deterministic def add_node(self, node, **kwargs): - """ Add a node + """ Add a node. :param node: The name of the node, e.g. ``9``, ``start`` :type node: Any hashable type + :param kwargs: Any extra node attributes + + Example of using node attributes :: + + >>> g.add_node(0, label="fred", position=(1,2,3)) + >>> g.node[0]["label"] + fred + """ assert not node in self.node, "Node {} already exists".format(v) self.adj[node] = {} @@ -37,18 +45,16 @@ class GraphState(object): self.node[node].update(kwargs) def add_nodes(self, nodes): - """ Add a buncha nodes """ + """ Add many nodes in one shot. """ for n in nodes: self.add_node(n) def act_circuit(self, circuit): - """ Run many gates in one call + """ Run many gates in one call. - :param circuit: An iterable containing tuples of the form ``(node, operation)``. - If ``operation`` is a name for a local operation (e.g. ``6``, ``hadamard``) then that operation is performed on ``node``. - If ``operation`` is ``"cz"`` then a CZ is performed on the two nodes in ``node. + :param circuit: An iterable containing tuples of the form ``(node, operation)``. If ``operation`` is a name for a local operation (e.g. ``6``, ``hadamard``) then that operation is performed on ``node``. If ``operation`` is ``cz`` then a CZ is performed on the two nodes in ``node``. - For example:: + Example (makes a Bell pair):: >>> g.act_circuit([(0, "hadamard"), (1, "hadamard"), ((0, 1), "cz")]) @@ -160,7 +166,15 @@ class GraphState(object): self._toggle_edge(a, b) def measure(self, node, basis, force=None): - """ Measure in an arbitrary basis """ + """ Measure in an arbitrary basis + + :param node: The name of the qubit to measure. + :param basis: The basis in which to measure. + :type basis: :math:`\in` ``{"px", "py", "pz"}`` + :param force: Measurements in quantum mechanics are probabilistic. If you want to force a particular outcome, use the ``force``. + :type force: boolean + + """ basis = clifford.by_name[basis] ha = clifford.conjugation_table[self.node[node]["vop"]] basis, phase = clifford.conjugate(basis, ha) @@ -287,10 +301,16 @@ class GraphState(object): return s def to_json(self, stringify=False): - """ - Convert the graph to JSON form. - JSON keys must be strings, But sometimes it is useful to have - a JSON-like object whose keys are tuples! + """ Convert the graph to JSON-like form. + + :param stringify: JSON keys must be strings, But sometimes it is useful to have a JSON-like object whose keys are tuples. + + If you want to dump a graph do disk, do something like this:: + + >>> import json + >>> with open("graph.json") as f: + json.dump(graph.to_json(True), f) + """ if stringify: node = {str(key): value for key, value in self.node.items()} @@ -306,7 +326,18 @@ class GraphState(object): # TODO def to_state_vector(self): - """ Get the full state vector """ + """ Get the full state vector corresponding to this stabilizer state. Useful for debugging, interface with other simulators. + + The output state is represented as a ``abp.qi.CircuitModel``:: + + >>> print g.to_state_vector() + |00000>: 0.18+0.00j + |00001>: 0.18+0.00j ... + + .. warning:: + Obviously this method becomes very slow for more than about ten qubits! + + """ if len(self.node) > 15: raise ValueError("Cannot build state vector: too many qubits") state = qi.CircuitModel(len(self.node)) @@ -319,7 +350,8 @@ class GraphState(object): return state def to_stabilizer(self): - """ Get the stabilizer of this graph """ + """ Get the stabilizer tableau. Work in progress! + """ return output = {a: {} for a in self.node} for a, b in it.product(self.node, self.node): diff --git a/doc/Makefile b/doc/Makefile index 43344dc..35fe2d9 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -190,3 +190,7 @@ pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +deploy: + scp -r ./_build/html/* rpi:abp/ + diff --git a/doc/conf.py b/doc/conf.py index 8afba1d..d27325a 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -173,13 +173,13 @@ html_static_path = ['_static'] #html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +html_show_copyright = False # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the diff --git a/doc/index.rst b/doc/index.rst index 2db3be3..0920514 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -16,6 +16,8 @@ This is the documentation for ``abp``. It's a work in progress. That means that you can make quantum states of thousands of qubits, perform any sequence of Clifford operations, and measure in any of :math:`\{\sigma_x, \sigma_y, \sigma_z\}`. It should do thousands of qubits without much trouble. +.. image:: ../examples/demo.gif + Installing ---------------------------- @@ -58,9 +60,6 @@ It's pretty easy to build a graph state, act some gates, and do measurements:: 2: IA (1,3) 3: IA (2,4) 4: IA (3,) - >>> print g.to_state_vector() - |00000>: 0.18+0.00j - |00001>: 0.18+0.00j ... >>> g.measure(2, "px") 0 >>> print g @@ -70,7 +69,7 @@ It's pretty easy to build a graph state, act some gates, and do measurements:: 3: ZA (0,1,4) 4: IA (3,) -GraphState +Working with GraphStates ------------------------- The ``abp.GraphState`` class is your main interface to ``abp``. @@ -90,15 +89,57 @@ Here follows complete documentation .. automethod:: abp.GraphState.act_cz - .. automethod:: abp.GraphState.add_edge + .. automethod:: abp.GraphState.act_circuit + + .. automethod:: abp.GraphState.measure + + .. automethod:: abp.GraphState.to_json + + .. automethod:: abp.GraphState.to_state_vector + + .. automethod:: abp.GraphState.to_stabilizer + +The Clifford group +---------------------- + +Visualization +---------------------- + +``abp`` comes with a tool to visualize graph states in a WebGL compatible web browser (Chrome, Firefox, Safari etc). It uses a client-server architecture. + +First, run ``abpserver`` in a terminal: + +.. code-block:: bash + + $ abpserver + Listening on port 5000 for clients.. + +Then browse to ``http://localhost:5001/`` (in some circumstances ``abp`` will automatically pop a browser window). + +Now, in another terminal, use ``abp.fancy.GraphState`` to run a Clifford circuit:: + + >>> from abp.fancy import GraphState + >>> g = GraphState(10) + >>> g = GraphState(range(10)) + >>> for i in range(10): + ... g.act_hadamard(i) + ... + >>> g.update() + >>> for i in range(9): + ... g.act_cz(i, i+1) + ... + >>> g.update() + ``` - .. automethod:: abp.GraphState.add_edges +And you should see a 3D visualization of the state. - .. automethod:: abp.GraphState.del_edge +.. image:: ../examples/viz.png Reference ---------------------------- +More detailed docs are available here: + * :ref:`genindex` * :ref:`modindex` * :ref:`search`