qadence 1.5.0__py3-none-any.whl → 1.5.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
qadence/backend.py CHANGED
@@ -26,7 +26,6 @@ from qadence.mitigations import Mitigations
26
26
  from qadence.noise import Noise
27
27
  from qadence.parameters import stringify
28
28
  from qadence.types import ArrayLike, BackendName, DiffMode, Endianness, Engine, ParamDictType
29
- from qadence.utils import validate_values_and_state
30
29
 
31
30
  logger = get_logger(__file__)
32
31
 
@@ -259,29 +258,6 @@ class Backend(ABC):
259
258
  """
260
259
  raise NotImplementedError
261
260
 
262
- @abstractmethod
263
- def _run(
264
- self,
265
- circuit: ConvertedCircuit,
266
- param_values: dict[str, ArrayLike] = {},
267
- state: ArrayLike | None = None,
268
- endianness: Endianness = Endianness.BIG,
269
- ) -> ArrayLike:
270
- """Run a circuit and return the resulting wave function.
271
-
272
- Arguments:
273
- circuit: A converted circuit as returned by `backend.circuit`.
274
- param_values: _**Already embedded**_ parameters of the circuit. See
275
- [`embedding`][qadence.blocks.embedding.embedding] for more info.
276
- state: Initial state.
277
- endianness: Endianness of the resulting wavefunction.
278
-
279
- Returns:
280
- A list of Counter objects where each key represents a bitstring
281
- and its value the number of times it has been sampled from the given wave function.
282
- """
283
- raise NotImplementedError
284
-
285
261
  def run(
286
262
  self,
287
263
  circuit: ConvertedCircuit,
@@ -304,8 +280,7 @@ class Backend(ABC):
304
280
  A list of Counter objects where each key represents a bitstring
305
281
  and its value the number of times it has been sampled from the given wave function.
306
282
  """
307
- validate_values_and_state(state, circuit.abstract.n_qubits, param_values)
308
- return self._run(circuit, param_values, state, endianness, *args, **kwargs)
283
+ raise NotImplementedError
309
284
 
310
285
  @abstractmethod
311
286
  def run_dm(
@@ -88,7 +88,7 @@ class Backend(BackendInterface):
88
88
  ).squeeze(0)
89
89
  return ConvertedObservable(native=native, abstract=obs, original=obs)
90
90
 
