classiq 0.86.1__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 (131) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/applications/__init__.py +1 -2
  3. classiq/applications/chemistry/hartree_fock.py +5 -1
  4. classiq/applications/chemistry/op_utils.py +2 -2
  5. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
  6. classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
  7. classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
  8. classiq/applications/combinatorial_helpers/memory.py +4 -4
  9. classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
  10. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
  11. classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
  12. classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
  13. classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
  14. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
  15. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
  16. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
  17. classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
  18. classiq/applications/hamiltonian/pauli_decomposition.py +34 -2
  19. classiq/evaluators/argument_types.py +15 -6
  20. classiq/evaluators/parameter_types.py +43 -39
  21. classiq/evaluators/qmod_annotated_expression.py +117 -17
  22. classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
  23. classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -5
  24. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +66 -16
  25. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +48 -26
  26. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +65 -72
  27. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +13 -6
  28. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
  29. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +36 -19
  30. classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +17 -5
  31. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +24 -2
  32. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
  33. classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
  34. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
  35. classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
  36. classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +3 -4
  37. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +51 -24
  38. classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
  39. classiq/evaluators/qmod_node_evaluators/utils.py +28 -6
  40. classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
  41. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +330 -0
  42. classiq/evaluators/quantum_type_utils.py +0 -131
  43. classiq/evaluators/type_type_match.py +1 -1
  44. classiq/execution/execution_session.py +18 -3
  45. classiq/execution/qnn.py +4 -1
  46. classiq/execution/user_budgets.py +1 -1
  47. classiq/interface/_version.py +1 -1
  48. classiq/interface/backend/backend_preferences.py +10 -30
  49. classiq/interface/backend/quantum_backend_providers.py +63 -52
  50. classiq/interface/execution/primitives.py +1 -0
  51. classiq/interface/generator/application_apis/__init__.py +0 -1
  52. classiq/interface/generator/arith/binary_ops.py +107 -115
  53. classiq/interface/generator/arith/extremum_operations.py +33 -45
  54. classiq/interface/generator/arith/number_utils.py +4 -1
  55. classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
  56. classiq/interface/generator/compiler_keywords.py +2 -0
  57. classiq/interface/generator/expressions/atomic_expression_functions.py +0 -2
  58. classiq/interface/generator/function_param_list.py +129 -5
  59. classiq/interface/generator/functions/classical_type.py +67 -2
  60. classiq/interface/generator/functions/qmod_python_interface.py +15 -0
  61. classiq/interface/generator/functions/type_name.py +12 -0
  62. classiq/interface/generator/model/preferences/preferences.py +1 -17
  63. classiq/interface/generator/quantum_program.py +1 -13
  64. classiq/interface/generator/transpiler_basis_gates.py +5 -1
  65. classiq/interface/generator/types/builtin_enum_declarations.py +0 -8
  66. classiq/interface/helpers/model_normalizer.py +2 -2
  67. classiq/interface/helpers/text_utils.py +7 -2
  68. classiq/interface/interface_version.py +1 -1
  69. classiq/interface/model/classical_if.py +48 -0
  70. classiq/interface/model/classical_parameter_declaration.py +4 -0
  71. classiq/interface/model/handle_binding.py +28 -16
  72. classiq/interface/model/port_declaration.py +12 -0
  73. classiq/interface/model/quantum_function_declaration.py +12 -0
  74. classiq/interface/model/quantum_type.py +117 -2
  75. classiq/interface/pretty_print/expression_to_qmod.py +7 -8
  76. classiq/interface/pyomo_extension/__init__.py +0 -4
  77. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
  78. classiq/model_expansions/arithmetic.py +43 -1
  79. classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
  80. classiq/model_expansions/capturing/captured_vars.py +2 -5
  81. classiq/model_expansions/quantum_operations/allocate.py +23 -16
  82. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
  83. classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
  84. classiq/model_expansions/quantum_operations/bind.py +15 -7
  85. classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
  86. classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
  87. classiq/model_expansions/quantum_operations/handle_evaluator.py +2 -8
  88. classiq/open_library/functions/__init__.py +4 -0
  89. classiq/open_library/functions/lcu.py +117 -0
  90. classiq/open_library/functions/state_preparation.py +47 -5
  91. classiq/qmod/builtins/__init__.py +0 -3
  92. classiq/qmod/builtins/classical_functions.py +0 -28
  93. classiq/qmod/builtins/enums.py +26 -20
  94. classiq/qmod/builtins/functions/__init__.py +0 -5
  95. classiq/qmod/builtins/operations.py +142 -0
  96. classiq/qmod/builtins/structs.py +33 -29
  97. classiq/qmod/native/pretty_printer.py +1 -1
  98. classiq/qmod/pretty_print/expression_to_python.py +1 -6
  99. classiq/qmod/pretty_print/pretty_printer.py +4 -1
  100. classiq/qmod/qmod_variable.py +94 -2
  101. classiq/qmod/semantics/annotation/call_annotation.py +4 -2
  102. classiq/qmod/semantics/annotation/qstruct_annotator.py +20 -5
  103. {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/METADATA +5 -5
  104. {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/RECORD +106 -124
  105. classiq/applications/finance/__init__.py +0 -15
  106. classiq/interface/finance/finance_modelling_params.py +0 -11
  107. classiq/interface/finance/function_input.py +0 -102
  108. classiq/interface/finance/gaussian_model_input.py +0 -50
  109. classiq/interface/finance/log_normal_model_input.py +0 -40
  110. classiq/interface/finance/model_input.py +0 -22
  111. classiq/interface/generator/amplitude_estimation.py +0 -34
  112. classiq/interface/generator/application_apis/finance_declarations.py +0 -108
  113. classiq/interface/generator/expressions/enums/__init__.py +0 -0
  114. classiq/interface/generator/expressions/enums/finance_functions.py +0 -12
  115. classiq/interface/generator/finance.py +0 -107
  116. classiq/interface/generator/function_param_list_without_self_reference.py +0 -160
  117. classiq/interface/generator/grover_diffuser.py +0 -93
  118. classiq/interface/generator/grover_operator.py +0 -106
  119. classiq/interface/generator/oracles/__init__.py +0 -3
  120. classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
  121. classiq/interface/generator/oracles/custom_oracle.py +0 -65
  122. classiq/interface/generator/oracles/oracle_abc.py +0 -76
  123. classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
  124. classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
  125. classiq/interface/generator/qpe.py +0 -169
  126. classiq/interface/grover/__init__.py +0 -0
  127. classiq/interface/grover/grover_modelling_params.py +0 -13
  128. classiq/model_expansions/transformers/var_splitter.py +0 -224
  129. classiq/qmod/builtins/functions/finance.py +0 -34
  130. /classiq/{interface/finance → evaluators/qmod_type_inference}/__init__.py +0 -0
  131. {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/WHEEL +0 -0
@@ -54,38 +54,10 @@ def hypercube_entangler_graph(
54
54
  )
55
55
 
56
56
 
57
- def gaussian_finance_post_process(
58
- finance_model: GaussianModel,
59
- estimation_method: FinanceFunction,
60
- probability: CReal,
61
- ) -> CReal:
62
- return symbolic_function(
63
- finance_model,
64
- estimation_method,
65
- probability,
66
- return_type=CReal, # type:ignore[type-abstract]
67
- )
68
-
69
-
70
- def log_normal_finance_post_process(
71
- finance_model: LogNormalModel,
72
- estimation_method: FinanceFunction,
73
- probability: CReal,
74
- ) -> CReal:
75
- return symbolic_function(
76
- finance_model,
77
- estimation_method,
78
- probability,
79
- return_type=CReal, # type:ignore[type-abstract]
80
- )
81
-
82
-
83
57
  __all__ = [
84
58
  "qft_const_adder_phase",
85
59
  "fock_hamiltonian_problem_to_hamiltonian",
86
60
  "molecule_problem_to_hamiltonian",
87
61
  "grid_entangler_graph",
88
62
  "hypercube_entangler_graph",
89
- "gaussian_finance_post_process",
90
- "log_normal_finance_post_process",
91
63
  ]
@@ -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 (
@@ -188,7 +195,7 @@ class Pauli(IntEnum):
188
195
  )
189
196
 
190
197
  return SparsePauliOp(
191
- terms=[ # type:ignore[arg-type]
198
+ terms=[
192
199
  SparsePauliTerm(
193
200
  paulis=[ # type:ignore[arg-type]
194
201
  IndexedPauli(pauli=self, index=index) # type:ignore[arg-type]
@@ -196,7 +203,7 @@ class Pauli(IntEnum):
196
203
  coefficient=1.0, # type:ignore[arg-type]
197
204
  )
198
205
  ],
199
- num_qubits=index + 1, # type:ignore[arg-type]
206
+ num_qubits=index + 1,
200
207
  )
201
208
 
202
209
 
@@ -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(
@@ -63,27 +63,31 @@ class SparsePauliOp:
63
63
  num_qubits (CInt): The number of qubits in the Hamiltonian.
64
64
  """
65
65
 
66
- terms: CArray[SparsePauliTerm]
67
- num_qubits: CInt
66
+ terms: list[SparsePauliTerm]
67
+ num_qubits: int
68
68
 
69
69
  def __mul__(self, obj: Union[float, "SparsePauliOp"]) -> "SparsePauliOp":
70
70
  if isinstance(obj, (int, float, complex)):
71
71
  return SparsePauliOp(
72
- terms=[ # type:ignore[arg-type]
72
+ terms=[
73
73
  SparsePauliTerm(
74
74
  paulis=term.paulis,
75
- coefficient=obj * term.coefficient,
75
+ coefficient=obj * term.coefficient, # type:ignore[arg-type]
76
76
  )
77
- for term in self.terms # type:ignore[attr-defined]
77
+ for term in self.terms
78
78
  ],
79
79
  num_qubits=self.num_qubits,
80
80
  )
81
- if len(self.terms) != 1 or len(obj.terms) != 1: # type:ignore[arg-type]
81
+ if len(self.terms) != 1 or len(obj.terms) != 1:
82
82
  raise ClassiqValueError("Cannot attach a pauli to multiple pauli terms")
83
83
  existing_indices = {
84
- indexed_pauli.index for indexed_pauli in self.terms[0].paulis
84
+ indexed_pauli.index
85
+ for indexed_pauli in self.terms[0].paulis # type:ignore[attr-defined]
86
+ }
87
+ added_indices = {
88
+ indexed_pauli.index
89
+ for indexed_pauli in obj.terms[0].paulis # type:ignore[attr-defined]
85
90
  }
86
- added_indices = {indexed_pauli.index for indexed_pauli in obj.terms[0].paulis}
87
91
  overlapping_indices = sorted(existing_indices.intersection(added_indices))
88
92
  if len(overlapping_indices):
89
93
  raise ClassiqValueError(
@@ -93,15 +97,15 @@ class SparsePauliOp:
93
97
  f"already assigned"
94
98
  )
95
99
  return SparsePauliOp(
96
- terms=[ # type:ignore[arg-type]
100
+ terms=[
97
101
  SparsePauliTerm(
98
- paulis=self.terms[0].paulis + obj.terms[0].paulis,
99
- coefficient=self.terms[0].coefficient * obj.terms[0].coefficient,
102
+ paulis=self.terms[0].paulis
103
+ + obj.terms[0].paulis, # type:ignore[arg-type]
104
+ coefficient=self.terms[0].coefficient
105
+ * obj.terms[0].coefficient, # type:ignore[arg-type]
100
106
  )
101
107
  ],
102
- num_qubits=max(
103
- self.num_qubits, obj.num_qubits # type:ignore[call-overload]
104
- ),
108
+ num_qubits=max(self.num_qubits, obj.num_qubits),
105
109
  )
106
110
 
107
111
  def __rmul__(self, obj: Union[float, "SparsePauliOp"]) -> "SparsePauliOp":
@@ -109,10 +113,21 @@ class SparsePauliOp:
109
113
 
110
114
  def __add__(self, other: "SparsePauliOp") -> "SparsePauliOp":
111
115
  return SparsePauliOp(
112
- terms=self.terms + other.terms, # type:ignore[arg-type]
113
- num_qubits=max(
114
- self.num_qubits, other.num_qubits # type:ignore[call-overload]
115
- ),
116
+ terms=self.terms + other.terms,
117
+ num_qubits=max(self.num_qubits, other.num_qubits),
118
+ )
119
+
120
+ def __sub__(self, other: "SparsePauliOp") -> "SparsePauliOp":
121
+ return self + -1.0 * other
122
+
123
+ def __str__(self) -> str:
124
+ return " + ".join(
125
+ (f"{term.coefficient}*" if term.coefficient != 1 else "")
126
+ + "*".join(
127
+ f"Pauli.{indexed_pauli.pauli.name}({indexed_pauli.index})"
128
+ for indexed_pauli in term.paulis # type:ignore[attr-defined]
129
+ )
130
+ for term in self.terms
116
131
  )
117
132
 
118
133
 
@@ -190,16 +205,6 @@ class LogNormalModel:
190
205
  sigma: CReal
191
206
 
192
207
 
193
- @dataclass
194
- class FinanceFunction:
195
- f: CInt
196
- threshold: CReal
197
- larger: CBool
198
- polynomial_degree: CInt
199
- use_chebyshev_polynomial_approximation: CBool
200
- tail_probability: CReal
201
-
202
-
203
208
  @dataclass
204
209
  class QsvmResult:
205
210
  test_score: CReal
@@ -231,7 +236,6 @@ BUILTIN_STRUCT_DECLARATIONS = {
231
236
  __all__ = [
232
237
  "ChemistryAtom",
233
238
  "CombinatorialOptimizationSolution",
234
- "FinanceFunction",
235
239
  "FockHamiltonianProblem",
236
240
  "GaussianModel",
237
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]
@@ -71,12 +71,7 @@ class ASTToQMODCode(ast.NodeVisitor):
71
71
  return self.indent.join(self.visit(child) for child in node.body)
72
72
 
73
73
  def visit_Attribute(self, node: ast.Attribute) -> str:
74
- if not isinstance(node.value, ast.Name) or not isinstance(node.attr, str):
75
- raise AssertionError("Error parsing enum attribute access")
76
- if not (IDENTIFIER.match(node.value.id) and IDENTIFIER.match(node.attr)):
77
- raise AssertionError("Error parsing enum attribute access")
78
- self._handle_imports(node.value.id)
79
- return f"{node.value.id!s}.{node.attr!s}"
74
+ return f"{self.visit(node.value)}.{node.attr}"
80
75
 
81
76
  def visit_Name(self, node: ast.Name) -> str:
82
77
  self._handle_imports(node.id, True)
@@ -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)