classiq 0.91.1__py3-none-any.whl → 0.93.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. classiq/__init__.py +13 -0
  2. classiq/_internals/config.py +1 -1
  3. classiq/analyzer/show_interactive_hack.py +1 -1
  4. classiq/applications/__init__.py +2 -6
  5. classiq/applications/qsp/__init__.py +7 -0
  6. classiq/applications/qsp/qsp.py +366 -0
  7. classiq/evaluators/parameter_types.py +13 -7
  8. classiq/execution/jobs.py +18 -8
  9. classiq/interface/_version.py +1 -1
  10. classiq/interface/backend/backend_preferences.py +8 -8
  11. classiq/interface/exceptions.py +4 -0
  12. classiq/interface/executor/result.py +4 -0
  13. classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
  14. classiq/interface/generator/generated_circuit_data.py +5 -17
  15. classiq/interface/generator/transpiler_basis_gates.py +1 -1
  16. classiq/interface/helpers/versioned_model.py +0 -2
  17. classiq/interface/interface_version.py +1 -1
  18. classiq/interface/model/bind_operation.py +0 -12
  19. classiq/interface/model/handle_binding.py +3 -0
  20. classiq/interface/model/skip_control.py +11 -0
  21. classiq/interface/model/statement_block.py +3 -0
  22. classiq/interface/server/routes.py +0 -3
  23. classiq/model_expansions/interpreters/generative_interpreter.py +18 -1
  24. classiq/model_expansions/quantum_operations/assignment_result_processor.py +6 -0
  25. classiq/model_expansions/quantum_operations/bind.py +14 -0
  26. classiq/model_expansions/quantum_operations/skip_control_verifier.py +20 -0
  27. classiq/model_expansions/quantum_operations/variable_decleration.py +59 -27
  28. classiq/open_library/functions/__init__.py +2 -0
  29. classiq/open_library/functions/discrete_sine_cosine_transform.py +15 -10
  30. classiq/open_library/functions/qsvt.py +60 -6
  31. classiq/qmod/builtins/operations.py +24 -0
  32. classiq/qmod/classical_variable.py +4 -2
  33. classiq/qmod/native/pretty_printer.py +8 -0
  34. classiq/qmod/pretty_print/pretty_printer.py +5 -0
  35. classiq/qmod/quantum_expandable.py +31 -15
  36. classiq/qmod/symbolic_expr.py +12 -4
  37. classiq/synthesis.py +1 -1
  38. {classiq-0.91.1.dist-info → classiq-0.93.0.dist-info}/METADATA +39 -34
  39. {classiq-0.91.1.dist-info → classiq-0.93.0.dist-info}/RECORD +41 -37
  40. classiq-0.93.0.dist-info/WHEEL +4 -0
  41. classiq-0.93.0.dist-info/licenses/LICENSE.txt +27 -0
  42. classiq/interface/ide/ide_data.py +0 -102
  43. classiq-0.91.1.dist-info/WHEEL +0 -4
classiq/__init__.py CHANGED
@@ -1,5 +1,18 @@
1
1
  """Classiq SDK."""
2
2
 
3
+ import sys
4
+ import warnings
5
+
6
+ from classiq.interface.exceptions import ClassiqDeprecationWarning
7
+
8
+ if sys.version_info[0:2] <= (3, 9):
9
+ warnings.warn(
10
+ "Python version 3.9 will no longer be supported starting on 2025-10-01 "
11
+ "at the earliest",
12
+ ClassiqDeprecationWarning,
13
+ stacklevel=2,
14
+ )
15
+
3
16
  from classiq.interface._version import VERSION as _VERSION
4
17
  from classiq.interface.generator.application_apis import * # noqa: F403