91
- def _run(
91
+ def run(
92
92
  self,
93
93
  circuit: ConvertedCircuit,
94
94
  param_values: dict[str, Tensor] = {},
@@ -66,7 +66,7 @@ class Backend(BackendInterface):
66
66
  hq_obs = convert_observable(block, n_qubits=n_qubits, config=self.config)
67
67
  return ConvertedObservable(native=hq_obs, abstract=block, original=observable)
68
68
 
69
- def _run(
69
+ def run(
70
70
  self,
71
71
  circuit: ConvertedCircuit,
72
72
  param_values: ParamDictType = {},
@@ -200,7 +200,7 @@ class Backend(BackendInterface):
200
200
 
201
201
  return circuit.native.build(**numpy_param_values)
202
202
 
203
- def _run(
203
+ def run(
204
204
  self,
205
205
  circuit: ConvertedCircuit,
206
206
  param_values: dict[str, Tensor] = {},
@@ -80,7 +80,7 @@ class Backend(BackendInterface):
80
80
  (native,) = convert_observable(block, n_qubits=n_qubits, config=self.config)
81
81
  return ConvertedObservable(native=native, abstract=block, original=observable)
82
82
 
83
- def _run(
83
+ def run(
84
84
  self,
85
85
  circuit: ConvertedCircuit,
86
86
  param_values: dict[str, Tensor] = {},
@@ -289,11 +289,23 @@ class TransformedModule(torch.nn.Module):
289
289
  def to(self, *args: Any, **kwargs: Any) -> TransformedModule:
290
290
  try:
291
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
-
292
+ if isinstance(self.model, QuantumModel):
293
+ device = self.model._circuit.native.device
294
+ dtype = (
295
+ torch.float64
296
+ if self.model._circuit.native.dtype == torch.cdouble
297
+ else torch.float32
298
+ )
299
+
300
+ self._input_scaling = self._input_scaling.to(device=device, dtype=dtype)
301
+ self._input_shifting = self._input_shifting.to(device=device, dtype=dtype)
302
+ self._output_scaling = self._output_scaling.to(device=device, dtype=dtype)
303
+ self._output_shifting = self._output_shifting.to(device=device, dtype=dtype)
304
+ elif isinstance(self.model, torch.nn.Module):
305
+ self._input_scaling = self._input_scaling.to(*args, **kwargs)
306
+ self._input_shifting = self._input_shifting.to(*args, **kwargs)
307
+ self._output_scaling = self._output_scaling.to(*args, **kwargs)
308
+ self._output_shifting = self._output_shifting.to(*args, **kwargs)
297
309
  logger.debug(f"Moved {self} to {args}, {kwargs}.")
298
310
  except Exception as e:
299
311
  logger.warning(f"Unable to move {self} to {args}, {kwargs} due to {e}.")
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import Callable, Union
4
4
 
5
5
  from rich.progress import BarColumn, Progress, TaskProgressColumn, TextColumn, TimeRemainingColumn
6
+ from torch import complex128, float32, float64
6
7
  from torch import device as torch_device
7
8
  from torch import dtype as torch_dtype
8
9
  from torch.nn import DataParallel, Module
@@ -110,17 +111,17 @@ def train(
110
111
  train_with_grad(model, data, optimizer, config, loss_fn=loss_fn)
111
112
  ```
112
113
  """
114
+ # load available checkpoint
115
+ init_iter = 0
116
+ if config.folder:
117
+ model, optimizer, init_iter = load_checkpoint(config.folder, model, optimizer)
118
+ logger.debug(f"Loaded model and optimizer from {config.folder}")
113
119
 
114
120
  # Move model to device before optimizer is loaded
115
121
  if isinstance(model, DataParallel):
116
122
  model = model.module.to(device=device, dtype=dtype)
117
123
  else:
118
124
  model = model.to(device=device, dtype=dtype)
119
- # load available checkpoint
120
- init_iter = 0
121
- if config.folder:
122
- model, optimizer, init_iter = load_checkpoint(config.folder, model, optimizer)
123
- logger.debug(f"Loaded model and optimizer from {config.folder}")
124
125
  # initialize tensorboard
125
126
  writer = SummaryWriter(config.folder, purge_step=init_iter)
126
127
 
@@ -131,7 +132,9 @@ def train(
131
132
  TaskProgressColumn(),
132
133
  TimeRemainingColumn(elapsed_when_finished=True),
133
134
  )
134
-
135
+ data_dtype = None
136
+ if dtype:
137
+ data_dtype = float64 if dtype == complex128 else float32
135
138
  with progress:
136
139
  dl_iter = iter(dataloader) if dataloader is not None else None
137
140
 
@@ -143,7 +146,12 @@ def train(
143
146
  # which do not have classical input data (e.g. chemistry)
144
147
  if dataloader is None:
145
148
  loss, metrics = optimize_step(
146
- model=model, optimizer=optimizer, loss_fn=loss_fn, xs=None, device=device
149
+ model=model,
150
+ optimizer=optimizer,
151
+ loss_fn=loss_fn,
152
+ xs=None,
153
+ device=device,
154
+ dtype=data_dtype,
147
155
  )
148
156
  loss = loss.item()
149
157
 
@@ -154,6 +162,7 @@ def train(
154
162
  loss_fn=loss_fn,
155
163
  xs=next(dl_iter), # type: ignore[arg-type]
156
164
  device=device,
165
+ dtype=data_dtype,
157
166
  )
158
167
 
159
168
  else:
@@ -342,9 +342,10 @@ class QuantumModel(nn.Module):
342
342
  return self.backend.assign_parameters(self._circuit, params)
343
343
 
344
344
  def to(self, *args: Any, **kwargs: Any) -> QuantumModel:
345
+ from pyqtorch import QuantumCircuit as PyQCircuit
346
+
345
347
  try:
346
- if isinstance(self._circuit.native, torch.nn.Module):
347
- # Backends which are not torch-based cannot be moved to 'device'
348
+ if isinstance(self._circuit.native, PyQCircuit):
348
349
  self._circuit.native = self._circuit.native.to(*args, **kwargs)
349
350
  if self._observable is not None:
350
351
  if isinstance(self._observable, ConvertedObservable):
@@ -359,6 +360,8 @@ class QuantumModel(nn.Module):
359
360
  else torch.float32,
360
361
  )
361
362
  logger.debug(f"Moved {self} to {args}, {kwargs}.")
363
+ else:
364
+ logger.debug("QuantumModel.to only supports pyqtorch.QuantumCircuits.")
362
365
  except Exception as e:
363
366
  logger.warning(f"Unable to move {self} to {args}, {kwargs} due to {e}.")
364
367
  return self
@@ -0,0 +1,11 @@
1
+ Program = expr EOF
2
+ expr = id '(' args ')'
3
+ args = (value / expr) (',' (value / expr))*
4
+ value = int / float_str / str / pair
5
+ pair = param '=' (int / bool / str)
6
+ param = r"[a-z][a-zA-Z]*"
7
+ id = r"[a-zA-Z][a-zA-Z_0-9]*"
8
+ bool = 'True' / 'False'
9
+ int = r"-?(0|[1-9][0-9]*)"
10
+ float_str = r"'-?(0|\d*(\.\d*))'"
11
+ str = r"'[a-zA-Z0-9\_\.]+'"
qadence/serialization.py CHANGED
@@ -2,21 +2,26 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import os
5
+ import sys
6
+ from dataclasses import dataclass
7
+ from dataclasses import field as dataclass_field
8
+ from functools import lru_cache
5
9
  from pathlib import Path
6
- from typing import Any, get_args
10
+ from typing import Any, Callable, get_args
7
11
  from typing import Union as TypingUnion
8
12
 
9
13
  import torch
14
+ from arpeggio import NoMatch
15
+ from arpeggio.cleanpeg import ParserPEG
10
16
  from sympy import *
11
- from sympy import Basic, Expr, srepr
17
+ from sympy import core, srepr
12
18
 
13
- from qadence import QuantumCircuit, operations
19
+ from qadence import QuantumCircuit, operations, parameters
14
20
  from qadence import blocks as qadenceblocks
15
21
  from qadence.blocks import AbstractBlock
16
22
  from qadence.blocks.utils import tag
17
23
  from qadence.logger import get_logger
18
- from qadence.ml_tools.models import TransformedModule
19
- from qadence.models import QNN, QuantumModel
24
+ from qadence.models import QuantumModel
20
25
  from qadence.parameters import Parameter
21
26
  from qadence.register import Register
22
27
  from qadence.types import SerializationFormat
@@ -43,27 +48,172 @@ SUPPORTED_OBJECTS = [
43
48
  AbstractBlock,
44
49
  QuantumCircuit,
45
50
  QuantumModel,
46
- QNN,
47
- TransformedModule,
48
51
  Register,
49
- Basic,
52
+ core.Basic,
50
53
  torch.nn.Module,
51
54
  ]
52
55
  SUPPORTED_TYPES = TypingUnion[
53
56
  AbstractBlock,
54
57
  QuantumCircuit,
55
58
  QuantumModel,
56
- QNN,
57
- TransformedModule,
58
59
  Register,
59
- Basic,
60
+ core.Basic,
60
61
  torch.nn.Module,
61
62
  ]
62
63
 
63
-
64
64
  ALL_BLOCK_NAMES = [
65
65
  n for n in dir(qadenceblocks) if not (n.startswith("__") and n.endswith("__"))
66
66
  ] + [n for n in dir(operations) if not (n.startswith("__") and n.endswith("__"))]
67
+ SYMPY_EXPRS = [n for n in dir(core) if not (n.startswith("__") and n.endswith("__"))]
68
+ QADENCE_PARAMETERS = [n for n in dir(parameters) if not (n.startswith("__") and n.endswith("__"))]
69
+
70
+
71
+ THIS_PATH = Path(__file__).parent
72
+ GRAMMAR_FILE = THIS_PATH / "serial_expr_grammar.peg"
73
+
74
+
75
+ @lru_cache
76
+ def _parser_fn() -> ParserPEG:
77
+ with open(GRAMMAR_FILE, "r") as f:
78
+ grammar = f.read()
79
+ return ParserPEG(grammar, "Program")
80
+
81
+
82
+ _parsing_serialize_expr = _parser_fn()
83
+
84
+
85
+ def parse_expr_fn(code: str) -> bool:
86
+ """
87
+ A parsing expressions function that checks whether a given code is valid on.
88
+
89
+ the parsing grammar. The grammar is defined to be compatible with `sympy`
90
+ expressions, such as `Float('-0.33261030434342942', precision=53)`, while
91
+ avoiding code injection such as `2*3` or `__import__('os').system('ls -la')`.
92
+
93
+ Args:
94
+ code (str): code to be parsed and checked.
95
+
96
+ Returns:
97
+ Boolean indicating whether the code matches the defined grammar or not.
98
+ """
99
+
100
+ parser = _parsing_serialize_expr
101
+ try:
102
+ parser.parse(code)
103
+ except NoMatch:
104
+ return False
105
+ else:
106
+ return True
107
+
108
+
109
+ @dataclass
110
+ class SerializationModel:
111
+ """
112
+ A serialization model class to serialize data from `QuantumModel`s,.
113
+
114
+ `torch.nn.Module` and similar structures. The data included in the
115
+ serialization logic includes: the `AbstractBlock` and its children
116
+ classes, `QuantumCircuit`, `Register`, and `sympy` expressions
117
+ (including `Parameter` class from `qadence.parameters`).
118
+
119
+ A children class must define the `value` attribute type and how to
120
+ handle it, since it is the main property for the class to be used
121
+ by the serialization process. For instance:
122
+
123
+ ```python
124
+ @dataclass
125
+ class QuantumCircuitSerialization(SerializationModel):
126
+ value: QuantumCircuit = dataclass_field(init=False)
127
+
128
+ def __post_init__(self) -> None:
129
+ self.value = (
130
+ QuantumCircuit._from_dict(self.d)
131
+ if isinstance(self.d, dict)
132
+ else self.d
133
+ )
134
+ ```
135
+ """
136
+
137
+ d: dict = dataclass_field(default_factory=dict)
138
+ value: Any = dataclass_field(init=False)
139
+
140
+
141
+ @dataclass
142
+ class BlockTypeSerialization(SerializationModel):
143
+ value: AbstractBlock = dataclass_field(init=False)
144
+
145
+ def __post_init__(self) -> None:
146
+ block = (
147
+ getattr(operations, self.d["type"])
148
+ if hasattr(operations, self.d["type"])
149
+ else getattr(qadenceblocks, self.d["type"])
150
+ )._from_dict(self.d)
151
+ if self.d["tag"] is not None:
152
+ block = tag(block, self.d["tag"])
153
+ self.value = block
154
+
155
+
156
+ @dataclass
157
+ class QuantumCircuitSerialization(SerializationModel):
158
+ value: QuantumCircuit = dataclass_field(init=False)
159
+
160
+ def __post_init__(self) -> None:
161
+ self.value = QuantumCircuit._from_dict(self.d) if isinstance(self.d, dict) else self.d
162
+
163
+
164
+ @dataclass
165
+ class RegisterSerialization(SerializationModel):
166
+ value: Register = dataclass_field(init=False)
167
+
168
+ def __post_init__(self) -> None:
169
+ self.value = Register._from_dict(self.d)
170
+
171
+
172
+ @dataclass
173
+ class ModelSerialization(SerializationModel):
174
+ as_torch: bool = False
175
+ value: torch.nn.Module = dataclass_field(init=False)
176
+
177
+ def __post_init__(self) -> None:
178
+ module_name = list(self.d.keys())[0]
179
+ obj = globals().get(module_name, None)
180
+ if obj is None:
181
+ obj = self._resolve_module(module_name)
182
+ if hasattr(obj, "_from_dict"):
183
+ self.value = obj._from_dict(self.d, self.as_torch)
184
+ elif hasattr(obj, "load_state_dict"):
185
+ self.value = obj.load_state_dict(self.d[module_name])
186
+ else:
187
+ msg = (
188
+ f"Unable to deserialize object '{module_name}'. "
189
+ f"Supported types are {SUPPORTED_OBJECTS}."
190
+ )
191
+ logger.error(TypeError(msg))
192
+ raise TypeError(msg)
193
+
194
+ @staticmethod
195
+ def _resolve_module(module: str) -> Any:
196
+ for loaded_module in sys.modules.keys():
197
+ if "qadence" in loaded_module:
198
+ obj = getattr(sys.modules[loaded_module], module, None)
199
+ if obj:
200
+ return obj
201
+ raise ValueError(f"Couldn't resolve module '{module}'.")
202
+
203
+
204
+ @dataclass
205
+ class ExpressionSerialization(SerializationModel):
206
+ value: str | core.Expr | float = dataclass_field(init=False)
207
+
208
+ def __post_init__(self) -> None:
209
+ if parse_expr_fn(self.d["expression"]):
210
+ expr = eval(self.d["expression"])
211
+ if hasattr(expr, "free_symbols"):
212
+ for s in expr.free_symbols:
213
+ s.value = float(self.d["symbols"][s.name]["value"])
214
+ self.value = expr
215
+ else:
216
+ raise ValueError(f"Invalid expression: {self.d['expression']}")
67
217
 
68
218
 
69
219
  def save_pt(d: dict, file_path: str | Path) -> None:
@@ -94,11 +244,11 @@ def serialize(obj: SUPPORTED_TYPES, save_params: bool = False) -> dict:
94
244
  """
95
245
  Supported Types:
96
246
 
97
- AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | Module
247
+ AbstractBlock | QuantumCircuit | QuantumModel | torch.nn.Module | Register | Module
98
248
  Serializes a qadence object to a dictionary.
99
249
 
100
250
  Arguments:
101
- obj (AbstractBlock | QuantumCircuit | QuantumModel | Register | Module):
251
+ obj (AbstractBlock | QuantumCircuit | QuantumModel | Register | torch.nn.Module):
102
252
  Returns:
103
253
  A dict.
104
254
 
@@ -132,21 +282,28 @@ def serialize(obj: SUPPORTED_TYPES, save_params: bool = False) -> dict:
132
282
  """
133
283
  if not isinstance(obj, get_args(SUPPORTED_TYPES)):
134
284
  logger.error(TypeError(f"Serialization of object type {type(obj)} not supported."))
135
- d: dict = {}
285
+
286
+ d: dict = dict()
136
287
  try:
137
- if isinstance(obj, Expr):
138
- symb_dict = {}
288
+ if isinstance(obj, core.Expr):
289
+ symb_dict = dict()
139
290
  expr_dict = {"name": str(obj), "expression": srepr(obj)}
140
- symbs: set[Parameter | Basic] = obj.free_symbols
291
+ symbs: set[Parameter | core.Basic] = obj.free_symbols
141
292
  if symbs:
142
293
  symb_dict = {"symbols": {str(s): s._to_dict() for s in symbs}}
143
294
  d = {**expr_dict, **symb_dict}
144
- elif isinstance(obj, (QuantumModel, QNN, TransformedModule)):
145
- d = obj._to_dict(save_params)
146
- elif isinstance(obj, torch.nn.Module):
147
- d = {type(obj).__name__: obj.state_dict()}
148
295
  else:
149
- d = obj._to_dict()
296
+ if hasattr(obj, "_to_dict"):
297
+ model_to_dict: Callable = obj._to_dict
298
+ d = (
299
+ model_to_dict(save_params)
300
+ if isinstance(obj, torch.nn.Module)
301
+ else model_to_dict()
302
+ )
303
+ elif hasattr(obj, "state_dict"):
304
+ d = {type(obj).__name__: obj.state_dict()}
305
+ else:
306
+ raise ValueError(f"Cannot serialize object {obj}.")
150
307
  except Exception as e:
151
308
  logger.error(f"Serialization of object {obj} failed due to {e}")
152
309
  return d
@@ -156,13 +313,14 @@ def deserialize(d: dict, as_torch: bool = False) -> SUPPORTED_TYPES:
156
313
  """
157
314
  Supported Types:
158
315
 
159
- AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | Module
316
+ AbstractBlock | QuantumCircuit | QuantumModel | Register | torch.nn.Module
160
317
  Deserializes a dict to one of the supported types.
161
318
 
162
319
  Arguments:
163
320
  d (dict): A dict containing a serialized object.
321
+ as_torch (bool): Whether to transform to torch for the deserialized object.
164
322
  Returns:
165
- AbstractBlock, QuantumCircuit, QuantumModel, TransformedModule, Register, Module.
323
+ AbstractBlock, QuantumCircuit, QuantumModel, Register, torch.nn.Module.
166
324
 
167
325
  Examples:
168
326
  ```python exec="on" source="material-block" result="json"
@@ -192,51 +350,18 @@ def deserialize(d: dict, as_torch: bool = False) -> SUPPORTED_TYPES:
192
350
  assert torch.isclose(qm.expectation({}), qm_deserialized.expectation({}))
193
351
  ```
194
352
  """
195
- obj: Any
353
+ obj: SerializationModel
196
354
  if d.get("expression"):
197
- expr = eval(d["expression"])
198
- if hasattr(expr, "free_symbols"):
199
- for symb in expr.free_symbols:
200
- symb.value = float(d["symbols"][symb.name]["value"])
201
- obj = expr
202
- elif d.get("QuantumModel"):
203
- obj = QuantumModel._from_dict(d, as_torch)
204
- elif d.get("QNN"):
205
- obj = QNN._from_dict(d, as_torch)
206
- elif d.get("TransformedModule"):
207
- obj = TransformedModule._from_dict(d, as_torch)
355
+ obj = ExpressionSerialization(d)
208
356
  elif d.get("block") and d.get("register"):
209
- obj = QuantumCircuit._from_dict(d)
357
+ obj = QuantumCircuitSerialization(d)
210
358
  elif d.get("graph"):
211
- obj = Register._from_dict(d)
359
+ obj = RegisterSerialization(d)
212
360
  elif d.get("type"):
213
- if d["type"] in ALL_BLOCK_NAMES:
214
- block: AbstractBlock = (
215
- getattr(operations, d["type"])._from_dict(d)
216
- if hasattr(operations, d["type"])
217
- else getattr(qadenceblocks, d["type"])._from_dict(d)
218
- )
219
- if d["tag"] is not None:
220
- block = tag(block, d["tag"])
221
- obj = block
361
+ obj = BlockTypeSerialization(d)
222
362
  else:
223
- import warnings
224
-
225
- msg = warnings.warn(
226
- "In order to load a custom torch.nn.Module, make sure its imported in the namespace."
227
- )
228
- try:
229
- module_name = list(d.keys())[0]
230
- obj = getattr(globals(), module_name)
231
- obj.load_state_dict(d[module_name])
232
- except Exception as e:
233
- logger.error(
234
- TypeError(
235
- f"{msg}. Unable to deserialize object due to {e}.\
236
- Supported objects are: {SUPPORTED_OBJECTS}"
237
- )
238
- )
239
- return obj
363
+ obj = ModelSerialization(d, as_torch=as_torch)
364
+ return obj.value
240
365
 
241
366
 
242
367
  def save(
qadence/utils.py CHANGED
@@ -154,11 +154,17 @@ def format_number(x: float | complex, num_digits: int = 3) -> str:
154
154
  raise ValueError(f"Unknown number type: {type(x)}")
155
155
 
156
156
 
157
- def format_parameter(p: sympy.Basic) -> str:
157
+ def format_parameter(p: sympy.Basic, num_digits: int = 3) -> str:
158
+ """Format numerical values within a sympy expression."""
159
+
158
160
  def round_expr(expr: sympy.Basic, num_digits: int) -> sympy.Basic:
159
161
  return expr.xreplace({n: round(n, num_digits) for n in expr.atoms(sympy.Number)})
160
162
 
161
- return str(round_expr(p, 3))
163
+ expr = round_expr(p, num_digits)
164
+ conv_str = str(expr)
165
+ if expr.is_real and len(conv_str) > num_digits + 2:
166
+ conv_str = conv_str[0 : num_digits + 2]
167
+ return conv_str
162
168
 
163
169
 
164
170
  def print_sympy_expr(expr: sympy.Expr, num_digits: int = 3) -> str:
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qadence
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: Pasqal interface for circuit-based quantum computing SDKs
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>
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>, Eduardo Maschio <eduardo.maschio@pasqal.com>
6
6
  License: Apache 2.0
7
7
  License-File: LICENSE
8
8
  Classifier: License :: OSI Approved :: Apache Software License
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: Implementation :: CPython
15
15
  Classifier: Programming Language :: Python :: Implementation :: PyPy
16
16
  Requires-Python: <3.13,>=3.9
17
+ Requires-Dist: arpeggio==2.0.2
17
18
  Requires-Dist: deepdiff
18
19
  Requires-Dist: jsonschema
19
20
  Requires-Dist: matplotlib
@@ -27,7 +28,7 @@ Requires-Dist: sympytorch>=0.1.2
27
28
  Requires-Dist: tensorboard>=2.12.0
28
29
  Requires-Dist: torch
29
30
  Provides-Extra: all
30
- Requires-Dist: amazon-braket-sdk; extra == 'all'
31
+ Requires-Dist: amazon-braket-sdk==1.71.0; extra == 'all'
31
32
  Requires-Dist: graphviz; extra == 'all'
32
33
  Requires-Dist: libs; extra == 'all'
33
34
  Requires-Dist: protocols; extra == 'all'
@@ -53,19 +54,21 @@ Provides-Extra: visualization
53
54
  Requires-Dist: graphviz; extra == 'visualization'
54
55
  Description-Content-Type: text/markdown
55
56
 
56
- <picture>
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">
60
- </picture>
57
+ <p align="center">
58
+ <picture>
59
+ <source media="(prefers-color-scheme: dark)" srcset="./docs/extras/assets/logo/qadence_logo_white.svg" width="75%">
60
+ <source media="(prefers-color-scheme: light)" srcset="./docs/extras/assets/logo/qadence_logo.svg" width="75%">
61
+ <img alt="Qadence logo" src="./docs/assets/logo/qadence_logo.svg" width="75%">
62
+ </picture>
63
+ </p>
64
+
65
+ **Qadence** is a Python package that provides a simple interface to build **digital-analog quantum
66
+ programs** with tunable qubit interactions and arbitrary register topologies realizable on neutral atom devices.
61
67
 
62
68
  **For a high-level overview of Qadence features, [check out our white paper](https://arxiv.org/abs/2401.09915).**
63
69
 
64
70
  **For more detailed information, [check out the documentation](https://pasqal-io.github.io/qadence/latest/).**
65
71
 
66
- **Qadence** is a Python package that provides a simple interface to build _**digital-analog quantum
67
- programs**_ with tunable qubit interaction defined on _**arbitrary register topologies**_ realizable on neutral atom devices.
68
-
69
72
  [![Linting](https://github.com/pasqal-io/qadence/actions/workflows/lint.yml/badge.svg)](https://github.com/pasqal-io/qadence/actions/workflows/lint.yml)
70
73
  [![Tests](https://github.com/pasqal-io/qadence/actions/workflows/test_fast.yml/badge.svg)](https://github.com/pasqal-io/qadence/actions/workflows/test_fast.yml)
71
74
  [![Documentation](https://github.com/pasqal-io/qadence/actions/workflows/build_docs.yml/badge.svg)](https://pasqal-io.github.io/qadence/latest)
@@ -74,27 +77,26 @@ programs**_ with tunable qubit interaction defined on _**arbitrary register topo
74
77
 
75
78
  ## Feature highlights
76
79
 
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
-
80
+ <p align="center">
81
+ <picture>
82
+ <source media="(prefers-color-scheme: dark)" srcset="./docs/extras/assets/qadence_arch.svg" width="75%">
83
+ <source media="(prefers-color-scheme: light)" srcset="./docs/extras/assets/qadence_arch.svg" width="75%">
84
+ <img alt="Qadence architecture" src="./docs/assets/qadence_arch.svg" width="75%">
85
+ </picture>
86
+ <p align="center">
83
87
 
84
- * A [block-based system](docs/tutorials/getting_started.md) for composing _**complex digital-analog
88
+ * A [block-based system](docs/content/block_system.md) for composing _**complex digital-analog
85
89
  programs**_ in a flexible and scalable manner, inspired by the Julia quantum SDK
86
90
  [Yao.jl](https://github.com/QuantumBFS/Yao.jl) and functional programming concepts.
87
91
 
88
- * A [simple interface](docs/digital_analog_qc/analog-basics.md) to work with _**interacting neutral-atom qubit systems**_
89
- using [arbitrary registers topologies](docs/tutorials/register.md).
90
-
91
- * An intuitive [expression-based system](docs/tutorials/parameters.md) developed on top of the symbolic library [Sympy](https://www.sympy.org/en/index.html) to construct _**parametric quantum programs**_ easily.
92
-
93
- * [High-order generalized parameter shift rules](docs/advanced_tutorials/differentiability.md) for _**differentiating parametrized quantum operations**_.
92
+ * An intuitive [expression-based system](docs/content/parameters.md) developed on top of the symbolic library [Sympy](https://www.sympy.org/en/index.html) to construct _**parametric quantum programs**_ easily.
94
93
 
95
94
  * Out-of-the-box _**automatic differentiability**_ of quantum programs with [PyTorch](https://pytorch.org/) integration.
96
95
 
97
- * _**Efficient execution**_ on a variety of different purpose backends: from state vector simulators to tensor network emulators and real devices.
96
+ * [High-order generalized parameter shift rules](docs/tutorials/advanced_tutorials/differentiability.md) for _**differentiating parametrized quantum operations**_.
97
+
98
+ * A [simple interface](docs/tutorials/digital_analog_qc/analog-basics.md) to work with _**interacting neutral-atom qubit systems**_
99
+ using [arbitrary registers topologies](docs/content/register.md).
98
100
 
99
101
  ## Installation guide
100
102
 
@@ -106,11 +108,10 @@ pip install qadence
106
108
 
107
109
  The default, pre-installed backend for Qadence is [PyQTorch](https://github.com/pasqal-io/pyqtorch), a differentiable state vector simulator for digital-analog simulation based on `PyTorch`. It is possible to install additional, `PyTorch` -based backends and the circuit visualization library using the following extras:
108
110
 
109
- * `pulser`: The [Pulser](https://github.com/pasqal-io/Pulser) backend for composing, simulating and executing pulse sequences for neutral-atom quantum devices.
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.
111
111
  * `visualization`: A visualization library to display quantum circuit diagrams.
112
112
  * `protocols`: A collection of [protocols](https://github.com/pasqal-io/qadence-protocols) for error mitigation in Qadence.
113
113
  * `libs`: A collection of [functionalities](https://github.com/pasqal-io/qadence-libs) for graph machine learning problems build on top of Qadence.
114
+ * `pulser`: The [Pulser](https://github.com/pasqal-io/Pulser) backend for composing, simulating and executing pulse sequences for neutral-atom quantum devices (experimental).
114
115
 
115
116
  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).
116
117
 
@@ -118,7 +119,7 @@ Qadence also supports a `JAX` engine which is currently supporting the [Horqrux]
118
119
  To install individual extras, use the following syntax (**IMPORTANT** Make sure to use quotes):
119
120
 
120
121
  ```bash
121
- pip install "qadence[braket,pulser,visualization]"
122
+ pip install "qadence[pulser,visualization]"
122
123
  ```
123
124
 
124
125
  To install all available extras, simply do:
@@ -144,10 +145,10 @@ conda install python-graphviz
144
145
 
145
146
  ## Contributing
146
147
 
147
- Before making a contribution, please review our [code of conduct](docs/CODE_OF_CONDUCT.md).
148
+ Before making a contribution, please review our [code of conduct](docs/getting_started/CODE_OF_CONDUCT.md).
148
149
 
149
150
  - **Submitting Issues:** To submit bug reports or feature requests, please use our [issue tracker](https://github.com/pasqal-io/qadence/issues).
150
- - **Developing in qadence:** To learn more about how to develop within `qadence`, please refer to [contributing guidelines](docs/CONTRIBUTING.md).
151
+ - **Developing in qadence:** To learn more about how to develop within `qadence`, please refer to [contributing guidelines](docs/getting_started/CONTRIBUTING.md).
151
152
 
152
153
  ### Setting up qadence in development mode
153
154
 
@@ -1,5 +1,5 @@
1
1
  qadence/__init__.py,sha256=-UKQQ_dYiaa7viishl2baAbxS82eS6dAoCnq_CLSmao,1708
2
- qadence/backend.py,sha256=5sfXUTRts_13v6lajq1Wvy3u_eOCOeIYnTiaZV_NGFQ,15493
2
+ qadence/backend.py,sha256=qxTCLfSqjtFAxlu3QgNj_npx_xbY9P2f3SP0mFkL-e8,14410
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
@@ -14,10 +14,11 @@ qadence/protocols.py,sha256=bcYTxSjgMPV-a-D6yv90jCpnGik8myzaNpFv9z1gzJ0,442
14
14
  qadence/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  qadence/qubit_support.py,sha256=Nkn1Q01RVViTcggSIom7EFKdWpAuM4TMGwBZ5feCUxA,2120
16
16
  qadence/register.py,sha256=cBMzwZ7GWZ5ieuFt0bpproEI6a2ncNwfjj7ic379zyg,10276
17
- qadence/serialization.py,sha256=BmBCFVAeLOL7KCYhUIN38cA43mA0tc5R7l0Fm2xtABU,11702
17
+ qadence/serial_expr_grammar.peg,sha256=z5ytL7do9kO8o4h-V5GrsDuLdso0KsRcMuIYURFfmAY,328
18
+ qadence/serialization.py,sha256=ra6oBB2KPDj0BlAL2fWqOSce9IBCfZuSKgFlh0Zjv-A,15695
18
19
  qadence/states.py,sha256=_J__vZuDPsKqKDFSCfgWxSNY2Ho6cCqTHjJ9-gMtd8M,14341
19
20
  qadence/types.py,sha256=cA3L3hlPW320_03n8_weCuAUXmDX5Jq3puawtkgOK7s,9699
20
- qadence/utils.py,sha256=c8qzsW1wtkBNhYW_aJwh40Jo9qqw6railN85KmTm7Qs,8829
21
+ qadence/utils.py,sha256=tSLXSt8pC1Oixs3gmgkAkHYG9MEH_Dfzyt6uxYfWhwg,9065
21
22
  qadence/analog/__init__.py,sha256=BCyS9R4KUjzUXN0Ax3b0eMo8ZAuSkGoJQVtZ4_pvAFs,279
22
23
  qadence/analog/addressing.py,sha256=fu5-xW9lquEbagApNp23S_ET1kl0iDtZUrIYSVNmw9s,6435
23
24
  qadence/analog/constants.py,sha256=B2phQoN1ASL8CwM-Dsa1rbraYwGwwPSeiB3HbVe-MPA,1243
@@ -31,15 +32,15 @@ qadence/backends/gpsr.py,sha256=227h5KPI_KStrwfP5zuwkzOqviRZmqa7ijIIhhawwPM,4341
31
32
  qadence/backends/jax_utils.py,sha256=VfKhqCKknHDWZO21UFipWH_Lkiq175Z5GkP49gWjbyw,5038
32
33
  qadence/backends/utils.py,sha256=hnV9AXztMvAPcO8mv9UhdGMbS9albiMQBxlYPgLrD68,6490
33
34
  qadence/backends/braket/__init__.py,sha256=eruyDZKMqkh1LE7eJ980vcrLJbia35uUX6krAP78clI,121
34
- qadence/backends/braket/backend.py,sha256=PLW-NCNp_RqAQy149ASEOOvwPrLsFGjCKWuEmTnS5Qg,8730
35
+ qadence/backends/braket/backend.py,sha256=XRrrkdylsH8GejbtY8fSJMmX2X7xWmZmEZPxcqWWM5E,8729
35
36
  qadence/backends/braket/config.py,sha256=b9aIdma0DRwC_3A6xUSLdXMCZe6z6kDcAgkp6MxcXIk,603
36
37
  qadence/backends/braket/convert_ops.py,sha256=DVXV7sT9sX_yGOgPKclD9KIGgmbBRuDy_e39i1Z8I1s,3417
37
38
  qadence/backends/horqrux/__init__.py,sha256=0OdVy6cq0oQggV48LO1WXdaZuSkDkz7OYNEPIkNAmfk,140
38
- qadence/backends/horqrux/backend.py,sha256=qdThkUXbhDrsD1lAio2SFsxdYATxLVXoNsuXNcD3ZBU,9330
39
+ qadence/backends/horqrux/backend.py,sha256=ZOkkklcqqM0T5CTwfSpNAAcW_a0l922h48gj6kPNw4I,9329
39
40
  qadence/backends/horqrux/config.py,sha256=fPWFag1hmRhqj0T-fJOx5x8_C5UEZUXpdUnpOgX0Jpc,901
40
41
  qadence/backends/horqrux/convert_ops.py,sha256=nzfYF0yjB7zwaHCEXWZUUYDfz38Yi22xF2zDRFaOwR0,8564
41
42
  qadence/backends/pulser/__init__.py,sha256=capQ-eHqwtOeLf4mWsI0BIseAHhiLGie5cFD4-iVhUo,116
42
- qadence/backends/pulser/backend.py,sha256=3p9cB5QN60nzqhWvdLZol0t66PugaWqvWHdDEXgGRwM,13868
43
+ qadence/backends/pulser/backend.py,sha256=ZxGg9zLyGTg3gJAZXTL7b96PHvhmN5D4yOAAdnVgLu4,13867
43
44
  qadence/backends/pulser/channels.py,sha256=ZF0yEXUFHAmi3IdeXjzdTNGR5NzaRRFTiUpUGVg2sO4,329
44
45
  qadence/backends/pulser/cloud.py,sha256=0uUluvbFV9sOuCPraE-9uiVtC3Q8QaDY1IJMDi8grDM,2057
45
46
  qadence/backends/pulser/config.py,sha256=1qu_GhGTGcCpFoKctGt_IhKOKWiMcJIL2vHTFJg9I3E,3122
@@ -48,7 +49,7 @@ qadence/backends/pulser/devices.py,sha256=DermLZNfmCB3SqteKVW4uhg4jp6ya1G6ptnXbB
48
49
  qadence/backends/pulser/pulses.py,sha256=DopdEZ8eeWK7wZxqJTBhqY0w5bEXu6fVK7rnZOb50ns,11893
49
50
  qadence/backends/pulser/waveforms.py,sha256=0uz95b7rUaUUtN0tuHBZmJ0H6UBmfHST_59ozwsRCzg,2227
50
51
  qadence/backends/pyqtorch/__init__.py,sha256=0OdVy6cq0oQggV48LO1WXdaZuSkDkz7OYNEPIkNAmfk,140
51
- qadence/backends/pyqtorch/backend.py,sha256=hNo9nKxfJ3rFDEPjZOhfmbKUUVsNzTl0aRh9sgeKlqc,9763
52
+ qadence/backends/pyqtorch/backend.py,sha256=eaC-yV-Ckgq6YCq1UrrOh6Ug_vFHmUR43RQBiXfcv1Q,9762
52
53
  qadence/backends/pyqtorch/config.py,sha256=f5BjWehCqm9do2OahNWrv2w55y3orkw0Wj2f6flwRaU,1907
53
54
  qadence/backends/pyqtorch/convert_ops.py,sha256=By_p1-Oem8MhHYP8jx5qdut9lhDWN0xc4B9YaP0MSxA,17512
54
55
  qadence/blocks/__init__.py,sha256=H6jEA_CptkE-eoB4UfSbUiDszbxxhZwECV_TgoZWXoU,960
@@ -105,18 +106,18 @@ qadence/mitigations/readout.py,sha256=HPfYmdjRlieUdOBMZTghFK4DRWfveM4KkDkEI0bMI0
105
106
  qadence/ml_tools/__init__.py,sha256=_H5A_BWZRZVGoJszb9s8XRJnLnJxUNfYjuT9HT2yASo,786
106
107
  qadence/ml_tools/config.py,sha256=X8dHyjq4D9-ITjs7UQo0vjJTcHkpbZC0gChH5eEN2G8,2356
107
108
  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/models.py,sha256=-9XOmMRXQDI5fAjlrqlSGI7vCV3DKJVmRdngu98QroM,12476
109
110
  qadence/ml_tools/optimize_step.py,sha256=ATXWmAqybJVK3QmAaDqVXB5mxjTo2MIi_e0a5WSPFpc,1800
110
111
  qadence/ml_tools/parameters.py,sha256=gew2Kq_5-RgRpaTvs8eauVhgo0sTqqDQEV6WHFEiLGM,1301
111
112
  qadence/ml_tools/printing.py,sha256=kwwD9yLVqezaqWX5OAsXr8GLdJUnGrY-t5SnoKHtl9g,707
112
113
  qadence/ml_tools/saveload.py,sha256=Xi3o2bMsYueFPxrU6AXgDB0MHSev8gKLVhdqecPDBt8,4663
113
114
  qadence/ml_tools/tensors.py,sha256=xZ9ZRzOqEaMgLUGWQf1najDmL6iLuN1ojCGVFs1Tm94,1337
114
- qadence/ml_tools/train_grad.py,sha256=b_FxOkK3QoLAOwSowjkkMIjlBEDjoLcjeo3Vk_RHhkc,7399
115
+ qadence/ml_tools/train_grad.py,sha256=zNzkgK73OtIllc8JLTqaM8P9m233BGa116HelsQBQqU,7727
115
116
  qadence/ml_tools/train_no_grad.py,sha256=erwus-pUOg8q6WgoQsDW6MeH80wlRPBh69W1ZMHKoL8,4714
116
117
  qadence/ml_tools/utils.py,sha256=_GZSN5Flk1nRFutkXih397Q3cWKdX0UP8c9CRXpUL7c,1654
117
118
  qadence/models/__init__.py,sha256=0nZzAC2TGr8Yuf40-R7m2cSsr_BlNq_GsMOwaOYZLqM,193
118
119
  qadence/models/qnn.py,sha256=gc_iC1GG6WJbeLaln9jy4yYp9fY0p8fkpKkKJpXJ3ck,10397
119
- qadence/models/quantum_model.py,sha256=ucExUBPBYWrC7mLF4SQbvHqjdXmkEi7-wIdXqpfaGew,14107
120
+ qadence/models/quantum_model.py,sha256=SetO2TPd9pe2QcNCcfdHKtGM1Rj-bhCTOsaExq7smnY,14186
120
121
  qadence/noise/__init__.py,sha256=r0nR8uEZeB1M9pI2UisjWq0bjw50fPFfVGzIMev923g,147
121
122
  qadence/noise/protocols.py,sha256=-aZ06JvMnpxCeT5v5lI_RNPOLbb9Ju1Pi1AB6uAXxVE,1653
122
123
  qadence/noise/readout.py,sha256=BqBIZbPXWqZaKi6EpBSpXXQ9NhQXdQ-YL6ZmwbSjgfE,6736
@@ -134,7 +135,7 @@ qadence/transpile/digitalize.py,sha256=iWRwYAYQsD2INHj0HNbGJriv_3fRCuBW1nDBrwtKS
134
135
  qadence/transpile/flatten.py,sha256=EdhSG5WyF56nbnxINNLqrHgY84MRM1YFjT3fR4aph5Q,3427
135
136
  qadence/transpile/invert.py,sha256=KAefHTG2AWr39aengVhXrzCtJPhrZC-ZnL6vYvmbnY0,4867
136
137
  qadence/transpile/transpile.py,sha256=6MRRkk1OS279L1fwUQjazA6qlfpbd-T_EJMKT8hAhOU,2721
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,,
138
+ qadence-1.5.2.dist-info/METADATA,sha256=19euItyRCLcNIYDi0bnc0RRw4eJBL7_zFAI6A7aW9xo,8931
139
+ qadence-1.5.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
140
+ qadence-1.5.2.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
141
+ qadence-1.5.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.22.4
2
+ Generator: hatchling 1.24.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any