qadence 1.5.2__py3-none-any.whl → 1.6.1__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.
- qadence/__init__.py +33 -5
- qadence/backend.py +2 -2
- qadence/backends/adjoint.py +8 -4
- qadence/backends/braket/backend.py +3 -2
- qadence/backends/braket/config.py +2 -2
- qadence/backends/gpsr.py +1 -1
- qadence/backends/horqrux/backend.py +23 -31
- qadence/backends/horqrux/config.py +2 -2
- qadence/backends/pulser/backend.py +82 -45
- qadence/backends/pulser/config.py +0 -28
- qadence/backends/pulser/convert_ops.py +20 -7
- qadence/backends/pulser/pulses.py +2 -2
- qadence/backends/pyqtorch/backend.py +3 -2
- qadence/backends/pyqtorch/config.py +2 -2
- qadence/backends/pyqtorch/convert_ops.py +40 -16
- qadence/blocks/block_to_tensor.py +7 -6
- qadence/blocks/matrix.py +2 -2
- qadence/blocks/primitive.py +2 -1
- qadence/blocks/utils.py +2 -2
- qadence/circuit.py +5 -2
- qadence/constructors/__init__.py +1 -10
- qadence/constructors/ansatze.py +1 -65
- qadence/constructors/daqc/daqc.py +3 -2
- qadence/constructors/daqc/gen_parser.py +3 -2
- qadence/constructors/daqc/utils.py +3 -3
- qadence/constructors/feature_maps.py +2 -90
- qadence/constructors/hamiltonians.py +2 -6
- qadence/constructors/rydberg_feature_maps.py +2 -2
- qadence/decompose.py +2 -2
- qadence/engines/torch/differentiable_expectation.py +7 -0
- qadence/extensions.py +4 -15
- qadence/log_config.yaml +24 -0
- qadence/logger.py +9 -27
- qadence/measurements/shadow.py +3 -16
- qadence/ml_tools/config.py +11 -1
- qadence/ml_tools/models.py +10 -2
- qadence/ml_tools/printing.py +1 -3
- qadence/ml_tools/saveload.py +23 -6
- qadence/ml_tools/train_grad.py +39 -6
- qadence/ml_tools/train_no_grad.py +2 -2
- qadence/models/quantum_model.py +13 -6
- qadence/noise/readout.py +2 -3
- qadence/operations/__init__.py +0 -2
- qadence/operations/analog.py +2 -12
- qadence/operations/control_ops.py +3 -2
- qadence/operations/ham_evo.py +5 -7
- qadence/operations/parametric.py +3 -2
- qadence/operations/primitive.py +2 -2
- qadence/overlap.py +7 -12
- qadence/parameters.py +2 -2
- qadence/serialization.py +2 -2
- qadence/states.py +20 -5
- qadence/transpile/block.py +2 -2
- qadence/types.py +2 -2
- qadence/utils.py +42 -3
- {qadence-1.5.2.dist-info → qadence-1.6.1.dist-info}/METADATA +15 -9
- {qadence-1.5.2.dist-info → qadence-1.6.1.dist-info}/RECORD +59 -58
- {qadence-1.5.2.dist-info → qadence-1.6.1.dist-info}/WHEEL +0 -0
- {qadence-1.5.2.dist-info → qadence-1.6.1.dist-info}/licenses/LICENSE +0 -0
@@ -4,7 +4,7 @@ from functools import reduce
|
|
4
4
|
from itertools import chain as flatten
|
5
5
|
from math import prod
|
6
6
|
from operator import add
|
7
|
-
from typing import Any, Sequence, Tuple
|
7
|
+
from typing import Any, Iterable, Sequence, Tuple
|
8
8
|
|
9
9
|
import pyqtorch as pyq
|
10
10
|
import sympy
|
@@ -203,20 +203,36 @@ class PyQComposedBlock(pyq.QuantumCircuit):
|
|
203
203
|
n_qubits: int,
|
204
204
|
config: Configuration = None,
|
205
205
|
):
|
206
|
-
"""
|
206
|
+
"""
|
207
|
+
Merge operations that are adjacent and have identical qubit_support.
|
207
208
|
|
208
|
-
call
|
209
|
+
It results in fewer call of apply_operator
|
209
210
|
"""
|
210
211
|
super().__init__(n_qubits, ops)
|
211
212
|
self.qubits = qubits
|
213
|
+
self.merged_qubits_support = [
|
214
|
+
grouped_op[-1].qubit_support for grouped_op in self.grouped_operations()
|
215
|
+
]
|
212
216
|
|
213
|
-
def
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
217
|
+
def grouped_operations(self) -> list[list[Module]]:
|
218
|
+
# takes a list of operations and group adjacent operations into sublist
|
219
|
+
# if those operations have the same control qubits
|
220
|
+
def _sublist_grouper(x: Iterable[list[Module]], y: Module) -> list[list[Module]]:
|
221
|
+
# Appends the element y with the last sublist in the list x
|
222
|
+
# if they have the same qubit_support.
|
223
|
+
# Appends the element y as a new sublist to x if it has different qubit_domain
|
224
|
+
x = list(x)
|
225
|
+
if y.qubit_support == x[-1][-1].qubit_support:
|
226
|
+
x[-1].append(y)
|
227
|
+
return x
|
228
|
+
else:
|
229
|
+
x.append([y])
|
230
|
+
return x
|
218
231
|
|
219
|
-
|
232
|
+
return list(reduce(_sublist_grouper, iter(self.operations[1:]), [[self.operations[0]]]))
|
233
|
+
|
234
|
+
def merged_unitary(self, values: dict[str, Tensor] | None, batch_size: int) -> list[Tensor]:
|
235
|
+
# compute the tensor multiplication of each group of operations
|
220
236
|
batch_first_perm = (2, 0, 1)
|
221
237
|
undo_perm = tuple(argsort(tensor(batch_first_perm)))
|
222
238
|
|
@@ -225,7 +241,7 @@ class PyQComposedBlock(pyq.QuantumCircuit):
|
|
225
241
|
m = m.unsqueeze(2).repeat(
|
226
242
|
1, 1, batch_size
|
227
243
|
) # Primitive gates are 2D, so we expand them.
|
228
|
-
elif m.shape != (2, 2, batch_size):
|
244
|
+
elif m.shape != (2, 2, batch_size) and m.shape != (4, 4, batch_size):
|
229
245
|
m = m.repeat(1, 1, batch_size) # In case a tensor is 3D doesnt have batch_size.
|
230
246
|
return m
|
231
247
|
|
@@ -237,13 +253,21 @@ class PyQComposedBlock(pyq.QuantumCircuit):
|
|
237
253
|
m, undo_perm
|
238
254
|
) # We need to undo the permute since PyQ expects (2, 2, batch_size).
|
239
255
|
|
240
|
-
|
256
|
+
def _list_wise_bmm(ops: list[Module]) -> Tensor:
|
257
|
+
# Takes a list of operations and apply torch.bmm to all the unitaries of the list
|
258
|
+
return _batch_last(
|
259
|
+
reduce(bmm, [_batch_first(_expand(op.unitary(values))) for op in reversed(ops)])
|
260
|
+
) # We reverse the list of tensors here since matmul is not commutative.
|
241
261
|
|
242
|
-
return
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
262
|
+
return list(map(_list_wise_bmm, reversed(self.grouped_operations())))[::-1]
|
263
|
+
|
264
|
+
def forward(self, state: Tensor, values: dict[str, Tensor] | None = None) -> Tensor:
|
265
|
+
# compute evolution of the state by the list of operations
|
266
|
+
batch_size = infer_batchsize(values)
|
267
|
+
return reduce(
|
268
|
+
lambda y, x: apply_operator(state=y, operator=x[0], qubits=x[1]),
|
269
|
+
zip(self.merged_unitary(values, batch_size), self.merged_qubits_support),
|
270
|
+
state,
|
247
271
|
)
|
248
272
|
|
249
273
|
|
@@ -62,7 +62,7 @@ def _fill_identities(
|
|
62
62
|
full_qubit_support: tuple | list,
|
63
63
|
diag_only: bool = False,
|
64
64
|
endianness: Endianness = Endianness.BIG,
|
65
|
-
device: torch.device =
|
65
|
+
device: torch.device | None = None,
|
66
66
|
) -> torch.Tensor:
|
67
67
|
"""Returns a Kronecker product of a block matrix with identities.
|
68
68
|
|
@@ -181,12 +181,13 @@ def _controlled_block_with_params(
|
|
181
181
|
AbstractBlock: redefined controlled rotation block
|
182
182
|
dict with new parameters which are added
|
183
183
|
"""
|
184
|
-
from qadence.operations import I
|
184
|
+
from qadence.operations import I
|
185
|
+
from qadence.utils import P1
|
185
186
|
|
186
187
|
# redefine controlled rotation block in a way suitable for matrix evaluation
|
187
188
|
control = block.qubit_support[:-1]
|
188
189
|
target = block.qubit_support[-1]
|
189
|
-
p1 = kron(
|
190
|
+
p1 = kron(P1(qubit) for qubit in control)
|
190
191
|
p0 = I(control[0]) - p1
|
191
192
|
c_block = kron(p0, I(target)) + kron(p1, block.blocks[0])
|
192
193
|
|
@@ -265,7 +266,7 @@ def block_to_diagonal(
|
|
265
266
|
qubit_support: tuple | list | None = None,
|
266
267
|
use_full_support: bool = True,
|
267
268
|
endianness: Endianness = Endianness.BIG,
|
268
|
-
device: torch.device =
|
269
|
+
device: torch.device = None,
|
269
270
|
) -> torch.Tensor:
|
270
271
|
if block.is_parametric:
|
271
272
|
raise TypeError("Sparse observables cant be parametric.")
|
@@ -310,7 +311,7 @@ def block_to_tensor(
|
|
310
311
|
use_full_support: bool = True,
|
311
312
|
tensor_type: TensorType = TensorType.DENSE,
|
312
313
|
endianness: Endianness = Endianness.BIG,
|
313
|
-
device: torch.device =
|
314
|
+
device: torch.device = None,
|
314
315
|
) -> torch.Tensor:
|
315
316
|
"""
|
316
317
|
Convert a block into a torch tensor.
|
@@ -369,7 +370,7 @@ def _block_to_tensor_embedded(
|
|
369
370
|
qubit_support: tuple | None = None,
|
370
371
|
use_full_support: bool = True,
|
371
372
|
endianness: Endianness = Endianness.BIG,
|
372
|
-
device: torch.device =
|
373
|
+
device: torch.device = None,
|
373
374
|
) -> torch.Tensor:
|
374
375
|
from qadence.blocks import MatrixBlock
|
375
376
|
from qadence.operations import CSWAP, SWAP, HamEvo
|
qadence/blocks/matrix.py
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from functools import cached_property
|
4
|
+
from logging import getLogger
|
4
5
|
|
5
6
|
import numpy as np
|
6
7
|
import torch
|
7
8
|
from torch.linalg import eigvals
|
8
9
|
|
9
10
|
from qadence.blocks import PrimitiveBlock
|
10
|
-
from qadence.logger import get_logger
|
11
11
|
|
12
|
-
logger =
|
12
|
+
logger = getLogger(__name__)
|
13
13
|
|
14
14
|
|
15
15
|
class MatrixBlock(PrimitiveBlock):
|
qadence/blocks/primitive.py
CHANGED
@@ -20,7 +20,6 @@ from qadence.parameters import (
|
|
20
20
|
stringify,
|
21
21
|
)
|
22
22
|
from qadence.types import TParameter
|
23
|
-
from qadence.utils import format_parameter
|
24
23
|
|
25
24
|
|
26
25
|
class PrimitiveBlock(AbstractBlock):
|
@@ -258,6 +257,8 @@ class ScaleBlock(ParametricBlock):
|
|
258
257
|
|
259
258
|
@property
|
260
259
|
def _block_title(self) -> str:
|
260
|
+
from qadence.utils import format_parameter
|
261
|
+
|
261
262
|
(scale,) = self.parameters.expressions()
|
262
263
|
s = rf"\[mul: {format_parameter(scale)}] "
|
263
264
|
return s
|
qadence/blocks/utils.py
CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
3
3
|
import typing
|
4
4
|
from enum import Enum
|
5
5
|
from itertools import chain as _flatten
|
6
|
+
from logging import getLogger
|
6
7
|
from typing import Generator, List, Type, TypeVar, Union, get_args
|
7
8
|
|
8
9
|
from sympy import Array, Basic, Expr
|
@@ -29,10 +30,9 @@ from qadence.blocks.analog import (
|
|
29
30
|
from qadence.blocks.analog import chain as analog_chain
|
30
31
|
from qadence.blocks.analog import kron as analog_kron
|
31
32
|
from qadence.exceptions import NotPauliBlockError
|
32
|
-
from qadence.logger import get_logger
|
33
33
|
from qadence.parameters import Parameter
|
34
34
|
|
35
|
-
logger =
|
35
|
+
logger = getLogger(__name__)
|
36
36
|
|
37
37
|
|
38
38
|
TPrimitiveBlock = TypeVar("TPrimitiveBlock", bound=PrimitiveBlock)
|
qadence/circuit.py
CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from itertools import chain as flatten
|
5
|
+
from logging import getLogger
|
5
6
|
from pathlib import Path
|
6
7
|
from typing import Iterable
|
7
8
|
|
@@ -15,6 +16,8 @@ from qadence.register import Register
|
|
15
16
|
# Modules to be automatically added to the qadence namespace
|
16
17
|
__all__ = ["QuantumCircuit"]
|
17
18
|
|
19
|
+
logger = getLogger(__name__)
|
20
|
+
|
18
21
|
|
19
22
|
@dataclass(eq=False) # Avoid unhashability errors due to mutable attributes.
|
20
23
|
class QuantumCircuit:
|
@@ -167,7 +170,7 @@ class QuantumCircuit:
|
|
167
170
|
with open(path, "w") as file:
|
168
171
|
file.write(qc_dumped)
|
169
172
|
except Exception as e:
|
170
|
-
|
173
|
+
logger.error(f"Unable to write QuantumCircuit to disk due to {e}")
|
171
174
|
|
172
175
|
return qc_dumped
|
173
176
|
|
@@ -199,6 +202,6 @@ class QuantumCircuit:
|
|
199
202
|
loaded_dict = json.load(file)
|
200
203
|
|
201
204
|
except Exception as e:
|
202
|
-
|
205
|
+
logger.error(f"Unable to load QuantumCircuit due to {e}")
|
203
206
|
|
204
207
|
return QuantumCircuit._from_dict(loaded_dict)
|
qadence/constructors/__init__.py
CHANGED
@@ -2,13 +2,10 @@
|
|
2
2
|
|
3
3
|
from .feature_maps import (
|
4
4
|
feature_map,
|
5
|
-
chebyshev_feature_map,
|
6
|
-
fourier_feature_map,
|
7
|
-
tower_feature_map,
|
8
5
|
exp_fourier_feature_map,
|
9
6
|
)
|
10
7
|
|
11
|
-
from .ansatze import hea
|
8
|
+
from .ansatze import hea
|
12
9
|
|
13
10
|
from .iia import identity_initialized_ansatz
|
14
11
|
|
@@ -17,7 +14,6 @@ from .daqc import daqc_transform
|
|
17
14
|
from .hamiltonians import (
|
18
15
|
hamiltonian_factory,
|
19
16
|
ising_hamiltonian,
|
20
|
-
single_z,
|
21
17
|
total_magnetization,
|
22
18
|
zz_hamiltonian,
|
23
19
|
)
|
@@ -30,16 +26,11 @@ from .qft import qft
|
|
30
26
|
# Modules to be automatically added to the qadence namespace
|
31
27
|
__all__ = [
|
32
28
|
"feature_map",
|
33
|
-
"chebyshev_feature_map",
|
34
|
-
"fourier_feature_map",
|
35
|
-
"tower_feature_map",
|
36
29
|
"exp_fourier_feature_map",
|
37
30
|
"hea",
|
38
31
|
"identity_initialized_ansatz",
|
39
|
-
"build_qnn",
|
40
32
|
"hamiltonian_factory",
|
41
33
|
"ising_hamiltonian",
|
42
|
-
"single_z",
|
43
34
|
"total_magnetization",
|
44
35
|
"zz_hamiltonian",
|
45
36
|
"qft",
|
qadence/constructors/ansatze.py
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import itertools
|
4
|
-
import
|
5
|
-
from typing import Any, Optional, Type, Union
|
4
|
+
from typing import Any, Type, Union
|
6
5
|
|
7
6
|
from qadence.blocks import AbstractBlock, block_is_qubit_hamiltonian, chain, kron, tag
|
8
7
|
from qadence.operations import CNOT, CPHASE, CRX, CRY, CRZ, CZ, RX, RY, HamEvo
|
9
8
|
from qadence.types import Interaction, Strategy
|
10
9
|
|
11
10
|
from .hamiltonians import hamiltonian_factory
|
12
|
-
from .utils import build_idx_fms
|
13
11
|
|
14
12
|
DigitalEntanglers = Union[CNOT, CZ, CRZ, CRY, CRX]
|
15
13
|
|
@@ -322,65 +320,3 @@ def hea_bDAQC(*args: Any, **kwargs: Any) -> Any:
|
|
322
320
|
|
323
321
|
def hea_analog(*args: Any, **kwargs: Any) -> Any:
|
324
322
|
raise NotImplementedError
|
325
|
-
|
326
|
-
|
327
|
-
#########
|
328
|
-
## QNN ##
|
329
|
-
#########
|
330
|
-
|
331
|
-
|
332
|
-
# FIXME: Remove in v1.5.0
|
333
|
-
def build_qnn(
|
334
|
-
n_qubits: int,
|
335
|
-
n_features: int,
|
336
|
-
depth: int = None,
|
337
|
-
ansatz: Optional[AbstractBlock] = None,
|
338
|
-
fm_pauli: Type[RY] = RY,
|
339
|
-
spectrum: str = "simple",
|
340
|
-
basis: str = "fourier",
|
341
|
-
fm_strategy: str = "parallel",
|
342
|
-
) -> list[AbstractBlock]:
|
343
|
-
"""Helper function to build a qadence QNN quantum circuit.
|
344
|
-
|
345
|
-
Args:
|
346
|
-
n_qubits (int): The number of qubits.
|
347
|
-
n_features (int): The number of input dimensions.
|
348
|
-
depth (int): The depth of the ansatz.
|
349
|
-
ansatz (Optional[AbstractBlock]): An optional argument to pass a custom qadence ansatz.
|
350
|
-
fm_pauli (str): The type of Pauli gate for the feature map. Must be one of 'RX',
|
351
|
-
'RY', or 'RZ'.
|
352
|
-
spectrum (str): The desired spectrum of the feature map generator. The options simple,
|
353
|
-
tower and exponential produce a spectrum with linear, quadratic and exponential
|
354
|
-
eigenvalues with respect to the number of qubits.
|
355
|
-
basis (str): The encoding function. The options fourier and chebyshev correspond to Φ(x)=x
|
356
|
-
and arcos(x) respectively.
|
357
|
-
fm_strategy (str): The feature map encoding strategy. If "parallel", the features
|
358
|
-
are encoded in one block of rotation gates, with each feature given
|
359
|
-
an equal number of qubits. If "serial", the features are encoded
|
360
|
-
sequentially, with a HEA block between.
|
361
|
-
|
362
|
-
Returns:
|
363
|
-
A list of Abstract blocks to be used for constructing a quantum circuit
|
364
|
-
"""
|
365
|
-
|
366
|
-
warnings.warn("Function build_qnn is deprecated and will be removed in v1.5.0.", FutureWarning)
|
367
|
-
|
368
|
-
depth = n_qubits if depth is None else depth
|
369
|
-
|
370
|
-
idx_fms = build_idx_fms(basis, fm_pauli, fm_strategy, n_features, n_qubits, spectrum)
|
371
|
-
|
372
|
-
if fm_strategy == "parallel":
|
373
|
-
_fm = kron(*idx_fms)
|
374
|
-
fm = tag(_fm, tag="FM")
|
375
|
-
|
376
|
-
elif fm_strategy == "serial":
|
377
|
-
fm_components: list[AbstractBlock] = []
|
378
|
-
for j, fm_idx in enumerate(idx_fms[:-1]):
|
379
|
-
fm_idx = tag(fm_idx, tag=f"FM{j}") # type: ignore[assignment]
|
380
|
-
fm_component = (fm_idx, hea(n_qubits, 1, f"theta_{j}"))
|
381
|
-
fm_components.extend(fm_component)
|
382
|
-
fm_components.append(tag(idx_fms[-1], tag=f"FM{len(idx_fms) - 1}"))
|
383
|
-
fm = chain(*fm_components) # type: ignore[assignment]
|
384
|
-
|
385
|
-
ansatz = hea(n_qubits, depth=depth) if ansatz is None else ansatz
|
386
|
-
return [fm, ansatz]
|
@@ -1,18 +1,19 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from logging import getLogger
|
4
|
+
|
3
5
|
import torch
|
4
6
|
|
5
7
|
from qadence.blocks import AbstractBlock, add, chain, kron
|
6
8
|
from qadence.blocks.utils import block_is_qubit_hamiltonian
|
7
9
|
from qadence.constructors.hamiltonians import hamiltonian_factory
|
8
|
-
from qadence.logger import get_logger
|
9
10
|
from qadence.operations import HamEvo, I, N, X
|
10
11
|
from qadence.types import GenDAQC, Interaction, Strategy
|
11
12
|
|
12
13
|
from .gen_parser import _check_compatibility, _parse_generator
|
13
14
|
from .utils import _build_matrix_M, _ix_map
|
14
15
|
|
15
|
-
logger =
|
16
|
+
logger = getLogger(__name__)
|
16
17
|
|
17
18
|
|
18
19
|
def daqc_transform(
|
@@ -1,17 +1,18 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from logging import getLogger
|
4
|
+
|
3
5
|
import torch
|
4
6
|
|
5
7
|
from qadence.blocks import AbstractBlock, KronBlock
|
6
8
|
from qadence.blocks.utils import unroll_block_with_scaling
|
7
|
-
from qadence.logger import get_logger
|
8
9
|
from qadence.operations import N, Z
|
9
10
|
from qadence.parameters import Parameter, evaluate
|
10
11
|
from qadence.types import GenDAQC
|
11
12
|
|
12
13
|
from .utils import _ix_map
|
13
14
|
|
14
|
-
logger =
|
15
|
+
logger = getLogger(__name__)
|
15
16
|
|
16
17
|
|
17
18
|
def _parse_generator(
|
@@ -1,19 +1,18 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import warnings
|
4
3
|
from collections.abc import Callable
|
4
|
+
from logging import getLogger
|
5
5
|
from math import isclose
|
6
6
|
from typing import Union
|
7
7
|
|
8
8
|
from sympy import Basic, acos
|
9
9
|
|
10
10
|
from qadence.blocks import AbstractBlock, KronBlock, chain, kron, tag
|
11
|
-
from qadence.logger import get_logger
|
12
11
|
from qadence.operations import PHASE, RX, RY, RZ, H
|
13
12
|
from qadence.parameters import FeatureParameter, Parameter, VariationalParameter
|
14
13
|
from qadence.types import PI, BasisSet, ReuploadScaling, TParameter
|
15
14
|
|
16
|
-
logger =
|
15
|
+
logger = getLogger(__name__)
|
17
16
|
|
18
17
|
ROTATIONS = [RX, RY, RZ, PHASE]
|
19
18
|
RotationTypes = type[Union[RX, RY, RZ, PHASE]]
|
@@ -35,28 +34,6 @@ RS_FUNC_DICT = {
|
|
35
34
|
}
|
36
35
|
|
37
36
|
|
38
|
-
# FIXME: Remove in v1.5.0
|
39
|
-
def backwards_compatibility(
|
40
|
-
fm_type: BasisSet | Callable | str,
|
41
|
-
reupload_scaling: ReuploadScaling | Callable | str,
|
42
|
-
) -> tuple:
|
43
|
-
if fm_type in ("fourier", "chebyshev", "tower"):
|
44
|
-
logger.warning(
|
45
|
-
"Selecting `fm_type` as 'fourier', 'chebyshev' or 'tower' is deprecated. "
|
46
|
-
"Please use the respective enumerations: 'fm_type = BasisSet.FOURIER', "
|
47
|
-
"'fm_type = BasisSet.CHEBYSHEV' or 'reupload_scaling = ReuploadScaling.TOWER'."
|
48
|
-
)
|
49
|
-
if fm_type == "fourier":
|
50
|
-
fm_type = BasisSet.FOURIER
|
51
|
-
elif fm_type == "chebyshev":
|
52
|
-
fm_type = BasisSet.CHEBYSHEV
|
53
|
-
elif fm_type == "tower":
|
54
|
-
fm_type = BasisSet.CHEBYSHEV
|
55
|
-
reupload_scaling = ReuploadScaling.TOWER
|
56
|
-
|
57
|
-
return fm_type, reupload_scaling
|
58
|
-
|
59
|
-
|
60
37
|
def fm_parameter_scaling(
|
61
38
|
fm_type: BasisSet | Callable | str,
|
62
39
|
param: Parameter | str = "phi",
|
@@ -195,9 +172,6 @@ def feature_map(
|
|
195
172
|
f"Please provide one from {[rot.__name__ for rot in ROTATIONS]}."
|
196
173
|
)
|
197
174
|
|
198
|
-
# Backwards compatibility
|
199
|
-
fm_type, reupload_scaling = backwards_compatibility(fm_type, reupload_scaling)
|
200
|
-
|
201
175
|
scaled_fparam = fm_parameter_scaling(
|
202
176
|
fm_type, param, feature_range=feature_range, target_range=target_range
|
203
177
|
)
|
@@ -225,68 +199,6 @@ def feature_map(
|
|
225
199
|
return fm
|
226
200
|
|
227
201
|
|
228
|
-
# FIXME: Remove in v1.5.0
|
229
|
-
def fourier_feature_map(
|
230
|
-
n_qubits: int, support: tuple[int, ...] = None, param: str = "phi", op: RotationTypes = RX
|
231
|
-
) -> AbstractBlock:
|
232
|
-
"""Construct a Fourier feature map.
|
233
|
-
|
234
|
-
Args:
|
235
|
-
n_qubits: number of qubits across which the FM is created
|
236
|
-
param: The base name for the feature `Parameter`
|
237
|
-
"""
|
238
|
-
warnings.warn(
|
239
|
-
"Function 'fourier_feature_map' is deprecated. Please use 'feature_map' directly.",
|
240
|
-
FutureWarning,
|
241
|
-
)
|
242
|
-
fm = feature_map(n_qubits, support=support, param=param, op=op, fm_type=BasisSet.FOURIER)
|
243
|
-
return fm
|
244
|
-
|
245
|
-
|
246
|
-
# FIXME: Remove in v1.5.0
|
247
|
-
def chebyshev_feature_map(
|
248
|
-
n_qubits: int, support: tuple[int, ...] = None, param: str = "phi", op: RotationTypes = RX
|
249
|
-
) -> AbstractBlock:
|
250
|
-
"""Construct a Chebyshev feature map.
|
251
|
-
|
252
|
-
Args:
|
253
|
-
n_qubits: number of qubits across which the FM is created
|
254
|
-
support (Iterable[int]): The qubit support
|
255
|
-
param: The base name for the feature `Parameter`
|
256
|
-
"""
|
257
|
-
warnings.warn(
|
258
|
-
"Function 'chebyshev_feature_map' is deprecated. Please use 'feature_map' directly.",
|
259
|
-
FutureWarning,
|
260
|
-
)
|
261
|
-
fm = feature_map(n_qubits, support=support, param=param, op=op, fm_type=BasisSet.CHEBYSHEV)
|
262
|
-
return fm
|
263
|
-
|
264
|
-
|
265
|
-
# FIXME: Remove in v1.5.0
|
266
|
-
def tower_feature_map(
|
267
|
-
n_qubits: int, support: tuple[int, ...] = None, param: str = "phi", op: RotationTypes = RX
|
268
|
-
) -> AbstractBlock:
|
269
|
-
"""Construct a Chebyshev tower feature map.
|
270
|
-
|
271
|
-
Args:
|
272
|
-
n_qubits: number of qubits across which the FM is created
|
273
|
-
param: The base name for the feature `Parameter`
|
274
|
-
"""
|
275
|
-
warnings.warn(
|
276
|
-
"Function 'tower_feature_map' is deprecated. Please use feature_map directly.",
|
277
|
-
FutureWarning,
|
278
|
-
)
|
279
|
-
fm = feature_map(
|
280
|
-
n_qubits,
|
281
|
-
support=support,
|
282
|
-
param=param,
|
283
|
-
op=op,
|
284
|
-
fm_type=BasisSet.CHEBYSHEV,
|
285
|
-
reupload_scaling=ReuploadScaling.TOWER,
|
286
|
-
)
|
287
|
-
return fm
|
288
|
-
|
289
|
-
|
290
202
|
def exp_fourier_feature_map(
|
291
203
|
n_qubits: int,
|
292
204
|
support: tuple[int, ...] = None,
|
@@ -1,17 +1,17 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from logging import getLogger
|
3
4
|
from typing import Callable, List, Type, Union
|
4
5
|
|
5
6
|
import numpy as np
|
6
7
|
from torch import Tensor, double, ones, rand
|
7
8
|
|
8
9
|
from qadence.blocks import AbstractBlock, add, block_is_qubit_hamiltonian
|
9
|
-
from qadence.logger import get_logger
|
10
10
|
from qadence.operations import N, X, Y, Z
|
11
11
|
from qadence.register import Register
|
12
12
|
from qadence.types import Interaction, TArray
|
13
13
|
|
14
|
-
logger =
|
14
|
+
logger = getLogger(__name__)
|
15
15
|
|
16
16
|
|
17
17
|
def interaction_zz(i: int, j: int) -> AbstractBlock:
|
@@ -207,10 +207,6 @@ def total_magnetization(n_qubits: int, z_terms: np.ndarray | list | None = None)
|
|
207
207
|
return hamiltonian_factory(n_qubits, detuning=Z, detuning_strength=z_terms)
|
208
208
|
|
209
209
|
|
210
|
-
def single_z(qubit: int = 0, z_coefficient: float = 1.0) -> AbstractBlock:
|
211
|
-
return Z(qubit) * z_coefficient
|
212
|
-
|
213
|
-
|
214
210
|
def zz_hamiltonian(
|
215
211
|
n_qubits: int,
|
216
212
|
z_terms: np.ndarray | None = None,
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from logging import getLogger
|
3
4
|
from typing import Callable
|
4
5
|
|
5
6
|
import numpy as np
|
@@ -7,12 +8,11 @@ from sympy import Basic
|
|
7
8
|
|
8
9
|
from qadence.blocks import AnalogBlock, KronBlock, kron
|
9
10
|
from qadence.constructors.feature_maps import fm_parameter_func, fm_parameter_scaling
|
10
|
-
from qadence.logger import get_logger
|
11
11
|
from qadence.operations import AnalogRot, AnalogRX, AnalogRY, AnalogRZ
|
12
12
|
from qadence.parameters import FeatureParameter, Parameter, VariationalParameter
|
13
13
|
from qadence.types import PI, BasisSet, ReuploadScaling, TParameter
|
14
14
|
|
15
|
-
logger =
|
15
|
+
logger = getLogger(__name__)
|
16
16
|
|
17
17
|
AnalogRotationTypes = [AnalogRX, AnalogRY, AnalogRZ]
|
18
18
|
|
qadence/decompose.py
CHANGED
@@ -2,20 +2,20 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import itertools
|
4
4
|
from enum import Enum
|
5
|
+
from logging import getLogger
|
5
6
|
from typing import Any, List, Tuple, Union
|
6
7
|
|
7
8
|
import sympy
|
8
9
|
|
9
10
|
from qadence.blocks import AbstractBlock
|
10
11
|
from qadence.blocks.utils import get_pauli_blocks, unroll_block_with_scaling
|
11
|
-
from qadence.logger import get_logger
|
12
12
|
from qadence.parameters import Parameter, evaluate
|
13
13
|
|
14
14
|
# from qadence.types import TNumber, TParameter
|
15
15
|
from qadence.types import PI
|
16
16
|
from qadence.types import LTSOrder as Order
|
17
17
|
|
18
|
-
logger =
|
18
|
+
logger = getLogger(__name__)
|
19
19
|
|
20
20
|
# flatten a doubly-nested list
|
21
21
|
flatten = lambda a: list(itertools.chain(*a)) # noqa: E731
|
@@ -45,6 +45,13 @@ class PSRExpectation(Function):
|
|
45
45
|
expectation_values = expectation_fn(param_values=param_dict(param_keys, param_values)) # type: ignore[call-arg] # noqa: E501
|
46
46
|
# Stack batches of expectations if so.
|
47
47
|
if isinstance(expectation_values, list):
|
48
|
+
# Check for first element being a list in case of noisy simulations in Pulser.
|
49
|
+
if isinstance(expectation_values[0], list):
|
50
|
+
exp_vals: list = []
|
51
|
+
for expectation_value in expectation_values:
|
52
|
+
res = list(map(lambda x: x.get_final_state().data.toarray(), expectation_value))
|
53
|
+
exp_vals.append(torch.tensor(res))
|
54
|
+
expectation_values = exp_vals
|
48
55
|
return torch.stack(expectation_values)
|
49
56
|
else:
|
50
57
|
return expectation_values
|