| """Hilbert spaces for quantum mechanics. |
| |
| Authors: |
| * Brian Granger |
| * Matt Curry |
| """ |
|
|
| from functools import reduce |
|
|
| from sympy.core.basic import Basic |
| from sympy.core.singleton import S |
| from sympy.core.sympify import sympify |
| from sympy.sets.sets import Interval |
| from sympy.printing.pretty.stringpict import prettyForm |
| from sympy.physics.quantum.qexpr import QuantumError |
|
|
|
|
| __all__ = [ |
| 'HilbertSpaceError', |
| 'HilbertSpace', |
| 'TensorProductHilbertSpace', |
| 'TensorPowerHilbertSpace', |
| 'DirectSumHilbertSpace', |
| 'ComplexSpace', |
| 'L2', |
| 'FockSpace' |
| ] |
|
|
| |
| |
| |
|
|
|
|
| class HilbertSpaceError(QuantumError): |
| pass |
|
|
| |
| |
| |
|
|
|
|
| class HilbertSpace(Basic): |
| """An abstract Hilbert space for quantum mechanics. |
| |
| In short, a Hilbert space is an abstract vector space that is complete |
| with inner products defined [1]_. |
| |
| Examples |
| ======== |
| |
| >>> from sympy.physics.quantum.hilbert import HilbertSpace |
| >>> hs = HilbertSpace() |
| >>> hs |
| H |
| |
| References |
| ========== |
| |
| .. [1] https://en.wikipedia.org/wiki/Hilbert_space |
| """ |
|
|
| def __new__(cls): |
| obj = Basic.__new__(cls) |
| return obj |
|
|
| @property |
| def dimension(self): |
| """Return the Hilbert dimension of the space.""" |
| raise NotImplementedError('This Hilbert space has no dimension.') |
|
|
| def __add__(self, other): |
| return DirectSumHilbertSpace(self, other) |
|
|
| def __radd__(self, other): |
| return DirectSumHilbertSpace(other, self) |
|
|
| def __mul__(self, other): |
| return TensorProductHilbertSpace(self, other) |
|
|
| def __rmul__(self, other): |
| return TensorProductHilbertSpace(other, self) |
|
|
| def __pow__(self, other, mod=None): |
| if mod is not None: |
| raise ValueError('The third argument to __pow__ is not supported \ |
| for Hilbert spaces.') |
| return TensorPowerHilbertSpace(self, other) |
|
|
| def __contains__(self, other): |
| """Is the operator or state in this Hilbert space. |
| |
| This is checked by comparing the classes of the Hilbert spaces, not |
| the instances. This is to allow Hilbert Spaces with symbolic |
| dimensions. |
| """ |
| if other.hilbert_space.__class__ == self.__class__: |
| return True |
| else: |
| return False |
|
|
| def _sympystr(self, printer, *args): |
| return 'H' |
|
|
| def _pretty(self, printer, *args): |
| ustr = '\N{LATIN CAPITAL LETTER H}' |
| return prettyForm(ustr) |
|
|
| def _latex(self, printer, *args): |
| return r'\mathcal{H}' |
|
|
|
|
| class ComplexSpace(HilbertSpace): |
| """Finite dimensional Hilbert space of complex vectors. |
| |
| The elements of this Hilbert space are n-dimensional complex valued |
| vectors with the usual inner product that takes the complex conjugate |
| of the vector on the right. |
| |
| A classic example of this type of Hilbert space is spin-1/2, which is |
| ``ComplexSpace(2)``. Generalizing to spin-s, the space is |
| ``ComplexSpace(2*s+1)``. Quantum computing with N qubits is done with the |
| direct product space ``ComplexSpace(2)**N``. |
| |
| Examples |
| ======== |
| |
| >>> from sympy import symbols |
| >>> from sympy.physics.quantum.hilbert import ComplexSpace |
| >>> c1 = ComplexSpace(2) |
| >>> c1 |
| C(2) |
| >>> c1.dimension |
| 2 |
| |
| >>> n = symbols('n') |
| >>> c2 = ComplexSpace(n) |
| >>> c2 |
| C(n) |
| >>> c2.dimension |
| n |
| |
| """ |
|
|
| def __new__(cls, dimension): |
| dimension = sympify(dimension) |
| r = cls.eval(dimension) |
| if isinstance(r, Basic): |
| return r |
| obj = Basic.__new__(cls, dimension) |
| return obj |
|
|
| @classmethod |
| def eval(cls, dimension): |
| if len(dimension.atoms()) == 1: |
| if not (dimension.is_Integer and dimension > 0 or dimension is S.Infinity |
| or dimension.is_Symbol): |
| raise TypeError('The dimension of a ComplexSpace can only' |
| 'be a positive integer, oo, or a Symbol: %r' |
| % dimension) |
| else: |
| for dim in dimension.atoms(): |
| if not (dim.is_Integer or dim is S.Infinity or dim.is_Symbol): |
| raise TypeError('The dimension of a ComplexSpace can only' |
| ' contain integers, oo, or a Symbol: %r' |
| % dim) |
|
|
| @property |
| def dimension(self): |
| return self.args[0] |
|
|
| def _sympyrepr(self, printer, *args): |
| return "%s(%s)" % (self.__class__.__name__, |
| printer._print(self.dimension, *args)) |
|
|
| def _sympystr(self, printer, *args): |
| return "C(%s)" % printer._print(self.dimension, *args) |
|
|
| def _pretty(self, printer, *args): |
| ustr = '\N{LATIN CAPITAL LETTER C}' |
| pform_exp = printer._print(self.dimension, *args) |
| pform_base = prettyForm(ustr) |
| return pform_base**pform_exp |
|
|
| def _latex(self, printer, *args): |
| return r'\mathcal{C}^{%s}' % printer._print(self.dimension, *args) |
|
|
|
|
| class L2(HilbertSpace): |
| """The Hilbert space of square integrable functions on an interval. |
| |
| An L2 object takes in a single SymPy Interval argument which represents |
| the interval its functions (vectors) are defined on. |
| |
| Examples |
| ======== |
| |
| >>> from sympy import Interval, oo |
| >>> from sympy.physics.quantum.hilbert import L2 |
| >>> hs = L2(Interval(0,oo)) |
| >>> hs |
| L2(Interval(0, oo)) |
| >>> hs.dimension |
| oo |
| >>> hs.interval |
| Interval(0, oo) |
| |
| """ |
|
|
| def __new__(cls, interval): |
| if not isinstance(interval, Interval): |
| raise TypeError('L2 interval must be an Interval instance: %r' |
| % interval) |
| obj = Basic.__new__(cls, interval) |
| return obj |
|
|
| @property |
| def dimension(self): |
| return S.Infinity |
|
|
| @property |
| def interval(self): |
| return self.args[0] |
|
|
| def _sympyrepr(self, printer, *args): |
| return "L2(%s)" % printer._print(self.interval, *args) |
|
|
| def _sympystr(self, printer, *args): |
| return "L2(%s)" % printer._print(self.interval, *args) |
|
|
| def _pretty(self, printer, *args): |
| pform_exp = prettyForm('2') |
| pform_base = prettyForm('L') |
| return pform_base**pform_exp |
|
|
| def _latex(self, printer, *args): |
| interval = printer._print(self.interval, *args) |
| return r'{\mathcal{L}^2}\left( %s \right)' % interval |
|
|
|
|
| class FockSpace(HilbertSpace): |
| """The Hilbert space for second quantization. |
| |
| Technically, this Hilbert space is a infinite direct sum of direct |
| products of single particle Hilbert spaces [1]_. This is a mess, so we have |
| a class to represent it directly. |
| |
| Examples |
| ======== |
| |
| >>> from sympy.physics.quantum.hilbert import FockSpace |
| >>> hs = FockSpace() |
| >>> hs |
| F |
| >>> hs.dimension |
| oo |
| |
| References |
| ========== |
| |
| .. [1] https://en.wikipedia.org/wiki/Fock_space |
| """ |
|
|
| def __new__(cls): |
| obj = Basic.__new__(cls) |
| return obj |
|
|
| @property |
| def dimension(self): |
| return S.Infinity |
|
|
| def _sympyrepr(self, printer, *args): |
| return "FockSpace()" |
|
|
| def _sympystr(self, printer, *args): |
| return "F" |
|
|
| def _pretty(self, printer, *args): |
| ustr = '\N{LATIN CAPITAL LETTER F}' |
| return prettyForm(ustr) |
|
|
| def _latex(self, printer, *args): |
| return r'\mathcal{F}' |
|
|
|
|
| class TensorProductHilbertSpace(HilbertSpace): |
| """A tensor product of Hilbert spaces [1]_. |
| |
| The tensor product between Hilbert spaces is represented by the |
| operator ``*`` Products of the same Hilbert space will be combined into |
| tensor powers. |
| |
| A ``TensorProductHilbertSpace`` object takes in an arbitrary number of |
| ``HilbertSpace`` objects as its arguments. In addition, multiplication of |
| ``HilbertSpace`` objects will automatically return this tensor product |
| object. |
| |
| Examples |
| ======== |
| |
| >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace |
| >>> from sympy import symbols |
| |
| >>> c = ComplexSpace(2) |
| >>> f = FockSpace() |
| >>> hs = c*f |
| >>> hs |
| C(2)*F |
| >>> hs.dimension |
| oo |
| >>> hs.spaces |
| (C(2), F) |
| |
| >>> c1 = ComplexSpace(2) |
| >>> n = symbols('n') |
| >>> c2 = ComplexSpace(n) |
| >>> hs = c1*c2 |
| >>> hs |
| C(2)*C(n) |
| >>> hs.dimension |
| 2*n |
| |
| References |
| ========== |
| |
| .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products |
| """ |
|
|
| def __new__(cls, *args): |
| r = cls.eval(args) |
| if isinstance(r, Basic): |
| return r |
| obj = Basic.__new__(cls, *args) |
| return obj |
|
|
| @classmethod |
| def eval(cls, args): |
| """Evaluates the direct product.""" |
| new_args = [] |
| recall = False |
| |
| for arg in args: |
| if isinstance(arg, TensorProductHilbertSpace): |
| new_args.extend(arg.args) |
| recall = True |
| elif isinstance(arg, (HilbertSpace, TensorPowerHilbertSpace)): |
| new_args.append(arg) |
| else: |
| raise TypeError('Hilbert spaces can only be multiplied by \ |
| other Hilbert spaces: %r' % arg) |
| |
| comb_args = [] |
| prev_arg = None |
| for new_arg in new_args: |
| if prev_arg is not None: |
| if isinstance(new_arg, TensorPowerHilbertSpace) and \ |
| isinstance(prev_arg, TensorPowerHilbertSpace) and \ |
| new_arg.base == prev_arg.base: |
| prev_arg = new_arg.base**(new_arg.exp + prev_arg.exp) |
| elif isinstance(new_arg, TensorPowerHilbertSpace) and \ |
| new_arg.base == prev_arg: |
| prev_arg = prev_arg**(new_arg.exp + 1) |
| elif isinstance(prev_arg, TensorPowerHilbertSpace) and \ |
| new_arg == prev_arg.base: |
| prev_arg = new_arg**(prev_arg.exp + 1) |
| elif new_arg == prev_arg: |
| prev_arg = new_arg**2 |
| else: |
| comb_args.append(prev_arg) |
| prev_arg = new_arg |
| elif prev_arg is None: |
| prev_arg = new_arg |
| comb_args.append(prev_arg) |
| if recall: |
| return TensorProductHilbertSpace(*comb_args) |
| elif len(comb_args) == 1: |
| return TensorPowerHilbertSpace(comb_args[0].base, comb_args[0].exp) |
| else: |
| return None |
|
|
| @property |
| def dimension(self): |
| arg_list = [arg.dimension for arg in self.args] |
| if S.Infinity in arg_list: |
| return S.Infinity |
| else: |
| return reduce(lambda x, y: x*y, arg_list) |
|
|
| @property |
| def spaces(self): |
| """A tuple of the Hilbert spaces in this tensor product.""" |
| return self.args |
|
|
| def _spaces_printer(self, printer, *args): |
| spaces_strs = [] |
| for arg in self.args: |
| s = printer._print(arg, *args) |
| if isinstance(arg, DirectSumHilbertSpace): |
| s = '(%s)' % s |
| spaces_strs.append(s) |
| return spaces_strs |
|
|
| def _sympyrepr(self, printer, *args): |
| spaces_reprs = self._spaces_printer(printer, *args) |
| return "TensorProductHilbertSpace(%s)" % ','.join(spaces_reprs) |
|
|
| def _sympystr(self, printer, *args): |
| spaces_strs = self._spaces_printer(printer, *args) |
| return '*'.join(spaces_strs) |
|
|
| def _pretty(self, printer, *args): |
| length = len(self.args) |
| pform = printer._print('', *args) |
| for i in range(length): |
| next_pform = printer._print(self.args[i], *args) |
| if isinstance(self.args[i], (DirectSumHilbertSpace, |
| TensorProductHilbertSpace)): |
| next_pform = prettyForm( |
| *next_pform.parens(left='(', right=')') |
| ) |
| pform = prettyForm(*pform.right(next_pform)) |
| if i != length - 1: |
| if printer._use_unicode: |
| pform = prettyForm(*pform.right(' ' + '\N{N-ARY CIRCLED TIMES OPERATOR}' + ' ')) |
| else: |
| pform = prettyForm(*pform.right(' x ')) |
| return pform |
|
|
| def _latex(self, printer, *args): |
| length = len(self.args) |
| s = '' |
| for i in range(length): |
| arg_s = printer._print(self.args[i], *args) |
| if isinstance(self.args[i], (DirectSumHilbertSpace, |
| TensorProductHilbertSpace)): |
| arg_s = r'\left(%s\right)' % arg_s |
| s = s + arg_s |
| if i != length - 1: |
| s = s + r'\otimes ' |
| return s |
|
|
|
|
| class DirectSumHilbertSpace(HilbertSpace): |
| """A direct sum of Hilbert spaces [1]_. |
| |
| This class uses the ``+`` operator to represent direct sums between |
| different Hilbert spaces. |
| |
| A ``DirectSumHilbertSpace`` object takes in an arbitrary number of |
| ``HilbertSpace`` objects as its arguments. Also, addition of |
| ``HilbertSpace`` objects will automatically return a direct sum object. |
| |
| Examples |
| ======== |
| |
| >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace |
| |
| >>> c = ComplexSpace(2) |
| >>> f = FockSpace() |
| >>> hs = c+f |
| >>> hs |
| C(2)+F |
| >>> hs.dimension |
| oo |
| >>> list(hs.spaces) |
| [C(2), F] |
| |
| References |
| ========== |
| |
| .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Direct_sums |
| """ |
| def __new__(cls, *args): |
| r = cls.eval(args) |
| if isinstance(r, Basic): |
| return r |
| obj = Basic.__new__(cls, *args) |
| return obj |
|
|
| @classmethod |
| def eval(cls, args): |
| """Evaluates the direct product.""" |
| new_args = [] |
| recall = False |
| |
| for arg in args: |
| if isinstance(arg, DirectSumHilbertSpace): |
| new_args.extend(arg.args) |
| recall = True |
| elif isinstance(arg, HilbertSpace): |
| new_args.append(arg) |
| else: |
| raise TypeError('Hilbert spaces can only be summed with other \ |
| Hilbert spaces: %r' % arg) |
| if recall: |
| return DirectSumHilbertSpace(*new_args) |
| else: |
| return None |
|
|
| @property |
| def dimension(self): |
| arg_list = [arg.dimension for arg in self.args] |
| if S.Infinity in arg_list: |
| return S.Infinity |
| else: |
| return reduce(lambda x, y: x + y, arg_list) |
|
|
| @property |
| def spaces(self): |
| """A tuple of the Hilbert spaces in this direct sum.""" |
| return self.args |
|
|
| def _sympyrepr(self, printer, *args): |
| spaces_reprs = [printer._print(arg, *args) for arg in self.args] |
| return "DirectSumHilbertSpace(%s)" % ','.join(spaces_reprs) |
|
|
| def _sympystr(self, printer, *args): |
| spaces_strs = [printer._print(arg, *args) for arg in self.args] |
| return '+'.join(spaces_strs) |
|
|
| def _pretty(self, printer, *args): |
| length = len(self.args) |
| pform = printer._print('', *args) |
| for i in range(length): |
| next_pform = printer._print(self.args[i], *args) |
| if isinstance(self.args[i], (DirectSumHilbertSpace, |
| TensorProductHilbertSpace)): |
| next_pform = prettyForm( |
| *next_pform.parens(left='(', right=')') |
| ) |
| pform = prettyForm(*pform.right(next_pform)) |
| if i != length - 1: |
| if printer._use_unicode: |
| pform = prettyForm(*pform.right(' \N{CIRCLED PLUS} ')) |
| else: |
| pform = prettyForm(*pform.right(' + ')) |
| return pform |
|
|
| def _latex(self, printer, *args): |
| length = len(self.args) |
| s = '' |
| for i in range(length): |
| arg_s = printer._print(self.args[i], *args) |
| if isinstance(self.args[i], (DirectSumHilbertSpace, |
| TensorProductHilbertSpace)): |
| arg_s = r'\left(%s\right)' % arg_s |
| s = s + arg_s |
| if i != length - 1: |
| s = s + r'\oplus ' |
| return s |
|
|
|
|
| class TensorPowerHilbertSpace(HilbertSpace): |
| """An exponentiated Hilbert space [1]_. |
| |
| Tensor powers (repeated tensor products) are represented by the |
| operator ``**`` Identical Hilbert spaces that are multiplied together |
| will be automatically combined into a single tensor power object. |
| |
| Any Hilbert space, product, or sum may be raised to a tensor power. The |
| ``TensorPowerHilbertSpace`` takes two arguments: the Hilbert space; and the |
| tensor power (number). |
| |
| Examples |
| ======== |
| |
| >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace |
| >>> from sympy import symbols |
| |
| >>> n = symbols('n') |
| >>> c = ComplexSpace(2) |
| >>> hs = c**n |
| >>> hs |
| C(2)**n |
| >>> hs.dimension |
| 2**n |
| |
| >>> c = ComplexSpace(2) |
| >>> c*c |
| C(2)**2 |
| >>> f = FockSpace() |
| >>> c*f*f |
| C(2)*F**2 |
| |
| References |
| ========== |
| |
| .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products |
| """ |
|
|
| def __new__(cls, *args): |
| r = cls.eval(args) |
| if isinstance(r, Basic): |
| return r |
| return Basic.__new__(cls, *r) |
|
|
| @classmethod |
| def eval(cls, args): |
| new_args = args[0], sympify(args[1]) |
| exp = new_args[1] |
| |
| if exp is S.One: |
| return args[0] |
| |
| if exp is S.Zero: |
| return S.One |
| |
| if len(exp.atoms()) == 1: |
| if not (exp.is_Integer and exp >= 0 or exp.is_Symbol): |
| raise ValueError('Hilbert spaces can only be raised to \ |
| positive integers or Symbols: %r' % exp) |
| else: |
| for power in exp.atoms(): |
| if not (power.is_Integer or power.is_Symbol): |
| raise ValueError('Tensor powers can only contain integers \ |
| or Symbols: %r' % power) |
| return new_args |
|
|
| @property |
| def base(self): |
| return self.args[0] |
|
|
| @property |
| def exp(self): |
| return self.args[1] |
|
|
| @property |
| def dimension(self): |
| if self.base.dimension is S.Infinity: |
| return S.Infinity |
| else: |
| return self.base.dimension**self.exp |
|
|
| def _sympyrepr(self, printer, *args): |
| return "TensorPowerHilbertSpace(%s,%s)" % (printer._print(self.base, |
| *args), printer._print(self.exp, *args)) |
|
|
| def _sympystr(self, printer, *args): |
| return "%s**%s" % (printer._print(self.base, *args), |
| printer._print(self.exp, *args)) |
|
|
| def _pretty(self, printer, *args): |
| pform_exp = printer._print(self.exp, *args) |
| if printer._use_unicode: |
| pform_exp = prettyForm(*pform_exp.left(prettyForm('\N{N-ARY CIRCLED TIMES OPERATOR}'))) |
| else: |
| pform_exp = prettyForm(*pform_exp.left(prettyForm('x'))) |
| pform_base = printer._print(self.base, *args) |
| return pform_base**pform_exp |
|
|
| def _latex(self, printer, *args): |
| base = printer._print(self.base, *args) |
| exp = printer._print(self.exp, *args) |
| return r'{%s}^{\otimes %s}' % (base, exp) |
|
|