classiq 0.69.0__py3-none-any.whl → 0.71.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 (97) hide show
  1. classiq/analyzer/analyzer.py +0 -18
  2. classiq/analyzer/url_utils.py +9 -4
  3. classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
  4. classiq/interface/_version.py +1 -1
  5. classiq/interface/backend/quantum_backend_providers.py +6 -0
  6. classiq/interface/chemistry/operator.py +1 -21
  7. classiq/interface/debug_info/debug_info.py +4 -0
  8. classiq/interface/executor/quantum_instruction_set.py +1 -0
  9. classiq/interface/generator/arith/arithmetic.py +21 -6
  10. classiq/interface/generator/circuit_code/circuit_code.py +4 -0
  11. classiq/interface/generator/circuit_code/types_and_constants.py +1 -0
  12. classiq/interface/generator/expressions/atomic_expression_functions.py +1 -2
  13. classiq/interface/generator/expressions/expression_constants.py +0 -3
  14. classiq/interface/generator/expressions/expression_types.py +12 -4
  15. classiq/interface/generator/expressions/proxies/__init__.py +0 -0
  16. classiq/interface/generator/expressions/proxies/classical/__init__.py +0 -0
  17. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +79 -0
  18. classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +26 -0
  19. classiq/interface/generator/expressions/proxies/classical/classical_scalar_proxy.py +32 -0
  20. classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +35 -0
  21. classiq/interface/generator/expressions/proxies/classical/utils.py +34 -0
  22. classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
  23. classiq/interface/generator/expressions/{qmod_qarray_proxy.py → proxies/quantum/qmod_qarray_proxy.py} +3 -1
  24. classiq/interface/generator/expressions/{qmod_qscalar_proxy.py → proxies/quantum/qmod_qscalar_proxy.py} +3 -1
  25. classiq/interface/generator/expressions/{qmod_qstruct_proxy.py → proxies/quantum/qmod_qstruct_proxy.py} +3 -1
  26. classiq/interface/generator/functions/classical_type.py +24 -30
  27. classiq/interface/generator/functions/type_name.py +42 -2
  28. classiq/interface/generator/functions/type_qualifier.py +7 -0
  29. classiq/interface/generator/generated_circuit_data.py +22 -4
  30. classiq/interface/generator/model/preferences/preferences.py +1 -0
  31. classiq/interface/generator/quantum_function_call.py +8 -1
  32. classiq/interface/generator/quantum_program.py +0 -1
  33. classiq/interface/generator/synthesis_execution_parameter.py +1 -0
  34. classiq/interface/generator/types/compilation_metadata.py +1 -0
  35. classiq/interface/ide/visual_model.py +1 -0
  36. classiq/interface/interface_version.py +1 -1
  37. classiq/interface/model/allocate.py +7 -0
  38. classiq/interface/model/block.py +12 -0
  39. classiq/interface/model/classical_if.py +4 -0
  40. classiq/interface/model/inplace_binary_operation.py +4 -0
  41. classiq/interface/model/model.py +3 -1
  42. classiq/interface/model/native_function_definition.py +0 -10
  43. classiq/interface/model/phase_operation.py +4 -0
  44. classiq/interface/model/port_declaration.py +3 -0
  45. classiq/interface/model/power.py +4 -0
  46. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -0
  47. classiq/interface/model/quantum_function_call.py +4 -0
  48. classiq/interface/model/quantum_function_declaration.py +1 -1
  49. classiq/interface/model/quantum_statement.py +5 -0
  50. classiq/interface/model/quantum_type.py +37 -3
  51. classiq/interface/model/repeat.py +4 -0
  52. classiq/interface/model/statement_block.py +3 -0
  53. classiq/interface/model/variable_declaration_statement.py +5 -0
  54. classiq/model_expansions/atomic_expression_functions_defs.py +9 -3
  55. classiq/model_expansions/capturing/captured_vars.py +156 -34
  56. classiq/model_expansions/evaluators/arg_type_match.py +4 -2
  57. classiq/model_expansions/evaluators/classical_expression.py +2 -2
  58. classiq/model_expansions/evaluators/classical_type_inference.py +70 -0
  59. classiq/model_expansions/evaluators/control.py +1 -1
  60. classiq/model_expansions/evaluators/parameter_types.py +72 -16
  61. classiq/model_expansions/evaluators/quantum_type_utils.py +7 -57
  62. classiq/model_expansions/expression_evaluator.py +3 -12
  63. classiq/model_expansions/function_builder.py +2 -8
  64. classiq/model_expansions/generative_functions.py +39 -3
  65. classiq/model_expansions/interpreters/base_interpreter.py +3 -4
  66. classiq/model_expansions/quantum_operations/arithmetic/__init__.py +0 -0
  67. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +60 -0
  68. classiq/model_expansions/quantum_operations/assignment_result_processor.py +9 -0
  69. classiq/model_expansions/quantum_operations/call_emitter.py +46 -6
  70. classiq/model_expansions/quantum_operations/emitter.py +41 -0
  71. classiq/model_expansions/quantum_operations/expression_evaluator.py +4 -0
  72. classiq/model_expansions/quantum_operations/quantum_function_call.py +0 -22
  73. classiq/model_expansions/scope.py +7 -14
  74. classiq/model_expansions/scope_initialization.py +32 -39
  75. classiq/model_expansions/transformers/model_renamer.py +13 -4
  76. classiq/model_expansions/visitors/variable_references.py +8 -4
  77. classiq/open_library/functions/__init__.py +2 -0
  78. classiq/open_library/functions/lookup_table.py +58 -0
  79. classiq/qmod/__init__.py +3 -1
  80. classiq/qmod/declaration_inferrer.py +55 -25
  81. classiq/qmod/native/pretty_printer.py +25 -3
  82. classiq/qmod/pretty_print/pretty_printer.py +31 -14
  83. classiq/qmod/python_classical_type.py +12 -1
  84. classiq/qmod/qfunc.py +33 -8
  85. classiq/qmod/qmod_parameter.py +8 -0
  86. classiq/qmod/qmod_variable.py +189 -151
  87. classiq/qmod/quantum_function.py +3 -4
  88. classiq/qmod/semantics/annotation/call_annotation.py +0 -28
  89. classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
  90. classiq/qmod/semantics/validation/main_validation.py +1 -1
  91. classiq/qmod/semantics/validation/type_hints.py +38 -0
  92. classiq/qmod/utilities.py +38 -1
  93. {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/METADATA +10 -12
  94. {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/RECORD +97 -82
  95. {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/WHEEL +1 -1
  96. /classiq/interface/generator/expressions/{qmod_struct_instance.py → proxies/classical/qmod_struct_instance.py} +0 -0
  97. /classiq/interface/generator/expressions/{qmod_sized_proxy.py → proxies/quantum/qmod_sized_proxy.py} +0 -0
@@ -1,30 +1,31 @@
1
- from typing import TYPE_CHECKING, Any, Literal, Union
1
+ from typing import TYPE_CHECKING, Any, Literal
2
2
 
3
3
  import pydantic
4
4
  from pydantic import ConfigDict, PrivateAttr
5
- from sympy import IndexedBase, Symbol
6
5
  from typing_extensions import Self
7
6
 
8
7
  from classiq.interface.ast_node import HashableASTNode
9
- from classiq.interface.generator.expressions.expression_types import RuntimeExpression
8
+ from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
9
+ ClassicalArrayProxy,
10
+ )
11
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
12
+ ClassicalProxy,
13
+ )
14
+ from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
15
+ ClassicalScalarProxy,
16
+ )
10
17
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
18
+ from classiq.interface.model.handle_binding import HandleBinding
11
19
 
