Repository: PennyLaneAI/pennylane

Issue:
CV gradients - Heisenberg derivatives
Hey everyone. Maybe we can move some of the discussions out of the paper and to here for now? At least as far as writing equations allows...

Christian, your comment on passing the derivative past a non-Gaussian circuit in the Heisenberg and "circuit" picture is very useful. I have not even thought about the case of U being non-Gaussian and something else than homodyne detection, I was more worried about and \hat{O} = \hat{x} and V being non-Gaussian. Would be interested to know if the same thing appears.

This is a really cool lesson in thorough Heisenberg calculus!


Discussion:
@cgogolin and @smite, great that you implemented Christian's trick and to know these things work. Is there any gate for which we can find a useful decomposition? In fact, either a decomposition of the generator into implementable projectors, or a decomposition of the generator into unitaries (from there we could use some tricks I think). I tried a million times for actual gates, but could never make it work. Maybe stuck in the same thoughts.
  
Thanks! But please check carefully that I didn't make stupid mistakes. It has been a terrible week and I am not as awake as I would like to be... 
I left a reply in the new "discussion" tex file. Think I know what went wrong, and indeed, this answers my question if we can take non-Gaussian circuits (to the negative for the existing equations, but maybe there are others) ! 

Resolving patch:
diff --git a/pennylane/transforms/hamiltonian_expand.py b/pennylane/transforms/hamiltonian_expand.py
--- a/pennylane/transforms/hamiltonian_expand.py
+++ b/pennylane/transforms/hamiltonian_expand.py
@@ -157,10 +157,21 @@ def hamiltonian_expand(tape, group=True):
             tapes.append(new_tape)
 
         def processing_fn(res_groupings):
-            dot_products = [
-                qml.math.dot(r_group, c_group)
-                for c_group, r_group in zip(coeff_groupings, res_groupings)
-            ]
+            if qml.active_return():
+                dot_products = [
+                    qml.math.dot(
+                        qml.math.reshape(
+                            qml.math.convert_like(r_group, c_group), qml.math.shape(c_group)
+                        ),
+                        c_group,
+                    )
+                    for c_group, r_group in zip(coeff_groupings, res_groupings)
+                ]
+            else:
+                dot_products = [
+                    qml.math.dot(r_group, c_group)
+                    for c_group, r_group in zip(coeff_groupings, res_groupings)
+                ]
             return qml.math.sum(qml.math.stack(dot_products), axis=0)
 
         return tapes, processing_fn


Test patch:
diff --git a/tests/returntypes/test_autograd_qnode_new.py b/tests/returntypes/test_autograd_qnode_new.py
--- a/tests/returntypes/test_autograd_qnode_new.py
+++ b/tests/returntypes/test_autograd_qnode_new.py
@@ -1471,7 +1471,6 @@ def circuit(data, weights, coeffs):
             ]
             assert np.allclose(grad2_w_c, expected)
 
-    @pytest.mark.xfail(reason="Update expand hamiltonian processing function.")
     @pytest.mark.slow
     @pytest.mark.parametrize("max_diff", [1, 2])
     def test_hamiltonian_expansion_finite_shots(