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
@@ -9,6 +9,7 @@ from typing import (
9
9
  import pydantic
10
10
  from pydantic import SerializeAsAny
11
11
  from pydantic_core.core_schema import ValidationInfo
12
+ from typing_extensions import Self
12
13
 
13
14
  from classiq.interface.exceptions import ClassiqInternalError
14
15
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
@@ -171,6 +172,12 @@ class AnonQuantumOperandDeclaration(AnonQuantumFunctionDeclaration):
171
172
  new_instance_data["kind"] = "QuantumOperandDeclaration"
172
173
  return QuantumOperandDeclaration(**new_instance_data)
173
174
 
175
+ @property
176
+ def element_declaration(self) -> Self:
177
+ if not self.is_list:
178
+ raise ClassiqInternalError
179
+ return self.model_copy(update={"is_list": False})
180
+
174
181
 
175
182
  AnonQuantumFunctionDeclaration.model_rebuild()
176
183
 
@@ -4,6 +4,7 @@ import pydantic
4
4
 
5
5
  from classiq.interface.ast_node import ASTNode
6
6
  from classiq.interface.exceptions import ClassiqError
7
+ from classiq.interface.generator.expressions.expression import Expression
7
8
  from classiq.interface.model.quantum_function_declaration import (
8
9
  AnonQuantumOperandDeclaration,
9
10
  )
@@ -52,5 +53,13 @@ class QuantumLambdaFunction(ASTNode):
52
53
  self._func_decl = fd
53
54
 
54
55
 
55
- QuantumCallable = Union[str, QuantumLambdaFunction]
56
+ class OperandIdentifier(ASTNode):
57
+ name: str
58
+ index: Expression
59
+
60
+ def __str__(self) -> str:
61
+ return f"{self.name}[{self.index.expr}]"
62
+
63
+
64
+ QuantumCallable = Union[str, OperandIdentifier, QuantumLambdaFunction]
56
65
  QuantumOperand = Union[QuantumCallable, list[QuantumCallable]]
@@ -159,7 +159,9 @@ class QuantumNumeric(QuantumScalar):
159
159
  def _validate_fields(self) -> Self:
160
160
  has_sign = self.is_signed is not None
161
161
  has_fraction_digits = self.fraction_digits is not None
162
- if has_sign and not has_fraction_digits or not has_sign and has_fraction_digits:
162
+ if (has_sign and not has_fraction_digits) or (
163
+ not has_sign and has_fraction_digits
164
+ ):
163
165
  raise ClassiqValueError(
164
166
  "Assign neither or both of is_signed and fraction_digits"
165
167
  )
@@ -61,7 +61,7 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
61
61
  for field_name, field_type in val.struct_declaration.variables.items()
62
62
  }
63
63
 
64
- if isinstance(val, Enum):
64
+ if isinstance(val, (Enum, int)):
65
65
  return val
66
66
 
67
67
  elif isinstance(qmod_type, ClassicalList):
@@ -147,6 +147,8 @@ def get_field(
147
147
  proxy: Union[QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list],
148
148
  field: str,
149
149
  ) -> ExpressionValue:
150
+ if isinstance(proxy, type) and issubclass(proxy, Enum):
151
+ return getattr(proxy, field)
150
152
  if isinstance(proxy, Symbol) and not isinstance(proxy, QmodSizedProxy):
