paulialgebra.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. """
  2. This module implements Pauli algebra by subclassing Symbol. Only algebraic
  3. properties of Pauli matrices are used (we do not use the Matrix class).
  4. See the documentation to the class Pauli for examples.
  5. References
  6. ==========
  7. .. [1] https://en.wikipedia.org/wiki/Pauli_matrices
  8. """
  9. from sympy.core.add import Add
  10. from sympy.core.mul import Mul
  11. from sympy.core.numbers import I
  12. from sympy.core.power import Pow
  13. from sympy.core.symbol import Symbol
  14. from sympy.physics.quantum import TensorProduct
  15. __all__ = ['evaluate_pauli_product']
  16. def delta(i, j):
  17. """
  18. Returns 1 if ``i == j``, else 0.
  19. This is used in the multiplication of Pauli matrices.
  20. Examples
  21. ========
  22. >>> from sympy.physics.paulialgebra import delta
  23. >>> delta(1, 1)
  24. 1
  25. >>> delta(2, 3)
  26. 0
  27. """
  28. if i == j:
  29. return 1
  30. else:
  31. return 0
  32. def epsilon(i, j, k):
  33. """
  34. Return 1 if i,j,k is equal to (1,2,3), (2,3,1), or (3,1,2);
  35. -1 if ``i``,``j``,``k`` is equal to (1,3,2), (3,2,1), or (2,1,3);
  36. else return 0.
  37. This is used in the multiplication of Pauli matrices.
  38. Examples
  39. ========
  40. >>> from sympy.physics.paulialgebra import epsilon
  41. >>> epsilon(1, 2, 3)
  42. 1
  43. >>> epsilon(1, 3, 2)
  44. -1
  45. """
  46. if (i, j, k) in ((1, 2, 3), (2, 3, 1), (3, 1, 2)):
  47. return 1
  48. elif (i, j, k) in ((1, 3, 2), (3, 2, 1), (2, 1, 3)):
  49. return -1
  50. else:
  51. return 0
  52. class Pauli(Symbol):
  53. """
  54. The class representing algebraic properties of Pauli matrices.
  55. Explanation
  56. ===========
  57. The symbol used to display the Pauli matrices can be changed with an
  58. optional parameter ``label="sigma"``. Pauli matrices with different
  59. ``label`` attributes cannot multiply together.
  60. If the left multiplication of symbol or number with Pauli matrix is needed,
  61. please use parentheses to separate Pauli and symbolic multiplication
  62. (for example: 2*I*(Pauli(3)*Pauli(2))).
  63. Another variant is to use evaluate_pauli_product function to evaluate
  64. the product of Pauli matrices and other symbols (with commutative
  65. multiply rules).
  66. See Also
  67. ========
  68. evaluate_pauli_product
  69. Examples
  70. ========
  71. >>> from sympy.physics.paulialgebra import Pauli
  72. >>> Pauli(1)
  73. sigma1
  74. >>> Pauli(1)*Pauli(2)
  75. I*sigma3
  76. >>> Pauli(1)*Pauli(1)
  77. 1
  78. >>> Pauli(3)**4
  79. 1
  80. >>> Pauli(1)*Pauli(2)*Pauli(3)
  81. I
  82. >>> from sympy.physics.paulialgebra import Pauli
  83. >>> Pauli(1, label="tau")
  84. tau1
  85. >>> Pauli(1)*Pauli(2, label="tau")
  86. sigma1*tau2
  87. >>> Pauli(1, label="tau")*Pauli(2, label="tau")
  88. I*tau3
  89. >>> from sympy import I
  90. >>> I*(Pauli(2)*Pauli(3))
  91. -sigma1
  92. >>> from sympy.physics.paulialgebra import evaluate_pauli_product
  93. >>> f = I*Pauli(2)*Pauli(3)
  94. >>> f
  95. I*sigma2*sigma3
  96. >>> evaluate_pauli_product(f)
  97. -sigma1
  98. """
  99. __slots__ = ("i", "label")
  100. def __new__(cls, i, label="sigma"):
  101. if i not in [1, 2, 3]:
  102. raise IndexError("Invalid Pauli index")
  103. obj = Symbol.__new__(cls, "%s%d" %(label,i), commutative=False, hermitian=True)
  104. obj.i = i
  105. obj.label = label
  106. return obj
  107. def __getnewargs_ex__(self):
  108. return (self.i, self.label), {}
  109. def _hashable_content(self):
  110. return (self.i, self.label)
  111. # FIXME don't work for -I*Pauli(2)*Pauli(3)
  112. def __mul__(self, other):
  113. if isinstance(other, Pauli):
  114. j = self.i
  115. k = other.i
  116. jlab = self.label
  117. klab = other.label
  118. if jlab == klab:
  119. return delta(j, k) \
  120. + I*epsilon(j, k, 1)*Pauli(1,jlab) \
  121. + I*epsilon(j, k, 2)*Pauli(2,jlab) \
  122. + I*epsilon(j, k, 3)*Pauli(3,jlab)
  123. return super().__mul__(other)
  124. def _eval_power(b, e):
  125. if e.is_Integer and e.is_positive:
  126. return super().__pow__(int(e) % 2)
  127. def evaluate_pauli_product(arg):
  128. '''Help function to evaluate Pauli matrices product
  129. with symbolic objects.
  130. Parameters
  131. ==========
  132. arg: symbolic expression that contains Paulimatrices
  133. Examples
  134. ========
  135. >>> from sympy.physics.paulialgebra import Pauli, evaluate_pauli_product
  136. >>> from sympy import I
  137. >>> evaluate_pauli_product(I*Pauli(1)*Pauli(2))
  138. -sigma3
  139. >>> from sympy.abc import x
  140. >>> evaluate_pauli_product(x**2*Pauli(2)*Pauli(1))
  141. -I*x**2*sigma3
  142. '''
  143. start = arg
  144. end = arg
  145. if isinstance(arg, Pow) and isinstance(arg.args[0], Pauli):
  146. if arg.args[1].is_odd:
  147. return arg.args[0]
  148. else:
  149. return 1
  150. if isinstance(arg, Add):
  151. return Add(*[evaluate_pauli_product(part) for part in arg.args])
  152. if isinstance(arg, TensorProduct):
  153. return TensorProduct(*[evaluate_pauli_product(part) for part in arg.args])
  154. elif not(isinstance(arg, Mul)):
  155. return arg
  156. while not start == end or start == arg and end == arg:
  157. start = end
  158. tmp = start.as_coeff_mul()
  159. sigma_product = 1
  160. com_product = 1
  161. keeper = 1
  162. for el in tmp[1]:
  163. if isinstance(el, Pauli):
  164. sigma_product *= el
  165. elif not el.is_commutative:
  166. if isinstance(el, Pow) and isinstance(el.args[0], Pauli):
  167. if el.args[1].is_odd:
  168. sigma_product *= el.args[0]
  169. elif isinstance(el, TensorProduct):
  170. keeper = keeper*sigma_product*\
  171. TensorProduct(
  172. *[evaluate_pauli_product(part) for part in el.args]
  173. )
  174. sigma_product = 1
  175. else:
  176. keeper = keeper*sigma_product*el
  177. sigma_product = 1
  178. else:
  179. com_product *= el
  180. end = tmp[0]*keeper*sigma_product*com_product
  181. if end == arg: break
  182. return end