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.
Files changed (59) hide show
  1. qadence/__init__.py +33 -5
  2. qadence/backend.py +2 -2
  3. qadence/backends/adjoint.py +8 -4
  4. qadence/backends/braket/backend.py +3 -2
  5. qadence/backends/braket/config.py +2 -2
  6. qadence/backends/gpsr.py +1 -1
  7. qadence/backends/horqrux/backend.py +23 -31
  8. qadence/backends/horqrux/config.py +2 -2
  9. qadence/backends/pulser/backend.py +82 -45
  10. qadence/backends/pulser/config.py +0 -28
  11. qadence/backends/pulser/convert_ops.py +20 -7
  12. qadence/backends/pulser/pulses.py +2 -2
  13. qadence/backends/pyqtorch/backend.py +3 -2
  14. qadence/backends/pyqtorch/config.py +2 -2
  15. qadence/backends/pyqtorch/convert_ops.py +40 -16
  16. qadence/blocks/block_to_tensor.py +7 -6
  17. qadence/blocks/matrix.py +2 -2
  18. qadence/blocks/primitive.py +2 -1
  19. qadence/blocks/utils.py +2 -2
  20. qadence/circuit.py +5 -2
  21. qadence/constructors/__init__.py +1 -10
  22. qadence/constructors/ansatze.py +1 -65
  23. qadence/constructors/daqc/daqc.py +3 -2
  24. qadence/constructors/daqc/gen_parser.py +3 -2
  25. qadence/constructors/daqc/utils.py +3 -3
  26. qadence/constructors/feature_maps.py +2 -90
  27. qadence/constructors/hamiltonians.py +2 -6
  28. qadence/constructors/rydberg_feature_maps.py +2 -2
  29. qadence/decompose.py +2 -2
  30. qadence/engines/torch/differentiable_expectation.py +7 -0
  31. qadence/extensions.py +4 -15
  32. qadence/log_config.yaml +24 -0
  33. qadence/logger.py +9 -27
  34. qadence/measurements/shadow.py +3 -16
  35. qadence/ml_tools/config.py +11 -1
  36. qadence/ml_tools/models.py +10 -2
  37. qadence/ml_tools/printing.py +1 -3
  38. qadence/ml_tools/saveload.py +23 -6
  39. qadence/ml_tools/train_grad.py +39 -6
  40. qadence/ml_tools/train_no_grad.py +2 -2
  41. qadence/models/quantum_model.py +13 -6
  42. qadence/noise/readout.py +2 -3
  43. qadence/operations/__init__.py +0 -2
  44. qadence/operations/analog.py +2 -12
  45. qadence/operations/control_ops.py +3 -2
  46. qadence/operations/ham_evo.py +5 -7
  47. qadence/operations/parametric.py +3 -2
  48. qadence/operations/primitive.py +2 -2
  49. qadence/overlap.py +7 -12
  50. qadence/parameters.py +2 -2
  51. qadence/serialization.py +2 -2
  52. qadence/states.py +20 -5
  53. qadence/transpile/block.py +2 -2
  54. qadence/types.py +2 -2
  55. qadence/utils.py +42 -3
  56. {qadence-1.5.2.dist-info → qadence-1.6.1.dist-info}/METADATA +15 -9
  57. {qadence-1.5.2.dist-info → qadence-1.6.1.dist-info}/RECORD +59 -58
  58. {qadence-1.5.2.dist-info → qadence-1.6.1.dist-info}/WHEEL +0 -0
  59. {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
- """Compose a chain of single qubit operations on the same qubit into a single.
206
+ """
207
+ Merge operations that are adjacent and have identical qubit_support.
207
208
 
208
- call to _apply_batch_gate.
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 forward(self, state: Tensor, values: dict[str, Tensor] | None = None) -> Tensor:
214
- batch_size = infer_batchsize(values)
215
- return apply_operator(
216
- state, self.unitary(values, batch_size), self.qubits, self.n_qubits, batch_size
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
- def unitary(self, values: dict[str, Tensor] | None, batch_size: int) -> Tensor:
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
- # We reverse the list of tensors here since matmul is not commutative.
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 _batch_last(
243
- reduce(
244
- bmm,
245
- (_batch_first(_expand(op.unitary(values))) for op in reversed(self.operations)),
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 = torch.device("cpu"),
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, Z
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(0.5 * I(qubit) + (-0.5) * Z(qubit) for qubit in control)
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 = torch.device("cpu"),
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 = torch.device("cpu"),
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 = torch.device("cpu"),
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 = get_logger(__name__)
12
+ logger = getLogger(__name__)
13
13
 
14
14
 
15
15
  class MatrixBlock(PrimitiveBlock):
@@ -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 = get_logger(__name__)
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
- print(f"Unable to write QuantumCircuit to disk due to {e}")
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
- print(f"Unable to load QuantumCircuit due to {e}")
205
+ logger.error(f"Unable to load QuantumCircuit due to {e}")
203
206
 
204
207
  return QuantumCircuit._from_dict(loaded_dict)
@@ -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, build_qnn
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",
@@ -1,15 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import itertools
4
- import warnings
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 = get_logger(__name__)
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 = get_logger(__name__)
15
+ logger = getLogger(__name__)
15
16
 
16
17
 
17
18
  def _parse_generator(
@@ -1,10 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
- import torch
3
+ from logging import getLogger
4
4
 
5
- from qadence.logger import get_logger
5
+ import torch
6
6
 
7
- logger = get_logger(__name__)
7
+ logger = getLogger(__name__)
8
8
 
9
9
 
10
10
  def _k_d(a: int, b: int) -> int:
@@ -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 = get_logger(__name__)
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 = get_logger(__name__)
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 = get_logger(__file__)
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 = get_logger(__name__)
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