anticommutator.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. """The anti-commutator: ``{A,B} = A*B + B*A``."""
  2. from sympy.core.expr import Expr
  3. from sympy.core.kind import KindDispatcher
  4. from sympy.core.mul import Mul
  5. from sympy.core.numbers import Integer
  6. from sympy.core.singleton import S
  7. from sympy.printing.pretty.stringpict import prettyForm
  8. from sympy.physics.quantum.dagger import Dagger
  9. from sympy.physics.quantum.kind import _OperatorKind, OperatorKind
  10. __all__ = [
  11. 'AntiCommutator'
  12. ]
  13. #-----------------------------------------------------------------------------
  14. # Anti-commutator
  15. #-----------------------------------------------------------------------------
  16. class AntiCommutator(Expr):
  17. """The standard anticommutator, in an unevaluated state.
  18. Explanation
  19. ===========
  20. Evaluating an anticommutator is defined [1]_ as: ``{A, B} = A*B + B*A``.
  21. This class returns the anticommutator in an unevaluated form. To evaluate
  22. the anticommutator, use the ``.doit()`` method.
  23. Canonical ordering of an anticommutator is ``{A, B}`` for ``A < B``. The
  24. arguments of the anticommutator are put into canonical order using
  25. ``__cmp__``. If ``B < A``, then ``{A, B}`` is returned as ``{B, A}``.
  26. Parameters
  27. ==========
  28. A : Expr
  29. The first argument of the anticommutator {A,B}.
  30. B : Expr
  31. The second argument of the anticommutator {A,B}.
  32. Examples
  33. ========
  34. >>> from sympy import symbols
  35. >>> from sympy.physics.quantum import AntiCommutator
  36. >>> from sympy.physics.quantum import Operator, Dagger
  37. >>> x, y = symbols('x,y')
  38. >>> A = Operator('A')
  39. >>> B = Operator('B')
  40. Create an anticommutator and use ``doit()`` to multiply them out.
  41. >>> ac = AntiCommutator(A,B); ac
  42. {A,B}
  43. >>> ac.doit()
  44. A*B + B*A
  45. The commutator orders it arguments in canonical order:
  46. >>> ac = AntiCommutator(B,A); ac
  47. {A,B}
  48. Commutative constants are factored out:
  49. >>> AntiCommutator(3*x*A,x*y*B)
  50. 3*x**2*y*{A,B}
  51. Adjoint operations applied to the anticommutator are properly applied to
  52. the arguments:
  53. >>> Dagger(AntiCommutator(A,B))
  54. {Dagger(A),Dagger(B)}
  55. References
  56. ==========
  57. .. [1] https://en.wikipedia.org/wiki/Commutator
  58. """
  59. is_commutative = False
  60. _kind_dispatcher = KindDispatcher("AntiCommutator_kind_dispatcher", commutative=True)
  61. @property
  62. def kind(self):
  63. arg_kinds = (a.kind for a in self.args)
  64. return self._kind_dispatcher(*arg_kinds)
  65. def __new__(cls, A, B):
  66. r = cls.eval(A, B)
  67. if r is not None:
  68. return r
  69. obj = Expr.__new__(cls, A, B)
  70. return obj
  71. @classmethod
  72. def eval(cls, a, b):
  73. if not (a and b):
  74. return S.Zero
  75. if a == b:
  76. return Integer(2)*a**2
  77. if a.is_commutative or b.is_commutative:
  78. return Integer(2)*a*b
  79. # [xA,yB] -> xy*[A,B]
  80. ca, nca = a.args_cnc()
  81. cb, ncb = b.args_cnc()
  82. c_part = ca + cb
  83. if c_part:
  84. return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb)))
  85. # Canonical ordering of arguments
  86. #The Commutator [A,B] is on canonical form if A < B.
  87. if a.compare(b) == 1:
  88. return cls(b, a)
  89. def doit(self, **hints):
  90. """ Evaluate anticommutator """
  91. # Keep the import of Operator here to avoid problems with
  92. # circular imports.
  93. from sympy.physics.quantum.operator import Operator
  94. A = self.args[0]
  95. B = self.args[1]
  96. if isinstance(A, Operator) and isinstance(B, Operator):
  97. try:
  98. comm = A._eval_anticommutator(B, **hints)
  99. except NotImplementedError:
  100. try:
  101. comm = B._eval_anticommutator(A, **hints)
  102. except NotImplementedError:
  103. comm = None
  104. if comm is not None:
  105. return comm.doit(**hints)
  106. return (A*B + B*A).doit(**hints)
  107. def _eval_adjoint(self):
  108. return AntiCommutator(Dagger(self.args[0]), Dagger(self.args[1]))
  109. def _sympyrepr(self, printer, *args):
  110. return "%s(%s,%s)" % (
  111. self.__class__.__name__, printer._print(
  112. self.args[0]), printer._print(self.args[1])
  113. )
  114. def _sympystr(self, printer, *args):
  115. return "{%s,%s}" % (
  116. printer._print(self.args[0]), printer._print(self.args[1]))
  117. def _pretty(self, printer, *args):
  118. pform = printer._print(self.args[0], *args)
  119. pform = prettyForm(*pform.right(prettyForm(',')))
  120. pform = prettyForm(*pform.right(printer._print(self.args[1], *args)))
  121. pform = prettyForm(*pform.parens(left='{', right='}'))
  122. return pform
  123. def _latex(self, printer, *args):
  124. return "\\left\\{%s,%s\\right\\}" % tuple([
  125. printer._print(arg, *args) for arg in self.args])
  126. @AntiCommutator._kind_dispatcher.register(_OperatorKind, _OperatorKind)
  127. def find_op_kind(e1, e2):
  128. """Find the kind of an anticommutator of two OperatorKinds."""
  129. return OperatorKind