Skip to content

Commit

Permalink
Merge pull request sympy#24164 from Costor/No_Ket_Op
Browse files Browse the repository at this point in the history
Fix the Ket*Op -> Op*Ket Bug in qapply and _apply_operator
  • Loading branch information
sylee957 authored Oct 24, 2022
2 parents 2e5f03f + 67edb10 commit 6967475
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 17 deletions.
4 changes: 2 additions & 2 deletions sympy/physics/quantum/boson.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def _eval_hilbert_space(cls, label):
def _eval_innerproduct_BosonFockBra(self, bra, **hints):
return KroneckerDelta(self.n, bra.n)

def _apply_operator_BosonOp(self, op, **options):
def _apply_from_right_to_BosonOp(self, op, **options):
if op.is_annihilation:
return sqrt(self.n) * BosonFockKet(self.n - 1)
else:
Expand Down Expand Up @@ -223,7 +223,7 @@ def _eval_innerproduct_BosonCoherentBra(self, bra, **hints):
else:
return exp(-(abs(self.alpha)**2 + abs(bra.alpha)**2 - 2 * conjugate(bra.alpha) * self.alpha)/2)

def _apply_operator_BosonOp(self, op, **options):
def _apply_from_right_to_BosonOp(self, op, **options):
if op.is_annihilation:
return self.alpha * self
else:
Expand Down
2 changes: 1 addition & 1 deletion sympy/physics/quantum/fermion.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def _eval_hilbert_space(cls, label):
def _eval_innerproduct_FermionFockBra(self, bra, **hints):
return KroneckerDelta(self.n, bra.n)

def _apply_operator_FermionOp(self, op, **options):
def _apply_from_right_to_FermionOp(self, op, **options):
if op.is_annihilation:
if self.n == 1:
return FermionFockKet(0)
Expand Down
10 changes: 5 additions & 5 deletions sympy/physics/quantum/pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,25 +457,25 @@ def _eval_hilbert_space(cls, label):
def _eval_innerproduct_SigmaZBra(self, bra, **hints):
return KroneckerDelta(self.n, bra.n)

def _apply_operator_SigmaZ(self, op, **options):
def _apply_from_right_to_SigmaZ(self, op, **options):
if self.n == 0:
return self
else:
return S.NegativeOne * self

def _apply_operator_SigmaX(self, op, **options):
def _apply_from_right_to_SigmaX(self, op, **options):
return SigmaZKet(1) if self.n == 0 else SigmaZKet(0)

def _apply_operator_SigmaY(self, op, **options):
def _apply_from_right_to_SigmaY(self, op, **options):
return I * SigmaZKet(1) if self.n == 0 else (-I) * SigmaZKet(0)

def _apply_operator_SigmaMinus(self, op, **options):
def _apply_from_right_to_SigmaMinus(self, op, **options):
if self.n == 0:
return SigmaZKet(1)
else:
return S.Zero

def _apply_operator_SigmaPlus(self, op, **options):
def _apply_from_right_to_SigmaPlus(self, op, **options):
if self.n == 0:
return S.Zero
else:
Expand Down
2 changes: 1 addition & 1 deletion sympy/physics/quantum/qapply.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def qapply_Mul(e, **options):
result = lhs._apply_operator(rhs, **options)
except (NotImplementedError, AttributeError):
try:
result = rhs._apply_operator(lhs, **options)
result = rhs._apply_from_right_to(lhs, **options)
except (NotImplementedError, AttributeError):
if isinstance(lhs, BraBase) and isinstance(rhs, KetBase):
result = InnerProduct(lhs, rhs)
Expand Down
12 changes: 6 additions & 6 deletions sympy/physics/quantum/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,26 +254,26 @@ def _eval_innerproduct(self, bra, **hints):
"""
return dispatch_method(self, '_eval_innerproduct', bra, **hints)

def _apply_operator(self, op, **options):
"""Apply an Operator to this Ket.
def _apply_from_right_to(self, op, **options):
"""Apply an Operator to this Ket as Operator*Ket
This method will dispatch to methods having the format::
``def _apply_operator_OperatorName(op, **options):``
``def _apply_from_right_to_OperatorName(op, **options):``
Subclasses should define these methods (one for each OperatorName) to
teach the Ket how operators act on it.
teach the Ket how to implement OperatorName*Ket
Parameters
==========
op : Operator
The Operator that is acting on the Ket.
The Operator that is acting on the Ket as op*Ket
options : dict
A dict of key/value pairs that control how the operator is applied
to the Ket.
"""
return dispatch_method(self, '_apply_operator', op, **options)
return dispatch_method(self, '_apply_from_right_to', op, **options)


class BraBase(StateBase):
Expand Down
21 changes: 19 additions & 2 deletions sympy/physics/quantum/tests/test_qapply.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
from sympy.physics.quantum.commutator import Commutator
from sympy.physics.quantum.constants import hbar
from sympy.physics.quantum.dagger import Dagger
from sympy.physics.quantum.gate import H
from sympy.physics.quantum.gate import H, XGate
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
from sympy.physics.quantum.qubit import Qubit, QubitBra
from sympy.physics.quantum.boson import BosonOp, BosonFockKet, BosonFockBra


Expand Down Expand Up @@ -128,3 +128,20 @@ def test_issue3044():
result = Mul(S.NegativeOne, Rational(1, 4), 2**S.Half, hbar**2)
result *= TensorProduct(JzKet(2,-1), JzKet(S.Half,S.Half))
assert qapply(expr1) == result


# Issue 24158: Tests whether qapply incorrectly evaluates some ket*op as op*ket
def test_issue24158_ket_times_op():
P = BosonFockKet(0) * BosonOp("a") # undefined term
# Does lhs._apply_operator_BosonOp(rhs) still evaluate ket*op as op*ket?
assert qapply(P) == P # qapply(P) -> BosonOp("a")*BosonFockKet(0) = 0 before fix
P = Qubit(1) * XGate(0) # undefined term
# Does rhs._apply_operator_Qubit(lhs) still evaluate ket*op as op*ket?
assert qapply(P) == P # qapply(P) -> Qubit(0) before fix
P1 = Mul(QubitBra(0), Mul(QubitBra(0), Qubit(0)), XGate(0)) # legal expr <0| * (<1|*|1>) * X
assert qapply(P1) == QubitBra(0) * XGate(0) # qapply(P1) -> 0 before fix
P1 = qapply(P1, dagger = True) # unsatisfactorily -> <0|*X(0), expect <1| since dagger=True
assert qapply(P1, dagger = True) == QubitBra(1) # qapply(P1, dagger=True) -> 0 before fix
P2 = QubitBra(0) * QubitBra(0) * Qubit(0) * XGate(0) # 'forgot' to set brackets
P2 = qapply(P2, dagger = True) # unsatisfactorily -> <0|*X(0), expect <1| since dagger=True
assert qapply(P2, dagger = True) == QubitBra(1) # qapply(P1) -> 0 before fix

0 comments on commit 6967475

Please sign in to comment.