123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- """Bosonic quantum operators."""
- from sympy.core.mul import Mul
- from sympy.core.numbers import Integer
- from sympy.core.singleton import S
- from sympy.functions.elementary.complexes import conjugate
- from sympy.functions.elementary.exponential import exp
- from sympy.functions.elementary.miscellaneous import sqrt
- from sympy.physics.quantum import Operator
- from sympy.physics.quantum import HilbertSpace, FockSpace, Ket, Bra, IdentityOperator
- from sympy.functions.special.tensor_functions import KroneckerDelta
- __all__ = [
- 'BosonOp',
- 'BosonFockKet',
- 'BosonFockBra',
- 'BosonCoherentKet',
- 'BosonCoherentBra'
- ]
- class BosonOp(Operator):
- """A bosonic operator that satisfies [a, Dagger(a)] == 1.
- Parameters
- ==========
- name : str
- A string that labels the bosonic mode.
- annihilation : bool
- A bool that indicates if the bosonic operator is an annihilation (True,
- default value) or creation operator (False)
- Examples
- ========
- >>> from sympy.physics.quantum import Dagger, Commutator
- >>> from sympy.physics.quantum.boson import BosonOp
- >>> a = BosonOp("a")
- >>> Commutator(a, Dagger(a)).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 ("a", 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_BosonOp(self, other, **hints):
- if self.name == other.name:
- # [a^\dagger, a] = -1
- if not self.is_annihilation and other.is_annihilation:
- return S.NegativeOne
- elif 'independent' in hints and hints['independent']:
- # [a, b] = 0
- return S.Zero
- return None
- def _eval_commutator_FermionOp(self, other, **hints):
- return S.Zero
- def _eval_anticommutator_BosonOp(self, other, **hints):
- if 'independent' in hints and hints['independent']:
- # {a, b} = 2 * a * b, because [a, b] = 0
- return 2 * self * other
- return None
- def _eval_adjoint(self):
- return BosonOp(str(self.name), not self.is_annihilation)
- def __mul__(self, other):
- if other == IdentityOperator(2):
- return self
- if isinstance(other, Mul):
- args1 = tuple(arg for arg in other.args if arg.is_commutative)
- args2 = tuple(arg for arg in other.args if not arg.is_commutative)
- x = self
- for y in args2:
- x = x * y
- return Mul(*args1) * x
- return Mul(self, other)
- 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 BosonFockKet(Ket):
- """Fock state ket for a bosonic mode.
- Parameters
- ==========
- n : Number
- The Fock state number.
- """
- def __new__(cls, n):
- return Ket.__new__(cls, n)
- @property
- def n(self):
- return self.label[0]
- @classmethod
- def dual_class(self):
- return BosonFockBra
- @classmethod
- def _eval_hilbert_space(cls, label):
- return FockSpace()
- def _eval_innerproduct_BosonFockBra(self, bra, **hints):
- return KroneckerDelta(self.n, bra.n)
- def _apply_operator_BosonOp(self, op, **options):
- if op.is_annihilation:
- return sqrt(self.n) * BosonFockKet(self.n - 1)
- else:
- return sqrt(self.n + 1) * BosonFockKet(self.n + 1)
- class BosonFockBra(Bra):
- """Fock state bra for a bosonic mode.
- Parameters
- ==========
- n : Number
- The Fock state number.
- """
- def __new__(cls, n):
- return Bra.__new__(cls, n)
- @property
- def n(self):
- return self.label[0]
- @classmethod
- def dual_class(self):
- return BosonFockKet
- @classmethod
- def _eval_hilbert_space(cls, label):
- return FockSpace()
- class BosonCoherentKet(Ket):
- """Coherent state ket for a bosonic mode.
- Parameters
- ==========
- alpha : Number, Symbol
- The complex amplitude of the coherent state.
- """
- def __new__(cls, alpha):
- return Ket.__new__(cls, alpha)
- @property
- def alpha(self):
- return self.label[0]
- @classmethod
- def dual_class(self):
- return BosonCoherentBra
- @classmethod
- def _eval_hilbert_space(cls, label):
- return HilbertSpace()
- def _eval_innerproduct_BosonCoherentBra(self, bra, **hints):
- if self.alpha == bra.alpha:
- return S.One
- else:
- return exp(-(abs(self.alpha)**2 + abs(bra.alpha)**2 - 2 * conjugate(bra.alpha) * self.alpha)/2)
- def _apply_operator_BosonOp(self, op, **options):
- if op.is_annihilation:
- return self.alpha * self
- else:
- return None
- class BosonCoherentBra(Bra):
- """Coherent state bra for a bosonic mode.
- Parameters
- ==========
- alpha : Number, Symbol
- The complex amplitude of the coherent state.
- """
- def __new__(cls, alpha):
- return Bra.__new__(cls, alpha)
- @property
- def alpha(self):
- return self.label[0]
- @classmethod
- def dual_class(self):
- return BosonCoherentKet
- def _apply_operator_BosonOp(self, op, **options):
- if not op.is_annihilation:
- return self.alpha * self
- else:
- return None
|