-
Notifications
You must be signed in to change notification settings - Fork 575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[QAOA] Adds Built-In MaxCut Cost Hamiltonian #718
Conversation
Codecov Report
@@ Coverage Diff @@
## master #718 +/- ##
==========================================
+ Coverage 95.47% 95.48% +0.01%
==========================================
Files 109 110 +1
Lines 6813 6829 +16
==========================================
+ Hits 6505 6521 +16
Misses 308 308
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Just missing usage details
pennylane/qaoa/cost.py
Outdated
find the cut of the graph such that the number of edges crossing the cut is maximized | ||
(see `Cut (graph theory) <https://en.wikipedia.org/wiki/Cut_(graph_theory)>`__). | ||
|
||
Recommended mixer Hamiltonian: ~.qaoa.x_mixer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this! Like a wine pairing in a restaurant menu 🍷 🍝
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work @Lucaman99. My main suggestion is with regard to docstring improvements, but the code and tests look great!
pennylane/qaoa/cost.py
Outdated
r"""A method that builds a QAOA cost Hamiltonian corresponding to the MaxCut problem, for a given graph. | ||
|
||
The goal of the MaxCut problem for a particular graph is to find a partition of nodes into two sets, such | ||
that the number of edges in the graph with endpoints in different sets is maximized. Formally, we wish to | ||
find the cut of the graph such that the number of edges crossing the cut is maximized | ||
(see `Cut (graph theory) <https://en.wikipedia.org/wiki/Cut_(graph_theory)>`__). | ||
|
||
The MaxCut Hamiltonian is defined as: | ||
|
||
.. math:: H_C \ = \ \frac{1}{2} \displaystyle\sum_{(i, j) \in E(G)} Z_i Z_j \ - \ \mathbb{I} | ||
|
||
where :math:`G` is some graph and :math:`Z_i` and :math:`Z_j` are the Pauli-Z operators on the :math:`i`-th and | ||
:math:`j`-th wire respectively. | ||
|
||
As one can check, the states :math:`|01\rangle` and | ||
:math:`|10\rangle` (representing a cut) both have eigenvalues with respect to :math:`H_C` of :math:`-1`. One can | ||
also see that :math:`|00\rangle` and :math:`|11\rangle`` (no cut) have eigenvalues of :math:`0`. | ||
Thus, for a given basis state, with each entry of the state vector representing a node of the graph, and :math:`0` and | ||
:math:`1` being the labels of the two partitioned sets, the MaxCut cost Hamiltonian effectively counts the number | ||
of edges crossing the cut and multiplies it by :math:`-1`. Upon minimization, we are left with the basis | ||
state that yields the maximum cut. | ||
|
||
Recommended mixer Hamiltonian: ~.qaoa.x_mixer | ||
|
||
Recommended initialization circuit: Even superposition over all basis states | ||
|
||
Args: | ||
graph (nx.Graph) A graph defining the pairs of wires on which each term of the Hamiltonian acts. | ||
|
||
Returns: | ||
~.Hamiltonian: | ||
|
||
.. UsageDetails:: | ||
|
||
The MaxCut cost Hamiltonian can be called as follows: | ||
|
||
.. code-block:: python | ||
|
||
from pennylane import qaoa | ||
from networkx import Graph | ||
|
||
graph = Graph([(0, 1), (1, 2)]) | ||
cost_h = qaoa.MaxCut(graph) | ||
|
||
>>> print(cost_h) | ||
(-0.5) [I0 I1] + (0.5) [Z0 Z1] + (-0.5) [I1 I2] + (0.5) [Z1 Z2] | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Lucaman99, the docstring might need some work, so that there is a better flow between essential details, examples, and technical details.
I suggest something similar to the following:
Returns the QAOA cost Hamiltonian corresponding to the MaxCut problem, for a given graph.
The goal of the MaxCut problem for a particular graph is to find a partition of nodes into two sets,
such that the number of edges in the graph with endpoints in different sets is maximized. Formally,
we wish to find the `cut of the graph <https://en.wikipedia.org/wiki/Cut_(graph_theory)>`__ such
that the number of edges crossing the cut is maximized.
The MaxCut Hamiltonian is defined as:
.. math:: H_C \ = \ \frac{1}{2} \displaystyle\sum_{(i, j) \in E(G)} Z_i Z_j \ - \ \mathbb{I}
where :math:`G` is some graph and :math:`Z_i` and :math:`Z_j` are the Pauli-Z operators on the
:math:`i`-th and :math:`j`-th wire respectively.
*Recommended mixer Hamiltonian:* :func:`~.qaoa.x_mixer`
*Recommended initialization circuit:* Even superposition over all basis states
Args:
graph (nx.Graph): a graph defining the pairs of wires on which each term of the Hamiltonian acts
Returns:
.Hamiltonian:
**Example**
>>> graph = nx.Graph([(0, 1), (1, 2)])
>>> cost_h = qml.qaoa.MaxCut(graph) print(cost_h)
(-0.5) [I0 I1] + (0.5) [Z0 Z1] + (-0.5) [I1 I2] + (0.5) [Z1 Z2]
.. UsageDetails::
<For more advanced examples, advanced usage details, and additional technical details>
I based this on the documentation guidelines. Breaking this down part by part:
-
The docstring summary: 'A method that builds' is redundant, and likely to be confused with class methods. Better to just start with 'Returns ...' or 'Creates...'.
-
Rather than using '(see )', it flows a bit better to have the actual term ('cut of the graph') link to the resource. Think of how Wikipedia articles do it 🙂 Aside from this, the introduction and latex descpription are great.
-
The paragraph that begins 'As one can check, ..' is more of an aside, and not essential for the top level docstring. I would suggest moving this down into 'Usage details'.
-
To create links to code objects in general text, you need to use Sphinx domains, e.g.,
:class:`~.BaseQNode`, :func:`~.StronglyEntanglingLayers`
The only exception is on the left hand side of the colon in the
Args:
andReturns:
sections. -
~
is a formatting specifier for links (it instructs Sphinx to display only the name of the object in the link, not the full absolute path. E.g.,.Hamiltonian
would display aspennylane.Hamiltonian
, whereas~.Hamiltonian
will display just asHamiltonian
. Since it is only for formatting, it shouldn't be used when specifying types on the left hand side of the colon in theArgs:
andReturns:
sections. -
All docstrings should include a top-level minimal example below
Returns:
. This example can assume standard imports (so no need to writeimport networkx as nx
andimport pennylane as qml
), and should show a basic working use-case of the function. This example should always use Python console syntax, and not a.. code-block::
. -
Finally, the 'Usage Details' section is optional, but the place to put any more advanced technical details, usage details, and bigger examples. For example, a lot of the templates use the UsageDetails section to add more usage examples. This section is collapsed by default, leaving only the top-level example visible, to avoid overwhelming the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@josh146 I see! In that case, I think it should be Ok to just have an example and omit the "Usage Details"!
|
||
for node1, node2 in edges: | ||
|
||
obs.append(qml.Identity(node1) @ qml.Identity(node2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something that just crossed my mind, is that if/when the Hamiltonian is being used as an observable (not for time evolution), the expectation value of these terms is simply <I>=1
, and we don't even need to create a QNode for this term.
On the other hand, it will be needed for doing time evolution...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's right, we thought it was worthwhile since the Hamiltonian may be used in both regards.
Co-authored-by: Josh Izaac <josh146@gmail.com>
Co-authored-by: Josh Izaac <josh146@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔥 🏅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Lucaman99, looks good and have left some comments.
tests/test_qaoa.py
Outdated
[ | ||
( | ||
Graph([(0, 1), (1, 2)]), | ||
qml.Hamiltonian( | ||
[-0.5, 0.5, -0.5, 0.5], | ||
[ | ||
qml.Identity(0) @ qml.Identity(1), | ||
qml.PauliZ(0) @ qml.PauliZ(1), | ||
qml.Identity(1) @ qml.Identity(2), | ||
qml.PauliZ(1) @ qml.PauliZ(2), | ||
], | ||
), | ||
), | ||
( | ||
Graph((np.array([0, 1]), np.array([1, 2]), np.array([0, 2]))), | ||
qml.Hamiltonian( | ||
[-0.5, 0.5, -0.5, 0.5, -0.5, 0.5], | ||
[ | ||
qml.Identity(0) @ qml.Identity(1), | ||
qml.PauliZ(0) @ qml.PauliZ(1), | ||
qml.Identity(0) @ qml.Identity(2), | ||
qml.PauliZ(0) @ qml.PauliZ(2), | ||
qml.Identity(1) @ qml.Identity(2), | ||
qml.PauliZ(1) @ qml.PauliZ(2), | ||
], | ||
), | ||
), | ||
( | ||
graph, | ||
qml.Hamiltonian( | ||
[-0.5, 0.5, -0.5, 0.5], | ||
[ | ||
qml.Identity(0) @ qml.Identity(1), | ||
qml.PauliZ(0) @ qml.PauliZ(1), | ||
qml.Identity(1) @ qml.Identity(2), | ||
qml.PauliZ(1) @ qml.PauliZ(2), | ||
], | ||
), | ||
), | ||
], | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor comment:
It might be nice to build this up earlier in TestCostHamiltonians
and then pass to parametrize()
, e.g.,
- Create graphs
- Create hamiltonians
- Create list of pairs
^ Just might help with readability.
Context:
Part of the new PennyLane QAOA functionality.
Description of the Change:
Adds a built-in MaxCut cost Hamiltonian and tests.
Benefits:
Possible Drawbacks:
Related GitHub Issues: