emu-mps 2.0.1__py3-none-any.whl → 2.0.2__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 +1 -1
- emu_mps/hamiltonian.py +333 -347
- emu_mps/mpo.py +1 -1
- emu_mps/mps.py +14 -5
- emu_mps/mps_backend_impl.py +8 -5
- emu_mps/optimatrix/__init__.py +4 -4
- emu_mps/optimatrix/optimiser.py +76 -66
- emu_mps/optimatrix/permutations.py +57 -49
- emu_mps/tdvp.py +1 -1
- {emu_mps-2.0.1.dist-info → emu_mps-2.0.2.dist-info}/METADATA +2 -2
- emu_mps-2.0.2.dist-info/RECORD +19 -0
- emu_mps-2.0.1.dist-info/RECORD +0 -19
- {emu_mps-2.0.1.dist-info → emu_mps-2.0.2.dist-info}/WHEEL +0 -0
emu_mps/mpo.py
CHANGED
|
@@ -83,7 +83,7 @@ class MPO(Operator[complex, torch.Tensor, MPS]):
|
|
|
83
83
|
other.factors,
|
|
84
84
|
config=other.config,
|
|
85
85
|
)
|
|
86
|
-
return MPS(factors, orthogonality_center=0)
|
|
86
|
+
return MPS(factors, orthogonality_center=0, eigenstates=other.eigenstates)
|
|
87
87
|
|
|
88
88
|
def __add__(self, other: MPO) -> MPO:
|
|
89
89
|
"""
|
emu_mps/mps.py
CHANGED
|
@@ -38,6 +38,7 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
38
38
|
orthogonality_center: Optional[int] = None,
|
|
39
39
|
config: Optional[MPSConfig] = None,
|
|
40
40
|
num_gpus_to_use: Optional[int] = DEVICE_COUNT,
|
|
41
|
+
eigenstates: Sequence[Eigenstate] = ("r", "g"),
|
|
41
42
|
):
|
|
42
43
|
"""
|
|
43
44
|
This constructor creates a MPS directly from a list of tensors. It is for internal use only.
|
|
@@ -56,7 +57,7 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
56
57
|
num_gpus_to_use: distribute the factors over this many GPUs
|
|
57
58
|
0=all factors to cpu, None=keep the existing device assignment.
|
|
58
59
|
"""
|
|
59
|
-
|
|
60
|
+
super().__init__(eigenstates=eigenstates)
|
|
60
61
|
self.config = config if config is not None else MPSConfig()
|
|
61
62
|
assert all(
|
|
62
63
|
factors[i - 1].shape[2] == factors[i].shape[0] for i in range(1, len(factors))
|
|
@@ -88,6 +89,7 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
88
89
|
num_sites: int,
|
|
89
90
|
config: Optional[MPSConfig] = None,
|
|
90
91
|
num_gpus_to_use: int = DEVICE_COUNT,
|
|
92
|
+
eigenstates: Sequence[Eigenstate] = ["0", "1"],
|
|
91
93
|
) -> MPS:
|
|
92
94
|
"""
|
|
93
95
|
Returns a MPS in ground state |000..0>.
|
|
@@ -111,6 +113,7 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
111
113
|
config=config,
|
|
112
114
|
num_gpus_to_use=num_gpus_to_use,
|
|
113
115
|
orthogonality_center=0, # Arbitrary: every qubit is an orthogonality center.
|
|
116
|
+
eigenstates=eigenstates,
|
|
114
117
|
)
|
|
115
118
|
|
|
116
119
|
def __repr__(self) -> str:
|
|
@@ -350,12 +353,16 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
350
353
|
the summed state
|
|
351
354
|
"""
|
|
352
355
|
assert isinstance(other, MPS), "Other state also needs to be an MPS"
|
|
356
|
+
assert (
|
|
357
|
+
self.eigenstates == other.eigenstates
|
|
358
|
+
), f"`Other` state has basis {other.eigenstates} != {self.eigenstates}"
|
|
353
359
|
new_tt = add_factors(self.factors, other.factors)
|
|
354
360
|
result = MPS(
|
|
355
361
|
new_tt,
|
|
356
362
|
config=self.config,
|
|
357
363
|
num_gpus_to_use=None,
|
|
358
364
|
orthogonality_center=None, # Orthogonality is lost.
|
|
365
|
+
eigenstates=self.eigenstates,
|
|
359
366
|
)
|
|
360
367
|
result.truncate()
|
|
361
368
|
return result
|
|
@@ -381,6 +388,7 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
381
388
|
config=self.config,
|
|
382
389
|
num_gpus_to_use=None,
|
|
383
390
|
orthogonality_center=self.orthogonality_center,
|
|
391
|
+
eigenstates=self.eigenstates,
|
|
384
392
|
)
|
|
385
393
|
|
|
386
394
|
def __imul__(self, scalar: complex) -> MPS:
|
|
@@ -390,7 +398,7 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
390
398
|
def _from_state_amplitudes(
|
|
391
399
|
cls,
|
|
392
400
|
*,
|
|
393
|
-
eigenstates: Sequence[
|
|
401
|
+
eigenstates: Sequence[Eigenstate],
|
|
394
402
|
amplitudes: Mapping[str, complex],
|
|
395
403
|
) -> tuple[MPS, Mapping[str, complex]]:
|
|
396
404
|
"""
|
|
@@ -404,8 +412,6 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
404
412
|
Returns:
|
|
405
413
|
The resulting MPS representation of the state.s
|
|
406
414
|
"""
|
|
407
|
-
|
|
408
|
-
nqubits = len(next(iter(amplitudes.keys())))
|
|
409
415
|
basis = set(eigenstates)
|
|
410
416
|
if basis == {"r", "g"}:
|
|
411
417
|
one = "r"
|
|
@@ -414,17 +420,20 @@ class MPS(State[complex, torch.Tensor]):
|
|
|
414
420
|
else:
|
|
415
421
|
raise ValueError("Unsupported basis provided")
|
|
416
422
|
|
|
423
|
+
nqubits = cls._validate_amplitudes(amplitudes, eigenstates)
|
|
424
|
+
|
|
417
425
|
basis_0 = torch.tensor([[[1.0], [0.0]]], dtype=torch.complex128) # ground state
|
|
418
426
|
basis_1 = torch.tensor([[[0.0], [1.0]]], dtype=torch.complex128) # excited state
|
|
419
427
|
|
|
420
428
|
accum_mps = MPS(
|
|
421
429
|
[torch.zeros((1, 2, 1), dtype=torch.complex128)] * nqubits,
|
|
422
430
|
orthogonality_center=0,
|
|
431
|
+
eigenstates=eigenstates,
|
|
423
432
|
)
|
|
424
433
|
|
|
425
434
|
for state, amplitude in amplitudes.items():
|
|
426
435
|
factors = [basis_1 if ch == one else basis_0 for ch in state]
|
|
427
|
-
accum_mps += amplitude * MPS(factors)
|
|
436
|
+
accum_mps += amplitude * MPS(factors, eigenstates=eigenstates)
|
|
428
437
|
norm = accum_mps.norm()
|
|
429
438
|
if not math.isclose(1.0, norm, rel_tol=1e-5, abs_tol=0.0):
|
|
430
439
|
print("\nThe state is not normalized, normalizing it for you.")
|
emu_mps/mps_backend_impl.py
CHANGED
|
@@ -208,6 +208,7 @@ class MPSBackendImpl:
|
|
|
208
208
|
[f.clone().detach() for f in initial_state.factors],
|
|
209
209
|
config=self.config,
|
|
210
210
|
num_gpus_to_use=self.config.num_gpus_to_use,
|
|
211
|
+
eigenstates=initial_state.eigenstates,
|
|
211
212
|
)
|
|
212
213
|
initial_state.truncate()
|
|
213
214
|
initial_state *= 1 / initial_state.norm()
|
|
@@ -496,13 +497,15 @@ class MPSBackendImpl:
|
|
|
496
497
|
)
|
|
497
498
|
full_state = MPS(
|
|
498
499
|
extended_mps_factors(
|
|
499
|
-
normalized_state.factors,
|
|
500
|
+
normalized_state.factors,
|
|
501
|
+
self.well_prepared_qubits_filter,
|
|
500
502
|
),
|
|
501
503
|
num_gpus_to_use=None, # Keep the already assigned devices.
|
|
502
504
|
orthogonality_center=get_extended_site_index(
|
|
503
505
|
self.well_prepared_qubits_filter,
|
|
504
506
|
normalized_state.orthogonality_center,
|
|
505
507
|
),
|
|
508
|
+
eigenstates=normalized_state.eigenstates,
|
|
506
509
|
)
|
|
507
510
|
|
|
508
511
|
callback(self.config, fractional_time, full_state, full_mpo, self.results)
|
|
@@ -535,7 +538,7 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
|
|
|
535
538
|
|
|
536
539
|
def set_jump_threshold(self, bound: float) -> None:
|
|
537
540
|
self.jump_threshold = random.uniform(0.0, bound)
|
|
538
|
-
self.norm_gap_before_jump = self.state.norm() ** 2 - self.jump_threshold
|
|
541
|
+
self.norm_gap_before_jump = self.state.norm().item() ** 2 - self.jump_threshold
|
|
539
542
|
|
|
540
543
|
def init(self) -> None:
|
|
541
544
|
self.init_lindblad_noise()
|
|
@@ -546,7 +549,7 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
|
|
|
546
549
|
previous_time = self.current_time
|
|
547
550
|
self.current_time = self.target_time
|
|
548
551
|
previous_norm_gap_before_jump = self.norm_gap_before_jump
|
|
549
|
-
self.norm_gap_before_jump = self.state.norm() ** 2 - self.jump_threshold
|
|
552
|
+
self.norm_gap_before_jump = self.state.norm().item() ** 2 - self.jump_threshold
|
|
550
553
|
|
|
551
554
|
if self.root_finder is None:
|
|
552
555
|
# No quantum jump location finding in progress
|
|
@@ -566,7 +569,7 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
|
|
|
566
569
|
|
|
567
570
|
return
|
|
568
571
|
|
|
569
|
-
self.norm_gap_before_jump = self.state.norm() ** 2 - self.jump_threshold
|
|
572
|
+
self.norm_gap_before_jump = self.state.norm().item() ** 2 - self.jump_threshold
|
|
570
573
|
self.root_finder.provide_ordinate(self.current_time, self.norm_gap_before_jump)
|
|
571
574
|
|
|
572
575
|
if self.root_finder.is_converged(tolerance=1):
|
|
@@ -592,7 +595,7 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
|
|
|
592
595
|
self.state *= 1 / self.state.norm()
|
|
593
596
|
self.init_baths()
|
|
594
597
|
|
|
595
|
-
norm_after_normalizing = self.state.norm()
|
|
598
|
+
norm_after_normalizing = self.state.norm().item()
|
|
596
599
|
assert math.isclose(norm_after_normalizing, 1, abs_tol=1e-10)
|
|
597
600
|
self.set_jump_threshold(norm_after_normalizing**2)
|
|
598
601
|
|
emu_mps/optimatrix/__init__.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from .optimiser import minimize_bandwidth
|
|
2
|
-
from .permutations import
|
|
2
|
+
from .permutations import permute_tensor, inv_permutation, permute_string
|
|
3
3
|
|
|
4
4
|
__all__ = [
|
|
5
5
|
"minimize_bandwidth",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
6
|
+
"permute_string",
|
|
7
|
+
"permute_tensor",
|
|
8
|
+
"inv_permutation",
|
|
9
9
|
]
|
emu_mps/optimatrix/optimiser.py
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
|
|
3
|
+
import torch
|
|
1
4
|
from scipy.sparse import csr_matrix
|
|
2
5
|
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
6
|
|
|
7
|
+
from emu_mps.optimatrix.permutations import permute_tensor
|
|
7
8
|
|
|
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
9
|
|
|
14
|
-
|
|
10
|
+
def is_symmetric(matrix: torch.Tensor, tol: float = 1e-8) -> bool:
|
|
11
|
+
return torch.allclose(matrix, matrix.T, atol=tol)
|
|
15
12
|
|
|
16
13
|
|
|
17
|
-
def matrix_bandwidth(mat:
|
|
18
|
-
"""matrix_bandwidth(matrix:
|
|
14
|
+
def matrix_bandwidth(mat: torch.Tensor) -> float:
|
|
15
|
+
"""matrix_bandwidth(matrix: torch.tensor) -> torch.Tensor
|
|
19
16
|
|
|
20
17
|
Computes bandwidth as max weighted distance between columns of
|
|
21
18
|
a square matrix as `max (abs(matrix[i, j] * (j - i))`.
|
|
@@ -45,19 +42,27 @@ def matrix_bandwidth(mat: np.ndarray) -> float:
|
|
|
45
42
|
|
|
46
43
|
Example:
|
|
47
44
|
-------
|
|
48
|
-
>>> matrix =
|
|
49
|
-
...
|
|
50
|
-
...
|
|
51
|
-
...
|
|
52
|
-
|
|
45
|
+
>>> matrix = torch.tensor([
|
|
46
|
+
... [1.0, -17.0, 2.4],
|
|
47
|
+
... [9.0, 1.0, -10.0],
|
|
48
|
+
... [-15.0, 20.0, 1.0]
|
|
49
|
+
... ])
|
|
50
|
+
>>> matrix_bandwidth(matrix) # because abs(-15 * (0 - 2)) = 30.0
|
|
53
51
|
30.0
|
|
54
52
|
"""
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
return float(bandwidth)
|
|
54
|
+
n = mat.shape[0]
|
|
58
55
|
|
|
56
|
+
i_arr = torch.arange(n).view(-1, 1) # shape (n, 1)
|
|
57
|
+
j_arr = torch.arange(n).view(1, -1) # shape (1, n)
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
weighted = torch.abs(mat * (j_arr - i_arr))
|
|
60
|
+
return torch.max(weighted).to(mat.dtype).item()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def minimize_bandwidth_above_threshold(
|
|
64
|
+
mat: torch.Tensor, threshold: float
|
|
65
|
+
) -> torch.Tensor:
|
|
61
66
|
"""
|
|
62
67
|
minimize_bandwidth_above_threshold(matrix, trunc) -> permutation_lists
|
|
63
68
|
|
|
@@ -78,24 +83,25 @@ def minimize_bandwidth_above_threshold(mat: np.ndarray, threshold: float) -> np.
|
|
|
78
83
|
|
|
79
84
|
Example:
|
|
80
85
|
-------
|
|
81
|
-
>>> matrix =
|
|
82
|
-
...
|
|
83
|
-
...
|
|
84
|
-
...
|
|
86
|
+
>>> matrix = torch.tensor([
|
|
87
|
+
... [1, 2, 3],
|
|
88
|
+
... [2, 5, 6],
|
|
89
|
+
... [3, 6, 9]
|
|
90
|
+
... ], dtype=torch.float32)
|
|
85
91
|
>>> threshold = 3
|
|
86
92
|
>>> minimize_bandwidth_above_threshold(matrix, threshold)
|
|
87
|
-
|
|
93
|
+
tensor([1, 2, 0], dtype=torch.int32)
|
|
88
94
|
"""
|
|
89
95
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
rcm_permutation = reverse_cuthill_mckee(
|
|
93
|
-
csr_matrix(matrix_truncated), symmetric_mode=True
|
|
94
|
-
)
|
|
95
|
-
return np.array(rcm_permutation)
|
|
96
|
+
m_trunc = mat.clone()
|
|
97
|
+
m_trunc[mat < threshold] = 0.0
|
|
96
98
|
|
|
99
|
+
matrix_np = csr_matrix(m_trunc.numpy()) # SciPy's RCM compatibility
|
|
100
|
+
rcm_perm = reverse_cuthill_mckee(matrix_np, symmetric_mode=True)
|
|
101
|
+
return torch.from_numpy(rcm_perm.copy()) # translation requires copy
|
|
97
102
|
|
|
98
|
-
|
|
103
|
+
|
|
104
|
+
def minimize_bandwidth_global(mat: torch.Tensor) -> torch.Tensor:
|
|
99
105
|
"""
|
|
100
106
|
minimize_bandwidth_global(matrix) -> list
|
|
101
107
|
|
|
@@ -111,74 +117,78 @@ def minimize_bandwidth_global(mat: np.ndarray) -> list[int]:
|
|
|
111
117
|
-------
|
|
112
118
|
permutation order that minimizes matrix bandwidth
|
|
113
119
|
|
|
114
|
-
Example
|
|
120
|
+
Example
|
|
115
121
|
-------
|
|
116
|
-
>>> matrix =
|
|
117
|
-
...
|
|
118
|
-
...
|
|
119
|
-
...
|
|
122
|
+
>>> matrix = torch.tensor([
|
|
123
|
+
... [1, 2, 3],
|
|
124
|
+
... [2, 5, 6],
|
|
125
|
+
... [3, 6, 9]
|
|
126
|
+
... ], dtype=torch.float32)
|
|
120
127
|
>>> minimize_bandwidth_global(matrix)
|
|
121
|
-
[2, 1, 0]
|
|
128
|
+
tensor([2, 1, 0], dtype=torch.int32)
|
|
122
129
|
"""
|
|
123
|
-
mat_amplitude =
|
|
124
|
-
|
|
130
|
+
mat_amplitude = torch.max(torch.abs(mat))
|
|
131
|
+
|
|
125
132
|
permutations = (
|
|
126
|
-
minimize_bandwidth_above_threshold(mat, trunc * mat_amplitude)
|
|
127
|
-
for trunc in
|
|
133
|
+
minimize_bandwidth_above_threshold(mat, trunc.item() * mat_amplitude)
|
|
134
|
+
for trunc in torch.arange(0.1, 1.0, 0.01)
|
|
128
135
|
)
|
|
129
136
|
|
|
130
137
|
opt_permutation = min(
|
|
131
|
-
permutations, key=lambda perm: matrix_bandwidth(
|
|
138
|
+
permutations, key=lambda perm: matrix_bandwidth(permute_tensor(mat, perm))
|
|
132
139
|
)
|
|
133
|
-
|
|
140
|
+
|
|
141
|
+
return opt_permutation
|
|
134
142
|
|
|
135
143
|
|
|
136
144
|
def minimize_bandwidth_impl(
|
|
137
|
-
matrix:
|
|
138
|
-
) -> tuple[
|
|
145
|
+
matrix: torch.Tensor, initial_perm: torch.Tensor
|
|
146
|
+
) -> tuple[torch.Tensor, float]:
|
|
139
147
|
"""
|
|
140
|
-
minimize_bandwidth_impl(matrix, initial_perm) ->
|
|
148
|
+
minimize_bandwidth_impl(matrix, initial_perm) -> (optimal_perm, bandwidth)
|
|
141
149
|
|
|
142
150
|
Applies initial_perm to a matrix and
|
|
143
|
-
finds the permutation list for a symmetric matrix
|
|
151
|
+
finds the permutation list for a symmetric matrix
|
|
152
|
+
that iteratively minimizes matrix bandwidth.
|
|
144
153
|
|
|
145
154
|
Parameters
|
|
146
155
|
-------
|
|
147
156
|
matrix :
|
|
148
157
|
symmetric square matrix
|
|
149
|
-
initial_perm: list of integers
|
|
158
|
+
initial_perm: torch list of integers
|
|
150
159
|
|
|
151
160
|
|
|
152
161
|
Returns
|
|
153
162
|
-------
|
|
154
|
-
permutation
|
|
163
|
+
optimal permutation and optimal matrix bandwidth
|
|
155
164
|
|
|
156
165
|
Example:
|
|
157
166
|
-------
|
|
158
167
|
Periodic 1D chain
|
|
159
|
-
>>> matrix =
|
|
168
|
+
>>> matrix = torch.tensor([
|
|
160
169
|
... [0, 1, 0, 0, 1],
|
|
161
170
|
... [1, 0, 1, 0, 0],
|
|
162
171
|
... [0, 1, 0, 1, 0],
|
|
163
172
|
... [0, 0, 1, 0, 1],
|
|
164
|
-
... [1, 0, 0, 1, 0]])
|
|
165
|
-
>>> id_perm =
|
|
173
|
+
... [1, 0, 0, 1, 0]], dtype=torch.float32)
|
|
174
|
+
>>> id_perm = torch.arange(matrix.shape[0])
|
|
166
175
|
>>> minimize_bandwidth_impl(matrix, id_perm) # [3, 2, 4, 1, 0] does zig-zag
|
|
167
|
-
([3, 2, 4, 1, 0], 2.0)
|
|
176
|
+
(tensor([3, 2, 4, 1, 0]), 2.0)
|
|
168
177
|
|
|
169
178
|
Simple 1D chain. Cannot be optimised further
|
|
170
|
-
>>> matrix =
|
|
179
|
+
>>> matrix = torch.tensor([
|
|
171
180
|
... [0, 1, 0, 0, 0],
|
|
172
181
|
... [1, 0, 1, 0, 0],
|
|
173
182
|
... [0, 1, 0, 1, 0],
|
|
174
183
|
... [0, 0, 1, 0, 1],
|
|
175
|
-
... [0, 0, 0, 1, 0]])
|
|
176
|
-
>>> id_perm =
|
|
184
|
+
... [0, 0, 0, 1, 0]], dtype=torch.float32)
|
|
185
|
+
>>> id_perm = torch.arange(matrix.shape[0])
|
|
177
186
|
>>> minimize_bandwidth_impl(matrix, id_perm)
|
|
178
|
-
([0, 1, 2, 3, 4], 1.0)
|
|
187
|
+
(tensor([0, 1, 2, 3, 4]), 1.0)
|
|
179
188
|
"""
|
|
180
|
-
|
|
181
|
-
|
|
189
|
+
L = matrix.shape[0]
|
|
190
|
+
if not torch.equal(initial_perm, torch.arange(L)):
|
|
191
|
+
matrix = permute_tensor(matrix, initial_perm)
|
|
182
192
|
bandwidth = matrix_bandwidth(matrix)
|
|
183
193
|
acc_permutation = initial_perm
|
|
184
194
|
|
|
@@ -191,28 +201,28 @@ def minimize_bandwidth_impl(
|
|
|
191
201
|
)
|
|
192
202
|
|
|
193
203
|
optimal_perm = minimize_bandwidth_global(matrix)
|
|
194
|
-
test_mat =
|
|
204
|
+
test_mat = permute_tensor(matrix, optimal_perm)
|
|
195
205
|
new_bandwidth = matrix_bandwidth(test_mat)
|
|
196
206
|
|
|
197
207
|
if bandwidth <= new_bandwidth:
|
|
198
208
|
break
|
|
199
209
|
|
|
200
210
|
matrix = test_mat
|
|
201
|
-
acc_permutation =
|
|
211
|
+
acc_permutation = permute_tensor(acc_permutation, optimal_perm)
|
|
202
212
|
bandwidth = new_bandwidth
|
|
203
213
|
|
|
204
214
|
return acc_permutation, bandwidth
|
|
205
215
|
|
|
206
216
|
|
|
207
|
-
def minimize_bandwidth(input_matrix:
|
|
217
|
+
def minimize_bandwidth(input_matrix: torch.Tensor, samples: int = 100) -> torch.Tensor:
|
|
208
218
|
assert is_symmetric(input_matrix), "Input matrix is not symmetric"
|
|
209
|
-
input_mat = abs(input_matrix)
|
|
219
|
+
input_mat = torch.abs(input_matrix)
|
|
210
220
|
# We are interested in strength of the interaction, not sign
|
|
211
221
|
|
|
212
222
|
L = input_mat.shape[0]
|
|
213
|
-
rnd_permutations
|
|
214
|
-
[
|
|
215
|
-
|
|
223
|
+
rnd_permutations = itertools.chain(
|
|
224
|
+
[torch.arange(L)], # identity permutation
|
|
225
|
+
[torch.randperm(L) for _ in range(samples)], # list of random permutations
|
|
216
226
|
)
|
|
217
227
|
|
|
218
228
|
opt_permutations_and_opt_bandwidth = (
|
|
@@ -1,36 +1,31 @@
|
|
|
1
|
-
import
|
|
1
|
+
import torch
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
def
|
|
4
|
+
def permute_string(input_str: str, perm: torch.Tensor) -> str:
|
|
5
5
|
"""
|
|
6
|
-
Permutes the input
|
|
7
|
-
|
|
6
|
+
Permutes the input string according to the given permutation.
|
|
8
7
|
Parameters
|
|
9
8
|
-------
|
|
10
|
-
|
|
11
|
-
A
|
|
9
|
+
input_string :
|
|
10
|
+
A string to permute.
|
|
12
11
|
permutation :
|
|
13
12
|
A list of indices representing the new order.
|
|
14
|
-
|
|
15
13
|
Returns
|
|
16
14
|
-------
|
|
17
|
-
The permuted
|
|
18
|
-
|
|
15
|
+
The permuted string.
|
|
19
16
|
Example
|
|
20
17
|
-------
|
|
21
|
-
>>>
|
|
22
|
-
|
|
18
|
+
>>> permute_string("abc", torch.tensor([2, 0, 1]))
|
|
19
|
+
'cab'
|
|
23
20
|
"""
|
|
21
|
+
char_list = list(input_str)
|
|
22
|
+
permuted = [char_list[i] for i in perm.tolist()]
|
|
23
|
+
return "".join(permuted)
|
|
24
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
25
|
|
|
30
|
-
|
|
31
|
-
def invert_permutation(permutation: list[int]) -> list[int]:
|
|
26
|
+
def inv_permutation(permutation: torch.Tensor) -> torch.Tensor:
|
|
32
27
|
"""
|
|
33
|
-
|
|
28
|
+
inv_permutation(permutation) -> inverted_perm
|
|
34
29
|
|
|
35
30
|
Inverts the input permutation list.
|
|
36
31
|
|
|
@@ -45,47 +40,60 @@ def invert_permutation(permutation: list[int]) -> list[int]:
|
|
|
45
40
|
|
|
46
41
|
Example:
|
|
47
42
|
-------
|
|
48
|
-
>>>
|
|
49
|
-
[1, 2, 0]
|
|
43
|
+
>>> inv_permutation(torch.tensor([2, 0, 1]))
|
|
44
|
+
tensor([1, 2, 0])
|
|
50
45
|
"""
|
|
51
|
-
|
|
52
|
-
inv_perm =
|
|
53
|
-
inv_perm
|
|
54
|
-
return list(inv_perm)
|
|
46
|
+
inv_perm = torch.empty_like(permutation)
|
|
47
|
+
inv_perm[permutation] = torch.arange(len(permutation))
|
|
48
|
+
return inv_perm
|
|
55
49
|
|
|
56
50
|
|
|
57
|
-
def
|
|
51
|
+
def permute_tensor(tensor: torch.Tensor, perm: torch.Tensor) -> torch.Tensor:
|
|
58
52
|
"""
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
Permute a 1D or square 2D torch tensor using the given permutation indices.
|
|
54
|
+
For 1D tensors, applies the permutation to the elements.
|
|
55
|
+
For 2D square tensors, applies the same permutation to both rows and columns.
|
|
62
56
|
|
|
63
57
|
Parameters
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
square
|
|
67
|
-
|
|
68
|
-
permutation
|
|
58
|
+
----------
|
|
59
|
+
tensor : torch.Tensor
|
|
60
|
+
A 1D or 2D square tensor to be permuted.
|
|
61
|
+
perm : torch.Tensor
|
|
62
|
+
A 1D tensor of indices specifying the permutation order.
|
|
69
63
|
|
|
70
64
|
Returns
|
|
71
65
|
-------
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
66
|
+
torch.Tensor
|
|
67
|
+
A new tensor with elements (1D) or rows and columns (2D) permuted according to `perm`.
|
|
68
|
+
|
|
69
|
+
Raises
|
|
70
|
+
------
|
|
71
|
+
ValueError
|
|
72
|
+
If tensor is not 1D or square 2D.
|
|
73
|
+
|
|
74
|
+
Examples
|
|
75
|
+
--------
|
|
76
|
+
>>> vector = torch.tensor([10, 20, 30])
|
|
77
|
+
>>> perm = torch.tensor([2, 0, 1])
|
|
78
|
+
>>> permute_tensor(vector, perm)
|
|
79
|
+
tensor([30, 10, 20])
|
|
80
|
+
|
|
81
|
+
>>> matrix = torch.tensor([
|
|
82
|
+
... [1, 2, 3],
|
|
83
|
+
... [4, 5, 6],
|
|
84
|
+
... [7, 8, 9]])
|
|
85
|
+
>>> perm = torch.tensor([1, 0, 2])
|
|
86
|
+
>>> permute_tensor(matrix, perm)
|
|
87
|
+
tensor([[5, 4, 6],
|
|
88
|
+
[2, 1, 3],
|
|
89
|
+
[8, 7, 9]])
|
|
85
90
|
"""
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
if tensor.ndim == 1:
|
|
92
|
+
return tensor[perm]
|
|
93
|
+
elif tensor.ndim == 2 and tensor.shape[0] == tensor.shape[1]:
|
|
94
|
+
return tensor[perm][:, perm]
|
|
95
|
+
else:
|
|
96
|
+
raise ValueError("Only 1D tensors or square 2D tensors are supported.")
|
|
89
97
|
|
|
90
98
|
|
|
91
99
|
if __name__ == "__main__":
|
emu_mps/tdvp.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: emu-mps
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Pasqal MPS based pulse emulator built on PyTorch
|
|
5
5
|
Project-URL: Documentation, https://pasqal-io.github.io/emulators/
|
|
6
6
|
Project-URL: Repository, https://github.com/pasqal-io/emulators
|
|
@@ -25,7 +25,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
25
25
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
27
27
|
Requires-Python: >=3.10
|
|
28
|
-
Requires-Dist: emu-base==2.0.
|
|
28
|
+
Requires-Dist: emu-base==2.0.2
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
|
|
31
31
|
<div align="center">
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
emu_mps/__init__.py,sha256=cjDXI6YNKEZ_qT8eIT8z9HUowyx4Mh8fNTFciJpMm9k,734
|
|
2
|
+
emu_mps/algebra.py,sha256=ngPtTH-j2ZCBWoaJZXlkUyIlug7dY7Q92gzfnRlpPMA,5485
|
|
3
|
+
emu_mps/custom_callback_implementations.py,sha256=CUs0kW3HRaPE7UeFNQOFbeWJMsz4hS2q4rgS57BBp-A,2411
|
|
4
|
+
emu_mps/hamiltonian.py,sha256=gOPxNOBmk6jRPPjevERuCP_scGv0EKYeAJ0uxooihes,15622
|
|
5
|
+
emu_mps/mpo.py,sha256=1ogQ25GZCwMzZ_m449oGHcYyDKrofBCr1eyzzrIPMhQ,8824
|
|
6
|
+
emu_mps/mps.py,sha256=GIiWxctNmHARgf-PgQc6IHKNCe5HYSnbtlXI6Hc-0wI,20085
|
|
7
|
+
emu_mps/mps_backend.py,sha256=_3rlg6XeI4fHaDiJRfPL6pDkX9k48hAHKXd8fkvkOFs,2004
|
|
8
|
+
emu_mps/mps_backend_impl.py,sha256=P8GYzM4C7r6Sgf9eSPQuwzQup4nwy3tPzlcQgGFkxpI,23132
|
|
9
|
+
emu_mps/mps_config.py,sha256=89nu5OhNUX31eAeeYvvKnAHegpPVD43jH5Nmp635HVU,6984
|
|
10
|
+
emu_mps/noise.py,sha256=h4X2EFjoC_Ok0gZ8I9wN77RANXaVehTBbjkcbY_GAmY,784
|
|
11
|
+
emu_mps/observables.py,sha256=7GQDH5kyaVNrwckk2f8ZJRV9Ca4jKhWWDsOCqYWsoEk,1349
|
|
12
|
+
emu_mps/tdvp.py,sha256=MMkYtVRNovNZiLO6BO1mmr6I6yYDYUJC3MGapfGlrQw,5756
|
|
13
|
+
emu_mps/utils.py,sha256=BqRJYAcXqprtZVJ0V_j954ON2bhTdtZiaTojsYyrWrg,8193
|
|
14
|
+
emu_mps/optimatrix/__init__.py,sha256=iFftb0AtiT_va153B_rZuY_PWWCo1SHnS8sRKjz8cS0,224
|
|
15
|
+
emu_mps/optimatrix/optimiser.py,sha256=k9suYmKLKlaZ7ozFuIqvXHyCBoCtGgkX1mpen9GOdOo,6977
|
|
16
|
+
emu_mps/optimatrix/permutations.py,sha256=kQKPF1Owe_f63zEhfaDadlxkqotIkAPK4kSzfqELIaM,2597
|
|
17
|
+
emu_mps-2.0.2.dist-info/METADATA,sha256=p6h2IcYP-wiR9yrs6Q_9lzgz5DpDn9YvM8dpLQmgbhI,3505
|
|
18
|
+
emu_mps-2.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
19
|
+
emu_mps-2.0.2.dist-info/RECORD,,
|
emu_mps-2.0.1.dist-info/RECORD
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
emu_mps/__init__.py,sha256=GIR0FJOvmMHby7Vx_Da3w7YqqLpOxa0E8E3poxXsapY,734
|
|
2
|
-
emu_mps/algebra.py,sha256=ngPtTH-j2ZCBWoaJZXlkUyIlug7dY7Q92gzfnRlpPMA,5485
|
|
3
|
-
emu_mps/custom_callback_implementations.py,sha256=CUs0kW3HRaPE7UeFNQOFbeWJMsz4hS2q4rgS57BBp-A,2411
|
|
4
|
-
emu_mps/hamiltonian.py,sha256=LcBs6CKBb643a1e9AAVtQoUfa4L_0dIhLOKecx5OOWs,15864
|
|
5
|
-
emu_mps/mpo.py,sha256=wSonS6i3zEt3yRTgyZ7F6vT51pUKavFcLOxFFphBv8k,8793
|
|
6
|
-
emu_mps/mps.py,sha256=KqAjo-nxgM-xQSg1NFNchwXKoPRcrKuuycFMsWr7iX8,19610
|
|
7
|
-
emu_mps/mps_backend.py,sha256=_3rlg6XeI4fHaDiJRfPL6pDkX9k48hAHKXd8fkvkOFs,2004
|
|
8
|
-
emu_mps/mps_backend_impl.py,sha256=M_do7QRBLAoHfwF_EpyMCb6g7w7BSs5hsPa5UE0z9Zs,22958
|
|
9
|
-
emu_mps/mps_config.py,sha256=89nu5OhNUX31eAeeYvvKnAHegpPVD43jH5Nmp635HVU,6984
|
|
10
|
-
emu_mps/noise.py,sha256=h4X2EFjoC_Ok0gZ8I9wN77RANXaVehTBbjkcbY_GAmY,784
|
|
11
|
-
emu_mps/observables.py,sha256=7GQDH5kyaVNrwckk2f8ZJRV9Ca4jKhWWDsOCqYWsoEk,1349
|
|
12
|
-
emu_mps/tdvp.py,sha256=pIQ2NXA2Mrkp3elhqQbX3pdJVbtKkG3c5r9fFlJo7pI,5755
|
|
13
|
-
emu_mps/utils.py,sha256=BqRJYAcXqprtZVJ0V_j954ON2bhTdtZiaTojsYyrWrg,8193
|
|
14
|
-
emu_mps/optimatrix/__init__.py,sha256=lHWYNeThHp57ZrwTwXd0p8bNvcCv0w_AZ31iCWflBUo,226
|
|
15
|
-
emu_mps/optimatrix/optimiser.py,sha256=7j9_jMQC-Uh2DzdIVB44InRzZO6AbbGhvmm7lC6N3tk,6737
|
|
16
|
-
emu_mps/optimatrix/permutations.py,sha256=JRXGont8B4QgbkV9CzrA0w7uzLgBrmZ1J9aa0G52hPo,1979
|
|
17
|
-
emu_mps-2.0.1.dist-info/METADATA,sha256=aGt2cFa9rplEaJAo8z4J5uoAkqq9WnQIlOhciUc6vkg,3505
|
|
18
|
-
emu_mps-2.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
19
|
-
emu_mps-2.0.1.dist-info/RECORD,,
|
|
File without changes
|