classiq 0.102.0__py3-none-any.whl → 1.0.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 +2 -0
  2. classiq/_internals/authentication/auth0.py +29 -0
  3. classiq/_internals/authentication/auth_flow_factory.py +43 -0
  4. classiq/_internals/authentication/machine_credentials_flow.py +26 -0
  5. classiq/_internals/authentication/password_manager.py +84 -0
  6. classiq/_internals/authentication/token_manager.py +24 -8
  7. classiq/analyzer/show_interactive_hack.py +0 -8
  8. classiq/applications/chemistry/op_utils.py +32 -0
  9. classiq/applications/combinatorial_optimization/combinatorial_problem.py +1 -1
  10. classiq/evaluators/qmod_annotated_expression.py +1 -1
  11. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
  12. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
  13. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
  14. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
  15. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
  16. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
  17. classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
  18. classiq/execution/all_hardware_devices.py +59 -1
  19. classiq/execution/execution_session.py +1 -1
  20. classiq/execution/functions/__init__.py +13 -0
  21. classiq/execution/functions/expectation_value.py +106 -0
  22. classiq/execution/functions/minimize.py +90 -0
  23. classiq/execution/functions/sample.py +76 -0
  24. classiq/execution/functions/state_vector.py +113 -0
  25. classiq/execution/functions/util/__init__.py +0 -0
  26. classiq/execution/functions/util/_logging.py +19 -0
  27. classiq/execution/functions/util/backend_preferences.py +188 -0
  28. classiq/execution/functions/util/constants.py +9 -0
  29. classiq/execution/functions/util/parse_provider_backend.py +90 -0
  30. classiq/interface/_version.py +1 -1
  31. classiq/interface/backend/backend_preferences.py +81 -0
  32. classiq/interface/backend/provider_config/providers/aqt.py +1 -1
  33. classiq/interface/backend/provider_config/providers/azure.py +1 -2
  34. classiq/interface/backend/provider_config/providers/ibm.py +1 -1
  35. classiq/interface/backend/quantum_backend_providers.py +14 -0
  36. classiq/interface/exceptions.py +0 -4
  37. classiq/interface/executor/result.py +9 -5
  38. classiq/interface/generator/arith/binary_ops.py +62 -2
  39. classiq/interface/generator/arith/number_utils.py +15 -6
  40. classiq/interface/generator/compiler_keywords.py +1 -0
  41. classiq/interface/generator/function_param_list.py +8 -2
  42. classiq/interface/generator/function_params.py +1 -1
  43. classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
  44. classiq/interface/generator/functions/classical_type.py +60 -0
  45. classiq/interface/generator/functions/type_name.py +36 -0
  46. classiq/interface/generator/generated_circuit_data.py +0 -2
  47. classiq/interface/generator/transpiler_basis_gates.py +1 -0
  48. classiq/interface/generator/types/compilation_metadata.py +18 -0
  49. classiq/interface/hardware.py +2 -0
  50. classiq/interface/helpers/model_normalizer.py +42 -6
  51. classiq/interface/interface_version.py +1 -1
  52. classiq/interface/model/invert.py +8 -0
  53. classiq/interface/model/model.py +19 -0
  54. classiq/interface/model/model_visitor.py +4 -2
  55. classiq/interface/model/quantum_type.py +36 -0
  56. classiq/interface/model/statement_block.py +0 -4
  57. classiq/interface/qubits_mapping/__init__.py +4 -0
  58. classiq/interface/qubits_mapping/path_expr_range.py +69 -0
  59. classiq/interface/qubits_mapping/qubits_mapping.py +231 -0
  60. classiq/interface/qubits_mapping/slices.py +112 -0
  61. classiq/model_expansions/arithmetic.py +6 -0
  62. classiq/model_expansions/capturing/captured_vars.py +16 -12
  63. classiq/model_expansions/function_builder.py +9 -1
  64. classiq/model_expansions/interpreters/base_interpreter.py +9 -8
  65. classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
  66. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
  67. classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
  68. classiq/model_expansions/quantum_operations/bind.py +4 -0
  69. classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
  70. classiq/model_expansions/quantum_operations/emitter.py +1 -4
  71. classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
  72. classiq/model_expansions/visitors/uncomputation_signature_inference.py +0 -9
  73. classiq/qmod/builtins/functions/__init__.py +21 -9
  74. classiq/qmod/builtins/functions/allocation.py +0 -36
  75. classiq/qmod/builtins/functions/arithmetic.py +183 -0
  76. classiq/qmod/builtins/functions/exponentiation.py +32 -2
  77. classiq/qmod/builtins/functions/gray_code.py +23 -0
  78. classiq/qmod/builtins/functions/mcx_func.py +10 -0
  79. classiq/qmod/builtins/operations.py +2 -38
  80. classiq/qmod/builtins/structs.py +22 -3
  81. classiq/qmod/native/pretty_printer.py +1 -12
  82. classiq/qmod/pretty_print/pretty_printer.py +1 -17
  83. classiq/qmod/qmod_parameter.py +4 -0
  84. classiq/qmod/qmod_variable.py +38 -63
  85. classiq/qmod/quantum_function.py +43 -7
  86. classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
  87. classiq/qmod/semantics/validation/model_validation.py +7 -2
  88. classiq/qmod/symbolic_type.py +4 -2
  89. classiq/qprog_to_cudaq.py +347 -0
  90. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/METADATA +4 -1
  91. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/RECORD +93 -76
  92. classiq/interface/generator/amplitude_loading.py +0 -103
  93. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
  94. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/WHEEL +0 -0
  95. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,12 +1,15 @@