151
153
  raise ClassiqExpansionError(
152
154
  f"Cannot evaluate '{proxy}.{field}': Variable {str(proxy)!r} is not "
@@ -1,8 +1,7 @@
1
1
  import dataclasses
2
- from collections.abc import Iterator, Sequence
3
- from contextlib import contextmanager
2
+ from collections.abc import Sequence
4
3
  from dataclasses import dataclass, field
5
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Optional
6
5
 
7
6
  from classiq.interface.enum_utils import StrEnum
8
7
  from classiq.interface.exceptions import (
@@ -16,12 +15,14 @@ from classiq.interface.model.handle_binding import HandleBinding, NestedHandleBi
16
15
  from classiq.interface.model.port_declaration import PortDeclaration
17
16
  from classiq.interface.model.quantum_function_call import ArgValue
18
17
  from classiq.interface.model.quantum_type import QuantumType
18
+ from classiq.interface.model.variable_declaration_statement import (
19
+ VariableDeclarationStatement,
20
+ )
19
21
 
20
22
  from classiq.model_expansions.capturing.mangling_utils import (
21
23
  demangle_handle,
22
24
  mangle_captured_var_name,
23
25
  )
24
- from classiq.model_expansions.scope import QuantumSymbol
25
26
  from classiq.model_expansions.transformers.var_splitter import SymbolPart, SymbolParts
26
27
 
27
28
  if TYPE_CHECKING:
@@ -71,7 +72,11 @@ class _CapturedHandle:
71
72
 
72
73
  @property
73
74
  def mangled_name(self) -> str:
74
- return mangle_captured_var_name(self.handle.identifier, self.defining_function)
75
+ return mangle_captured_var_name(
76
+ self.handle.identifier,
77
+ self.defining_function.name,
78
+ self.defining_function.depth,
79
+ )
75
80
 
76
81
  @property
77
82
  def port(self) -> PortDeclaration:
@@ -211,7 +216,16 @@ class CapturedVars:
211
216
  ]
212
217
  )
213
218
 
214
- def filter(self, current_function: "FunctionClosure") -> "CapturedVars":
219
+ def filter_vars(
220
+ self,
221
+ current_function: "FunctionClosure",
222
+ current_declarations: Optional[list[VariableDeclarationStatement]] = None,
223
+ ) -> "CapturedVars":
224
+ current_declared_vars = (
225
+ None
226
+ if current_declarations is None
227
+ else {decl.name for decl in current_declarations}
228
+ )
215
229
  return CapturedVars(
216
230
  _captured_handles=[
217
231
  captured_handle
@@ -219,6 +233,10 @@ class CapturedVars:
219
233
  if not _same_closure(
220
234
  captured_handle.defining_function, current_function
221
235
  )
236
+ or (
237
+ current_declared_vars is not None
238
+ and captured_handle.handle.name not in current_declared_vars
239
+ )
222
240
  ]
223
241
  )
224
242
 
@@ -247,10 +265,7 @@ class CapturedVars:
247
265
 
248
266
  def get_captured_mapping(self) -> SymbolParts:
