| 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)
 
 
  |