123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- """The commutator: [A,B] = A*B - B*A."""
- from sympy.core.add import Add
- from sympy.core.expr import Expr
- from sympy.core.mul import Mul
- from sympy.core.power import Pow
- from sympy.core.singleton import S
- from sympy.printing.pretty.stringpict import prettyForm
- from sympy.physics.quantum.dagger import Dagger
- from sympy.physics.quantum.operator import Operator
- __all__ = [
- 'Commutator'
- ]
- #-----------------------------------------------------------------------------
- # Commutator
- #-----------------------------------------------------------------------------
- class Commutator(Expr):
- """The standard commutator, in an unevaluated state.
- Explanation
- ===========
- Evaluating a commutator is defined [1]_ as: ``[A, B] = A*B - B*A``. This
- class returns the commutator in an unevaluated form. To evaluate the
- commutator, use the ``.doit()`` method.
- Canonical ordering of a commutator is ``[A, B]`` for ``A < B``. The
- arguments of the commutator are put into canonical order using ``__cmp__``.
- If ``B < A``, then ``[B, A]`` is returned as ``-[A, B]``.
- Parameters
- ==========
- A : Expr
- The first argument of the commutator [A,B].
- B : Expr
- The second argument of the commutator [A,B].
- Examples
- ========
- >>> from sympy.physics.quantum import Commutator, Dagger, Operator
- >>> from sympy.abc import x, y
- >>> A = Operator('A')
- >>> B = Operator('B')
- >>> C = Operator('C')
- Create a commutator and use ``.doit()`` to evaluate it:
- >>> comm = Commutator(A, B)
- >>> comm
- [A,B]
- >>> comm.doit()
- A*B - B*A
- The commutator orders it arguments in canonical order:
- >>> comm = Commutator(B, A); comm
- -[A,B]
- Commutative constants are factored out:
- >>> Commutator(3*x*A, x*y*B)
- 3*x**2*y*[A,B]
- Using ``.expand(commutator=True)``, the standard commutator expansion rules
- can be applied:
- >>> Commutator(A+B, C).expand(commutator=True)
- [A,C] + [B,C]
- >>> Commutator(A, B+C).expand(commutator=True)
- [A,B] + [A,C]
- >>> Commutator(A*B, C).expand(commutator=True)
- [A,C]*B + A*[B,C]
- >>> Commutator(A, B*C).expand(commutator=True)
- [A,B]*C + B*[A,C]
- Adjoint operations applied to the commutator are properly applied to the
- arguments:
- >>> Dagger(Commutator(A, B))
- -[Dagger(A),Dagger(B)]
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Commutator
- """
- is_commutative = False
- def __new__(cls, A, B):
- r = cls.eval(A, B)
- if r is not None:
- return r
- obj = Expr.__new__(cls, A, B)
- return obj
- @classmethod
- def eval(cls, a, b):
- if not (a and b):
- return S.Zero
- if a == b:
- return S.Zero
- if a.is_commutative or b.is_commutative:
- return S.Zero
- # [xA,yB] -> xy*[A,B]
- ca, nca = a.args_cnc()
- cb, ncb = b.args_cnc()
- c_part = ca + cb
- if c_part:
- return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb)))
- # Canonical ordering of arguments
- # The Commutator [A, B] is in canonical form if A < B.
- if a.compare(b) == 1:
- return S.NegativeOne*cls(b, a)
- def _expand_pow(self, A, B, sign):
- exp = A.exp
- if not exp.is_integer or not exp.is_constant() or abs(exp) <= 1:
- # nothing to do
- return self
- base = A.base
- if exp.is_negative:
- base = A.base**-1
- exp = -exp
- comm = Commutator(base, B).expand(commutator=True)
- result = base**(exp - 1) * comm
- for i in range(1, exp):
- result += base**(exp - 1 - i) * comm * base**i
- return sign*result.expand()
- def _eval_expand_commutator(self, **hints):
- A = self.args[0]
- B = self.args[1]
- if isinstance(A, Add):
- # [A + B, C] -> [A, C] + [B, C]
- sargs = []
- for term in A.args:
- comm = Commutator(term, B)
- if isinstance(comm, Commutator):
- comm = comm._eval_expand_commutator()
- sargs.append(comm)
- return Add(*sargs)
- elif isinstance(B, Add):
- # [A, B + C] -> [A, B] + [A, C]
- sargs = []
- for term in B.args:
- comm = Commutator(A, term)
- if isinstance(comm, Commutator):
- comm = comm._eval_expand_commutator()
- sargs.append(comm)
- return Add(*sargs)
- elif isinstance(A, Mul):
- # [A*B, C] -> A*[B, C] + [A, C]*B
- a = A.args[0]
- b = Mul(*A.args[1:])
- c = B
- comm1 = Commutator(b, c)
- comm2 = Commutator(a, c)
- if isinstance(comm1, Commutator):
- comm1 = comm1._eval_expand_commutator()
- if isinstance(comm2, Commutator):
- comm2 = comm2._eval_expand_commutator()
- first = Mul(a, comm1)
- second = Mul(comm2, b)
- return Add(first, second)
- elif isinstance(B, Mul):
- # [A, B*C] -> [A, B]*C + B*[A, C]
- a = A
- b = B.args[0]
- c = Mul(*B.args[1:])
- comm1 = Commutator(a, b)
- comm2 = Commutator(a, c)
- if isinstance(comm1, Commutator):
- comm1 = comm1._eval_expand_commutator()
- if isinstance(comm2, Commutator):
- comm2 = comm2._eval_expand_commutator()
- first = Mul(comm1, c)
- second = Mul(b, comm2)
- return Add(first, second)
- elif isinstance(A, Pow):
- # [A**n, C] -> A**(n - 1)*[A, C] + A**(n - 2)*[A, C]*A + ... + [A, C]*A**(n-1)
- return self._expand_pow(A, B, 1)
- elif isinstance(B, Pow):
- # [A, C**n] -> C**(n - 1)*[C, A] + C**(n - 2)*[C, A]*C + ... + [C, A]*C**(n-1)
- return self._expand_pow(B, A, -1)
- # No changes, so return self
- return self
- def doit(self, **hints):
- """ Evaluate commutator """
- A = self.args[0]
- B = self.args[1]
- if isinstance(A, Operator) and isinstance(B, Operator):
- try:
- comm = A._eval_commutator(B, **hints)
- except NotImplementedError:
- try:
- comm = -1*B._eval_commutator(A, **hints)
- except NotImplementedError:
- comm = None
- if comm is not None:
- return comm.doit(**hints)
- return (A*B - B*A).doit(**hints)
- def _eval_adjoint(self):
- return Commutator(Dagger(self.args[1]), Dagger(self.args[0]))
- def _sympyrepr(self, printer, *args):
- return "%s(%s,%s)" % (
- self.__class__.__name__, printer._print(
- self.args[0]), printer._print(self.args[1])
- )
- def _sympystr(self, printer, *args):
- return "[%s,%s]" % (
- printer._print(self.args[0]), printer._print(self.args[1]))
- def _pretty(self, printer, *args):
- pform = printer._print(self.args[0], *args)
- pform = prettyForm(*pform.right(prettyForm(',')))
- pform = prettyForm(*pform.right(printer._print(self.args[1], *args)))
- pform = prettyForm(*pform.parens(left='[', right=']'))
- return pform
- def _latex(self, printer, *args):
- return "\\left[%s,%s\\right]" % tuple([
- printer._print(arg, *args) for arg in self.args])
|