classiq 0.100.0__py3-none-any.whl → 0.104.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 (95) hide show
  1. classiq/__init__.py +3 -0
  2. classiq/_internals/api_wrapper.py +29 -4
  3. classiq/applications/chemistry/op_utils.py +63 -1
  4. classiq/applications/chemistry/problems.py +18 -6
  5. classiq/applications/chemistry/ucc.py +2 -2
  6. classiq/evaluators/parameter_types.py +1 -4
  7. classiq/evaluators/qmod_annotated_expression.py +1 -1
  8. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
  9. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
  10. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
  11. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
  12. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
  13. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
  14. classiq/evaluators/qmod_node_evaluators/utils.py +6 -3
  15. classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
  16. classiq/execution/__init__.py +11 -1
  17. classiq/execution/execution_session.py +1 -1
  18. classiq/execution/functions/__init__.py +3 -0
  19. classiq/execution/functions/_logging.py +19 -0
  20. classiq/execution/functions/constants.py +9 -0
  21. classiq/execution/functions/parse_provider_backend.py +90 -0
  22. classiq/execution/functions/sample.py +257 -0
  23. classiq/execution/jobs.py +122 -5
  24. classiq/interface/_version.py +1 -1
  25. classiq/interface/backend/backend_preferences.py +15 -0
  26. classiq/interface/backend/provider_config/providers/aqt.py +1 -1
  27. classiq/interface/backend/provider_config/providers/azure.py +1 -2
  28. classiq/interface/backend/provider_config/providers/ibm.py +1 -1
  29. classiq/interface/backend/quantum_backend_providers.py +3 -0
  30. classiq/interface/exceptions.py +0 -42
  31. classiq/interface/executor/execution_request.py +1 -0
  32. classiq/interface/executor/quantum_code.py +0 -6
  33. classiq/interface/executor/result.py +9 -5
  34. classiq/interface/generator/arith/binary_ops.py +38 -2
  35. classiq/interface/generator/function_param_list.py +4 -2
  36. classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
  37. classiq/interface/generator/functions/classical_type.py +45 -0
  38. classiq/interface/generator/functions/type_name.py +23 -0
  39. classiq/interface/generator/generated_circuit_data.py +0 -2
  40. classiq/interface/generator/generation_request.py +9 -4
  41. classiq/interface/generator/quantum_program.py +8 -36
  42. classiq/interface/generator/types/compilation_metadata.py +9 -0
  43. classiq/interface/hardware.py +1 -0
  44. classiq/interface/helpers/model_normalizer.py +62 -2
  45. classiq/interface/helpers/text_utils.py +17 -6
  46. classiq/interface/interface_version.py +1 -1
  47. classiq/interface/model/invert.py +15 -0
  48. classiq/interface/model/model.py +42 -3
  49. classiq/interface/model/model_visitor.py +4 -2
  50. classiq/interface/model/quantum_function_call.py +17 -5
  51. classiq/interface/model/quantum_type.py +21 -0
  52. classiq/interface/model/statement_block.py +0 -4
  53. classiq/model_expansions/capturing/captured_vars.py +16 -12
  54. classiq/model_expansions/function_builder.py +9 -1
  55. classiq/model_expansions/interpreters/base_interpreter.py +12 -10
  56. classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
  57. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
  58. classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
  59. classiq/model_expansions/quantum_operations/bind.py +4 -0
  60. classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
  61. classiq/model_expansions/quantum_operations/emitter.py +1 -4
  62. classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
  63. classiq/model_expansions/visitors/uncomputation_signature_inference.py +15 -47
  64. classiq/open_library/functions/__init__.py +42 -27
  65. classiq/open_library/functions/bit_operations.py +30 -0
  66. classiq/open_library/functions/modular_arithmetics.py +597 -0
  67. classiq/open_library/functions/qft_space_arithmetics.py +81 -0
  68. classiq/open_library/functions/state_preparation.py +6 -3
  69. classiq/open_library/functions/utility_functions.py +22 -3
  70. classiq/qmod/builtins/functions/__init__.py +9 -0
  71. classiq/qmod/builtins/functions/arithmetic.py +131 -0
  72. classiq/qmod/builtins/functions/exponentiation.py +34 -4
  73. classiq/qmod/builtins/operations.py +30 -41
  74. classiq/qmod/native/pretty_printer.py +12 -12
  75. classiq/qmod/pretty_print/pretty_printer.py +11 -15
  76. classiq/qmod/qmod_parameter.py +4 -0
  77. classiq/qmod/qmod_variable.py +38 -63
  78. classiq/qmod/quantum_callable.py +8 -2
  79. classiq/qmod/quantum_expandable.py +3 -1
  80. classiq/qmod/quantum_function.py +45 -8
  81. classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
  82. classiq/qmod/semantics/validation/model_validation.py +7 -2
  83. classiq/qmod/symbolic_type.py +4 -2
  84. classiq/qmod/utilities.py +7 -4
  85. classiq/synthesis_action/__init__.py +20 -0
  86. classiq/synthesis_action/actions.py +106 -0
  87. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/METADATA +1 -1
  88. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/RECORD +90 -84
  89. classiq/interface/executor/register_initialization.py +0 -36
  90. classiq/interface/generator/amplitude_loading.py +0 -103
  91. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
  92. classiq/open_library/functions/modular_exponentiation.py +0 -272
  93. classiq/open_library/functions/qsvt_temp.py +0 -536
  94. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/WHEEL +0 -0
  95. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -6,11 +6,32 @@ from classiq.interface.generator.expressions.expression import Expression
6
6
  from classiq.interface.generator.functions.classical_type import ClassicalType
7
7
  from classiq.interface.generator.functions.type_modifier import TypeModifier
8
8
  from classiq.interface.generator.visitor import Transformer, Visitor
9
+ from classiq.interface.model.handle_binding import HandleBinding
9
10
  from classiq.interface.model.model import Model
10
- from classiq.interface.model.port_declaration import AnonPortDeclaration
11
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
12
+ from classiq.interface.model.port_declaration import (
13
+ PortDeclaration,
14
+ )
15
+ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
16
+ from classiq.interface.model.variable_declaration_statement import (
17
+ VariableDeclarationStatement,
18
+ )
19
+
20
+ from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
11
21
 
12
22
 
13
23
  class ModelNormalizer(Visitor):
24
+ def __init__(
25
+ self,
26
+ normalize_func_names: bool = False,
27
+ normalize_quantum_var_names: bool = False,
28
+ ) -> None:
29
+ self._normalize_func_names = normalize_func_names
30
+ self._normalize_quantum_var_names = normalize_quantum_var_names
31
+ self._funcs_renames: dict[str, str] = {}
32
+ self._count_name = CountedNameAllocator()
33
+ self.original_names: dict[str, str] = {}
34
+
14
35
  def visit(self, node: Any) -> None:
15
36
  if isinstance(node, ASTNode):
16
37
  node.model_config["frozen"] = False
@@ -23,10 +44,49 @@ class ModelNormalizer(Visitor):
23
44
  def visit_Model(self, model: Model) -> None:
24
45
  model.debug_info = DebugInfoCollection()
25
46
  model.functions.sort(key=lambda x: x.name)
47
+ self._funcs_renames = {
48
+ func.name: f"___func_{index}" for index, func in enumerate(model.functions)
49
+ }
26
50
  self.generic_visit(model)
27
51
 
28
- def visit_AnonPortDeclaration(self, decl: AnonPortDeclaration) -> None:
52
+ def visit_NativeFunctionDefinition(self, func: NativeFunctionDefinition) -> None:
53
+ if self._normalize_func_names:
54
+ func.name = self._funcs_renames[func.name]
55
+ self.generic_visit(func)
56
+
57
+ def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
58
+ if self._normalize_func_names:
59
+ if isinstance(call.function, str):
60
+ if call.function in self._funcs_renames:
61
+ call.function = self._funcs_renames[call.function]
62
+ else:
63
+ if call.function.name in self._funcs_renames:
64
+ call.function.name = self._funcs_renames[call.function.name]
65
+ self.generic_visit(call)
66
+
67
+ def visit_PortDeclaration(self, decl: PortDeclaration) -> None:
29
68
  decl.type_modifier = TypeModifier.Mutable
69
+ self._rename_quantum_var(decl, "_port")
70
+
71
+ def visit_VariableDeclarationStatement(
72
+ self, var: VariableDeclarationStatement
73
+ ) -> None:
74
+ self._rename_quantum_var(var, "_var")
75
+
76
+ def _rename_quantum_var(
77
+ self, var: VariableDeclarationStatement | PortDeclaration, new_name_prefix: str
78
+ ) -> None:
79
+ if self._normalize_quantum_var_names:
80
+ old_name = var.name
81
+ var.name = self._count_name.allocate(new_name_prefix)
82
+ self.original_names[old_name] = var.name
83
+
84
+ def visit_HandleBinding(self, handle: HandleBinding) -> None:
85
+ if self._normalize_quantum_var_names:
86
+ # this is a hack use just for testing, do not use in production
87
+ object.__setattr__(
88
+ handle, "name", self.original_names.get(handle.name, handle.name)
89
+ )
30
90
 
31
91
 
32
92
  class ClearModelInternals(Transformer):
@@ -1,22 +1,33 @@
1
- def s(items: list | int) -> str:
2
- if isinstance(items, list):
1
+ from collections.abc import Sequence, Sized
2
+
3
+
4
+ def s(items: Sized | int) -> str:
5
+ if isinstance(items, Sized):
3
6
  items = len(items)
4
7
  return "" if items == 1 else "s"
5
8
 
6
9
 
7
- def are(items: list) -> str:
10
+ def are(items: Sized) -> str:
8
11
  return "is" if len(items) == 1 else "are"
9
12
 
10
13
 
11
- def they(items: list) -> str:
14
+ def were(items: Sized) -> str:
15
+ return "was" if len(items) == 1 else "were"
16
+
17
+
18
+ def an(items: Sized) -> str:
19
+ return "an " if len(items) == 1 else ""
20
+
21
+
22
+ def they(items: Sized) -> str:
12
23
  return "it" if len(items) == 1 else "they"
13
24
 
14
25
 
15
- def conj(items: list) -> str:
26
+ def conj(items: Sized) -> str:
16
27
  return "s" if len(items) == 1 else ""
17
28
 
18
29
 
19
- def readable_list(items: list, quote: bool = False) -> str:
30
+ def readable_list(items: Sequence, quote: bool = False) -> str:
20
31
  if quote:
21
32
  items = [repr(str(item)) for item in items]
22
33
  if len(items) == 1:
@@ -1 +1 @@
1
- INTERFACE_VERSION = "15"
1
+ INTERFACE_VERSION = "16"
@@ -1,16 +1,25 @@
1
1
  from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.ast_node import ASTNodeType, reset_lists
4
+ from classiq.interface.enum_utils import StrEnum
5
+ from classiq.interface.exceptions import ClassiqInternalExpansionError
6
+ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
4
7
  from classiq.interface.model.quantum_statement import QuantumOperation
5
8
 
6
9
  if TYPE_CHECKING:
7
10
  from classiq.interface.model.statement_block import StatementBlock
8
11
 
9
12
 
13
+ class BlockKind(StrEnum):
14
+ SingleCall = "single_call"
15
+ Compound = "compound"
16
+
17
+
10
18
  class Invert(QuantumOperation):
11
19
  kind: Literal["Invert"]
12
20
 
13
21
  body: "StatementBlock"
22
+ block_kind: BlockKind = BlockKind.Compound
14
23
 
15
24
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
16
25
  return reset_lists(self, ["body"])
@@ -18,3 +27,9 @@ class Invert(QuantumOperation):
18
27
  @property
19
28
  def blocks(self) -> dict[str, "StatementBlock"]:
20
29
  return {"body": self.body}
30
+
31
+ def validate_node(self) -> None:
32
+ if self.block_kind == BlockKind.SingleCall and (
33
+ len(self.body) != 1 or not isinstance(self.body[0], QuantumFunctionCall)
34
+ ):
35
+ raise ClassiqInternalExpansionError("Malformed single-call invert")
@@ -5,6 +5,7 @@ from typing import Annotated, Any, Literal, NewType
5
5
  import pydantic
6
6
 
7
7
  from classiq.interface.ast_node import ASTNode
8
+ from classiq.interface.compression_utils import compress_pydantic, decompress
8
9
  from classiq.interface.debug_info.debug_info import DebugInfoCollection
9
10
  from classiq.interface.exceptions import ClassiqValueError
10
11
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
@@ -96,9 +97,9 @@ class Model(VersionedModel, ASTNode):
96
97
  )
97
98
  preferences: Preferences = pydantic.Field(default_factory=Preferences)
98
99
 