5
18
  from classiq.interface.generator.arith.register_user_input import (
@@ -11,7 +11,7 @@ from pydantic import BaseModel
11
11
  from classiq.interface.enum_utils import StrEnum
12
12
  from classiq.interface.server.routes import DEFAULT_IDE_FE_APP
13
13
 
14
- DEFAULT_HOST = "https://api.classiq.io"
14
+ DEFAULT_HOST = "https://platform.classiq.io"
15
15
 
16
16
 
17
17
  class SDKMode(StrEnum):
@@ -36,7 +36,7 @@ def get_app_url(
36
36
  client_ide_base_url(),
37
37
  circuit_page_uri(
38
38
  circuit_id=data_id.id,
39
- circuit_version=circuit.version,
39
+ circuit_version=circuit.interface_version,
40
40
  include_query=include_query,
41
41
  ),
42
42
  )
@@ -1,10 +1,6 @@
1
- from classiq.applications import chemistry, combinatorial_optimization, qsvm
1
+ from classiq.applications import chemistry, combinatorial_optimization, qsp, qsvm
2
2
 
3
- __all__ = [
4
- "chemistry",
5
- "combinatorial_optimization",
6
- "qsvm",
7
- ]
3
+ __all__ = ["chemistry", "combinatorial_optimization", "qsp", "qsvm"]
8
4
 
9
5
 
10
6
  _NON_IMPORTED_PUBLIC_SUBMODULES = ["qnn"]
@@ -0,0 +1,7 @@
1
+ from .qsp import gqsp_phases, qsp_approximate, qsvt_phases
2
+
3
+ __all__ = ["gqsp_phases", "qsp_approximate", "qsvt_phases"]
4
+
5
+
6
+ def __dir__() -> list[str]:
7
+ return __all__
@@ -0,0 +1,366 @@
1
+ import builtins
2
+ import importlib.util
3
+ from functools import wraps
4
+ from typing import Callable, Optional
5
+
6
+ import numpy as np
7
+ from matplotlib import pyplot as plt
8
+ from numpy.polynomial import Chebyshev, Polynomial
9
+ from numpy.polynomial.chebyshev import cheb2poly, poly2cheb
10
+
11
+
12
+ def _require_qsp() -> None:
13
+ missing = [m for m in ("cvxpy", "pyqsp") if importlib.util.find_spec(m) is None]
14
+ if missing:
15
+ raise RuntimeError(
16
+ "This feature needs the 'qsp' extra."
17
+ "Install with: pip install classiq[qsp]"
18
+ f"(missing: {', '.join(missing)})"
19
+ )
20
+
21
+
22
+ def silence(func: Callable) -> Callable:
23
+ @wraps(func)
24
+ def wrapper(*args, **kwargs): # type:ignore[no-untyped-def]
25
+ try:
26
+ original_print = print
27
+ builtins.print = lambda *a, **k: None
28
+
29
+ result = func(*args, **kwargs)
30
+ finally:
31
+ builtins.print = original_print
32
+ return result
33
+
34
+ return wrapper
35
+
36
+
37
+ @silence
38
+ def _pyqsp_get_phases(
39
+ poly_coeffs: np.ndarray, tol: float = 1e-12
40
+ ) -> tuple[np.ndarray, float]:
41
+ from pyqsp.sym_qsp_opt import newton_solver # type:ignore[import]
42
+
43
+ parity = (len(poly_coeffs) + 1) % 2
44
+ reduced_coefs = poly_coeffs[parity::2]
45
+ _phases, err, _tot_iter, opt = newton_solver(reduced_coefs, parity, crit=tol)
46
+ return opt.full_phases, err
47
+
48
+
49
+ def qsvt_phases(
50
+ poly_coeffs: np.ndarray, cheb_basis: bool = True, tol: float = 1e-12
51
+ ) -> np.ndarray:
52
+ r"""
53
+ Get QSVT phases that will generate the given Chebyshev polynomial.
54
+ The phases are ready to be used in `qsvt` and `qsvt_lcu` functions in the classiq library. The convetion
55
+ is the reflection signal operator, and the measurement basis is the hadamard basis (see https://arxiv.org/abs/2105.02859
56
+ APPENDIX A.).
57
+ The current implementation is using the pyqsp package, based on techniques in https://arxiv.org/abs/2003.02831.
58
+
59
+ Notes:
60
+ 1. The polynomial should have a definite parity, and bounded in magnitude by 1 in the interval [-1, 1].
61
+ 2. The phase finding works in the Chebyshev basis. If the a monomial basis polynomial is provided,
62
+ it will be converted to the chebyshev basis (and introduce an additional overhead).
63
+ 3. The user is advised to get the polynomial using the `qsp_approximate` function.
64
+ 4. If the function fails, try to scale down the polynomial by a factor, it should ease the angle finding.
65
+
66
+ Args:
67
+ poly_coeffs: Array of polynomial coefficients (Chebyshev\Monomial, depending on cheb_basis).
68
+ cheb_basis: Whether the poly coefficients are given in Chebyshev (True) or Monomial(False). Defaults to Chebyshev.
69
+ tol: Error tolerance for the phases.
70
+ Returns:
71
+ phases: array of the qsvt phases corresponding to the given polynomial.
72
+ """
73
+ _require_qsp()
74
+
75
+ assert poly_coeffs is not None
76
+ assert len(poly_coeffs) > 1, "polynomial should have degree >= 1"
77
+
78
+ # verify parity
79
+ is_even = np.sum(np.abs(poly_coeffs[0::2])) > 1e-8
80
+ is_odd = np.sum(np.abs(poly_coeffs[1::2])) > 1e-8
81
+ assert is_even or is_odd, "Polynomial should have a definite parity"
82
+
83
+ poly_coeffs = np.array(np.trim_zeros(poly_coeffs, "b"))
84
+
85
+ if not cheb_basis:
86
+ poly_coeffs = poly2cheb(poly_coeffs)
87
+
88
+ # heuristic bound verification
89
+ grid = np.linspace(-1, 1, 1000)
90
+ assert (
91
+ np.max(np.abs(Chebyshev(poly_coeffs)(grid))) <= 1
92
+ ), "polynomial should be bounded in magnitude by 1"
93
+
94
+ # get the phases using pyqsp
95
+ phases, err = _pyqsp_get_phases(poly_coeffs, tol)
96
+ if err > tol:
97
+ raise RuntimeError(
98
+ f"Phase finding did not meet target tolerance "
99
+ f"(target={tol:.3e}, achieved={err:.3e}). "
100
+ "Consider increasing the degree, relaxing tol, or changing solver settings."
101
+ )
102
+
103
+ # verify conventions.
104
+ ## change the R(x) to W(x), as the phases are in the W(x) conventions
105
+ ## minus is due to exp(-i*phi*z) in qsvt in comparison to qsp
106
+ phases[1:-1] = phases[1:-1] - np.pi / 2
107
+ phases[0] = phases[0] - np.pi / 4
108
+ phases[-1] = phases[-1] + (2 * (len(phases) - 1) - 1) * np.pi / 4
109
+
110
+ ## the symmetric method creates the polynomial on Im[P(x)] with Im[Q(x)]=0, so adjust the phases
111
+ ## to extract that (equivalent to applying S on the auxiliary after the first H and before the last H)
112
+ phases[0] -= np.pi / 4
113
+ phases[-1] -= np.pi / 4
114
+
115
+ ## multiply by 2 as RZ(theta) = exp(-i*theta/2)
116
+ phases = -2 * phases
117
+ return phases
118
+
119
+
120
+ def _plot_qsp_approx(
121
+ poly_cheb: np.ndarray,
122
+ f_target: Callable[[np.ndarray], np.ndarray],
123
+ interval: tuple[float, float] = (-1, 1),
124
+ ) -> None:
125
+ grid_full = np.linspace(-1, 1, 3000)
126
+ grid_interval = np.linspace(interval[0], interval[1], 3000)
127
+
128
+ y_target = f_target(grid_interval)
129
+ y_approx = np.polynomial.Chebyshev(poly_cheb)(grid_full)
130
+
131
+ # Plot
132
+ plt.figure(figsize=(10, 5))
133
+ plt.plot(grid_interval, y_target, label="Target function", linewidth=4)
134
+ plt.plot(
135
+ grid_full,
136
+ y_approx,
137
+ "--",
138
+ label="Polynomial approximation",
139
+ linewidth=2,
140
+ c="r",
141
+ )
142
+ plt.title("Polynomial Approximation vs Target Function")
143
+ plt.xlabel("x")
144
+ plt.ylabel("f(x)")
145
+ # Draw vertical lines
146
+ plt.axvline(interval[0], color="gray", linestyle=":", linewidth=3)
147
+ plt.axvline(interval[1], color="gray", linestyle=":", linewidth=3)
148
+
149
+ plt.legend()
150
+ plt.grid(True)
151
+ plt.show()
152
+
153
+
154
+ def qsp_approximate(
155
+ f_target: Callable[[np.ndarray], np.ndarray],
156
+ degree: int,
157
+ parity: Optional[int] = None,
158
+ interval: tuple[float, float] = (-1, 1),
159
+ bound: float = 0.99,
160
+ num_grid_points: Optional[int] = None,
161
+ plot: bool = False,
162
+ ) -> tuple[np.ndarray, float]:
163
+ """
164
+ Approximate the target function on the given (sub-)interval of [-1,1], using QSP-compatible chebyshev polynomials.
165
+ The approximating polynomial is enforced to |P(x)| <= bound on all of [-1,1].
166
+
167
+ Note: scaling f_target by a factor < 1 might help the convergence and also a later qsp phase factor finiding.
168
+
169
+ Args:
170
+ f_target: Real function to approximate within the given interval. Should be bounded by [-1, 1] in the given interval.
171
+ degree: Approximating polynomial degree.
172
+ parity: None - full polynomial, 0 - restrict to even polynomial, 1 - odd polynomial.
173
+ interval: sub interval of [-1, 1] to approximate the function within.
174
+ bound: global polynomial bound on [-1,1] (defaults to 0.99).
175
+ num_grid_points: sets the number of grid points used for the polynomial approximation (defaults to `max(2 * degree, 1000)`).
176
+ plot: A flag for plotting the resulting approximation vs the target function.
177
+
178
+ Returns:
179
+ coeffs: Array of Chebyshev coefficients. In case of definite parity, still a full coefficients array is returned.
180
+ max_error: (Approximated) maximum error between the target function and the approximating polynomial within the interval.
181
+ """
182
+ _require_qsp()
183
+ import cvxpy as cp # type:ignore[import]
184
+
185
+ if num_grid_points is None:
186
+ num_grid_points = max(2 * degree, 1000)
187
+ # Discretize [-1, 1] using the grid points (interpolants)
188
+ xj_full = np.cos(
189
+ np.pi * np.arange(num_grid_points) / (num_grid_points - 1)
190
+ ) # Chebyshev nodes on [-1, 1]
191
+
192
+ # Select grid points for the objective in [w_min, w_max]
193
+ xj_obj = xj_full[(xj_full >= interval[0]) & (xj_full <= interval[1])]
194
+
195
+ yj_obj = f_target(xj_obj)
196
+ # heuristic verification
197
+ bound = min(1, bound)
198
+ assert (
199
+ np.max(np.abs(yj_obj)) <= bound
200
+ ), f"f_target function values should be bounded in magnitude by bound={bound} within the interval:{interval}"
201
+
202
+ # Define the Chebyshev polynomials
203
+ con_mat = np.polynomial.chebyshev.chebvander(xj_full, degree)
204
+ obj_mat = np.polynomial.chebyshev.chebvander(xj_obj, degree)
205
+
206
+ # Choose which Chebyshev indices to use
207
+ if parity is None:
208
+ cols = np.arange(degree + 1) # full
209
+ elif parity == 0:
210
+ cols = np.arange(0, degree + 1, 2) # even T_0, T_2, ...
211
+ elif parity == 1:
212
+ cols = np.arange(1, degree + 1, 2) # odd T_1, T_3, ...
213
+ else:
214
+ raise ValueError("parity must be None, 0 (even), or 1 (odd)")
215
+
216
+ con_mat = con_mat[:, cols]
217
+ obj_mat = obj_mat[:, cols]
218
+
219
+ # Define optimization variables
220
+ c = cp.Variable(len(cols)) # Coefficients for Chebyshev polynomials
221
+ f_values_full = con_mat @ c
222
+ f_values_obj = obj_mat @ c
223
+
224
+ # Define the optimization problem
225
+ objective = cp.Minimize(cp.max(cp.abs(f_values_obj - yj_obj)))
226
+ constraints = [cp.abs(f_values_full) <= bound] # global bound
227
+ prob = cp.Problem(objective, constraints)
228
+
229
+ # Solve the optimization problem
230
+ prob.solve()
231
+
232
+ # Return coefficients, optimal value, and grid points
233
+ pcoeffs = np.zeros(degree + 1)
234
+ pcoeffs[cols] = c.value
235
+
236
+ if plot:
237
+ _plot_qsp_approx(pcoeffs, f_target, interval)
238
+
239
+ return pcoeffs, prob.value
240
+
241
+
242
+ def _gqsp_complementary_polynomial(poly_coeffs: np.ndarray) -> np.ndarray:
243
+ """
244
+ Given polynomial coefficients of a wanted P such that |P(e^{i*theta})| <= 1,
245
+ calculates the complementary polynomial Q for the GQSP protocol. The polynomials
246
+ should fulfil |P(e^{i*theta})|^2 + |Q(e^{i*theta})|^2<= 1
247
+
248
+ The Implementation is based on the paper https://arxiv.org/abs/2308.01501 Theorem 4.
249
+
250
+ Args:
251
+ poly_coeffs: polynomial coefficients of the P polynomial in the monomial basis.
252
+
253
+ Returns:
254
+ Q: the coefficient of the complementary Q polynomial in monomial basis.
255
+ """
256
+ degree = len(poly_coeffs) - 1
257
+
258
+ grid = np.exp(1j * np.linspace(0.0, 2.0 * np.pi, 2000))
259
+ p_z = Polynomial(poly_coeffs)(grid)
260
+ assert (
261
+ np.max(np.abs(p_z)) <= 1 + 1e-10
262
+ ), "P violates |P(e^{i*theta})| <= 1; cannot construct a complementary Q."
263
+
264
+ r = Polynomial.basis(degree) - Polynomial(poly_coeffs) * Polynomial(
265
+ np.conj(poly_coeffs[::-1])
266
+ )
267
+ roots = r.roots()
268
+
269
+ roots_circle = roots[np.isclose(np.abs(roots), 1)]
270
+ roots_out = roots[~np.isclose(np.abs(roots), 1)]
271
+ roots_large = roots_out[np.abs(roots_out) > 1]
272
+ roots_small = roots_out[np.abs(roots_out) < 1]
273
+
274
+ assert len(roots_small) + len(roots_large) + len(roots_circle) == 2 * (degree)
275
+
276
+ # assume the unit roots are with even multiplicity
277
+ roots_circle_halved = sorted(roots_circle)[::2]
278
+ q_roots = np.concatenate([roots_small, roots_circle_halved])
279
+
280
+ scale = np.sqrt(np.abs(np.prod(roots_large) * r.coef[-1]))
281
+ q = Polynomial.fromroots(q_roots) * scale
282
+
283
+ # verify the completion
284
+ q_z = q(grid)
285
+ if not np.allclose(np.square(np.abs(p_z)) + np.square(np.abs(q_z)), 1, atol=1e-3):
286
+ raise ValueError("Failed to Complete P")
287
+
288
+ return q.coef
289
+
290
+
291
+ def _r_rot(theta: float, phi: float) -> np.ndarray:
292
+ return np.array(
293
+ [
294
+ [np.exp(1j * (phi)) * np.cos(theta), np.exp(1j * (phi)) * np.sin(theta)],
295
+ [np.sin(theta), -np.cos(theta)],
296
+ ],
297
+ dtype=complex,
298
+ )
299
+
300
+
301
+ def gqsp_phases(
302
+ poly_coeffs: np.ndarray, cheb_basis: bool = False
303
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
304
+ """
305
+ Compute GQSP phases for a polynomial in the monomial (power) basis.
306
+
307
+ The returned phases are compatible with Classiq's `gqsp` function and use the Wz signal
308
+ operator convention.
309
+
310
+ Notes:
311
+ - The polynomial must be bounded on the unit circle:
312
+ |P(e^{i*theta})| <= 1 for all theta in [0, 2*pi).
313
+ - Laurent polynomials are supported by degree shifting. If
314
+ P(z) = sum_{k=m}^n c_k * z^k with m < 0, the phases correspond to the
315
+ degree-shifted polynomial z^{-m} * P(z) (so the minimal degree is zero).
316
+ - The phase finiding works in the monomial basis. If the a Chebyshev basis polynomial is provided,
317
+ it will be converted to the monomial basis (and introduce an additional overhead).
318
+
319
+ Args:
320
+ poly: array-like of complex, shape (d+1). Monomial coefficients in ascending
321
+ order: [c_0, c_1, ..., c_d].
322
+ cheb_basis: Whether the poly coefficients are given in Chebyshev (True) or Monomial(False). Defaults to Monomial.
323
+
324
+ Returns:
325
+ phases: tuple of np.ndarray (thetas, phis, lambdas), ready to use with `gqsp`.
326
+
327
+ Raises:
328
+ ValueError: if |P(e^{i*theta})| > 1 anywhere on the unit circle.
329
+ """
330
+ # remove redundant zeros at the end
331
+ poly_coeffs = np.array(np.trim_zeros(poly_coeffs, "b"))
332
+
333
+ # move to monomial basis if needed
334
+ if cheb_basis:
335
+ poly_coeffs = cheb2poly(poly_coeffs)
336
+
337
+ # verify the normalization
338
+ grid = np.exp(1j * np.linspace(0.0, 2.0 * np.pi, 2000))
339
+ p_z = Polynomial(poly_coeffs)(grid)
340
+ assert (
341
+ np.max(np.abs(p_z)) < 1 + 1e-10
342
+ ), "P violates |P(e^{i*theta})| <= 1; cannot create calculate gqsp phases."
343
+
344
+ # get complementary gqsp polynomial
345
+ comp = _gqsp_complementary_polynomial(poly_coeffs)
346
+
347
+ s = np.array([poly_coeffs, comp])
348
+ thetas, phis, lambdas = np.zeros((3, len(poly_coeffs)))
349
+
350
+ for i in reversed(range(len(poly_coeffs))):
351
+ p_i, q_i = s[:, i]
352
+ thetas[i] = np.arctan2(np.abs(q_i), np.abs(p_i))
353
+
354
+ phis[i] = (
355
+ 0
356
+ if np.isclose(np.abs([q_i, p_i]), 0, atol=1e-10).any()
357
+ else np.angle(p_i * np.conj(q_i))
358
+ )
359
+
360
+ if i == 0:
361
+ lambdas[i] = 0 if np.allclose(np.abs(q_i), 0) else np.angle(q_i)
362
+ else:
363
+ s = _r_rot(thetas[i], phis[i]).conj().T @ s
364
+ s = np.array([s[0][1 : i + 1], s[1][:i]])
365
+
366
+ return thetas, phis, lambdas
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, Union
1
+ from typing import TYPE_CHECKING, Any, NoReturn, Optional, TypeVar, Union
2
2
 
3
3
  import sympy
4
4
 
@@ -377,15 +377,21 @@ def _eval_expr(
377
377
  val = get_sympy_val(val)
378
378
  if expected_type is int and isinstance(val, float) and int(val) == val:
379
379
  val = int(val)
380
- if not isinstance(val, expected_type) and (
381
- not isinstance(val, QmodAnnotatedExpression)
382
- or not isinstance(val.get_type(val.root), expected_qmod_type)
383
- ):
380
+
381
+ failing_type: Optional[str] = None
382
+ if isinstance(val, QmodAnnotatedExpression):
383
+ val_type = val.get_type(val.root)
384
+ if not isinstance(val_type, expected_qmod_type):
385
+ failing_type = val_type.raw_qmod_type_name
386
+ elif not isinstance(val, expected_type):
387
+ failing_type = type(val).__name__
388
+ if failing_type is not None:
384
389
  raise ClassiqExpansionError(
385
390
  f"When inferring the type of parameter {param_name!r}: "
386
- f"{type_name} {attr_name} must be {expected_qmod_type.__name__}, got "
387
- f"{str(val)!r}"
391
+ f"{type_name} {attr_name} must be {expected_qmod_type().qmod_type_name}, "
392
+ f"got {str(val)!r} of type {failing_type}"
388
393
  )
394
+
389
395
  expr = Expression(expr=str(val))
390
396
  expr._evaluated_expr = EvaluatedExpression(value=val)
391
397
  return expr
classiq/execution/jobs.py CHANGED
@@ -1,3 +1,4 @@
1
+ import warnings
1
2
  import webbrowser
2
3
  from datetime import datetime
3
4
  from typing import Any, Optional, Union
@@ -167,11 +168,13 @@ class ExecutionJob:
167
168
  raise ClassiqExecutionResultError("sample")
168
169
 
169
170
  result = results[0].value
170
- if isinstance(result, ExecutionDetails):
171
- return result
172
171
  if isinstance(result, MultipleExecutionDetails) and len(result.details) == 1:
173
- return result.details[0]
174
- raise ClassiqExecutionResultError("sample")
172
+ result = result.details[0]
173
+ if not isinstance(result, ExecutionDetails):
174
+ raise ClassiqExecutionResultError("sample")
175
+ for warning_str in result.warnings:
176
+ warnings.warn(warning_str, stacklevel=2)
177
+ return result
175
178
 
176
179
  def get_batch_sample_result(
177
180
  self, _http_client: Optional[httpx.AsyncClient] = None
@@ -192,11 +195,18 @@ class ExecutionJob:
192
195
 
193
196
  result = results[0].value
194
197
  if isinstance(result, ExecutionDetails):
195
- return [result]
196
- if isinstance(result, MultipleExecutionDetails):
197
- return result.details
198
+ result_list = [result]
199
+ elif isinstance(result, MultipleExecutionDetails):
200
+ result_list = result.details
201
+ else:
202
+ raise ClassiqExecutionResultError("batch_sample")
198
203
 
199
- raise ClassiqExecutionResultError("batch_sample")
204
+ warning_strs = [
205
+ warning for result in result_list for warning in result.warnings
206
+ ]
207
+ for warning_str in warning_strs:
208
+ warnings.warn(warning_str, stacklevel=2)
209
+ return result_list
200
210
 
201
211
  def get_estimate_result(
202
212
  self, _http_client: Optional[httpx.AsyncClient] = None
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.91.1'
6
+ SEMVER_VERSION = '0.93.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -97,7 +97,7 @@ class AliceBobBackendPreferences(BackendPreferences):
97
97
  The API key required to access Alice&Bob's quantum hardware.
98
98
  - **Required**: Yes.
99
99
 
100
- For more details, refer to the [Alice&Bob Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/alice-and-bob-backends/).
100
+ For more details, refer to the [Alice&Bob Backend Documentation](https://docs.classiq.io/latest/sdk-reference/providers/Alice%20and%20Bob/).
101
101
  """
102
102
 
103
103
  backend_service_provider: ProviderTypeVendor.ALICE_BOB = pydantic.Field(
@@ -148,7 +148,7 @@ class ClassiqBackendPreferences(BackendPreferences):
148
148
  This class is used to configure the backend options for executing quantum circuits on Classiq's platform.
149
149
  The relevant backend names for Classiq targets are specified in `ClassiqSimulatorBackendNames` & `ClassiqNvidiaBackendNames`.
150
150
 
151
- For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/classiq-backends/).
151
+ For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/sdk-reference/providers/Classiq/).
152
152
  """
153
153
 
154
154
  backend_service_provider: ProviderTypeVendor.CLASSIQ = pydantic.Field(
@@ -187,7 +187,7 @@ class AwsBackendPreferences(BackendPreferences):
187
187
 
188
188
 
189
189
  For more details, refer to:
190
- [AwsBackendPreferences examples](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/amazon-backends/?h=awsbackend#usage)
190
+ [AwsBackendPreferences examples](https://docs.classiq.io/latest/sdk-reference/providers/AWS/)
191
191
  """
192
192
 
193
193
  backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET = pydantic.Field(
@@ -223,7 +223,7 @@ class IBMBackendPreferences(BackendPreferences):
223
223
  instance_crn (str): The IBM Cloud instance CRN (Cloud Resource Name) for the IBM Quantum service.
224
224
  run_through_classiq (bool): Run through Classiq's credentials. Defaults to `False`.
225
225
 
226
- See examples in the [IBM Quantum Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/ibm-backends/?h=).
226
+ See examples in the [IBM Quantum Backend Documentation](https://docs.classiq.io/latest/sdk-reference/providers/IBM/).
227
227
  """
228
228
 
229
229
  backend_service_provider: ProviderTypeVendor.IBM_CLOUD = pydantic.Field(
@@ -285,7 +285,7 @@ class AzureBackendPreferences(BackendPreferences):
285
285
  """
286
286
  This class inherits from BackendPreferences.
287
287
  This is where you specify Azure Quantum preferences.
288
- See usage in the [Azure Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/azure-backends/).
288
+ See usage in the [Azure Backend Documentation](https://docs.classiq.io/latest/sdk-reference/providers/Azure/).
289
289
 
290
290
  Attributes:
291
291
  location (str): Azure personal resource region. Defaults to `"East US"`.
@@ -337,7 +337,7 @@ class IonqBackendPreferences(BackendPreferences):
337
337
  error_mitigation (bool): A configuration option to enable or disable error mitigation during execution. Defaults to `False`.
338
338
  run_through_classiq (bool): Running through Classiq's credentials while using user's allocated budget.
339
339
 
340
- See examples in the [IonQ Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/ionq-backends/?h=).
340
+ See examples in the [IonQ Backend Documentation](https://docs.classiq.io/latest/sdk-reference/providers/IonQ/).
341
341
  """
342
342
 
343
343
  backend_service_provider: ProviderTypeVendor.IONQ = pydantic.Field(
@@ -366,7 +366,7 @@ class GCPBackendPreferences(BackendPreferences):
366
366
  backend_service_provider (ProviderTypeVendor.GOOGLE): Indicates the backend service provider as Google,
367
367
  specifically for quantum computing services on Google Cloud Platform (GCP).
368
368
 
369
- See examples in the [Google Cloud Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/google-backends/?h=).
369
+ See examples in the [Google Cloud Backend Documentation](https://docs.classiq.io/latest/sdk-reference/providers/GCP/).
370
370
  """
371
371
 
372
372
  backend_service_provider: ProviderTypeVendor.GOOGLE = pydantic.Field(
@@ -402,7 +402,7 @@ class IntelBackendPreferences(BackendPreferences):
402
402
  This class is used to configure the backend options for executing quantum circuits on Classiq's platform.
403
403
  The relevant backend names for Classiq targets are specified in `ClassiqSimulatorBackendNames` & `ClassiqNvidiaBackendNames`.
404
404
 
405
- For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/classiq-backends/).
405
+ For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/user-guide/execution/cloud-providers/intel-backends/?h=intel).
406
406
  """
407
407
 
408
408
  backend_service_provider: ProviderTypeVendor.INTEL = pydantic.Field(
@@ -66,6 +66,10 @@ class ClassiqValueError(ClassiqError, ValueError):
66
66
  pass
67
67
 
68
68
 
69
+ class ClassiqTypeError(ClassiqError, TypeError):
70
+ pass
71
+
72
+
69
73
  class ClassiqArithmeticError(ClassiqValueError):
70
74
  pass
71
75
 
@@ -247,6 +247,10 @@ class ExecutionDetails(BaseModel, QmodPyObject):
247
247
 
248
248
  output_type_map: RegisterQuantumTypeDict = pydantic.Field(default_factory=dict)
249
249
 
250
+ warnings: list[str] = pydantic.Field(
251
+ default_factory=list, description="A list of warning messages"
252
+ )
253
+
250
254
  @pydantic.field_validator("counts", mode="after")
251
255
  @classmethod
252
256
  def _clean_spaces_from_counts_keys(cls, v: Counts) -> Counts:
@@ -1,5 +1,6 @@
1
1
  CTRL_VAR_PREFIX = "ctrl__"
2
2
  CONTROL_OPERATOR_NAME = "control"
3
+ SKIP_CONTROL_OPERATOR_NAME = "skip_control"
3
4
  INVERT_OPERATOR_NAME = "invert"
4
5
  REPEAT_OPERATOR_NAME = "iteration"
5
6
  CLASSICAL_IF_OPERATOR_NAME = "classical_if"