pauli.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. """Pauli operators and states"""
  2. from sympy.core.add import Add
  3. from sympy.core.mul import Mul
  4. from sympy.core.numbers import I
  5. from sympy.core.power import Pow
  6. from sympy.core.singleton import S
  7. from sympy.functions.elementary.exponential import exp
  8. from sympy.physics.quantum import Operator, Ket, Bra
  9. from sympy.physics.quantum import ComplexSpace
  10. from sympy.matrices import Matrix
  11. from sympy.functions.special.tensor_functions import KroneckerDelta
  12. __all__ = [
  13. 'SigmaX', 'SigmaY', 'SigmaZ', 'SigmaMinus', 'SigmaPlus', 'SigmaZKet',
  14. 'SigmaZBra', 'qsimplify_pauli'
  15. ]
  16. class SigmaOpBase(Operator):
  17. """Pauli sigma operator, base class"""
  18. @property
  19. def name(self):
  20. return self.args[0]
  21. @property
  22. def use_name(self):
  23. return bool(self.args[0]) is not False
  24. @classmethod
  25. def default_args(self):
  26. return (False,)
  27. def __new__(cls, *args, **hints):
  28. return Operator.__new__(cls, *args, **hints)
  29. def _eval_commutator_BosonOp(self, other, **hints):
  30. return S.Zero
  31. class SigmaX(SigmaOpBase):
  32. """Pauli sigma x operator
  33. Parameters
  34. ==========
  35. name : str
  36. An optional string that labels the operator. Pauli operators with
  37. different names commute.
  38. Examples
  39. ========
  40. >>> from sympy.physics.quantum import represent
  41. >>> from sympy.physics.quantum.pauli import SigmaX
  42. >>> sx = SigmaX()
  43. >>> sx
  44. SigmaX()
  45. >>> represent(sx)
  46. Matrix([
  47. [0, 1],
  48. [1, 0]])
  49. """
  50. def __new__(cls, *args, **hints):
  51. return SigmaOpBase.__new__(cls, *args, **hints)
  52. def _eval_commutator_SigmaY(self, other, **hints):
  53. if self.name != other.name:
  54. return S.Zero
  55. else:
  56. return 2 * I * SigmaZ(self.name)
  57. def _eval_commutator_SigmaZ(self, other, **hints):
  58. if self.name != other.name:
  59. return S.Zero
  60. else:
  61. return - 2 * I * SigmaY(self.name)
  62. def _eval_commutator_BosonOp(self, other, **hints):
  63. return S.Zero
  64. def _eval_anticommutator_SigmaY(self, other, **hints):
  65. return S.Zero
  66. def _eval_anticommutator_SigmaZ(self, other, **hints):
  67. return S.Zero
  68. def _eval_adjoint(self):
  69. return self
  70. def _print_contents_latex(self, printer, *args):
  71. if self.use_name:
  72. return r'{\sigma_x^{(%s)}}' % str(self.name)
  73. else:
  74. return r'{\sigma_x}'
  75. def _print_contents(self, printer, *args):
  76. return 'SigmaX()'
  77. def _eval_power(self, e):
  78. if e.is_Integer and e.is_positive:
  79. return SigmaX(self.name).__pow__(int(e) % 2)
  80. def _represent_default_basis(self, **options):
  81. format = options.get('format', 'sympy')
  82. if format == 'sympy':
  83. return Matrix([[0, 1], [1, 0]])
  84. else:
  85. raise NotImplementedError('Representation in format ' +
  86. format + ' not implemented.')
  87. class SigmaY(SigmaOpBase):
  88. """Pauli sigma y operator
  89. Parameters
  90. ==========
  91. name : str
  92. An optional string that labels the operator. Pauli operators with
  93. different names commute.
  94. Examples
  95. ========
  96. >>> from sympy.physics.quantum import represent
  97. >>> from sympy.physics.quantum.pauli import SigmaY
  98. >>> sy = SigmaY()
  99. >>> sy
  100. SigmaY()
  101. >>> represent(sy)
  102. Matrix([
  103. [0, -I],
  104. [I, 0]])
  105. """
  106. def __new__(cls, *args, **hints):
  107. return SigmaOpBase.__new__(cls, *args)
  108. def _eval_commutator_SigmaZ(self, other, **hints):
  109. if self.name != other.name:
  110. return S.Zero
  111. else:
  112. return 2 * I * SigmaX(self.name)
  113. def _eval_commutator_SigmaX(self, other, **hints):
  114. if self.name != other.name:
  115. return S.Zero
  116. else:
  117. return - 2 * I * SigmaZ(self.name)
  118. def _eval_anticommutator_SigmaX(self, other, **hints):
  119. return S.Zero
  120. def _eval_anticommutator_SigmaZ(self, other, **hints):
  121. return S.Zero
  122. def _eval_adjoint(self):
  123. return self
  124. def _print_contents_latex(self, printer, *args):
  125. if self.use_name:
  126. return r'{\sigma_y^{(%s)}}' % str(self.name)
  127. else:
  128. return r'{\sigma_y}'
  129. def _print_contents(self, printer, *args):
  130. return 'SigmaY()'
  131. def _eval_power(self, e):
  132. if e.is_Integer and e.is_positive:
  133. return SigmaY(self.name).__pow__(int(e) % 2)
  134. def _represent_default_basis(self, **options):
  135. format = options.get('format', 'sympy')
  136. if format == 'sympy':
  137. return Matrix([[0, -I], [I, 0]])
  138. else:
  139. raise NotImplementedError('Representation in format ' +
  140. format + ' not implemented.')
  141. class SigmaZ(SigmaOpBase):
  142. """Pauli sigma z operator
  143. Parameters
  144. ==========
  145. name : str
  146. An optional string that labels the operator. Pauli operators with
  147. different names commute.
  148. Examples
  149. ========
  150. >>> from sympy.physics.quantum import represent
  151. >>> from sympy.physics.quantum.pauli import SigmaZ
  152. >>> sz = SigmaZ()
  153. >>> sz ** 3
  154. SigmaZ()
  155. >>> represent(sz)
  156. Matrix([
  157. [1, 0],
  158. [0, -1]])
  159. """
  160. def __new__(cls, *args, **hints):
  161. return SigmaOpBase.__new__(cls, *args)
  162. def _eval_commutator_SigmaX(self, other, **hints):
  163. if self.name != other.name:
  164. return S.Zero
  165. else:
  166. return 2 * I * SigmaY(self.name)
  167. def _eval_commutator_SigmaY(self, other, **hints):
  168. if self.name != other.name:
  169. return S.Zero
  170. else:
  171. return - 2 * I * SigmaX(self.name)
  172. def _eval_anticommutator_SigmaX(self, other, **hints):
  173. return S.Zero
  174. def _eval_anticommutator_SigmaY(self, other, **hints):
  175. return S.Zero
  176. def _eval_adjoint(self):
  177. return self
  178. def _print_contents_latex(self, printer, *args):
  179. if self.use_name:
  180. return r'{\sigma_z^{(%s)}}' % str(self.name)
  181. else:
  182. return r'{\sigma_z}'
  183. def _print_contents(self, printer, *args):
  184. return 'SigmaZ()'
  185. def _eval_power(self, e):
  186. if e.is_Integer and e.is_positive:
  187. return SigmaZ(self.name).__pow__(int(e) % 2)
  188. def _represent_default_basis(self, **options):
  189. format = options.get('format', 'sympy')
  190. if format == 'sympy':
  191. return Matrix([[1, 0], [0, -1]])
  192. else:
  193. raise NotImplementedError('Representation in format ' +
  194. format + ' not implemented.')
  195. class SigmaMinus(SigmaOpBase):
  196. """Pauli sigma minus operator
  197. Parameters
  198. ==========
  199. name : str
  200. An optional string that labels the operator. Pauli operators with
  201. different names commute.
  202. Examples
  203. ========
  204. >>> from sympy.physics.quantum import represent, Dagger
  205. >>> from sympy.physics.quantum.pauli import SigmaMinus
  206. >>> sm = SigmaMinus()
  207. >>> sm
  208. SigmaMinus()
  209. >>> Dagger(sm)
  210. SigmaPlus()
  211. >>> represent(sm)
  212. Matrix([
  213. [0, 0],
  214. [1, 0]])
  215. """
  216. def __new__(cls, *args, **hints):
  217. return SigmaOpBase.__new__(cls, *args)
  218. def _eval_commutator_SigmaX(self, other, **hints):
  219. if self.name != other.name:
  220. return S.Zero
  221. else:
  222. return -SigmaZ(self.name)
  223. def _eval_commutator_SigmaY(self, other, **hints):
  224. if self.name != other.name:
  225. return S.Zero
  226. else:
  227. return I * SigmaZ(self.name)
  228. def _eval_commutator_SigmaZ(self, other, **hints):
  229. return 2 * self
  230. def _eval_commutator_SigmaMinus(self, other, **hints):
  231. return SigmaZ(self.name)
  232. def _eval_anticommutator_SigmaZ(self, other, **hints):
  233. return S.Zero
  234. def _eval_anticommutator_SigmaX(self, other, **hints):
  235. return S.One
  236. def _eval_anticommutator_SigmaY(self, other, **hints):
  237. return I * S.NegativeOne
  238. def _eval_anticommutator_SigmaPlus(self, other, **hints):
  239. return S.One
  240. def _eval_adjoint(self):
  241. return SigmaPlus(self.name)
  242. def _eval_power(self, e):
  243. if e.is_Integer and e.is_positive:
  244. return S.Zero
  245. def _print_contents_latex(self, printer, *args):
  246. if self.use_name:
  247. return r'{\sigma_-^{(%s)}}' % str(self.name)
  248. else:
  249. return r'{\sigma_-}'
  250. def _print_contents(self, printer, *args):
  251. return 'SigmaMinus()'
  252. def _represent_default_basis(self, **options):
  253. format = options.get('format', 'sympy')
  254. if format == 'sympy':
  255. return Matrix([[0, 0], [1, 0]])
  256. else:
  257. raise NotImplementedError('Representation in format ' +
  258. format + ' not implemented.')
  259. class SigmaPlus(SigmaOpBase):
  260. """Pauli sigma plus operator
  261. Parameters
  262. ==========
  263. name : str
  264. An optional string that labels the operator. Pauli operators with
  265. different names commute.
  266. Examples
  267. ========
  268. >>> from sympy.physics.quantum import represent, Dagger
  269. >>> from sympy.physics.quantum.pauli import SigmaPlus
  270. >>> sp = SigmaPlus()
  271. >>> sp
  272. SigmaPlus()
  273. >>> Dagger(sp)
  274. SigmaMinus()
  275. >>> represent(sp)
  276. Matrix([
  277. [0, 1],
  278. [0, 0]])
  279. """
  280. def __new__(cls, *args, **hints):
  281. return SigmaOpBase.__new__(cls, *args)
  282. def _eval_commutator_SigmaX(self, other, **hints):
  283. if self.name != other.name:
  284. return S.Zero
  285. else:
  286. return SigmaZ(self.name)
  287. def _eval_commutator_SigmaY(self, other, **hints):
  288. if self.name != other.name:
  289. return S.Zero
  290. else:
  291. return I * SigmaZ(self.name)
  292. def _eval_commutator_SigmaZ(self, other, **hints):
  293. if self.name != other.name:
  294. return S.Zero
  295. else:
  296. return -2 * self
  297. def _eval_commutator_SigmaMinus(self, other, **hints):
  298. return SigmaZ(self.name)
  299. def _eval_anticommutator_SigmaZ(self, other, **hints):
  300. return S.Zero
  301. def _eval_anticommutator_SigmaX(self, other, **hints):
  302. return S.One
  303. def _eval_anticommutator_SigmaY(self, other, **hints):
  304. return I
  305. def _eval_anticommutator_SigmaMinus(self, other, **hints):
  306. return S.One
  307. def _eval_adjoint(self):
  308. return SigmaMinus(self.name)
  309. def _eval_mul(self, other):
  310. return self * other
  311. def _eval_power(self, e):
  312. if e.is_Integer and e.is_positive:
  313. return S.Zero
  314. def _print_contents_latex(self, printer, *args):
  315. if self.use_name:
  316. return r'{\sigma_+^{(%s)}}' % str(self.name)
  317. else:
  318. return r'{\sigma_+}'
  319. def _print_contents(self, printer, *args):
  320. return 'SigmaPlus()'
  321. def _represent_default_basis(self, **options):
  322. format = options.get('format', 'sympy')
  323. if format == 'sympy':
  324. return Matrix([[0, 1], [0, 0]])
  325. else:
  326. raise NotImplementedError('Representation in format ' +
  327. format + ' not implemented.')
  328. class SigmaZKet(Ket):
  329. """Ket for a two-level system quantum system.
  330. Parameters
  331. ==========
  332. n : Number
  333. The state number (0 or 1).
  334. """
  335. def __new__(cls, n):
  336. if n not in (0, 1):
  337. raise ValueError("n must be 0 or 1")
  338. return Ket.__new__(cls, n)
  339. @property
  340. def n(self):
  341. return self.label[0]
  342. @classmethod
  343. def dual_class(self):
  344. return SigmaZBra
  345. @classmethod
  346. def _eval_hilbert_space(cls, label):
  347. return ComplexSpace(2)
  348. def _eval_innerproduct_SigmaZBra(self, bra, **hints):
  349. return KroneckerDelta(self.n, bra.n)
  350. def _apply_operator_SigmaZ(self, op, **options):
  351. if self.n == 0:
  352. return self
  353. else:
  354. return S.NegativeOne * self
  355. def _apply_operator_SigmaX(self, op, **options):
  356. return SigmaZKet(1) if self.n == 0 else SigmaZKet(0)
  357. def _apply_operator_SigmaY(self, op, **options):
  358. return I * SigmaZKet(1) if self.n == 0 else (-I) * SigmaZKet(0)
  359. def _apply_operator_SigmaMinus(self, op, **options):
  360. if self.n == 0:
  361. return SigmaZKet(1)
  362. else:
  363. return S.Zero
  364. def _apply_operator_SigmaPlus(self, op, **options):
  365. if self.n == 0:
  366. return S.Zero
  367. else:
  368. return SigmaZKet(0)
  369. def _represent_default_basis(self, **options):
  370. format = options.get('format', 'sympy')
  371. if format == 'sympy':
  372. return Matrix([[1], [0]]) if self.n == 0 else Matrix([[0], [1]])
  373. else:
  374. raise NotImplementedError('Representation in format ' +
  375. format + ' not implemented.')
  376. class SigmaZBra(Bra):
  377. """Bra for a two-level quantum system.
  378. Parameters
  379. ==========
  380. n : Number
  381. The state number (0 or 1).
  382. """
  383. def __new__(cls, n):
  384. if n not in (0, 1):
  385. raise ValueError("n must be 0 or 1")
  386. return Bra.__new__(cls, n)
  387. @property
  388. def n(self):
  389. return self.label[0]
  390. @classmethod
  391. def dual_class(self):
  392. return SigmaZKet
  393. def _qsimplify_pauli_product(a, b):
  394. """
  395. Internal helper function for simplifying products of Pauli operators.
  396. """
  397. if not (isinstance(a, SigmaOpBase) and isinstance(b, SigmaOpBase)):
  398. return Mul(a, b)
  399. if a.name != b.name:
  400. # Pauli matrices with different labels commute; sort by name
  401. if a.name < b.name:
  402. return Mul(a, b)
  403. else:
  404. return Mul(b, a)
  405. elif isinstance(a, SigmaX):
  406. if isinstance(b, SigmaX):
  407. return S.One
  408. if isinstance(b, SigmaY):
  409. return I * SigmaZ(a.name)
  410. if isinstance(b, SigmaZ):
  411. return - I * SigmaY(a.name)
  412. if isinstance(b, SigmaMinus):
  413. return (S.Half + SigmaZ(a.name)/2)
  414. if isinstance(b, SigmaPlus):
  415. return (S.Half - SigmaZ(a.name)/2)
  416. elif isinstance(a, SigmaY):
  417. if isinstance(b, SigmaX):
  418. return - I * SigmaZ(a.name)
  419. if isinstance(b, SigmaY):
  420. return S.One
  421. if isinstance(b, SigmaZ):
  422. return I * SigmaX(a.name)
  423. if isinstance(b, SigmaMinus):
  424. return -I * (S.One + SigmaZ(a.name))/2
  425. if isinstance(b, SigmaPlus):
  426. return I * (S.One - SigmaZ(a.name))/2
  427. elif isinstance(a, SigmaZ):
  428. if isinstance(b, SigmaX):
  429. return I * SigmaY(a.name)
  430. if isinstance(b, SigmaY):
  431. return - I * SigmaX(a.name)
  432. if isinstance(b, SigmaZ):
  433. return S.One
  434. if isinstance(b, SigmaMinus):
  435. return - SigmaMinus(a.name)
  436. if isinstance(b, SigmaPlus):
  437. return SigmaPlus(a.name)
  438. elif isinstance(a, SigmaMinus):
  439. if isinstance(b, SigmaX):
  440. return (S.One - SigmaZ(a.name))/2
  441. if isinstance(b, SigmaY):
  442. return - I * (S.One - SigmaZ(a.name))/2
  443. if isinstance(b, SigmaZ):
  444. # (SigmaX(a.name) - I * SigmaY(a.name))/2
  445. return SigmaMinus(b.name)
  446. if isinstance(b, SigmaMinus):
  447. return S.Zero
  448. if isinstance(b, SigmaPlus):
  449. return S.Half - SigmaZ(a.name)/2
  450. elif isinstance(a, SigmaPlus):
  451. if isinstance(b, SigmaX):
  452. return (S.One + SigmaZ(a.name))/2
  453. if isinstance(b, SigmaY):
  454. return I * (S.One + SigmaZ(a.name))/2
  455. if isinstance(b, SigmaZ):
  456. #-(SigmaX(a.name) + I * SigmaY(a.name))/2
  457. return -SigmaPlus(a.name)
  458. if isinstance(b, SigmaMinus):
  459. return (S.One + SigmaZ(a.name))/2
  460. if isinstance(b, SigmaPlus):
  461. return S.Zero
  462. else:
  463. return a * b
  464. def qsimplify_pauli(e):
  465. """
  466. Simplify an expression that includes products of pauli operators.
  467. Parameters
  468. ==========
  469. e : expression
  470. An expression that contains products of Pauli operators that is
  471. to be simplified.
  472. Examples
  473. ========
  474. >>> from sympy.physics.quantum.pauli import SigmaX, SigmaY
  475. >>> from sympy.physics.quantum.pauli import qsimplify_pauli
  476. >>> sx, sy = SigmaX(), SigmaY()
  477. >>> sx * sy
  478. SigmaX()*SigmaY()
  479. >>> qsimplify_pauli(sx * sy)
  480. I*SigmaZ()
  481. """
  482. if isinstance(e, Operator):
  483. return e
  484. if isinstance(e, (Add, Pow, exp)):
  485. t = type(e)
  486. return t(*(qsimplify_pauli(arg) for arg in e.args))
  487. if isinstance(e, Mul):
  488. c, nc = e.args_cnc()
  489. nc_s = []
  490. while nc:
  491. curr = nc.pop(0)
  492. while (len(nc) and
  493. isinstance(curr, SigmaOpBase) and
  494. isinstance(nc[0], SigmaOpBase) and
  495. curr.name == nc[0].name):
  496. x = nc.pop(0)
  497. y = _qsimplify_pauli_product(curr, x)
  498. c1, nc1 = y.args_cnc()
  499. curr = Mul(*nc1)
  500. c = c + c1
  501. nc_s.append(curr)
  502. return Mul(*c) * Mul(*nc_s)
  503. return e