12
20
  if TYPE_CHECKING:
13
21
  from classiq.interface.generator.functions.concrete_types import (
14
22
  ConcreteClassicalType,
15
23
  )
16
24
 
17
- CLASSICAL_ATTRIBUTES = {"len", "size", "is_signed", "fraction_digits"}
18
-
19
- NamedSymbol = Union[IndexedBase, Symbol]
20
-
21
25
 
22
26
  class ClassicalType(HashableASTNode):
23
27
  _is_generative: bool = PrivateAttr(default=False)
24
28
 
25
- def as_symbolic(self, name: str) -> Union[NamedSymbol, list[NamedSymbol]]:
26
- return Symbol(name)
27
-
28
29
  model_config = ConfigDict(extra="forbid")
29
30
 
30
31
  def __str__(self) -> str:
@@ -38,13 +39,13 @@ class ClassicalType(HashableASTNode):
38
39
  def is_generative(self) -> bool:
39
40
  return self._is_generative
40
41
 
42
+ def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
43
+ return ClassicalScalarProxy(handle, self)
44
+
41
45
 
42
46
  class Integer(ClassicalType):
43
47
  kind: Literal["int"]
44
48
 
45
- def as_symbolic(self, name: str) -> Symbol:
46
- return Symbol(name, integer=True)
47
-
48
49
  @pydantic.model_validator(mode="before")
