|
|
"""Functions for reordering operator expressions.""" |
|
|
|
|
|
import warnings |
|
|
|
|
|
from sympy.core.add import Add |
|
|
from sympy.core.mul import Mul |
|
|
from sympy.core.numbers import Integer |
|
|
from sympy.core.power import Pow |
|
|
from sympy.physics.quantum import Commutator, AntiCommutator |
|
|
from sympy.physics.quantum.boson import BosonOp |
|
|
from sympy.physics.quantum.fermion import FermionOp |
|
|
|
|
|
__all__ = [ |
|
|
'normal_order', |
|
|
'normal_ordered_form' |
|
|
] |
|
|
|
|
|
|
|
|
def _expand_powers(factors): |
|
|
""" |
|
|
Helper function for normal_ordered_form and normal_order: Expand a |
|
|
power expression to a multiplication expression so that that the |
|
|
expression can be handled by the normal ordering functions. |
|
|
""" |
|
|
|
|
|
new_factors = [] |
|
|
for factor in factors.args: |
|
|
if (isinstance(factor, Pow) |
|
|
and isinstance(factor.args[1], Integer) |
|
|
and factor.args[1] > 0): |
|
|
for n in range(factor.args[1]): |
|
|
new_factors.append(factor.args[0]) |
|
|
else: |
|
|
new_factors.append(factor) |
|
|
|
|
|
return new_factors |
|
|
|
|
|
def _normal_ordered_form_factor(product, independent=False, recursive_limit=10, |
|
|
_recursive_depth=0): |
|
|
""" |
|
|
Helper function for normal_ordered_form_factor: Write multiplication |
|
|
expression with bosonic or fermionic operators on normally ordered form, |
|
|
using the bosonic and fermionic commutation relations. The resulting |
|
|
operator expression is equivalent to the argument, but will in general be |
|
|
a sum of operator products instead of a simple product. |
|
|
""" |
|
|
|
|
|
factors = _expand_powers(product) |
|
|
|
|
|
new_factors = [] |
|
|
n = 0 |
|
|
while n < len(factors) - 1: |
|
|
current, next = factors[n], factors[n + 1] |
|
|
if any(not isinstance(f, (FermionOp, BosonOp)) for f in (current, next)): |
|
|
new_factors.append(current) |
|
|
n += 1 |
|
|
continue |
|
|
|
|
|
key_1 = (current.is_annihilation, str(current.name)) |
|
|
key_2 = (next.is_annihilation, str(next.name)) |
|
|
|
|
|
if key_1 <= key_2: |
|
|
new_factors.append(current) |
|
|
n += 1 |
|
|
continue |
|
|
|
|
|
n += 2 |
|
|
if current.is_annihilation and not next.is_annihilation: |
|
|
if isinstance(current, BosonOp) and isinstance(next, BosonOp): |
|
|
if current.args[0] != next.args[0]: |
|
|
if independent: |
|
|
c = 0 |
|
|
else: |
|
|
c = Commutator(current, next) |
|
|
new_factors.append(next * current + c) |
|
|
else: |
|
|
new_factors.append(next * current + 1) |
|
|
elif isinstance(current, FermionOp) and isinstance(next, FermionOp): |
|
|
if current.args[0] != next.args[0]: |
|
|
if independent: |
|
|
c = 0 |
|
|
else: |
|
|
c = AntiCommutator(current, next) |
|
|
new_factors.append(-next * current + c) |
|
|
else: |
|
|
new_factors.append(-next * current + 1) |
|
|
elif (current.is_annihilation == next.is_annihilation and |
|
|
isinstance(current, FermionOp) and isinstance(next, FermionOp)): |
|
|
new_factors.append(-next * current) |
|
|
else: |
|
|
new_factors.append(next * current) |
|
|
|
|
|
if n == len(factors) - 1: |
|
|
new_factors.append(factors[-1]) |
|
|
|
|
|
if new_factors == factors: |
|
|
return product |
|
|
else: |
|
|
expr = Mul(*new_factors).expand() |
|
|
return normal_ordered_form(expr, |
|
|
recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth + 1, |
|
|
independent=independent) |
|
|
|
|
|
|
|
|
def _normal_ordered_form_terms(expr, independent=False, recursive_limit=10, |
|
|
_recursive_depth=0): |
|
|
""" |
|
|
Helper function for normal_ordered_form: loop through each term in an |
|
|
addition expression and call _normal_ordered_form_factor to perform the |
|
|
factor to an normally ordered expression. |
|
|
""" |
|
|
|
|
|
new_terms = [] |
|
|
for term in expr.args: |
|
|
if isinstance(term, Mul): |
|
|
new_term = _normal_ordered_form_factor( |
|
|
term, recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth, independent=independent) |
|
|
new_terms.append(new_term) |
|
|
else: |
|
|
new_terms.append(term) |
|
|
|
|
|
return Add(*new_terms) |
|
|
|
|
|
|
|
|
def normal_ordered_form(expr, independent=False, recursive_limit=10, |
|
|
_recursive_depth=0): |
|
|
"""Write an expression with bosonic or fermionic operators on normal |
|
|
ordered form, where each term is normally ordered. Note that this |
|
|
normal ordered form is equivalent to the original expression. |
|
|
|
|
|
Parameters |
|
|
========== |
|
|
|
|
|
expr : expression |
|
|
The expression write on normal ordered form. |
|
|
independent : bool (default False) |
|
|
Whether to consider operator with different names as operating in |
|
|
different Hilbert spaces. If False, the (anti-)commutation is left |
|
|
explicit. |
|
|
recursive_limit : int (default 10) |
|
|
The number of allowed recursive applications of the function. |
|
|
|
|
|
Examples |
|
|
======== |
|
|
|
|
|
>>> from sympy.physics.quantum import Dagger |
|
|
>>> from sympy.physics.quantum.boson import BosonOp |
|
|
>>> from sympy.physics.quantum.operatorordering import normal_ordered_form |
|
|
>>> a = BosonOp("a") |
|
|
>>> normal_ordered_form(a * Dagger(a)) |
|
|
1 + Dagger(a)*a |
|
|
""" |
|
|
|
|
|
if _recursive_depth > recursive_limit: |
|
|
warnings.warn("Too many recursions, aborting") |
|
|
return expr |
|
|
|
|
|
if isinstance(expr, Add): |
|
|
return _normal_ordered_form_terms(expr, |
|
|
recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth, |
|
|
independent=independent) |
|
|
elif isinstance(expr, Mul): |
|
|
return _normal_ordered_form_factor(expr, |
|
|
recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth, |
|
|
independent=independent) |
|
|
else: |
|
|
return expr |
|
|
|
|
|
|
|
|
def _normal_order_factor(product, recursive_limit=10, _recursive_depth=0): |
|
|
""" |
|
|
Helper function for normal_order: Normal order a multiplication expression |
|
|
with bosonic or fermionic operators. In general the resulting operator |
|
|
expression will not be equivalent to original product. |
|
|
""" |
|
|
|
|
|
factors = _expand_powers(product) |
|
|
|
|
|
n = 0 |
|
|
new_factors = [] |
|
|
while n < len(factors) - 1: |
|
|
|
|
|
if (isinstance(factors[n], BosonOp) and |
|
|
factors[n].is_annihilation): |
|
|
|
|
|
if not isinstance(factors[n + 1], BosonOp): |
|
|
new_factors.append(factors[n]) |
|
|
else: |
|
|
if factors[n + 1].is_annihilation: |
|
|
new_factors.append(factors[n]) |
|
|
else: |
|
|
if factors[n].args[0] != factors[n + 1].args[0]: |
|
|
new_factors.append(factors[n + 1] * factors[n]) |
|
|
else: |
|
|
new_factors.append(factors[n + 1] * factors[n]) |
|
|
n += 1 |
|
|
|
|
|
elif (isinstance(factors[n], FermionOp) and |
|
|
factors[n].is_annihilation): |
|
|
|
|
|
if not isinstance(factors[n + 1], FermionOp): |
|
|
new_factors.append(factors[n]) |
|
|
else: |
|
|
if factors[n + 1].is_annihilation: |
|
|
new_factors.append(factors[n]) |
|
|
else: |
|
|
if factors[n].args[0] != factors[n + 1].args[0]: |
|
|
new_factors.append(-factors[n + 1] * factors[n]) |
|
|
else: |
|
|
new_factors.append(-factors[n + 1] * factors[n]) |
|
|
n += 1 |
|
|
|
|
|
else: |
|
|
new_factors.append(factors[n]) |
|
|
|
|
|
n += 1 |
|
|
|
|
|
if n == len(factors) - 1: |
|
|
new_factors.append(factors[-1]) |
|
|
|
|
|
if new_factors == factors: |
|
|
return product |
|
|
else: |
|
|
expr = Mul(*new_factors).expand() |
|
|
return normal_order(expr, |
|
|
recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth + 1) |
|
|
|
|
|
|
|
|
def _normal_order_terms(expr, recursive_limit=10, _recursive_depth=0): |
|
|
""" |
|
|
Helper function for normal_order: look through each term in an addition |
|
|
expression and call _normal_order_factor to perform the normal ordering |
|
|
on the factors. |
|
|
""" |
|
|
|
|
|
new_terms = [] |
|
|
for term in expr.args: |
|
|
if isinstance(term, Mul): |
|
|
new_term = _normal_order_factor(term, |
|
|
recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth) |
|
|
new_terms.append(new_term) |
|
|
else: |
|
|
new_terms.append(term) |
|
|
|
|
|
return Add(*new_terms) |
|
|
|
|
|
|
|
|
def normal_order(expr, recursive_limit=10, _recursive_depth=0): |
|
|
"""Normal order an expression with bosonic or fermionic operators. Note |
|
|
that this normal order is not equivalent to the original expression, but |
|
|
the creation and annihilation operators in each term in expr is reordered |
|
|
so that the expression becomes normal ordered. |
|
|
|
|
|
Parameters |
|
|
========== |
|
|
|
|
|
expr : expression |
|
|
The expression to normal order. |
|
|
|
|
|
recursive_limit : int (default 10) |
|
|
The number of allowed recursive applications of the function. |
|
|
|
|
|
Examples |
|
|
======== |
|
|
|
|
|
>>> from sympy.physics.quantum import Dagger |
|
|
>>> from sympy.physics.quantum.boson import BosonOp |
|
|
>>> from sympy.physics.quantum.operatorordering import normal_order |
|
|
>>> a = BosonOp("a") |
|
|
>>> normal_order(a * Dagger(a)) |
|
|
Dagger(a)*a |
|
|
""" |
|
|
if _recursive_depth > recursive_limit: |
|
|
warnings.warn("Too many recursions, aborting") |
|
|
return expr |
|
|
|
|
|
if isinstance(expr, Add): |
|
|
return _normal_order_terms(expr, recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth) |
|
|
elif isinstance(expr, Mul): |
|
|
return _normal_order_factor(expr, recursive_limit=recursive_limit, |
|
|
_recursive_depth=_recursive_depth) |
|
|
else: |
|
|
return expr |
|
|
|