99
- debug_info: DebugInfoCollection = pydantic.Field(
100
- default_factory=DebugInfoCollection
101
- )
100
+ _debug_info: DebugInfoCollection | None = pydantic.PrivateAttr(default=None)
101
+ compressed_debug_info: bytes | None = pydantic.Field(default=None)
102
+
102
103
  functions_compilation_metadata: defaultdict[
103
104
  str,
104
105
  Annotated[
@@ -198,3 +199,41 @@ class Model(VersionedModel, ASTNode):
198
199
  return model.model_dump(
199
200
  exclude={"constraints", "execution_preferences", "preferences"},
200
201
  )
202
+
203
+ # TODO (CLS-4966): remove
204
+ @pydantic.model_validator(mode="wrap")
205
+ @classmethod
206
+ def get_deprecated_debug_info(
207
+ cls, data: Any, handler: pydantic.ModelWrapValidatorHandler
208
+ ) -> "Model":
209
+ model = handler(data)
210
+ if isinstance(data, dict) and "debug_info" in data:
211
+ model._debug_info = DebugInfoCollection.model_validate(data["debug_info"])
212
+ return model
213
+
214
+ @property
215
+ def debug_info(self) -> DebugInfoCollection:
216
+ if self._debug_info is None:
217
+ if self.compressed_debug_info is None:
218
+ self._debug_info = DebugInfoCollection()
219
+ else:
220
+ self._debug_info = DebugInfoCollection.model_validate(
221
+ decompress(self.compressed_debug_info)
222
+ )
223
+
224
+ return self._debug_info
225
+
226
+ @debug_info.setter
227
+ def debug_info(self, value: DebugInfoCollection) -> None:
228
+ self._debug_info = value
229
+ self.compressed_debug_info = None
230
+
231
+ def clear_debug_info(self) -> None:
232
+ self._debug_info = None
233
+ self.compressed_debug_info = None
234
+
235
+ def compress_debug_info(self) -> None:
236
+ if self._debug_info is None:
237
+ self.compressed_debug_info = None
238
+ else:
239
+ self.compressed_debug_info = compress_pydantic(self._debug_info)
@@ -10,8 +10,10 @@ from classiq.interface.model.quantum_statement import QuantumStatement
10
10
 
11
11
 
12
12
  class ModelVisitor(Visitor):
13
- def visit_DebugInfoCollection(self, debug_info: DebugInfoCollection) -> None:
14
- return
13
+ def visit_DebugInfoCollection(
14
+ self, debug_info: DebugInfoCollection
15
+ ) -> RetType | None:
16
+ return None
15
17
 
16
18
 
17
19
  class ModelStatementsVisitor(ModelVisitor):
@@ -29,6 +29,13 @@ from classiq.interface.model.quantum_lambda_function import (
29
29
  )
30
30
  from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
31
31
 
32
+
33
+ def _split_concatenation(var: HandleBinding | HandlesList) -> list[HandleBinding]:
34
+ if isinstance(var, HandleBinding):
35
+ return [var]
36
+ return list(chain.from_iterable(_split_concatenation(item) for item in var.handles))
37
+
38
+
32
39
  ArgValue = Union[
33
40
  Expression,
34
41
  QuantumOperand,
@@ -221,18 +228,23 @@ class QuantumFunctionCall(QuantumOperation):
221
228
  def _get_handles_with_declarations(
222
229
  self,
223
230
  ) -> Iterable[tuple[int, AnonPortDeclaration, HandleBinding]]:
231
+ """
232
+ Get variable arguments attached to their position and parameter declaration.
233
+ Splits concatenations into variables.
234
+ """
224
235
  return [
225
- (idx, port, handle)
226
- for idx, (port, handle) in enumerate(
236
+ (positional_idx, port, var)
237
+ for positional_idx, (port, var_or_concatenation) in enumerate(
227
238
  zip(
228
239
  (port_decl for port_decl in self.func_decl.port_declarations),
229
240
  (
230
- param
231
- for param in self.positional_args
232
- if isinstance(param, HandleBinding)
241
+ arg
242
+ for arg in self.positional_args
243
+ if isinstance(arg, (HandleBinding, HandlesList))
233
244
  ),
234
245
  )
235
246
  )
247
+ for var in _split_concatenation(var_or_concatenation)
236
248
  ]
237
249
 
238
250
  def _get_readable_location(
@@ -78,6 +78,9 @@ class QuantumType(HashableASTNode):
78
78
  def without_symbolic_attributes(self) -> Self:
79
79
  return self
80
80
 
81
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
82
+ return {}
83
+
81
84
 
82
85
  class QuantumScalar(QuantumType):
83
86
  @property
@@ -262,6 +265,14 @@ class QuantumBitvector(QuantumType):
262
265
  length = 1
263
266
  return length * self.element_type.minimal_size_in_bits
264
267
 
268
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
269
+ attrs: dict[str, Any] = {}
270
+ if self.has_constant_length:
271
+ attrs[f"{path_expr_prefix}.len"] = self.length_value
272
+ return attrs | self.element_type.get_compile_time_attributes(
273
+ f"{path_expr_prefix}[0]"
274
+ )
275
+
265
276
  def without_symbolic_attributes(self) -> "QuantumBitvector":
266
277
  length = (
267
278
  None
@@ -301,6 +312,16 @@ class QuantumNumeric(QuantumScalar):
301
312
  )
302
313
  return self
303
314
 
315
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
316
+ attrs: dict[str, Any] = {}
317
+ if self.has_size_in_bits:
318
+ attrs[f"{path_expr_prefix}.size"] = self.size_in_bits
319
+ if self.has_constant_sign:
320
+ attrs[f"{path_expr_prefix}.is_signed"] = self.sign_value
321
+ if self.has_constant_fraction_digits:
322
+ attrs[f"{path_expr_prefix}.fraction_digits"] = self.fraction_digits_value
323
+ return attrs
324
+
304
325
  def set_size_in_bits(self, val: int) -> None:
305
326
  super().set_size_in_bits(val)
306
327
  if self.size is not None:
@@ -13,9 +13,6 @@ from classiq.interface.model.invert import Invert
13
13
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
14
14
  from classiq.interface.model.phase_operation import PhaseOperation
15
15
  from classiq.interface.model.power import Power
16
- from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
17
- AmplitudeLoadingOperation,
18
- )
19
16
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
20
17
  ArithmeticOperation,
21
18
  )
@@ -38,7 +35,6 @@ ConcreteQuantumStatement = Annotated[
38
35
  QuantumFunctionCall,
39
36
  Allocate,
40
37
  ArithmeticOperation,
41
- AmplitudeLoadingOperation,
42
38
  VariableDeclarationStatement,
43
39
  BindOperation,
44
40
  InplaceBinaryOperation,
@@ -56,8 +56,8 @@ if TYPE_CHECKING:
56
56
  from classiq.model_expansions.closure import FunctionClosure
57
57
 
58
58
 
59
- INITIALIZED_VAR_MESSAGE = "Variable '{}' should be uninitialized here"
60
- UNINITIALIZED_VAR_MESSAGE = "Variable '{}' should be initialized here"
59
+ _INITIALIZED_VAR_MESSAGE = "Variable '{}' should be uninitialized here"
60
+ _UNINITIALIZED_VAR_MESSAGE = "Variable '{}' should be initialized here"
61
61
 
62
62
 
63
63
  def _get_symbol_expr(symbol: str, classical_type: ClassicalType) -> Expression:
@@ -311,7 +311,7 @@ class CapturedVars:
311
311
  return PortDirection.Inout
312
312
  if target_direction == PortDirection.Outin:
313
313
  return PortDirection.Input
314
- raise ClassiqExpansionError(UNINITIALIZED_VAR_MESSAGE.format(var_name))
314
+ raise ClassiqExpansionError(_UNINITIALIZED_VAR_MESSAGE.format(var_name))
315
315
 
316
316
  if source_direction == PortDirection.Output:
317
317
  if target_direction == PortDirection.Input:
@@ -320,18 +320,18 @@ class CapturedVars:
320
320
  PortDirection.Output,
321
321
  PortDirection.Outin,
322
322
  ):
323
- raise ClassiqExpansionError(INITIALIZED_VAR_MESSAGE.format(var_name))
323
+ raise ClassiqExpansionError(_INITIALIZED_VAR_MESSAGE.format(var_name))
324
324
  return PortDirection.Output
325
325
 
326
326
  if source_direction == PortDirection.Inout:
327
327
  if target_direction in (PortDirection.Input, PortDirection.Inout):
328
328
  return target_direction
329
- raise ClassiqExpansionError(INITIALIZED_VAR_MESSAGE.format(var_name))
329
+ raise ClassiqExpansionError(_INITIALIZED_VAR_MESSAGE.format(var_name))
330
330
 
331
331
  if source_direction == PortDirection.Outin:
332
332
  if target_direction in (PortDirection.Output, PortDirection.Outin):
333
333
  return target_direction
334
- raise ClassiqExpansionError(UNINITIALIZED_VAR_MESSAGE.format(var_name))
334
+ raise ClassiqExpansionError(_UNINITIALIZED_VAR_MESSAGE.format(var_name))
335
335
 
336
336
  raise ClassiqInternalExpansionError(f"Unexpected direction {source_direction}")
337
337
 
@@ -346,7 +346,7 @@ class CapturedVars:
346
346
  PortDirection.Outin,
347
347
  ):
348
348
  raise ClassiqExpansionError(
349
- UNINITIALIZED_VAR_MESSAGE.format(captured_handle.handle)
349
+ _UNINITIALIZED_VAR_MESSAGE.format(captured_handle.handle)
350
350
  )
351
351
  return existing_captured_handle
352
352
 
@@ -356,7 +356,7 @@ class CapturedVars:
356
356
  PortDirection.Outin,
357
357
  ):
358
358
  raise ClassiqExpansionError(
359
- INITIALIZED_VAR_MESSAGE.format(captured_handle.handle)
359
+ _INITIALIZED_VAR_MESSAGE.format(captured_handle.handle)
360
360
  )
361
361
  return captured_handle
362
362
 
@@ -705,7 +705,9 @@ class CapturedVars:
705
705
  def set_parent(self, parent: "CapturedVars") -> None:
706
706
  self._handle_states += parent._get_handle_states()
707
707
 
708
- def get_state(self, var_name: str, defining_function: "FunctionClosure") -> bool:
708
+ def get_state(
709
+ self, var_name: str, defining_function: "FunctionClosure"
710
+ ) -> bool | None:
709
711
  for name, func, state in self._handle_states:
710
712
  if name == var_name and _same_closure(func, defining_function):
711
713
  return state
@@ -717,9 +719,7 @@ class CapturedVars:
717
719
  PortDirection.Output,
718
720
  PortDirection.Inout,
719
721
  )
