qadence 1.7.7__py3-none-any.whl → 1.8.0__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 (53) hide show
  1. qadence/analog/device.py +1 -1
  2. qadence/backend.py +3 -3
  3. qadence/backends/horqrux/backend.py +3 -3
  4. qadence/backends/pulser/backend.py +16 -17
  5. qadence/backends/pulser/convert_ops.py +2 -2
  6. qadence/backends/pyqtorch/backend.py +7 -7
  7. qadence/backends/pyqtorch/convert_ops.py +191 -240
  8. qadence/backends/utils.py +9 -1
  9. qadence/blocks/abstract.py +1 -1
  10. qadence/blocks/embedding.py +21 -11
  11. qadence/blocks/matrix.py +3 -1
  12. qadence/blocks/primitive.py +36 -11
  13. qadence/circuit.py +1 -1
  14. qadence/constructors/__init__.py +2 -1
  15. qadence/constructors/ansatze.py +176 -0
  16. qadence/engines/differentiable_backend.py +3 -3
  17. qadence/engines/jax/differentiable_backend.py +2 -2
  18. qadence/engines/jax/differentiable_expectation.py +2 -2
  19. qadence/engines/torch/differentiable_backend.py +2 -2
  20. qadence/engines/torch/differentiable_expectation.py +2 -2
  21. qadence/execution.py +14 -14
  22. qadence/extensions.py +1 -1
  23. qadence/measurements/shadow.py +4 -5
  24. qadence/measurements/tomography.py +2 -2
  25. qadence/measurements/utils.py +2 -2
  26. qadence/mitigations/analog_zne.py +8 -7
  27. qadence/mitigations/protocols.py +2 -2
  28. qadence/mitigations/readout.py +8 -5
  29. qadence/ml_tools/config.py +14 -0
  30. qadence/ml_tools/constructors.py +9 -4
  31. qadence/ml_tools/models.py +7 -7
  32. qadence/ml_tools/printing.py +2 -1
  33. qadence/ml_tools/train_grad.py +39 -7
  34. qadence/model.py +5 -5
  35. qadence/noise/__init__.py +2 -2
  36. qadence/noise/protocols.py +216 -29
  37. qadence/operations/control_ops.py +37 -22
  38. qadence/operations/ham_evo.py +1 -0
  39. qadence/operations/parametric.py +32 -10
  40. qadence/operations/primitive.py +61 -29
  41. qadence/overlap.py +0 -6
  42. qadence/parameters.py +3 -2
  43. qadence/transpile/__init__.py +2 -1
  44. qadence/transpile/noise.py +46 -0
  45. qadence/types.py +26 -2
  46. {qadence-1.7.7.dist-info → qadence-1.8.0.dist-info}/METADATA +5 -8
  47. {qadence-1.7.7.dist-info → qadence-1.8.0.dist-info}/RECORD +49 -52
  48. qadence/backends/braket/__init__.py +0 -4
  49. qadence/backends/braket/backend.py +0 -234
  50. qadence/backends/braket/config.py +0 -22
  51. qadence/backends/braket/convert_ops.py +0 -116
  52. {qadence-1.7.7.dist-info → qadence-1.8.0.dist-info}/WHEEL +0 -0
  53. {qadence-1.7.7.dist-info → qadence-1.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -11,6 +11,7 @@ from rich.panel import Panel
11
11
  from rich.tree import Tree
12
12
 
13
13
  from qadence.blocks.abstract import AbstractBlock
14
+ from qadence.noise import NoiseHandler
14
15
  from qadence.parameters import (
15
16
  Parameter,
16
17
  ParamMap,
@@ -33,13 +34,22 @@ class PrimitiveBlock(AbstractBlock):
33
34
 
34
35
  name = "PrimitiveBlock"
35
36
 
36
- def __init__(self, qubit_support: tuple[int, ...]):
37
+ def __init__(
38
+ self,
39
+ qubit_support: tuple[int, ...],
40
+ noise: NoiseHandler | None = None,
41
+ ):
37
42
  self._qubit_support = qubit_support
43
+ self._noise = noise
38
44
 
39
45
  @property
40
46
  def qubit_support(self) -> Tuple[int, ...]:
41
47
  return self._qubit_support
42
48
 
49
+ @property
50
+ def noise(self) -> NoiseHandler | None:
51
+ return self._noise
52
+
43
53
  def digital_decomposition(self) -> AbstractBlock:
44
54
  """Decomposition into purely digital gates.
45
55
 
@@ -85,11 +95,12 @@ class PrimitiveBlock(AbstractBlock):
85
95
  "type": type(self).__name__,
86
96
  "qubit_support": self.qubit_support,
87
97
  "tag": self.tag,
98
+ "noise": self.noise._to_dict() if self.noise is not None else None,
88
99
  }
89
100
 
90
101
  @classmethod
91
102
  def _from_dict(cls, d: dict) -> PrimitiveBlock:
92
- return cls(*d["qubit_support"])
103
+ return cls(*d["qubit_support"], NoiseHandler._from_dict(d.get("noise"))) # type: ignore[call-arg]
93
104
 
94
105
  def __hash__(self) -> int:
95
106
  return hash(self._to_json())
@@ -196,18 +207,19 @@ class ParametricBlock(PrimitiveBlock):
196
207
  "qubit_support": self.qubit_support,
197
208
  "tag": self.tag,
198
209
  "parameters": self.parameters._to_dict(),
210
+ "noise": self.noise._to_dict() if self.noise is not None else None,
199
211
  }
200
212
 
201
213
  @classmethod
202
214
  def _from_dict(cls, d: dict) -> ParametricBlock:
203
215
  params = ParamMap._from_dict(d["parameters"])
204
216
  target = d["qubit_support"][0]
205
- return cls(target, params) # type: ignore[call-arg]
217
+ return cls(target, params, NoiseHandler._from_dict(d.get("noise"))) # type: ignore[call-arg, arg-type]
206
218
 
207
219
  def dagger(self) -> ParametricBlock:
208
220
  exprs = self.parameters.expressions()
209
221
  params = tuple(-extract_original_param_entry(param) for param in exprs)
210
- return type(self)(*self.qubit_support, *params) # type: ignore[arg-type]
222
+ return type(self)(*self.qubit_support, *params, self.noise) # type: ignore[call-arg, arg-type]
211
223
 
212
224
 
213
225
  class ScaleBlock(ParametricBlock):
@@ -357,14 +369,19 @@ class ControlBlock(PrimitiveBlock):
357
369
  control: tuple[int, ...]
358
370
  target: tuple[int, ...]
359
371
 
360
- def __init__(self, control: tuple[int, ...], target_block: PrimitiveBlock) -> None:
372
+ def __init__(
373
+ self,
374
+ control: tuple[int, ...],
375
+ target_block: PrimitiveBlock,
376
+ noise: NoiseHandler | None = None,
377
+ ) -> None:
361
378
  self.control = control
362
379
  self.blocks = (target_block,)
363
380
  self.target = target_block.qubit_support
364
381
 
365
382
  # using tuple expansion because some control operations could
366
383
  # have multiple targets, e.g. CSWAP
367
- super().__init__((*control, *self.target)) # target_block.qubit_support[0]))
384
+ super().__init__((*control, *self.target), noise=noise) # target_block.qubit_support[0]))
368
385
 
369
386
  @property
370
387
  def n_controls(self) -> int:
@@ -395,13 +412,14 @@ class ControlBlock(PrimitiveBlock):
395
412
  "qubit_support": self.qubit_support,
396
413
  "tag": self.tag,
397
414
  "blocks": [b._to_dict() for b in self.blocks],
415
+ "noise": self.noise._to_dict() if self.noise is not None else None,
398
416
  }
399
417
 
400
418
  @classmethod
401
419
  def _from_dict(cls, d: dict) -> ControlBlock:
402
420
  control = d["qubit_support"][0]
403
421
  target = d["qubit_support"][1]
404
- return cls(control, target)
422
+ return cls(control, target, NoiseHandler._from_dict(d.get("noise")))
405
423
 
406
424
  def dagger(self) -> ControlBlock:
407
425
  blk = deepcopy(self)
@@ -416,11 +434,16 @@ class ParametricControlBlock(ParametricBlock):
416
434
  control: tuple[int, ...] = ()
417
435
  blocks: tuple[ParametricBlock, ...]
418
436
 
419
- def __init__(self, control: tuple[int, ...], target_block: ParametricBlock) -> None:
437
+ def __init__(
438
+ self,
439
+ control: tuple[int, ...],
440
+ target_block: ParametricBlock,
441
+ noise: NoiseHandler | None = None,
442
+ ) -> None:
420
443
  self.blocks = (target_block,)
421
444
  self.control = control
422
445
  self.parameters = target_block.parameters
423
- super().__init__((*control, *target_block.qubit_support))
446
+ super().__init__((*control, *target_block.qubit_support), noise=noise)
424
447
 
425
448
  @property
426
449
  def n_controls(self) -> int:
@@ -450,6 +473,7 @@ class ParametricControlBlock(ParametricBlock):
450
473
  "qubit_support": self.qubit_support,
451
474
  "tag": self.tag,
452
475
  "blocks": [b._to_dict() for b in self.blocks],
476
+ "noise": self.noise._to_dict() if self.noise is not None else None,
453
477
  }
454
478
 
455
479
  @classmethod
@@ -460,7 +484,7 @@ class ParametricControlBlock(ParametricBlock):
460
484
  target = d["qubit_support"][1]
461
485
  targetblock = d["blocks"][0]
462
486
  expr = deserialize(targetblock["parameters"])
463
- block = cls(control, target, expr) # type: ignore[call-arg]
487
+ block = cls(control, target, NoiseHandler._from_dict(d.get("noise")), expr) # type: ignore[call-arg]
464
488
  return block
465
489
 
466
490
  @property
@@ -497,6 +521,7 @@ class ProjectorBlock(PrimitiveBlock):
497
521
  ket: str,
498
522
  bra: str,
499
523
  qubit_support: int | tuple[int, ...],
524
+ noise: NoiseHandler | None = None,
500
525
  ) -> None:
501
526
  """
502
527
  Arguments:
@@ -522,4 +547,4 @@ class ProjectorBlock(PrimitiveBlock):
522
547
 
523
548
  self.ket = ket
524
549
  self.bra = bra
525
- super().__init__(qubit_support)
550
+ super().__init__(qubit_support, noise=noise)
qadence/circuit.py CHANGED
@@ -194,7 +194,7 @@ class QuantumCircuit:
194
194
  def _from_json(cls, path: str | Path) -> QuantumCircuit:
195
195
  import json
196
196
 
197
- loaded_dict: dict = {}
197
+ loaded_dict: dict = dict()
198
198
  if isinstance(path, str):
199
199
  path = Path(path)
200
200
  try:
@@ -5,7 +5,7 @@ from .feature_maps import (
5
5
  exp_fourier_feature_map,
6
6
  )
7
7
 
8
- from .ansatze import hea
8
+ from .ansatze import hea, alt
9
9
 
10
10
  from .iia import identity_initialized_ansatz
11
11
 
@@ -29,6 +29,7 @@ __all__ = [
29
29
  "feature_map",
30
30
  "exp_fourier_feature_map",
31
31
  "hea",
32
+ "alt",
32
33
  "identity_initialized_ansatz",
33
34
  "hamiltonian_factory",
34
35
  "ising_hamiltonian",
@@ -320,3 +320,179 @@ def hea_bDAQC(*args: Any, **kwargs: Any) -> Any:
320
320
 
321
321
  def hea_analog(*args: Any, **kwargs: Any) -> Any:
322
322
  raise NotImplementedError
323
+
324
+
325
+ def alt(
326
+ n_qubits: int,
327
+ m_block_qubits: int,
328
+ depth: int = 1,
329
+ param_prefix: str = "theta",
330
+ support: tuple[int, ...] = None,
331
+ strategy: Strategy = Strategy.DIGITAL,
332
+ **strategy_args: Any,
333
+ ) -> AbstractBlock:
334
+ """
335
+ Factory function for the alternating layer ansatz (alt).
336
+
337
+ Args:
338
+ n_qubits: number of qubits in the block
339
+ m_block_qubits: number of qubits in the local entangling block
340
+ depth: number of layers of the alt
341
+ param_prefix: the base name of the variational parameters
342
+ support: qubit indexes where the alt is applied
343
+ strategy: Strategy.Digital or Strategy.DigitalAnalog
344
+ **strategy_args: see below
345
+
346
+ Keyword Arguments:
347
+ operations (list): list of operations to cycle through in the
348
+ digital single-qubit rotations of each layer. Valid for
349
+ Digital .
350
+ entangler (AbstractBlock):
351
+ - Digital: 2-qubit entangling operation. Supports CNOT, CZ,
352
+ CRX, CRY, CRZ, CPHASE. Controlled rotations will have variational
353
+ parameters on the rotation angles.
354
+ """
355
+
356
+ if support is None:
357
+ support = tuple(range(n_qubits))
358
+
359
+ alt_func_dict = {
360
+ Strategy.DIGITAL: alt_digital,
361
+ Strategy.SDAQC: alt_sDAQC,
362
+ Strategy.BDAQC: alt_bDAQC,
363
+ Strategy.ANALOG: alt_analog,
364
+ }
365
+
366
+ try:
367
+ alt_func = alt_func_dict[strategy]
368
+ except KeyError:
369
+ raise KeyError(f"Strategy {strategy} not recognized.")
370
+
371
+ hea_block: AbstractBlock = alt_func(
372
+ n_qubits=n_qubits,
373
+ m_block_qubits=m_block_qubits,
374
+ depth=depth,
375
+ param_prefix=param_prefix,
376
+ support=support,
377
+ **strategy_args,
378
+ ) # type: ignore
379
+
380
+ return hea_block
381
+
382
+
383
+ #################
384
+ ## DIGITAL ALT ##
385
+ #################
386
+
387
+
388
+ def _entanglers_block_digital(
389
+ n_qubits: int,
390
+ m_block_qubits: int,
391
+ depth: int,
392
+ param_prefix: str = "theta",
393
+ support: tuple[int, ...] = None,
394
+ entangler: Type[DigitalEntanglers] = CNOT,
395
+ ) -> list[AbstractBlock]:
396
+ if support is None:
397
+ support = tuple(range(n_qubits))
398
+ iterator = itertools.count()
399
+ ent_list: list[AbstractBlock] = []
400
+
401
+ for d in range(depth):
402
+ start_i = 0 if not d % 2 else -m_block_qubits // 2
403
+ ents = [
404
+ kron(
405
+ _entangler(
406
+ control=support[i + j],
407
+ target=support[i + j + 1],
408
+ param_str=param_prefix + f"_ent_{next(iterator)}",
409
+ op=entangler,
410
+ )
411
+ for j in range(start_j, m_block_qubits, 2)
412
+ for i in range(start_i, n_qubits, m_block_qubits)
413
+ if i + j + 1 < n_qubits and j + 1 < m_block_qubits and i + j >= 0
414
+ )
415
+ for start_j in [i for i in range(2) if m_block_qubits > 2 or i == 0]
416
+ ]
417
+
418
+ ent_list.append(chain(*ents))
419
+ return ent_list
420
+
421
+
422
+ def alt_digital(
423
+ n_qubits: int,
424
+ m_block_qubits: int,
425
+ depth: int = 1,
426
+ support: tuple[int, ...] = None,
427
+ param_prefix: str = "theta",
428
+ operations: list[type[AbstractBlock]] = [RX, RY],
429
+ entangler: Type[DigitalEntanglers] = CNOT,
430
+ ) -> AbstractBlock:
431
+ """
432
+ Construct the digital alternating layer ansatz (ALT).
433
+
434
+ Args:
435
+ n_qubits (int): number of qubits in the ansatz.
436
+ m_block_qubits (int): number of qubits in the local entangling block.
437
+ depth (int): number of layers of the ALT.
438
+ param_prefix (str): the base name of the variational parameters
439
+ operations (list): list of operations to cycle through in the
440
+ digital single-qubit rotations of each layer.
441
+ support (tuple): qubit indexes where the ALT is applied.
442
+ entangler (AbstractBlock): 2-qubit entangling operation.
443
+ Supports CNOT, CZ, CRX, CRY, CRZ. Controlld rotations
444
+ will have variational parameters on the rotation angles.
445
+ """
446
+
447
+ try:
448
+ if entangler not in [CNOT, CZ, CRX, CRY, CRZ, CPHASE]:
449
+ raise ValueError(
450
+ "Please provide a valid two-qubit entangler operation for digital ALT."
451
+ )
452
+ except TypeError:
453
+ raise ValueError("Please provide a valid two-qubit entangler operation for digital ALT.")
454
+
455
+ rot_list = _rotations_digital(
456
+ n_qubits=n_qubits,
457
+ depth=depth,
458
+ support=support,
459
+ param_prefix=param_prefix,
460
+ operations=operations,
461
+ )
462
+
463
+ ent_list = _entanglers_block_digital(
464
+ n_qubits,
465
+ m_block_qubits,
466
+ param_prefix=param_prefix + "_ent",
467
+ depth=depth,
468
+ support=support,
469
+ entangler=entangler,
470
+ )
471
+
472
+ layers = []
473
+ for d in range(depth):
474
+ layers.append(rot_list[d])
475
+ layers.append(ent_list[d])
476
+
477
+ return tag(chain(*layers), "ALT")
478
+
479
+
480
+ #################
481
+ ## sdaqc ALT ##
482
+ #################
483
+ def alt_sDAQC(*args: Any, **kwargs: Any) -> Any:
484
+ raise NotImplementedError
485
+
486
+
487
+ #################
488
+ ## bdaqc ALT ##
489
+ #################
490
+ def alt_bDAQC(*args: Any, **kwargs: Any) -> Any:
491
+ raise NotImplementedError
492
+
493
+
494
+ #################
495
+ ## analog ALT ##
496
+ #################
497
+ def alt_analog(*args: Any, **kwargs: Any) -> Any:
498
+ raise NotImplementedError
@@ -11,7 +11,7 @@ from qadence.blocks.utils import uuid_to_block
11
11
  from qadence.circuit import QuantumCircuit
12
12
  from qadence.measurements import Measurements
13
13
  from qadence.mitigations import Mitigations
14
- from qadence.noise import Noise
14
+ from qadence.noise import NoiseHandler
15
15
  from qadence.types import ArrayLike, DiffMode, Endianness, Engine, ParamDictType
16
16
 
17
17
 
@@ -40,7 +40,7 @@ class DifferentiableBackend(ABC):
40
40
  param_values: ParamDictType = {},
41
41
  n_shots: int = 100,
42
42
  state: ArrayLike | None = None,
43
- noise: Noise | None = None,
43
+ noise: NoiseHandler | None = None,
44
44
  mitigation: Mitigations | None = None,
45
45
  endianness: Endianness = Endianness.BIG,
46
46
  ) -> list[Counter]:
@@ -89,7 +89,7 @@ class DifferentiableBackend(ABC):
89
89
  param_values: ParamDictType = {},
90
90
  state: ArrayLike | None = None,
91
91
  measurement: Measurements | None = None,
92
- noise: Noise | None = None,
92
+ noise: NoiseHandler | None = None,
93
93
  mitigation: Mitigations | None = None,
94
94
  endianness: Endianness = Endianness.BIG,
95
95
  ) -> Any:
@@ -7,7 +7,7 @@ from qadence.engines.differentiable_backend import (
7
7
  from qadence.engines.jax.differentiable_expectation import DifferentiableExpectation
8
8
  from qadence.measurements import Measurements
9
9
  from qadence.mitigations import Mitigations
10
- from qadence.noise import Noise
10
+ from qadence.noise import NoiseHandler
11
11
  from qadence.types import ArrayLike, DiffMode, Endianness, Engine, ParamDictType
12
12
 
13
13
 
@@ -36,7 +36,7 @@ class DifferentiableBackend(DifferentiableBackendInterface):
36
36
  param_values: ParamDictType = {},
37
37
  state: ArrayLike | None = None,
38
38
  measurement: Measurements | None = None,
39
- noise: Noise | None = None,
39
+ noise: NoiseHandler | None = None,
40
40
  mitigation: Mitigations | None = None,
41
41
  endianness: Endianness = Endianness.BIG,
42
42
  ) -> ArrayLike:
@@ -14,7 +14,7 @@ from qadence.backends.jax_utils import (
14
14
  from qadence.blocks.utils import uuid_to_eigen
15
15
  from qadence.measurements import Measurements
16
16
  from qadence.mitigations import Mitigations
17
- from qadence.noise import Noise
17
+ from qadence.noise import NoiseHandler
18
18
  from qadence.types import Endianness, Engine, ParamDictType
19
19
 
20
20
 
@@ -34,7 +34,7 @@ class DifferentiableExpectation:
34
34
  param_values: ParamDictType
35
35
  state: Array | None = None
36
36
  measurement: Measurements | None = None
37
- noise: Noise | None = None
37
+ noise: NoiseHandler | None = None
38
38
  mitigation: Mitigations | None = None
39
39
  endianness: Endianness = Endianness.BIG
40
40
  engine: Engine = Engine.JAX
@@ -11,7 +11,7 @@ from qadence.engines.torch.differentiable_expectation import DifferentiableExpec
11
11
  from qadence.extensions import get_gpsr_fns
12
12
  from qadence.measurements import Measurements
13
13
  from qadence.mitigations import Mitigations
14
- from qadence.noise import Noise
14
+ from qadence.noise import NoiseHandler
15
15
  from qadence.types import ArrayLike, DiffMode, Endianness, Engine, ParamDictType
16
16
 
17
17
 
@@ -40,7 +40,7 @@ class DifferentiableBackend(DifferentiableBackendInterface):
40
40
  param_values: ParamDictType = {},
41
41
  state: ArrayLike | None = None,
42
42
  measurement: Measurements | None = None,
43
- noise: Noise | None = None,
43
+ noise: NoiseHandler | None = None,
44
44
  mitigation: Mitigations | None = None,
45
45
  endianness: Endianness = Endianness.BIG,
46
46
  ) -> ArrayLike:
@@ -19,7 +19,7 @@ from qadence.circuit import QuantumCircuit
19
19
  from qadence.measurements import Measurements
20
20
  from qadence.mitigations import Mitigations
21
21
  from qadence.ml_tools import promote_to_tensor
22
- from qadence.noise import Noise
22
+ from qadence.noise import NoiseHandler
23
23
  from qadence.types import Endianness
24
24
 
25
25
 
@@ -95,7 +95,7 @@ class DifferentiableExpectation:
95
95
  param_values: dict[str, Tensor]
96
96
  state: Tensor | None = None
97
97
  measurement: Measurements | None = None
98
- noise: Noise | None = None
98
+ noise: NoiseHandler | None = None
99
99
  mitigation: Mitigations | None = None
100
100
  endianness: Endianness = Endianness.BIG
101
101
 
qadence/execution.py CHANGED
@@ -12,7 +12,7 @@ from qadence.blocks import AbstractBlock
12
12
  from qadence.circuit import QuantumCircuit
13
13
  from qadence.measurements import Measurements
14
14
  from qadence.mitigations import Mitigations
15
- from qadence.noise import Noise
15
+ from qadence.noise import NoiseHandler
16
16
  from qadence.qubit_support import QubitSupport
17
17
  from qadence.register import Register
18
18
  from qadence.types import BackendName, DiffMode, Endianness
@@ -35,7 +35,7 @@ def _n_qubits_block(block: AbstractBlock) -> int:
35
35
  def run(
36
36
  x: Union[QuantumCircuit, AbstractBlock, Register, int],
37
37
  *args: Any,
38
- values: dict = {},
38
+ values: Union[dict, None] = None,
39
39
  state: Tensor = None,
40
40
  backend: BackendName = BackendName.PYQTORCH,
41
41
  endianness: Endianness = Endianness.BIG,
@@ -65,7 +65,7 @@ def run(
65
65
  @run.register
66
66
  def _(
67
67
  circuit: QuantumCircuit,
68
- values: dict = {},
68
+ values: Union[dict, None] = None,
69
69
  state: Tensor = None,
70
70
  backend: BackendName = BackendName.PYQTORCH,
71
71
  endianness: Endianness = Endianness.BIG,
@@ -79,7 +79,7 @@ def _(
79
79
  with no_grad():
80
80
  return bknd.run(
81
81
  circuit=conv.circuit,
82
- param_values=conv.embedding_fn(conv.params, values),
82
+ param_values=conv.embedding_fn(conv.params, values or dict()),
83
83
  state=state,
84
84
  endianness=endianness,
85
85
  )
@@ -113,12 +113,12 @@ def _(circs: list, **kwargs: Any) -> Tensor: # type: ignore[misc]
113
113
  def sample(
114
114
  x: Union[QuantumCircuit, AbstractBlock, Register, int],
115
115
  *args: Any,
116
- values: dict = {},
116
+ values: Union[dict, None] = None,
117
117
  state: Union[Tensor, None] = None,
118
118
  n_shots: int = 100,
119
119
  backend: BackendName = BackendName.PYQTORCH,
120
120
  endianness: Endianness = Endianness.BIG,
121
- noise: Union[Noise, None] = None,
121
+ noise: Union[NoiseHandler, None] = None,
122
122
  configuration: Union[BackendConfiguration, dict, None] = None,
123
123
  ) -> list[Counter]:
124
124
  """Convenience wrapper for the `QuantumModel.sample` method.
@@ -142,11 +142,11 @@ def sample(
142
142
  @sample.register
143
143
  def _(
144
144
  circuit: QuantumCircuit,
145
- values: dict = {},
145
+ values: Union[dict, None] = None,
146
146
  state: Union[Tensor, None] = None,
147
147
  n_shots: int = 100,
148
148
  backend: BackendName = BackendName.PYQTORCH,
149
- noise: Union[Noise, None] = None,
149
+ noise: Union[NoiseHandler, None] = None,
150
150
  endianness: Endianness = Endianness.BIG,
151
151
  configuration: Union[BackendConfiguration, dict, None] = None,
152
152
  ) -> list[Counter]:
@@ -157,7 +157,7 @@ def _(
157
157
  conv = bknd.convert(circuit)
158
158
  return bknd.sample(
159
159
  circuit=conv.circuit,
160
- param_values=conv.embedding_fn(conv.params, values),
160
+ param_values=conv.embedding_fn(conv.params, values or dict()),
161
161
  n_shots=n_shots,
162
162
  state=state,
163
163
  noise=noise,
@@ -185,11 +185,11 @@ def _(block: AbstractBlock, **kwargs: Any) -> Tensor:
185
185
  def expectation(
186
186
  x: Union[QuantumCircuit, AbstractBlock, Register, int],
187
187
  observable: Union[list[AbstractBlock], AbstractBlock],
188
- values: dict = {},
188
+ values: Union[dict, None] = None,
189
189
  state: Tensor = None,
190
190
  backend: BackendName = BackendName.PYQTORCH,
191
191
  diff_mode: Union[DiffMode, str, None] = None,
192
- noise: Union[Noise, None] = None,
192
+ noise: Union[NoiseHandler, None] = None,
193
193
  endianness: Endianness = Endianness.BIG,
194
194
  configuration: Union[BackendConfiguration, dict, None] = None,
195
195
  ) -> Tensor:
@@ -237,12 +237,12 @@ def expectation(
237
237
  def _(
238
238
  circuit: QuantumCircuit,
239
239
  observable: Union[list[AbstractBlock], AbstractBlock],
240
- values: dict = {},
240
+ values: Union[dict, None] = None,
241
241
  state: Tensor = None,
242
242
  backend: BackendName = BackendName.PYQTORCH,
243
243
  diff_mode: Union[DiffMode, str, None] = None,
244
244
  measurement: Measurements = None,
245
- noise: Union[Noise, None] = None,
245
+ noise: Union[NoiseHandler, None] = None,
246
246
  mitigation: Mitigations = None,
247
247
  endianness: Endianness = Endianness.BIG,
248
248
  configuration: Union[BackendConfiguration, dict, None] = None,
@@ -257,7 +257,7 @@ def _(
257
257
  return bknd.expectation(
258
258
  circuit=conv.circuit,
259
259
  observable=conv.observable, # type: ignore[arg-type]
260
- param_values=conv.embedding_fn(conv.params, values),
260
+ param_values=conv.embedding_fn(conv.params, values or dict()),
261
261
  state=state,
262
262
  measurement=measurement,
263
263
  noise=noise,
qadence/extensions.py CHANGED
@@ -138,7 +138,7 @@ def _set_backend_config(backend: Backend, diff_mode: DiffMode) -> None:
138
138
 
139
139
  _validate_diff_mode(backend, diff_mode)
140
140
 
141
- # (1) When using PSR with any backend or (2) we use the backends Pulser or Braket,
141
+ # (1) When using PSR with any backend or (2) we use the backends Pulser,
142
142
  # we have to use gate-level parameters
143
143
 
144
144
  # We can use expression-level parameters for AD.
@@ -16,7 +16,7 @@ from qadence.blocks.primitive import PrimitiveBlock
16
16
  from qadence.blocks.utils import get_pauli_blocks, unroll_block_with_scaling
17
17
  from qadence.circuit import QuantumCircuit
18
18
  from qadence.engines.differentiable_backend import DifferentiableBackend
19
- from qadence.noise import Noise
19
+ from qadence.noise import NoiseHandler
20
20
  from qadence.operations import X, Y, Z
21
21
  from qadence.types import Endianness
22
22
  from qadence.utils import P0_MATRIX, P1_MATRIX
@@ -117,8 +117,7 @@ def classical_shadow(
117
117
  param_values: dict,
118
118
  state: Tensor | None = None,
119
119
  backend: Backend | DifferentiableBackend = PyQBackend(),
120
- # FIXME: Changed below from Little to Big, double-check when Roland is back
121
- noise: Noise | None = None,
120
+ noise: NoiseHandler | None = None,
122
121
  endianness: Endianness = Endianness.BIG,
123
122
  ) -> list:
124
123
  shadow: list = []
@@ -249,7 +248,7 @@ def estimations(
249
248
  confidence: float = 0.1,
250
249
  state: Tensor | None = None,
251
250
  backend: Backend | DifferentiableBackend = PyQBackend(),
252
- noise: Noise | None = None,
251
+ noise: NoiseHandler | None = None,
253
252
  endianness: Endianness = Endianness.BIG,
254
253
  ) -> Tensor:
255
254
  """Compute expectation values for all local observables using median of means."""
@@ -302,7 +301,7 @@ def compute_expectation(
302
301
  options: dict,
303
302
  state: Tensor | None = None,
304
303
  backend: Backend | DifferentiableBackend = PyQBackend(),
305
- noise: Noise | None = None,
304
+ noise: NoiseHandler | None = None,
306
305
  endianness: Endianness = Endianness.BIG,
307
306
  ) -> Tensor:
308
307
  """
@@ -10,7 +10,7 @@ from qadence.blocks.utils import unroll_block_with_scaling
10
10
  from qadence.circuit import QuantumCircuit
11
11
  from qadence.engines.differentiable_backend import DifferentiableBackend
12
12
  from qadence.measurements.utils import iterate_pauli_decomposition
13
- from qadence.noise import Noise
13
+ from qadence.noise import NoiseHandler
14
14
  from qadence.utils import Endianness
15
15
 
16
16
 
@@ -21,7 +21,7 @@ def compute_expectation(
21
21
  options: dict,
22
22
  state: Tensor | None = None,
23
23
  backend: Backend | DifferentiableBackend = PyQBackend(),
24
- noise: Noise | None = None,
24
+ noise: NoiseHandler | None = None,
25
25
  endianness: Endianness = Endianness.BIG,
26
26
  ) -> Tensor:
27
27
  """Basic tomography protocol with rotations.
@@ -14,7 +14,7 @@ from qadence.backends.pyqtorch import Backend as PyQBackend
14
14
  from qadence.blocks import AbstractBlock, PrimitiveBlock, chain
15
15
  from qadence.circuit import QuantumCircuit
16
16
  from qadence.engines.differentiable_backend import DifferentiableBackend
17
- from qadence.noise import Noise
17
+ from qadence.noise import NoiseHandler
18
18
  from qadence.operations import H, SDagger, X, Y, Z
19
19
  from qadence.parameters import evaluate
20
20
  from qadence.utils import Endianness
@@ -128,7 +128,7 @@ def iterate_pauli_decomposition(
128
128
  n_shots: int,
129
129
  state: Tensor | None = None,
130
130
  backend: Backend | DifferentiableBackend = PyQBackend(),
131
- noise: Noise | None = None,
131
+ noise: NoiseHandler | None = None,
132
132
  endianness: Endianness = Endianness.BIG,
133
133
  ) -> Tensor:
134
134
  """Estimate total expectation value by averaging all Pauli terms.