classiq 0.87.0__py3-none-any.whl → 0.88.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.

Potentially problematic release.


This version of classiq might be problematic. Click here for more details.

Files changed (67) hide show
  1. classiq/applications/__init__.py +1 -2
  2. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
  3. classiq/applications/hamiltonian/pauli_decomposition.py +1 -1
  4. classiq/evaluators/qmod_annotated_expression.py +30 -7
  5. classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -5
  6. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +18 -11
  7. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +14 -7
  8. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +39 -16
  9. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +1 -1
  10. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +18 -8
  11. classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +8 -0
  12. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +4 -1
  13. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -1
  14. classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +1 -1
  15. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +3 -3
  16. classiq/evaluators/qmod_node_evaluators/utils.py +1 -1
  17. classiq/evaluators/qmod_type_inference/classical_type_inference.py +4 -4
  18. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +38 -0
  19. classiq/evaluators/type_type_match.py +1 -1
  20. classiq/execution/execution_session.py +17 -2
  21. classiq/interface/_version.py +1 -1
  22. classiq/interface/execution/primitives.py +1 -0
  23. classiq/interface/generator/application_apis/__init__.py +0 -1
  24. classiq/interface/generator/expressions/atomic_expression_functions.py +0 -2
  25. classiq/interface/generator/function_param_list.py +0 -4
  26. classiq/interface/generator/functions/classical_type.py +8 -0
  27. classiq/interface/generator/functions/type_name.py +6 -0
  28. classiq/interface/generator/transpiler_basis_gates.py +5 -1
  29. classiq/interface/generator/types/builtin_enum_declarations.py +0 -8
  30. classiq/interface/model/classical_if.py +16 -8
  31. classiq/interface/model/classical_parameter_declaration.py +4 -0
  32. classiq/interface/model/port_declaration.py +12 -0
  33. classiq/interface/model/quantum_function_declaration.py +12 -0
  34. classiq/interface/model/quantum_type.py +56 -0
  35. classiq/interface/pretty_print/expression_to_qmod.py +3 -17
  36. classiq/model_expansions/quantum_operations/allocate.py +1 -1
  37. classiq/model_expansions/quantum_operations/handle_evaluator.py +2 -8
  38. classiq/open_library/functions/__init__.py +1 -0
  39. classiq/open_library/functions/lcu.py +2 -2
  40. classiq/open_library/functions/state_preparation.py +47 -5
  41. classiq/qmod/builtins/__init__.py +0 -3
  42. classiq/qmod/builtins/classical_functions.py +0 -28
  43. classiq/qmod/builtins/enums.py +24 -18
  44. classiq/qmod/builtins/functions/__init__.py +0 -5
  45. classiq/qmod/builtins/operations.py +142 -0
  46. classiq/qmod/builtins/structs.py +0 -11
  47. classiq/qmod/native/pretty_printer.py +1 -1
  48. classiq/qmod/pretty_print/expression_to_python.py +3 -6
  49. classiq/qmod/pretty_print/pretty_printer.py +4 -1
  50. classiq/qmod/qmod_variable.py +94 -2
  51. classiq/qmod/semantics/annotation/call_annotation.py +4 -2
  52. classiq/qmod/semantics/annotation/qstruct_annotator.py +20 -5
  53. {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/METADATA +3 -3
  54. {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/RECORD +55 -67
  55. classiq/applications/finance/__init__.py +0 -15
  56. classiq/interface/finance/__init__.py +0 -0
  57. classiq/interface/finance/finance_modelling_params.py +0 -11
  58. classiq/interface/finance/function_input.py +0 -102
  59. classiq/interface/finance/gaussian_model_input.py +0 -50
  60. classiq/interface/finance/log_normal_model_input.py +0 -40
  61. classiq/interface/finance/model_input.py +0 -22
  62. classiq/interface/generator/application_apis/finance_declarations.py +0 -108
  63. classiq/interface/generator/expressions/enums/__init__.py +0 -0
  64. classiq/interface/generator/expressions/enums/finance_functions.py +0 -12
  65. classiq/interface/generator/finance.py +0 -107
  66. classiq/qmod/builtins/functions/finance.py +0 -34
  67. {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/WHEEL +0 -0
@@ -135,13 +135,6 @@ class FermionMapping(IntEnum):
135
135
  FAST_BRAVYI_KITAEV = 3
136
136
 
137
137
 
138
- class FinanceFunctionType(IntEnum):
139
- VAR = 0
140
- SHORTFALL = 1
141
- X_SQUARE = 2
142
- EUROPEAN_CALL_OPTION = 3
143
-
144
-
145
138
  class LadderOperator(IntEnum):
146
139
  PLUS = 0
147
140
  MINUS = 1
@@ -160,25 +153,39 @@ class Pauli(IntEnum):
160
153
  """
161
154
  Enumeration for the Pauli matrices used in quantum computing.
162
155
 
163
- The Pauli matrices are fundamental operations in quantum computing, and this
164
- enum assigns integer values to represent each matrix.
156
+ Represents the four Pauli matrices used in quantum mechanics: Identity (I), X, Y, and Z operators.
157
+ The Pauli matrices are defined as:
158
+
159
+ $$
160
+ I = \\begin{pmatrix} 1 & 0 \\\\ 0 & 1 \\end{pmatrix}
161
+ $$
162
+
163
+ $$
164
+ X = \\begin{pmatrix} 0 & 1 \\\\ 1 & 0 \\end{pmatrix}
165
+ $$
166
+
167
+ $$
168
+ Y = \\begin{pmatrix} 0 & -i \\\\ i & 0 \\end{pmatrix}
169
+ $$
170
+
171
+ $$
172
+ Z = \\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix}
173
+ $$
174
+
175
+ Attributes:
176
+ I (int): The identity operator (value 0).
177
+ X (int): The Pauli-X operator (value 1).
178
+ Y (int): The Pauli-Y operator (value 2).
179
+ Z (int): The Pauli-Z operator (value 3).
165
180
  """
166
181
 
167
182
  I = 0 # noqa: E741
168
- """I (int): Identity matrix, represented by the integer 0. \n
169
- $I = \\begin{bmatrix} 1 & 0 \\\\ 0 & 1 \\end{bmatrix}$"""
170
183
 
171
184
  X = 1
172
- """X (int): Pauli-X matrix, represented by the integer 1. \n
173
- $X = \\begin{bmatrix} 0 & 1 \\\\ 1 & 0 \\end{bmatrix}$"""
174
185
 
175
186
  Y = 2
176
- """Y (int): Pauli-Y matrix, represented by the integer 2. \n
177
- $Y = \\begin{bmatrix} 0 & -i \\\\ i & 0 \\end{bmatrix}$"""
178
187
 
179
188
  Z = 3
180
- """Z (int): Pauli-Z matrix, represented by the integer 3. \n
181
- $Z = \\begin{bmatrix} 1 & 0 \\\\ 0 & -1 \\end{bmatrix}$"""
182
189
 
183
190
  def __call__(self, index: int) -> "SparsePauliOp":
184
191
  from classiq.qmod.builtins.structs import (
@@ -224,7 +231,6 @@ BUILTIN_ENUM_DECLARATIONS = {
224
231
  __all__ = [
225
232
  "Element",
226
233
  "FermionMapping",
227
- "FinanceFunctionType",
228
234
  "LadderOperator",
229
235
  "Optimizer",
230
236
  "Pauli",
@@ -3,7 +3,6 @@ from .arithmetic import *
3
3
  from .benchmarking import *
4
4
  from .chemistry import *
5
5
  from .exponentiation import *
6
- from .finance import *
7
6
  from .mid_circuit_measurement import *
8
7
  from .operators import *
9
8
  from .qsvm import *
@@ -18,8 +17,6 @@ CORE_LIB_DECLS = [
18
17
  fock_hamiltonian_ucc,
19
18
  fock_hamiltonian_hva,
20
19
  fock_hamiltonian_hartree_fock,
21
- log_normal_finance,
22
- gaussian_finance,
23
20
  pauli_feature_map,
24
21
  bloch_sphere_feature_map,
25
22
  H,
@@ -121,13 +118,11 @@ __all__ = [ # noqa: RUF022
121
118
  "fock_hamiltonian_hva",
122
119
  "fock_hamiltonian_ucc",
123
120
  "free",
124
- "gaussian_finance",
125
121
  "inplace_prepare_amplitudes",
126
122
  "inplace_prepare_amplitudes_approx",
127
123
  "inplace_prepare_state",
128
124
  "inplace_prepare_state_approx",
129
125
  "integer_xor",
130
- "log_normal_finance",
131
126
  "modular_add",
132
127
  "modular_add_constant",
133
128
  "molecule_hartree_fock",
@@ -147,6 +147,22 @@ def bind(
147
147
  source: Union[Input[QVar], list[Input[QVar]]],
148
148
  destination: Union[Output[QVar], list[Output[QVar]]],
149
149
  ) -> None:
150
+ """
151
+ Reassign qubit or arrays of qubits by redirecting their logical identifiers.
152
+
153
+ This operation rewires the logical identity of the `source` qubits to new objects given in `destination`.
154
+ For example, an array of two qubits `X` can be mapped to individual qubits `Y` and `Z`.
155
+
156
+ Args:
157
+ source: A qubit or list of initialized qubits to reassign.
158
+ destination: A qubit or list of target qubits to bind to. Must match the number of qubits in `source`.
159
+
160
+ Notes:
161
+ - After this operation, `source` qubits are unbound and considered uninitialized.
162
+ - `source` and `destination` must be of the same length.
163
+
164
+ For more details, see [Qmod Reference](https://docs.classiq.io/latest/qmod-reference/language-reference/statements/bind).
165
+ """
150
166
  assert QCallable.CURRENT_EXPANDABLE is not None
151
167
  source_ref = get_source_ref(sys._getframe(1))
152
168
  if not isinstance(source, list):
@@ -168,6 +184,18 @@ def if_(
168
184
  then: Union[QCallable, Callable[[], Statements]],
169
185
  else_: Union[QCallable, Callable[[], Statements], int] = _MISSING_VALUE,
170
186
  ) -> None:
187
+ """
188
+ Conditionally executes quantum operations based on a symbolic or boolean expression.
189
+
190
+ This function defines classical control flow within a quantum program. It allows quantum operations to be
191
+ conditionally executed based on symbolic expressions - such as parameters used in variational algorithms,
192
+ loop indices, or other classical variables affecting quantum control flow.
193
+
194
+ Args:
195
+ condition: A symbolic or boolean expression evaluated at runtime to determine the execution path.
196
+ then: A quantum operation executed when `condition` evaluates to True.
197
+ else_: (Optional) A quantum operation executed when `condition` evaluates to False.
198
+ """
171
199
  _validate_operand(then)
172
200
  if else_ != _MISSING_VALUE:
173
201
  _validate_operand(else_)
@@ -193,6 +221,22 @@ def control(
193
221
  stmt_block: Union[QCallable, Callable[[], Statements]],
194
222
  else_block: Union[QCallable, Callable[[], Statements], None] = None,
195
223
  ) -> None:
224
+ """
225
+ Conditionally executes quantum operations based on the value of quantum variables or expressions.
226
+
227
+ This operation enables quantum control flow similar to classical `if` statements. It evaluates a quantum condition
228
+ and executes one of the provided quantum code blocks accordingly.
229
+
230
+ Args:
231
+ ctrl: A quantum control expression, which can be a logical expression, a single `QBit`, or a `QArray[QBit]`.
232
+ If `ctrl` is a logical expression, `stmt_block` is executed when it evaluates to `True`.
233
+ If `ctrl` is a `QBit` or `QArray[QBit]`, `stmt_block` is executed if all qubits are in the |1> state.
234
+ stmt_block: The quantum operations to execute when the condition holds. This can be a `QCallable` or a function
235
+ returning a `Statements` block.
236
+ else_block: (Optional) Quantum operations to execute when the condition does not hold.
237
+
238
+ For more details, see [Qmod Reference](https://docs.classiq.io/latest/qmod-reference/language-reference/statements/control).
239
+ """
196
240
  _validate_operand(stmt_block)
197
241
  assert QCallable.CURRENT_EXPANDABLE is not None
198
242
  source_ref = get_source_ref(sys._getframe(1))
@@ -308,6 +352,18 @@ def within_apply(
308
352
  within: Callable[[], Statements],
309
353
  apply: Callable[[], Statements],
310
354
  ) -> None:
355
+ r"""
356
+ Given two operations $U$ and $V$, performs the sequence of operations $U^{-1} V U$.
357
+
358
+ This operation is used to represent a sequence where the inverse gate `U^{-1}` is applied, followed by another operation `V`, and then `U` is applied to uncompute. This pattern is common in reversible
359
+ computation and quantum subroutines.
360
+
361
+ Args:
362
+ within: The unitary operation `U` to be computed and then uncomputed.
363
+ apply: The operation `V` to be applied within the `U` block.
364
+
365
+ For more details, see [Qmod Reference](https://docs.classiq.io/latest/qmod-reference/language-reference/statements/within-apply).
366
+ """
311
367
  _validate_operand(within)
312
368
  _validate_operand(apply)
313
369
  assert QCallable.CURRENT_EXPANDABLE is not None
@@ -327,6 +383,29 @@ def within_apply(
327
383
  def repeat(
328
384
  count: Union[SymbolicExpr, int], iteration: Callable[[int], Statements]
329
385
  ) -> None:
386
+ """
387
+ Executes a quantum loop a specified number of times, applying a quantum operation on each iteration.
388
+
389
+ This operation provides quantum control flow similar to a classical `for` loop, enabling repeated
390
+ application of quantum operations based on classical loop variables.
391
+
392
+ Args:
393
+ count: An integer or symbolic expression specifying the number of loop iterations.
394
+ iteration: A callable that takes a single integer index and returns the quantum operations to
395
+ be performed at each iteration.
396
+
397
+ Example:
398
+ ```python
399
+ from classiq import qfunc, Output, QArray, QBit, allocate, repeat, RX
400
+ from classiq.qmod.symbolic import pi
401
+
402
+
403
+ @qfunc
404
+ def main(x: Output[QArray[QBit]]):
405
+ allocate(10, x)
406
+ repeat(x.len, lambda i: RX(2 * pi * i / x.len, x[i]))
407
+ ```
408
+ """
330
409
  _validate_operand(iteration, num_params=1)
331
410
  assert QCallable.CURRENT_EXPANDABLE is not None
332
411
  source_ref = get_source_ref(sys._getframe(1))
@@ -362,6 +441,34 @@ def power(
362
441
  exponent: Union[SymbolicExpr, int],
363
442
  stmt_block: Union[QCallable, Callable[[], Statements]],
364
443
  ) -> None:
444
+ """
445
+ Apply a quantum operation raised to a symbolic or integer power.
446
+
447
+ This function enables exponentiation of a quantum gate, where the exponent can be a
448
+ symbolic expression or an integer. It is typically used within a quantum program
449
+ to repeat or scale quantum operations in a parameterized way.
450
+
451
+ Args:
452
+ exponent: The exponent value, either as an integer or a symbolic expression.
453
+ stmt_block: A callable that produces the quantum operation to be exponentiated.
454
+
455
+ Example:
456
+ ```python
457
+ from classiq import qfunc, Output, QArray, QBit, allocate, repeat, RX, power
458
+ from classiq.qmod.symbolic import pi
459
+
460
+
461
+ @qfunc
462
+ def my_RX(x: QArray[QBit], i: CInt):
463
+ RX(2 * pi / x.len, x[i])
464
+
465
+
466
+ @qfunc
467
+ def main(x: Output[QArray[QBit]]):
468
+ allocate(10, x)
469
+ repeat(x.len, lambda i: power(i, lambda: my_RX(x, i)))
470
+ ```
471
+ """
365
472
  _validate_operand(stmt_block)
366
473
  assert QCallable.CURRENT_EXPANDABLE is not None
367
474
  source_ref = get_source_ref(sys._getframe(1))
@@ -377,6 +484,27 @@ def power(
377
484
 
378
485
  @suppress_return_value
379
486
  def invert(stmt_block: Union[QCallable, Callable[[], Statements]]) -> None:
487
+ """
488
+ Apply the inverse of a quantum gate.
489
+
490
+ This function allows inversion of a quantum gate. It is typically used within a quantum program
491
+ to invert a sequence of operations.
492
+
493
+ Args:
494
+ stmt_block: A callable that produces the quantum operation to be inverted.
495
+
496
+ Example:
497
+ ```python
498
+ from classiq import qfunc, Output, QArray, QBit, allocate, qft, invert
499
+ from classiq.qmod.symbolic import pi
500
+
501
+
502
+ @qfunc
503
+ def main(x: Output[QArray[QBit]]):
504
+ allocate(10, x)
505
+ invert(qft(x))
506
+ ```
507
+ """
380
508
  _validate_operand(stmt_block)
381
509
  assert QCallable.CURRENT_EXPANDABLE is not None
382
510
  source_ref = get_source_ref(sys._getframe(1))
@@ -390,6 +518,20 @@ def invert(stmt_block: Union[QCallable, Callable[[], Statements]]) -> None:
390
518
 
391
519
  @suppress_return_value
392
520
  def phase(expr: SymbolicExpr, theta: float = 1.0) -> None:
521
+ """
522
+ Applies a state-dependent phase shift to the quantum state.
523
+
524
+ This operation multiplies each basis state |x> by a complex phase factor `theta * expr(x)`,
525
+ where `expr` is a symbolic expression dependent on the state value `x`, and `theta` is a scalar multiplier.
526
+
527
+ Args:
528
+ expr: A symbolic expression that evaluates to an angle (in radians) as a function of the quantum state value `x`.
529
+ theta: (Optional) A scalar multiplier for the evaluated expression. Defaults to 1.0.
530
+
531
+ Note:
532
+ The `phase` operation is equivalent to a Z-rotation up to a global phase. It is commonly used
533
+ to apply relative phase shifts conditioned on the quantum state.
534
+ """
393
535
  assert QCallable.CURRENT_EXPANDABLE is not None
394
536
  source_ref = get_source_ref(sys._getframe(1))
395
537
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
@@ -205,16 +205,6 @@ class LogNormalModel:
205
205
  sigma: CReal
206
206
 
207
207
 
208
- @dataclass
209
- class FinanceFunction:
210
- f: CInt
211
- threshold: CReal
212
- larger: CBool
213
- polynomial_degree: CInt
214
- use_chebyshev_polynomial_approximation: CBool
215
- tail_probability: CReal
216
-
217
-
218
208
  @dataclass
219
209
  class QsvmResult:
220
210
  test_score: CReal
@@ -246,7 +236,6 @@ BUILTIN_STRUCT_DECLARATIONS = {
246
236
  __all__ = [
247
237
  "ChemistryAtom",
248
238
  "CombinatorialOptimizationSolution",
249
- "FinanceFunction",
250
239
  "FockHamiltonianProblem",
251
240
  "GaussianModel",
252
241
  "IndexedPauli",
@@ -111,7 +111,7 @@ class DSLPrettyPrinter(ModelVisitor):
111
111
 
112
112
  def visit_Model(self, model: Model) -> str:
113
113
  # FIXME - CAD-20149: Remove this line once the froggies are removed, and the visit of lambdas can be done without accessing the func_decl property (with rename_params values only).
114
- resolve_function_calls(model, model.function_dict)
114
+ resolve_function_calls(model, model.function_dict, annotate_types=False)
115
115
  self._compilation_metadata = model.functions_compilation_metadata
116
116
 
117
117
  enum_decls = [self.visit(enum_decl) for enum_decl in model.enums]
@@ -154,12 +154,9 @@ class ASTToQMODCode(ast.NodeVisitor):
154
154
  )
155
155
  return f"{self.visit(node.args[0])}({initializer_list})"
156
156
  else:
157
- args = [self._cleaned_ast_to_code(arg) for arg in node.args]
158
- kwargs = [
159
- f"{kwarg.arg}={self._cleaned_ast_to_code(kwarg.value)}"
160
- for kwarg in node.keywords
161
- ]
162
- return "{}({})".format(func, ", ".join(args + kwargs))
157
+ return "{}({})".format(
158
+ func, ", ".join(self._cleaned_ast_to_code(arg) for arg in node.args)
159
+ )
163
160
 
164
161
  def visit_Expr(self, node: ast.Expr) -> str:
165
162
  return self._cleaned_ast_to_code(node.value)
@@ -303,10 +303,13 @@ class PythonPrettyPrinter(ModelVisitor):
303
303
  raise ClassiqInternalError
304
304
 
305
305
  is_unsigned = (
306
- is_signed_expr.is_evaluated() and not is_signed_expr.to_bool_value()
306
+ is_signed_expr.is_evaluated()
307
+ and is_signed_expr.is_constant()
308
+ and not is_signed_expr.to_bool_value()
307
309
  ) or is_signed_expr.expr == "UNSIGNED"
308
310
  is_integer = (
309
311
  fraction_digits_expr.is_evaluated()
312
+ and fraction_digits_expr.is_constant()
310
313
  and fraction_digits_expr.to_int_value() == 0
311
314
  )
312
315
  if is_unsigned and is_integer:
@@ -63,7 +63,7 @@ from classiq.interface.model.quantum_type import (
63
63
  )
64
64
  from classiq.interface.source_reference import SourceReference
65
65
 
66
- from classiq.qmod.cparam import ArrayBase, CInt, CParamScalar
66
+ from classiq.qmod.cparam import ArrayBase, CBool, CInt, CParamScalar
67
67
  from classiq.qmod.generative import (
68
68
  generative_mode_context,
69
69
  interpret_expression,
@@ -270,6 +270,59 @@ class QScalar(QVar, SymbolicExpr):
270
270
 
271
271
 
272
272
  class QBit(QScalar):
273
+ """A type representing a single qubit.
274
+
275
+ `QBit` serves both as a placeholder for a temporary, non-allocated qubit
276
+ and as the type of an allocated physical or logical qubit.
277
+ Conceptually, a qubit is a two-level quantum system, described by the
278
+ superposition of the computational basis states:
279
+
280
+ $$
281
+ |0\\rangle = \\begin{pmatrix} 1 \\\\ 0 \\end{pmatrix},
282
+ \\quad
283
+ |1\\rangle = \\begin{pmatrix} 0 \\\\ 1 \\end{pmatrix}
284
+ $$
285
+
286
+ Therefore, a qubit state is a linear combination:
287
+
288
+ $$
289
+ |\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle,
290
+ $$
291
+
292
+ where \\( \\alpha \\) and \\( \\beta \\) are complex numbers satisfying:
293
+
294
+ $$
295
+ |\\alpha|^2 + |\\beta|^2 = 1.
296
+ $$
297
+
298
+ Typical usage includes:
299
+
300
+ - Representing an unallocated qubit before its allocation.
301
+ - Acting as the output type for a qubit or an allocated qubit in the main function after calling an allocation function.
302
+
303
+ Examples:
304
+
305
+ Example 1: Unallocated qubit:
306
+ ```python
307
+ @qfunc
308
+ def my_func(x1: QBit):
309
+ # Defining x2 as an unallocated qubit, binding it to declared qubit
310
+ x2 = QBit()
311
+ bind(x1, x2)
312
+ ```
313
+
314
+ Example 2, output type for a qubit:
315
+ ```python
316
+ def main(q: Output[QBit]):
317
+ allocate(1, q)
318
+ ```
319
+
320
+ Attributes:
321
+ None
322
+
323
+ For more details, see [Qmod Reference](https://docs.classiq.io/latest/qmod-reference/language-reference/quantum-types/#semantics).
324
+ """
325
+
273
326
  @classmethod
274
327
  def to_qvar(
275
328
  cls,
@@ -287,13 +340,52 @@ _P = ParamSpec("_P")
287
340
 
288
341
 
289
342
  class QNum(Generic[_P], QScalar):
343
+ """
344
+ QNum is a quantum variable that represents a numeric value, which can be either integer or fixed-point,
345
+ encoded within a quantum register. It consists of an array of qubits for quantum representation and
346
+ classical metadata (number of fraction digits, sign) to define its numeric behavior.
347
+
348
+ QNum enables numerical computation in quantum circuits, supporting both signed and unsigned
349
+ formats, as well as configurable fixed-point precision. It is a parameterizable scalar type,
350
+ meaning its behavior can depend on symbolic or compile-time values. The total number of
351
+ qubits (`size`) determines the resolution and range of representable values.
352
+
353
+ Args:
354
+ name (str, optional): Identifier for this quantum number.
355
+ size (int, CInt, optional): Number of qubits allocated for this number.
356
+ Must be defined if either `is_signed` or `fraction_digits` is set.
357
+ is_signed (Union[bool, Expression, SymbolicExpr], optional): Whether the number is signed (i.e., can be negative).
358
+ Can be defined by a bool variable, or an arithmetic expression.
359
+ Must be set in tandem with `fraction_digits`.
360
+ fraction_digits (Union[int, CInt, Expression], optional): Number of fractional binary digits.
361
+ Defines the fixed-point precision. Must be set along with `is_signed`.
362
+
363
+ Methods:
364
+ fraction_digits -> Union[CParamScalar, int]:
365
+ Property that retrieves the number of fractional digits. Defaults to 0 if not specified.
366
+
367
+ is_signed -> Union[CParamScalar, bool]:
368
+ Property that retrieves whether the number is signed. Defaults to unsigned if not specified.
369
+
370
+ Example:
371
+ Example 1
372
+ ```python
373
+ @qfunc
374
+ def main(x: Output[QNum], y: Output[QNum]):
375
+ x |= 3.5 # Allocate a quantum number
376
+ y |= 2 * x
377
+ ```
378
+
379
+ For more details, see [Qmod Reference](https://docs.classiq.io/latest/qmod-reference/language-reference/quantum-types/#semantics).
380
+ """
381
+
290
382
  CONSTRUCTOR_DEPTH: int = 3
291
383
 
292
384
  def __init__(
293
385
  self,
294
386
  name: Union[None, str, HandleBinding] = None,
295
387
  size: Union[int, CInt, Expression, SymbolicExpr, None] = None,
296
- is_signed: Union[bool, Expression, SymbolicExpr, None] = None,
388
+ is_signed: Union[bool, CBool, Expression, SymbolicExpr, None] = None,
297
389
  fraction_digits: Union[int, CInt, Expression, None] = None,
298
390
  _expr_str: Optional[str] = None,
299
391
  ):
@@ -82,6 +82,7 @@ class _CallLambdaAnnotator(ModelVisitor):
82
82
  def resolve_function_calls(
83
83
  root: Any,
84
84
  quantum_function_dict: Optional[Mapping[str, QuantumFunctionDeclaration]] = None,
85
+ annotate_types: bool = True,
85
86
  ) -> None:
86
87
  if quantum_function_dict is None:
87
88
  quantum_function_dict = {}
@@ -93,6 +94,7 @@ def resolve_function_calls(
93
94
  **quantum_function_dict,
94
95
  }
95
96
  with ErrorManager().ignore_errors_context():
96
- QStructAnnotator().visit(quantum_function_dict)
97
- QStructAnnotator().visit(root)
97
+ if annotate_types:
98
+ QStructAnnotator().visit(quantum_function_dict)
99
+ QStructAnnotator().visit(root)
98
100
  _CallLambdaAnnotator(all_functions).visit(root)
@@ -1,15 +1,30 @@
1
+ from classiq.interface.exceptions import ClassiqExpansionError
1
2
  from classiq.interface.generator.functions.type_name import TypeName
2
3
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
3
4
  from classiq.interface.model.model_visitor import ModelVisitor
4
5
 
6
+ from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
7
+ from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
5
8
  from classiq.qmod.model_state_container import QMODULE
6
9
 
10
+ IGNORED_MISSING_TYPES = {"MoleculeResult"}
11
+
7
12
 
8
13
  class QStructAnnotator(ModelVisitor):
9
14
  def __init__(self) -> None:
10
- self._visited: set[TypeName] = set()
15
+ self._visited: set[int] = set()
16
+ self._defined_type_names = (
17
+ set(QMODULE.enum_decls)
18
+ | set(QMODULE.type_decls)
19
+ | set(QMODULE.qstruct_decls)
20
+ | set(BUILTIN_STRUCT_DECLARATIONS)
21
+ | set(BUILTIN_ENUM_DECLARATIONS)
22
+ | IGNORED_MISSING_TYPES
23
+ )
11
24
 
12
25
  def visit_TypeName(self, type_name: TypeName) -> None:
26
+ if type_name.name not in self._defined_type_names:
27
+ raise ClassiqExpansionError(f"Undefined type {type_name.name}")
13
28
  self._annotate_quantum_struct(type_name)
14
29
  self._annotate_classical_struct(type_name)
15
30
 
@@ -17,13 +32,13 @@ class QStructAnnotator(ModelVisitor):
17
32
  if (
18
33
  type_name.has_classical_struct_decl
19
34
  or type_name.has_fields
20
- or type_name in self._visited
35
+ or id(type_name) in self._visited
21
36
  ):
22
37
  return
23
38
  decl = QMODULE.qstruct_decls.get(type_name.name)
24
39
  if decl is None:
25
40
  return
26
- self._visited.add(type_name)
41
+ self._visited.add(id(type_name))
27
42
  new_fields = {
28
43
  field_name: field_type.model_copy()
29
44
  for field_name, field_type in decl.fields.items()
@@ -37,13 +52,13 @@ class QStructAnnotator(ModelVisitor):
37
52
  if (
38
53
  type_name.has_classical_struct_decl
39
54
  or type_name.has_fields
40
- or type_name in self._visited
55
+ or id(type_name) in self._visited
41
56
  ):
42
57
  return
43
58
  decl = QMODULE.type_decls.get(type_name.name)
44
59
  if decl is None:
45
60
  return
46
- self._visited.add(type_name)
61
+ self._visited.add(id(type_name))
47
62
  new_fields = {
48
63
  field_name: field_type.model_copy(deep=True)
49
64
  for field_name, field_type in decl.variables.items()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: classiq
3
- Version: 0.87.0
3
+ Version: 0.88.0
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  License: Proprietary
6
6
  Keywords: quantum computing,quantum circuits,quantum algorithms,QAD,QDL
@@ -40,8 +40,8 @@ Requires-Dist: matplotlib (>=3.4.3,<4.0.0)
40
40
  Requires-Dist: networkx (>=3.2.0,<4.0.0)
41
41
  Requires-Dist: notebook ; extra == "analyzer-sdk"
42
42
  Requires-Dist: numexpr (>=2.7.3,<3.0.0)
43
- Requires-Dist: numpy (>=1.20.1,<2.0.0) ; python_version < "3.12"
44
- Requires-Dist: numpy (>=1.26.0,<2.0.0) ; python_version >= "3.12"
43
+ Requires-Dist: numpy (<3.0.0) ; python_version >= "3.10"
44
+ Requires-Dist: numpy (>=1.26.4,<2.0.0) ; python_version < "3.10"
45
45
  Requires-Dist: openfermion ; extra == "chemistry"
46
46
  Requires-Dist: openfermionpyscf ; extra == "chemistry"
47
47
  Requires-Dist: packaging (>=23.2,<24.0)