123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- """
- This module implements Pauli algebra by subclassing Symbol. Only algebraic
- properties of Pauli matrices are used (we do not use the Matrix class).
- See the documentation to the class Pauli for examples.
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Pauli_matrices
- """
- from sympy.core.add import Add
- from sympy.core.mul import Mul
- from sympy.core.numbers import I
- from sympy.core.power import Pow
- from sympy.core.symbol import Symbol
- from sympy.physics.quantum import TensorProduct
- __all__ = ['evaluate_pauli_product']
- def delta(i, j):
- """
- Returns 1 if ``i == j``, else 0.
- This is used in the multiplication of Pauli matrices.
- Examples
- ========
- >>> from sympy.physics.paulialgebra import delta
- >>> delta(1, 1)
- 1
- >>> delta(2, 3)
- 0
- """
- if i == j:
- return 1
- else:
- return 0
- def epsilon(i, j, k):
- """
- Return 1 if i,j,k is equal to (1,2,3), (2,3,1), or (3,1,2);
- -1 if ``i``,``j``,``k`` is equal to (1,3,2), (3,2,1), or (2,1,3);
- else return 0.
- This is used in the multiplication of Pauli matrices.
- Examples
- ========
- >>> from sympy.physics.paulialgebra import epsilon
- >>> epsilon(1, 2, 3)
- 1
- >>> epsilon(1, 3, 2)
- -1
- """
- if (i, j, k) in ((1, 2, 3), (2, 3, 1), (3, 1, 2)):
- return 1
- elif (i, j, k) in ((1, 3, 2), (3, 2, 1), (2, 1, 3)):
- return -1
- else:
- return 0
- class Pauli(Symbol):
- """
- The class representing algebraic properties of Pauli matrices.
- Explanation
- ===========
- The symbol used to display the Pauli matrices can be changed with an
- optional parameter ``label="sigma"``. Pauli matrices with different
- ``label`` attributes cannot multiply together.
- If the left multiplication of symbol or number with Pauli matrix is needed,
- please use parentheses to separate Pauli and symbolic multiplication
- (for example: 2*I*(Pauli(3)*Pauli(2))).
- Another variant is to use evaluate_pauli_product function to evaluate
- the product of Pauli matrices and other symbols (with commutative
- multiply rules).
- See Also
- ========
- evaluate_pauli_product
- Examples
- ========
- >>> from sympy.physics.paulialgebra import Pauli
- >>> Pauli(1)
- sigma1
- >>> Pauli(1)*Pauli(2)
- I*sigma3
- >>> Pauli(1)*Pauli(1)
- 1
- >>> Pauli(3)**4
- 1
- >>> Pauli(1)*Pauli(2)*Pauli(3)
- I
- >>> from sympy.physics.paulialgebra import Pauli
- >>> Pauli(1, label="tau")
- tau1
- >>> Pauli(1)*Pauli(2, label="tau")
- sigma1*tau2
- >>> Pauli(1, label="tau")*Pauli(2, label="tau")
- I*tau3
- >>> from sympy import I
- >>> I*(Pauli(2)*Pauli(3))
- -sigma1
- >>> from sympy.physics.paulialgebra import evaluate_pauli_product
- >>> f = I*Pauli(2)*Pauli(3)
- >>> f
- I*sigma2*sigma3
- >>> evaluate_pauli_product(f)
- -sigma1
- """
- __slots__ = ("i", "label")
- def __new__(cls, i, label="sigma"):
- if i not in [1, 2, 3]:
- raise IndexError("Invalid Pauli index")
- obj = Symbol.__new__(cls, "%s%d" %(label,i), commutative=False, hermitian=True)
- obj.i = i
- obj.label = label
- return obj
- def __getnewargs_ex__(self):
- return (self.i, self.label), {}
- def _hashable_content(self):
- return (self.i, self.label)
- # FIXME don't work for -I*Pauli(2)*Pauli(3)
- def __mul__(self, other):
- if isinstance(other, Pauli):
- j = self.i
- k = other.i
- jlab = self.label
- klab = other.label
- if jlab == klab:
- return delta(j, k) \
- + I*epsilon(j, k, 1)*Pauli(1,jlab) \
- + I*epsilon(j, k, 2)*Pauli(2,jlab) \
- + I*epsilon(j, k, 3)*Pauli(3,jlab)
- return super().__mul__(other)
- def _eval_power(b, e):
- if e.is_Integer and e.is_positive:
- return super().__pow__(int(e) % 2)
- def evaluate_pauli_product(arg):
- '''Help function to evaluate Pauli matrices product
- with symbolic objects.
- Parameters
- ==========
- arg: symbolic expression that contains Paulimatrices
- Examples
- ========
- >>> from sympy.physics.paulialgebra import Pauli, evaluate_pauli_product
- >>> from sympy import I
- >>> evaluate_pauli_product(I*Pauli(1)*Pauli(2))
- -sigma3
- >>> from sympy.abc import x
- >>> evaluate_pauli_product(x**2*Pauli(2)*Pauli(1))
- -I*x**2*sigma3
- '''
- start = arg
- end = arg
- if isinstance(arg, Pow) and isinstance(arg.args[0], Pauli):
- if arg.args[1].is_odd:
- return arg.args[0]
- else:
- return 1
- if isinstance(arg, Add):
- return Add(*[evaluate_pauli_product(part) for part in arg.args])
- if isinstance(arg, TensorProduct):
- return TensorProduct(*[evaluate_pauli_product(part) for part in arg.args])
- elif not(isinstance(arg, Mul)):
- return arg
- while not start == end or start == arg and end == arg:
- start = end
- tmp = start.as_coeff_mul()
- sigma_product = 1
- com_product = 1
- keeper = 1
- for el in tmp[1]:
- if isinstance(el, Pauli):
- sigma_product *= el
- elif not el.is_commutative:
- if isinstance(el, Pow) and isinstance(el.args[0], Pauli):
- if el.args[1].is_odd:
- sigma_product *= el.args[0]
- elif isinstance(el, TensorProduct):
- keeper = keeper*sigma_product*\
- TensorProduct(
- *[evaluate_pauli_product(part) for part in el.args]
- )
- sigma_product = 1
- else:
- keeper = keeper*sigma_product*el
- sigma_product = 1
- else:
- com_product *= el
- end = tmp[0]*keeper*sigma_product*com_product
- if end == arg: break
- return end
|