720
- raise ClassiqInternalExpansionError(
721
- f"Cannot find {var_name!r} from {defining_function.name!r}"
722
- )
722
+ return None
723
723
 
724
724
  def clone(self) -> "CapturedVars":
725
725
  return CapturedVars(
@@ -846,6 +846,10 @@ def validate_end_state(func: "FunctionClosure", captured_vars: CapturedVars) ->
846
846
  for param in func.positional_arg_declarations:
847
847
  if isinstance(param, PortDeclaration):
848
848
  state = captured_vars.get_state(param.name, func)
849
+ if state is None:
850
+ raise ClassiqInternalExpansionError(
851
+ f"Cannot find {param.name!r} from {func.name!r}"
852
+ )
849
853
  expected_state = param.direction in (
850
854
  PortDeclarationDirection.Output,
851
855
  PortDeclarationDirection.Inout,
@@ -13,6 +13,8 @@ from classiq.interface.generator.compiler_keywords import (
13
13
  )
14
14
  from classiq.interface.generator.functions.builtins.internal_operators import (
15
15
  BLOCK_OPERATOR_NAME,
16
+ INVERT_OPERATOR_NAMES,
17
+ SINGLE_CALL_INVERT_OPERATOR_NAME,
16
18
  SKIP_CONTROL_OPERATOR_NAME,
17
19
  WITHIN_APPLY_NAME,
18
20
  )
@@ -44,6 +46,7 @@ BLOCKS_ALLOWED_CAPTURING = (
44
46
  WITHIN_APPLY_NAME,
45
47
  BLOCK_OPERATOR_NAME,
46
48
  SKIP_CONTROL_OPERATOR_NAME,
49
+ SINGLE_CALL_INVERT_OPERATOR_NAME,
47
50
  )
48
51
 
49
52
 
@@ -155,6 +158,8 @@ class OperationBuilder:
155
158
  self._operations[-1].blocks[block_name] = block
156
159
  yield
157
160
  captured_vars = self.current_block.captured_vars
161
+ if self.current_operation.name in INVERT_OPERATOR_NAMES:
162
+ captured_vars = captured_vars.negate()
158
163
  if (
159
164
  not isinstance(self.current_operation, FunctionClosure)
160
165
  and self.current_operation.name not in BLOCKS_ALLOWED_CAPTURING
@@ -178,7 +183,10 @@ class OperationBuilder:
178
183
  context.closure.captured_vars.init_params(original_operation)
179
184
  else:
180
185
  context = OperationContext(closure=original_operation)
181
- context.closure.captured_vars.set_parent(self.current_block.captured_vars)
186
+ if context.name != SINGLE_CALL_INVERT_OPERATOR_NAME:
187
+ context.closure.captured_vars.set_parent(
188
+ self.current_block.captured_vars
189
+ )
182
190
  self._operations.append(context)
183
191
  yield context
184
192
  self._finalize_within_apply()
@@ -32,6 +32,7 @@ from classiq.interface.model.handle_binding import (
32
32
  from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
33
33
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
34
34
  from classiq.interface.model.quantum_function_declaration import (
35
+ NamedParamsQuantumFunctionDeclaration,
35
36
  QuantumFunctionDeclaration,
36
37
  )
37
38
  from classiq.interface.model.quantum_lambda_function import (
@@ -76,6 +77,7 @@ from classiq.model_expansions.scope_initialization import (
76
77
  from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
77
78
  from classiq.qmod.builtins.constants import __all__ as builtin_constants
78
79
  from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
80
+ from classiq.qmod.builtins.functions import CORE_LIB_DECLS
79
81
  from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
80
82
  from classiq.qmod.model_state_container import QMODULE
81
83
  from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
@@ -98,7 +100,7 @@ class BaseInterpreter:
98
100
  skip_type_modifier_validation: bool = False
99
101
 
100
102
  def __init__(self, model: Model) -> None:
101
- validate_model(model)
103
+ validate_model(model, self.get_builtin_functions())
102
104
  self._model = model
103
105
  self._top_level_scope = Scope()
104
106
  self._counted_name_allocator = CountedNameAllocator()
@@ -121,6 +123,9 @@ class BaseInterpreter:
121
123
  self._counted_name_allocator = CountedNameAllocator()
122
124
  self._error_manager: ErrorManager = ErrorManager()
123
125
 
126
+ def get_builtin_functions(self) -> list[NamedParamsQuantumFunctionDeclaration]:
127
+ return CORE_LIB_DECLS
128
+
124
129
  def _expand_main_func(self) -> None:
125
130
  main_closure = self._get_main_closure(
126
131
  self._top_level_scope[MAIN_FUNCTION_NAME].value
@@ -159,7 +164,7 @@ class BaseInterpreter:
159
164
  finally:
160
165
  self._error_manager.report_errors(ClassiqExpansionError)
161
166
 
162
- return Model(
167
+ model = Model(
163
168
  constraints=self._model.constraints,
164
169
  preferences=self._model.preferences,
165
170
  classical_execution_code=self._model.classical_execution_code,
@@ -181,9 +186,10 @@ class BaseInterpreter:
181
186
  if name not in BUILTIN_STRUCT_DECLARATIONS
182
187
  ],
183
188
  qstructs=list(QMODULE.qstruct_decls.values()),
184
- debug_info=self._model.debug_info,
185
189
  functions_compilation_metadata=self._expanded_functions_compilation_metadata,
186
190
  )
191
+ model.debug_info = self._model.debug_info
192
+ return model
187
193
 
188
194
  def process_exception(self, e: Exception) -> None:
189
195
  if not isinstance(e, (ClassiqError, ValidationError)):
@@ -206,15 +212,14 @@ class BaseInterpreter:
206
212
  expression: Expression,
207
213
  *,
208
214
  simplify: bool = False,
209
- treat_qnum_as_float: bool = False,
210
215
  ) -> Evaluated:
211
216
  if expression.is_evaluated():
212
217
  return Evaluated(value=expression.value.value)
213
218
  expr_ast = ast.parse(expression.expr, mode="eval").body
214
- expr_val = self._eval_expr(ast.unparse(expr_ast), treat_qnum_as_float)
219
+ expr_val = self._eval_expr(ast.unparse(expr_ast))
215
220
  if simplify and not expr_val.has_value(expr_val.root):
216
221
  simplified_expr = simplify_qmod_expression(expr_val)
217
- expr_val = self._eval_expr(simplified_expr, treat_qnum_as_float)
222
+ expr_val = self._eval_expr(simplified_expr)
218
223
  if expr_val.has_value(expr_val.root):
219
224
  value = expr_val.get_value(expr_val.root)
220
225
  else:
@@ -222,12 +227,9 @@ class BaseInterpreter:
222
227
 
223
228
  return Evaluated(value=value)
224
229
 
225
- def _eval_expr(
226
- self, expr: str, treat_qnum_as_float: bool
227
- ) -> QmodAnnotatedExpression:
230
+ def _eval_expr(self, expr: str) -> QmodAnnotatedExpression:
228
231
  return evaluate_qmod_expression(
229
232
  expr,
230
- treat_qnum_as_float=treat_qnum_as_float,
231
233
  machine_precision=self._model.preferences.machine_precision,
232
234
  classical_struct_declarations=list(QMODULE.type_decls.values()),
233
235
  enum_declarations=list(QMODULE.enum_decls.values()),
@@ -9,10 +9,11 @@ from classiq.interface.generator.expressions.expression import Expression
9
9
  from classiq.interface.generator.functions.builtins.internal_operators import (
10
10
  BLOCK_OPERATOR_NAME,
11
11
  CLASSICAL_IF_OPERATOR_NAME,
12
+ COMPOUND_INVERT_OPERATOR_NAME,
12
13
  CONTROL_OPERATOR_NAME,
13
- INVERT_OPERATOR_NAME,
14
14
  POWER_OPERATOR_NAME,
15
15
  REPEAT_OPERATOR_NAME,
16
+ SINGLE_CALL_INVERT_OPERATOR_NAME,
16
17
  SKIP_CONTROL_OPERATOR_NAME,
17
18
  WITHIN_APPLY_NAME,
18
19
  )
@@ -23,14 +24,11 @@ from classiq.interface.model.bounds import SetBoundsStatement
23
24
  from classiq.interface.model.classical_if import ClassicalIf
24
25
  from classiq.interface.model.control import Control
25
26
  from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
26
- from classiq.interface.model.invert import Invert
27
+ from classiq.interface.model.invert import BlockKind, Invert
27
28
  from classiq.interface.model.model import Model
28
29
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
29
30
  from classiq.interface.model.phase_operation import PhaseOperation
30
31
  from classiq.interface.model.power import Power
31
- from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
32
- AmplitudeLoadingOperation,
33
- )
34
32
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
35
33
  ArithmeticOperation,
36
34
  )
@@ -199,24 +197,6 @@ class GenerativeInterpreter(BaseInterpreter):
199
197
  bind
200
198
  )
201
199
 
202
- @emit.register
203
- def emit_amplitude_loading_operation(self, op: AmplitudeLoadingOperation) -> None:
204
- CompositeEmitter[AmplitudeLoadingOperation](
205
- self,
206
- [
207
- HandleEvaluator(self, "result_var"),
208
- ExpressionEvaluator(
209
- self,
210
- "expression",
211
- readable_expression_name="amplitude-encoding expression",
212
- simplify=True,
213
- treat_qnum_as_float=True,
214
- allow_runtime_vars=self._symbolic_parameters_switch,
215
- ),
216
- AssignmentResultProcessor(self),
217
- ],
218
- ).emit(op)
219
-
220
200
  @emit.register
221
201
  def _emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
222
202
  self.emit_arithmetic_operation(op)
@@ -285,7 +265,12 @@ class GenerativeInterpreter(BaseInterpreter):
285
265
 
286
266
  @emit.register
287
267
  def emit_invert(self, invert: Invert) -> None:
288
- BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
268
+ match invert.block_kind:
269
+ case BlockKind.SingleCall:
270
+ op_name = SINGLE_CALL_INVERT_OPERATOR_NAME
271
+ case BlockKind.Compound:
272
+ op_name = COMPOUND_INVERT_OPERATOR_NAME
273
+ BlockEvaluator(self, op_name, "body").emit(invert)
289
274
 
290
275
  @emit.register
291
276
  def emit_skip_control(self, skip_control: SkipControl) -> None:
@@ -50,6 +50,7 @@ def convert_inplace_op_bool_expression(
50
50
  def _supported_types() -> tuple[str, ...]:
51
51
  return (
52
52
  QuantumBit().qmod_type_name,
53
+ QuantumNumeric().qmod_type_name,
53
54
  QuantumNumeric(
54
55
  size=Expression(expr="1"),
55
56
  is_signed=Expression(expr="False"),