249
267
  return {
250
- QuantumSymbol(
251
- handle=captured_handle.handle,
252
- quantum_type=captured_handle.quantum_type,
253
- ): [
268
+ captured_handle.handle: [
254
269
  SymbolPart(
255
270
  source_handle=captured_handle.handle,
256
271
  target_var_name=captured_handle.mangled_name,
@@ -261,11 +276,8 @@ class CapturedVars:
261
276
  if not captured_handle.is_propagated
262
277
  }
263
278
 
264
- @contextmanager
265
- def freeze(self) -> Iterator[None]:
266
- previous = self._captured_handles
267
- yield
268
- self._captured_handles = previous
279
+ def clone(self) -> "CapturedVars":
280
+ return CapturedVars(_captured_handles=list(self._captured_handles))
269
281
 
270
282
 
271
283
  def _same_closure(closure_1: "FunctionClosure", closure_2: "FunctionClosure") -> bool:
@@ -295,7 +307,9 @@ def validate_args_are_not_propagated(
295
307
  )
296
308
 
297
309
 
298
- def validate_captured_directions(captured_vars: CapturedVars) -> None:
310
+ def validate_captured_directions(
311
+ captured_vars: CapturedVars, report_outin: bool = True
312
+ ) -> None:
299
313
  captured_inputs = [
300
314
  captured_handle.handle.name
301
315
  for captured_handle in captured_vars._captured_handles
@@ -304,7 +318,12 @@ def validate_captured_directions(captured_vars: CapturedVars) -> None:
304
318
  captured_outputs = [
305
319
  captured_handle.handle.name
306
320
  for captured_handle in captured_vars._captured_handles
307
- if captured_handle.direction == PortDirection.Output
321
+ if captured_handle.direction
322
+ in (
323
+ (PortDirection.Output, PortDirection.Outin)
324
+ if report_outin
325
+ else (PortDirection.Output,)
326
+ )
308
327
  ]
309
328
  if len(captured_inputs) > 0:
310
329
  raise ClassiqExpansionError(
@@ -1,12 +1,9 @@
1
1
  import re
2
- from typing import TYPE_CHECKING
2
+ from typing import Optional
3
3
 
4
4
  from classiq.interface.generator.compiler_keywords import CAPTURE_SUFFIX
5
5
  from classiq.interface.model.handle_binding import HANDLE_ID_SEPARATOR, HandleBinding
6
6
 
7
- if TYPE_CHECKING:
8
- from classiq.model_expansions.closure import FunctionClosure
9
-
10
7
  IDENTIFIER_PATTERN = r"[a-zA-Z_][a-zA-Z0-9_]*"
11
8
  CAPTURE_PATTERN = re.compile(
12
9
  rf"({IDENTIFIER_PATTERN}){CAPTURE_SUFFIX}{IDENTIFIER_PATTERN}__\d*"
@@ -15,24 +12,34 @@ ARRAY_CAST_SUFFIX = HANDLE_ID_SEPARATOR + "array_cast"
15
12
 
16
13
 
17
14
  def mangle_captured_var_name(
18
- var_name: str, defining_function: "FunctionClosure"
15
+ var_name: str, function_name: str, function_depth: int
19
16
  ) -> str:
20
- return (
21
- f"{var_name}{CAPTURE_SUFFIX}{defining_function.name}__{defining_function.depth}"
22
- )
17
+ return f"{var_name}{CAPTURE_SUFFIX}{function_name}__{function_depth}"
23
18
 
24
19
 
25
- def demangle_name(name: str) -> str:
26
- match = re.match(CAPTURE_PATTERN, name)
20
+ def _match_capture_pattern(name: str) -> Optional[re.Match[str]]:
21
+ return re.match(CAPTURE_PATTERN, name)
22
+
23
+
24
+ def is_captured_var_name(name: str) -> bool:
25
+ return _match_capture_pattern(name) is not None
26
+
27
+
28
+ def demangle_capture_name(name: str) -> str:
29
+ match = _match_capture_pattern(name)
27
30
  return match.group(1) if match else name
28
31
 
29
32
 
30
33
  def demangle_handle(handle: HandleBinding) -> HandleBinding:
31
- name = handle.name
34
+ demangled_name = demangle_name(handle.name)
35
+ return handle.rename(demangled_name)
36
+
37
+
38
+ def demangle_name(name: str) -> str:
32
39
  if HANDLE_ID_SEPARATOR not in name:
33
- return handle
40
+ return name
34
41
  if ARRAY_CAST_SUFFIX in name:
35
- return HandleBinding(name=name.split(ARRAY_CAST_SUFFIX)[0])
42
+ return name.split(ARRAY_CAST_SUFFIX)[0]
36
43
  name = re.sub(r"([^_])_\d+$", r"\1", name)
37
44
  name_parts = name.split(HANDLE_ID_SEPARATOR)
38
45
  new_name_parts = [name_parts[0]]
@@ -44,5 +51,6 @@ def demangle_handle(handle: HandleBinding) -> HandleBinding:
44
51
  new_name_parts.append(f"[{part_left}:{part_right}]")
45
52
  else:
46
53
  new_name_parts.append(f".{part}")
47
- new_name_parts = list(map(demangle_name, new_name_parts))
48
- return handle.rename("".join(new_name_parts))
54
+ new_name_parts = list(map(demangle_capture_name, new_name_parts))
55
+ new_name = "".join(new_name_parts)
56
+ return new_name
@@ -1,8 +1,7 @@
1
1
  import dataclasses
2
2
  import json
3
3
  import uuid
4
- from collections.abc import Collection, Iterator, Sequence
5
- from contextlib import contextmanager
4
+ from collections.abc import Collection, Sequence
6
5
  from dataclasses import dataclass, field
7
6
  from functools import singledispatch
8
7
  from symtable import Symbol
@@ -51,11 +50,6 @@ class Closure:
51
50
  if isinstance(param, PortDeclaration)
52
51
  }
53
52
 
54
- @contextmanager
55
- def freeze(self) -> Iterator[None]:
56
- with self.scope.freeze(), self.captured_vars.freeze():
57
- yield
58
-
59
53
 
60
54
  @dataclass(frozen=True)
61
55
  class GenerativeClosure(Closure):
@@ -142,9 +136,12 @@ class FunctionClosure(Closure):
142
136
  def set_depth(self, depth: int) -> Self:
143
137
  return dataclasses.replace(self, _depth=depth)
144
138
 
145
- def copy_scope(self) -> Self: # Remove when scoping is normal (CAD-24980)
139
+ def clone(self) -> Self:
146
140
  return dataclasses.replace(
147
- self, scope=Scope(self.scope.data, parent=self.scope.parent)
141
+ self,
142
+ scope=self.scope.clone(),
143
+ signature_scope=self.signature_scope.clone(),
144
+ captured_vars=self.captured_vars.clone(),
148
145
  )
149
146
 
150
147
 
@@ -135,13 +135,13 @@ def _check_classical_type_match(
135
135
  arg_struct_name = None if not arg_is_struct else argument.struct_declaration.name
136
136
  if (
137
137
  arg_is_qvar
138
- or arg_is_builtin
139
- and (type_is_struct or type_is_enum)
140
- or arg_is_struct
141
- and (not type_is_struct or arg_struct_name != type_name)
142
- or arg_is_enum
143
- and get_qmod_type(classical_type) != CInt
144
- and (not type_is_enum or type(argument).__name__ != type_name)
138
+ or (arg_is_builtin and (type_is_struct or type_is_enum))
139
+ or (arg_is_struct and (not type_is_struct or arg_struct_name != type_name))
140
+ or (
141
+ arg_is_enum
142
+ and get_qmod_type(classical_type) != CInt
143
+ and (not type_is_enum or type(argument).__name__ != type_name)
144
+ )
145
145
  ):
146
146
  raise ClassiqExpansionError(error_message)
147
147
 
@@ -1,4 +1,5 @@
1
1
  import ast
2
+ import re
2
3
  from collections.abc import Mapping
3
4
  from enum import EnumMeta
4
5
  from typing import Any, Optional
@@ -12,7 +13,7 @@ from classiq.interface.generator.expressions.evaluated_expression import (
12
13
  )
13
14
  from classiq.interface.generator.expressions.expression import Expression
14
15
  from classiq.interface.generator.expressions.expression_constants import (
15
- CPARAM_EXECUTION_SUFFIX,
16
+ CPARAM_EXECUTION_SUFFIX_PATTERN,
16
17
  )
17
18
  from classiq.interface.generator.expressions.expression_types import ExpressionValue
18
19
  from classiq.interface.generator.expressions.sympy_supported_expressions import (
@@ -99,7 +100,9 @@ def _validate_undefined_vars(
99
100
 
100
101
  # Ignore expanded execution parameters
101
102
  undefined_vars = {
102
- var for var in undefined_vars if not var.endswith(CPARAM_EXECUTION_SUFFIX)
103
+ var
104
+ for var in undefined_vars
105
+ if not re.search(CPARAM_EXECUTION_SUFFIX_PATTERN, var)
103
106
  }
104
107
 
105
108
  if len(undefined_vars) == 1:
@@ -20,6 +20,9 @@ from classiq.interface.model.quantum_function_declaration import (
20
20
  PositionalArg,
21
21
  )
22
22
  from classiq.interface.model.quantum_statement import QuantumStatement
23
+ from classiq.interface.model.variable_declaration_statement import (
24
+ VariableDeclarationStatement,
25
+ )
23
26
  from classiq.interface.source_reference import SourceReference
24
27
 
25
28
  from classiq.model_expansions.capturing.captured_vars import (
@@ -37,6 +40,14 @@ class Block:
37
40
  statements: list[QuantumStatement] = field(default_factory=list)
38
41
  captured_vars: CapturedVars = field(default_factory=CapturedVars)
39
42
 
43
+ @property
44
+ def variable_declarations(self) -> list[VariableDeclarationStatement]:
45
+ return [
46
+ stmt
47
+ for stmt in self.statements
48
+ if isinstance(stmt, VariableDeclarationStatement)
49
+ ]
50
+
40
51
 
41
52
  @dataclass
42
53
  class OperationContext(Generic[ClosureType]):
@@ -81,6 +92,10 @@ class OperationBuilder:
81
92
  def current_operation(self) -> Closure:
82
93
  return self._operations[-1].closure
83
94
 
95
+ @property
96
+ def current_scope(self) -> Scope:
97
+ return self.current_operation.scope
98
+
84
99
  @property
85
100
  def current_function(self) -> FunctionClosure:
86
101
  return self._get_last_function(self._operations)
@@ -123,9 +138,14 @@ class OperationBuilder:
123
138
  not isinstance(self.current_operation, FunctionClosure)
124
139
  and self.current_operation.name != WITHIN_APPLY_NAME
125
140
  ):
126
- validate_captured_directions(captured_vars)
141
+ validate_captured_directions(
142
+ captured_vars.filter_vars(
143
+ self.current_function, self.current_block.variable_declarations
144
+ ),
145
+ report_outin=False,
146
+ )
127
147
  self.current_operation.captured_vars.update(
128
- captured_vars.filter(self.current_function)
148
+ captured_vars.filter_vars(self.current_function)
129
149
  )
130
150
  self._blocks.pop()
131
151
 
@@ -149,7 +169,7 @@ class OperationBuilder:
149
169
  return
150
170
  within_captured_vars = self._operations[-1].blocks["within"].captured_vars
151
171
  self.current_operation.captured_vars.update(
152
- within_captured_vars.filter(self.current_function).negate()
172
+ within_captured_vars.filter_vars(self.current_function).negate()
153
173
  )
154
174
 
155
175
  def _propagate_captured_vars(self) -> None:
@@ -160,7 +180,9 @@ class OperationBuilder:
160
180
  if len(self._operations) < 2:
161
181
  return
162
182
  parent_block = self._operations[-2].blocks[self._blocks[-1]]
163
- parent_block.captured_vars.update(captured_vars.filter(self.parent_function))
183
+ parent_block.captured_vars.update(
184
+ captured_vars.filter_vars(self.parent_function)
185
+ )
164
186
 
165
187
  @contextmanager
166
188
  def source_ref_context(
@@ -1,31 +1,23 @@
1
1
  from collections.abc import Mapping
2
2
  from typing import TYPE_CHECKING, Any
3
3
 
4
- from classiq.interface.exceptions import ClassiqInternalExpansionError
5
4
  from classiq.interface.generator.expressions.qmod_struct_instance import (
6
5
  QmodStructInstance,
7
6
  )
8
7
  from classiq.interface.generator.functions.type_name import Struct
9
- from classiq.interface.generator.visitor import Visitor
10
8
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
11
9
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
12
10
  from classiq.interface.model.port_declaration import PortDeclaration
13
- from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
14
11
  from classiq.interface.model.quantum_function_declaration import (
15
12
  PositionalArg,
16
13
  QuantumFunctionDeclaration,
17
14
  QuantumOperandDeclaration,
18
15
  )
19
- from classiq.interface.model.quantum_lambda_function import (
20
- QuantumCallable,
21
- QuantumLambdaFunction,
22
- )
23
16
  from classiq.interface.model.quantum_statement import QuantumStatement
24
17
 
25
18
  from classiq.model_expansions.closure import (
26
19
  FunctionClosure,
27
20
  GenerativeClosure,
28
- GenerativeFunctionClosure,
29
21
  )
30
22
  from classiq.model_expansions.scope import Evaluated, QuantumSymbol
31
23
  from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
@@ -35,7 +27,6 @@ from classiq.qmod.qmod_variable import QNum, _create_qvar_for_qtype
35
27
  from classiq.qmod.quantum_callable import QCallable
36
28
  from classiq.qmod.quantum_expandable import (
37
29
  QExpandable,
38
- QLambdaFunction,
39
30
  QTerminalCallable,
40
31
  )
41
32
  from classiq.qmod.quantum_function import QFunc
@@ -71,12 +62,18 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated)
71
62
  )
72
63
  if isinstance(param, QuantumOperandDeclaration):
73
64
  if param.is_list:
74
- return QTerminalCallable(
75
- QuantumOperandDeclaration(
76
- name=param.name,
77
- positional_arg_declarations=param.positional_arg_declarations,
78
- is_list=True,
79
- ),
65
+ func_list: list[FunctionClosure] = evaluated.as_type(list)
66
+ return LenList(
67
+ [
68
+ QTerminalCallable(
69
+ QuantumOperandDeclaration(
70
+ name=param.name,
71
+ positional_arg_declarations=param.positional_arg_declarations,
72
+ ),
73
+ index_=idx,
74
+ )
75
+ for idx in range(len(func_list))
76
+ ]
80
77
  )
81
78
  else:
82
79
  func = evaluated.as_type(FunctionClosure)
@@ -119,7 +116,7 @@ class _InterpreterExpandable(QFunc):
119
116
  name=name,
120
117
  positional_arg_declarations=evaluated.value.positional_arg_declarations,
121
118
  )
122
- for name, evaluated in self._interpreter._current_scope.items()
119
+ for name, evaluated in self._interpreter._builder.current_scope.items()
123
120
  if isinstance(evaluated, Evaluated)
124
121
  and isinstance(evaluated.value, FunctionClosure)
125
122
  } | nameables_to_dict(self._interpreter._get_function_declarations())
@@ -143,78 +140,3 @@ def emit_generative_statements(
143
140
  True
144
141
  ):
145
142
  generative_function._py_callable(*python_qmod_args)
146
-
147
-
148
- def emit_operands_as_declarative(
149
- interpreter: "Interpreter", param: PositionalArg, arg: Evaluated
150
- ) -> ArgValue:
151
- if not isinstance(param, QuantumOperandDeclaration):
152
- return arg.emit()
153
- value = arg.value
154
- if isinstance(value, list):
155
- return [
156
- _expand_operand_as_declarative(interpreter, param, item) for item in value
157
- ]
158
- if isinstance(value, GenerativeFunctionClosure):
159
- return _expand_operand_as_declarative(interpreter, param, value)
160
- if isinstance(value, FunctionClosure):
161
- if value.is_lambda:
162
- raise ClassiqInternalExpansionError
163
- _register_declarative_function(interpreter, value.name)
164
- return value.name
165
- raise ClassiqInternalExpansionError
166
-
167
-
168
- def _expand_operand_as_declarative(
169
- interpreter: "Interpreter",
170
- param: QuantumOperandDeclaration,
171
- arg: GenerativeFunctionClosure,
172
- ) -> QuantumCallable:
173
- if not arg.is_lambda:
174
- _register_declarative_function(interpreter, arg.name)
175
- return arg.name
176
- val = QLambdaFunction(param, arg.generative_blocks["body"]._py_callable)
177
- with generative_mode_context(False):
178
- val.expand()
179
- _DecFuncVisitor(interpreter).visit(val.body)
180
- qlambda = QuantumLambdaFunction(
181
- pos_rename_params=val.infer_rename_params(),
182
- body=val.body,
183
- )
184
- qlambda.set_op_decl(param)
185
- return qlambda
186
-
187
-
188
- def _register_declarative_function(interpreter: "Interpreter", func_name: str) -> None:
189
- if func_name in nameables_to_dict(list(interpreter._expanded_functions.values())):
190
- return
191
-
192
- for user_gen_func in interpreter._generative_functions:
193
- if user_gen_func.func_decl.name == func_name:
194
- break
195
- else:
196
- return
197
-
198
- with generative_mode_context(False):
199
- dec_func = QFunc(user_gen_func._py_callable)
200
- dec_func.expand()
201
- dec_func_def = QMODULE.native_defs[func_name]
202
- interpreter._expanded_functions[func_name] = dec_func_def
203
- _DecFuncVisitor(interpreter).visit(dec_func_def)
204
-
205
-
206
- class _DecFuncVisitor(Visitor):
207
- def __init__(self, interpreter: "Interpreter"):
208
- self._interpreter = interpreter
209
-
210
- def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
211
- _register_declarative_function(self._interpreter, call.func_name)
212
- for arg in call.positional_args:
213
- if isinstance(arg, str):
214
- arg = [arg]
215
- if isinstance(arg, list):
216
- for possible_func_name in arg:
217
- if isinstance(possible_func_name, str):
218
- _register_declarative_function(
219
- self._interpreter, possible_func_name
220
- )