You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
4.4 KiB

5 months ago
"""Fermionic quantum operators."""
from sympy.core.numbers import Integer
from sympy.core.singleton import S
from sympy.physics.quantum import Operator
from sympy.physics.quantum import HilbertSpace, Ket, Bra
from sympy.functions.special.tensor_functions import KroneckerDelta
__all__ = [
'FermionOp',
'FermionFockKet',
'FermionFockBra'
]
class FermionOp(Operator):
"""A fermionic operator that satisfies {c, Dagger(c)} == 1.
Parameters
==========
name : str
A string that labels the fermionic mode.
annihilation : bool
A bool that indicates if the fermionic operator is an annihilation
(True, default value) or creation operator (False)
Examples
========
>>> from sympy.physics.quantum import Dagger, AntiCommutator
>>> from sympy.physics.quantum.fermion import FermionOp
>>> c = FermionOp("c")
>>> AntiCommutator(c, Dagger(c)).doit()
1
"""
@property
def name(self):
return self.args[0]
@property
def is_annihilation(self):
return bool(self.args[1])
@classmethod
def default_args(self):
return ("c", True)
def __new__(cls, *args, **hints):
if not len(args) in [1, 2]:
raise ValueError('1 or 2 parameters expected, got %s' % args)
if len(args) == 1:
args = (args[0], S.One)
if len(args) == 2:
args = (args[0], Integer(args[1]))
return Operator.__new__(cls, *args)
def _eval_commutator_FermionOp(self, other, **hints):
if 'independent' in hints and hints['independent']:
# [c, d] = 0
return S.Zero
return None
def _eval_anticommutator_FermionOp(self, other, **hints):
if self.name == other.name:
# {a^\dagger, a} = 1
if not self.is_annihilation and other.is_annihilation:
return S.One
elif 'independent' in hints and hints['independent']:
# {c, d} = 2 * c * d, because [c, d] = 0 for independent operators
return 2 * self * other
return None
def _eval_anticommutator_BosonOp(self, other, **hints):
# because fermions and bosons commute
return 2 * self * other
def _eval_commutator_BosonOp(self, other, **hints):
return S.Zero
def _eval_adjoint(self):
return FermionOp(str(self.name), not self.is_annihilation)
def _print_contents_latex(self, printer, *args):
if self.is_annihilation:
return r'{%s}' % str(self.name)
else:
return r'{{%s}^\dagger}' % str(self.name)
def _print_contents(self, printer, *args):
if self.is_annihilation:
return r'%s' % str(self.name)
else:
return r'Dagger(%s)' % str(self.name)
def _print_contents_pretty(self, printer, *args):
from sympy.printing.pretty.stringpict import prettyForm
pform = printer._print(self.args[0], *args)
if self.is_annihilation:
return pform
else:
return pform**prettyForm('\N{DAGGER}')
class FermionFockKet(Ket):
"""Fock state ket for a fermionic mode.
Parameters
==========
n : Number
The Fock state number.
"""
def __new__(cls, n):
if n not in (0, 1):
raise ValueError("n must be 0 or 1")
return Ket.__new__(cls, n)
@property
def n(self):
return self.label[0]
@classmethod
def dual_class(self):
return FermionFockBra
@classmethod
def _eval_hilbert_space(cls, label):
return HilbertSpace()
def _eval_innerproduct_FermionFockBra(self, bra, **hints):
return KroneckerDelta(self.n, bra.n)
def _apply_from_right_to_FermionOp(self, op, **options):
if op.is_annihilation:
if self.n == 1:
return FermionFockKet(0)
else:
return S.Zero
else:
if self.n == 0:
return FermionFockKet(1)
else:
return S.Zero
class FermionFockBra(Bra):
"""Fock state bra for a fermionic mode.
Parameters
==========
n : Number
The Fock state number.
"""
def __new__(cls, n):
if n not in (0, 1):
raise ValueError("n must be 0 or 1")
return Bra.__new__(cls, n)
@property
def n(self):
return self.label[0]
@classmethod
def dual_class(self):
return FermionFockKet