qadence 1.4.0__py3-none-any.whl → 1.5.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.
qadence/__init__.py CHANGED
@@ -32,6 +32,7 @@ DEFAULT_FLOAT_DTYPE = torchfloat64
32
32
  DEFAULT_COMPLEX_DTYPE = cdouble
33
33
  set_default_dtype(DEFAULT_FLOAT_DTYPE)
34
34
 
35
+
35
36
  """Fetch the functions defined in the __all__ of each sub-module.
36
37
 
37
38
  Import to the qadence name space. Make sure each added submodule has the respective definition:
@@ -71,7 +71,7 @@ def make_sequence(circ: QuantumCircuit, config: Configuration) -> Sequence:
71
71
  )
72
72
 
73
73
  ########
74
- # FIXME: Remove the block below in V1.1.0
74
+ # FIXME: Remove the block below in V1.5.0
75
75
  if config.spacing is not None:
76
76
  logger.warning(
77
77
  "Passing register spacing in the backend configuration is deprecated. "
@@ -30,6 +30,7 @@ class Configuration(BackendConfiguration):
30
30
 
31
31
  FIXME: This is deprecated, the device_type is now controlled in the
32
32
  Qadence Device, as detailed in the documentation.
33
+ FIXME: Remove in v1.5.0
33
34
  """
34
35
 
35
36
  sampling_rate: float = 1.0
@@ -44,6 +45,7 @@ class Configuration(BackendConfiguration):
44
45
 
45
46
  FIXME: This is deprecated, spacing is now controlled in the Register,
46
47
  as detailed in the register tutorial.
48
+ FIXME: Remove in v1.5.0
47
49
  """
48
50
 
49
51
  method_solv: str = "adams"
@@ -89,6 +91,7 @@ class Configuration(BackendConfiguration):
89
91
 
90
92
  FIXME: This is deprecated, the interaction is now controlled in the
91
93
  Qadence Device, as detailed in the documentation.
94
+ FIXME: Remove in v1.5.0
92
95
  """
93
96
 
94
97
  # configuration for cloud simulations
@@ -151,7 +151,9 @@ class Backend(BackendInterface):
151
151
  if state is None:
152
152
  from qadence.states import zero_state
153
153
 
154
- state = zero_state(circuit.abstract.n_qubits, batch_size=1)
154
+ state = zero_state(circuit.abstract.n_qubits, batch_size=1).to(
155
+ dtype=circuit.native.dtype
156
+ )
155
157
  if state.size(0) != 1:
156
158
  raise ValueError(
157
159
  "Looping expectation does not make sense with batched initial state. "
@@ -222,28 +224,29 @@ class Backend(BackendInterface):
222
224
  }
223
225
  )
224
226
 
