123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653 |
- """Hilbert spaces for quantum mechanics.
- Authors:
- * Brian Granger
- * Matt Curry
- """
- from functools import reduce
- from sympy.core.basic import Basic
- from sympy.core.numbers import oo
- 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'
- ]
- #-----------------------------------------------------------------------------
- # Main objects
- #-----------------------------------------------------------------------------
- class HilbertSpaceError(QuantumError):
- pass
- #-----------------------------------------------------------------------------
- # Main objects
- #-----------------------------------------------------------------------------
- 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 oo
- 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 oo 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 oo
- @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 oo
- 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
- #flatten arguments
- 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)
- #combine like arguments into direct powers
- 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 oo in arg_list:
- return oo
- 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
- #flatten arguments
- 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 oo in arg_list:
- return oo
- 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]
- #simplify hs**1 -> hs
- if exp == 1:
- return args[0]
- #simplify hs**0 -> 1
- if exp == 0:
- return sympify(1)
- #check (and allow) for hs**(x+42+y...) case
- 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 oo:
- return oo
- 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)
|