classiq 0.88.0__py3-none-any.whl → 0.90.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of classiq might be problematic. Click here for more details.

Files changed (103) hide show
  1. classiq/__init__.py +1 -0
  2. classiq/_internals/api_wrapper.py +16 -32
  3. classiq/_internals/config.py +1 -1
  4. classiq/analyzer/show_interactive_hack.py +26 -1
  5. classiq/applications/chemistry/chemistry_model_constructor.py +14 -2
  6. classiq/applications/combinatorial_helpers/pyomo_utils.py +9 -6
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -2
  8. classiq/applications/combinatorial_optimization/combinatorial_problem.py +16 -8
  9. classiq/evaluators/classical_expression.py +63 -41
  10. classiq/evaluators/control.py +31 -52
  11. classiq/evaluators/expression_evaluator.py +8 -4
  12. classiq/evaluators/parameter_types.py +200 -104
  13. classiq/evaluators/qmod_annotated_expression.py +10 -9
  14. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +2 -2
  15. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +1 -1
  16. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +66 -5
  17. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +12 -37
  18. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +8 -17
  19. classiq/evaluators/qmod_node_evaluators/measurement_evaluation.py +1 -1
  20. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +7 -1
  21. classiq/evaluators/qmod_node_evaluators/name_evaluation.py +0 -1
  22. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +9 -1
  23. classiq/evaluators/qmod_node_evaluators/utils.py +33 -0
  24. classiq/evaluators/qmod_type_inference/classical_type_inference.py +4 -7
  25. classiq/interface/_version.py +1 -1
  26. classiq/interface/analyzer/analysis_params.py +2 -26
  27. classiq/interface/analyzer/result.py +4 -0
  28. classiq/interface/backend/backend_preferences.py +1 -1
  29. classiq/interface/chemistry/ground_state_problem.py +16 -2
  30. classiq/interface/executor/optimizer_preferences.py +0 -112
  31. classiq/interface/generator/application_apis/chemistry_declarations.py +3 -1
  32. classiq/interface/generator/arith/arithmetic_expression_validator.py +2 -7
  33. classiq/interface/generator/arith/register_user_input.py +1 -1
  34. classiq/interface/generator/expressions/evaluated_expression.py +3 -13
  35. classiq/interface/generator/expressions/expression_types.py +8 -22
  36. classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +2 -2
  37. classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +1 -2
  38. classiq/interface/generator/functions/classical_type.py +24 -3
  39. classiq/interface/generator/functions/concrete_types.py +1 -1
  40. classiq/interface/generator/functions/function_declaration.py +0 -4
  41. classiq/interface/generator/functions/type_name.py +25 -0
  42. classiq/interface/generator/generated_circuit_data.py +4 -0
  43. classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
  44. classiq/interface/generator/preferences/qasm_to_qmod_params.py +14 -0
  45. classiq/interface/generator/quantum_function_call.py +3 -3
  46. classiq/interface/generator/user_defined_function_params.py +0 -3
  47. classiq/interface/helpers/model_normalizer.py +0 -6
  48. classiq/interface/ide/ide_data.py +1 -1
  49. classiq/interface/ide/visual_model.py +3 -2
  50. classiq/interface/model/block.py +5 -1
  51. classiq/interface/model/handle_binding.py +2 -2
  52. classiq/interface/model/port_declaration.py +2 -1
  53. classiq/interface/model/quantum_expressions/arithmetic_operation.py +16 -12
  54. classiq/interface/model/quantum_lambda_function.py +1 -1
  55. classiq/interface/model/quantum_statement.py +2 -4
  56. classiq/interface/model/quantum_type.py +47 -4
  57. classiq/interface/server/routes.py +2 -3
  58. classiq/model_expansions/atomic_expression_functions_defs.py +4 -22
  59. classiq/model_expansions/capturing/captured_vars.py +7 -3
  60. classiq/model_expansions/closure.py +8 -0
  61. classiq/model_expansions/interpreters/base_interpreter.py +84 -22
  62. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +1 -1
  63. classiq/model_expansions/interpreters/generative_interpreter.py +7 -5
  64. classiq/model_expansions/quantum_operations/allocate.py +92 -21
  65. classiq/model_expansions/quantum_operations/assignment_result_processor.py +28 -27
  66. classiq/model_expansions/quantum_operations/call_emitter.py +32 -26
  67. classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -2
  68. classiq/model_expansions/quantum_operations/emitter.py +39 -69
  69. classiq/model_expansions/quantum_operations/expression_evaluator.py +13 -2
  70. classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -5
  71. classiq/model_expansions/quantum_operations/variable_decleration.py +16 -11
  72. classiq/model_expansions/scope.py +36 -29
  73. classiq/model_expansions/scope_initialization.py +3 -6
  74. classiq/model_expansions/sympy_conversion/sympy_to_python.py +6 -2
  75. classiq/model_expansions/transformers/model_renamer.py +35 -64
  76. classiq/model_expansions/transformers/type_modifier_inference.py +6 -6
  77. classiq/model_expansions/visitors/boolean_expression_transformers.py +7 -31
  78. classiq/model_expansions/visitors/symbolic_param_inference.py +9 -3
  79. classiq/open_library/functions/__init__.py +2 -0
  80. classiq/open_library/functions/state_preparation.py +140 -5
  81. classiq/qmod/builtins/functions/allocation.py +8 -8
  82. classiq/qmod/builtins/functions/arithmetic.py +1 -1
  83. classiq/qmod/builtins/functions/chemistry.py +64 -0
  84. classiq/qmod/builtins/functions/exponentiation.py +7 -13
  85. classiq/qmod/builtins/functions/qsvm.py +1 -1
  86. classiq/qmod/builtins/operations.py +38 -10
  87. classiq/qmod/generative.py +2 -4
  88. classiq/qmod/native/pretty_printer.py +1 -1
  89. classiq/qmod/pretty_print/pretty_printer.py +1 -1
  90. classiq/qmod/qmod_constant.py +1 -1
  91. classiq/qmod/qmod_parameter.py +2 -2
  92. classiq/qmod/qmod_variable.py +62 -16
  93. classiq/qmod/quantum_expandable.py +1 -1
  94. classiq/synthesis.py +37 -1
  95. classiq/visualization.py +1 -1
  96. {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/METADATA +2 -2
  97. {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/RECORD +98 -102
  98. classiq/evaluators/arg_type_match.py +0 -168
  99. classiq/evaluators/classical_type_inference.py +0 -121
  100. classiq/interface/combinatorial_optimization/optimization_problem.py +0 -17
  101. classiq/interface/combinatorial_optimization/result.py +0 -9
  102. classiq/model_expansions/transformers/ast_renamer.py +0 -26
  103. {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/WHEEL +0 -0
@@ -2,7 +2,7 @@ from itertools import chain
2
2
  from typing import TYPE_CHECKING, Any, Literal, Optional
3
3
 
4
4
  import pydantic
5
- from pydantic import ConfigDict, PrivateAttr
5
+ from pydantic import PrivateAttr
6
6
  from typing_extensions import Self
7
7
 
8
8
  from classiq.interface.ast_node import HashableASTNode
@@ -34,8 +34,6 @@ if TYPE_CHECKING:
34
34
  class ClassicalType(HashableASTNode):
35
35
  _is_generative: bool = PrivateAttr(default=False)
36
36
 
37
- model_config = ConfigDict(extra="forbid")
38
-
39
37
  def __str__(self) -> str:
40
38
  return str(type(self).__name__)
41
39
 
@@ -78,6 +76,9 @@ class ClassicalType(HashableASTNode):
78
76
  def get_raw_type(self) -> "ConcreteClassicalType":
79
77
  return self # type:ignore[return-value]
80
78
 
79
+ def without_symbolic_attributes(self) -> Self:
80
+ return self
81
+
81
82
 
82
83
  class Integer(ClassicalType):
83
84
  kind: Literal["int"]
@@ -203,6 +204,18 @@ class ClassicalArray(ClassicalType):
203
204
  def raw_qmod_type_name(self) -> str:
204
205
  return "CArray"
205
206
 
207
+ def without_symbolic_attributes(self) -> "ClassicalArray":
208
+ length = (
209
+ None
210
+ if self.length is None
211
+ or not self.length.is_evaluated()
212
+ or not self.length.is_constant()
213
+ else self.length
214
+ )
215
+ return ClassicalArray(
216
+ element_type=self.element_type.without_symbolic_attributes(), length=length
217
+ )
218
+
206
219
 
207
220
  class ClassicalTuple(ClassicalType):
208
221
  kind: Literal["tuple"]
@@ -273,6 +286,14 @@ class ClassicalTuple(ClassicalType):
273
286
  def raw_qmod_type_name(self) -> str:
274
287
  return "CArray"
275
288
 
289
+ def without_symbolic_attributes(self) -> "ClassicalTuple":
290
+ return ClassicalTuple(
291
+ element_types=[
292
+ element_type.without_symbolic_attributes()
293
+ for element_type in self.element_types
294
+ ]
295
+ )
296
+
276
297
 
277
298
  class OpaqueHandle(ClassicalType):
278
299
  pass
@@ -47,7 +47,7 @@ PythonClassicalPydanticTypes = (Enum,)
47
47
 
48
48
  ConcreteQuantumType = Annotated[
49
49
  Union[QuantumBit, QuantumBitvector, QuantumNumeric, TypeName],
50
- Field(discriminator="kind", default_factory=QuantumBitvector),
50
+ Field(discriminator="kind"),
51
51
  ]
52
52
  QuantumBitvector.model_rebuild()
53
53
  TypeName.model_rebuild()
@@ -1,8 +1,6 @@
1
1
  import abc
2
2
  from collections.abc import Sequence
3
3
 
4
- from pydantic import ConfigDict
5
-
6
4
  from classiq.interface.model.classical_parameter_declaration import (
7
5
  AnonClassicalParameterDeclaration,
8
6
  )
@@ -19,7 +17,5 @@ class FunctionDeclaration(Parameter, abc.ABC):
19
17
  def param_decls(self) -> Sequence["AnonClassicalParameterDeclaration"]:
20
18
  pass
21
19
 
22
- model_config = ConfigDict(extra="forbid")
23
-
24
20
 
25
21
  FunctionDeclaration.model_rebuild()
@@ -189,6 +189,31 @@ class TypeName(ClassicalType, QuantumType):
189
189
  field_type.minimal_size_in_bits for field_type in self.fields.values()
190
190
  )
191
191
 
192
+ def without_symbolic_attributes(self) -> "TypeName":
193
+ if self.has_fields:
194
+ type_name = TypeName(name=self.name)
195
+ type_name.set_fields(
196
+ {
197
+ field_name: field_type.without_symbolic_attributes()
198
+ for field_name, field_type in self.fields.items()
199
+ }
200
+ )
201
+ return type_name
202
+ if self.has_classical_struct_decl:
203
+ type_name = TypeName(name=self.name)
204
+ type_name.set_classical_struct_decl(
205
+ self.classical_struct_decl.model_copy(
206
+ update=dict(
207
+ variables={
208
+ field_name: field_type.without_symbolic_attributes()
209
+ for field_name, field_type in self.classical_struct_decl.variables.items()
210
+ }
211
+ )
212
+ )
213
+ )
214
+ return type_name
215
+ return self
216
+
192
217
 
193
218
  class Enum(TypeName):
194
219
  pass
@@ -17,6 +17,7 @@ from classiq.interface.generator.register_role import RegisterRole
17
17
  from classiq.interface.generator.synthesis_metadata.synthesis_execution_data import (
18
18
  ExecutionData,
19
19
  )
20
+ from classiq.interface.model.block import Block
20
21
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
21
22
  ArithmeticOperationKind,
22
23
  )
@@ -210,10 +211,13 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
210
211
  )
