| """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 |
| from sympy.physics.quantum.kind import KetKind, BraKind |
|
|
|
|
| __all__ = [ |
| 'KetBase', |
| 'BraBase', |
| 'StateBase', |
| 'State', |
| 'Ket', |
| 'Bra', |
| 'TimeDepState', |
| 'TimeDepBra', |
| 'TimeDepKet', |
| 'OrthogonalKet', |
| 'OrthogonalBra', |
| 'OrthogonalState', |
| 'Wavefunction' |
| ] |
|
|
|
|
| |
| |
| |
|
|
| |
| _lbracket = "<" |
| _rbracket = ">" |
| _straight_bracket = "|" |
|
|
|
|
| |
| |
| _lbracket_ucode = "\N{MATHEMATICAL LEFT ANGLE BRACKET}" |
| _rbracket_ucode = "\N{MATHEMATICAL RIGHT ANGLE BRACKET}" |
| |
| _straight_bracket_ucode = "\N{LIGHT VERTICAL BAR}" |
|
|
| |
|
|
| |
| |
| |
|
|
| |
| |
| |
|
|
| |
| |
|
|
|
|
| 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 |
| 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) |
|
|
| def _apply_operator(self, op, **options): |
| return None |
|
|
| |
| |
| |
|
|
| @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 |
|
|
| |
| |
| |
|
|
| def _pretty_brackets(self, height, use_unicode=True): |
| |
| |
|
|
| |
| 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 == 1: |
| return stringPict(lbracket), stringPict(rbracket) |
| |
| height += (height % 2) |
|
|
| brackets = [] |
| for bracket in lbracket, rbracket: |
| |
| 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)]) |
| |
| 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)]) |
| |
| 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 |
| |
| pform = self._print_contents_pretty(printer, *args) |
| lbracket, rbracket = self._pretty_brackets( |
| pform.height(), printer._use_unicode) |
| |
| pform = prettyForm(*pform.left(lbracket)) |
| pform = prettyForm(*pform.right(rbracket)) |
| return pform |
|
|
| def _latex(self, printer, *args): |
| contents = self._print_contents_latex(printer, *args) |
| |
| |
| 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. |
| """ |
|
|
| kind = KetKind |
|
|
| 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 _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. |
| """ |
|
|
| kind = BraKind |
|
|
| 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 _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 |
|
|
| |
| |
| |
|
|
|
|
| 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. |
| """ |
|
|
| |
| |
| |
|
|
| @classmethod |
| def default_args(self): |
| return ("psi", "t") |
|
|
| |
| |
| |
|
|
| @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] |
|
|
| |
| |
| |
|
|
| 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): |
| """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 |
|
|
| if is_zero is None: |
| return None |
|
|
| return S.One |
|
|
|
|
| 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) |
| |
| """ |
|
|
| |
| |
| |
| 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 |
| |
| for v in var: |
| lower, upper = self.limits[v] |
|
|
| |
| |
| |
| 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 |
|
|
| |
| 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 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 |
| @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) |
|
|