1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012 |
- """Dirac notation for states."""
- from sympy.core.cache import cacheit
- from sympy.core.containers import Tuple
- from sympy.core.expr import Expr
- from sympy.core.function import Function
- from sympy.core.numbers import oo
- from sympy.core.singleton import S
- from sympy.functions.elementary.complexes import conjugate
- from sympy.functions.elementary.miscellaneous import sqrt
- from sympy.integrals.integrals import integrate
- from sympy.printing.pretty.stringpict import stringPict
- from sympy.physics.quantum.qexpr import QExpr, dispatch_method
- __all__ = [
- 'KetBase',
- 'BraBase',
- 'StateBase',
- 'State',
- 'Ket',
- 'Bra',
- 'TimeDepState',
- 'TimeDepBra',
- 'TimeDepKet',
- 'OrthogonalKet',
- 'OrthogonalBra',
- 'OrthogonalState',
- 'Wavefunction'
- ]
- #-----------------------------------------------------------------------------
- # States, bras and kets.
- #-----------------------------------------------------------------------------
- # ASCII brackets
- _lbracket = "<"
- _rbracket = ">"
- _straight_bracket = "|"
- # Unicode brackets
- # MATHEMATICAL ANGLE BRACKETS
- _lbracket_ucode = "\N{MATHEMATICAL LEFT ANGLE BRACKET}"
- _rbracket_ucode = "\N{MATHEMATICAL RIGHT ANGLE BRACKET}"
- # LIGHT VERTICAL BAR
- _straight_bracket_ucode = "\N{LIGHT VERTICAL BAR}"
- # Other options for unicode printing of <, > and | for Dirac notation.
- # LEFT-POINTING ANGLE BRACKET
- # _lbracket = "\u2329"
- # _rbracket = "\u232A"
- # LEFT ANGLE BRACKET
- # _lbracket = "\u3008"
- # _rbracket = "\u3009"
- # VERTICAL LINE
- # _straight_bracket = "\u007C"
- class StateBase(QExpr):
- """Abstract base class for general abstract states in quantum mechanics.
- All other state classes defined will need to inherit from this class. It
- carries the basic structure for all other states such as dual, _eval_adjoint
- and label.
- This is an abstract base class and you should not instantiate it directly,
- instead use State.
- """
- @classmethod
- def _operators_to_state(self, ops, **options):
- """ Returns the eigenstate instance for the passed operators.
- This method should be overridden in subclasses. It will handle being
- passed either an Operator instance or set of Operator instances. It
- should return the corresponding state INSTANCE or simply raise a
- NotImplementedError. See cartesian.py for an example.
- """
- raise NotImplementedError("Cannot map operators to states in this class. Method not implemented!")
- def _state_to_operators(self, op_classes, **options):
- """ Returns the operators which this state instance is an eigenstate
- of.
- This method should be overridden in subclasses. It will be called on
- state instances and be passed the operator classes that we wish to make
- into instances. The state instance will then transform the classes
- appropriately, or raise a NotImplementedError if it cannot return
- operator instances. See cartesian.py for examples,
- """
- raise NotImplementedError(
- "Cannot map this state to operators. Method not implemented!")
- @property
- def operators(self):
- """Return the operator(s) that this state is an eigenstate of"""
- from .operatorset import state_to_operators # import internally to avoid circular import errors
- return state_to_operators(self)
- def _enumerate_state(self, num_states, **options):
- raise NotImplementedError("Cannot enumerate this state!")
- def _represent_default_basis(self, **options):
- return self._represent(basis=self.operators)
- #-------------------------------------------------------------------------
- # Dagger/dual
- #-------------------------------------------------------------------------
- @property
- def dual(self):
- """Return the dual state of this one."""
- return self.dual_class()._new_rawargs(self.hilbert_space, *self.args)
- @classmethod
- def dual_class(self):
- """Return the class used to construct the dual."""
- raise NotImplementedError(
- 'dual_class must be implemented in a subclass'
- )
- def _eval_adjoint(self):
- """Compute the dagger of this state using the dual."""
- return self.dual
- #-------------------------------------------------------------------------
- # Printing
- #-------------------------------------------------------------------------
- def _pretty_brackets(self, height, use_unicode=True):
- # Return pretty printed brackets for the state
- # Ideally, this could be done by pform.parens but it does not support the angled < and >
- # Setup for unicode vs ascii
- if use_unicode:
- lbracket, rbracket = getattr(self, 'lbracket_ucode', ""), getattr(self, 'rbracket_ucode', "")
- slash, bslash, vert = '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT}', \
- '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT}', \
- '\N{BOX DRAWINGS LIGHT VERTICAL}'
- else:
- lbracket, rbracket = getattr(self, 'lbracket', ""), getattr(self, 'rbracket', "")
- slash, bslash, vert = '/', '\\', '|'
- # If height is 1, just return brackets
- if height == 1:
- return stringPict(lbracket), stringPict(rbracket)
- # Make height even
- height += (height % 2)
- brackets = []
- for bracket in lbracket, rbracket:
- # Create left bracket
- if bracket in {_lbracket, _lbracket_ucode}:
- bracket_args = [ ' ' * (height//2 - i - 1) +
- slash for i in range(height // 2)]
- bracket_args.extend(
- [' ' * i + bslash for i in range(height // 2)])
- # Create right bracket
- elif bracket in {_rbracket, _rbracket_ucode}:
- bracket_args = [ ' ' * i + bslash for i in range(height // 2)]
- bracket_args.extend([ ' ' * (
- height//2 - i - 1) + slash for i in range(height // 2)])
- # Create straight bracket
- elif bracket in {_straight_bracket, _straight_bracket_ucode}:
- bracket_args = [vert] * height
- else:
- raise ValueError(bracket)
- brackets.append(
- stringPict('\n'.join(bracket_args), baseline=height//2))
- return brackets
- def _sympystr(self, printer, *args):
- contents = self._print_contents(printer, *args)
- return '%s%s%s' % (getattr(self, 'lbracket', ""), contents, getattr(self, 'rbracket', ""))
- def _pretty(self, printer, *args):
- from sympy.printing.pretty.stringpict import prettyForm
- # Get brackets
- pform = self._print_contents_pretty(printer, *args)
- lbracket, rbracket = self._pretty_brackets(
- pform.height(), printer._use_unicode)
- # Put together state
- pform = prettyForm(*pform.left(lbracket))
- pform = prettyForm(*pform.right(rbracket))
- return pform
- def _latex(self, printer, *args):
- contents = self._print_contents_latex(printer, *args)
- # The extra {} brackets are needed to get matplotlib's latex
- # rendered to render this properly.
- return '{%s%s%s}' % (getattr(self, 'lbracket_latex', ""), contents, getattr(self, 'rbracket_latex', ""))
- class KetBase(StateBase):
- """Base class for Kets.
- This class defines the dual property and the brackets for printing. This is
- an abstract base class and you should not instantiate it directly, instead
- use Ket.
- """
- lbracket = _straight_bracket
- rbracket = _rbracket
- lbracket_ucode = _straight_bracket_ucode
- rbracket_ucode = _rbracket_ucode
- lbracket_latex = r'\left|'
- rbracket_latex = r'\right\rangle '
- @classmethod
- def default_args(self):
- return ("psi",)
- @classmethod
- def dual_class(self):
- return BraBase
- def __mul__(self, other):
- """KetBase*other"""
- from sympy.physics.quantum.operator import OuterProduct
- if isinstance(other, BraBase):
- return OuterProduct(self, other)
- else:
- return Expr.__mul__(self, other)
- def __rmul__(self, other):
- """other*KetBase"""
- from sympy.physics.quantum.innerproduct import InnerProduct
- if isinstance(other, BraBase):
- return InnerProduct(other, self)
- else:
- return Expr.__rmul__(self, other)
- #-------------------------------------------------------------------------
- # _eval_* methods
- #-------------------------------------------------------------------------
- def _eval_innerproduct(self, bra, **hints):
- """Evaluate the inner product between this ket and a bra.
- This is called to compute <bra|ket>, where the ket is ``self``.
- This method will dispatch to sub-methods having the format::
- ``def _eval_innerproduct_BraClass(self, **hints):``
- Subclasses should define these methods (one for each BraClass) to
- teach the ket how to take inner products with bras.
- """
- return dispatch_method(self, '_eval_innerproduct', bra, **hints)
- def _apply_operator(self, op, **options):
- """Apply an Operator to this Ket.
- This method will dispatch to methods having the format::
- ``def _apply_operator_OperatorName(op, **options):``
- Subclasses should define these methods (one for each OperatorName) to
- teach the Ket how operators act on it.
- Parameters
- ==========
- op : Operator
- The Operator that is acting on the Ket.
- options : dict
- A dict of key/value pairs that control how the operator is applied
- to the Ket.
- """
- return dispatch_method(self, '_apply_operator', op, **options)
- class BraBase(StateBase):
- """Base class for Bras.
- This class defines the dual property and the brackets for printing. This
- is an abstract base class and you should not instantiate it directly,
- instead use Bra.
- """
- lbracket = _lbracket
- rbracket = _straight_bracket
- lbracket_ucode = _lbracket_ucode
- rbracket_ucode = _straight_bracket_ucode
- lbracket_latex = r'\left\langle '
- rbracket_latex = r'\right|'
- @classmethod
- def _operators_to_state(self, ops, **options):
- state = self.dual_class()._operators_to_state(ops, **options)
- return state.dual
- def _state_to_operators(self, op_classes, **options):
- return self.dual._state_to_operators(op_classes, **options)
- def _enumerate_state(self, num_states, **options):
- dual_states = self.dual._enumerate_state(num_states, **options)
- return [x.dual for x in dual_states]
- @classmethod
- def default_args(self):
- return self.dual_class().default_args()
- @classmethod
- def dual_class(self):
- return KetBase
- def __mul__(self, other):
- """BraBase*other"""
- from sympy.physics.quantum.innerproduct import InnerProduct
- if isinstance(other, KetBase):
- return InnerProduct(self, other)
- else:
- return Expr.__mul__(self, other)
- def __rmul__(self, other):
- """other*BraBase"""
- from sympy.physics.quantum.operator import OuterProduct
- if isinstance(other, KetBase):
- return OuterProduct(other, self)
- else:
- return Expr.__rmul__(self, other)
- def _represent(self, **options):
- """A default represent that uses the Ket's version."""
- from sympy.physics.quantum.dagger import Dagger
- return Dagger(self.dual._represent(**options))
- class State(StateBase):
- """General abstract quantum state used as a base class for Ket and Bra."""
- pass
- class Ket(State, KetBase):
- """A general time-independent Ket in quantum mechanics.
- Inherits from State and KetBase. This class should be used as the base
- class for all physical, time-independent Kets in a system. This class
- and its subclasses will be the main classes that users will use for
- expressing Kets in Dirac notation [1]_.
- Parameters
- ==========
- args : tuple
- The list of numbers or parameters that uniquely specify the
- ket. This will usually be its symbol or its quantum numbers. For
- time-dependent state, this will include the time.
- Examples
- ========
- Create a simple Ket and looking at its properties::
- >>> from sympy.physics.quantum import Ket
- >>> from sympy import symbols, I
- >>> k = Ket('psi')
- >>> k
- |psi>
- >>> k.hilbert_space
- H
- >>> k.is_commutative
- False
- >>> k.label
- (psi,)
- Ket's know about their associated bra::
- >>> k.dual
- <psi|
- >>> k.dual_class()
- <class 'sympy.physics.quantum.state.Bra'>
- Take a linear combination of two kets::
- >>> k0 = Ket(0)
- >>> k1 = Ket(1)
- >>> 2*I*k0 - 4*k1
- 2*I*|0> - 4*|1>
- Compound labels are passed as tuples::
- >>> n, m = symbols('n,m')
- >>> k = Ket(n,m)
- >>> k
- |nm>
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Bra-ket_notation
- """
- @classmethod
- def dual_class(self):
- return Bra
- class Bra(State, BraBase):
- """A general time-independent Bra in quantum mechanics.
- Inherits from State and BraBase. A Bra is the dual of a Ket [1]_. This
- class and its subclasses will be the main classes that users will use for
- expressing Bras in Dirac notation.
- Parameters
- ==========
- args : tuple
- The list of numbers or parameters that uniquely specify the
- ket. This will usually be its symbol or its quantum numbers. For
- time-dependent state, this will include the time.
- Examples
- ========
- Create a simple Bra and look at its properties::
- >>> from sympy.physics.quantum import Bra
- >>> from sympy import symbols, I
- >>> b = Bra('psi')
- >>> b
- <psi|
- >>> b.hilbert_space
- H
- >>> b.is_commutative
- False
- Bra's know about their dual Ket's::
- >>> b.dual
- |psi>
- >>> b.dual_class()
- <class 'sympy.physics.quantum.state.Ket'>
- Like Kets, Bras can have compound labels and be manipulated in a similar
- manner::
- >>> n, m = symbols('n,m')
- >>> b = Bra(n,m) - I*Bra(m,n)
- >>> b
- -I*<mn| + <nm|
- Symbols in a Bra can be substituted using ``.subs``::
- >>> b.subs(n,m)
- <mm| - I*<mm|
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Bra-ket_notation
- """
- @classmethod
- def dual_class(self):
- return Ket
- #-----------------------------------------------------------------------------
- # Time dependent states, bras and kets.
- #-----------------------------------------------------------------------------
- class TimeDepState(StateBase):
- """Base class for a general time-dependent quantum state.
- This class is used as a base class for any time-dependent state. The main
- difference between this class and the time-independent state is that this
- class takes a second argument that is the time in addition to the usual
- label argument.
- Parameters
- ==========
- args : tuple
- The list of numbers or parameters that uniquely specify the ket. This
- will usually be its symbol or its quantum numbers. For time-dependent
- state, this will include the time as the final argument.
- """
- #-------------------------------------------------------------------------
- # Initialization
- #-------------------------------------------------------------------------
- @classmethod
- def default_args(self):
- return ("psi", "t")
- #-------------------------------------------------------------------------
- # Properties
- #-------------------------------------------------------------------------
- @property
- def label(self):
- """The label of the state."""
- return self.args[:-1]
- @property
- def time(self):
- """The time of the state."""
- return self.args[-1]
- #-------------------------------------------------------------------------
- # Printing
- #-------------------------------------------------------------------------
- def _print_time(self, printer, *args):
- return printer._print(self.time, *args)
- _print_time_repr = _print_time
- _print_time_latex = _print_time
- def _print_time_pretty(self, printer, *args):
- pform = printer._print(self.time, *args)
- return pform
- def _print_contents(self, printer, *args):
- label = self._print_label(printer, *args)
- time = self._print_time(printer, *args)
- return '%s;%s' % (label, time)
- def _print_label_repr(self, printer, *args):
- label = self._print_sequence(self.label, ',', printer, *args)
- time = self._print_time_repr(printer, *args)
- return '%s,%s' % (label, time)
- def _print_contents_pretty(self, printer, *args):
- label = self._print_label_pretty(printer, *args)
- time = self._print_time_pretty(printer, *args)
- return printer._print_seq((label, time), delimiter=';')
- def _print_contents_latex(self, printer, *args):
- label = self._print_sequence(
- self.label, self._label_separator, printer, *args)
- time = self._print_time_latex(printer, *args)
- return '%s;%s' % (label, time)
- class TimeDepKet(TimeDepState, KetBase):
- """General time-dependent Ket in quantum mechanics.
- This inherits from ``TimeDepState`` and ``KetBase`` and is the main class
- that should be used for Kets that vary with time. Its dual is a
- ``TimeDepBra``.
- Parameters
- ==========
- args : tuple
- The list of numbers or parameters that uniquely specify the ket. This
- will usually be its symbol or its quantum numbers. For time-dependent
- state, this will include the time as the final argument.
- Examples
- ========
- Create a TimeDepKet and look at its attributes::
- >>> from sympy.physics.quantum import TimeDepKet
- >>> k = TimeDepKet('psi', 't')
- >>> k
- |psi;t>
- >>> k.time
- t
- >>> k.label
- (psi,)
- >>> k.hilbert_space
- H
- TimeDepKets know about their dual bra::
- >>> k.dual
- <psi;t|
- >>> k.dual_class()
- <class 'sympy.physics.quantum.state.TimeDepBra'>
- """
- @classmethod
- def dual_class(self):
- return TimeDepBra
- class TimeDepBra(TimeDepState, BraBase):
- """General time-dependent Bra in quantum mechanics.
- This inherits from TimeDepState and BraBase and is the main class that
- should be used for Bras that vary with time. Its dual is a TimeDepBra.
- Parameters
- ==========
- args : tuple
- The list of numbers or parameters that uniquely specify the ket. This
- will usually be its symbol or its quantum numbers. For time-dependent
- state, this will include the time as the final argument.
- Examples
- ========
- >>> from sympy.physics.quantum import TimeDepBra
- >>> b = TimeDepBra('psi', 't')
- >>> b
- <psi;t|
- >>> b.time
- t
- >>> b.label
- (psi,)
- >>> b.hilbert_space
- H
- >>> b.dual
- |psi;t>
- """
- @classmethod
- def dual_class(self):
- return TimeDepKet
- class OrthogonalState(State, StateBase):
- """General abstract quantum state used as a base class for Ket and Bra."""
- pass
- class OrthogonalKet(OrthogonalState, KetBase):
- """Orthogonal Ket in quantum mechanics.
- The inner product of two states with different labels will give zero,
- states with the same label will give one.
- >>> from sympy.physics.quantum import OrthogonalBra, OrthogonalKet
- >>> from sympy.abc import m, n
- >>> (OrthogonalBra(n)*OrthogonalKet(n)).doit()
- 1
- >>> (OrthogonalBra(n)*OrthogonalKet(n+1)).doit()
- 0
- >>> (OrthogonalBra(n)*OrthogonalKet(m)).doit()
- <n|m>
- """
- @classmethod
- def dual_class(self):
- return OrthogonalBra
- def _eval_innerproduct(self, bra, **hints):
- if len(self.args) != len(bra.args):
- raise ValueError('Cannot multiply a ket that has a different number of labels.')
- for i in range(len(self.args)):
- diff = self.args[i] - bra.args[i]
- diff = diff.expand()
- if diff.is_zero is False:
- return 0
- if diff.is_zero is None:
- return None
- return 1
- class OrthogonalBra(OrthogonalState, BraBase):
- """Orthogonal Bra in quantum mechanics.
- """
- @classmethod
- def dual_class(self):
- return OrthogonalKet
- class Wavefunction(Function):
- """Class for representations in continuous bases
- This class takes an expression and coordinates in its constructor. It can
- be used to easily calculate normalizations and probabilities.
- Parameters
- ==========
- expr : Expr
- The expression representing the functional form of the w.f.
- coords : Symbol or tuple
- The coordinates to be integrated over, and their bounds
- Examples
- ========
- Particle in a box, specifying bounds in the more primitive way of using
- Piecewise:
- >>> from sympy import Symbol, Piecewise, pi, N
- >>> from sympy.functions import sqrt, sin
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> x = Symbol('x', real=True)
- >>> n = 1
- >>> L = 1
- >>> g = Piecewise((0, x < 0), (0, x > L), (sqrt(2//L)*sin(n*pi*x/L), True))
- >>> f = Wavefunction(g, x)
- >>> f.norm
- 1
- >>> f.is_normalized
- True
- >>> p = f.prob()
- >>> p(0)
- 0
- >>> p(L)
- 0
- >>> p(0.5)
- 2
- >>> p(0.85*L)
- 2*sin(0.85*pi)**2
- >>> N(p(0.85*L))
- 0.412214747707527
- Additionally, you can specify the bounds of the function and the indices in
- a more compact way:
- >>> from sympy import symbols, pi, diff
- >>> from sympy.functions import sqrt, sin
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> x, L = symbols('x,L', positive=True)
- >>> n = symbols('n', integer=True, positive=True)
- >>> g = sqrt(2/L)*sin(n*pi*x/L)
- >>> f = Wavefunction(g, (x, 0, L))
- >>> f.norm
- 1
- >>> f(L+1)
- 0
- >>> f(L-1)
- sqrt(2)*sin(pi*n*(L - 1)/L)/sqrt(L)
- >>> f(-1)
- 0
- >>> f(0.85)
- sqrt(2)*sin(0.85*pi*n/L)/sqrt(L)
- >>> f(0.85, n=1, L=1)
- sqrt(2)*sin(0.85*pi)
- >>> f.is_commutative
- False
- All arguments are automatically sympified, so you can define the variables
- as strings rather than symbols:
- >>> expr = x**2
- >>> f = Wavefunction(expr, 'x')
- >>> type(f.variables[0])
- <class 'sympy.core.symbol.Symbol'>
- Derivatives of Wavefunctions will return Wavefunctions:
- >>> diff(f, x)
- Wavefunction(2*x, x)
- """
- #Any passed tuples for coordinates and their bounds need to be
- #converted to Tuples before Function's constructor is called, to
- #avoid errors from calling is_Float in the constructor
- def __new__(cls, *args, **options):
- new_args = [None for i in args]
- ct = 0
- for arg in args:
- if isinstance(arg, tuple):
- new_args[ct] = Tuple(*arg)
- else:
- new_args[ct] = arg
- ct += 1
- return super().__new__(cls, *new_args, **options)
- def __call__(self, *args, **options):
- var = self.variables
- if len(args) != len(var):
- raise NotImplementedError(
- "Incorrect number of arguments to function!")
- ct = 0
- #If the passed value is outside the specified bounds, return 0
- for v in var:
- lower, upper = self.limits[v]
- #Do the comparison to limits only if the passed symbol is actually
- #a symbol present in the limits;
- #Had problems with a comparison of x > L
- if isinstance(args[ct], Expr) and \
- not (lower in args[ct].free_symbols
- or upper in args[ct].free_symbols):
- continue
- if (args[ct] < lower) == True or (args[ct] > upper) == True:
- return S.Zero
- ct += 1
- expr = self.expr
- #Allows user to make a call like f(2, 4, m=1, n=1)
- for symbol in list(expr.free_symbols):
- if str(symbol) in options.keys():
- val = options[str(symbol)]
- expr = expr.subs(symbol, val)
- return expr.subs(zip(var, args))
- def _eval_derivative(self, symbol):
- expr = self.expr
- deriv = expr._eval_derivative(symbol)
- return Wavefunction(deriv, *self.args[1:])
- def _eval_conjugate(self):
- return Wavefunction(conjugate(self.expr), *self.args[1:])
- def _eval_transpose(self):
- return self
- @property
- def free_symbols(self):
- return self.expr.free_symbols
- @property
- def is_commutative(self):
- """
- Override Function's is_commutative so that order is preserved in
- represented expressions
- """
- return False
- @classmethod
- def eval(self, *args):
- return None
- @property
- def variables(self):
- """
- Return the coordinates which the wavefunction depends on
- Examples
- ========
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> from sympy import symbols
- >>> x,y = symbols('x,y')
- >>> f = Wavefunction(x*y, x, y)
- >>> f.variables
- (x, y)
- >>> g = Wavefunction(x*y, x)
- >>> g.variables
- (x,)
- """
- var = [g[0] if isinstance(g, Tuple) else g for g in self._args[1:]]
- return tuple(var)
- @property
- def limits(self):
- """
- Return the limits of the coordinates which the w.f. depends on If no
- limits are specified, defaults to ``(-oo, oo)``.
- Examples
- ========
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> from sympy import symbols
- >>> x, y = symbols('x, y')
- >>> f = Wavefunction(x**2, (x, 0, 1))
- >>> f.limits
- {x: (0, 1)}
- >>> f = Wavefunction(x**2, x)
- >>> f.limits
- {x: (-oo, oo)}
- >>> f = Wavefunction(x**2 + y**2, x, (y, -1, 2))
- >>> f.limits
- {x: (-oo, oo), y: (-1, 2)}
- """
- limits = [(g[1], g[2]) if isinstance(g, Tuple) else (-oo, oo)
- for g in self._args[1:]]
- return dict(zip(self.variables, tuple(limits)))
- @property
- def expr(self):
- """
- Return the expression which is the functional form of the Wavefunction
- Examples
- ========
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> from sympy import symbols
- >>> x, y = symbols('x, y')
- >>> f = Wavefunction(x**2, x)
- >>> f.expr
- x**2
- """
- return self._args[0]
- @property
- def is_normalized(self):
- """
- Returns true if the Wavefunction is properly normalized
- Examples
- ========
- >>> from sympy import symbols, pi
- >>> from sympy.functions import sqrt, sin
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> x, L = symbols('x,L', positive=True)
- >>> n = symbols('n', integer=True, positive=True)
- >>> g = sqrt(2/L)*sin(n*pi*x/L)
- >>> f = Wavefunction(g, (x, 0, L))
- >>> f.is_normalized
- True
- """
- return (self.norm == 1.0)
- @property # type: ignore
- @cacheit
- def norm(self):
- """
- Return the normalization of the specified functional form.
- This function integrates over the coordinates of the Wavefunction, with
- the bounds specified.
- Examples
- ========
- >>> from sympy import symbols, pi
- >>> from sympy.functions import sqrt, sin
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> x, L = symbols('x,L', positive=True)
- >>> n = symbols('n', integer=True, positive=True)
- >>> g = sqrt(2/L)*sin(n*pi*x/L)
- >>> f = Wavefunction(g, (x, 0, L))
- >>> f.norm
- 1
- >>> g = sin(n*pi*x/L)
- >>> f = Wavefunction(g, (x, 0, L))
- >>> f.norm
- sqrt(2)*sqrt(L)/2
- """
- exp = self.expr*conjugate(self.expr)
- var = self.variables
- limits = self.limits
- for v in var:
- curr_limits = limits[v]
- exp = integrate(exp, (v, curr_limits[0], curr_limits[1]))
- return sqrt(exp)
- def normalize(self):
- """
- Return a normalized version of the Wavefunction
- Examples
- ========
- >>> from sympy import symbols, pi
- >>> from sympy.functions import sin
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> x = symbols('x', real=True)
- >>> L = symbols('L', positive=True)
- >>> n = symbols('n', integer=True, positive=True)
- >>> g = sin(n*pi*x/L)
- >>> f = Wavefunction(g, (x, 0, L))
- >>> f.normalize()
- Wavefunction(sqrt(2)*sin(pi*n*x/L)/sqrt(L), (x, 0, L))
- """
- const = self.norm
- if const is oo:
- raise NotImplementedError("The function is not normalizable!")
- else:
- return Wavefunction((const)**(-1)*self.expr, *self.args[1:])
- def prob(self):
- r"""
- Return the absolute magnitude of the w.f., `|\psi(x)|^2`
- Examples
- ========
- >>> from sympy import symbols, pi
- >>> from sympy.functions import sin
- >>> from sympy.physics.quantum.state import Wavefunction
- >>> x, L = symbols('x,L', real=True)
- >>> n = symbols('n', integer=True)
- >>> g = sin(n*pi*x/L)
- >>> f = Wavefunction(g, (x, 0, L))
- >>> f.prob()
- Wavefunction(sin(pi*n*x/L)**2, x)
- """
- return Wavefunction(self.expr*conjugate(self.expr), *self.variables)
|