Repository: PennyLaneAI/pennylane
Pull request #981 (2020-12-29 19:24:50)

print of vqe.hamiltonian sorts terms by number of wires and coefficients
This is a minor aesthetic change to improve readability on printing objects of type `pennylane.vqe.vqe.Hamiltonian`.

Currently, the H2 hamiltonian from the [VQE tutorial](https://pennylane.ai/qml/demos/tutorial_vqe.html) prints as:
```
(-0.04207897647782188) [I0]
+ (0.17771287465139934) [Z0]
+ (0.1777128746513993) [Z1]
+ (-0.24274280513140484) [Z2]
+ (-0.24274280513140484) [Z3]
+ (0.17059738328801055) [Z0 Z1]
+ (0.04475014401535161) [Y0 X1 X2 Y3]
+ (-0.04475014401535161) [Y0 Y1 X2 X3]
+ (-0.04475014401535161) [X0 X1 Y2 Y3]
+ (0.04475014401535161) [X0 Y1 Y2 X3]
+ (0.12293305056183801) [Z0 Z2]
+ (0.1676831945771896) [Z0 Z3]
+ (0.1676831945771896) [Z1 Z2]
+ (0.12293305056183801) [Z1 Z3]
+ (0.176276408043196) [Z2 Z3]
```

With this change, the terms will be sorted in the number of wires, and a tab `\t` attempts to line up the operation terms.
```
  (-0.24274280513140484)	[Z2]
+ (-0.24274280513140484)	[Z3]
+ (-0.04207897647782188)	[I0]
+ (0.1777128746513993)	[Z1]
+ (0.17771287465139934)	[Z0]
+ (0.12293305056183801)	[Z0 Z2]
+ (0.12293305056183801)	[Z1 Z3]
+ (0.1676831945771896)	[Z0 Z3]
+ (0.1676831945771896)	[Z1 Z2]
+ (0.17059738328801055)	[Z0 Z1]
+ (0.176276408043196)	[Z2 Z3]
+ (-0.04475014401535161)	[Y0 Y1 X2 X3]
+ (-0.04475014401535161)	[X0 X1 Y2 Y3]
+ (0.04475014401535161)	[Y0 X1 X2 Y3]
+ (0.04475014401535161)	[X0 Y1 Y2 X3]
```

This improves the user's ability to compare like terms. For example, now I can much more easily see that `[Z0 Z2]` and `[Z1 Z3]` have the same coefficient.

This new function <b>doesn't</b> distinguish trivial wires acted upon by the identity.  For example, after sorting by the coefficient, the identity term gets mixed into the single wire terms. Fixing that would add more complexity to a fairly simple function, so I don't know if it's worth figuring that out.



github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [.github/CHANGELOG.md](/PennyLaneAI/pennylane/blob/master/.github/CHANGELOG.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981?src=pr&el=h1) Report
> Merging [#981](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981?src=pr&el=desc) (edeb9cd) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/36c3bfadd0e741b5f101775b422dc1f626a76f4b?el=desc) (36c3bfa) will **decrease** coverage by `0.01%`.
> The diff coverage is `0.00%`.

[![Impacted file tree graph](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981/graphs/tree.svg?width=650&height=150&src=pr&token=9S3YzlUgGk)](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #981      +/-   ##
==========================================
- Coverage   97.82%   97.80%   -0.02%     
==========================================
  Files         150      150              
  Lines       10500    10502       +2     
==========================================
  Hits        10272    10272              
- Misses        228      230       +2     
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pennylane/vqe/vqe.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981/diff?src=pr&el=tree#diff-cGVubnlsYW5lL3ZxZS92cWUucHk=) | `93.78% <0.00%> (-0.99%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981?src=pr&el=footer). Last update [36c3bfa...edeb9cd](https://codecov.io/gh/PennyLaneAI/pennylane/pull/981?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

albi3ro: Will wait on Issue #982 to write up the tests.
albi3ro: Just updated this to just get it out of the way and clear the backlog.
josh146: Hi @albi3ro, just double checking the status of this PR - is it ready for re-review, is it still WIP, or has it been superseded?
albi3ro: @josh146 I can't even find what change you requested anymore, but this should *finally*  be good to merge in.

Patch:
diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md
index dd27d23e4..357fdab7a 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -648,6 +648,9 @@
   [RX(0, wires=[0]), RZ(2, wires=[1])]
   ```
 
+* When printing `qml.Hamiltonian` objects, the terms are sorted by number of wires followed by coefficients.
+  [(#981)](https://github.com/PennyLaneAI/pennylane/pull/981)
+
 <h3>Breaking changes</h3>
 
 * Devices do not have an `analytic` argument or attribute anymore. 
@@ -759,7 +762,8 @@
 This release contains contributions from (in alphabetical order):
 
 Juan Miguel Arrazola, Thomas Bromley, Olivia Di Matteo, Kyle Godbey, Diego Guala, Josh Izaac,
-Daniel Polatajko, Chase Roberts, Sankalp Sanand, Pritish Sehzpaul, Maria Schuld, Antal Száva.
+Christina Lee, Daniel Polatajko, Chase Roberts, Sankalp Sanand, Pritish Sehzpaul, Maria Schuld,
+Antal Száva.
 
 # Release 0.14.1 (current release)
 
diff --git a/pennylane/vqe/vqe.py b/pennylane/vqe/vqe.py
index d034b3976..facae5920 100644
--- a/pennylane/vqe/vqe.py
+++ b/pennylane/vqe/vqe.py
@@ -172,9 +172,12 @@ class Hamiltonian:
         # Lambda function that formats the wires
         wires_print = lambda ob: "'".join(map(str, ob.wires.tolist()))
 
+        paired_coeff_obs = list(zip(self.coeffs, self.ops))
+        paired_coeff_obs.sort(key=lambda pair: (len(pair[1].wires), pair[0]))
+
         terms_ls = []
 
-        for i, obs in enumerate(self.ops):
+        for coeff, obs in paired_coeff_obs:
 
             if isinstance(obs, Tensor):
                 obs_strs = [f"{OBS_MAP.get(ob.name, ob.name)}{wires_print(ob)}" for ob in obs.obs]
@@ -182,11 +185,11 @@ class Hamiltonian:
             elif isinstance(obs, Observable):
                 ob_str = f"{OBS_MAP.get(obs.name, obs.name)}{wires_print(obs)}"
 
-            term_str = f"({self.coeffs[i]}) [{ob_str}]"
+            term_str = f"({coeff}) [{ob_str}]"
 
             terms_ls.append(term_str)
 
-        return "\n+ ".join(terms_ls)
+        return "  " + "\n+ ".join(terms_ls)
 
     def _obs_data(self):
         r"""Extracts the data from a Hamiltonian and serializes it in an order-independent fashion.


Test patch:
diff --git a/tests/test_vqe.py b/tests/test_vqe.py
index ccd7dee57..3e3b01109 100644
--- a/tests/test_vqe.py
+++ b/tests/test_vqe.py
@@ -79,17 +79,17 @@ valid_hamiltonians = [
 ]
 
 valid_hamiltonians_str = [
-    "(1.0) [Hermitian0'1]",
-    "(-0.8) [Z0]",
-    "(0.6) [X0 X1]",
-    "(0.5) [X0]\n+ (-1.6) [Y1]",
-    "(0.5) [X1]\n+ (-1.6) [Y1]",
-    "(0.5) [Xa]\n+ (-1.6) [Yb]",
-    "(1.1) [X0]\n+ (-0.4) [Hermitian2]\n+ (0.333) [Z2]",
-    "(-0.4) [Hermitian0'2]\n+ (0.15) [Z1]",
-    "(1.5) [Z0]\n+ (2.0) [Y2]",
-    "(-0.1) [Hermitian0'1]\n+ (0.5) [Y0]",
-    "(0.5) [X0]\n+ (1.2) [X0 X1]",
+    "  (1.0) [Hermitian0'1]",
+    "  (-0.8) [Z0]",
+    "  (0.6) [X0 X1]",
+    "  (-1.6) [Y1]\n+ (0.5) [X0]",
+    "  (-1.6) [Y1]\n+ (0.5) [X1]",
+    "  (-1.6) [Yb]\n+ (0.5) [Xa]",
+    "  (-0.4) [Hermitian2]\n+ (0.333) [Z2]\n+ (1.1) [X0]",
+    "  (0.15) [Z1]\n+ (-0.4) [Hermitian0'2]",
+    "  (1.5) [Z0]\n+ (2.0) [Y2]",
+    "  (0.5) [Y0]\n+ (-0.1) [Hermitian0'1]",
+    "  (0.5) [X0]\n+ (1.2) [X0 X1]",
 ]
 
 invalid_hamiltonians = [