123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014 |
- """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, equal_valued
- 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_from_right_to(self, op, **options):
- """Apply an Operator to this Ket as Operator*Ket
- This method will dispatch to methods having the format::
- ``def _apply_from_right_to_OperatorName(op, **options):``
- Subclasses should define these methods (one for each OperatorName) to
- teach the Ket how to implement OperatorName*Ket
- Parameters
- ==========
- op : Operator
- The Operator that is acting on the Ket as op*Ket
- options : dict
- A dict of key/value pairs that control how the operator is applied
- to the Ket.
- """
- return dispatch_method(self, '_apply_from_right_to', 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 arg, bra_arg in zip(self.args, bra.args):
- diff = arg - bra_arg
- diff = diff.expand()
- is_zero = diff.is_zero
- if is_zero is False:
- return S.Zero # i.e. Integer(0)
- if is_zero is None:
- return None
- return S.One # i.e. Integer(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 equal_valued(self.norm, 1)
- @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)
|