emu-mps 1.2.3__py3-none-any.whl → 1.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- emu_mps/__init__.py +2 -2
- emu_mps/algebra.py +19 -14
- emu_mps/constants.py +4 -0
- emu_mps/hamiltonian.py +3 -3
- emu_mps/mpo.py +26 -23
- emu_mps/mps.py +16 -29
- emu_mps/mps_backend.py +40 -3
- emu_mps/mps_backend_impl.py +61 -23
- emu_mps/mps_config.py +15 -1
- emu_mps/optimatrix/__init__.py +9 -0
- emu_mps/optimatrix/optimiser.py +234 -0
- emu_mps/optimatrix/permutations.py +94 -0
- emu_mps/tdvp.py +15 -32
- emu_mps/utils.py +10 -10
- emu_mps-1.2.5.dist-info/METADATA +101 -0
- emu_mps-1.2.5.dist-info/RECORD +18 -0
- emu_mps-1.2.3.dist-info/METADATA +0 -133
- emu_mps-1.2.3.dist-info/RECORD +0 -14
- {emu_mps-1.2.3.dist-info → emu_mps-1.2.5.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
from scipy.sparse import csr_matrix
|
|
2
|
+
from scipy.sparse.csgraph import reverse_cuthill_mckee
|
|
3
|
+
import numpy as np
|
|
4
|
+
from emu_mps.optimatrix.permutations import permute_matrix, permute_list
|
|
5
|
+
import itertools
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def is_symmetric(mat: np.ndarray) -> bool:
|
|
9
|
+
if mat.shape[0] != mat.shape[1]:
|
|
10
|
+
return False
|
|
11
|
+
if not np.allclose(mat, mat.T, atol=1e-8):
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
return True
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def matrix_bandwidth(mat: np.ndarray) -> float:
|
|
18
|
+
"""matrix_bandwidth(matrix: np.ndarray) -> float
|
|
19
|
+
|
|
20
|
+
Computes bandwidth as max weighted distance between columns of
|
|
21
|
+
a square matrix as `max (abs(matrix[i, j] * (j - i))`.
|
|
22
|
+
|
|
23
|
+
abs(j-i)
|
|
24
|
+
|<--------->|
|
|
25
|
+
(i,i) (i,j)
|
|
26
|
+
| |
|
|
27
|
+
| * . . . . . |
|
|
28
|
+
| . * . . a . |
|
|
29
|
+
| . . * . . . |
|
|
30
|
+
| . . . * . . |
|
|
31
|
+
| . . . . * . |
|
|
32
|
+
| . . . . . * |
|
|
33
|
+
|
|
34
|
+
Distance from the main diagonal `[i,i]` and element `m[i,j]` along row is
|
|
35
|
+
`abs(j-i)` and therefore the weighted distance is `abs(matrix[i, j] * (j - i))`
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
-------
|
|
39
|
+
matrix :
|
|
40
|
+
square matrix nxn
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
bandwidth of the input matrix
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
-------
|
|
48
|
+
>>> matrix = np.array([
|
|
49
|
+
... [ 1, -17, 2.4],
|
|
50
|
+
... [ 9, 1, -10],
|
|
51
|
+
... [-15, 20, 1],])
|
|
52
|
+
>>> matrix_bandwidth(matrix) # 30.0 because abs(-15 * (2-0) == 30)
|
|
53
|
+
30.0
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
bandwidth = max(abs(el * (index[0] - index[1])) for index, el in np.ndenumerate(mat))
|
|
57
|
+
return float(bandwidth)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def minimize_bandwidth_above_threshold(mat: np.ndarray, threshold: float) -> np.ndarray:
|
|
61
|
+
"""
|
|
62
|
+
minimize_bandwidth_above_threshold(matrix, trunc) -> permutation_lists
|
|
63
|
+
|
|
64
|
+
Finds a permutation list that minimizes a bandwidth of a symmetric matrix `A = A.T`
|
|
65
|
+
using the reverse Cuthill-Mckee algorithm from `scipy.sparse.csgraph.reverse_cuthill_mckee`.
|
|
66
|
+
Matrix elements below a threshold `m[i,j] < threshold` are considered as 0.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
-------
|
|
70
|
+
matrix :
|
|
71
|
+
symmetric square matrix
|
|
72
|
+
threshold :
|
|
73
|
+
matrix elements `m[i,j] < threshold` are considered as 0
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
permutation list that minimizes matrix bandwidth for a given threshold
|
|
78
|
+
|
|
79
|
+
Example:
|
|
80
|
+
-------
|
|
81
|
+
>>> matrix = np.array([
|
|
82
|
+
... [1, 2, 3],
|
|
83
|
+
... [2, 5, 6],
|
|
84
|
+
... [3, 6, 9]])
|
|
85
|
+
>>> threshold = 3
|
|
86
|
+
>>> minimize_bandwidth_above_threshold(matrix, threshold)
|
|
87
|
+
array([1, 2, 0], dtype=int32)
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
matrix_truncated = mat.copy()
|
|
91
|
+
matrix_truncated[mat < threshold] = 0
|
|
92
|
+
rcm_permutation = reverse_cuthill_mckee(
|
|
93
|
+
csr_matrix(matrix_truncated), symmetric_mode=True
|
|
94
|
+
)
|
|
95
|
+
return np.array(rcm_permutation)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def minimize_bandwidth_global(mat: np.ndarray) -> list[int]:
|
|
99
|
+
"""
|
|
100
|
+
minimize_bandwidth_global(matrix) -> list
|
|
101
|
+
|
|
102
|
+
Does one optimisation step towards finding
|
|
103
|
+
a permutation of a matrix that minimizes matrix bandwidth.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
-------
|
|
107
|
+
matrix :
|
|
108
|
+
symmetric square matrix
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
permutation order that minimizes matrix bandwidth
|
|
113
|
+
|
|
114
|
+
Example:
|
|
115
|
+
-------
|
|
116
|
+
>>> matrix = np.array([
|
|
117
|
+
... [1, 2, 3],
|
|
118
|
+
... [2, 5, 6],
|
|
119
|
+
... [3, 6, 9]])
|
|
120
|
+
>>> minimize_bandwidth_global(matrix)
|
|
121
|
+
[2, 1, 0]
|
|
122
|
+
"""
|
|
123
|
+
mat_amplitude = np.max(np.abs(mat))
|
|
124
|
+
# Search from 1.0 to 0.1 doesn't change result
|
|
125
|
+
permutations = (
|
|
126
|
+
minimize_bandwidth_above_threshold(mat, trunc * mat_amplitude)
|
|
127
|
+
for trunc in np.arange(start=0.1, stop=1.0, step=0.01)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
opt_permutation = min(
|
|
131
|
+
permutations, key=lambda perm: matrix_bandwidth(permute_matrix(mat, list(perm)))
|
|
132
|
+
)
|
|
133
|
+
return list(opt_permutation) # opt_permutation is np.ndarray
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def minimize_bandwidth_impl(
|
|
137
|
+
matrix: np.ndarray, initial_perm: list[int]
|
|
138
|
+
) -> tuple[list[int], float]:
|
|
139
|
+
"""
|
|
140
|
+
minimize_bandwidth_impl(matrix, initial_perm) -> list
|
|
141
|
+
|
|
142
|
+
Applies initial_perm to a matrix and
|
|
143
|
+
finds the permutation list for a symmetric matrix that iteratively minimizes matrix bandwidth.
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
-------
|
|
147
|
+
matrix :
|
|
148
|
+
symmetric square matrix
|
|
149
|
+
initial_perm: list of integers
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
permutation order that minimizes matrix bandwidth
|
|
155
|
+
|
|
156
|
+
Example:
|
|
157
|
+
-------
|
|
158
|
+
Periodic 1D chain
|
|
159
|
+
>>> matrix = np.array([
|
|
160
|
+
... [0, 1, 0, 0, 1],
|
|
161
|
+
... [1, 0, 1, 0, 0],
|
|
162
|
+
... [0, 1, 0, 1, 0],
|
|
163
|
+
... [0, 0, 1, 0, 1],
|
|
164
|
+
... [1, 0, 0, 1, 0]])
|
|
165
|
+
>>> id_perm = list(range(matrix.shape[0]))
|
|
166
|
+
>>> minimize_bandwidth_impl(matrix, id_perm) # [3, 2, 4, 1, 0] does zig-zag
|
|
167
|
+
([3, 2, 4, 1, 0], 2.0)
|
|
168
|
+
|
|
169
|
+
Simple 1D chain. Cannot be optimised further
|
|
170
|
+
>>> matrix = np.array([
|
|
171
|
+
... [0, 1, 0, 0, 0],
|
|
172
|
+
... [1, 0, 1, 0, 0],
|
|
173
|
+
... [0, 1, 0, 1, 0],
|
|
174
|
+
... [0, 0, 1, 0, 1],
|
|
175
|
+
... [0, 0, 0, 1, 0]])
|
|
176
|
+
>>> id_perm = list(range(matrix.shape[0]))
|
|
177
|
+
>>> minimize_bandwidth_impl(matrix, id_perm)
|
|
178
|
+
([0, 1, 2, 3, 4], 1.0)
|
|
179
|
+
"""
|
|
180
|
+
if initial_perm != list(range(matrix.shape[0])):
|
|
181
|
+
matrix = permute_matrix(matrix, initial_perm)
|
|
182
|
+
bandwidth = matrix_bandwidth(matrix)
|
|
183
|
+
acc_permutation = initial_perm
|
|
184
|
+
|
|
185
|
+
for counter in range(101):
|
|
186
|
+
if counter == 100:
|
|
187
|
+
raise (
|
|
188
|
+
NotImplementedError(
|
|
189
|
+
"The algorithm takes too many steps, " "probably not converging."
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
optimal_perm = minimize_bandwidth_global(matrix)
|
|
194
|
+
test_mat = permute_matrix(matrix, optimal_perm)
|
|
195
|
+
new_bandwidth = matrix_bandwidth(test_mat)
|
|
196
|
+
|
|
197
|
+
if bandwidth <= new_bandwidth:
|
|
198
|
+
break
|
|
199
|
+
|
|
200
|
+
matrix = test_mat
|
|
201
|
+
acc_permutation = permute_list(acc_permutation, optimal_perm)
|
|
202
|
+
bandwidth = new_bandwidth
|
|
203
|
+
|
|
204
|
+
return acc_permutation, bandwidth
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def minimize_bandwidth(input_matrix: np.ndarray, samples: int = 100) -> list[int]:
|
|
208
|
+
assert is_symmetric(input_matrix), "Input matrix is not symmetric"
|
|
209
|
+
input_mat = abs(input_matrix)
|
|
210
|
+
# We are interested in strength of the interaction, not sign
|
|
211
|
+
|
|
212
|
+
L = input_mat.shape[0]
|
|
213
|
+
rnd_permutations = itertools.chain(
|
|
214
|
+
[list(range(L))], # First element is always the identity list
|
|
215
|
+
(np.random.permutation(L).tolist() for _ in range(samples)),
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
opt_permutations_and_opt_bandwidth = (
|
|
219
|
+
minimize_bandwidth_impl(input_mat, rnd_perm) for rnd_perm in rnd_permutations
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
best_perm, best_bandwidth = min(
|
|
223
|
+
opt_permutations_and_opt_bandwidth,
|
|
224
|
+
key=lambda perm_and_bandwidth: perm_and_bandwidth[1],
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
assert best_bandwidth <= matrix_bandwidth(input_matrix), "Matrix is not optimised"
|
|
228
|
+
return best_perm
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
if __name__ == "__main__":
|
|
232
|
+
import doctest
|
|
233
|
+
|
|
234
|
+
doctest.testmod()
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def permute_list(input_list: list, permutation: list[int]) -> list:
|
|
5
|
+
"""
|
|
6
|
+
Permutes the input list according to the given permutation.
|
|
7
|
+
|
|
8
|
+
Parameters
|
|
9
|
+
-------
|
|
10
|
+
input_list :
|
|
11
|
+
A list to permute.
|
|
12
|
+
permutation :
|
|
13
|
+
A list of indices representing the new order.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
The permuted list.
|
|
18
|
+
|
|
19
|
+
Example
|
|
20
|
+
-------
|
|
21
|
+
>>> permute_list(['a', 'b', 'c'], [2, 0, 1])
|
|
22
|
+
['c', 'a', 'b']
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
permuted_list = [None] * len(input_list)
|
|
26
|
+
for i, p in enumerate(permutation):
|
|
27
|
+
permuted_list[i] = input_list[p]
|
|
28
|
+
return permuted_list
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def invert_permutation(permutation: list[int]) -> list[int]:
|
|
32
|
+
"""
|
|
33
|
+
invert_permutation(permutation) -> inv_permutation
|
|
34
|
+
|
|
35
|
+
Inverts the input permutation list.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
-------
|
|
39
|
+
permutation :
|
|
40
|
+
A list of indices representing the order
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
permutation list inverse to the input list
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
-------
|
|
48
|
+
>>> invert_permutation([2, 0, 1])
|
|
49
|
+
[1, 2, 0]
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
inv_perm = np.empty_like(permutation)
|
|
53
|
+
inv_perm[permutation] = np.arange(len(permutation))
|
|
54
|
+
return list(inv_perm)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def permute_matrix(mat: np.ndarray, permutation: list[int]) -> np.ndarray:
|
|
58
|
+
"""
|
|
59
|
+
permute_matrix(matrix, permutation_list) -> permuted_matrix
|
|
60
|
+
|
|
61
|
+
Simultaneously permutes columns and rows according to a permutation list.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
-------
|
|
65
|
+
matrix :
|
|
66
|
+
square matrix nxn
|
|
67
|
+
permutation :
|
|
68
|
+
permutation list
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
matrix with permuted columns and rows
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
-------
|
|
76
|
+
>>> matrix = np.array([
|
|
77
|
+
... [1, 2, 3],
|
|
78
|
+
... [4, 5, 6],
|
|
79
|
+
... [7, 8, 9]])
|
|
80
|
+
>>> permutation = [1, 0, 2]
|
|
81
|
+
>>> permute_matrix(matrix, permutation)
|
|
82
|
+
array([[5, 4, 6],
|
|
83
|
+
[2, 1, 3],
|
|
84
|
+
[8, 7, 9]])
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
perm = np.array(permutation)
|
|
88
|
+
return mat[perm, :][:, perm]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
import doctest
|
|
93
|
+
|
|
94
|
+
doctest.testmod()
|
emu_mps/tdvp.py
CHANGED
|
@@ -3,6 +3,7 @@ import torch
|
|
|
3
3
|
from emu_base import krylov_exp
|
|
4
4
|
from emu_mps import MPS, MPO
|
|
5
5
|
from emu_mps.utils import split_tensor
|
|
6
|
+
from emu_mps.mps_config import MPSConfig
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
def new_right_bath(
|
|
@@ -10,7 +11,8 @@ def new_right_bath(
|
|
|
10
11
|
) -> torch.Tensor:
|
|
11
12
|
bath = torch.tensordot(state, bath, ([2], [2]))
|
|
12
13
|
bath = torch.tensordot(op.to(bath.device), bath, ([2, 3], [1, 3]))
|
|
13
|
-
|
|
14
|
+
bath = torch.tensordot(state.conj(), bath, ([1, 2], [1, 3]))
|
|
15
|
+
return bath
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
"""
|
|
@@ -79,27 +81,6 @@ def apply_effective_Hamiltonian(
|
|
|
79
81
|
_TIME_CONVERSION_COEFF = 0.001 # Omega and delta are given in rad/ms, dt in ns
|
|
80
82
|
|
|
81
83
|
|
|
82
|
-
class EvolveConfig:
|
|
83
|
-
def __init__(
|
|
84
|
-
self,
|
|
85
|
-
*,
|
|
86
|
-
exp_tolerance: float,
|
|
87
|
-
norm_tolerance: float,
|
|
88
|
-
max_krylov_dim: int,
|
|
89
|
-
is_hermitian: bool,
|
|
90
|
-
max_error: float,
|
|
91
|
-
max_rank: int
|
|
92
|
-
) -> None:
|
|
93
|
-
self.exp_tolerance = exp_tolerance
|
|
94
|
-
self.norm_tolerance = norm_tolerance
|
|
95
|
-
self.max_krylov_dim = max_krylov_dim
|
|
96
|
-
self.is_hermitian = is_hermitian
|
|
97
|
-
self.max_error = (
|
|
98
|
-
max_error # FIXME: max_error and max_rank are irrelevant for evolve_single
|
|
99
|
-
)
|
|
100
|
-
self.max_rank = max_rank
|
|
101
|
-
|
|
102
|
-
|
|
103
84
|
def evolve_pair(
|
|
104
85
|
*,
|
|
105
86
|
state_factors: list[torch.Tensor],
|
|
@@ -107,7 +88,8 @@ def evolve_pair(
|
|
|
107
88
|
ham_factors: list[torch.Tensor],
|
|
108
89
|
dt: float,
|
|
109
90
|
orth_center_right: bool,
|
|
110
|
-
|
|
91
|
+
is_hermitian: bool,
|
|
92
|
+
config: MPSConfig,
|
|
111
93
|
) -> tuple[torch.Tensor, torch.Tensor]:
|
|
112
94
|
"""
|
|
113
95
|
Time evolution of a pair of tensors of a tensor train using baths and truncated SVD.
|
|
@@ -154,16 +136,16 @@ def evolve_pair(
|
|
|
154
136
|
evol = krylov_exp(
|
|
155
137
|
op,
|
|
156
138
|
combined_state_factors,
|
|
157
|
-
exp_tolerance=config.
|
|
158
|
-
norm_tolerance=config.
|
|
139
|
+
exp_tolerance=config.precision * config.extra_krylov_tolerance,
|
|
140
|
+
norm_tolerance=config.precision * config.extra_krylov_tolerance,
|
|
159
141
|
max_krylov_dim=config.max_krylov_dim,
|
|
160
|
-
is_hermitian=
|
|
142
|
+
is_hermitian=is_hermitian,
|
|
161
143
|
).reshape(left_bond_dim * 2, 2 * right_bond_dim)
|
|
162
144
|
|
|
163
145
|
l, r = split_tensor(
|
|
164
146
|
evol,
|
|
165
|
-
max_error=config.
|
|
166
|
-
max_rank=config.
|
|
147
|
+
max_error=config.precision,
|
|
148
|
+
max_rank=config.max_bond_dim,
|
|
167
149
|
orth_center_right=orth_center_right,
|
|
168
150
|
)
|
|
169
151
|
|
|
@@ -178,7 +160,8 @@ def evolve_single(
|
|
|
178
160
|
baths: tuple[torch.Tensor, torch.Tensor],
|
|
179
161
|
ham_factor: torch.Tensor,
|
|
180
162
|
dt: float,
|
|
181
|
-
|
|
163
|
+
is_hermitian: bool,
|
|
164
|
+
config: MPSConfig,
|
|
182
165
|
) -> torch.Tensor:
|
|
183
166
|
"""
|
|
184
167
|
Time evolution of a single tensor of a tensor train using baths.
|
|
@@ -202,8 +185,8 @@ def evolve_single(
|
|
|
202
185
|
return krylov_exp(
|
|
203
186
|
op,
|
|
204
187
|
state_factor,
|
|
205
|
-
exp_tolerance=config.
|
|
206
|
-
norm_tolerance=config.
|
|
188
|
+
exp_tolerance=config.precision * config.extra_krylov_tolerance,
|
|
189
|
+
norm_tolerance=config.precision * config.extra_krylov_tolerance,
|
|
207
190
|
max_krylov_dim=config.max_krylov_dim,
|
|
208
|
-
is_hermitian=
|
|
191
|
+
is_hermitian=is_hermitian,
|
|
209
192
|
)
|
emu_mps/utils.py
CHANGED
|
@@ -3,7 +3,7 @@ import torch
|
|
|
3
3
|
import random
|
|
4
4
|
from collections import Counter
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
from emu_mps import MPSConfig
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def new_left_bath(
|
|
@@ -12,15 +12,16 @@ def new_left_bath(
|
|
|
12
12
|
# this order is more efficient than contracting the op first in general
|
|
13
13
|
bath = torch.tensordot(bath, state.conj(), ([0], [0]))
|
|
14
14
|
bath = torch.tensordot(bath, op.to(bath.device), ([0, 2], [0, 1]))
|
|
15
|
-
|
|
15
|
+
bath = torch.tensordot(bath, state, ([0, 2], [0, 1]))
|
|
16
|
+
return bath
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def _determine_cutoff_index(d: torch.Tensor, max_error: float) -> int:
|
|
19
20
|
assert max_error > 0
|
|
20
21
|
squared_max_error = max_error * max_error
|
|
21
|
-
acc = 0
|
|
22
|
+
acc = 0.0
|
|
22
23
|
for i in range(d.shape[0]):
|
|
23
|
-
acc += d[i]
|
|
24
|
+
acc += d[i].item()
|
|
24
25
|
if acc > squared_max_error:
|
|
25
26
|
return i
|
|
26
27
|
return 0 # type: ignore[no-any-return]
|
|
@@ -60,9 +61,8 @@ def split_tensor(
|
|
|
60
61
|
|
|
61
62
|
|
|
62
63
|
def truncate_impl(
|
|
63
|
-
factors: list[torch.
|
|
64
|
-
|
|
65
|
-
max_rank: int = 1024,
|
|
64
|
+
factors: list[torch.Tensor],
|
|
65
|
+
config: MPSConfig,
|
|
66
66
|
) -> None:
|
|
67
67
|
"""
|
|
68
68
|
Eigenvalues-based truncation of a matrix product.
|
|
@@ -78,8 +78,8 @@ def truncate_impl(
|
|
|
78
78
|
|
|
79
79
|
l, r = split_tensor(
|
|
80
80
|
factors[i].reshape(factor_shape[0], -1),
|
|
81
|
-
max_error=
|
|
82
|
-
max_rank=
|
|
81
|
+
max_error=config.precision,
|
|
82
|
+
max_rank=config.max_bond_dim,
|
|
83
83
|
orth_center_right=False,
|
|
84
84
|
)
|
|
85
85
|
|
|
@@ -241,7 +241,7 @@ def apply_measurement_errors(
|
|
|
241
241
|
return result
|
|
242
242
|
|
|
243
243
|
|
|
244
|
-
n_operator = torch.tensor(
|
|
244
|
+
n_operator: torch.Tensor = torch.tensor(
|
|
245
245
|
[
|
|
246
246
|
[0, 0],
|
|
247
247
|
[0, 1],
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: emu-mps
|
|
3
|
+
Version: 1.2.5
|
|
4
|
+
Summary: Pasqal MPS based pulse emulator built on PyTorch
|
|
5
|
+
Author-email: Anton Quelle <anton.quelle@pasqal.com>, Mauro Mendizabal <mauro.mendizabal-pico@pasqal.com>, Stefano Grava <stefano.grava@pasqal.com>, Pablo Le Henaff <pablo.le-henaff@pasqal.com>
|
|
6
|
+
License: PASQAL OPEN-SOURCE SOFTWARE LICENSE AGREEMENT (MIT-derived)
|
|
7
|
+
|
|
8
|
+
The author of the License is:
|
|
9
|
+
Pasqal, a Société par Actions Simplifiée (Simplified Joint Stock Company) registered under number 849 441 522 at the Registre du commerce et des sociétés (Trade and Companies Register) of Evry – France, headquartered at 7 rue Leonard de Vinci – 91300 – Massy – France, duly represented by its Président, M. Georges-Olivier REYMOND,
|
|
10
|
+
|
|
11
|
+
Hereafter referred to as « the Licensor »
|
|
12
|
+
|
|
13
|
+
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software (the “Licensee”) and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The Software is “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non-infringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise arising from, out of or in connection with the Software or the use or other dealings in the Software.
|
|
15
|
+
|
|
16
|
+
- If use of the Software leads to the necessary use of any patent of the Licensor and/or any of its Affiliates (defined as a company owned or controlled by the Licensor), the Licensee is granted a royalty-free license, in any country where such patent is in force, to use the object of such patent; or use the process covered by such patent,
|
|
17
|
+
|
|
18
|
+
- Such a patent license is granted for internal research or academic use of the Licensee's, which includes use by employees and students of the Licensee, acting on behalf of the Licensee, for research purposes only.
|
|
19
|
+
|
|
20
|
+
- The License is governed by the laws of France. Any dispute relating to the License, notably its execution, performance and/or termination shall be brought to, heard and tried by the Tribunal Judiciaire de Paris, regardless of the rules of jurisdiction in the matter.
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: emu-base==1.2.5
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
<div align="center">
|
|
29
|
+
<img src="docs/logos/LogoTaglineSoftGreen.svg">
|
|
30
|
+
|
|
31
|
+
# Emu-MPS
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
**Emu-mps** is a backend for the [Pulser low-level Quantum Programming toolkit](https://pulser.readthedocs.io) that lets you run Quantum Algorithms on a simulated device, using GPU acceleration if available. More in depth, emu-mps is designed to **emu**late the dynamics of programmable arrays of neutral atoms, with matrix product states (**mps**). While benchmarking is incomplete as of this writing, early results suggest that this design makes emu-mps faster and more memory-efficient than previous generations of quantum emulators at running simulations with large numbers of qubits.
|
|
35
|
+
|
|
36
|
+
As of this writing, Emu-MPS is provided for Linux and macOS but will not work under Windows.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
**Warning:** installing emu-mps will update pulser-core
|
|
41
|
+
|
|
42
|
+
### Using `hatch`, `uv` or any pyproject-compatible Python manager
|
|
43
|
+
|
|
44
|
+
To add `emu-mps` to your project, edit your `pyproject.toml` to add the line
|
|
45
|
+
|
|
46
|
+
```toml
|
|
47
|
+
"emu-mps"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
to the list of `dependencies`.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
### Using `pip` or `pipx`
|
|
54
|
+
To install the `pipy` package using `pip` or `pipx`
|
|
55
|
+
|
|
56
|
+
1. Create a `venv` if that's not done yet
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
$ python -m venv venv
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
2. Enter the venv
|
|
64
|
+
|
|
65
|
+
If you're running Unix:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
$ . venv/bin/activate
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If you're running Windows:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
C:\> /path/to/new/virtual/environment/Scripts/activate
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
3. Install the package
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
$ pip install emu-mps
|
|
81
|
+
# or
|
|
82
|
+
$ pipx install emu-mps
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
Join us on [Slack](https://pasqalworkspace.slack.com/archives/C07MUV5K7EU) or by [e-mail](mailto:emulation@pasqal.com) to give us feedback about how you plan to use Emu-MPS or if you require specific feature-upgrades.
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
For the time being, the easiest way to learn how to use this package is to look
|
|
91
|
+
at the [examples](examples/emu_mps_examples) and [notebooks](https://pasqal-io.github.io/emulators/latest/).
|
|
92
|
+
|
|
93
|
+
See also the [full documentation](https://github.com/pasqal-io/emulators/blob/main/docs/index.md) for
|
|
94
|
+
the API, information about contributing, benchmarks, etc.
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
## Getting in touch
|
|
98
|
+
|
|
99
|
+
- [Pasqal Community Portal](https://community.pasqal.com/) (forums, chat, tutorials, examples, code library).
|
|
100
|
+
- [GitHub Repository](https://github.com/pasqal-io/quantum-evolution-kernel) (source code, issue tracker).
|
|
101
|
+
- [Professional Support](https://www.pasqal.com/contact-us/) (if you need tech support, custom licenses, a variant of this library optimized for your workload, your own QPU, remote access to a QPU, ...)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
emu_mps/__init__.py,sha256=EdVngqaa6GtyXmEP2aK3BfTHjYLBJSN3wR0CvltS9NQ,646
|
|
2
|
+
emu_mps/algebra.py,sha256=ngPtTH-j2ZCBWoaJZXlkUyIlug7dY7Q92gzfnRlpPMA,5485
|
|
3
|
+
emu_mps/constants.py,sha256=41LYkKLUCz-oxPbd-j7nUDZuhIbUrnez6prT0uR0jcE,56
|
|
4
|
+
emu_mps/hamiltonian.py,sha256=LcBs6CKBb643a1e9AAVtQoUfa4L_0dIhLOKecx5OOWs,15864
|
|
5
|
+
emu_mps/mpo.py,sha256=7y6q0UIfyX9igQknqtgt6nymuVcgjHlH3-Qv7N7uOZE,8769
|
|
6
|
+
emu_mps/mps.py,sha256=OjG_caqPOioCdOt-bFUkOf2xuNGnKzj0LaMc3EJCHi4,17855
|
|
7
|
+
emu_mps/mps_backend.py,sha256=6fVaq-D4xyicYRjGjhqMEieC7---90LpfpbV7ZD7zkQ,2192
|
|
8
|
+
emu_mps/mps_backend_impl.py,sha256=HKDqUakqSs1THeeEZP5MFZaUyALnaIhrlsZTQ0Qp4qU,20867
|
|
9
|
+
emu_mps/mps_config.py,sha256=MxahrPDaOpfdB6SLG1610iDUOuLR04IaCjKQRk99ICY,3346
|
|
10
|
+
emu_mps/noise.py,sha256=h4X2EFjoC_Ok0gZ8I9wN77RANXaVehTBbjkcbY_GAmY,784
|
|
11
|
+
emu_mps/tdvp.py,sha256=TH4CcBNczRURXYGPXndWKDs0jWXz_x9ozM961uGiSOw,5711
|
|
12
|
+
emu_mps/utils.py,sha256=n9BcpuIz4Kl6EYlATaK8TKsyF-T7FTwbBo6KSAQYzl8,8066
|
|
13
|
+
emu_mps/optimatrix/__init__.py,sha256=lHWYNeThHp57ZrwTwXd0p8bNvcCv0w_AZ31iCWflBUo,226
|
|
14
|
+
emu_mps/optimatrix/optimiser.py,sha256=cVMdm2r_4OpbthcQuFMrJ9rNR9WEJRga9c_lHrJFkhw,6687
|
|
15
|
+
emu_mps/optimatrix/permutations.py,sha256=JRXGont8B4QgbkV9CzrA0w7uzLgBrmZ1J9aa0G52hPo,1979
|
|
16
|
+
emu_mps-1.2.5.dist-info/METADATA,sha256=bOtqQKZZ6ZkK9C6aV4puIipHUm5v1G9-tQrUftkIw0M,5559
|
|
17
|
+
emu_mps-1.2.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
+
emu_mps-1.2.5.dist-info/RECORD,,
|