hilbert.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. """Hilbert spaces for quantum mechanics.
  2. Authors:
  3. * Brian Granger
  4. * Matt Curry
  5. """
  6. from functools import reduce
  7. from sympy.core.basic import Basic
  8. from sympy.core.numbers import oo
  9. from sympy.core.sympify import sympify
  10. from sympy.sets.sets import Interval
  11. from sympy.printing.pretty.stringpict import prettyForm
  12. from sympy.physics.quantum.qexpr import QuantumError
  13. __all__ = [
  14. 'HilbertSpaceError',
  15. 'HilbertSpace',
  16. 'TensorProductHilbertSpace',
  17. 'TensorPowerHilbertSpace',
  18. 'DirectSumHilbertSpace',
  19. 'ComplexSpace',
  20. 'L2',
  21. 'FockSpace'
  22. ]
  23. #-----------------------------------------------------------------------------
  24. # Main objects
  25. #-----------------------------------------------------------------------------
  26. class HilbertSpaceError(QuantumError):
  27. pass
  28. #-----------------------------------------------------------------------------
  29. # Main objects
  30. #-----------------------------------------------------------------------------
  31. class HilbertSpace(Basic):
  32. """An abstract Hilbert space for quantum mechanics.
  33. In short, a Hilbert space is an abstract vector space that is complete
  34. with inner products defined [1]_.
  35. Examples
  36. ========
  37. >>> from sympy.physics.quantum.hilbert import HilbertSpace
  38. >>> hs = HilbertSpace()
  39. >>> hs
  40. H
  41. References
  42. ==========
  43. .. [1] https://en.wikipedia.org/wiki/Hilbert_space
  44. """
  45. def __new__(cls):
  46. obj = Basic.__new__(cls)
  47. return obj
  48. @property
  49. def dimension(self):
  50. """Return the Hilbert dimension of the space."""
  51. raise NotImplementedError('This Hilbert space has no dimension.')
  52. def __add__(self, other):
  53. return DirectSumHilbertSpace(self, other)
  54. def __radd__(self, other):
  55. return DirectSumHilbertSpace(other, self)
  56. def __mul__(self, other):
  57. return TensorProductHilbertSpace(self, other)
  58. def __rmul__(self, other):
  59. return TensorProductHilbertSpace(other, self)
  60. def __pow__(self, other, mod=None):
  61. if mod is not None:
  62. raise ValueError('The third argument to __pow__ is not supported \
  63. for Hilbert spaces.')
  64. return TensorPowerHilbertSpace(self, other)
  65. def __contains__(self, other):
  66. """Is the operator or state in this Hilbert space.
  67. This is checked by comparing the classes of the Hilbert spaces, not
  68. the instances. This is to allow Hilbert Spaces with symbolic
  69. dimensions.
  70. """
  71. if other.hilbert_space.__class__ == self.__class__:
  72. return True
  73. else:
  74. return False
  75. def _sympystr(self, printer, *args):
  76. return 'H'
  77. def _pretty(self, printer, *args):
  78. ustr = '\N{LATIN CAPITAL LETTER H}'
  79. return prettyForm(ustr)
  80. def _latex(self, printer, *args):
  81. return r'\mathcal{H}'
  82. class ComplexSpace(HilbertSpace):
  83. """Finite dimensional Hilbert space of complex vectors.
  84. The elements of this Hilbert space are n-dimensional complex valued
  85. vectors with the usual inner product that takes the complex conjugate
  86. of the vector on the right.
  87. A classic example of this type of Hilbert space is spin-1/2, which is
  88. ``ComplexSpace(2)``. Generalizing to spin-s, the space is
  89. ``ComplexSpace(2*s+1)``. Quantum computing with N qubits is done with the
  90. direct product space ``ComplexSpace(2)**N``.
  91. Examples
  92. ========
  93. >>> from sympy import symbols
  94. >>> from sympy.physics.quantum.hilbert import ComplexSpace
  95. >>> c1 = ComplexSpace(2)
  96. >>> c1
  97. C(2)
  98. >>> c1.dimension
  99. 2
  100. >>> n = symbols('n')
  101. >>> c2 = ComplexSpace(n)
  102. >>> c2
  103. C(n)
  104. >>> c2.dimension
  105. n
  106. """
  107. def __new__(cls, dimension):
  108. dimension = sympify(dimension)
  109. r = cls.eval(dimension)
  110. if isinstance(r, Basic):
  111. return r
  112. obj = Basic.__new__(cls, dimension)
  113. return obj
  114. @classmethod
  115. def eval(cls, dimension):
  116. if len(dimension.atoms()) == 1:
  117. if not (dimension.is_Integer and dimension > 0 or dimension is oo
  118. or dimension.is_Symbol):
  119. raise TypeError('The dimension of a ComplexSpace can only'
  120. 'be a positive integer, oo, or a Symbol: %r'
  121. % dimension)
  122. else:
  123. for dim in dimension.atoms():
  124. if not (dim.is_Integer or dim is oo or dim.is_Symbol):
  125. raise TypeError('The dimension of a ComplexSpace can only'
  126. ' contain integers, oo, or a Symbol: %r'
  127. % dim)
  128. @property
  129. def dimension(self):
  130. return self.args[0]
  131. def _sympyrepr(self, printer, *args):
  132. return "%s(%s)" % (self.__class__.__name__,
  133. printer._print(self.dimension, *args))
  134. def _sympystr(self, printer, *args):
  135. return "C(%s)" % printer._print(self.dimension, *args)
  136. def _pretty(self, printer, *args):
  137. ustr = '\N{LATIN CAPITAL LETTER C}'
  138. pform_exp = printer._print(self.dimension, *args)
  139. pform_base = prettyForm(ustr)
  140. return pform_base**pform_exp
  141. def _latex(self, printer, *args):
  142. return r'\mathcal{C}^{%s}' % printer._print(self.dimension, *args)
  143. class L2(HilbertSpace):
  144. """The Hilbert space of square integrable functions on an interval.
  145. An L2 object takes in a single SymPy Interval argument which represents
  146. the interval its functions (vectors) are defined on.
  147. Examples
  148. ========
  149. >>> from sympy import Interval, oo
  150. >>> from sympy.physics.quantum.hilbert import L2
  151. >>> hs = L2(Interval(0,oo))
  152. >>> hs
  153. L2(Interval(0, oo))
  154. >>> hs.dimension
  155. oo
  156. >>> hs.interval
  157. Interval(0, oo)
  158. """
  159. def __new__(cls, interval):
  160. if not isinstance(interval, Interval):
  161. raise TypeError('L2 interval must be an Interval instance: %r'
  162. % interval)
  163. obj = Basic.__new__(cls, interval)
  164. return obj
  165. @property
  166. def dimension(self):
  167. return oo
  168. @property
  169. def interval(self):
  170. return self.args[0]
  171. def _sympyrepr(self, printer, *args):
  172. return "L2(%s)" % printer._print(self.interval, *args)
  173. def _sympystr(self, printer, *args):
  174. return "L2(%s)" % printer._print(self.interval, *args)
  175. def _pretty(self, printer, *args):
  176. pform_exp = prettyForm('2')
  177. pform_base = prettyForm('L')
  178. return pform_base**pform_exp
  179. def _latex(self, printer, *args):
  180. interval = printer._print(self.interval, *args)
  181. return r'{\mathcal{L}^2}\left( %s \right)' % interval
  182. class FockSpace(HilbertSpace):
  183. """The Hilbert space for second quantization.
  184. Technically, this Hilbert space is a infinite direct sum of direct
  185. products of single particle Hilbert spaces [1]_. This is a mess, so we have
  186. a class to represent it directly.
  187. Examples
  188. ========
  189. >>> from sympy.physics.quantum.hilbert import FockSpace
  190. >>> hs = FockSpace()
  191. >>> hs
  192. F
  193. >>> hs.dimension
  194. oo
  195. References
  196. ==========
  197. .. [1] https://en.wikipedia.org/wiki/Fock_space
  198. """
  199. def __new__(cls):
  200. obj = Basic.__new__(cls)
  201. return obj
  202. @property
  203. def dimension(self):
  204. return oo
  205. def _sympyrepr(self, printer, *args):
  206. return "FockSpace()"
  207. def _sympystr(self, printer, *args):
  208. return "F"
  209. def _pretty(self, printer, *args):
  210. ustr = '\N{LATIN CAPITAL LETTER F}'
  211. return prettyForm(ustr)
  212. def _latex(self, printer, *args):
  213. return r'\mathcal{F}'
  214. class TensorProductHilbertSpace(HilbertSpace):
  215. """A tensor product of Hilbert spaces [1]_.
  216. The tensor product between Hilbert spaces is represented by the
  217. operator ``*`` Products of the same Hilbert space will be combined into
  218. tensor powers.
  219. A ``TensorProductHilbertSpace`` object takes in an arbitrary number of
  220. ``HilbertSpace`` objects as its arguments. In addition, multiplication of
  221. ``HilbertSpace`` objects will automatically return this tensor product
  222. object.
  223. Examples
  224. ========
  225. >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace
  226. >>> from sympy import symbols
  227. >>> c = ComplexSpace(2)
  228. >>> f = FockSpace()
  229. >>> hs = c*f
  230. >>> hs
  231. C(2)*F
  232. >>> hs.dimension
  233. oo
  234. >>> hs.spaces
  235. (C(2), F)
  236. >>> c1 = ComplexSpace(2)
  237. >>> n = symbols('n')
  238. >>> c2 = ComplexSpace(n)
  239. >>> hs = c1*c2
  240. >>> hs
  241. C(2)*C(n)
  242. >>> hs.dimension
  243. 2*n
  244. References
  245. ==========
  246. .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products
  247. """
  248. def __new__(cls, *args):
  249. r = cls.eval(args)
  250. if isinstance(r, Basic):
  251. return r
  252. obj = Basic.__new__(cls, *args)
  253. return obj
  254. @classmethod
  255. def eval(cls, args):
  256. """Evaluates the direct product."""
  257. new_args = []
  258. recall = False
  259. #flatten arguments
  260. for arg in args:
  261. if isinstance(arg, TensorProductHilbertSpace):
  262. new_args.extend(arg.args)
  263. recall = True
  264. elif isinstance(arg, (HilbertSpace, TensorPowerHilbertSpace)):
  265. new_args.append(arg)
  266. else:
  267. raise TypeError('Hilbert spaces can only be multiplied by \
  268. other Hilbert spaces: %r' % arg)
  269. #combine like arguments into direct powers
  270. comb_args = []
  271. prev_arg = None
  272. for new_arg in new_args:
  273. if prev_arg is not None:
  274. if isinstance(new_arg, TensorPowerHilbertSpace) and \
  275. isinstance(prev_arg, TensorPowerHilbertSpace) and \
  276. new_arg.base == prev_arg.base:
  277. prev_arg = new_arg.base**(new_arg.exp + prev_arg.exp)
  278. elif isinstance(new_arg, TensorPowerHilbertSpace) and \
  279. new_arg.base == prev_arg:
  280. prev_arg = prev_arg**(new_arg.exp + 1)
  281. elif isinstance(prev_arg, TensorPowerHilbertSpace) and \
  282. new_arg == prev_arg.base:
  283. prev_arg = new_arg**(prev_arg.exp + 1)
  284. elif new_arg == prev_arg:
  285. prev_arg = new_arg**2
  286. else:
  287. comb_args.append(prev_arg)
  288. prev_arg = new_arg
  289. elif prev_arg is None:
  290. prev_arg = new_arg
  291. comb_args.append(prev_arg)
  292. if recall:
  293. return TensorProductHilbertSpace(*comb_args)
  294. elif len(comb_args) == 1:
  295. return TensorPowerHilbertSpace(comb_args[0].base, comb_args[0].exp)
  296. else:
  297. return None
  298. @property
  299. def dimension(self):
  300. arg_list = [arg.dimension for arg in self.args]
  301. if oo in arg_list:
  302. return oo
  303. else:
  304. return reduce(lambda x, y: x*y, arg_list)
  305. @property
  306. def spaces(self):
  307. """A tuple of the Hilbert spaces in this tensor product."""
  308. return self.args
  309. def _spaces_printer(self, printer, *args):
  310. spaces_strs = []
  311. for arg in self.args:
  312. s = printer._print(arg, *args)
  313. if isinstance(arg, DirectSumHilbertSpace):
  314. s = '(%s)' % s
  315. spaces_strs.append(s)
  316. return spaces_strs
  317. def _sympyrepr(self, printer, *args):
  318. spaces_reprs = self._spaces_printer(printer, *args)
  319. return "TensorProductHilbertSpace(%s)" % ','.join(spaces_reprs)
  320. def _sympystr(self, printer, *args):
  321. spaces_strs = self._spaces_printer(printer, *args)
  322. return '*'.join(spaces_strs)
  323. def _pretty(self, printer, *args):
  324. length = len(self.args)
  325. pform = printer._print('', *args)
  326. for i in range(length):
  327. next_pform = printer._print(self.args[i], *args)
  328. if isinstance(self.args[i], (DirectSumHilbertSpace,
  329. TensorProductHilbertSpace)):
  330. next_pform = prettyForm(
  331. *next_pform.parens(left='(', right=')')
  332. )
  333. pform = prettyForm(*pform.right(next_pform))
  334. if i != length - 1:
  335. if printer._use_unicode:
  336. pform = prettyForm(*pform.right(' ' + '\N{N-ARY CIRCLED TIMES OPERATOR}' + ' '))
  337. else:
  338. pform = prettyForm(*pform.right(' x '))
  339. return pform
  340. def _latex(self, printer, *args):
  341. length = len(self.args)
  342. s = ''
  343. for i in range(length):
  344. arg_s = printer._print(self.args[i], *args)
  345. if isinstance(self.args[i], (DirectSumHilbertSpace,
  346. TensorProductHilbertSpace)):
  347. arg_s = r'\left(%s\right)' % arg_s
  348. s = s + arg_s
  349. if i != length - 1:
  350. s = s + r'\otimes '
  351. return s
  352. class DirectSumHilbertSpace(HilbertSpace):
  353. """A direct sum of Hilbert spaces [1]_.
  354. This class uses the ``+`` operator to represent direct sums between
  355. different Hilbert spaces.
  356. A ``DirectSumHilbertSpace`` object takes in an arbitrary number of
  357. ``HilbertSpace`` objects as its arguments. Also, addition of
  358. ``HilbertSpace`` objects will automatically return a direct sum object.
  359. Examples
  360. ========
  361. >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace
  362. >>> c = ComplexSpace(2)
  363. >>> f = FockSpace()
  364. >>> hs = c+f
  365. >>> hs
  366. C(2)+F
  367. >>> hs.dimension
  368. oo
  369. >>> list(hs.spaces)
  370. [C(2), F]
  371. References
  372. ==========
  373. .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Direct_sums
  374. """
  375. def __new__(cls, *args):
  376. r = cls.eval(args)
  377. if isinstance(r, Basic):
  378. return r
  379. obj = Basic.__new__(cls, *args)
  380. return obj
  381. @classmethod
  382. def eval(cls, args):
  383. """Evaluates the direct product."""
  384. new_args = []
  385. recall = False
  386. #flatten arguments
  387. for arg in args:
  388. if isinstance(arg, DirectSumHilbertSpace):
  389. new_args.extend(arg.args)
  390. recall = True
  391. elif isinstance(arg, HilbertSpace):
  392. new_args.append(arg)
  393. else:
  394. raise TypeError('Hilbert spaces can only be summed with other \
  395. Hilbert spaces: %r' % arg)
  396. if recall:
  397. return DirectSumHilbertSpace(*new_args)
  398. else:
  399. return None
  400. @property
  401. def dimension(self):
  402. arg_list = [arg.dimension for arg in self.args]
  403. if oo in arg_list:
  404. return oo
  405. else:
  406. return reduce(lambda x, y: x + y, arg_list)
  407. @property
  408. def spaces(self):
  409. """A tuple of the Hilbert spaces in this direct sum."""
  410. return self.args
  411. def _sympyrepr(self, printer, *args):
  412. spaces_reprs = [printer._print(arg, *args) for arg in self.args]
  413. return "DirectSumHilbertSpace(%s)" % ','.join(spaces_reprs)
  414. def _sympystr(self, printer, *args):
  415. spaces_strs = [printer._print(arg, *args) for arg in self.args]
  416. return '+'.join(spaces_strs)
  417. def _pretty(self, printer, *args):
  418. length = len(self.args)
  419. pform = printer._print('', *args)
  420. for i in range(length):
  421. next_pform = printer._print(self.args[i], *args)
  422. if isinstance(self.args[i], (DirectSumHilbertSpace,
  423. TensorProductHilbertSpace)):
  424. next_pform = prettyForm(
  425. *next_pform.parens(left='(', right=')')
  426. )
  427. pform = prettyForm(*pform.right(next_pform))
  428. if i != length - 1:
  429. if printer._use_unicode:
  430. pform = prettyForm(*pform.right(' \N{CIRCLED PLUS} '))
  431. else:
  432. pform = prettyForm(*pform.right(' + '))
  433. return pform
  434. def _latex(self, printer, *args):
  435. length = len(self.args)
  436. s = ''
  437. for i in range(length):
  438. arg_s = printer._print(self.args[i], *args)
  439. if isinstance(self.args[i], (DirectSumHilbertSpace,
  440. TensorProductHilbertSpace)):
  441. arg_s = r'\left(%s\right)' % arg_s
  442. s = s + arg_s
  443. if i != length - 1:
  444. s = s + r'\oplus '
  445. return s
  446. class TensorPowerHilbertSpace(HilbertSpace):
  447. """An exponentiated Hilbert space [1]_.
  448. Tensor powers (repeated tensor products) are represented by the
  449. operator ``**`` Identical Hilbert spaces that are multiplied together
  450. will be automatically combined into a single tensor power object.
  451. Any Hilbert space, product, or sum may be raised to a tensor power. The
  452. ``TensorPowerHilbertSpace`` takes two arguments: the Hilbert space; and the
  453. tensor power (number).
  454. Examples
  455. ========
  456. >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace
  457. >>> from sympy import symbols
  458. >>> n = symbols('n')
  459. >>> c = ComplexSpace(2)
  460. >>> hs = c**n
  461. >>> hs
  462. C(2)**n
  463. >>> hs.dimension
  464. 2**n
  465. >>> c = ComplexSpace(2)
  466. >>> c*c
  467. C(2)**2
  468. >>> f = FockSpace()
  469. >>> c*f*f
  470. C(2)*F**2
  471. References
  472. ==========
  473. .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products
  474. """
  475. def __new__(cls, *args):
  476. r = cls.eval(args)
  477. if isinstance(r, Basic):
  478. return r
  479. return Basic.__new__(cls, *r)
  480. @classmethod
  481. def eval(cls, args):
  482. new_args = args[0], sympify(args[1])
  483. exp = new_args[1]
  484. #simplify hs**1 -> hs
  485. if exp == 1:
  486. return args[0]
  487. #simplify hs**0 -> 1
  488. if exp == 0:
  489. return sympify(1)
  490. #check (and allow) for hs**(x+42+y...) case
  491. if len(exp.atoms()) == 1:
  492. if not (exp.is_Integer and exp >= 0 or exp.is_Symbol):
  493. raise ValueError('Hilbert spaces can only be raised to \
  494. positive integers or Symbols: %r' % exp)
  495. else:
  496. for power in exp.atoms():
  497. if not (power.is_Integer or power.is_Symbol):
  498. raise ValueError('Tensor powers can only contain integers \
  499. or Symbols: %r' % power)
  500. return new_args
  501. @property
  502. def base(self):
  503. return self.args[0]
  504. @property
  505. def exp(self):
  506. return self.args[1]
  507. @property
  508. def dimension(self):
  509. if self.base.dimension is oo:
  510. return oo
  511. else:
  512. return self.base.dimension**self.exp
  513. def _sympyrepr(self, printer, *args):
  514. return "TensorPowerHilbertSpace(%s,%s)" % (printer._print(self.base,
  515. *args), printer._print(self.exp, *args))
  516. def _sympystr(self, printer, *args):
  517. return "%s**%s" % (printer._print(self.base, *args),
  518. printer._print(self.exp, *args))
  519. def _pretty(self, printer, *args):
  520. pform_exp = printer._print(self.exp, *args)
  521. if printer._use_unicode:
  522. pform_exp = prettyForm(*pform_exp.left(prettyForm('\N{N-ARY CIRCLED TIMES OPERATOR}')))
  523. else:
  524. pform_exp = prettyForm(*pform_exp.left(prettyForm('x')))
  525. pform_base = printer._print(self.base, *args)
  526. return pform_base**pform_exp
  527. def _latex(self, printer, *args):
  528. base = printer._print(self.base, *args)
  529. exp = printer._print(self.exp, *args)
  530. return r'{%s}^{\otimes %s}' % (base, exp)