Repository: sympy/sympy

Issue:
qapply does not work for c_part*TensorProduct
The function qapply_Mul returns without doing anything if the argument is of the form c_part*TensorProduct. For example, try qapply with the following expressions:

```
exp1 = TensorProduct(Jz*JzKet(S(2),S(-1))/sqrt(2), Jz*JzKet(S(1)/2,S(1)/2))

exp2 = TensorProduct(Jz*JzKet(S(2),S(1)), Jz*JzKet(S(1)/2,S(1)/2))
```

`qapply(exp1)` does not apply the operators, but `qapply(exp2)` applies the operators.

To make qapply work properly, one should first split the commutative parts from the non-commutative parts. Then qapply should be applied on the non-commutative parts.

Alaska

Original issue for #6143: http://code.google.com/p/sympy/issues/detail?id=3044
Original author: https://code.google.com/u/104202817633480218674/


Discussion:

Patch:
diff --git a/sympy/physics/quantum/qapply.py b/sympy/physics/quantum/qapply.py
index ac7730eaa1..b432b03ee5 100644
--- a/sympy/physics/quantum/qapply.py
+++ b/sympy/physics/quantum/qapply.py
@@ -93,7 +93,7 @@ def qapply(e, **options):
         result = 0
         for arg in e.args:
             result += qapply(arg, **options)
-        return result
+        return result.expand()
 
     # For a Density operator call qapply on its state
     elif isinstance(e, Density):
@@ -111,7 +111,13 @@ def qapply(e, **options):
 
     # We have a Mul where there might be actual operators to apply to kets.
     elif isinstance(e, Mul):
-        result = qapply_Mul(e, **options)
+        c_part, nc_part = e.args_cnc()
+        c_mul = Mul(*c_part)
+        nc_mul = Mul(*nc_part)
+        if isinstance(nc_mul, Mul):
+            result = c_mul*qapply_Mul(nc_mul, **options)
+        else:
+            result = c_mul*qapply(nc_mul, **options)
         if result == e and dagger:
             return Dagger(qapply_Mul(Dagger(e), **options))
         else:


Test patch:
diff --git a/sympy/physics/quantum/tests/test_qapply.py b/sympy/physics/quantum/tests/test_qapply.py
index f9a44f88d9..0009c8c66e 100644
--- a/sympy/physics/quantum/tests/test_qapply.py
+++ b/sympy/physics/quantum/tests/test_qapply.py
@@ -1,4 +1,4 @@
-from sympy import I, Integer, sqrt, symbols
+from sympy import I, Integer, sqrt, symbols, S, Mul
 
 from sympy.physics.quantum.anticommutator import AntiCommutator
 from sympy.physics.quantum.commutator import Commutator
@@ -8,6 +8,7 @@
 from sympy.physics.quantum.operator import Operator
 from sympy.physics.quantum.qapply import qapply
 from sympy.physics.quantum.spin import Jx, Jy, Jz, Jplus, Jminus, J2, JzKet
+from sympy.physics.quantum.tensorproduct import TensorProduct
 from sympy.physics.quantum.state import Ket
 from sympy.physics.quantum.density import Density
 from sympy.physics.quantum.qubit import Qubit
@@ -117,3 +118,10 @@ def test_issue_6073():
 def test_density():
     d = Density([Jz*mo, 0.5], [Jz*po, 0.5])
     assert qapply(d) == Density([-hbar*mo, 0.5], [hbar*po, 0.5])
+
+
+def test_issue3044():
+    expr1 = TensorProduct(Jz*JzKet(S(2),S(-1))/sqrt(2), Jz*JzKet(S(1)/2,S(1)/2))
+    result = Mul(S(-1), S(1)/4, (2**(S(1)/2)), hbar**2)
+    result *= TensorProduct(JzKet(2,-1), JzKet(S(1)/2,S(1)/2))
+    assert qapply(expr1) == result