225
- wf = self.run(circuit=circuit, param_values=param_values, state=state)
226
- probs = torch.abs(torch.pow(wf, 2))
227
- samples = list(
228
- map(
229
- lambda _probs: _sample(
230
- _probs=_probs,
231
- n_shots=n_shots,
232
- endianness=endianness,
233
- n_qubits=circuit.abstract.n_qubits,
234
- ),
235
- probs,
236
- )
237
- )
238
- if noise is not None:
239
- samples = apply_noise(noise=noise, samples=samples)
240
- if mitigation is not None:
241
- logger.warning(
242
- "Mitigation protocol is deprecated. Use qadence-protocols instead.",
227
+ with torch.no_grad():
228
+ wf = self.run(circuit=circuit, param_values=param_values, state=state)
229
+ probs = torch.abs(torch.pow(wf, 2))
230
+ samples = list(
231
+ map(
232
+ lambda _probs: _sample(
233
+ _probs=_probs,
234
+ n_shots=n_shots,
235
+ endianness=endianness,
236
+ n_qubits=circuit.abstract.n_qubits,
237
+ ),
238
+ probs,
239
+ )
243
240
  )
244
- assert noise
245
- samples = apply_mitigation(noise=noise, mitigation=mitigation, samples=samples)
246
- return samples
241
+ if noise is not None:
242
+ samples = apply_noise(noise=noise, samples=samples)
243
+ if mitigation is not None:
244
+ logger.warning(
245
+ "Mitigation protocol is deprecated. Use qadence-protocols instead.",
246
+ )
247
+ assert noise
248
+ samples = apply_mitigation(noise=noise, mitigation=mitigation, samples=samples)
249
+ return samples
247
250
 
248
251
  def assign_parameters(self, circuit: ConvertedCircuit, param_values: dict[str, Tensor]) -> Any:
249
252
  raise NotImplementedError
@@ -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 Sequence, Tuple
7
+ from typing import Any, Sequence, Tuple
8
8
 
9
9
  import pyqtorch as pyq
10
10
  import sympy
@@ -26,6 +26,7 @@ from torch import (
26
26
  transpose,
27
27
  )
28
28
  from torch import device as torch_device
29
+ from torch import dtype as torch_dtype
29
30
  from torch.nn import Module
30
31
 
31
32
  from qadence.backends.utils import (
@@ -178,6 +179,7 @@ class PyQMatrixBlock(Module):
178
179
  self.register_buffer("mat", block.matrix.unsqueeze(2))
179
180
  self.mat: Tensor
180
181
  self._device: torch_device = self.mat.device
182
+ self._dtype: torch_dtype = self.mat.dtype
181
183
 
182
184
  def forward(self, state: Tensor, _: dict[str, Tensor] = None) -> Tensor:
183
185
  return apply_operator(state, self.mat, self.qubits, self.n_qubits)
@@ -186,9 +188,10 @@ class PyQMatrixBlock(Module):
186
188
  def device(self) -> torch_device:
187
189
  return self._device
188
190
 
189
- def to(self, device: torch_device) -> PyQMatrixBlock:
190
- self.mat = self.mat.to(device)
191
- self._device = device
191
+ def to(self, *args: Any, **kwargs: Any) -> PyQMatrixBlock:
192
+ self.mat = self.mat.to(*args, **kwargs)
193
+ self._device = self.mat.device
194
+ self._dtype = self.mat.dtype
192
195
  return self
193
196
 
194
197
 
@@ -262,6 +265,7 @@ class PyQObservable(Module):
262
265
  )
263
266
  self._forward = lambda self, state, values: self.operation(state, values)
264
267
  self._device = self.operation.device
268
+ self._dtype = self.operation.dtype
265
269
 
266
270
  def run(self, state: Tensor, values: dict[str, Tensor]) -> Tensor:
267
271
  return self._forward(self, state, values)
@@ -273,9 +277,14 @@ class PyQObservable(Module):
273
277
  def device(self) -> torch_device:
274
278
  return self._device
275
279
 
276
- def to(self, device: torch_device) -> PyQObservable:
277
- self.operation = self.operation.to(device)
278
- self._device = device
280
+ @property
281
+ def dtype(self) -> torch_dtype:
282
+ return self._dtype
283
+
284
+ def to(self, *args: Any, **kwargs: Any) -> PyQObservable:
285
+ self.operation = self.operation.to(*args, **kwargs)
286
+ self._device = self.operation.device
287
+ self._dtype = self.operation.dtype
279
288
  return self
280
289
 
281
290
 
@@ -338,6 +347,7 @@ class PyQHamiltonianEvolution(Module):
338
347
  self._device: torch_device = (
339
348
  self.hmat.device if hasattr(self, "hmat") else torch_device("cpu")
340
349
  )
350
+ self._dtype: torch_dtype = self.hmat.dtype if hasattr(self, "hmat") else cdouble
341
351
 
342
352
  def _unitary(self, hamiltonian: Tensor, time_evolution: Tensor) -> Tensor:
343
353
  self.batch_size = max(hamiltonian.size()[2], len(time_evolution))
@@ -419,10 +429,15 @@ class PyQHamiltonianEvolution(Module):
419
429
  def device(self) -> torch_device:
420
430
  return self._device
421
431
 
422
- def to(self, device: torch_device) -> PyQHamiltonianEvolution:
432
+ @property
433
+ def dtype(self) -> torch_dtype:
434
+ return self._dtype
435
+
436
+ def to(self, *args: Any, **kwargs: Any) -> PyQHamiltonianEvolution:
423
437
  if hasattr(self, "hmat"):
424
- self.hmat = self.hmat.to(device)
425
- self._device = device
438
+ self.hmat = self.hmat.to(*args, **kwargs)
439
+ self._device = self.hmat.device
440
+ self._dtype = self.hmat.dtype
426
441
  return self
427
442
 
428
443
 
qadence/backends/utils.py CHANGED
@@ -13,6 +13,7 @@ from pyqtorch.parametric import Parametric as PyQParametric
13
13
  from torch import (
14
14
  Tensor,
15
15
  cat,
16
+ complex64,
16
17
  complex128,
17
18
  mean,
18
19
  no_grad,
@@ -129,8 +130,8 @@ def is_pyq_shape(state: Tensor, n_qubits: int) -> bool:
129
130
 
130
131
  def validate_state(state: Tensor, n_qubits: int) -> None:
131
132
  """Check if a custom initial state conforms to the qadence or the pyqtorch format."""
132
- if state.dtype != complex128:
133
- raise TypeError(f"Expected type complex128, got {state.dtype}")
133
+ if state.dtype not in [complex128, complex64]:
134
+ raise TypeError(f"Expected complex dtype, got {state.dtype}")
134
135
  elif len(state.size()) < 2:
135
136
  raise ValueError(f"Invalid state shape. Got {state.shape}")
136
137
  elif not is_qadence_shape(state, n_qubits) and not is_pyq_shape(state, n_qubits):
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import itertools
4
+ import warnings
4
5
  from typing import Any, Optional, Type, Union
5
6
 
6
7
  from qadence.blocks import AbstractBlock, block_is_qubit_hamiltonian, chain, kron, tag
@@ -328,6 +329,7 @@ def hea_analog(*args: Any, **kwargs: Any) -> Any:
328
329
  #########
329
330
 
330
331
 
332
+ # FIXME: Remove in v1.5.0
331
333
  def build_qnn(
332
334
  n_qubits: int,
333
335
  n_features: int,
@@ -360,6 +362,9 @@ def build_qnn(
360
362
  Returns:
361
363
  A list of Abstract blocks to be used for constructing a quantum circuit
362
364
  """
365
+
366
+ warnings.warn("Function build_qnn is deprecated and will be removed in v1.5.0.", FutureWarning)
367
+
363
368
  depth = n_qubits if depth is None else depth
364
369
 
365
370
  idx_fms = build_idx_fms(basis, fm_pauli, fm_strategy, n_features, n_qubits, spectrum)
@@ -35,6 +35,7 @@ RS_FUNC_DICT = {
35
35
  }
36
36
 
37
37
 
38
+ # FIXME: Remove in v1.5.0
38
39
  def backwards_compatibility(
39
40
  fm_type: BasisSet | Callable | str,
40
41
  reupload_scaling: ReuploadScaling | Callable | str,
@@ -224,6 +225,7 @@ def feature_map(
224
225
  return fm
225
226
 
226
227
 
228
+ # FIXME: Remove in v1.5.0
227
229
  def fourier_feature_map(
228
230
  n_qubits: int, support: tuple[int, ...] = None, param: str = "phi", op: RotationTypes = RX
229
231
  ) -> AbstractBlock:
@@ -241,6 +243,7 @@ def fourier_feature_map(
241
243
  return fm
242
244
 
243
245
 
246
+ # FIXME: Remove in v1.5.0
244
247
  def chebyshev_feature_map(
245
248
  n_qubits: int, support: tuple[int, ...] = None, param: str = "phi", op: RotationTypes = RX
246
249
  ) -> AbstractBlock:
@@ -259,6 +262,7 @@ def chebyshev_feature_map(
259
262
  return fm
260
263
 
261
264
 
265
+ # FIXME: Remove in v1.5.0
262
266
  def tower_feature_map(
263
267
  n_qubits: int, support: tuple[int, ...] = None, param: str = "phi", op: RotationTypes = RX
264
268
  ) -> AbstractBlock:
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections import Counter, OrderedDict
3
+ from collections import OrderedDict
4
4
  from dataclasses import dataclass
5
5
  from functools import partial
6
6
  from typing import Any, Callable, Sequence
@@ -8,22 +8,19 @@ from typing import Any, Callable, Sequence
8
8
  import torch
9
9
  from torch import Tensor
10
10
  from torch.autograd import Function
11
- from torch.nn import Module
12
11
 
13
12
  from qadence.backend import Backend as QuantumBackend
14
- from qadence.backend import Converted, ConvertedCircuit, ConvertedObservable
13
+ from qadence.backend import ConvertedCircuit, ConvertedObservable
15
14
  from qadence.backends.adjoint import AdjointExpectation
16
15
  from qadence.backends.utils import infer_batchsize, is_pyq_shape, param_dict, pyqify, validate_state
17
16
  from qadence.blocks.abstract import AbstractBlock
18
- from qadence.blocks.primitive import PrimitiveBlock
19
- from qadence.blocks.utils import uuid_to_block, uuid_to_eigen
17
+ from qadence.blocks.utils import uuid_to_eigen
20
18
  from qadence.circuit import QuantumCircuit
21
- from qadence.extensions import get_gpsr_fns
22
19
  from qadence.measurements import Measurements
23
20
  from qadence.mitigations import Mitigations
24
21
  from qadence.ml_tools import promote_to_tensor
25
22
  from qadence.noise import Noise
26
- from qadence.types import DiffMode, Endianness
23
+ from qadence.types import Endianness
27
24
 
28
25
 
29
26
  class PSRExpectation(Function):
@@ -232,160 +229,3 @@ class DifferentiableExpectation:
232
229
  # Since they are constants their gradients are 0.
233
230
  param_to_psr[param_id] = lambda x: torch.tensor([0.0], requires_grad=False)
234
231
  return param_to_psr
235
-
236
-
237
- class DifferentiableBackend(Module):
238
- """A class to abstract the operations done by the autodiff engine.
239
-
240
- Arguments:
241
- backend: An instance of the QuantumBackend type perform execution.
242
- diff_mode: A differentiable mode supported by the differentiation engine.
243
- **psr_args: Arguments that will be passed on to `DifferentiableExpectation`.
244
- """
245
-
246
- def __init__(
247
- self,
248
- backend: QuantumBackend,
249
- diff_mode: DiffMode = DiffMode.AD,
250
- **psr_args: int | float | None,
251
- ) -> None:
252
- super().__init__()
253
-
254
- self.backend = backend
255
- self.diff_mode = diff_mode
256
- self.psr_args = psr_args
257
- # TODO: Add differentiable overlap calculation
258
- self._overlap: Callable = None # type: ignore [assignment]
259
-
260
- def run(
261
- self,
262
- circuit: ConvertedCircuit,
263
- param_values: dict = {},
264
- state: Tensor | None = None,
265
- endianness: Endianness = Endianness.BIG,
266
- ) -> Tensor:
267
- """Run on the underlying backend."""
268
- return self.backend.run(
269
- circuit=circuit, param_values=param_values, state=state, endianness=endianness
270
- )
271
-
272
- def expectation(
273
- self,
274
- circuit: ConvertedCircuit,
275
- observable: list[ConvertedObservable] | ConvertedObservable,
276
- param_values: dict[str, Tensor] = {},
277
- state: Tensor | None = None,
278
- measurement: Measurements | None = None,
279
- noise: Noise | None = None,
280
- mitigation: Mitigations | None = None,
281
- endianness: Endianness = Endianness.BIG,
282
- ) -> Tensor:
283
- """Compute the expectation value of a given observable.
284
-
285
- Arguments:
286
- circuit: A backend native quantum circuit to be executed.
287
- observable: A backend native observable to compute the expectation value from.
288
- param_values: A dict of values for symbolic substitution.
289
- state: An initial state.
290
- measurement: A shot-based measurement protocol.
291
- endianness: Endianness of the state.
292
-
293
- Returns:
294
- A tensor of expectation values.
295
- """
296
- observable = observable if isinstance(observable, list) else [observable]
297
- differentiable_expectation = DifferentiableExpectation(
298
- backend=self.backend,
299
- circuit=circuit,
300
- observable=observable,
301
- param_values=param_values,
302
- state=state,
303
- measurement=measurement,
304
- noise=noise,
305
- mitigation=mitigation,
306
- endianness=endianness,
307
- )
308
-
309
- if self.diff_mode == DiffMode.AD:
310
- expectation = differentiable_expectation.ad
311
- elif self.diff_mode == DiffMode.ADJOINT:
312
- expectation = differentiable_expectation.adjoint
313
- else:
314
- try:
315
- fns = get_gpsr_fns()
316
- psr_fn = fns[self.diff_mode]
317
- except KeyError:
318
- raise ValueError(f"{self.diff_mode} differentiation mode is not supported")
319
- expectation = partial(differentiable_expectation.psr, psr_fn=psr_fn, **self.psr_args)
320
- return expectation()
321
-
322
- def sample(
323
- self,
324
- circuit: ConvertedCircuit,
325
- param_values: dict[str, Tensor],
326
- n_shots: int = 1,
327
- state: Tensor | None = None,
328
- noise: Noise | None = None,
329
- mitigation: Mitigations | None = None,
330
- endianness: Endianness = Endianness.BIG,
331
- ) -> list[Counter]:
332
- """Sample bitstring from the registered circuit.
333
-
334
- Arguments:
335
- circuit: A backend native quantum circuit to be executed.
336
- param_values: The values of the parameters after embedding
337
- n_shots: The number of shots. Defaults to 1.
338
- state: Initial state.
339
- noise: A noise model to use.
340
- mitigation: A mitigation protocol to apply to noisy samples.
341
- endianness: Endianness of the resulting bitstrings.
342
-
343
- Returns:
344
- An iterable with all the sampled bitstrings
345
- """
346
- with torch.no_grad():
347
- return self.backend.sample(
348
- circuit=circuit,
349
- param_values=param_values,
350
- n_shots=n_shots,
351
- state=state,
352
- noise=noise,
353
- mitigation=mitigation,
354
- endianness=endianness,
355
- )
356
-
357
- def circuit(self, circuit: QuantumCircuit) -> ConvertedCircuit:
358
- parametrized_blocks = list(uuid_to_block(circuit.block).values())
359
- non_prim_blocks = filter(lambda b: not isinstance(b, PrimitiveBlock), parametrized_blocks)
360
- if len(list(non_prim_blocks)) > 0:
361
- raise ValueError(
362
- "The circuit contains non-primitive blocks that are currently not supported by the "
363
- "PSR differentiable mode."
364
- )
365
- return self.backend.circuit(circuit)
366
-
367
- def observable(self, observable: AbstractBlock, n_qubits: int) -> ConvertedObservable:
368
- if observable is not None and observable.is_parametric:
369
- raise ValueError("PSR cannot be applied to a parametric observable.")
370
- return self.backend.observable(observable, n_qubits)
371
-
372
- def convert(
373
- self,
374
- circuit: QuantumCircuit,
375
- observable: list[AbstractBlock] | AbstractBlock | None = None,
376
- ) -> Converted:
377
- if self.diff_mode != DiffMode.AD and observable is not None:
378
- msg = (
379
- f"Differentiation mode '{self.diff_mode}' does not support parametric observables."
380
- )
381
- if isinstance(observable, list):
382
- for obs in observable:
383
- if obs.is_parametric:
384
- raise ValueError(msg)
385
- else:
386
- if observable.is_parametric:
387
- raise ValueError(msg)
388
- return self.backend.convert(circuit, observable)
389
-
390
- def assign_parameters(self, circuit: ConvertedCircuit, param_values: dict[str, Tensor]) -> Any:
391
- return self.backend.assign_parameters(circuit, param_values)
qadence/extensions.py CHANGED
@@ -79,6 +79,7 @@ def _validate_diff_mode(backend: Backend, diff_mode: DiffMode) -> None:
79
79
 
80
80
  def _validate_backend_config(backend: Backend) -> None:
81
81
  if backend.config.use_gradient_checkpointing:
82
+ # FIXME: Remove in v1.5.0
82
83
  msg = "use_gradient_checkpointing is deprecated."
83
84
  import warnings
84
85
 
qadence/libs.py ADDED
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+
5
+ from qadence.logger import get_logger
6
+
7
+ logger = get_logger(__name__)
8
+
9
+ try:
10
+ module = importlib.import_module("qadence_libs.protocols")
11
+ available_libs = getattr(module, "available_libs")
12
+ except ModuleNotFoundError:
13
+ raise ModuleNotFoundError(
14
+ "The 'qadence_libs' module is not present." " Please install the 'qadence-libs' package."
15
+ )
@@ -5,16 +5,16 @@ from dataclasses import dataclass
5
5
  from typing import Callable, cast
6
6
 
7
7
  PROTOCOL_TO_MODULE = {
8
- "tomography": "qadence.measurements.tomography",
9
8
  "shadow": "qadence.measurements.shadow",
9
+ "tomography": "qadence.measurements.tomography",
10
10
  }
11
11
 
12
12
 
13
13
  # TODO: make this a StrEnum to keep consistency with the rest of the interface
14
14
  @dataclass
15
15
  class Measurements:
16
- TOMOGRAPHY = "tomography"
17
16
  SHADOW = "shadow"
17
+ TOMOGRAPHY = "tomography"
18
18
 
19
19
  def __init__(self, protocol: str, options: dict) -> None:
20
20
  self.protocol: str = protocol
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from collections import Counter
4
+ from typing import List
5
+
6
+ from torch import Tensor
7
+
8
+ from qadence.blocks import AbstractBlock
9
+ from qadence.blocks.utils import unroll_block_with_scaling
10
+ from qadence.measurements.utils import pauli_z_expectation
11
+
12
+
13
+ def compute_expectation(
14
+ observable: List[AbstractBlock],
15
+ samples: List[Counter],
16
+ ) -> List[Tensor]:
17
+ """Given a list of observables in Z basis, compute the expectation values against samples.
18
+
19
+ Args:
20
+ observables: A list of observables
21
+ to estimate the expectation values from.
22
+ samples: List of samples against which expectation value is to be computed
23
+ """
24
+
25
+ if not isinstance(observable, list):
26
+ raise TypeError(
27
+ f"Observables must be of type <class 'List[AbstractBlock]'>. Got {type(observable)}."
28
+ )
29
+
30
+ expectation_vals = []
31
+
32
+ for obs in observable:
33
+ decomposition = unroll_block_with_scaling(obs)
34
+ if not obs._is_diag_pauli or obs.is_identity:
35
+ raise TypeError("observable provided is not in the Z basis")
36
+ expectation_vals.append(pauli_z_expectation(decomposition, samples))
37
+
38
+ return expectation_vals
@@ -1,129 +1,19 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections import Counter
4
- from functools import reduce
5
-
6
- import numpy as np
7
3
  import torch
8
4
  from torch import Tensor
9
5
 
10
6
  from qadence.backend import Backend
11
7
  from qadence.backends.pyqtorch import Backend as PyQBackend
12
- from qadence.blocks import AbstractBlock, PrimitiveBlock, chain
8
+ from qadence.blocks import AbstractBlock
13
9
  from qadence.blocks.utils import unroll_block_with_scaling
14
10
  from qadence.circuit import QuantumCircuit
15
11
  from qadence.engines.differentiable_backend import DifferentiableBackend
12
+ from qadence.measurements.utils import iterate_pauli_decomposition
16
13
  from qadence.noise import Noise
17
- from qadence.operations import H, SDagger, X, Y, Z
18
- from qadence.parameters import evaluate
19
14
  from qadence.utils import Endianness
20
15
 
21
16
 
22
- def get_qubit_indices_for_op(pauli_term: tuple, op: PrimitiveBlock | None = None) -> list[int]:
23
- """Get qubit indices for the given op in the Pauli term if any."""
24
- indices = []
25
- blocks = getattr(pauli_term[0], "blocks", None)
26
- if blocks is not None:
27
- for block in blocks:
28
- if op is None:
29
- indices.append(block.qubit_support[0])
30
- if isinstance(block, type(op)):
31
- indices.append(block.qubit_support[0])
32
- else:
33
- block = pauli_term[0]
34
- if op is None:
35
- indices.append(block.qubit_support[0])
36
- if isinstance(block, type(op)):
37
- indices.append(block.qubit_support[0])
38
- return indices
39
-
40
-
41
- def rotate(circuit: QuantumCircuit, pauli_term: tuple) -> QuantumCircuit:
42
- """Rotate circuit to measurement basis and return the qubit support."""
43
- rotations = []
44
-
45
- # Mypy expects concrete types. Although there definitely should be
46
- # a better way to pass the operation type.
47
- for op, gate in [(X(0), Z), (Y(0), SDagger)]:
48
- qubit_indices = get_qubit_indices_for_op(pauli_term, op=op)
49
- for index in qubit_indices:
50
- rotations.append(gate(index) * H(index))
51
- rotated_block = chain(circuit.block, *rotations)
52
- return QuantumCircuit(circuit.register, rotated_block)
53
-
54
-
55
- def get_counts(samples: list, support: list) -> list:
56
- """Marginalise the probablity mass function to the support."""
57
- counts = []
58
- for sample in samples:
59
- sample_counts = []
60
- for k, v in sample.items():
61
- sample_counts.append(Counter({"".join([k[i] for i in support]): sample[k]}))
62
- reduced_counts = reduce(lambda x, y: x + y, sample_counts)
63
- counts.append(reduced_counts)
64
- return counts
65
-
66
-
67
- def empirical_average(samples: list, support: list) -> Tensor:
68
- """Compute the empirical average."""
69
- counters = get_counts(samples, support)
70
- expectations = []
71
- n_shots = np.sum(list(counters[0].values()))
72
- parity = -1
73
- for counter in counters:
74
- counter_exps = []
75
- for bitstring, count in counter.items():
76
- counter_exps.append(count * parity ** (np.sum([int(bit) for bit in bitstring])))
77
- expectations.append(np.sum(counter_exps) / n_shots)
78
- return torch.tensor(expectations)
79
-
80
-
81
- def iterate_pauli_decomposition(
82
- circuit: QuantumCircuit,
83
- param_values: dict,
84
- pauli_decomposition: list,
85
- n_shots: int,
86
- state: Tensor | None = None,
87
- backend: Backend | DifferentiableBackend = PyQBackend(),
88
- noise: Noise | None = None,
89
- endianness: Endianness = Endianness.BIG,
90
- ) -> Tensor:
91
- """Estimate total expectation value by averaging all Pauli terms."""
92
-
93
- estimated_values = []
94
-
95
- for pauli_term in pauli_decomposition:
96
- if pauli_term[0].is_identity:
97
- estimated_values.append(evaluate(pauli_term[1], as_torch=True))
98
- else:
99
- # Get the full qubit support for the Pauli term.
100
- # Note: duplicates must be kept here to allow for
101
- # observables chaining multiple operations on the same qubit
102
- # such as `b = chain(Z(0), Z(0))`
103
- support = get_qubit_indices_for_op(pauli_term)
104
- # Rotate the circuit according to the given observable term.
105
- rotated_circuit = rotate(circuit=circuit, pauli_term=pauli_term)
106
- # Use the low-level backend API to avoid embedding of parameters
107
- # already performed at the higher QuantumModel level.
108
- # Therefore, parameters passed here have already been embedded.
109
- conv_circ = backend.circuit(rotated_circuit)
110
- samples = backend.sample(
111
- circuit=conv_circ,
112
- param_values=param_values,
113
- n_shots=n_shots,
114
- state=state,
115
- noise=noise,
116
- endianness=endianness,
117
- )
118
- estim_values = empirical_average(samples=samples, support=support)
119
- # TODO: support for parametric observables to be tested
120
- estimated_values.append(estim_values * evaluate(pauli_term[1]))
121
- res = torch.sum(torch.stack(estimated_values), axis=0)
122
- # Allow for automatic differentiation.
123
- res.requires_grad = True
124
- return res
125
-
126
-
127
17
  def compute_expectation(
128
18
  circuit: QuantumCircuit,
129
19
  observables: list[AbstractBlock],
@@ -0,0 +1,180 @@
1
+ from __future__ import annotations
2
+
3
+ from collections import Counter
4
+ from functools import reduce
5
+ from typing import Dict, List, Tuple
6
+
7
+ import numpy as np
8
+ import torch
9
+ from sympy import Basic
10
+ from torch import Tensor
11
+
12
+ from qadence.backend import Backend
13
+ from qadence.backends.pyqtorch import Backend as PyQBackend
14
+ from qadence.blocks import AbstractBlock, PrimitiveBlock, chain
15
+ from qadence.circuit import QuantumCircuit
16
+ from qadence.engines.differentiable_backend import DifferentiableBackend
17
+ from qadence.noise import Noise
18
+ from qadence.operations import H, SDagger, X, Y, Z
19
+ from qadence.parameters import evaluate
20
+ from qadence.utils import Endianness
21
+
22
+
23
+ def get_qubit_indices_for_op(
24
+ pauli_term: Tuple[AbstractBlock, Basic], op: PrimitiveBlock | None = None
25
+ ) -> List[int]:
26
+ """Get qubit indices for the given op in the Pauli term if any.
27
+
28
+ Args:
29
+ pauli_term: Tuple of a Pauli block and a parameter.
30
+ op: Tuple of Primitive blocks or None.
31
+
32
+ Returns: A list of integers representing qubit indices.
33
+ """
34
+ blocks = getattr(pauli_term[0], "blocks", None)
35
+ blocks = blocks if blocks is not None else [pauli_term[0]]
36
+ indices = [
37
+ block.qubit_support[0] for block in blocks if (op is None) or (isinstance(block, type(op)))
38
+ ]
39
+ return indices
40
+
41
+
42
+ def get_counts(samples: List, support: List[int]) -> List[Counter]:
43
+ """Marginalise the probability mass function to the support.
44
+
45
+ Args:
46
+ samples: List of samples against which expectation value is to be computed.
47
+ support: A list of integers representing qubit indices.
48
+
49
+ Returns: A List[Counter] of bit strings.
50
+ """
51
+ return [
52
+ reduce(
53
+ lambda x, y: x + y,
54
+ [Counter({"".join([k[i] for i in support]): sample[k]}) for k, v in sample.items()],
55
+ )
56
+ for sample in samples
57
+ ]
58
+
59
+
60
+ def empirical_average(samples: List, support: List[int]) -> Tensor:
61
+ """Compute the empirical average.
62
+
63
+ Args:
64
+ samples: List of samples against which expectation value is to be computed.
65
+ support: A list of integers representing qubit indices.
66
+
67
+ Returns: A torch.Tensor of the empirical average.
68
+ """
69
+ PARITY = -1
70
+ counters = get_counts(samples, support)
71
+ n_shots = np.sum(list(counters[0].values()))
72
+ expectations = []
73
+ for counter in counters:
74
+ counter_exps = []
75
+ for bitstring, count in counter.items():
76
+ counter_exps.append(count * PARITY ** (np.sum([int(bit) for bit in bitstring])))
77
+ expectations.append(np.sum(counter_exps) / n_shots)
78
+ return torch.tensor(expectations)
79
+
80
+
81
+ def pauli_z_expectation(
82
+ pauli_decomposition: List[Tuple[AbstractBlock, Basic]],
83
+ samples: List[Counter],
84
+ ) -> Tensor:
85
+ """Estimate total expectation value from samples by averaging all Pauli terms.
86
+
87
+ Args:
88
+ pauli_decomposition: A list of Pauli decomposed terms.
89
+ samples: Samples of bit string as Counters.
90
+
91
+ Returns: A torch.Tensor of the total expectation.
92
+ """
93
+
94
+ estimated_values = []
95
+ for pauli_term in pauli_decomposition:
96
+ support = get_qubit_indices_for_op(pauli_term)
97
+ estim_values = empirical_average(samples=samples, support=support)
98
+ # TODO: support for parametric observables to be tested
99
+ estimated_values.append(estim_values * evaluate(pauli_term[1]))
100
+ res = torch.sum(torch.stack(estimated_values), axis=0)
101
+ return res
102
+
103
+
104
+ def rotate(circuit: QuantumCircuit, pauli_term: Tuple[AbstractBlock, Basic]) -> QuantumCircuit:
105
+ """Rotate circuit to measurement basis and return the qubit support.
106
+
107
+ Args:
108
+ circuit: The circuit that is executed.
109
+ pauli_term: Tuple of a Pauli term and a parameter.
110
+
111
+ Returns: Rotated QuantumCircuit.
112
+ """
113
+
114
+ rotations = []
115
+
116
+ for op, gate in [(X(0), Z), (Y(0), SDagger)]:
117
+ qubit_indices = get_qubit_indices_for_op(pauli_term, op=op)
118
+ for index in qubit_indices:
119
+ rotations.append(gate(index) * H(index))
120
+ rotated_block = chain(circuit.block, *rotations)
121
+ return QuantumCircuit(circuit.register, rotated_block)
122
+
123
+
124
+ def iterate_pauli_decomposition(
125
+ circuit: QuantumCircuit,
126
+ param_values: Dict[str, Tensor],
127
+ pauli_decomposition: List[Tuple[AbstractBlock, Basic]],
128
+ n_shots: int,
129
+ state: Tensor | None = None,
130
+ backend: Backend | DifferentiableBackend = PyQBackend(),
131
+ noise: Noise | None = None,
132
+ endianness: Endianness = Endianness.BIG,
133
+ ) -> Tensor:
134
+ """Estimate total expectation value by averaging all Pauli terms.
135
+
136
+ Args:
137
+ circuit: The circuit that is executed.
138
+ param_values: Parameters of the circuit.
139
+ pauli_decomposition: A list of Pauli decomposed terms.
140
+ n_shots: Number of shots to sample.
141
+ state: Initial state.
142
+ backend: A backend for circuit execution.
143
+ noise: A noise model to use.
144
+ endianness: Endianness of the resulting bit strings.
145
+
146
+ Returns: A torch.Tensor of bit strings n_shots x n_qubits.
147
+ """
148
+
149
+ estimated_values = []
150
+
151
+ for pauli_term in pauli_decomposition:
152
+ if pauli_term[0].is_identity:
153
+ estimated_values.append(evaluate(pauli_term[1], as_torch=True))
154
+ else:
155
+ # Get the full qubit support for the Pauli term.
156
+ # Note: duplicates must be kept here to allow for
157
+ # observables chaining multiple operations on the same qubit
158
+ # such as `b = chain(Z(0), Z(0))`
159
+ support = get_qubit_indices_for_op(pauli_term)
160
+ # Rotate the circuit according to the given observable term.
161
+ rotated_circuit = rotate(circuit=circuit, pauli_term=pauli_term)
162
+ # Use the low-level backend API to avoid embedding of parameters
163
+ # already performed at the higher QuantumModel level.
164
+ # Therefore, parameters passed here have already been embedded.
165
+ conv_circ = backend.circuit(rotated_circuit)
166
+ samples = backend.sample(
167
+ circuit=conv_circ,
168
+ param_values=param_values,
169
+ n_shots=n_shots,
170
+ state=state,
171
+ noise=noise,
172
+ endianness=endianness,
173
+ )
174
+ estim_values = empirical_average(samples=samples, support=support)
175
+ # TODO: support for parametric observables to be tested
176
+ estimated_values.append(estim_values * evaluate(pauli_term[1]))
177
+ res = torch.sum(torch.stack(estimated_values), axis=0)
178
+ # Allow for automatic differentiation.
179
+ res.requires_grad = True
180
+ return res
qadence/ml_tools/data.py CHANGED
@@ -82,34 +82,34 @@ def to_dataloader(*tensors: Tensor, batch_size: int = 1, infinite: bool = False)
82
82
 
83
83
 
84
84
  @singledispatch
85
- def data_to_device(xs: Any, device: torch_device) -> Any:
85
+ def data_to_device(xs: Any, *args: Any, **kwargs: Any) -> Any:
86
86
  """Utility method to move arbitrary data to 'device'."""
87
- raise ValueError(f"Cannot move {type(xs)} to a pytorch device.")
87
+ raise ValueError(f"Unable to move {type(xs)} with input args: {args} and kwargs: {kwargs}.")
88
88
 
89
89
 
90
90
  @data_to_device.register
91
- def _(xs: None, device: torch_device) -> None:
91
+ def _(xs: None, *args: Any, **kwargs: Any) -> None:
92
92
  return xs
93
93
 
94
94
 
95
95
  @data_to_device.register(Tensor)
96
- def _(xs: Tensor, device: torch_device) -> Tensor:
97
- return xs.to(device=device, non_blocking=True)
96
+ def _(xs: Tensor, *args: Any, **kwargs: Any) -> Tensor:
97
+ return xs.to(*args, **kwargs)
98
98
 
99
99
 
100
100
  @data_to_device.register(list)
101
- def _(xs: list, device: torch_device) -> list:
102
- return [data_to_device(x, device) for x in xs]
101
+ def _(xs: list, *args: Any, **kwargs: Any) -> list:
102
+ return [data_to_device(x, *args, **kwargs) for x in xs]
103
103
 
104
104
 
105
105
  @data_to_device.register(dict)
106
- def _(xs: dict, device: torch_device) -> dict:
107
- return {key: data_to_device(val, device) for key, val in xs.items()}
106
+ def _(xs: dict, *args: Any, **kwargs: Any) -> dict:
107
+ return {key: data_to_device(val, *args, **kwargs) for key, val in xs.items()}
108
108
 
109
109
 
110
110
  @data_to_device.register(DataLoader)
111
- def _(xs: DataLoader, device: torch_device) -> DataLoader:
112
- return DataLoader(data_to_device(xs.dataset, device))
111
+ def _(xs: DataLoader, *args: Any, **kwargs: Any) -> DataLoader:
112
+ return DataLoader(data_to_device(xs.dataset, *args, **kwargs))
113
113
 
114
114
 
115
115
  @data_to_device.register(DictDataLoader)
@@ -286,15 +286,15 @@ class TransformedModule(torch.nn.Module):
286
286
  output_shifting=torch.tensor(d["_output_shifting"]),
287
287
  )
288
288
 
289
- def to(self, device: torch.device) -> TransformedModule:
289
+ def to(self, *args: Any, **kwargs: Any) -> TransformedModule:
290
290
  try:
291
- self.model = self.model.to(device)
292
- self._input_scaling = self._input_scaling.to(device)
293
- self._input_shifting = self._input_shifting.to(device)
294
- self._output_scaling = self._output_scaling.to(device)
295
- self._output_shifting = self._output_shifting.to(device)
291
+ self.model = self.model.to(*args, **kwargs)
292
+ self._input_scaling = self._input_scaling.to(*args, **kwargs)
293
+ self._input_shifting = self._input_shifting.to(*args, **kwargs)
294
+ self._output_scaling = self._output_scaling.to(*args, **kwargs)
295
+ self._output_shifting = self._output_shifting.to(*args, **kwargs)
296
296
 
297
- logger.debug(f"Moved {self} to device {device}.")
297
+ logger.debug(f"Moved {self} to {args}, {kwargs}.")
298
298
  except Exception as e:
299
- logger.warning(f"Unable to move {self} to device {device} due to {e}.")
299
+ logger.warning(f"Unable to move {self} to {args}, {kwargs} due to {e}.")
300
300
  return self
@@ -15,6 +15,7 @@ def optimize_step(
15
15
  loss_fn: Callable,
16
16
  xs: dict | list | torch.Tensor | None,
17
17
  device: torch.device = None,
18
+ dtype: torch.dtype = None,
18
19
  ) -> tuple[torch.Tensor | float, dict | None]:
19
20
  """Default Torch optimize step with closure.
20
21
 
@@ -35,7 +36,7 @@ def optimize_step(
35
36
  """
36
37
 
37
38
  loss, metrics = None, {}
38
- xs_to_device = data_to_device(xs, device)
39
+ xs_to_device = data_to_device(xs, device=device, dtype=dtype)
39
40
 
40
41
  def closure() -> Any:
41
42
  # NOTE: We need the nonlocal as we can't return a metric dict and
@@ -4,6 +4,7 @@ from typing import Callable, Union
4
4
 
5
5
  from rich.progress import BarColumn, Progress, TaskProgressColumn, TextColumn, TimeRemainingColumn
6
6
  from torch import device as torch_device
7
+ from torch import dtype as torch_dtype
7
8
  from torch.nn import DataParallel, Module
8
9
  from torch.optim import Optimizer
9
10
  from torch.utils.data import DataLoader
@@ -28,6 +29,7 @@ def train(
28
29
  device: torch_device = None,
29
30
  optimize_step: Callable = optimize_step,
30
31
  write_tensorboard: Callable = write_tensorboard,
32
+ dtype: torch_dtype = None,
31
33
  ) -> tuple[Module, Optimizer]:
32
34
  """Runs the training loop with gradient-based optimizer.
33
35
 
@@ -111,9 +113,9 @@ def train(
111
113
 
112
114
  # Move model to device before optimizer is loaded
113
115
  if isinstance(model, DataParallel):
114
- model = model.module.to(device)
116
+ model = model.module.to(device=device, dtype=dtype)
115
117
  else:
116
- model = model.to(device)
118
+ model = model.to(device=device, dtype=dtype)
117
119
  # load available checkpoint
118
120
  init_iter = 0
119
121
  if config.folder:
@@ -341,19 +341,24 @@ class QuantumModel(nn.Module):
341
341
  params = self.embedding_fn(self._params, values)
342
342
  return self.backend.assign_parameters(self._circuit, params)
343
343
 
344
- def to(self, device: torch.device) -> QuantumModel:
344
+ def to(self, *args: Any, **kwargs: Any) -> QuantumModel:
345
345
  try:
346
346
  if isinstance(self._circuit.native, torch.nn.Module):
347
347
  # Backends which are not torch-based cannot be moved to 'device'
348
- self._params = self._params.to(device)
349
- self._circuit.native = self._circuit.native.to(device)
348
+ self._circuit.native = self._circuit.native.to(*args, **kwargs)
350
349
  if self._observable is not None:
351
350
  if isinstance(self._observable, ConvertedObservable):
352
- self._observable.native = self._observable.native.to(device)
351
+ self._observable.native = self._observable.native.to(*args, **kwargs)
353
352
  elif isinstance(self._observable, list):
354
353
  for obs in self._observable:
355
- obs.native = obs.native.to(device)
356
- logger.debug(f"Moved {self} to device {device}.")
354
+ obs.native = obs.native.to(*args, **kwargs)
355
+ self._params = self._params.to(
356
+ device=self._circuit.native.device,
357
+ dtype=torch.float64
358
+ if self._circuit.native.dtype == torch.cdouble
359
+ else torch.float32,
360
+ )
361
+ logger.debug(f"Moved {self} to {args}, {kwargs}.")
357
362
  except Exception as e:
358
- logger.warning(f"Unable to move {self} to device {device} due to {e}.")
363
+ logger.warning(f"Unable to move {self} to {args}, {kwargs} due to {e}.")
359
364
  return self
@@ -84,6 +84,7 @@ def AnalogInteraction(
84
84
  return InteractionBlock(parameters=ps, qubit_support=q, add_pattern=add_pattern)
85
85
 
86
86
 
87
+ # FIXME: Remove in v1.5.0
87
88
  def wait(
88
89
  duration: TNumber | sympy.Basic,
89
90
  qubit_support: str | QubitSupport | tuple = "global",
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: qadence
3
- Version: 1.4.0
3
+ Version: 1.5.0
4
4
  Summary: Pasqal interface for circuit-based quantum computing SDKs
5
5
  Author-email: Aleksander Wennersteen <aleksander.wennersteen@pasqal.com>, Gert-Jan Both <gert-jan.both@pasqal.com>, Niklas Heim <niklas.heim@pasqal.com>, Mario Dagrada <mario.dagrada@pasqal.com>, Vincent Elfving <vincent.elfving@pasqal.com>, Dominik Seitz <dominik.seitz@pasqal.com>, Roland Guichard <roland.guichard@pasqal.com>, "Joao P. Moutinho" <joao.moutinho@pasqal.com>, Vytautas Abramavicius <vytautas.abramavicius@pasqal.com>, Gergana Velikova <gergana.velikova@pasqal.com>
6
6
  License: Apache 2.0
@@ -13,14 +13,14 @@ Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: Implementation :: CPython
15
15
  Classifier: Programming Language :: Python :: Implementation :: PyPy
16
- Requires-Python: <3.12,>=3.9
16
+ Requires-Python: <3.13,>=3.9
17
17
  Requires-Dist: deepdiff
18
18
  Requires-Dist: jsonschema
19
19
  Requires-Dist: matplotlib
20
20
  Requires-Dist: nevergrad
21
21
  Requires-Dist: numpy
22
22
  Requires-Dist: openfermion
23
- Requires-Dist: pyqtorch==1.0.6
23
+ Requires-Dist: pyqtorch==1.1.0
24
24
  Requires-Dist: rich
25
25
  Requires-Dist: scipy
26
26
  Requires-Dist: sympytorch>=0.1.2
@@ -29,10 +29,11 @@ Requires-Dist: torch
29
29
  Provides-Extra: all
30
30
  Requires-Dist: amazon-braket-sdk; extra == 'all'
31
31
  Requires-Dist: graphviz; extra == 'all'
32
+ Requires-Dist: libs; extra == 'all'
32
33
  Requires-Dist: protocols; extra == 'all'
33
34
  Requires-Dist: pulser>=0.15.2; extra == 'all'
34
35
  Provides-Extra: braket
35
- Requires-Dist: amazon-braket-sdk; extra == 'braket'
36
+ Requires-Dist: amazon-braket-sdk==1.71.0; extra == 'braket'
36
37
  Provides-Extra: horqrux
37
38
  Requires-Dist: einops; extra == 'horqrux'
38
39
  Requires-Dist: flax; extra == 'horqrux'
@@ -41,6 +42,8 @@ Requires-Dist: jax; extra == 'horqrux'
41
42
  Requires-Dist: jaxopt; extra == 'horqrux'
42
43
  Requires-Dist: optax; extra == 'horqrux'
43
44
  Requires-Dist: sympy2jax; extra == 'horqrux'
45
+ Provides-Extra: libs
46
+ Requires-Dist: qadence-libs; extra == 'libs'
44
47
  Provides-Extra: protocols
45
48
  Requires-Dist: qadence-protocols; extra == 'protocols'
46
49
  Provides-Extra: pulser
@@ -51,13 +54,15 @@ Requires-Dist: graphviz; extra == 'visualization'
51
54
  Description-Content-Type: text/markdown
52
55
 
53
56
  <picture>
54
- <source media="(prefers-color-scheme: dark)" srcset="./docs/logo/qadence_logo_white.svg">
55
- <source media="(prefers-color-scheme: light)" srcset="./docs/logo/qadence_logo.svg">
56
- <img alt="Qadence logo" src="./docs/logo/qadence_logo.svg">
57
+ <source media="(prefers-color-scheme: dark)" srcset="./docs/assets/logo/qadence_logo_white.svg">
58
+ <source media="(prefers-color-scheme: light)" srcset="./docs/assets/logo/qadence_logo.svg">
59
+ <img alt="Qadence logo" src="./docs/assets/logo/qadence_logo.svg">
57
60
  </picture>
58
61
 
59
62
  **For a high-level overview of Qadence features, [check out our white paper](https://arxiv.org/abs/2401.09915).**
60
63
 
64
+ **For more detailed information, [check out the documentation](https://pasqal-io.github.io/qadence/latest/).**
65
+
61
66
  **Qadence** is a Python package that provides a simple interface to build _**digital-analog quantum
62
67
  programs**_ with tunable qubit interaction defined on _**arbitrary register topologies**_ realizable on neutral atom devices.
63
68
 
@@ -69,6 +74,13 @@ programs**_ with tunable qubit interaction defined on _**arbitrary register topo
69
74
 
70
75
  ## Feature highlights
71
76
 
77
+ <picture>
78
+ <source media="(prefers-color-scheme: dark)" srcset="./docs/assets/qadence_arch.svg">
79
+ <source media="(prefers-color-scheme: light)" srcset="./docs/assets/qadence_arch.svg">
80
+ <img alt="Qadence architecture" src="./docs/assets/qadence_arch.svg">
81
+ </picture>
82
+
83
+
72
84
  * A [block-based system](docs/tutorials/getting_started.md) for composing _**complex digital-analog
73
85
  programs**_ in a flexible and scalable manner, inspired by the Julia quantum SDK
74
86
  [Yao.jl](https://github.com/QuantumBFS/Yao.jl) and functional programming concepts.
@@ -97,6 +109,8 @@ The default, pre-installed backend for Qadence is [PyQTorch](https://github.com/
97
109
  * `pulser`: The [Pulser](https://github.com/pasqal-io/Pulser) backend for composing, simulating and executing pulse sequences for neutral-atom quantum devices.
98
110
  * `braket`: The [Braket](https://github.com/amazon-braket/amazon-braket-sdk-python) backend, an open source library that provides a framework for interacting with quantum computing hardware devices through Amazon Braket.
99
111
  * `visualization`: A visualization library to display quantum circuit diagrams.
112
+ * `protocols`: A collection of [protocols](https://github.com/pasqal-io/qadence-protocols) for error mitigation in Qadence.
113
+ * `libs`: A collection of [functionalities](https://github.com/pasqal-io/qadence-libs) for graph machine learning problems build on top of Qadence.
100
114
 
101
115
  Qadence also supports a `JAX` engine which is currently supporting the [Horqrux](https://github.com/pasqal-io/horqrux) backend. `horqrux` is currently only available via the [low-level API](examples/backends/low_level/horqrux_backend.py).
102
116
 
@@ -1,11 +1,12 @@
1
- qadence/__init__.py,sha256=XxVbw_UToWu0PUKxOg2C42lYT22cgQH_ysy8PRGT0q0,1707
1
+ qadence/__init__.py,sha256=-UKQQ_dYiaa7viishl2baAbxS82eS6dAoCnq_CLSmao,1708
2
2
  qadence/backend.py,sha256=5sfXUTRts_13v6lajq1Wvy3u_eOCOeIYnTiaZV_NGFQ,15493
3
3
  qadence/circuit.py,sha256=EGBPRRWlK-mcXaaAhJnp-hxVWQ8NxngGKbvhPqrEeKM,6892
4
4
  qadence/decompose.py,sha256=_L0hI3SbYErXEDp-aXFeNk0JR9ffJ_JD_EnRJbJKT20,5230
5
5
  qadence/divergences.py,sha256=JhpELhWSnuDvQxa9hJp_DE3EQg2Ban-Ta0mHZ_fVrHg,1832
6
6
  qadence/execution.py,sha256=5_P5OSatiwEAu7aAkCLau5VcmtIZiC3VFIj5YYdwAbY,9287
7
- qadence/extensions.py,sha256=KVuAFLmytpy7TdSCRTHGS1s-OdkgiJmoidtzt0lpEmM,4548
7
+ qadence/extensions.py,sha256=CgaUR3amh80g_zwxGaAjFvgI-JT_pmDiUMzzzVQP7zc,4582
8
8
  qadence/finitediff.py,sha256=TijuaWUbX9VlbLyMYco6HkK9eCoRTVnKug4Ekd6mlTI,1592
9
+ qadence/libs.py,sha256=HetkKO8TCTlVCViQdVQJvxwBekrhd-y_iMox4UJMY1M,410
9
10
  qadence/logger.py,sha256=mdTr52nL30ipPRwp11nIHKLEoB3hqs7J-Mric5KVfyM,912
10
11
  qadence/overlap.py,sha256=3vsg0HLOO3X8LiVgvjSc5s-cs8Di4TpEA657LWZ5HEY,17294
11
12
  qadence/parameters.py,sha256=svZ3L-Z4pzm2PkPDIlb-DWkwGOQLAm1eECCtu7nd3W0,12334
@@ -28,7 +29,7 @@ qadence/backends/adjoint.py,sha256=C2BdLUs2rdV9TiErkVlE0hoeLx_nK7up9mzIO-0vB2g,6
28
29
  qadence/backends/api.py,sha256=6PoK4ydhi2tj9w0ePMQl1G4kEFROoWe3lrkrtQwWxkc,3224
29
30
  qadence/backends/gpsr.py,sha256=227h5KPI_KStrwfP5zuwkzOqviRZmqa7ijIIhhawwPM,4341
30
31
  qadence/backends/jax_utils.py,sha256=VfKhqCKknHDWZO21UFipWH_Lkiq175Z5GkP49gWjbyw,5038
31
- qadence/backends/utils.py,sha256=q8vVk5GOZgbaijRdKgPGPuHsoXBkQfzX0cr9rf17W2U,6460
32
+ qadence/backends/utils.py,sha256=hnV9AXztMvAPcO8mv9UhdGMbS9albiMQBxlYPgLrD68,6490
32
33
  qadence/backends/braket/__init__.py,sha256=eruyDZKMqkh1LE7eJ980vcrLJbia35uUX6krAP78clI,121
33
34
  qadence/backends/braket/backend.py,sha256=PLW-NCNp_RqAQy149ASEOOvwPrLsFGjCKWuEmTnS5Qg,8730
34
35
  qadence/backends/braket/config.py,sha256=b9aIdma0DRwC_3A6xUSLdXMCZe6z6kDcAgkp6MxcXIk,603
@@ -38,18 +39,18 @@ qadence/backends/horqrux/backend.py,sha256=qdThkUXbhDrsD1lAio2SFsxdYATxLVXoNsuXN
38
39
  qadence/backends/horqrux/config.py,sha256=fPWFag1hmRhqj0T-fJOx5x8_C5UEZUXpdUnpOgX0Jpc,901
39
40
  qadence/backends/horqrux/convert_ops.py,sha256=nzfYF0yjB7zwaHCEXWZUUYDfz38Yi22xF2zDRFaOwR0,8564
40
41
  qadence/backends/pulser/__init__.py,sha256=capQ-eHqwtOeLf4mWsI0BIseAHhiLGie5cFD4-iVhUo,116
41
- qadence/backends/pulser/backend.py,sha256=vd2fycEoGpYQsYJkpvx1abpy4tnyzKvoo2dReol9VvI,13868
42
+ qadence/backends/pulser/backend.py,sha256=3p9cB5QN60nzqhWvdLZol0t66PugaWqvWHdDEXgGRwM,13868
42
43
  qadence/backends/pulser/channels.py,sha256=ZF0yEXUFHAmi3IdeXjzdTNGR5NzaRRFTiUpUGVg2sO4,329
43
44
  qadence/backends/pulser/cloud.py,sha256=0uUluvbFV9sOuCPraE-9uiVtC3Q8QaDY1IJMDi8grDM,2057
44
- qadence/backends/pulser/config.py,sha256=DdboScn5TrtVwCcsHgZjNCQmWy46aSrf44FhOTJRxaw,3038
45
+ qadence/backends/pulser/config.py,sha256=1qu_GhGTGcCpFoKctGt_IhKOKWiMcJIL2vHTFJg9I3E,3122
45
46
  qadence/backends/pulser/convert_ops.py,sha256=0HGWe5kIwI1ZALHf2j68B8aBOhwFNZV-mDy1_6zsF5g,1227
46
47
  qadence/backends/pulser/devices.py,sha256=DermLZNfmCB3SqteKVW4uhg4jp6ya1G6ptnXbBnJogI,2448
47
48
  qadence/backends/pulser/pulses.py,sha256=DopdEZ8eeWK7wZxqJTBhqY0w5bEXu6fVK7rnZOb50ns,11893
48
49
  qadence/backends/pulser/waveforms.py,sha256=0uz95b7rUaUUtN0tuHBZmJ0H6UBmfHST_59ozwsRCzg,2227
49
50
  qadence/backends/pyqtorch/__init__.py,sha256=0OdVy6cq0oQggV48LO1WXdaZuSkDkz7OYNEPIkNAmfk,140
50
- qadence/backends/pyqtorch/backend.py,sha256=CcbWWKQfee7cSz19xiw9g_ZyFsLJ1KmriIjTReSSb_k,9584
51
+ qadence/backends/pyqtorch/backend.py,sha256=hNo9nKxfJ3rFDEPjZOhfmbKUUVsNzTl0aRh9sgeKlqc,9763
51
52
  qadence/backends/pyqtorch/config.py,sha256=f5BjWehCqm9do2OahNWrv2w55y3orkw0Wj2f6flwRaU,1907
52
- qadence/backends/pyqtorch/convert_ops.py,sha256=SEOoVpbznlVDmeb1ZPGmw-WO0sOUNj1OgQPSjx5eAok,16928
53
+ qadence/backends/pyqtorch/convert_ops.py,sha256=By_p1-Oem8MhHYP8jx5qdut9lhDWN0xc4B9YaP0MSxA,17512
53
54
  qadence/blocks/__init__.py,sha256=H6jEA_CptkE-eoB4UfSbUiDszbxxhZwECV_TgoZWXoU,960
54
55
  qadence/blocks/abstract.py,sha256=35RcVlNvD1BmBoJ8bbYJ3LrdU72wixt9ZmTbCtEwNus,11796
55
56
  qadence/blocks/analog.py,sha256=ymnnlSVoW1XL05ZvnnHCqRTHuOXIEY_7E9M0PNKJZy4,10812
@@ -61,8 +62,8 @@ qadence/blocks/matrix.py,sha256=XQI6D4CWhCf3j-hvA0jRKOgprs0RA6su7OythCoH6Ls,3785
61
62
  qadence/blocks/primitive.py,sha256=fC5ItpA-52LOiGPT1ERM4RshP6PQlkxlgR9p2J0Rgz4,16631
62
63
  qadence/blocks/utils.py,sha256=lNWNCGpM4q_KilaiSGj1u8XJrilR5PdV92KZHZt6MEQ,16358
63
64
  qadence/constructors/__init__.py,sha256=d4ndrNCTCDS_kUYeigGFQOUFSAMaPKL--_FcdZy7eQo,1152
64
- qadence/constructors/ansatze.py,sha256=PWC6ILioReF6vlS22UevCSLIHGR1HMQpUVPlCyZ4rNY,12026
65
- qadence/constructors/feature_maps.py,sha256=WEUPdHY-v_dftWhb8sziL85FJ_qiBGGhM7MMnfi1qEA,11462
65
+ qadence/constructors/ansatze.py,sha256=8JoYvv7nYPgygIZpB227Zx7csPxg8SIR1tnYl0SzAb4,12170
66
+ qadence/constructors/feature_maps.py,sha256=Z8h_UDpG9wtpt72htZK6c0mV0YNwzSsH4rv2A_vRhNw,11566
66
67
  qadence/constructors/hamiltonians.py,sha256=rEeMkMepQE5xe-siAfhIlgUE2aIGwk8SUdPLNTPHUnU,8860
67
68
  qadence/constructors/iia.py,sha256=z-4AA9Oj-j2oZ0QDkLYNk4duS3UHY_98Qwt9VO_ZDDU,7001
68
69
  qadence/constructors/qft.py,sha256=2LpgQ-z1HUxB3rqHzYsbjqpdU63gyuuaUVCbNEFbjo8,7688
@@ -88,37 +89,39 @@ qadence/engines/jax/differentiable_backend.py,sha256=W5rDA8wb-ECnFWoLj4dVugF9v1l
88
89
  qadence/engines/jax/differentiable_expectation.py,sha256=XBYHT1XKRuZfKxTcNy8KJpSDPt-2PR4ZCanImCPI9OI,3677
89
90
  qadence/engines/torch/__init__.py,sha256=iZFdD32ot0B0CVyC-f5dVViOBnqoalxa6M9Lj4WQuPE,160
90
91
  qadence/engines/torch/differentiable_backend.py,sha256=AWthwvKE8pCOih4dZ3tXxQX4W1ps9mBcvo7n4V9V24Y,3553
91
- qadence/engines/torch/differentiable_expectation.py,sha256=EaGcDvdF_lDKuD2qp8Uv1naXLdfURhPdcq_weCnR9p8,15382
92
+ qadence/engines/torch/differentiable_expectation.py,sha256=w_9infZDQRRU7sII8V0aklXrR73IOU0Bjf8C5neJLIY,9161
92
93
  qadence/exceptions/__init__.py,sha256=BU6vWrI9mshzr1aTPm1Ticr_o_42GjTrWI4OZXhThsI,203
93
94
  qadence/exceptions/exceptions.py,sha256=4j_VJpx2sZ2Mir5BJUWu4nwb131FY1ygO4q8-XlyfRc,190
94
95
  qadence/measurements/__init__.py,sha256=RIjG9tVJMqhNzyj7maZI250Um0KgHl2PizDcKJag-JU,161
95
- qadence/measurements/protocols.py,sha256=815fqd0kfFpiD4W4QFN0uumucSDBUG3xwVx60JjADOQ,1161
96
+ qadence/measurements/protocols.py,sha256=mD50R9yPs5bIYH7Efd0BsR0503apiyrsZydi_Q6BJag,1161
97
+ qadence/measurements/samples.py,sha256=AVvszDwgfKnZ_ooATyTA3270vGeg1V3WO94jsfrTk-8,1200
96
98
  qadence/measurements/shadow.py,sha256=ROMQFtV9LaUB2Q6pjcBY1qDAYjDUGq1FUFmI8WXTd0g,12550
97
- qadence/measurements/tomography.py,sha256=i0IBJnDyeSFUvgzREwtKCByhHD6RNcLfjzdY-sTKuEE,7023
99
+ qadence/measurements/tomography.py,sha256=8fzXhYOu_DaMiUoZzLvpP03WhuwlZ3ldkWepLUHjWqM,2665
100
+ qadence/measurements/utils.py,sha256=CJmnSobzdeR4T4FuEpad7d-BSJ9W-wTaU9hRbveB6kY,6534
98
101
  qadence/mitigations/__init__.py,sha256=RzaxYJftePFMloGhBVSixZ8fSe-ps_Jc-EyPm6xz-bs,159
99
102
  qadence/mitigations/analog_zne.py,sha256=g0QkjSdF-N9Dv2N8Oza4sylnjUMid5ea-4NCT9Tcm3Y,7768
100
103
  qadence/mitigations/protocols.py,sha256=Jq9MyLujfTyWmc7XVUGYVRUkJT1MmZw-GgmWpVjmX2Y,1608
101
104
  qadence/mitigations/readout.py,sha256=HPfYmdjRlieUdOBMZTghFK4DRWfveM4KkDkEI0bMI0E,6262
102
105
  qadence/ml_tools/__init__.py,sha256=_H5A_BWZRZVGoJszb9s8XRJnLnJxUNfYjuT9HT2yASo,786
103
106
  qadence/ml_tools/config.py,sha256=X8dHyjq4D9-ITjs7UQo0vjJTcHkpbZC0gChH5eEN2G8,2356
104
- qadence/ml_tools/data.py,sha256=KvEGeN6AaCXIhLcSO7WZUMNUhfscmI_V3KR40mmT4Ng,4215
105
- qadence/ml_tools/models.py,sha256=ZCIzxJvwQigL4uBXkR8EYLasclLVRDdDD4XT9IgzNZ4,11684
106
- qadence/ml_tools/optimize_step.py,sha256=UtyF68CJC-bYP5yEovu5EhWe9XpSjwFUtC6NQjkaUq8,1749
107
+ qadence/ml_tools/data.py,sha256=8ZUFjhQSp94w7icX7RzM2J39Yo7P_T-AgjcThBc8miI,4283
108
+ qadence/ml_tools/models.py,sha256=biUWnqXKmGMJfT-QObJ-cQ6770YIfOTz-o28EKPkM3Q,11736
109
+ qadence/ml_tools/optimize_step.py,sha256=ATXWmAqybJVK3QmAaDqVXB5mxjTo2MIi_e0a5WSPFpc,1800
107
110
  qadence/ml_tools/parameters.py,sha256=gew2Kq_5-RgRpaTvs8eauVhgo0sTqqDQEV6WHFEiLGM,1301
108
111
  qadence/ml_tools/printing.py,sha256=kwwD9yLVqezaqWX5OAsXr8GLdJUnGrY-t5SnoKHtl9g,707
109
112
  qadence/ml_tools/saveload.py,sha256=Xi3o2bMsYueFPxrU6AXgDB0MHSev8gKLVhdqecPDBt8,4663
110
113
  qadence/ml_tools/tensors.py,sha256=xZ9ZRzOqEaMgLUGWQf1najDmL6iLuN1ojCGVFs1Tm94,1337
111
- qadence/ml_tools/train_grad.py,sha256=ydZjbGCCe1W31AOUp7D7ya4wdREV1s44fgcGaM-tG1k,7289
114
+ qadence/ml_tools/train_grad.py,sha256=b_FxOkK3QoLAOwSowjkkMIjlBEDjoLcjeo3Vk_RHhkc,7399
112
115
  qadence/ml_tools/train_no_grad.py,sha256=erwus-pUOg8q6WgoQsDW6MeH80wlRPBh69W1ZMHKoL8,4714
113
116
  qadence/ml_tools/utils.py,sha256=_GZSN5Flk1nRFutkXih397Q3cWKdX0UP8c9CRXpUL7c,1654
114
117
  qadence/models/__init__.py,sha256=0nZzAC2TGr8Yuf40-R7m2cSsr_BlNq_GsMOwaOYZLqM,193
115
118
  qadence/models/qnn.py,sha256=gc_iC1GG6WJbeLaln9jy4yYp9fY0p8fkpKkKJpXJ3ck,10397
116
- qadence/models/quantum_model.py,sha256=6fSq9Oh6JstA12GMPfTyRFK9r0TkLHbLcJd1pQ3XkQk,13859
119
+ qadence/models/quantum_model.py,sha256=ucExUBPBYWrC7mLF4SQbvHqjdXmkEi7-wIdXqpfaGew,14107
117
120
  qadence/noise/__init__.py,sha256=r0nR8uEZeB1M9pI2UisjWq0bjw50fPFfVGzIMev923g,147
118
121
  qadence/noise/protocols.py,sha256=-aZ06JvMnpxCeT5v5lI_RNPOLbb9Ju1Pi1AB6uAXxVE,1653
119
122
  qadence/noise/readout.py,sha256=BqBIZbPXWqZaKi6EpBSpXXQ9NhQXdQ-YL6ZmwbSjgfE,6736
120
123
  qadence/operations/__init__.py,sha256=6D2yNOJ78BgFBZpHpHYMUDzU2R1HovB-mwGgNq-Uwwk,1944
121
- qadence/operations/analog.py,sha256=h2wx4DqRvvhD9DwmAyxHorGuZvpuoEJx_8nmgJ0yK-w,7756
124
+ qadence/operations/analog.py,sha256=FkwAtsL7M6EPk5_shCXqHXzJDr0MY3_mA9R5LbZKu8w,7782
122
125
  qadence/operations/control_ops.py,sha256=6PVTFELkbvfvgczPbKw0QDin_CpDFzganIdJFaQJHjY,9492
123
126
  qadence/operations/ham_evo.py,sha256=EhBz5ZgoWsP4PhR8DLvTdje8bl17oEBipBdSkpCTWV4,7400
124
127
  qadence/operations/parametric.py,sha256=RVRTlKOd2_bKXwNorO3TYhZ88AFaEgGkxKYKzT_RuIA,4919
@@ -131,7 +134,7 @@ qadence/transpile/digitalize.py,sha256=iWRwYAYQsD2INHj0HNbGJriv_3fRCuBW1nDBrwtKS
131
134
  qadence/transpile/flatten.py,sha256=EdhSG5WyF56nbnxINNLqrHgY84MRM1YFjT3fR4aph5Q,3427
132
135
  qadence/transpile/invert.py,sha256=KAefHTG2AWr39aengVhXrzCtJPhrZC-ZnL6vYvmbnY0,4867
133
136
  qadence/transpile/transpile.py,sha256=6MRRkk1OS279L1fwUQjazA6qlfpbd-T_EJMKT8hAhOU,2721
134
- qadence-1.4.0.dist-info/METADATA,sha256=Uu4ENgsHtoKV_J3thoHJYKDJMy7eNtvJfPFtZB1goSk,8210
135
- qadence-1.4.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
136
- qadence-1.4.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
137
- qadence-1.4.0.dist-info/RECORD,,
137
+ qadence-1.5.0.dist-info/METADATA,sha256=NgAwZRUkuLfgnTuo46gGAW1Pj8EmPCAvvPr3FbPi1Ww,8997
138
+ qadence-1.5.0.dist-info/WHEEL,sha256=uNdcs2TADwSd5pVaP0Z_kcjcvvTUklh2S7bxZMF8Uj0,87
139
+ qadence-1.5.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
140
+ qadence-1.5.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.21.1
2
+ Generator: hatchling 1.22.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any