211
212
  name_with_suffix = self.add_suffix_from_generated_name(generated_name, name)
212
213
  return name_with_suffix
214
+ if isinstance(back_ref, Block) and back_ref.label is not None:
215
+ return back_ref.label
213
216
 
214
217
  statement_kind: str = back_ref.kind
215
218
  if isinstance(back_ref, ArithmeticOperation):
216
219
  statement_kind = back_ref.operation_kind.value
220
+
217
221
  return self.add_suffix_from_generated_name(
218
222
  generated_name, STATEMENTS_NAME[statement_kind]
219
223
  )
@@ -42,7 +42,7 @@ class HardwareEfficientAnsatz(function_params.FunctionParams):
42
42
  "If none specified - use connectivity map from the model hardware settings. "
43
43
  "If none specified as well, all qubit pairs will be connected.",
44
44
  )
45
- num_qubits: pydantic.PositiveInt = pydantic.Field(
45
+ num_qubits: pydantic.PositiveInt = pydantic.Field( # type: ignore[assignment]
46
46
  default=None,
47
47
  description="Number of qubits in the ansatz.",
48
48
  validate_default=True,
@@ -0,0 +1,14 @@
1
+ from pydantic import BaseModel
2
+
3
+ from classiq.interface.analyzer.result import QasmCode
4
+ from classiq.interface.enum_utils import StrEnum
5
+
6
+
7
+ class QmodFormat(StrEnum):
8
+ NATIVE = "native"
9
+ PYTHON = "python"
10
+
11
+
12
+ class QasmToQmodParams(BaseModel):
13
+ qasm: QasmCode
14
+ qmod_format: QmodFormat
@@ -130,7 +130,7 @@ class SynthesisQuantumFunctionCall(BaseModel):
130
130
  default=True,
131
131
  description="False value indicates this call shouldn't be controlled even if the flow is controlled.",
132
132
  )
133
- inputs: IOType = pydantic.Field(
133
+ inputs: IOType = pydantic.Field( # type: ignore[assignment]
134
134
  default_factory=dict,
135
135
  description="A mapping from the input name to the wire it connects to",
136
136
  )
@@ -138,14 +138,14 @@ class SynthesisQuantumFunctionCall(BaseModel):
138
138
  default_factory=dict,
139
139
  description="A mapping from in/out name to the wires that connect to it",
140
140
  )
141
- outputs: IOType = pydantic.Field(
141
+ outputs: IOType = pydantic.Field( # type: ignore[assignment]
142
142
  default_factory=dict,
143
143
  description="A mapping from the output name to the wire it connects to",
144
144
  )
145
145
  power: PydanticPowerType = pydantic.Field(
146
146
  default=1, description="Number of successive calls to the operation"
147
147
  )
148
- name: PydanticNonEmptyString = pydantic.Field(
148
+ name: PydanticNonEmptyString = pydantic.Field( # type: ignore[assignment]
149
149
  default=None,
150
150
  validate_default=True,
151
151
  description="The name of the function instance. "
@@ -1,7 +1,6 @@
1
1
  from collections.abc import Mapping
2
2
 
3
3
  import pydantic
4
- from pydantic import ConfigDict
5
4
 
6
5
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
7
6
  from classiq.interface.generator.function_params import ArithmeticIODict, FunctionParams
@@ -12,8 +11,6 @@ class CustomFunction(FunctionParams):
12
11
  A user-defined custom function parameters object.
13
12
  """
14
13
 
15
- model_config = ConfigDict(frozen=True, extra="forbid")
16
-
17
14
  _name: str = pydantic.PrivateAttr(default="")
18
15
 
19
16
  input_decls: ArithmeticIODict = pydantic.Field(
@@ -1,4 +1,3 @@
1
- import ast
2
1
  from typing import Any
3
2
 
4
3
  from classiq.interface.ast_node import ASTNode
@@ -10,8 +9,6 @@ from classiq.interface.generator.visitor import Transformer, Visitor
10
9
  from classiq.interface.model.model import Model
11
10
  from classiq.interface.model.port_declaration import AnonPortDeclaration
12
11
 
13
- from classiq.model_expansions.transformers.model_renamer import ExprNormalizer
14
-
15
12
 
16
13
  class ModelNormalizer(Visitor):
17
14
  def visit(self, node: Any) -> None:
@@ -28,9 +25,6 @@ class ModelNormalizer(Visitor):
28
25
  model.functions.sort(key=lambda x: x.name)
29
26
  self.generic_visit(model)
30
27
 
31
- def visit_Expression(self, expr: Expression) -> None:
32
- expr.expr = ast.unparse(ExprNormalizer().visit(ast.parse(expr.expr)))
33
-
34
28
  def visit_AnonPortDeclaration(self, decl: AnonPortDeclaration) -> None:
35
29
  decl.type_modifier = TypeModifier.Mutable
36
30
 
@@ -59,7 +59,7 @@ class IDEDataOperation(pydantic.BaseModel):
59
59
  _qubits: list = pydantic.PrivateAttr() # list[Qubit]
60
60
 
61
61
  displayArgs: str = ""
62
- targets: Union[list[IDEQubitDef], list[IDEClassicalBitDef]] = pydantic.Field(
62
+ targets: Union[list[IDEQubitDef], list[IDEClassicalBitDef]] = pydantic.Field( # type: ignore[assignment]
63
63
  default_factory=list
64
64
  )
65
65
  controls: list[IDEQubitDef] = list()
@@ -171,6 +171,7 @@ class Operation(pydantic.BaseModel):
171
171
  expanded: bool = pydantic.Field(default=False)
172
172
  show_expanded_label: bool = pydantic.Field(default=False)
173
173
  is_low_level_fallback: bool = pydantic.Field(default=False)
174
+ is_measurement: bool = pydantic.Field(default=False)
174
175
 
175
176
  model_config = ConfigDict(frozen=True)
176
177
 
@@ -207,9 +208,9 @@ class Operation(pydantic.BaseModel):
207
208
 
208
209
 
209
210
  class ProgramVisualModel(VersionedModel):
210
- main_operation: Operation = pydantic.Field(default=None)
211
+ main_operation: Operation = pydantic.Field(default=None) # type: ignore[assignment]
211
212
  id_to_operations: dict[int, Operation] = pydantic.Field(default_factory=dict)
212
- main_operation_id: int = pydantic.Field(default=None)
213
+ main_operation_id: int = pydantic.Field(default=None) # type: ignore[assignment]
213
214
  program_data: ProgramData
214
215
 
215
216
  @property
@@ -1,4 +1,6 @@
1
- from typing import TYPE_CHECKING, Literal
1
+ from typing import TYPE_CHECKING, Literal, Optional
2
+
3
+ import pydantic
2
4
 
3
5
  from classiq.interface.model.quantum_statement import QuantumOperation
4
6
 
@@ -10,3 +12,5 @@ class Block(QuantumOperation):
10
12
  kind: Literal["Block"]
11
13
 
12
14
  statements: "StatementBlock"
15
+
16
+ label: Optional[str] = pydantic.Field(default=None)
@@ -19,7 +19,7 @@ def _get_expr_id(expr: Expression) -> str:
19
19
 
20
20
 
21
21
  class HandleBinding(ASTNode):
22
- name: str = Field(default=None)
22
+ name: str = Field(default=None) # type: ignore[assignment]
23
23
  model_config = ConfigDict(frozen=True, extra="forbid")
24
24
 
25
25
  def __str__(self) -> str:
@@ -349,7 +349,7 @@ class FieldHandleBinding(NestedHandleBinding):
349
349
 
350
350
  @property
351
351
  def qmod_expr(self) -> str:
352
- return f"get_field({self.base_handle.qmod_expr}, '{self.field}')"
352
+ return f"{self.base_handle.qmod_expr}.{self.field}"
353
353
 
354
354
  @property
355
355
  def identifier(self) -> str:
@@ -13,10 +13,11 @@ from classiq.interface.generator.functions.type_modifier import (
13
13
  )
14
14
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
15
15
  from classiq.interface.model.parameter import Parameter
16
+ from classiq.interface.model.quantum_type import QuantumBitvector
16
17
 
17
18
 
18
19
  class AnonPortDeclaration(Parameter):
19
- quantum_type: ConcreteQuantumType
20
+ quantum_type: ConcreteQuantumType = pydantic.Field(default_factory=QuantumBitvector)
20
21
  direction: PortDeclarationDirection
21
22
  kind: Literal["PortDeclaration"]
22
23
  type_modifier: TypeModifier
@@ -1,12 +1,9 @@
1
1
  from collections.abc import Mapping, Sequence
2
- from typing import Literal
3
-
4
- from pydantic import PrivateAttr
2
+ from typing import Literal, cast
5
3
 
6
4
  from classiq.interface.enum_utils import StrEnum
7
5
  from classiq.interface.generator.arith.arithmetic import (
8
6
  ARITHMETIC_EXPRESSION_RESULT_NAME,
9
- compute_arithmetic_result_type,
10
7
  )
11
8
  from classiq.interface.model.handle_binding import (
12
9
  ConcreteHandleBinding,
@@ -18,6 +15,9 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
18
15
  from classiq.interface.model.quantum_statement import HandleMetadata
19
16
  from classiq.interface.model.quantum_type import QuantumType
20
17
 
18
+ from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
19
+ from classiq.model_expansions.arithmetic import NumericAttributes
20
+
21
21
 
22
22
  class ArithmeticOperationKind(StrEnum):
23
23
  InplaceAdd = "inplace_add"
@@ -29,7 +29,7 @@ class ArithmeticOperation(QuantumAssignmentOperation):
29
29
  kind: Literal["ArithmeticOperation"]
30
30
 
31
31
  operation_kind: ArithmeticOperationKind
32
- _classical_assignment: bool = PrivateAttr(default=False)
32
+ classical_assignment: bool = False
33
33
 
34
34
  @property
35
35
  def is_inplace(self) -> bool:
@@ -44,16 +44,20 @@ class ArithmeticOperation(QuantumAssignmentOperation):
44
44
  machine_precision: int,
45
45
  ) -> None:
46
46
  super().initialize_var_types(var_types, machine_precision)
47
- self._result_type = compute_arithmetic_result_type(
48
- self.expression.expr, var_types, machine_precision
49
- )
47
+ expr_val = self.expression.value.value
48
+ if isinstance(expr_val, QmodAnnotatedExpression):
49
+ self._result_type = expr_val.get_quantum_type(expr_val.root)
50
+ else:
51
+ self._result_type = NumericAttributes.from_constant(
52
+ cast(float, expr_val), machine_precision
53
+ ).to_quantum_numeric()
50
54
 
51
55
  @property
52
56
  def wiring_inouts(
53
57
  self,
54
58
  ) -> Mapping[str, ConcreteHandleBinding]:
55
59
  inouts = dict(super().wiring_inouts)
56
- if self.is_inplace and not self._classical_assignment:
60
+ if self.is_inplace and not self.classical_assignment:
57
61
  inouts[self.result_name()] = self.result_var
58
62
  return inouts
59
63
 
@@ -63,7 +67,7 @@ class ArithmeticOperation(QuantumAssignmentOperation):
63
67
  HandleMetadata(handle=handle, readable_location="in an expression")
64
68
  for handle in self.var_handles
65
69
  ]
66
- if self.is_inplace and not self._classical_assignment:
70
+ if self.is_inplace and not self.classical_assignment:
67
71
  inouts.append(
68
72
  HandleMetadata(
69
73
  handle=self.result_var,
@@ -74,13 +78,13 @@ class ArithmeticOperation(QuantumAssignmentOperation):
74
78
 
75
79
  @property
76
80
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
77
- if self.is_inplace or self._classical_assignment:
81
+ if self.is_inplace or self.classical_assignment:
78
82
  return {}
79
83
  return super().wiring_outputs
80
84
 
81
85
  @property
82
86
  def readable_outputs(self) -> Sequence[HandleMetadata]:
83
- if self.is_inplace or self._classical_assignment:
87
+ if self.is_inplace or self.classical_assignment:
84
88
  return []
85
89
  return [
86
90
  HandleMetadata(
@@ -32,7 +32,7 @@ class QuantumLambdaFunction(ASTNode):
32
32
  default=None
33
33
  )
34
34
 
35
- _py_callable: Callable = pydantic.PrivateAttr(default=None)
35
+ _py_callable: Callable = pydantic.PrivateAttr(default=None) # type: ignore[assignment]
36
36
 
37
37
  @property
38
38
  def py_callable(self) -> Callable:
@@ -4,7 +4,6 @@ from typing import Any, Callable, Optional
4
4
  from uuid import UUID, uuid4
5
5
 
6
6
  import pydantic
7
- from pydantic import ConfigDict
8
7
  from typing_extensions import Self
9
8
 
10
9
  from classiq.interface.ast_node import ASTNode
@@ -21,7 +20,6 @@ from classiq.interface.model.handle_binding import (
21
20
 
22
21
  class QuantumStatement(ASTNode):
23
22
  kind: str
24
- model_config = ConfigDict(extra="forbid")
25
23
  uuid: UUID = pydantic.Field(
26
24
  description="A unique identifier for this operation", default_factory=uuid4
27
25
  )
@@ -29,12 +27,12 @@ class QuantumStatement(ASTNode):
29
27
  def model_copy(
30
28
  self,
31
29
  *,
32
- update: Optional[dict[str, Any]] = None,
30
+ update: Optional[Mapping[str, Any]] = None,
33
31
  deep: bool = False,
34
32
  keep_uuid: bool = False,
35
33
  ) -> Self:
36
34
  if not keep_uuid:
37
- update = update or dict()
35
+ update = dict(update) if update is not None else dict()
38
36
  update.setdefault("uuid", uuid4())
39
37
  return super().model_copy(update=update, deep=deep)
40
38
 
@@ -1,7 +1,7 @@
1
1
  from typing import TYPE_CHECKING, Any, Literal, Optional
2
2
 
3
3
  import pydantic
4
- from pydantic import BaseModel, ConfigDict, Field
4
+ from pydantic import BaseModel, Field
5
5
  from typing_extensions import Self
6
6
 
7
7
  from classiq.interface.ast_node import HashableASTNode
@@ -35,8 +35,6 @@ if TYPE_CHECKING:
35
35
 
36
36
 
37
37
  class QuantumType(HashableASTNode):
38
- model_config = ConfigDict(extra="forbid")
39
-
40
38
  _size_in_bits: Optional[int] = pydantic.PrivateAttr(default=None)
41
39
 
42
40
  def _update_size_in_bits_from_declaration(self) -> None:
@@ -92,6 +90,9 @@ class QuantumType(HashableASTNode):
92
90
  def expressions(self) -> list[Expression]:
93
91
  return []
94
92
 
93
+ def without_symbolic_attributes(self) -> Self:
94
+ return self
95
+
95
96
 
96
97
  class QuantumScalar(QuantumType):
97
98
  def get_proxy(self, handle: "HandleBinding") -> QmodQScalarProxy:
@@ -292,6 +293,18 @@ class QuantumBitvector(QuantumType):
292
293
  length = 1
293
294
  return length * self.element_type.minimal_size_in_bits
294
295
 
296
+ def without_symbolic_attributes(self) -> "QuantumBitvector":
297
+ length = (
298
+ None
299
+ if self.length is None
300
+ or not self.length.is_evaluated()
301
+ or not self.length.is_constant()
302
+ else self.length
303
+ )
304
+ return QuantumBitvector(
305
+ element_type=self.element_type.without_symbolic_attributes(), length=length
306
+ )
307
+
295
308
 
296
309
  class QuantumNumeric(QuantumScalar):
297
310
  kind: Literal["qnum"]
@@ -487,9 +500,39 @@ class QuantumNumeric(QuantumScalar):
487
500
  def minimal_size_in_bits(self) -> int:
488
501
  return self.size_in_bits if self.has_size_in_bits else 1
489
502
 
503
+ def without_symbolic_attributes(self) -> "QuantumNumeric":
504
+ size = (
505
+ None
506
+ if self.size is None
507
+ or not self.size.is_evaluated()
508
+ or not self.size.is_constant()
509
+ else self.size
510
+ )
511
+ is_signed = (
512
+ None
513
+ if self.is_signed is None
514
+ or not self.is_signed.is_evaluated()
515
+ or not self.is_signed.is_constant()
516
+ else self.is_signed
517
+ )
518
+ fraction_digits = (
519
+ None
520
+ if self.fraction_digits is None
521
+ or not self.fraction_digits.is_evaluated()
522
+ or not self.fraction_digits.is_constant()
523
+ else self.fraction_digits
524
+ )
525
+ if size is None or is_signed is None or fraction_digits is None:
526
+ is_signed = fraction_digits = None
527
+ qnum = QuantumNumeric(
528
+ size=size, is_signed=is_signed, fraction_digits=fraction_digits
529
+ )
530
+ qnum.set_bounds(self.get_bounds())
531
+ return qnum
532
+
490
533
 
491
534
  class RegisterQuantumType(BaseModel):
492
- quantum_types: "ConcreteQuantumType"
535
+ quantum_types: "ConcreteQuantumType" = Field(default_factory=QuantumBitvector)
493
536
  size: int = Field(default=1)
494
537
 
495
538
  @property
@@ -44,9 +44,6 @@ TASKS_VISUALIZE_SUFFIX = TASKS_SUFFIX + "/visualize"
44
44
  TASKS_VISUAL_MODEL_SUFFIX = TASKS_SUFFIX + "/visual_model"
45
45
  TASKS_SOLVE_SUFFIX = "/tasks/solve"
46
46
 
47
- CHEMISTRY_QMOD_PATH = "/generate_model/chemistry/qmod"
48
-
49
-
50
47
  TASK_TRAIN_SUFFIX = TASKS_SUFFIX + "/train"
51
48
  TASK_TEST_SUFFIX = TASKS_SUFFIX + "/test"
52
49
  TASK_PREDICT_SUFFIX = TASKS_SUFFIX + "/predict"
@@ -75,6 +72,8 @@ CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_SUFFIX = "/execution_input"
75
72
  CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_FULL = (
76
73
  CONVERSION_PREFIX + CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_SUFFIX
77
74
  )
75
+ QASM_TO_QMOD_SUFFIX = "/qasm_to_qmod"
76
+ QASM_TO_QMOD_FULL_PATH = CONVERSION_PREFIX + QASM_TO_QMOD_SUFFIX
78
77
 
79
78
  STATIC_SEMANTICS_VALIDATION_PATH = "/validate_static_semantics"
80
79
 
@@ -15,6 +15,7 @@ from classiq.interface.generator.expressions.atomic_expression_functions import
15
15
  from classiq.interface.generator.expressions.expression_types import (
16
16
  ExpressionValue,
17
17
  QmodStructInstance,
18
+ RuntimeConstant,
18
19
  )
19
20
  from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
20
21
  AnyClassicalValue,
@@ -44,14 +45,12 @@ from classiq.interface.generator.functions.classical_type import (
44
45
  ClassicalArray,
45
46
  ClassicalTuple,
46
47
  ClassicalType,
47
- OpaqueHandle,
48
- QmodPyObject,
49
48
  Real,
50
- StructMetaType,
51
49
  )
52
50
  from classiq.interface.generator.functions.type_name import TypeName
53
51
  from classiq.interface.helpers.backward_compatibility import zip_strict
54
52
 
53
+ from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
55
54
  from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
56
55
  BitwiseAnd,
57
56
  BitwiseNot,
@@ -61,10 +60,6 @@ from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
61
60
  LShift,
62
61
  RShift,
63
62
  )
64
- from classiq.model_expansions.model_tables import (
65
- HandleIdentifier,
66
- HandleTable,
67
- )
68
63
  from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
69
64
  MISSING_SLICE_VALUE_PLACEHOLDER,
70
65
  )
@@ -106,10 +101,6 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
106
101
  )
107
102
  ]
108
103
 
109
- elif isinstance(qmod_type, OpaqueHandle):
110
- if isinstance(val, HandleIdentifier):
111
- return HandleTable.get_handle_object(val)
112
-
113
104
  elif isinstance(val, Expr):
114
105
  return sympy_to_python(val)
115
106
 
@@ -121,10 +112,6 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
121
112
  if isinstance(val, bool):
122
113
  return val
123
114
 
124
- elif isinstance(qmod_type, StructMetaType):
125
- if isinstance(val, TypeProxy):
126
- return val.struct_declaration
127
-
128
115
  elif isinstance(val, int): # other scalars are represented as int
129
116
  return val
130
117
 
@@ -162,11 +149,6 @@ def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
162
149
  for elem, elem_type in zip_strict(val, qmod_type.element_types, strict=True)
163
150
  ]
164
151
 
165
- if isinstance(qmod_type, OpaqueHandle):
166
- if not isinstance(val, QmodPyObject):
167
- raise ClassiqInternalExpansionError("Bad value opaque handle")
168
- return HandleTable.set_handle_object(val)
169
-
170
152
  return val
171
153
 
172
154
 
@@ -194,7 +176,7 @@ def get_field(
194
176
  QmodSizedProxy, QmodStructInstance, list, ClassicalProxy, AnyClassicalValue
195
177
  ],
196
178
  field: str,
197
- ) -> ExpressionValue:
179
+ ) -> Any:
198
180
  if isinstance(proxy, AnyClassicalValue) or (
199
181
  isinstance(proxy, Symbol)
200
182
  and not isinstance(proxy, QmodSizedProxy)
@@ -244,7 +226,7 @@ def do_div(lhs: Any, rhs: Any) -> Any:
244
226
  return res
245
227
 
246
228
 
247
- _EXPRESSION_TYPES = get_args(ExpressionValue)
229
+ _EXPRESSION_TYPES = (*get_args(RuntimeConstant), QmodAnnotatedExpression)
248
230
 
249
231
 
250
232
  def _is_qmod_value(val: Any) -> bool:
@@ -1,3 +1,4 @@
1
+ import ast
1
2
  import dataclasses
2
3
  from collections.abc import Sequence
3
4
  from dataclasses import dataclass, field
@@ -41,6 +42,7 @@ from classiq.interface.model.variable_declaration_statement import (
41
42
  VariableDeclarationStatement,
42
43
  )
43
44
 
45
+ from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
44
46
  from classiq.model_expansions.capturing.mangling_utils import (
45
47
  demangle_handle,
46
48
  mangle_captured_var_name,
@@ -60,9 +62,11 @@ UNINITIALIZED_VAR_MESSAGE = "Variable '{}' should be initialized here"
60
62
 
61
63
  def _get_symbol_expr(symbol: str, classical_type: ClassicalType) -> Expression:
62
64
  expr = Expression(expr=symbol)
63
- expr._evaluated_expr = EvaluatedExpression(
64
- value=classical_type.get_classical_proxy(handle=HandleBinding(name=symbol))
65
- )
65
+ expr_val = QmodAnnotatedExpression(ast.Name(id=symbol))
66
+ expr_val.set_type(expr_val.root, classical_type)
67
+ expr_val.set_var(expr_val.root, HandleBinding(name=symbol))
68
+ expr_val.lock()
69
+ expr._evaluated_expr = EvaluatedExpression(value=expr_val)
66
70
  return expr
67
71
 
68
72