49
50
  @classmethod
50
51
  def _set_kind(cls, values: Any) -> dict[str, Any]:
@@ -54,9 +55,6 @@ class Integer(ClassicalType):
54
55
  class Real(ClassicalType):
55
56
  kind: Literal["real"]
56
57
 
57
- def as_symbolic(self, name: str) -> Symbol:
58
- return Symbol(name, real=True)
59
-
60
58
  @pydantic.model_validator(mode="before")
61
59
  @classmethod
62
60
  def _set_kind(cls, values: Any) -> dict[str, Any]:
@@ -76,14 +74,14 @@ class ClassicalList(ClassicalType):
76
74
  kind: Literal["list"]
77
75
  element_type: "ConcreteClassicalType"
78
76
 
79
- def as_symbolic(self, name: str) -> Symbol:
80
- return IndexedBase(name)
81
-
82
77
  @pydantic.model_validator(mode="before")
83
78
  @classmethod
84
79
  def _set_kind(cls, values: Any) -> dict[str, Any]:
85
80
  return values_with_discriminator(values, "kind", "list")
86
81
 
82
+ def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
83
+ raise NotImplementedError
84
+
87
85
 
88
86
  class StructMetaType(ClassicalType):
89
87
  kind: Literal["type_proxy"]
@@ -93,20 +91,23 @@ class StructMetaType(ClassicalType):
93
91
  def _set_kind(cls, values: Any) -> dict[str, Any]:
94
92
  return values_with_discriminator(values, "kind", "type_proxy")
95
93
 
94
+ def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
95
+ raise NotImplementedError
96
+
96
97
 
97
98
  class ClassicalArray(ClassicalType):
98
99
  kind: Literal["array"]
99
100
  element_type: "ConcreteClassicalType"
100
- size: pydantic.PositiveInt
101
-
102
- def as_symbolic(self, name: str) -> list:
103
- return [self.element_type.as_symbolic(f"{name}_{i}") for i in range(self.size)]
101
+ size: int
104
102
 
105
103
  @pydantic.model_validator(mode="before")
106
104
  @classmethod
107
105
  def _set_kind(cls, values: Any) -> dict[str, Any]:
108
106
  return values_with_discriminator(values, "kind", "array")
109
107
 
108
+ def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
109
+ return ClassicalArrayProxy(handle, self.element_type, self.size)
110
+
110
111
 
111
112
  class OpaqueHandle(ClassicalType):
112
113
  pass
@@ -148,12 +149,5 @@ class IQAERes(OpaqueHandle):
148
149
  return values_with_discriminator(values, "kind", "iqae_result")
149
150
 
150
151
 
151
- def as_symbolic(symbols: dict[str, ClassicalType]) -> dict[str, RuntimeExpression]:
152
- return {
153
- param_name: param_type.as_symbolic(param_name)
154
- for param_name, param_type in symbols.items()
155
- }
156
-
157
-
158
152
  class QmodPyObject:
159
153
  pass
@@ -1,10 +1,20 @@
1
1
  from collections.abc import Mapping
2
+ from itertools import chain
2
3
  from typing import TYPE_CHECKING, Any, Literal, Optional
3
4
 
4
5
  import pydantic
5
6
 
6
7
  from classiq.interface.exceptions import ClassiqExpansionError
7
- from classiq.interface.generator.expressions.qmod_qstruct_proxy import QmodQStructProxy
8
+ from classiq.interface.generator.expressions.expression import Expression
9
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
10
+ ClassicalProxy,
11
+ )
12
+ from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
13
+ ClassicalStructProxy,
14
+ )
15
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
16
+ QmodQStructProxy,
17
+ )
8
18
  from classiq.interface.generator.functions.classical_type import (
9
19
  ClassicalType,
10
20
  )