1
1
  import itertools
2
2
 
3
- from classiq.interface.generator.amplitude_loading import AmplitudeLoading
4
3
  from classiq.interface.generator.arith.arithmetic import Arithmetic
5
4
  from classiq.interface.generator.arith.binary_ops import (
6
5
  Adder,
7
6
  BitwiseAnd,
8
7
  BitwiseOr,
9
8
  BitwiseXor,
9
+ CanonicalAdder,
10
+ CanonicalConstantAdder,
11
+ CanonicalConstantMultiplier,
12
+ CanonicalMultiplier,
10
13
  Equal,
11
14
  GreaterEqual,
12
15
  GreaterThan,
@@ -58,6 +61,8 @@ function_param_library: FunctionParamLibrary = FunctionParamLibrary(
58
61
  BitwiseXor,
59
62
  BitwiseInvert,
60
63
  Adder,
64
+ CanonicalAdder,
65
+ CanonicalConstantAdder,
61
66
  Arithmetic,
62
67
  Sign,
63
68
  Equal,
@@ -79,6 +84,8 @@ function_param_library: FunctionParamLibrary = FunctionParamLibrary(
79
84
  HardwareEfficientAnsatz,
80
85
  UnitaryGate,
81
86
  Multiplier,
87
+ CanonicalMultiplier,
88
+ CanonicalConstantMultiplier,
82
89
  Power,
83
90
  Min,
84
91
  Max,
@@ -88,7 +95,6 @@ function_param_library: FunctionParamLibrary = FunctionParamLibrary(
88
95
  Identity,
89
96
  RandomizedBenchmarking,
90
97
  UGate,
91
- AmplitudeLoading,
92
98
  HadamardTransform,
93
99
  Copy,
94
100
  Reset,
@@ -46,7 +46,7 @@ END_BAD_REGISTER_ERROR_MSG = (
46
46
  )
47
47
 
48
48
  ALPHANUM_AND_UNDERSCORE = r"[0-9a-zA-Z_]*"
49
- NAME_REGEX = rf"_?[a-zA-Z]{ALPHANUM_AND_UNDERSCORE}"
49
+ NAME_REGEX = rf"_{{0,2}}[a-zA-Z]{ALPHANUM_AND_UNDERSCORE}"
50
50
 
51
51
  _UNVALIDATED_FUNCTIONS = ["Arithmetic", "CustomFunction"]
52
52
 
@@ -1,7 +1,8 @@
1
1
  CTRL_VAR_PREFIX = "ctrl__"
2
2
  CONTROL_OPERATOR_NAME = "control"
3
3
  SKIP_CONTROL_OPERATOR_NAME = "skip_control"
4
- INVERT_OPERATOR_NAME = "invert"
4
+ COMPOUND_INVERT_OPERATOR_NAME = "compound_invert"
5
+ SINGLE_CALL_INVERT_OPERATOR_NAME = "single_call_invert"
5
6
  REPEAT_OPERATOR_NAME = "iteration"
6
7
  CLASSICAL_IF_OPERATOR_NAME = "classical_if"
7
8
  POWER_OPERATOR_NAME = "power"
@@ -9,12 +10,7 @@ UNCOMPUTE_OPERATOR_NAME = "uncompute"
9
10
  WITHIN_APPLY_NAME = "within_apply"
10
11
  BLOCK_OPERATOR_NAME = "block"
11
12
 
12
- All_BUILTINS_OPERATORS = {
13
- CONTROL_OPERATOR_NAME,
14
- INVERT_OPERATOR_NAME,
15
- REPEAT_OPERATOR_NAME,
16
- POWER_OPERATOR_NAME,
17
- UNCOMPUTE_OPERATOR_NAME,
18
- WITHIN_APPLY_NAME,
19
- BLOCK_OPERATOR_NAME,
13
+ INVERT_OPERATOR_NAMES = {
14
+ COMPOUND_INVERT_OPERATOR_NAME,
15
+ SINGLE_CALL_INVERT_OPERATOR_NAME,
20
16
  }
@@ -61,6 +61,10 @@ class ClassicalType(HashableASTNode):
61
61
  def raw_qmod_type_name(self) -> str:
62
62
  return self.qmod_type_name
63
63
 
64
+ @property
65
+ def python_type_name(self) -> str:
66
+ raise NotImplementedError
67
+
64
68
  @property
65
69
  def expressions(self) -> list[Expression]:
66
70
  return []
@@ -76,6 +80,12 @@ class ClassicalType(HashableASTNode):
76
80
  def without_symbolic_attributes(self) -> Self:
77
81
  return self
78
82
 
83
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
84
+ return {}
85
+
86
+ def get_compile_time_attribute_types(self, prefix: str) -> dict[str, type]:
87
+ return {}
88
+
79
89
 
80
90
  class Integer(ClassicalType):
81
91
  kind: Literal["int"]
@@ -89,6 +99,10 @@ class Integer(ClassicalType):
89
99
  def qmod_type_name(self) -> str:
90
100
  return "CInt"
91
101
 
102
+ @property
103
+ def python_type_name(self) -> str:
104
+ return "int"
105
+
92
106
 
93
107
  class Real(ClassicalType):
94
108
  kind: Literal["real"]
@@ -102,6 +116,10 @@ class Real(ClassicalType):
102
116
  def qmod_type_name(self) -> str:
103
117
  return "CReal"
104
118
 
119
+ @property
120
+ def python_type_name(self) -> str:
121
+ return "float"
122
+
105
123
 
106
124
  class Bool(ClassicalType):
107
125
  kind: Literal["bool"]
@@ -115,6 +133,10 @@ class Bool(ClassicalType):
115
133
  def qmod_type_name(self) -> str:
116
134
  return "CBool"
117
135
 
136
+ @property
137
+ def python_type_name(self) -> str:
138
+ return "bool"
139
+
118
140
 
119
141
  class StructMetaType(ClassicalType):
120
142
  kind: Literal["type_proxy"]
@@ -201,6 +223,10 @@ class ClassicalArray(ClassicalType):
201
223
  def raw_qmod_type_name(self) -> str:
202
224
  return "CArray"
203
225
 
226
+ @property
227
+ def python_type_name(self) -> str:
228
+ return f"list[{self.element_type.python_type_name}]"
229
+
204
230
  def without_symbolic_attributes(self) -> "ClassicalArray":
205
231
  length = (
206
232
  None
@@ -213,6 +239,19 @@ class ClassicalArray(ClassicalType):
213
239
  element_type=self.element_type.without_symbolic_attributes(), length=length
214
240
  )
215
241
 
242
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
243
+ attrs: dict[str, Any] = {}
244
+ if self.has_constant_length:
245
+ attrs[f"{path_expr_prefix}.len"] = self.length_value
246
+ return attrs | self.element_type.get_compile_time_attributes(
247
+ f"{path_expr_prefix}[0]"
248
+ )
249
+
250
+ def get_compile_time_attribute_types(self, prefix: str) -> dict[str, type]:
251
+ return {
252
+ f"{prefix}.len": int
253
+ } | self.element_type.get_compile_time_attribute_types(f"{prefix}[0]")
254
+
216
255
 
217
256
  class ClassicalTuple(ClassicalType):
218
257
  kind: Literal["tuple"]
@@ -283,6 +322,13 @@ class ClassicalTuple(ClassicalType):
283
322
  def raw_qmod_type_name(self) -> str:
284
323
  return "CArray"
285
324
 
325
+ @property
326
+ def python_type_name(self) -> str:
327
+ raw_type = self.get_raw_type(preserve_length=True)
328
+ if isinstance(raw_type, ClassicalTuple):
329
+ return "list"
330
+ return raw_type.python_type_name
331
+
286
332
  def without_symbolic_attributes(self) -> "ClassicalTuple":
287
333
  return ClassicalTuple(
288
334
  element_types=[
@@ -291,6 +337,20 @@ class ClassicalTuple(ClassicalType):
291
337
  ]
292
338
  )
293
339
 
340
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
341
+ raw_type = self.get_raw_type(preserve_length=True)
342
+ attrs = {f"{path_expr_prefix}.len": len(self.element_types)}
343
+ if isinstance(raw_type, ClassicalTuple):
344
+ return attrs
345
+ return attrs | raw_type.get_compile_time_attributes(path_expr_prefix)
346
+
347
+ def get_compile_time_attribute_types(self, prefix: str) -> dict[str, type]:
348
+ raw_type = self.get_raw_type(preserve_length=True)
349
+ attrs: dict[str, type] = {f"{prefix}.len": int}
350
+ if isinstance(raw_type, ClassicalTuple):
351
+ return attrs
352
+ return attrs | raw_type.get_compile_time_attribute_types(prefix)
353
+
294
354
 
295
355
  class OpaqueHandle(ClassicalType):
296
356
  pass
@@ -60,6 +60,10 @@ class TypeName(ClassicalType, QuantumType):
60
60
  def qmod_type_name(self) -> str:
61
61
  return self.name
62
62
 
63
+ @property
64
+ def python_type_name(self) -> str:
65
+ return self.name
66
+
63
67
  @property
64
68
  def type_name(self) -> str:
65
69
  return self.name
@@ -202,6 +206,38 @@ class TypeName(ClassicalType, QuantumType):
202
206
  return type_name
203
207
  return self
204
208
 
209
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
210
+ attrs: dict[str, Any] = {}
211
+ if self.has_fields:
212
+ for field_name, field_type in self.fields.items():
213
+ field_prefix = f"{path_expr_prefix}.{field_name}"
214
+ attrs |= field_type.get_compile_time_attributes(field_prefix)
215
+ elif self.has_classical_struct_decl:
216
+ for (
217
+ field_name,
218
+ classical_field_type,
219
+ ) in self.classical_struct_decl.variables.items():
220
+ field_prefix = f"{path_expr_prefix}.{field_name}"
221
+ attrs |= classical_field_type.get_compile_time_attributes(field_prefix)
222
+ return attrs
223
+
224
+ def get_compile_time_attribute_types(self, prefix: str) -> dict[str, type]:
225
+ attrs: dict[str, type] = {}
226
+ if self.has_fields:
227
+ for field_name, field_type in self.fields.items():
228
+ field_prefix = f"{prefix}.{field_name}"
229
+ attrs |= field_type.get_compile_time_attribute_types(field_prefix)
230
+ elif self.has_classical_struct_decl:
231
+ for (
232
+ field_name,
233
+ classical_field_type,
234
+ ) in self.classical_struct_decl.variables.items():
235
+ field_prefix = f"{prefix}.{field_name}"
236
+ attrs |= classical_field_type.get_compile_time_attribute_types(
237
+ field_prefix
238
+ )
239
+ return attrs
240
+
205
241
 
206
242
  class Enum(TypeName):
207
243
  pass
@@ -140,7 +140,6 @@ class StatementType(StrEnum):
140
140
  WITHIN = "within"
141
141
  APPLY = "apply"
142
142
  ASSIGN = "assign"
143
- ASSIGN_AMPLITUDE = "assign amplitude"
144
143
  PHASE = "phase"
145
144
  INPLACE_XOR = "inplace xor"
146
145
  INPLACE_ADD = "inplace add"
@@ -163,7 +162,6 @@ STATEMENTS_NAME: dict[str, StatementType] = {
163
162
  "Uncompute": StatementType.WITHIN,
164
163
  ArithmeticOperationKind.Assignment.value: StatementType.ASSIGN,
165
164
  "InplaceBinaryOperation": StatementType.ASSIGN,
166
- "AmplitudeLoadingOperation": StatementType.ASSIGN_AMPLITUDE,
167
165
  "PhaseOperation": StatementType.PHASE,
168
166
  ArithmeticOperationKind.InplaceXor.value: StatementType.INPLACE_XOR,
169
167
  ArithmeticOperationKind.InplaceAdd.value: StatementType.INPLACE_ADD,
@@ -59,6 +59,7 @@ EXTRA_TWO_QUBIT_GATES: BasisGates = frozenset(
59
59
  "cu",
60
60
  "ch",
61
61
  "cp",
62
+ "iswap",
62
63
  )
63
64
  )
64
65
 
@@ -5,6 +5,8 @@ class CompilationMetadata(BaseModel):
5
5
  should_synthesize_separately: bool = Field(default=False)
6
6
  occurrences_number: NonNegativeInt = Field(default=0)
7
7
  _occupation_number: NonNegativeInt = PrivateAttr(default=0)
8
+ _min_required_clean_qubit: NonNegativeInt = PrivateAttr(default=0)
9
+ _max_required_clean_qubit: NonNegativeInt = PrivateAttr(default=0)
8
10
  disable_perm_check: bool = Field(default=False)
9
11
  disable_const_checks: list[str] | bool = Field(default=False)
10
12
 
@@ -16,6 +18,22 @@ class CompilationMetadata(BaseModel):
16
18
  def occupation_number(self, value: NonNegativeInt) -> None:
17
19
  self._occupation_number = value
18
20
 
21
+ @property
22
+ def min_required_clean_qubit(self) -> NonNegativeInt:
23
+ return self._min_required_clean_qubit
24
+
25
+ @min_required_clean_qubit.setter
26
+ def min_required_clean_qubit(self, value: NonNegativeInt) -> None:
27
+ self._min_required_clean_qubit = value
28
+
29
+ @property
30
+ def max_required_clean_qubit(self) -> NonNegativeInt:
31
+ return self._max_required_clean_qubit
32
+
33
+ @max_required_clean_qubit.setter
34
+ def max_required_clean_qubit(self, value: NonNegativeInt) -> None:
35
+ self._max_required_clean_qubit = value
36
+
19
37
  @property
20
38
  def has_user_directives(self) -> bool:
21
39
  return bool(self.disable_perm_check or self.disable_const_checks)
@@ -33,6 +33,8 @@ class Provider(StrEnum):
33
33
  INTEL = "Intel"
34
34
  AQT = "AQT"
35
35
  CINECA = "CINECA"
36
+ SOFTBANK = "Softbank"
37
+ C12 = "C12"
36
38
 
37
39
  @property
38
40
  def id(self) -> "ProviderIDEnum":
@@ -6,16 +6,31 @@ 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
11
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
11
- from classiq.interface.model.port_declaration import AnonPortDeclaration
12
+ from classiq.interface.model.port_declaration import (
13
+ PortDeclaration,
14
+ )
12
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
13
21
 
14
22
 
15
23
  class ModelNormalizer(Visitor):
16
- def __init__(self, normalize_names: bool = False) -> None:
17
- self._normalize_names = normalize_names
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
18
31
  self._funcs_renames: dict[str, str] = {}
32
+ self._count_name = CountedNameAllocator()
33
+ self.original_names: dict[str, str] = {}
19
34
 
20
35
  def visit(self, node: Any) -> None:
21
36
  if isinstance(node, ASTNode):
@@ -35,12 +50,12 @@ class ModelNormalizer(Visitor):
35
50
  self.generic_visit(model)
36
51
 
37
52
  def visit_NativeFunctionDefinition(self, func: NativeFunctionDefinition) -> None:
38
- if self._normalize_names:
53
+ if self._normalize_func_names:
39
54
  func.name = self._funcs_renames[func.name]
40
55
  self.generic_visit(func)
41
56
 
42
57
  def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
43
- if self._normalize_names:
58
+ if self._normalize_func_names:
44
59
  if isinstance(call.function, str):
45
60
  if call.function in self._funcs_renames:
46
61
  call.function = self._funcs_renames[call.function]
@@ -49,8 +64,29 @@ class ModelNormalizer(Visitor):
49
64
  call.function.name = self._funcs_renames[call.function.name]
50
65
  self.generic_visit(call)
51
66
 
52
- def visit_AnonPortDeclaration(self, decl: AnonPortDeclaration) -> None:
67
+ def visit_PortDeclaration(self, decl: PortDeclaration) -> None:
53
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
+ )
54
90
 
55
91
 
56
92
  class ClearModelInternals(Transformer):
@@ -1 +1 @@
1
- INTERFACE_VERSION = "15"
1
+ INTERFACE_VERSION = "17"
@@ -2,6 +2,8 @@ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.ast_node import ASTNodeType, reset_lists
4
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
5
7
  from classiq.interface.model.quantum_statement import QuantumOperation
6
8
 
7
9
  if TYPE_CHECKING:
@@ -25,3 +27,9 @@ class Invert(QuantumOperation):
25
27
  @property
26
28
  def blocks(self) -> dict[str, "StatementBlock"]:
27
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")
@@ -10,6 +10,7 @@ from classiq.interface.debug_info.debug_info import DebugInfoCollection
10
10
  from classiq.interface.exceptions import ClassiqValueError
11
11
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
12
12
  from classiq.interface.generator.constant import Constant
13
+ from classiq.interface.generator.function_params import ArithmeticIODict
13
14
  from classiq.interface.generator.functions.port_declaration import (
14
15
  PortDeclarationDirection,
15
16
  )
@@ -28,6 +29,10 @@ from classiq.interface.model.native_function_definition import (
28
29
  from classiq.interface.model.quantum_function_declaration import (
29
30
  NamedParamsQuantumFunctionDeclaration,
30
31
  )
32
+ from classiq.interface.model.quantum_type import (
33
+ RegisterQuantumTypeDict,
34
+ quantum_type_to_register_quantum_type,
35
+ )
31
36
  from classiq.interface.model.statement_block import StatementBlock
32
37
 
33
38
  USER_MODEL_MARKER = "user"
@@ -237,3 +242,17 @@ class Model(VersionedModel, ASTNode):
237
242
  self.compressed_debug_info = None
238
243
  else:
239
244
  self.compressed_debug_info = compress_pydantic(self._debug_info)
245
+
246
+ @property
247
+ def measured_registers(self) -> ArithmeticIODict:
248
+ return self.main_func.outputs_dict
249
+
250
+ @property
251
+ def measured_registers_type(self) -> RegisterQuantumTypeDict:
252
+ return {
253
+ key: quantum_type_to_register_quantum_type(
254
+ self.main_func.port_declarations_dict[key].quantum_type,
255
+ self.main_func.port_declarations_dict[key].quantum_type.size_in_bits,
256
+ )
257
+ for key in self.measured_registers.keys()
258
+ }
@@ -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):
@@ -78,6 +78,12 @@ 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
+
84
+ def get_compile_time_attribute_types(self, prefix: str) -> dict[str, type]:
85
+ return {}
86
+
81
87
 
82
88
  class QuantumScalar(QuantumType):
83
89
  @property
@@ -262,6 +268,19 @@ class QuantumBitvector(QuantumType):
262
268
  length = 1
263
269
  return length * self.element_type.minimal_size_in_bits
264
270
 
271
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
272
+ attrs: dict[str, Any] = {}
273
+ if self.has_constant_length:
274
+ attrs[f"{path_expr_prefix}.len"] = self.length_value
275
+ return attrs | self.element_type.get_compile_time_attributes(
276
+ f"{path_expr_prefix}[0]"
277
+ )
278
+
279
+ def get_compile_time_attribute_types(self, prefix: str) -> dict[str, type]:
280
+ return {
281
+ f"{prefix}.len": int
282
+ } | self.element_type.get_compile_time_attribute_types(f"{prefix}[0]")
283
+
265
284
  def without_symbolic_attributes(self) -> "QuantumBitvector":
266
285
  length = (
267
286
  None
@@ -301,6 +320,23 @@ class QuantumNumeric(QuantumScalar):
301
320
  )
302
321
  return self
303
322
 
323
+ def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
324
+ attrs: dict[str, Any] = {}
325
+ if self.has_size_in_bits:
326
+ attrs[f"{path_expr_prefix}.size"] = self.size_in_bits
327
+ if self.has_constant_sign:
328
+ attrs[f"{path_expr_prefix}.is_signed"] = self.sign_value
329
+ if self.has_constant_fraction_digits:
330
+ attrs[f"{path_expr_prefix}.fraction_digits"] = self.fraction_digits_value
331
+ return attrs
332
+
333
+ def get_compile_time_attribute_types(self, prefix: str) -> dict[str, type]:
334
+ return {
335
+ f"{prefix}.size": int,
336
+ f"{prefix}.is_signed": bool,
337
+ f"{prefix}.fraction_digits": int,
338
+ }
339
+
304
340
  def set_size_in_bits(self, val: int) -> None:
305
341
  super().set_size_in_bits(val)
306
342
  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,
@@ -0,0 +1,4 @@
1
+ from .qubits_mapping import FunctionScope, QubitsMapping
2
+ from .slices import Slices
3
+
4
+ __all__ = ["FunctionScope", "QubitsMapping", "Slices"]
@@ -0,0 +1,69 @@
1
+ from functools import singledispatch
2
+
3
+ from classiq.interface.exceptions import ClassiqInternalExpansionError
4
+ from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
5
+ from classiq.interface.generator.functions.type_name import TypeName
6
+ from classiq.interface.model.handle_binding import (
7
+ FieldHandleBinding,
8
+ HandleBinding,
9
+ SlicedHandleBinding,
10
+ SubscriptHandleBinding,
11
+ )
12
+ from classiq.interface.model.quantum_type import QuantumBitvector
13
+
14
+
15
+ def get_path_expr_range(
16
+ var: HandleBinding, quantum_type: ConcreteQuantumType
17
+ ) -> tuple[int, int]:
18
+ start = 0
19
+ stop = quantum_type.size_in_bits
20
+ for var_prefix in var.prefixes()[1:]:
21
+ start, stop, quantum_type = _pop_var_range(var_prefix, quantum_type, start)
22
+ return start, stop
23
+
24
+
25
+ @singledispatch
26
+ def _pop_var_range(
27
+ var_prefix: HandleBinding, quantum_type: ConcreteQuantumType, start: int
28
+ ) -> tuple[int, int, ConcreteQuantumType]:
29
+ raise ClassiqInternalExpansionError("Unexpected path expression")
30
+
31
+
32
+ @_pop_var_range.register
33
+ def _(
34
+ var_prefix: SubscriptHandleBinding, quantum_type: ConcreteQuantumType, start: int
35
+ ) -> tuple[int, int, ConcreteQuantumType]:
36
+ if not isinstance(quantum_type, QuantumBitvector):
37
+ raise ClassiqInternalExpansionError("Unexpected path expression")
38
+ index = var_prefix.index.to_int_value()
39
+ element_type = quantum_type.element_type
40
+ start += element_type.size_in_bits * index
41
+ stop = start + element_type.size_in_bits
42
+ return start, stop, element_type
43
+
44
+
45
+ @_pop_var_range.register
46
+ def _(
47
+ var_prefix: SlicedHandleBinding, quantum_type: ConcreteQuantumType, start: int
48
+ ) -> tuple[int, int, ConcreteQuantumType]:
49
+ if not isinstance(quantum_type, QuantumBitvector):
50
+ raise ClassiqInternalExpansionError("Unexpected path expression")
51
+ slice_start = var_prefix.start.to_int_value()
52
+ slice_stop = var_prefix.end.to_int_value()
53
+ stop = start + quantum_type.element_type.size_in_bits * slice_stop
54
+ start += quantum_type.element_type.size_in_bits * slice_start
55
+ return start, stop, quantum_type
56
+
57
+
58
+ @_pop_var_range.register
59
+ def _(
60
+ var_prefix: FieldHandleBinding, quantum_type: ConcreteQuantumType, start: int
61
+ ) -> tuple[int, int, ConcreteQuantumType]:
62
+ if not isinstance(quantum_type, TypeName) or not quantum_type.has_fields:
63
+ raise ClassiqInternalExpansionError("Unexpected path expression")
64
+ for field, field_type in quantum_type.fields.items():
65
+ if field == var_prefix.field:
66
+ stop = start + field_type.size_in_bits
67
+ return start, stop, field_type
68
+ start += field_type.size_in_bits
69
+ raise ClassiqInternalExpansionError("Unexpected path expression")