1"""
2Defines functions for constructing the skeleton out of Pauli operators.
3"""
4
5import functools
6
7import numpy as np
8
9from .... import hilbert_spaces
10
11PAULI = np.array([[[ 0, 1 ], # Pauli-X
12 [ 1, 0 ]],
13 [[ 0, 1j], # Pauli-Y
14 [-1j, 0 ]],
15 [[-1, 0 ], # Pauli-Z
16 [ 0, 1 ]]])
17
18LADDER_BASIS = np.array([[[ 0, 1],
19 [ 0, 0]],
20 [[ 0, 0],
21 [ 1, 0]],
22 [[-1, 0],
23 [ 0, 1]]])
24
[docs]
25def second_order_tensor(hilbert_space: hilbert_spaces.QubitSpace,
26 xyz_basis: bool = True):
27 r"""
28 Generates a tensor given by the following expression
29 $$
30 t_{i,j,\alpha,\beta}\coloneqq \left(\sigma^{(i)}_j\right)_{\alpha,\beta}
31 $$
32 where $\sigma^{(i)}_j$ is the $j$th Pauli operator acting on the $i$th
33 qubit, and $\alpha$ and $\beta$ are the rows and columns of the matrix
34 representation of the operator $\sigma^{(i)}_j$ in the computational basis.
35
36 Parameters
37 ----------
38 hilbert_space: QubitSpace
39 The hilbert space of the qubits
40 xyz_basis: bool
41 Uses the Pauli basis if ``True`` and the
42 $\sigma_{\pm}\coloneqq(\sigma_1\pm i\sigma_2)/2$ and Pauli-z basis if
43 ``False``, by default ``True``
44
45 Returns
46 -------
47 NDArray[Shape[``hilbert_space.qubits``, 3, ``hilbert_space.dim``, ``hilbert_space.dim``], int]
48 The second order skeleton tensor
49 """
50 basis = PAULI if xyz_basis else LADDER_BASIS
51 qubits = hilbert_space.qubits
52 t = np.zeros((qubits, 3, len(hilbert_space), len(hilbert_space)),
53 dtype=complex)
54 for i in range(qubits):
55 for j, operator in enumerate(basis):
56 t[i, j] = functools.reduce(np.kron, [np.identity(2**(qubits-1-i)),
57 operator,
58 np.identity(2**i)])
59 return t
60
[docs]
61def fourth_order_tensor(hilbert_space: hilbert_spaces.QubitSpace,
62 xyz_basis: bool = True):
63 r"""
64 Generates a tensor given by the following expression
65 $$
66 u_{i,j,k,l,\alpha,\beta}\coloneqq \left(\sigma^{(i)}_k\sigma^{(j)}_l\right)_{\alpha,\beta}
67 $$
68 where $\sigma^{(i)}_j$ is the $j$th Pauli operator acting on the $i$th
69 qubit, and $\alpha$ and $\beta$ are the rows and columns of the matrix
70 representation of the operator $\sigma^{(i)}_k\sigma^{(j)}_l$ in the
71 computational basis.
72
73 Parameters
74 ----------
75 hilbert_space: QubitSpace
76 The hilbert space of the qubits
77 xyz_basis: bool
78 Uses the Pauli basis if ``True`` and the
79 $\sigma_{\pm}\coloneqq(\sigma_1\pm i\sigma_2)/2$ and Pauli-z basis if
80 ``False``, by default ``True``
81
82 Returns
83 -------
84 NDArray[Shape[``hilbert_space.qubits``, ``hilbert_space.qubits``, 3, 3, ``hilbert_space.dim``, ``hilbert_space.dim``], int]
85 The fourth order skeleton tensor
86 """
87 basis = PAULI if xyz_basis else LADDER_BASIS
88 qubits = hilbert_space.qubits
89 u = np.zeros((qubits,
90 qubits,
91 3,
92 3,
93 hilbert_space.dim,
94 hilbert_space.dim),
95 dtype=complex)
96 for i in range(qubits):
97 for j in range(qubits):
98 if i != j:
99 for k, operator1 in enumerate(basis):
100 for l, operator2 in enumerate(basis):
101 indices = np.array([i, j])
102 operators = np.array([operator1, operator2])
103 order = np.argsort(indices)
104 indices = indices[order]
105 operators = operators[order]
106 u[i, j, k, l] = \
107 functools.reduce(np.kron,
108 [np.identity(2**(qubits-1-indices[1])),
109 operators[1],
110 np.identity(2**(indices[1]-indices[0]-1)),
111 operators[0],
112 np.identity(2**indices[0])])
113 return u