@@ -16,6 +26,7 @@ from classiq.interface.model.quantum_type import (
16
26
 
17
27
  if TYPE_CHECKING:
18
28
  from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
29
+ from classiq.interface.generator.types.struct_declaration import StructDeclaration
19
30
 
20
31
 
21
32
  class TypeName(ClassicalType, QuantumType):
@@ -24,6 +35,9 @@ class TypeName(ClassicalType, QuantumType):
24
35
  _assigned_fields: Optional[Mapping[str, "ConcreteQuantumType"]] = (
25
36
  pydantic.PrivateAttr(default=None)
26
37
  )
38
+ _classical_struct_decl: Optional["StructDeclaration"] = pydantic.PrivateAttr(
39
+ default=None
40
+ )
27
41
 
28
42
  @pydantic.model_validator(mode="before")
29
43
  @classmethod
@@ -40,7 +54,7 @@ class TypeName(ClassicalType, QuantumType):
40
54
  )
41
55
 
42
56
  def get_proxy(self, handle: "HandleBinding") -> "QmodQStructProxy":
43
- from classiq.interface.generator.expressions.qmod_qstruct_proxy import (
57
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
44
58
  QmodQStructProxy,
45
59
  )
46
60
 
@@ -81,6 +95,32 @@ class TypeName(ClassicalType, QuantumType):
81
95
  field_type.is_evaluated for field_type in self.fields.values()
82
96
  )
83
97
 
98
+ @property
99
+ def has_classical_struct_decl(self) -> bool:
100
+ return self._classical_struct_decl is not None
101
+
102
+ @property
103
+ def classical_struct_decl(self) -> "StructDeclaration":
104
+ if self._classical_struct_decl is None:
105
+ raise ClassiqExpansionError(f"Type {self.name!r} is undefined")
106
+ return self._classical_struct_decl
107
+
108
+ def set_classical_struct_decl(self, decl: "StructDeclaration") -> None:
109
+ self._classical_struct_decl = decl
110
+
111
+ def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
112
+ if self._classical_struct_decl is None:
113
+ raise ClassiqExpansionError(f"Type {self.name!r} is undefined")
114
+ return ClassicalStructProxy(handle, self._classical_struct_decl)
115
+
116
+ @property
117
+ def expressions(self) -> list[Expression]:
118
+ return list(
119
+ chain.from_iterable(
120
+ field_type.expressions for field_type in self.fields.values()
121
+ )
122
+ )
123
+
84
124
 
85
125
  class Enum(TypeName):
86
126
  pass
@@ -0,0 +1,7 @@
1
+ from classiq.interface.enum_utils import StrEnum
2
+
3
+
4
+ class TypeQualifier(StrEnum):
5
+ Const = "const"
6
+ QFree = "qfree"
7
+ Quantum = "quantum"
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import re
2
3
  from typing import Literal, Optional, Union
3
4
 
4
5
  import pydantic
@@ -7,6 +8,9 @@ from typing_extensions import TypeAlias
7
8
 
8
9
  from classiq.interface.debug_info.back_ref_util import is_allocate_or_free_by_backref
9
10
  from classiq.interface.enum_utils import StrEnum
11
+ from classiq.interface.generator.compiler_keywords import (
12
+ generate_original_function_name,
13
+ )
10
14
  from classiq.interface.generator.control_state import ControlState
11
15
  from classiq.interface.generator.register_role import RegisterRole
