classiq 0.60.1__py3-none-any.whl → 0.62.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 (108) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/_internals/client.py +6 -1
  3. classiq/applications/__init__.py +1 -1
  4. classiq/applications/chemistry/__init__.py +7 -7
  5. classiq/applications/chemistry/chemistry_model_constructor.py +17 -6
  6. classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
  7. classiq/applications/combinatorial_helpers/pyomo_utils.py +60 -9
  8. classiq/applications/combinatorial_optimization/__init__.py +7 -1
  9. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
  10. classiq/applications/combinatorial_optimization/combinatorial_problem.py +230 -0
  11. classiq/applications/finance/finance_model_constructor.py +6 -6
  12. classiq/applications/grover/grover_model_constructor.py +3 -0
  13. classiq/applications/libraries/qmci_library.py +1 -10
  14. classiq/applications/qnn/__init__.py +1 -1
  15. classiq/applications/qnn/datasets/__init__.py +8 -8
  16. classiq/applications/qsvm/qsvm.py +1 -1
  17. classiq/execution/__init__.py +0 -2
  18. classiq/execution/execution_session.py +6 -0
  19. classiq/execution/jobs.py +9 -1
  20. classiq/executor.py +1 -1
  21. classiq/interface/_version.py +1 -1
  22. classiq/interface/backend/backend_preferences.py +33 -15
  23. classiq/interface/backend/quantum_backend_providers.py +3 -1
  24. classiq/interface/executor/execution_preferences.py +1 -1
  25. classiq/interface/generator/application_apis/chemistry_declarations.py +1 -1
  26. classiq/interface/generator/application_apis/finance_declarations.py +2 -2
  27. classiq/interface/generator/arith/arithmetic.py +16 -1
  28. classiq/interface/generator/arith/arithmetic_expression_validator.py +4 -3
  29. classiq/interface/generator/copy.py +47 -0
  30. classiq/interface/generator/expressions/expression_constants.py +3 -0
  31. classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
  32. classiq/interface/generator/generated_circuit_data.py +58 -20
  33. classiq/interface/generator/model/__init__.py +1 -1
  34. classiq/interface/generator/model/preferences/preferences.py +1 -1
  35. classiq/interface/generator/model/quantum_register.py +3 -3
  36. classiq/interface/generator/standard_gates/controlled_standard_gates.py +20 -32
  37. classiq/interface/generator/types/compilation_metadata.py +2 -1
  38. classiq/interface/ide/visual_model.py +1 -0
  39. classiq/interface/interface_version.py +1 -1
  40. classiq/interface/model/model.py +2 -3
  41. classiq/interface/model/quantum_function_call.py +4 -7
  42. classiq/interface/model/quantum_function_declaration.py +7 -0
  43. classiq/interface/model/quantum_lambda_function.py +10 -1
  44. classiq/interface/model/quantum_type.py +3 -1
  45. classiq/model_expansions/atomic_expression_functions_defs.py +3 -1
  46. classiq/model_expansions/capturing/captured_vars.py +36 -17
  47. classiq/model_expansions/capturing/mangling_utils.py +23 -15
  48. classiq/model_expansions/closure.py +6 -9
  49. classiq/model_expansions/evaluators/arg_type_match.py +7 -7
  50. classiq/model_expansions/expression_evaluator.py +5 -2
  51. classiq/model_expansions/function_builder.py +26 -4
  52. classiq/model_expansions/generative_functions.py +13 -91
  53. classiq/model_expansions/interpreter.py +75 -46
  54. classiq/model_expansions/quantum_operations/call_emitter.py +42 -29
  55. classiq/model_expansions/quantum_operations/classicalif.py +1 -1
  56. classiq/model_expansions/quantum_operations/control.py +5 -31
  57. classiq/model_expansions/quantum_operations/emitter.py +29 -17
  58. classiq/model_expansions/quantum_operations/expression_operation.py +3 -5
  59. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +57 -15
  60. classiq/model_expansions/quantum_operations/invert.py +1 -6
  61. classiq/model_expansions/quantum_operations/phase.py +2 -5
  62. classiq/model_expansions/quantum_operations/power.py +0 -4
  63. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +19 -30
  64. classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -2
  65. classiq/model_expansions/quantum_operations/shallow_emitter.py +161 -0
  66. classiq/model_expansions/quantum_operations/within_apply.py +0 -14
  67. classiq/model_expansions/scope.py +12 -16
  68. classiq/model_expansions/scope_initialization.py +0 -11
  69. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +7 -0
  70. classiq/model_expansions/sympy_conversion/sympy_to_python.py +12 -2
  71. classiq/model_expansions/transformers/ast_renamer.py +26 -0
  72. classiq/model_expansions/transformers/var_splitter.py +11 -12
  73. classiq/model_expansions/visitors/variable_references.py +20 -12
  74. classiq/qmod/builtins/classical_execution_primitives.py +6 -6
  75. classiq/qmod/builtins/classical_functions.py +10 -10
  76. classiq/qmod/builtins/functions/__init__.py +89 -103
  77. classiq/qmod/builtins/functions/amplitude_estimation.py +1 -1
  78. classiq/qmod/builtins/functions/arithmetic.py +1 -1
  79. classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +6 -6
  80. classiq/qmod/builtins/functions/grover.py +5 -5
  81. classiq/qmod/builtins/functions/hea.py +1 -1
  82. classiq/qmod/builtins/functions/linear_pauli_rotation.py +2 -2
  83. classiq/qmod/builtins/functions/modular_exponentiation.py +8 -8
  84. classiq/qmod/builtins/functions/operators.py +1 -1
  85. classiq/qmod/builtins/functions/qaoa_penalty.py +5 -5
  86. classiq/qmod/builtins/functions/qft_functions.py +2 -2
  87. classiq/qmod/builtins/functions/qpe.py +9 -12
  88. classiq/qmod/builtins/functions/qsvt.py +177 -15
  89. classiq/qmod/builtins/functions/state_preparation.py +9 -9
  90. classiq/qmod/builtins/functions/swap_test.py +1 -1
  91. classiq/qmod/builtins/functions/utility_functions.py +2 -2
  92. classiq/qmod/builtins/functions/variational.py +2 -2
  93. classiq/qmod/builtins/operations.py +22 -83
  94. classiq/qmod/builtins/structs.py +9 -9
  95. classiq/qmod/native/pretty_printer.py +17 -19
  96. classiq/qmod/pretty_print/pretty_printer.py +9 -6
  97. classiq/qmod/python_classical_type.py +1 -5
  98. classiq/qmod/qmod_variable.py +2 -5
  99. classiq/qmod/quantum_expandable.py +20 -5
  100. classiq/qmod/quantum_function.py +23 -10
  101. classiq/qmod/semantics/static_semantics_visitor.py +34 -16
  102. classiq/qmod/semantics/validation/func_call_validation.py +9 -5
  103. classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
  104. classiq/qmod/symbolic.py +47 -47
  105. {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/METADATA +2 -1
  106. {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/RECORD +107 -103
  107. classiq/execution/qaoa.py +0 -86
  108. {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/WHEEL +0 -0
@@ -1,16 +1,12 @@
1
1
  import inspect
2
2
  import sys
3
- import warnings
4
3
  from collections.abc import Mapping
5
4
  from types import FrameType
6
5
  from typing import (
7
- TYPE_CHECKING,
8
6
  Any,
9
7
  Callable,
10
8
  Final,
11
- Optional,
12
9
  Union,
13
- overload,
14
10
  )
15
11
 
16
12
  from classiq.interface.exceptions import ClassiqValueError
@@ -44,7 +40,8 @@ from classiq.interface.model.repeat import Repeat
44
40
  from classiq.interface.model.statement_block import StatementBlock
45
41
  from classiq.interface.model.within_apply_operation import WithinApply
46
42
 
47
- from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QNum, QScalar, QVar
43
+ from classiq.qmod.generative import is_generative_mode
44
+ from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QScalar, QVar
48
45
  from classiq.qmod.quantum_callable import QCallable
49
46
  from classiq.qmod.quantum_expandable import prepare_arg
50
47
  from classiq.qmod.symbolic_expr import SymbolicExpr
@@ -89,9 +86,10 @@ def if_(
89
86
  else_=_operand_to_body(else_, "else") if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
90
87
  source_ref=source_ref,
91
88
  )
92
- if_stmt.set_generative_block("then", then)
93
- if callable(else_):
94
- if_stmt.set_generative_block("else", else_)
89
+ if is_generative_mode():
90
+ if_stmt.set_generative_block("then", then)
91
+ if callable(else_):
92
+ if_stmt.set_generative_block("else", else_)
95
93
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(if_stmt)
96
94
 
97
95
 
@@ -109,9 +107,10 @@ def control(
109
107
  else_block=_operand_to_body(else_block, "else_block") if else_block else None,
110
108
  source_ref=source_ref,
111
109
  )
112
- control_stmt.set_generative_block("body", stmt_block)
113
- if else_block is not None:
114
- control_stmt.set_generative_block("else_block", else_block)
110
+ if is_generative_mode():
111
+ control_stmt.set_generative_block("body", stmt_block)
112
+ if else_block is not None:
113
+ control_stmt.set_generative_block("else_block", else_block)
115
114
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(control_stmt)
116
115
 
117
116
 
@@ -161,22 +160,7 @@ def assign_amplitude(expression: SymbolicExpr, target_var: QScalar) -> None:
161
160
  )
162
161
 
163
162
 
164
- @overload
165
163
  def inplace_add(expression: SymbolicExpr, target_var: QScalar) -> None:
166
- pass
167
-
168
-
169
- @overload
170
- def inplace_add(*, value: QNum, target: QNum) -> None:
171
- pass
172
-
173
-
174
- def inplace_add(
175
- expression: Optional[SymbolicExpr] = None,
176
- target_var: Optional[QScalar] = None,
177
- value: Optional[QNum] = None,
178
- target: Optional[QNum] = None,
179
- ) -> None:
180
164
  """
181
165
  Add an arithmetic expression to a quantum variable.
182
166
 
@@ -187,23 +171,6 @@ def inplace_add(
187
171
  target_var: A scalar quantum variable
188
172
  """
189
173
  assert QCallable.CURRENT_EXPANDABLE is not None
190
- if value is not None or target is not None:
191
- warnings.warn(
192
- "Parameters 'value' and 'target of function 'inplace_add' have "
193
- "been renamed to 'expression' and 'target_var' respectively. Parameters "
194
- "'value' and 'target' will no longer be supported starting on 02/12/24 at "
195
- "the earliest.\nHint: Change `inplace_add(value=..., target=...)` to "
196
- "`inplace_add(expression=..., target_var=...)` or `inplace_add(..., ...)`.",
197
- category=DeprecationWarning,
198
- stacklevel=2,
199
- )
200
- if value is not None:
201
- expression = value
202
- if target is not None:
203
- target_var = target
204
- if TYPE_CHECKING:
205
- assert expression is not None
206
- assert target_var is not None
207
174
  source_ref = get_source_ref(sys._getframe(1))
208
175
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
209
176
  ArithmeticOperation(
@@ -215,22 +182,7 @@ def inplace_add(
215
182
  )
216
183
 
217
184
 
218
- @overload
219
185
  def inplace_xor(expression: SymbolicExpr, target_var: QScalar) -> None:
220
- pass
221
-
222
-
223
- @overload
224
- def inplace_xor(*, value: QNum, target: QNum) -> None:
225
- pass
226
-
227
-
228
- def inplace_xor(
229
- expression: Optional[SymbolicExpr] = None,
230
- target_var: Optional[QScalar] = None,
231
- value: Optional[QNum] = None,
232
- target: Optional[QNum] = None,
233
- ) -> None:
234
186
  """
235
187
  Bitwise-XOR a quantum variable with an arithmetic expression.
236
188
 
@@ -241,23 +193,6 @@ def inplace_xor(
241
193
  target_var: A scalar quantum variable
242
194
  """
243
195
  assert QCallable.CURRENT_EXPANDABLE is not None
244
- if value is not None or target is not None:
245
- warnings.warn(
246
- "Parameters 'value' and 'target of function 'inplace_xor' have "
247
- "been renamed to 'expression' and 'target_var' respectively. Parameters "
248
- "'value' and 'target' will no longer be supported starting on 02/12/24 at "
249
- "the earliest.\nHint: Change `inplace_xor(value=..., target=...)` to "
250
- "`inplace_xor(expression=..., target_var=...)` or `inplace_xor(..., ...)`.",
251
- category=DeprecationWarning,
252
- stacklevel=2,
253
- )
254
- if value is not None:
255
- expression = value
256
- if target is not None:
257
- target_var = target
258
- if TYPE_CHECKING:
259
- assert expression is not None
260
- assert target_var is not None
261
196
  source_ref = get_source_ref(sys._getframe(1))
262
197
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
263
198
  ArithmeticOperation(
@@ -282,8 +217,9 @@ def within_apply(
282
217
  action=_operand_to_body(apply, "apply"),
283
218
  source_ref=source_ref,
284
219
  )
285
- within_apply_stmt.set_generative_block("within", within)
286
- within_apply_stmt.set_generative_block("apply", apply)
220
+ if is_generative_mode():
221
+ within_apply_stmt.set_generative_block("within", within)
222
+ within_apply_stmt.set_generative_block("apply", apply)
287
223
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(within_apply_stmt)
288
224
 
289
225
 
@@ -313,7 +249,8 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
313
249
  body=iteration_operand.body,
314
250
  source_ref=source_ref,
315
251
  )
316
- repeat_stmt.set_generative_block("body", iteration)
252
+ if is_generative_mode():
253
+ repeat_stmt.set_generative_block("body", iteration)
317
254
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(repeat_stmt)
318
255
 
319
256
 
@@ -329,7 +266,8 @@ def power(
329
266
  body=_operand_to_body(stmt_block, "stmt_block"),
330
267
  source_ref=source_ref,
331
268
  )
332
- power_stmt.set_generative_block("body", stmt_block)
269
+ if is_generative_mode():
270
+ power_stmt.set_generative_block("body", stmt_block)
333
271
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(power_stmt)
334
272
 
335
273
 
@@ -340,7 +278,8 @@ def invert(stmt_block: Union[QCallable, Callable[[], None]]) -> None:
340
278
  invert_stmt = Invert(
341
279
  body=_operand_to_body(stmt_block, "stmt_block"), source_ref=source_ref
342
280
  )
343
- invert_stmt.set_generative_block("body", stmt_block)
281
+ if is_generative_mode():
282
+ invert_stmt.set_generative_block("body", stmt_block)
344
283
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(invert_stmt)
345
284
 
346
285
 
@@ -434,14 +373,14 @@ __all__ = [
434
373
  "assign_amplitude",
435
374
  "bind",
436
375
  "control",
437
- "invert",
438
376
  "if_",
439
377
  "inplace_add",
440
378
  "inplace_xor",
379
+ "invert",
380
+ "phase",
441
381
  "power",
442
- "within_apply",
443
382
  "repeat",
444
- "phase",
383
+ "within_apply",
445
384
  ]
446
385
 
447
386
 
@@ -134,18 +134,18 @@ BUILTIN_STRUCT_DECLARATIONS = {
134
134
 
135
135
 
136
136
  __all__ = [
137
- "PauliTerm",
138
- "MoleculeProblem",
139
- "Molecule",
140
137
  "ChemistryAtom",
141
- "Position",
142
- "FockHamiltonianProblem",
143
- "LadderTerm",
144
- "LadderOp",
145
138
  "CombinatorialOptimizationSolution",
139
+ "FinanceFunction",
140
+ "FockHamiltonianProblem",
146
141
  "GaussianModel",
142
+ "LadderOp",
143
+ "LadderTerm",
147
144
  "LogNormalModel",
148
- "FinanceFunction",
149
- "QsvmResult",
145
+ "Molecule",
146
+ "MoleculeProblem",
147
+ "PauliTerm",
148
+ "Position",
150
149
  "QSVMFeatureMapPauli",
150
+ "QsvmResult",
151
151
  ]
@@ -51,7 +51,6 @@ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
51
51
  ArithmeticOperationKind,
52
52
  )
53
53
  from classiq.interface.model.quantum_function_call import (
54
- OperandIdentifier,
55
54
  QuantumFunctionCall,
56
55
  )
57
56
  from classiq.interface.model.quantum_function_declaration import (
@@ -60,7 +59,10 @@ from classiq.interface.model.quantum_function_declaration import (
60
59
  QuantumFunctionDeclaration,
61
60
  QuantumOperandDeclaration,
62
61
  )
63
- from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
62
+ from classiq.interface.model.quantum_lambda_function import (
63
+ OperandIdentifier,
64
+ QuantumLambdaFunction,
65
+ )
64
66
  from classiq.interface.model.quantum_type import (
65
67
  QuantumBit,
66
68
  QuantumBitvector,
@@ -76,6 +78,7 @@ from classiq.interface.model.variable_declaration_statement import (
76
78
  )
77
79
  from classiq.interface.model.within_apply_operation import WithinApply
78
80
 
81
+ from classiq.qmod.builtins.functions import OPEN_LIBRARY_FUNCTIONS
79
82
  from classiq.qmod.native.expression_to_qmod import transform_expression
80
83
  from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
81
84
  from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
@@ -85,11 +88,11 @@ class DSLPrettyPrinter(Visitor):
85
88
  def __init__(
86
89
  self,
87
90
  decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION,
88
- rename_phase: bool = False,
91
+ emit_open_lib_functions: bool = False,
89
92
  ) -> None:
90
93
  self._level = 0
91
94
  self._decimal_precision = decimal_precision
92
- self._rename_phase = rename_phase
95
+ self._emit_open_lib_functions = emit_open_lib_functions
93
96
 
94
97
  def visit(self, node: NodeType) -> str:
95
98
  res = super().visit(node)
@@ -168,10 +171,7 @@ class DSLPrettyPrinter(Visitor):
168
171
  def visit_QuantumVariableDeclaration(
169
172
  self, var_decl: QuantumVariableDeclaration
170
173
  ) -> str:
171
- var_name = var_decl.name
172
- if self._rename_phase and var_name == "phase":
173
- var_name = "phase_var"
174
- return f"{var_name}: {self.visit(var_decl.quantum_type)}"
174
+ return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
175
175
 
176
176
  def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
177
177
  dir_str = (
@@ -179,12 +179,7 @@ class DSLPrettyPrinter(Visitor):
179
179
  if port_decl.direction != PortDeclarationDirection.Inout
180
180
  else ""
181
181
  )
182
- port_name = (
183
- port_decl.name
184
- if not (self._rename_phase and port_decl.name == "phase")
185
- else "phase_var"
186
- )
187
- param_name = f"{port_name}: " if port_decl.name is not None else ""
182
+ param_name = f"{port_decl.name}: " if port_decl.name is not None else ""
188
183
  return f"{dir_str}{param_name}{self.visit(port_decl.quantum_type)}"
189
184
 
190
185
  def visit_QuantumBit(self, qtype: QuantumBit) -> str:
@@ -250,6 +245,10 @@ class DSLPrettyPrinter(Visitor):
250
245
  return self.visit_AnonQuantumOperandDeclaration(op_decl)
251
246
 
252
247
  def visit_NativeFunctionDefinition(self, func_def: NativeFunctionDefinition) -> str:
248
+ if not self._emit_open_lib_functions and func_def.name in [
249
+ qfunc_.func_decl.name for qfunc_ in OPEN_LIBRARY_FUNCTIONS
250
+ ]:
251
+ return ""
253
252
  self._level += 1
254
253
  body = "".join(self.visit(qvar_decl) for qvar_decl in func_def.body)
255
254
  self._level -= 1
@@ -350,11 +349,7 @@ class DSLPrettyPrinter(Visitor):
350
349
  return f"lambda({positional_args}) {{\n{body}{self._indent}}}"
351
350
 
352
351
  def visit_HandleBinding(self, var_ref: HandleBinding) -> str:
353
- return (
354
- var_ref.name
355
- if not (self._rename_phase and var_ref.name == "phase")
356
- else "phase_var"
357
- )
352
+ return var_ref.name
358
353
 
359
354
  def visit_SlicedHandleBinding(self, var_ref: SlicedHandleBinding) -> str:
360
355
  return f"{self.visit(var_ref.base_handle)}[{self.visit(var_ref.start)}:{self.visit(var_ref.end)}]"
@@ -391,6 +386,9 @@ class DSLPrettyPrinter(Visitor):
391
386
  def visit_list(self, node: list) -> str:
392
387
  return "[" + ", ".join(self.visit(elem) for elem in node) + "]"
393
388
 
389
+ def visit_OperandIdentifier(self, op: OperandIdentifier) -> str:
390
+ return str(op)
391
+
394
392
  @property
395
393
  def _indent(self) -> str:
396
394
  return " " * self._level
@@ -52,7 +52,6 @@ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
52
52
  ArithmeticOperationKind,
53
53
  )
54
54
  from classiq.interface.model.quantum_function_call import (
55
- OperandIdentifier,
56
55
  QuantumFunctionCall,
57
56
  )
58
57
  from classiq.interface.model.quantum_function_declaration import (
@@ -61,7 +60,10 @@ from classiq.interface.model.quantum_function_declaration import (
61
60
  QuantumFunctionDeclaration,
62
61
  QuantumOperandDeclaration,
63
62
  )
64
- from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
63
+ from classiq.interface.model.quantum_lambda_function import (
64
+ OperandIdentifier,
65
+ QuantumLambdaFunction,
66
+ )
65
67
  from classiq.interface.model.quantum_type import (
66
68
  QuantumBit,
67
69
  QuantumBitvector,
@@ -285,10 +287,8 @@ class PythonPrettyPrinter(Visitor):
285
287
  raise ClassiqInternalError
286
288
 
287
289
  is_unsigned = (
288
- is_signed_expr.is_evaluated()
289
- and not is_signed_expr.to_bool_value()
290
- or is_signed_expr.expr == "UNSIGNED"
291
- )
290
+ is_signed_expr.is_evaluated() and not is_signed_expr.to_bool_value()
291
+ ) or is_signed_expr.expr == "UNSIGNED"
292
292
  is_integer = (
293
293
  fraction_digits_expr.is_evaluated()
294
294
  and fraction_digits_expr.to_int_value() == 0
@@ -526,6 +526,9 @@ class PythonPrettyPrinter(Visitor):
526
526
  def visit_list(self, node: list) -> str:
527
527
  return "[" + ", ".join(self.visit(elem) for elem in node) + "]"
528
528
 
529
+ def visit_OperandIdentifier(self, op: OperandIdentifier) -> str:
530
+ return str(op)
531
+
529
532
  @property
530
533
  def _indent(self) -> str:
531
534
  return " " * self._level
@@ -1,6 +1,5 @@
1
1
  import dataclasses
2
2
  import inspect
3
- import sys
4
3
  from enum import EnumMeta
5
4
  from typing import (
6
5
  Optional,
@@ -16,16 +15,13 @@ from classiq.interface.generator.functions.classical_type import (
16
15
  Integer,
17
16
  Real,
18
17
  )
18
+ from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
19
19
  from classiq.interface.generator.functions.type_name import Enum, Struct
20
20
 
21
21
  from classiq.qmod.cparam import CArray, CBool, CInt, CReal
22
22
  from classiq.qmod.qmod_variable import get_type_hint_expr
23
23
  from classiq.qmod.utilities import version_portable_get_args
24
24
 
25
- if sys.version_info[0:2] >= (3, 9):
26
- pass
27
- from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
28
-
29
25
  CARRAY_ERROR_MESSAGE = (
30
26
  "CArray accepts one or two generic parameters in the form "
31
27
  "`CArray[<element-type>]` or `CArray[<element-type>, <size>]`"
@@ -452,11 +452,8 @@ class QArray(ArrayBase[_P], QVar):
452
452
  )
453
453
  if self._length is not None and self._length.is_evaluated():
454
454
  length = self._length.to_int_value()
455
- if (
456
- isinstance(slice_.start, int)
457
- and slice_.start < 0
458
- or isinstance(slice_.stop, int)
459
- and slice_.stop > length
455
+ if (isinstance(slice_.start, int) and slice_.start < 0) or (
456
+ isinstance(slice_.stop, int) and slice_.stop > length
460
457
  ):
461
458
  raise ClassiqValueError(SLICE_OUT_OF_BOUNDS_MSG)
462
459
 
@@ -18,7 +18,7 @@ import pydantic
18
18
  from sympy import Basic
19
19
  from typing_extensions import Self
20
20
 
21
- from classiq.interface.exceptions import ClassiqValueError
21
+ from classiq.interface.exceptions import ClassiqInternalError, ClassiqValueError
22
22
  from classiq.interface.generator.expressions.expression import Expression
23
23
  from classiq.interface.generator.functions.concrete_types import (
24
24
  NativePythonClassicalTypes,
@@ -30,7 +30,6 @@ from classiq.interface.model.classical_parameter_declaration import (
30
30
  from classiq.interface.model.port_declaration import AnonPortDeclaration
31
31
  from classiq.interface.model.quantum_function_call import (
32
32
  ArgValue,
33
- OperandIdentifier,
34
33
  QuantumFunctionCall,
35
34
  )
36
35
  from classiq.interface.model.quantum_function_declaration import (
@@ -39,7 +38,11 @@ from classiq.interface.model.quantum_function_declaration import (
39
38
  AnonQuantumOperandDeclaration,
40
39
  QuantumFunctionDeclaration,
41
40
  )
42
- from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
41
+ from classiq.interface.model.quantum_lambda_function import (
42
+ OperandIdentifier,
43
+ QuantumCallable,
44
+ QuantumLambdaFunction,
45
+ )
43
46
  from classiq.interface.model.quantum_statement import QuantumStatement
44
47
  from classiq.interface.model.quantum_type import QuantumType
45
48
  from classiq.interface.model.variable_declaration_statement import (
@@ -232,7 +235,9 @@ class QTerminalCallable(QCallable):
232
235
  raise NotImplementedError("Operand lists don't support slicing")
233
236
  if isinstance(key, CParam) and not isinstance(key, CParamScalar):
234
237
  raise ClassiqValueError("Non-classical parameter for slicing")
235
- return QTerminalCallable(self._decl, index_=key)
238
+ if not isinstance(self._decl, AnonQuantumOperandDeclaration):
239
+ raise ClassiqInternalError
240
+ return QTerminalCallable(self._decl.element_declaration, index_=key)
236
241
 
237
242
  def __len__(self) -> int:
238
243
  raise ClassiqValueError(
@@ -267,6 +272,13 @@ class QTerminalCallable(QCallable):
267
272
  self.func_decl, self._index, source_ref_, *args, **kwargs
268
273
  )
269
274
 
275
+ def get_arg(self) -> QuantumCallable:
276
+ if self._index is None:
277
+ return self._decl.name
278
+ return OperandIdentifier(
279
+ name=self._decl.name, index=Expression(expr=str(self._index))
280
+ )
281
+
270
282
 
271
283
  @overload
272
284
  def prepare_arg(
@@ -324,11 +336,14 @@ def prepare_arg(
324
336
  pos_rename_params=val.infer_rename_params(),
325
337
  body=val.body,
326
338
  )
327
- qlambda.set_py_callable(val._py_callable)
339
+ if is_generative_mode():
340
+ qlambda.set_py_callable(val._py_callable)
328
341
  return qlambda
329
342
 
330
343
  if isinstance(val, QExpandable):
331
344
  val.expand()
345
+ elif isinstance(val, QTerminalCallable):
346
+ return val.get_arg()
332
347
  return val.func_decl.name
333
348
 
334
349
 
@@ -77,12 +77,24 @@ class QFunc(BaseQFunc):
77
77
  self.compilation_metadata: Optional[CompilationMetadata] = None
78
78
 
79
79
  @property
80
- def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
81
- return self._qmodule.native_defs.get(
82
- self._py_callable.__name__,
83
- infer_func_decl(self._py_callable, qmodule=self._qmodule),
80
+ def pure_decl(self) -> NamedParamsQuantumFunctionDeclaration:
81
+ if type(self.func_decl) is NamedParamsQuantumFunctionDeclaration:
82
+ return self.func_decl
83
+ return NamedParamsQuantumFunctionDeclaration(
84
+ **{
85
+ k: v
86
+ for k, v in self.func_decl.model_dump().items()
87
+ if k in NamedParamsQuantumFunctionDeclaration.model_fields
88
+ }
84
89
  )
85
90
 
91
+ @property
92
+ def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
93
+ name = self._py_callable.__name__
94
+ if hasattr(self._qmodule, "native_defs") and name in self._qmodule.native_defs:
95
+ return self._qmodule.native_defs[name]
96
+ return infer_func_decl(self._py_callable, qmodule=self._qmodule)
97
+
86
98
  def __call__(self, *args: Any, **kwargs: Any) -> None:
87
99
  super().__call__(*args, **kwargs)
88
100
  self.expand()
@@ -181,6 +193,10 @@ class ExternalQFunc(QTerminalCallable):
181
193
  def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
182
194
  return self._decl
183
195
 
196
+ @property
197
+ def pure_decl(self) -> NamedParamsQuantumFunctionDeclaration:
198
+ return self.func_decl
199
+
184
200
  def get_implementation(self) -> NativeFunctionDefinition:
185
201
  model = QFunc(self._py_callable).create_model()
186
202
  return [
@@ -224,12 +240,9 @@ def _validate_no_gen_params(annotations: dict[str, Any]) -> None:
224
240
  for name, annotation in annotations.items()
225
241
  if not (
226
242
  name == "return"
227
- or isclass(annotation)
228
- and issubclass(annotation, CParam)
229
- or isclass(annotation)
230
- and is_dataclass(annotation)
231
- or isclass(annotation)
232
- and isinstance(annotation, EnumMeta)
243
+ or (isclass(annotation) and issubclass(annotation, CParam))
244
+ or (isclass(annotation) and is_dataclass(annotation))
245
+ or (isclass(annotation) and isinstance(annotation, EnumMeta))
233
246
  or get_origin(annotation) is CArray
234
247
  or (get_origin(annotation) or annotation) is QCallable
235
248
  or (get_origin(annotation) or annotation) is QCallableList
@@ -1,3 +1,4 @@
1
+ import ast
1
2
  from collections.abc import Iterator, Mapping, Sequence
2
3
  from contextlib import contextmanager
3
4
  from typing import (
@@ -6,7 +7,9 @@ from typing import (
6
7
  )
7
8
 
8
9
  from classiq.interface.exceptions import ClassiqSemanticError
10
+ from classiq.interface.generator.expressions.expression import Expression
9
11
  from classiq.interface.generator.function_params import PortDirection
12
+ from classiq.interface.generator.functions.classical_type import CLASSICAL_ATTRIBUTES
10
13
  from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
11
14
  from classiq.interface.generator.functions.port_declaration import (
12
15
  PortDeclarationDirection,
@@ -25,6 +28,9 @@ from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperat
25
28
  from classiq.interface.model.model import Model
26
29
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
27
30
  from classiq.interface.model.port_declaration import PortDeclaration
31
+ from classiq.interface.model.quantum_expressions.quantum_expression import (
32
+ QuantumExpressionOperation,
33
+ )
28
34
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
29
35
  from classiq.interface.model.quantum_function_declaration import (
30
36
  AnonQuantumOperandDeclaration,
@@ -41,7 +47,10 @@ from classiq.interface.model.variable_declaration_statement import (
41
47
  )
42
48
  from classiq.interface.model.within_apply_operation import WithinApply
43
49
 
44
- from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
50
+ from classiq.model_expansions.visitors.variable_references import VarRefCollector
51
+ from classiq.qmod.builtins.functions import (
52
+ BUILTIN_FUNCTION_DECLARATIONS,
53
+ )
45
54
  from classiq.qmod.semantics.annotation import annotate_function_call_decl
46
55
  from classiq.qmod.semantics.error_manager import ErrorManager
47
56
  from classiq.qmod.semantics.qstruct_annotator import QStructAnnotator
@@ -52,6 +61,9 @@ from classiq.qmod.semantics.validation.func_call_validation import (
52
61
  check_no_overlapping_quantum_args,
53
62
  validate_call_arguments,
54
63
  )
64
+ from classiq.qmod.semantics.validation.function_name_collisions_validation import (
65
+ _check_function_name_collisions,
66
+ )
55
67
  from classiq.qmod.semantics.validation.handle_validation import resolve_handle
56
68
  from classiq.qmod.semantics.validation.main_validation import validate_main_function
57
69
  from classiq.qmod.semantics.validation.types_validation import (
@@ -266,6 +278,26 @@ class StaticSemanticsVisitor(Visitor):
266
278
  def visit_HandleBinding(self, handle: HandleBinding) -> None:
267
279
  resolve_handle(self.current_scope, handle)
268
280
 
281
+ def visit_Expression(self, expr: Expression) -> None:
282
+ if len(self._scope) == 0:
283
+ return
284
+ vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
285
+ vrc.visit(ast.parse(expr.expr))
286
+ handles = [
287
+ HandleMetadata(handle=handle)
288
+ for handle in vrc.var_handles
289
+ if handle.name in self.current_scope.variable_states
290
+ and (
291
+ not isinstance(handle, FieldHandleBinding)
292
+ or handle.field not in CLASSICAL_ATTRIBUTES
293
+ )
294
+ ]
295
+ self._handle_inouts(handles)
296
+
297
+ def visit_QuantumExpressionOperation(self, op: QuantumExpressionOperation) -> None:
298
+ self.visit_Expression(op.expression)
299
+ self.visit_QuantumOperation(op)
300
+
269
301
  def _handle_state_changing_ios(
270
302
  self,
271
303
  ios: Sequence[HandleMetadata],
@@ -314,9 +346,6 @@ class StaticSemanticsVisitor(Visitor):
314
346
  )
315
347
 
316
348
  def _handle_inouts(self, inouts: Sequence[HandleMetadata]) -> None:
317
- sliced_handles = set()
318
- whole_handles = set()
319
-
320
349
  for handle_metadata in inouts:
321
350
  handle_binding = handle_metadata.handle
322
351
 
@@ -345,18 +374,6 @@ class StaticSemanticsVisitor(Visitor):
345
374
  f"{location}"
346
375
  )
347
376
 
348
- if isinstance(
349
- handle_binding, (SlicedHandleBinding, SubscriptHandleBinding)
350
- ):
351
- sliced_handles.add(handle_binding.name)
352
- else:
353
- whole_handles.add(handle_binding.name)
354
-
355
- for handle in sliced_handles & whole_handles:
356
- self._error_manager.add_error(
357
- f"Invalid use of inout handle {handle!r}, used both in slice or subscript and whole"
358
- )
359
-
360
377
 
361
378
  def resolve_function_calls(
362
379
  root: Any,
@@ -374,6 +391,7 @@ def resolve_function_calls(
374
391
  def static_semantics_analysis_pass(
375
392
  model: Model, error_type: Optional[type[Exception]] = ClassiqSemanticError
376
393
  ) -> None:
394
+ _check_function_name_collisions(model, error_type)
377
395
  QStructAnnotator().visit(model)
378
396
  StaticSemanticsVisitor(
379
397
  {**BUILTIN_FUNCTION_DECLARATIONS, **model.function_dict},
@@ -10,6 +10,7 @@ from classiq.interface.model.quantum_function_declaration import (
10
10
  QuantumFunctionDeclaration,
11
11
  )
12
12
  from classiq.interface.model.quantum_lambda_function import (
13
+ OperandIdentifier,
13
14
  QuantumLambdaFunction,
14
15
  QuantumOperand,
15
16
  )
@@ -56,16 +57,19 @@ def _check_operand_against_declaration(
56
57
  )
57
58
  return
58
59
  operand_arg_decl: AnonQuantumFunctionDeclaration
59
- if isinstance(operand_argument, str):
60
- if operand_argument not in function_dict:
60
+ operand_argument_for_decl = operand_argument
61
+ if isinstance(operand_argument_for_decl, OperandIdentifier):
62
+ operand_argument_for_decl = operand_argument_for_decl.name
63
+ if isinstance(operand_argument_for_decl, str):
64
+ if operand_argument_for_decl not in function_dict:
61
65
  ErrorManager().add_error(
62
66
  f"{operand_argument!r} argument to {func_name!r} is not a "
63
67
  f"registered function."
64
68
  )
65
69
  return
66
- operand_arg_decl = function_dict[operand_argument]
67
- elif isinstance(operand_argument, QuantumLambdaFunction):
68
- operand_arg_decl = operand_argument.func_decl
70
+ operand_arg_decl = function_dict[operand_argument_for_decl]
71
+ elif isinstance(operand_argument_for_decl, QuantumLambdaFunction):
72
+ operand_arg_decl = operand_argument_for_decl.func_decl
69
73
  else:
70
74
  raise ClassiqError(
71
75
  f"{str(operand_argument)!r} argument to {func_name!r} is not a "