Spaces:
Sleeping
Sleeping
| """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 | |
| 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]) | |