图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

647 lines
19 KiB

  1. """Quantum mechanical operators.
  2. TODO:
  3. * Fix early 0 in apply_operators.
  4. * Debug and test apply_operators.
  5. * Get cse working with classes in this file.
  6. * Doctests and documentation of special methods for InnerProduct, Commutator,
  7. AntiCommutator, represent, apply_operators.
  8. """
  9. from sympy.core.add import Add
  10. from sympy.core.expr import Expr
  11. from sympy.core.function import (Derivative, expand)
  12. from sympy.core.mul import Mul
  13. from sympy.core.numbers import oo
  14. from sympy.core.singleton import S
  15. from sympy.printing.pretty.stringpict import prettyForm
  16. from sympy.physics.quantum.dagger import Dagger
  17. from sympy.physics.quantum.qexpr import QExpr, dispatch_method
  18. from sympy.matrices import eye
  19. __all__ = [
  20. 'Operator',
  21. 'HermitianOperator',
  22. 'UnitaryOperator',
  23. 'IdentityOperator',
  24. 'OuterProduct',
  25. 'DifferentialOperator'
  26. ]
  27. #-----------------------------------------------------------------------------
  28. # Operators and outer products
  29. #-----------------------------------------------------------------------------
  30. class Operator(QExpr):
  31. """Base class for non-commuting quantum operators.
  32. An operator maps between quantum states [1]_. In quantum mechanics,
  33. observables (including, but not limited to, measured physical values) are
  34. represented as Hermitian operators [2]_.
  35. Parameters
  36. ==========
  37. args : tuple
  38. The list of numbers or parameters that uniquely specify the
  39. operator. For time-dependent operators, this will include the time.
  40. Examples
  41. ========
  42. Create an operator and examine its attributes::
  43. >>> from sympy.physics.quantum import Operator
  44. >>> from sympy import I
  45. >>> A = Operator('A')
  46. >>> A
  47. A
  48. >>> A.hilbert_space
  49. H
  50. >>> A.label
  51. (A,)
  52. >>> A.is_commutative
  53. False
  54. Create another operator and do some arithmetic operations::
  55. >>> B = Operator('B')
  56. >>> C = 2*A*A + I*B
  57. >>> C
  58. 2*A**2 + I*B
  59. Operators do not commute::
  60. >>> A.is_commutative
  61. False
  62. >>> B.is_commutative
  63. False
  64. >>> A*B == B*A
  65. False
  66. Polymonials of operators respect the commutation properties::
  67. >>> e = (A+B)**3
  68. >>> e.expand()
  69. A*B*A + A*B**2 + A**2*B + A**3 + B*A*B + B*A**2 + B**2*A + B**3
  70. Operator inverses are handle symbolically::
  71. >>> A.inv()
  72. A**(-1)
  73. >>> A*A.inv()
  74. 1
  75. References
  76. ==========
  77. .. [1] https://en.wikipedia.org/wiki/Operator_%28physics%29
  78. .. [2] https://en.wikipedia.org/wiki/Observable
  79. """
  80. @classmethod
  81. def default_args(self):
  82. return ("O",)
  83. #-------------------------------------------------------------------------
  84. # Printing
  85. #-------------------------------------------------------------------------
  86. _label_separator = ','
  87. def _print_operator_name(self, printer, *args):
  88. return self.__class__.__name__
  89. _print_operator_name_latex = _print_operator_name
  90. def _print_operator_name_pretty(self, printer, *args):
  91. return prettyForm(self.__class__.__name__)
  92. def _print_contents(self, printer, *args):
  93. if len(self.label) == 1:
  94. return self._print_label(printer, *args)
  95. else:
  96. return '%s(%s)' % (
  97. self._print_operator_name(printer, *args),
  98. self._print_label(printer, *args)
  99. )
  100. def _print_contents_pretty(self, printer, *args):
  101. if len(self.label) == 1:
  102. return self._print_label_pretty(printer, *args)
  103. else:
  104. pform = self._print_operator_name_pretty(printer, *args)
  105. label_pform = self._print_label_pretty(printer, *args)
  106. label_pform = prettyForm(
  107. *label_pform.parens(left='(', right=')')
  108. )
  109. pform = prettyForm(*pform.right(label_pform))
  110. return pform
  111. def _print_contents_latex(self, printer, *args):
  112. if len(self.label) == 1:
  113. return self._print_label_latex(printer, *args)
  114. else:
  115. return r'%s\left(%s\right)' % (
  116. self._print_operator_name_latex(printer, *args),
  117. self._print_label_latex(printer, *args)
  118. )
  119. #-------------------------------------------------------------------------
  120. # _eval_* methods
  121. #-------------------------------------------------------------------------
  122. def _eval_commutator(self, other, **options):
  123. """Evaluate [self, other] if known, return None if not known."""
  124. return dispatch_method(self, '_eval_commutator', other, **options)
  125. def _eval_anticommutator(self, other, **options):
  126. """Evaluate [self, other] if known."""
  127. return dispatch_method(self, '_eval_anticommutator', other, **options)
  128. #-------------------------------------------------------------------------
  129. # Operator application
  130. #-------------------------------------------------------------------------
  131. def _apply_operator(self, ket, **options):
  132. return dispatch_method(self, '_apply_operator', ket, **options)
  133. def matrix_element(self, *args):
  134. raise NotImplementedError('matrix_elements is not defined')
  135. def inverse(self):
  136. return self._eval_inverse()
  137. inv = inverse
  138. def _eval_inverse(self):
  139. return self**(-1)
  140. def __mul__(self, other):
  141. if isinstance(other, IdentityOperator):
  142. return self
  143. return Mul(self, other)
  144. class HermitianOperator(Operator):
  145. """A Hermitian operator that satisfies H == Dagger(H).
  146. Parameters
  147. ==========
  148. args : tuple
  149. The list of numbers or parameters that uniquely specify the
  150. operator. For time-dependent operators, this will include the time.
  151. Examples
  152. ========
  153. >>> from sympy.physics.quantum import Dagger, HermitianOperator
  154. >>> H = HermitianOperator('H')
  155. >>> Dagger(H)
  156. H
  157. """
  158. is_hermitian = True
  159. def _eval_inverse(self):
  160. if isinstance(self, UnitaryOperator):
  161. return self
  162. else:
  163. return Operator._eval_inverse(self)
  164. def _eval_power(self, exp):
  165. if isinstance(self, UnitaryOperator):
  166. if exp == -1:
  167. return Operator._eval_power(self, exp)
  168. elif abs(exp) % 2 == 0:
  169. return self*(Operator._eval_inverse(self))
  170. else:
  171. return self
  172. else:
  173. return Operator._eval_power(self, exp)
  174. class UnitaryOperator(Operator):
  175. """A unitary operator that satisfies U*Dagger(U) == 1.
  176. Parameters
  177. ==========
  178. args : tuple
  179. The list of numbers or parameters that uniquely specify the
  180. operator. For time-dependent operators, this will include the time.
  181. Examples
  182. ========
  183. >>> from sympy.physics.quantum import Dagger, UnitaryOperator
  184. >>> U = UnitaryOperator('U')
  185. >>> U*Dagger(U)
  186. 1
  187. """
  188. def _eval_adjoint(self):
  189. return self._eval_inverse()
  190. class IdentityOperator(Operator):
  191. """An identity operator I that satisfies op * I == I * op == op for any
  192. operator op.
  193. Parameters
  194. ==========
  195. N : Integer
  196. Optional parameter that specifies the dimension of the Hilbert space
  197. of operator. This is used when generating a matrix representation.
  198. Examples
  199. ========
  200. >>> from sympy.physics.quantum import IdentityOperator
  201. >>> IdentityOperator()
  202. I
  203. """
  204. @property
  205. def dimension(self):
  206. return self.N
  207. @classmethod
  208. def default_args(self):
  209. return (oo,)
  210. def __init__(self, *args, **hints):
  211. if not len(args) in (0, 1):
  212. raise ValueError('0 or 1 parameters expected, got %s' % args)
  213. self.N = args[0] if (len(args) == 1 and args[0]) else oo
  214. def _eval_commutator(self, other, **hints):
  215. return S.Zero
  216. def _eval_anticommutator(self, other, **hints):
  217. return 2 * other
  218. def _eval_inverse(self):
  219. return self
  220. def _eval_adjoint(self):
  221. return self
  222. def _apply_operator(self, ket, **options):
  223. return ket
  224. def _eval_power(self, exp):
  225. return self
  226. def _print_contents(self, printer, *args):
  227. return 'I'
  228. def _print_contents_pretty(self, printer, *args):
  229. return prettyForm('I')
  230. def _print_contents_latex(self, printer, *args):
  231. return r'{\mathcal{I}}'
  232. def __mul__(self, other):
  233. if isinstance(other, (Operator, Dagger)):
  234. return other
  235. return Mul(self, other)
  236. def _represent_default_basis(self, **options):
  237. if not self.N or self.N == oo:
  238. raise NotImplementedError('Cannot represent infinite dimensional' +
  239. ' identity operator as a matrix')
  240. format = options.get('format', 'sympy')
  241. if format != 'sympy':
  242. raise NotImplementedError('Representation in format ' +
  243. '%s not implemented.' % format)
  244. return eye(self.N)
  245. class OuterProduct(Operator):
  246. """An unevaluated outer product between a ket and bra.
  247. This constructs an outer product between any subclass of ``KetBase`` and
  248. ``BraBase`` as ``|a><b|``. An ``OuterProduct`` inherits from Operator as they act as
  249. operators in quantum expressions. For reference see [1]_.
  250. Parameters
  251. ==========
  252. ket : KetBase
  253. The ket on the left side of the outer product.
  254. bar : BraBase
  255. The bra on the right side of the outer product.
  256. Examples
  257. ========
  258. Create a simple outer product by hand and take its dagger::
  259. >>> from sympy.physics.quantum import Ket, Bra, OuterProduct, Dagger
  260. >>> from sympy.physics.quantum import Operator
  261. >>> k = Ket('k')
  262. >>> b = Bra('b')
  263. >>> op = OuterProduct(k, b)
  264. >>> op
  265. |k><b|
  266. >>> op.hilbert_space
  267. H
  268. >>> op.ket
  269. |k>
  270. >>> op.bra
  271. <b|
  272. >>> Dagger(op)
  273. |b><k|
  274. In simple products of kets and bras outer products will be automatically
  275. identified and created::
  276. >>> k*b
  277. |k><b|
  278. But in more complex expressions, outer products are not automatically
  279. created::
  280. >>> A = Operator('A')
  281. >>> A*k*b
  282. A*|k>*<b|
  283. A user can force the creation of an outer product in a complex expression
  284. by using parentheses to group the ket and bra::
  285. >>> A*(k*b)
  286. A*|k><b|
  287. References
  288. ==========
  289. .. [1] https://en.wikipedia.org/wiki/Outer_product
  290. """
  291. is_commutative = False
  292. def __new__(cls, *args, **old_assumptions):
  293. from sympy.physics.quantum.state import KetBase, BraBase
  294. if len(args) != 2:
  295. raise ValueError('2 parameters expected, got %d' % len(args))
  296. ket_expr = expand(args[0])
  297. bra_expr = expand(args[1])
  298. if (isinstance(ket_expr, (KetBase, Mul)) and
  299. isinstance(bra_expr, (BraBase, Mul))):
  300. ket_c, kets = ket_expr.args_cnc()
  301. bra_c, bras = bra_expr.args_cnc()
  302. if len(kets) != 1 or not isinstance(kets[0], KetBase):
  303. raise TypeError('KetBase subclass expected'
  304. ', got: %r' % Mul(*kets))
  305. if len(bras) != 1 or not isinstance(bras[0], BraBase):
  306. raise TypeError('BraBase subclass expected'
  307. ', got: %r' % Mul(*bras))
  308. if not kets[0].dual_class() == bras[0].__class__:
  309. raise TypeError(
  310. 'ket and bra are not dual classes: %r, %r' %
  311. (kets[0].__class__, bras[0].__class__)
  312. )
  313. # TODO: make sure the hilbert spaces of the bra and ket are
  314. # compatible
  315. obj = Expr.__new__(cls, *(kets[0], bras[0]), **old_assumptions)
  316. obj.hilbert_space = kets[0].hilbert_space
  317. return Mul(*(ket_c + bra_c)) * obj
  318. op_terms = []
  319. if isinstance(ket_expr, Add) and isinstance(bra_expr, Add):
  320. for ket_term in ket_expr.args:
  321. for bra_term in bra_expr.args:
  322. op_terms.append(OuterProduct(ket_term, bra_term,
  323. **old_assumptions))
  324. elif isinstance(ket_expr, Add):
  325. for ket_term in ket_expr.args:
  326. op_terms.append(OuterProduct(ket_term, bra_expr,
  327. **old_assumptions))
  328. elif isinstance(bra_expr, Add):
  329. for bra_term in bra_expr.args:
  330. op_terms.append(OuterProduct(ket_expr, bra_term,
  331. **old_assumptions))
  332. else:
  333. raise TypeError(
  334. 'Expected ket and bra expression, got: %r, %r' %
  335. (ket_expr, bra_expr)
  336. )
  337. return Add(*op_terms)
  338. @property
  339. def ket(self):
  340. """Return the ket on the left side of the outer product."""
  341. return self.args[0]
  342. @property
  343. def bra(self):
  344. """Return the bra on the right side of the outer product."""
  345. return self.args[1]
  346. def _eval_adjoint(self):
  347. return OuterProduct(Dagger(self.bra), Dagger(self.ket))
  348. def _sympystr(self, printer, *args):
  349. return printer._print(self.ket) + printer._print(self.bra)
  350. def _sympyrepr(self, printer, *args):
  351. return '%s(%s,%s)' % (self.__class__.__name__,
  352. printer._print(self.ket, *args), printer._print(self.bra, *args))
  353. def _pretty(self, printer, *args):
  354. pform = self.ket._pretty(printer, *args)
  355. return prettyForm(*pform.right(self.bra._pretty(printer, *args)))
  356. def _latex(self, printer, *args):
  357. k = printer._print(self.ket, *args)
  358. b = printer._print(self.bra, *args)
  359. return k + b
  360. def _represent(self, **options):
  361. k = self.ket._represent(**options)
  362. b = self.bra._represent(**options)
  363. return k*b
  364. def _eval_trace(self, **kwargs):
  365. # TODO if operands are tensorproducts this may be will be handled
  366. # differently.
  367. return self.ket._eval_trace(self.bra, **kwargs)
  368. class DifferentialOperator(Operator):
  369. """An operator for representing the differential operator, i.e. d/dx
  370. It is initialized by passing two arguments. The first is an arbitrary
  371. expression that involves a function, such as ``Derivative(f(x), x)``. The
  372. second is the function (e.g. ``f(x)``) which we are to replace with the
  373. ``Wavefunction`` that this ``DifferentialOperator`` is applied to.
  374. Parameters
  375. ==========
  376. expr : Expr
  377. The arbitrary expression which the appropriate Wavefunction is to be
  378. substituted into
  379. func : Expr
  380. A function (e.g. f(x)) which is to be replaced with the appropriate
  381. Wavefunction when this DifferentialOperator is applied
  382. Examples
  383. ========
  384. You can define a completely arbitrary expression and specify where the
  385. Wavefunction is to be substituted
  386. >>> from sympy import Derivative, Function, Symbol
  387. >>> from sympy.physics.quantum.operator import DifferentialOperator
  388. >>> from sympy.physics.quantum.state import Wavefunction
  389. >>> from sympy.physics.quantum.qapply import qapply
  390. >>> f = Function('f')
  391. >>> x = Symbol('x')
  392. >>> d = DifferentialOperator(1/x*Derivative(f(x), x), f(x))
  393. >>> w = Wavefunction(x**2, x)
  394. >>> d.function
  395. f(x)
  396. >>> d.variables
  397. (x,)
  398. >>> qapply(d*w)
  399. Wavefunction(2, x)
  400. """
  401. @property
  402. def variables(self):
  403. """
  404. Returns the variables with which the function in the specified
  405. arbitrary expression is evaluated
  406. Examples
  407. ========
  408. >>> from sympy.physics.quantum.operator import DifferentialOperator
  409. >>> from sympy import Symbol, Function, Derivative
  410. >>> x = Symbol('x')
  411. >>> f = Function('f')
  412. >>> d = DifferentialOperator(1/x*Derivative(f(x), x), f(x))
  413. >>> d.variables
  414. (x,)
  415. >>> y = Symbol('y')
  416. >>> d = DifferentialOperator(Derivative(f(x, y), x) +
  417. ... Derivative(f(x, y), y), f(x, y))
  418. >>> d.variables
  419. (x, y)
  420. """
  421. return self.args[-1].args
  422. @property
  423. def function(self):
  424. """
  425. Returns the function which is to be replaced with the Wavefunction
  426. Examples
  427. ========
  428. >>> from sympy.physics.quantum.operator import DifferentialOperator
  429. >>> from sympy import Function, Symbol, Derivative
  430. >>> x = Symbol('x')
  431. >>> f = Function('f')
  432. >>> d = DifferentialOperator(Derivative(f(x), x), f(x))
  433. >>> d.function
  434. f(x)
  435. >>> y = Symbol('y')
  436. >>> d = DifferentialOperator(Derivative(f(x, y), x) +
  437. ... Derivative(f(x, y), y), f(x, y))
  438. >>> d.function
  439. f(x, y)
  440. """
  441. return self.args[-1]
  442. @property
  443. def expr(self):
  444. """
  445. Returns the arbitrary expression which is to have the Wavefunction
  446. substituted into it
  447. Examples
  448. ========
  449. >>> from sympy.physics.quantum.operator import DifferentialOperator
  450. >>> from sympy import Function, Symbol, Derivative
  451. >>> x = Symbol('x')
  452. >>> f = Function('f')
  453. >>> d = DifferentialOperator(Derivative(f(x), x), f(x))
  454. >>> d.expr
  455. Derivative(f(x), x)
  456. >>> y = Symbol('y')
  457. >>> d = DifferentialOperator(Derivative(f(x, y), x) +
  458. ... Derivative(f(x, y), y), f(x, y))
  459. >>> d.expr
  460. Derivative(f(x, y), x) + Derivative(f(x, y), y)
  461. """
  462. return self.args[0]
  463. @property
  464. def free_symbols(self):
  465. """
  466. Return the free symbols of the expression.
  467. """
  468. return self.expr.free_symbols
  469. def _apply_operator_Wavefunction(self, func):
  470. from sympy.physics.quantum.state import Wavefunction
  471. var = self.variables
  472. wf_vars = func.args[1:]
  473. f = self.function
  474. new_expr = self.expr.subs(f, func(*var))
  475. new_expr = new_expr.doit()
  476. return Wavefunction(new_expr, *wf_vars)
  477. def _eval_derivative(self, symbol):
  478. new_expr = Derivative(self.expr, symbol)
  479. return DifferentialOperator(new_expr, self.args[-1])
  480. #-------------------------------------------------------------------------
  481. # Printing
  482. #-------------------------------------------------------------------------
  483. def _print(self, printer, *args):
  484. return '%s(%s)' % (
  485. self._print_operator_name(printer, *args),
  486. self._print_label(printer, *args)
  487. )
  488. def _print_pretty(self, printer, *args):
  489. pform = self._print_operator_name_pretty(printer, *args)
  490. label_pform = self._print_label_pretty(printer, *args)
  491. label_pform = prettyForm(
  492. *label_pform.parens(left='(', right=')')
  493. )
  494. pform = prettyForm(*pform.right(label_pform))
  495. return pform