12
16
  from classiq.interface.generator.synthesis_metadata.synthesis_execution_data import (
@@ -32,6 +36,11 @@ ParameterName = str
32
36
  IOQubitMapping: TypeAlias = dict[str, tuple[int, ...]]
33
37
 
34
38
  CLASSIQ_HIERARCHY_SEPARATOR: Literal["__"] = "__"
39
+ QASM_SEPARATOR = "_"
40
+ SPLIT_MARKER: str = "part"
41
+ PART_SUFFIX_REGEX = re.compile(
42
+ rf".+{QASM_SEPARATOR}{SPLIT_MARKER}{QASM_SEPARATOR}(\d+)$"
43
+ )
35
44
 
36
45
  VISUALIZATION_HIDE_LIST = [
37
46
  "apply_to_all",
@@ -74,7 +83,7 @@ class GeneratedRegister(pydantic.BaseModel):
74
83
  @staticmethod
75
84
  def demangle_name(name: str) -> str:
76
85
  if is_captured_var_name(name):
77
- return demangle_capture_name(name)
86
+ name = demangle_capture_name(name)
78
87
  return demangle_name(name)
79
88
 
80
89
 
@@ -168,9 +177,18 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
168
177
 
169
178
  @property
170
179
  def name(self) -> str:
171
- if self.generated_function is None:
172
- return ""
173
- return self.generated_function.name
180
+ generated_name = self.generated_function.name if self.generated_function else ""
181
+ # Temp fix for currently "supported" statements (same as for level_ property)
182
+ if generated_name in {StatementType.CONTROL, StatementType.POWER}:
183
+ return generated_name
184
+ if self.first_back_ref and isinstance(self.first_back_ref, QuantumFunctionCall):
185
+ name = generate_original_function_name(self.first_back_ref.func_name)
186
+ if part_match := PART_SUFFIX_REGEX.match(generated_name):
187
+ suffix = f" [{part_match.group(1)}]"
188
+ else:
189
+ suffix = ""
190
+ return f"{name}{suffix}"
191
+ return generated_name
174
192
 
175
193
  @property
176
194
  def first_back_ref(self) -> Optional[ConcreteQuantumStatement]:
@@ -47,6 +47,7 @@ class QuantumFormat(StrEnum):
47
47
  IONQ = "ionq"
48
48
  CIRQ_JSON = "cirq_json"
49
49
  QASM_CIRQ_COMPATIBLE = "qasm_cirq_compatible"
50
+ EXECUTION_SERIALIZATION = "_execution_serialization"
50
51
 
51
52
 
52
53
  _SERVICE_PROVIDER_TO_FORMAT: dict[Provider, QuantumFormat] = {
@@ -40,7 +40,10 @@ from classiq.interface.generator.slice_parsing_utils import (
40
40
  SLICING,
41
41
  parse_io_slicing,
42
42
  )
43
- from classiq.interface.generator.synthesis_execution_parameter import PydanticPowerType
43
+ from classiq.interface.generator.synthesis_execution_parameter import (
44
+ ClassicalArg,
45
+ PydanticPowerType,
46
+ )
44
47
  from classiq.interface.generator.user_defined_function_params import CustomFunction
45
48
  from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyString
46
49
  from classiq.interface.helpers.hashable_pydantic_base_model import (
@@ -148,6 +151,10 @@ class SynthesisQuantumFunctionCall(BaseModel):
148
151
  description="The name of the function instance. "
149
152
  "If not set, determined automatically.",
150
153
  )
154
+ caller_parameters: Optional[list[str]] = pydantic.Field(default=None)
155
+ parameter_assignments: Optional[dict[str, ClassicalArg]] = pydantic.Field(
156
+ default=None
157
+ )
151
158
  source_id: Optional[UUID] = pydantic.Field(default=None)
152
159
  arithmetic_id: Optional[str] = pydantic.Field(default=None)
153
160
  inverse_op_id: Optional[UUID] = pydantic.Field(default=None)
@@ -117,7 +117,6 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
117
117
  instruction_set: Optional[QuantumInstructionSet] = None,
118
118
  ) -> quantum_code.QuantumCode:
119
119
  initial_values = initial_values or self.initial_values
120
-
121
120
  if instruction_set is not None:
122
121
  code, syntax = (
123
122
  self.program_circuit.get_code(instruction_set),
@@ -6,3 +6,4 @@ from classiq.interface.backend.pydantic_backend import PydanticExecutionParamete
6
6
 
7
7
  PydanticIntSynthesisExecutionParameter = Union[PydanticExecutionParameter, int]
8
8
  PydanticPowerType: TypeAlias = PydanticIntSynthesisExecutionParameter
9
+ ClassicalArg = Union[float, str]
@@ -4,3 +4,4 @@ from pydantic import BaseModel, Field, NonNegativeInt
4
4
  class CompilationMetadata(BaseModel):
5
5
  should_synthesize_separately: bool = Field(default=False)
6
6
  occurrences_number: NonNegativeInt = Field(default=1)
7
+ atomic_qualifiers: list[str] = Field(default_factory=list)
@@ -97,6 +97,7 @@ class AtomicGate(StrEnum):
97
97
  SWAP = "SWAP"
98
98
  IDENTITY = "IDENTITY"
99
99
  U = "U"
100
+ RESET = "RESET"
100
101
 
101
102
  @property
102
103
  def is_control_gate(self) -> bool:
@@ -1 +1 @@
1
- INTERFACE_VERSION = "8"
1
+ INTERFACE_VERSION = "9"
@@ -14,3 +14,10 @@ class Allocate(QuantumOperation):
14
14
  @property
15
15
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
16
16
  return {"out": self.target}
17
+
18
+ @property
19
+ def expressions(self) -> list[Expression]:
20
+ exprs = []
21
+ if self.size is not None:
22
+ exprs.append(self.size)
23
+ return exprs
@@ -0,0 +1,12 @@
1
+ from typing import TYPE_CHECKING, Literal
2
+
3
+ from classiq.interface.model.quantum_statement import QuantumOperation
4
+
5
+ if TYPE_CHECKING:
6
+ from classiq.interface.model.statement_block import StatementBlock
7
+
8
+
9
+ class Block(QuantumOperation):
10
+ kind: Literal["Block"]
11
+
12
+ statements: "StatementBlock"
@@ -17,3 +17,7 @@ class ClassicalIf(QuantumOperation):
17
17
 
18
18
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
19
19
  return reset_lists(self, ["then", "else_"])
20
+
21
+ @property
22
+ def expressions(self) -> list[Expression]:
23
+ return [self.condition]
@@ -41,3 +41,7 @@ class InplaceBinaryOperation(QuantumOperation):
41
41
  )
42
42
  )
43
43
  return readable_inouts
44
+
45
+ @property
46
+ def expressions(self) -> list[Expression]:
47
+ return [self.value] if isinstance(self.value, Expression) else []
@@ -103,7 +103,9 @@ class Model(VersionedModel, ASTNode):
103
103
  functions_compilation_metadata: dict[str, CompilationMetadata] = pydantic.Field(
104
104
  default_factory=dict
105
105
  )
106
- execution_parameters: Optional[dict[str, ConcreteClassicalType]] = None
106
+ execution_parameters: Optional[dict[str, ConcreteClassicalType]] = pydantic.Field(
107
+ default=None, exclude=True
108
+ )
107
109
 
108
110
  @property
109
111
  def main_func(self) -> NativeFunctionDefinition:
@@ -10,13 +10,6 @@ if TYPE_CHECKING:
10
10
  from classiq.interface.model.statement_block import StatementBlock
11
11
 
12
12
 
13
- class FunctionSynthesisData(pydantic.BaseModel):
14
- should_synthesize_separately: bool = pydantic.Field(
15
- default=False,
16
- description="Whether the function should be synthesized separately.",
17
- )
18
-
19
-
20
13
  class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
21
14
  """
22
15
  Facilitates the creation of a user-defined composite function
@@ -28,6 +21,3 @@ class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
28
21
  body: "StatementBlock" = pydantic.Field(
29
22
  default_factory=list, description="List of function calls to perform."
30
23
  )
31
- synthesis_data: FunctionSynthesisData = pydantic.Field(
32
- default_factory=FunctionSynthesisData, deprecated=True, exclude=True
33
- )
@@ -9,3 +9,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
9
9
  class PhaseOperation(QuantumExpressionOperation):
10
10
  kind: Literal["PhaseOperation"]
11
11
  theta: Expression
12
+
13
+ @property
14
+ def expressions(self) -> list[Expression]:
15
+ return super().expressions + [self.theta]
@@ -8,6 +8,7 @@ from classiq.interface.generator.functions.concrete_types import ConcreteQuantum
8
8
  from classiq.interface.generator.functions.port_declaration import (
9
9
  PortDeclarationDirection,
10
10
  )
11
+ from classiq.interface.generator.functions.type_qualifier import TypeQualifier
11
12
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
12
13
  from classiq.interface.model.parameter import Parameter
13
14
 
@@ -15,6 +16,8 @@ from classiq.interface.model.parameter import Parameter
15
16
  class AnonPortDeclaration(Parameter):
16
17
  quantum_type: ConcreteQuantumType
17
18
  direction: PortDeclarationDirection
19
+ # TODO remove default after BWC-breaking version
20
+ type_qualifier: TypeQualifier = pydantic.Field(default=TypeQualifier.Quantum)
18
21
  kind: Literal["PortDeclaration"]
19
22
 
20
23
  @pydantic.model_validator(mode="before")
@@ -16,3 +16,7 @@ class Power(QuantumOperation):
16
16
 
17
17
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
18
18
  return reset_lists(self, ["body"])
19
+
20
+ @property
21
+ def expressions(self) -> list[Expression]:
22
+ return [self.power]
@@ -46,6 +46,10 @@ class QuantumExpressionOperation(QuantumOperation):
46
46
  def wiring_inouts(self) -> Mapping[str, ConcreteHandleBinding]:
47
47
  return nameables_to_dict(self.var_handles)
48
48
 
49
+ @property
50
+ def expressions(self) -> list[Expression]:
51
+ return [self.expression]
52
+
49
53
 
50
54
  class QuantumAssignmentOperation(QuantumExpressionOperation):
51
55
  result_var: ConcreteHandleBinding = pydantic.Field(
@@ -170,6 +170,10 @@ class QuantumFunctionCall(QuantumOperation):
170
170
  param for param in self.positional_args if isinstance(param, HandleBinding)
171
171
  ]
172
172
 
173
+ @property
174
+ def expressions(self) -> list[Expression]:
175
+ return [arg for arg in self.positional_args if isinstance(arg, Expression)]
176
+
173
177
  def _get_handles_by_direction(
174
178
  self, direction: PortDeclarationDirection
175
179
  ) -> list[tuple[int, AnonPortDeclaration, HandleBinding]]:
@@ -87,7 +87,7 @@ class AnonQuantumFunctionDeclaration(FunctionDeclaration):
87
87
  ]
88
88
 
89
89
  @property
90
- def param_names(self) -> Sequence[str]:
90
+ def param_names(self) -> list[str]:
91
91
  return [param.get_name() for param in self.param_decls]
92
92
 
93
93
  @property
@@ -8,6 +8,7 @@ from pydantic import ConfigDict
8
8
  from typing_extensions import Self
9
9
 
10
10
  from classiq.interface.ast_node import ASTNode
11
+ from classiq.interface.generator.expressions.expression import Expression
11
12
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
12
13
  from classiq.interface.model.handle_binding import (
13
14
  ConcreteHandleBinding,
@@ -39,6 +40,10 @@ class QuantumStatement(ASTNode):
39
40
  def _set_kind(cls, values: Any) -> dict[str, Any]:
40
41
  return values_with_discriminator(values, "kind", cls.__name__)
41
42
 
43
+ @property
44
+ def expressions(self) -> list[Expression]:
45
+ return []
46
+
42
47
 
43
48
  @dataclass
44
49
  class HandleMetadata:
@@ -11,13 +11,17 @@ from classiq.interface.generator.arith.register_user_input import (
11
11
  RegisterUserInput,
12
12
  )
13
13
  from classiq.interface.generator.expressions.expression import Expression
14
- from classiq.interface.generator.expressions.qmod_qarray_proxy import QmodQArrayProxy
15
- from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
14
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy import (
15
+ QmodQArrayProxy,
16
+ )
17
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
16
18
  QmodQBitProxy,
17
19
  QmodQNumProxy,
18
20
  QmodQScalarProxy,
19
21
  )
20
- from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
22
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
23
+ QmodSizedProxy,
24
+ )
21
25
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
22
26
  from classiq.interface.model.handle_binding import HandleBinding
23
27
 
@@ -67,6 +71,10 @@ class QuantumType(HashableASTNode):
67
71
  def is_evaluated(self) -> bool:
68
72
  raise NotImplementedError
69
73
 
74
+ @property
75
+ def expressions(self) -> list[Expression]:
76
+ return []
77
+
70
78
 
71
79
  class QuantumScalar(QuantumType):
72
80
  def get_proxy(self, handle: "HandleBinding") -> QmodQScalarProxy:
@@ -170,6 +178,13 @@ class QuantumBitvector(QuantumType):
170
178
  and self.element_type.is_evaluated
171
179
  )
172
180
 
181
+ @property
182
+ def expressions(self) -> list[Expression]:
183
+ exprs = self.element_type.expressions
184
+ if self.length is not None:
185
+ exprs.append(self.length)
186
+ return exprs
187
+
173
188
 
174
189
  class QuantumNumeric(QuantumScalar):
175
190
  kind: Literal["qnum"]
@@ -213,6 +228,14 @@ class QuantumNumeric(QuantumScalar):
213
228
  0 if self.fraction_digits is None else self.fraction_digits.to_int_value()
214
229
  )
215
230
 
231
+ @property
232
+ def is_qbit(self) -> bool:
233
+ return (
234
+ self.size_in_bits == 1
235
+ and self.fraction_digits_value == 0
236
+ and not self.sign_value
237
+ )
238
+
216
239
  def _update_size_in_bits_from_declaration(self) -> None:
217
240
  if self.size is not None and self.size.is_evaluated():
218
241
  self._size_in_bits = self.size.to_int_value()
@@ -253,6 +276,17 @@ class QuantumNumeric(QuantumScalar):
253
276
  self.fraction_digits is not None and not self.fraction_digits.is_evaluated()
254
277
  )
255
278
 
279
+ @property
280
+ def expressions(self) -> list[Expression]:
281
+ exprs = []
282
+ if self.size is not None:
283
+ exprs.append(self.size)
284
+ if self.is_signed is not None:
285
+ exprs.append(self.is_signed)
286
+ if self.fraction_digits is not None:
287
+ exprs.append(self.fraction_digits)
288
+ return exprs
289
+
256
290
 
257
291
  class RegisterQuantumType(BaseModel):
258
292
  quantum_types: "ConcreteQuantumType"
@@ -17,3 +17,7 @@ class Repeat(QuantumOperation):
17
17
 
18
18
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
19
19
  return reset_lists(self, ["body"])
20
+
21
+ @property
22
+ def expressions(self) -> list[Expression]:
23
+ return [self.count]
@@ -4,6 +4,7 @@ from pydantic import Field
4
4
 
5
5
  from classiq.interface.model.allocate import Allocate
6
6
  from classiq.interface.model.bind_operation import BindOperation
7
+ from classiq.interface.model.block import Block
7
8
  from classiq.interface.model.classical_if import ClassicalIf
8
9
  from classiq.interface.model.control import Control
9
10
  from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
@@ -41,12 +42,14 @@ ConcreteQuantumStatement = Annotated[
41
42
  Control,
42
43
  WithinApply,
43
44
  PhaseOperation,
45
+ Block,
44
46
  ],
45
47
  Field(..., discriminator="kind"),
46
48
  ]
47
49
 
48
50
  StatementBlock = list[ConcreteQuantumStatement]
49
51
 
52
+ Block.model_rebuild()
50
53
  Control.model_rebuild()
51
54
  QuantumLambdaFunction.model_rebuild()
52
55
  Repeat.model_rebuild()
@@ -1,5 +1,6 @@
1
1
  from typing import Literal
2
2
 
3
+ from classiq.interface.generator.expressions.expression import Expression
3
4
  from classiq.interface.model.quantum_statement import QuantumStatement
4
5
  from classiq.interface.model.quantum_variable_declaration import (
5
6
  QuantumVariableDeclaration,
@@ -8,3 +9,7 @@ from classiq.interface.model.quantum_variable_declaration import (
8
9
 
9
10
  class VariableDeclarationStatement(QuantumStatement, QuantumVariableDeclaration):
10
11
  kind: Literal["VariableDeclarationStatement"]
12
+
13
+ @property
14
+ def expressions(self) -> list[Expression]:
15
+ return self.quantum_type.expressions
@@ -12,9 +12,15 @@ from classiq.interface.generator.expressions.expression_types import (
12
12
  ExpressionValue,
13
13
  QmodStructInstance,
14
14
  )
15
- from classiq.interface.generator.expressions.qmod_qscalar_proxy import QmodQNumProxy
16
- from classiq.interface.generator.expressions.qmod_qstruct_proxy import QmodQStructProxy
17
- from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
15
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
16
+ QmodQNumProxy,
17
+ )
18
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
19
+ QmodQStructProxy,
20
+ )
21
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
22
+ QmodSizedProxy,
23
+ )
18
24
  from classiq.interface.generator.expressions.type_proxy import TypeProxy
19
25
  from classiq.interface.generator.functions.classical_function_declaration import (
20
26
  ClassicalFunctionDeclaration,