180 lines
4.4 KiB
Python
180 lines
4.4 KiB
Python
"""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
|