classiq 0.82.1__py3-none-any.whl → 0.84.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 (96) hide show
  1. classiq/_internals/api_wrapper.py +27 -0
  2. classiq/applications/chemistry/chemistry_model_constructor.py +2 -4
  3. classiq/applications/chemistry/hartree_fock.py +68 -0
  4. classiq/applications/chemistry/mapping.py +85 -0
  5. classiq/applications/chemistry/op_utils.py +79 -0
  6. classiq/applications/chemistry/problems.py +195 -0
  7. classiq/applications/chemistry/ucc.py +109 -0
  8. classiq/applications/chemistry/z2_symmetries.py +368 -0
  9. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +30 -1
  10. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -2
  11. classiq/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
  12. classiq/{model_expansions/evaluators → evaluators}/argument_types.py +3 -3
  13. classiq/{model_expansions/evaluators → evaluators}/classical_expression.py +1 -1
  14. classiq/{model_expansions/evaluators → evaluators}/classical_type_inference.py +3 -4
  15. classiq/{model_expansions/evaluators → evaluators}/parameter_types.py +17 -15
  16. classiq/execution/__init__.py +12 -1
  17. classiq/execution/execution_session.py +189 -43
  18. classiq/execution/jobs.py +26 -1
  19. classiq/execution/qnn.py +2 -2
  20. classiq/execution/user_budgets.py +39 -0
  21. classiq/interface/_version.py +1 -1
  22. classiq/interface/constants.py +1 -0
  23. classiq/interface/execution/primitives.py +29 -1
  24. classiq/interface/executor/estimate_cost.py +35 -0
  25. classiq/interface/executor/execution_result.py +13 -0
  26. classiq/interface/executor/result.py +116 -1
  27. classiq/interface/executor/user_budget.py +26 -33
  28. classiq/interface/generator/application_apis/finance_declarations.py +3 -3
  29. classiq/interface/generator/expressions/atomic_expression_functions.py +11 -3
  30. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
  31. classiq/interface/generator/functions/classical_type.py +2 -35
  32. classiq/interface/generator/functions/concrete_types.py +0 -3
  33. classiq/interface/generator/functions/type_modifier.py +22 -0
  34. classiq/interface/generator/generated_circuit_data.py +5 -16
  35. classiq/interface/generator/model/model.py +8 -0
  36. classiq/interface/generator/quantum_program.py +0 -13
  37. classiq/interface/generator/types/compilation_metadata.py +0 -3
  38. classiq/interface/helpers/model_normalizer.py +2 -2
  39. classiq/interface/ide/visual_model.py +6 -2
  40. classiq/interface/model/model.py +12 -7
  41. classiq/interface/model/port_declaration.py +4 -2
  42. classiq/interface/pretty_print/__init__.py +0 -0
  43. classiq/{qmod/native → interface/pretty_print}/expression_to_qmod.py +18 -11
  44. classiq/interface/server/routes.py +4 -0
  45. classiq/model_expansions/atomic_expression_functions_defs.py +42 -5
  46. classiq/model_expansions/capturing/captured_vars.py +21 -8
  47. classiq/model_expansions/interpreters/base_interpreter.py +3 -3
  48. classiq/model_expansions/quantum_operations/allocate.py +1 -1
  49. classiq/model_expansions/quantum_operations/assignment_result_processor.py +1 -1
  50. classiq/model_expansions/quantum_operations/bind.py +2 -2
  51. classiq/model_expansions/quantum_operations/call_emitter.py +42 -36
  52. classiq/model_expansions/quantum_operations/variable_decleration.py +1 -1
  53. classiq/model_expansions/scope_initialization.py +3 -3
  54. classiq/model_expansions/transformers/model_renamer.py +16 -5
  55. classiq/model_expansions/transformers/{type_qualifier_inference.py → type_modifier_inference.py} +134 -100
  56. classiq/model_expansions/visitors/symbolic_param_inference.py +10 -7
  57. classiq/open_library/functions/__init__.py +3 -0
  58. classiq/open_library/functions/amplitude_amplification.py +10 -18
  59. classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
  60. classiq/open_library/functions/grover.py +14 -6
  61. classiq/open_library/functions/modular_exponentiation.py +22 -20
  62. classiq/open_library/functions/state_preparation.py +18 -1
  63. classiq/qmod/__init__.py +2 -2
  64. classiq/qmod/builtins/enums.py +23 -0
  65. classiq/qmod/builtins/functions/__init__.py +2 -0
  66. classiq/qmod/builtins/functions/allocation.py +2 -2
  67. classiq/qmod/builtins/functions/arithmetic.py +16 -8
  68. classiq/qmod/builtins/functions/exponentiation.py +32 -4
  69. classiq/qmod/builtins/functions/standard_gates.py +7 -7
  70. classiq/qmod/builtins/structs.py +55 -3
  71. classiq/qmod/declaration_inferrer.py +8 -7
  72. classiq/qmod/native/pretty_printer.py +7 -11
  73. classiq/qmod/pretty_print/expression_to_python.py +2 -1
  74. classiq/qmod/pretty_print/pretty_printer.py +7 -12
  75. classiq/qmod/python_classical_type.py +12 -5
  76. classiq/qmod/qfunc.py +1 -1
  77. classiq/qmod/qmod_constant.py +2 -5
  78. classiq/qmod/qmod_parameter.py +2 -5
  79. classiq/qmod/qmod_variable.py +66 -25
  80. classiq/qmod/quantum_expandable.py +4 -2
  81. classiq/qmod/quantum_function.py +7 -2
  82. classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
  83. classiq/qmod/semantics/validation/main_validation.py +1 -9
  84. classiq/qmod/semantics/validation/type_hints.py +9 -9
  85. classiq/qmod/utilities.py +0 -2
  86. classiq/qmod/write_qmod.py +1 -1
  87. classiq/synthesis.py +0 -2
  88. {classiq-0.82.1.dist-info → classiq-0.84.0.dist-info}/METADATA +4 -1
  89. {classiq-0.82.1.dist-info → classiq-0.84.0.dist-info}/RECORD +95 -86
  90. classiq/interface/generator/functions/type_qualifier.py +0 -22
  91. /classiq/{model_expansions/evaluators → evaluators}/__init__.py +0 -0
  92. /classiq/{model_expansions/evaluators → evaluators}/control.py +0 -0
  93. /classiq/{model_expansions → evaluators}/expression_evaluator.py +0 -0
  94. /classiq/{model_expansions/evaluators → evaluators}/quantum_type_utils.py +0 -0
  95. /classiq/{model_expansions/evaluators → evaluators}/type_type_match.py +0 -0
  96. {classiq-0.82.1.dist-info → classiq-0.84.0.dist-info}/WHEEL +0 -0
@@ -4,6 +4,7 @@ import itertools
4
4
  import warnings
5
5
  from collections.abc import Collection, Iterator, Sequence
6
6
  from contextlib import contextmanager
7
+ from typing import Optional, Union
7
8
 
8
9
  from classiq.interface.exceptions import (
9
10
  ClassiqDeprecationWarning,
@@ -12,12 +13,13 @@ from classiq.interface.exceptions import (
12
13
  from classiq.interface.generator.functions.port_declaration import (
13
14
  PortDeclarationDirection,
14
15
  )
15
- from classiq.interface.generator.functions.type_qualifier import TypeQualifier
16
+ from classiq.interface.generator.functions.type_modifier import TypeModifier
16
17
  from classiq.interface.model.allocate import Allocate
17
18
  from classiq.interface.model.bind_operation import BindOperation
18
19
  from classiq.interface.model.control import Control
19
20
  from classiq.interface.model.invert import Invert
20
21
  from classiq.interface.model.model_visitor import ModelVisitor
22
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
21
23
  from classiq.interface.model.phase_operation import PhaseOperation
22
24
  from classiq.interface.model.port_declaration import PortDeclaration
23
25
  from classiq.interface.model.power import Power
@@ -31,41 +33,50 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
31
33
  QuantumExpressionOperation,
32
34
  )
33
35
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
34
- from classiq.interface.model.quantum_statement import QuantumStatement
35
36
  from classiq.interface.model.within_apply_operation import WithinApply
37
+ from classiq.interface.source_reference import SourceReference
36
38
 
37
39
  from classiq.model_expansions.visitors.variable_references import VarRefCollector
38
40
 
39
41
 
40
- def _inconsistent_type_qualifier_error(
41
- port_name: str, expected: TypeQualifier, actual: TypeQualifier
42
+ def _inconsistent_type_modifier_error(
43
+ port_name: str,
44
+ expected: TypeModifier,
45
+ actual: TypeModifier,
46
+ source_ref: Optional[Union[SourceReference, str]] = None,
42
47
  ) -> str:
48
+ source_ref_str = f"\n\tat {source_ref}" if source_ref else ""
43
49
  return (
44
- f"The type modifier of variable '{port_name}' does not conform to the function signature: "
50
+ f"The use of variable '{port_name}' does not conform to its declared modifier: "
45
51
  f"expected '{expected.name}', but found '{actual.name}'.\n"
46
- f"Tip: If the final role of the variable in the function matches '{expected.name}', "
47
- f"you may use the `unchecked` flag to instruct the compiler to disregard individual operations.\n"
48
- # TODO add earliest date of enforcement. See https://classiq.atlassian.net/browse/CLS-2709.
52
+ f"Tip: If the cumulative use of the variable in the function matches '{expected.name}', "
53
+ f"use the `unchecked` flag to instruct the compiler to disregard individual operations."
54
+ f"{source_ref_str}\n"
55
+ "The deprecation warning will be elevated to an error starting July 23, 2025, at the earliest."
49
56
  )
50
57
 
51
58
 
52
- def _inconsistent_type_qualifier_in_binding_error(
53
- expected: TypeQualifier, known_qualifiers: dict[str, TypeQualifier]
59
+ def _inconsistent_type_modifier_in_binding_error(
60
+ expected: TypeModifier,
61
+ known_modifiers: dict[str, TypeModifier],
62
+ source_ref: Optional[Union[SourceReference, str]] = None,
54
63
  ) -> str:
55
64
  actual = ", ".join(
56
- f"{name}: {qualifier.name}" for name, qualifier in known_qualifiers.items()
65
+ f"{name}: {modifier.name}" for name, modifier in known_modifiers.items()
57
66
  )
67
+ source_ref_str = f"\n\tat {source_ref}" if source_ref else ""
58
68
  return (
59
- f"The variable binding has inconsistent type modifiers: "
69
+ f"Inconsistent modifiers in variable binding: "
60
70
  f"Expected modifier: {expected.name}, Actual modifiers: {actual}"
61
- # TODO add earliest date of enforcement. See https://classiq.atlassian.net/browse/CLS-2709.
71
+ f"{source_ref_str}\n"
72
+ "The deprecation warning will be elevated to an error starting July 23, 2025, at the earliest."
62
73
  )
63
74
 
64
75
 
65
- class TypeQualifierValidation(ModelVisitor):
76
+ class TypeModifierValidation(ModelVisitor):
66
77
  """
67
78
  This class assumes that function calls are topologically sorted, so it traverses
68
- the list of function calls and infers the type qualifiers for each function call
79
+ the list of function calls and infers the type modifiers for each function call
69
80
  without going recursively into the function calls.
70
81
  The function definition ports are modified inplace.
71
82
  """
@@ -77,7 +88,7 @@ class TypeQualifierValidation(ModelVisitor):
77
88
  self._inferred_ports: dict[str, PortDeclaration] = dict()
78
89
  self._unchecked: set[str] = set()
79
90
 
80
- self._initialized_vars: dict[str, TypeQualifier] = dict()
91
+ self._initialized_vars: dict[str, TypeModifier] = dict()
81
92
  self._bound_vars: list[set[str]] = []
82
93
 
83
94
  self._conjugation_context: bool = False
@@ -85,13 +96,14 @@ class TypeQualifierValidation(ModelVisitor):
85
96
  support_unused_ports # could be turned off for debugging
86
97
  )
87
98
  self._skip_validation = skip_validation
99
+ self._source_ref: Optional[Union[SourceReference, str]] = None
88
100
 
89
101
  @contextmanager
90
102
  def validate_ports(
91
103
  self, ports: Collection[PortDeclaration], unchecked: Collection[str]
92
104
  ) -> Iterator[bool]:
93
105
  for port in ports:
94
- if port.type_qualifier is TypeQualifier.Inferred:
106
+ if port.type_modifier is TypeModifier.Inferred:
95
107
  self._inferred_ports[port.name] = port
96
108
  else:
97
109
  self._signature_ports[port.name] = port
@@ -99,7 +111,7 @@ class TypeQualifierValidation(ModelVisitor):
99
111
 
100
112
  yield len(self._inferred_ports) > 0 or (
101
113
  any(
102
- port.type_qualifier is not TypeQualifier.Quantum
114
+ port.type_modifier is not TypeModifier.Mutable
103
115
  for port in self._signature_ports.values()
104
116
  )
105
117
  and not self._skip_validation
@@ -119,27 +131,38 @@ class TypeQualifierValidation(ModelVisitor):
119
131
  finally:
120
132
  self._conjugation_context = previous_context
121
133
 
134
+ @contextmanager
135
+ def source_reference_context(
136
+ self, source_ref: Optional[Union[SourceReference, str]]
137
+ ) -> Iterator[None]:
138
+ previous_source_ref = self._source_ref
139
+ self._source_ref = source_ref
140
+ try:
141
+ yield
142
+ finally:
143
+ self._source_ref = previous_source_ref
144
+
122
145
  def _set_unused_as_const(self) -> None:
123
146
  unresolved_ports = [
124
147
  port
125
148
  for port in self._inferred_ports.values()
126
- if port.type_qualifier is TypeQualifier.Inferred
149
+ if port.type_modifier is TypeModifier.Inferred
127
150
  ]
128
151
  if not self._support_unused_ports and len(unresolved_ports) > 0:
129
152
  raise ClassiqInternalExpansionError(
130
153
  f"Unresolved inferred ports detected: {', '.join(port.name for port in unresolved_ports)}. "
131
- "All ports must have their type qualifiers resolved."
154
+ "All ports must have their type modifiers resolved."
132
155
  )
133
156
  for port in unresolved_ports:
134
- port.type_qualifier = TypeQualifier.Const
157
+ port.type_modifier = TypeModifier.Const
135
158
 
136
- def _validate_qualifier(self, candidate: str, qualifier: TypeQualifier) -> None:
137
- if self._conjugation_context and qualifier is TypeQualifier.QFree:
138
- qualifier = TypeQualifier.Const
159
+ def _validate_modifier(self, candidate: str, modifier: TypeModifier) -> None:
160
+ if self._conjugation_context and modifier is TypeModifier.Permutable:
161
+ modifier = TypeModifier.Const
139
162
 
140
163
  if candidate in self._inferred_ports:
141
- self._inferred_ports[candidate].type_qualifier = TypeQualifier.and_(
142
- self._inferred_ports[candidate].type_qualifier, qualifier
164
+ self._inferred_ports[candidate].type_modifier = TypeModifier.and_(
165
+ self._inferred_ports[candidate].type_modifier, modifier
143
166
  )
144
167
  return
145
168
 
@@ -147,64 +170,68 @@ class TypeQualifierValidation(ModelVisitor):
147
170
  return
148
171
 
149
172
  if candidate in self._signature_ports:
150
- self._validate_signature_qualifier(candidate, qualifier)
173
+ self._validate_signature_modifier(candidate, modifier)
151
174
 
152
175
  elif candidate in self._initialized_vars:
153
- self._initialized_vars[candidate] = TypeQualifier.and_(
154
- self._initialized_vars[candidate], qualifier
176
+ self._initialized_vars[candidate] = TypeModifier.and_(
177
+ self._initialized_vars[candidate], modifier
155
178
  )
156
179
 
157
- def _validate_signature_qualifier(
158
- self, candidate: str, qualifier: TypeQualifier
180
+ def _validate_signature_modifier(
181
+ self, candidate: str, modifier: TypeModifier
159
182
  ) -> None:
160
- signature_qualifier = self._signature_ports[candidate].type_qualifier
161
- if signature_qualifier is not TypeQualifier.and_(
162
- signature_qualifier, qualifier
163
- ):
183
+ signature_modifier = self._signature_ports[candidate].type_modifier
184
+ if signature_modifier is not TypeModifier.and_(signature_modifier, modifier):
164
185
  warnings.warn(
165
- _inconsistent_type_qualifier_error(
166
- candidate, signature_qualifier, qualifier
186
+ _inconsistent_type_modifier_error(
187
+ candidate, signature_modifier, modifier, self._source_ref
167
188
  ),
168
189
  ClassiqDeprecationWarning,
169
190
  stacklevel=1,
170
191
  )
171
192
 
172
- def _add_initialized_qualifier(self, var: str, qualifier: TypeQualifier) -> None:
193
+ def _add_initialized_modifier(self, var: str, modifier: TypeModifier) -> None:
173
194
  if var in self._inferred_ports or var in self._signature_ports:
174
195
  return
175
- if self._conjugation_context and qualifier is TypeQualifier.QFree:
176
- qualifier = TypeQualifier.Const
177
- self._initialized_vars[var] = qualifier
196
+ if self._conjugation_context and modifier is TypeModifier.Permutable:
197
+ modifier = TypeModifier.Const
198
+ self._initialized_vars[var] = modifier
178
199
 
179
200
  def run(
180
201
  self,
181
- ports: Collection[PortDeclaration],
182
- body: Sequence[QuantumStatement],
202
+ func_def: NativeFunctionDefinition,
183
203
  unchecked: Collection[str],
184
204
  ) -> None:
185
- with self.validate_ports(ports, unchecked) as should_validate:
205
+ with (
206
+ self.validate_ports(
207
+ func_def.port_declarations, unchecked
208
+ ) as should_validate,
209
+ self.source_reference_context(f"function '{func_def.name}'"),
210
+ ):
186
211
  if should_validate:
187
- self.visit(body)
212
+ self.visit(func_def.body)
188
213
  self._update_bound_vars()
189
214
 
190
215
  def _update_bound_vars(self) -> None:
191
216
  merged_bound_vars = _merge_overlapping(self._bound_vars)
192
217
  for bound_vars in merged_bound_vars:
193
- reduced_qualifier = self._get_reduced_qualifier(bound_vars)
218
+ reduced_modifier = self._get_reduced_modifier(bound_vars)
194
219
  for var in bound_vars:
195
- self._validate_qualifier(var, reduced_qualifier)
220
+ self._validate_modifier(var, reduced_modifier)
196
221
 
197
222
  def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
198
- for handle, port in call.handles_with_params:
199
- self._validate_qualifier(handle.name, port.type_qualifier)
200
- if port.direction is PortDeclarationDirection.Output:
201
- self._add_initialized_qualifier(handle.name, port.type_qualifier)
223
+ with self.source_reference_context(call.source_ref):
224
+ for handle, port in call.handles_with_params:
225
+ self._validate_modifier(handle.name, port.type_modifier)
226
+ if port.direction is PortDeclarationDirection.Output:
227
+ self._add_initialized_modifier(handle.name, port.type_modifier)
202
228
 
203
229
  if self._has_inputs(call):
204
230
  bound_vars = {
205
231
  handle.name
206
232
  for handle, port in call.handles_with_params
207
233
  if port.direction is not PortDeclarationDirection.Inout
234
+ and handle.name not in self._unchecked
208
235
  }
209
236
  self._bound_vars.append(bound_vars)
210
237
 
@@ -216,61 +243,61 @@ class TypeQualifierValidation(ModelVisitor):
216
243
  )
217
244
 
218
245
  def visit_Allocate(self, alloc: Allocate) -> None:
219
- self._validate_qualifier(alloc.target.name, TypeQualifier.QFree)
220
- self._add_initialized_qualifier(alloc.target.name, TypeQualifier.QFree)
246
+ with self.source_reference_context(alloc.source_ref):
247
+ self._validate_modifier(alloc.target.name, TypeModifier.Permutable)
248
+ self._add_initialized_modifier(alloc.target.name, TypeModifier.Permutable)
221
249
 
222
250
  def visit_BindOperation(self, bind_op: BindOperation) -> None:
223
251
  var_names = {
224
252
  handle.name
225
253
  for handle in itertools.chain(bind_op.in_handles, bind_op.out_handles)
254
+ if handle.name not in self._unchecked
226
255
  }
227
256
  self._bound_vars.append(var_names)
228
257
  for handle in bind_op.out_handles:
229
- self._add_initialized_qualifier(handle.name, TypeQualifier.Inferred)
258
+ self._add_initialized_modifier(handle.name, TypeModifier.Inferred)
230
259
 
231
- def _get_reduced_qualifier(self, bound_vars: set[str]) -> TypeQualifier:
232
- signature_qualifier = {
233
- name: self._signature_ports[name].type_qualifier
260
+ def _get_reduced_modifier(self, bound_vars: set[str]) -> TypeModifier:
261
+ signature_modifiers = {
262
+ name: self._signature_ports[name].type_modifier
234
263
  for name in bound_vars.intersection(self._signature_ports)
235
264
  }
236
- known_inferred_qualifiers = {
237
- name: self._inferred_ports[name].type_qualifier
265
+ known_inferred_modifiers = {
266
+ name: self._inferred_ports[name].type_modifier
238
267
  for name in bound_vars.intersection(self._inferred_ports)
239
- if self._inferred_ports[name].type_qualifier is not TypeQualifier.Inferred
268
+ if self._inferred_ports[name].type_modifier is not TypeModifier.Inferred
240
269
  }
241
- known_initialized_qualifiers = {
270
+ known_initialized_modifiers = {
242
271
  name: self._initialized_vars[name]
243
272
  for name in bound_vars.intersection(self._initialized_vars)
244
- if self._initialized_vars[name] is not TypeQualifier.Inferred
273
+ if self._initialized_vars[name] is not TypeModifier.Inferred
245
274
  }
246
- known_qualifiers = (
247
- signature_qualifier
248
- | known_inferred_qualifiers
249
- | known_initialized_qualifiers
275
+ known_modifiers = (
276
+ signature_modifiers | known_inferred_modifiers | known_initialized_modifiers
250
277
  )
251
- min_qualifier = self._get_min_qualifier(list(known_qualifiers.values()))
278
+ min_modifier = self._get_min_modifier(list(known_modifiers.values()))
252
279
  if not all(
253
- type_qualifier is min_qualifier
254
- for type_qualifier in signature_qualifier.values()
280
+ type_modifier is min_modifier
281
+ for type_modifier in signature_modifiers.values()
255
282
  ):
256
283
  warnings.warn(
257
- _inconsistent_type_qualifier_in_binding_error(
258
- min_qualifier, known_qualifiers
284
+ _inconsistent_type_modifier_in_binding_error(
285
+ min_modifier, known_modifiers, self._source_ref
259
286
  ),
260
287
  ClassiqDeprecationWarning,
261
288
  stacklevel=1,
262
289
  )
263
290
 
264
- return min_qualifier
291
+ return min_modifier
265
292
 
266
293
  @staticmethod
267
- def _get_min_qualifier(qualifiers: list[TypeQualifier]) -> TypeQualifier:
268
- if len(qualifiers) == 0:
269
- return TypeQualifier.Const
270
- elif len(qualifiers) == 1:
271
- return qualifiers[0]
294
+ def _get_min_modifier(modifiers: list[TypeModifier]) -> TypeModifier:
295
+ if len(modifiers) == 0:
296
+ return TypeModifier.Const
297
+ elif len(modifiers) == 1:
298
+ return modifiers[0]
272
299
  else:
273
- return functools.reduce(TypeQualifier.and_, qualifiers)
300
+ return functools.reduce(TypeModifier.and_, modifiers)
274
301
 
275
302
  @staticmethod
276
303
  def _extract_expr_vars(expr_op: QuantumExpressionOperation) -> list[str]:
@@ -281,42 +308,49 @@ class TypeQualifierValidation(ModelVisitor):
281
308
  return [handle.name for handle in vrc.var_handles]
282
309
 
283
310
  def visit_ArithmeticOperation(self, arith: ArithmeticOperation) -> None:
284
- result_var = arith.result_var.name
285
- self._validate_qualifier(result_var, TypeQualifier.QFree)
286
- for expr_var in self._extract_expr_vars(arith):
287
- self._validate_qualifier(expr_var, TypeQualifier.Const)
288
- if not arith.is_inplace:
289
- self._add_initialized_qualifier(result_var, TypeQualifier.QFree)
311
+ with self.source_reference_context(arith.source_ref):
312
+ result_var = arith.result_var.name
313
+ self._validate_modifier(result_var, TypeModifier.Permutable)
314
+ for expr_var in self._extract_expr_vars(arith):
315
+ self._validate_modifier(expr_var, TypeModifier.Const)
316
+ if not arith.is_inplace:
317
+ self._add_initialized_modifier(result_var, TypeModifier.Permutable)
290
318
 
291
319
  def visit_AmplitudeLoadingOperation(
292
320
  self, amp_load: AmplitudeLoadingOperation
293
321
  ) -> None:
294
- result_var = amp_load.result_var.name
295
- self._validate_qualifier(result_var, TypeQualifier.Quantum)
296
- for expr_var in self._extract_expr_vars(amp_load):
297
- self._validate_qualifier(expr_var, TypeQualifier.Const)
322
+ with self.source_reference_context(amp_load.source_ref):
323
+ result_var = amp_load.result_var.name
324
+ self._validate_modifier(result_var, TypeModifier.Mutable)
325
+ for expr_var in self._extract_expr_vars(amp_load):
326
+ self._validate_modifier(expr_var, TypeModifier.Const)
298
327
 
299
328
  def visit_PhaseOperation(self, phase_op: PhaseOperation) -> None:
300
- for expr_var in self._extract_expr_vars(phase_op):
301
- self._validate_qualifier(expr_var, TypeQualifier.Const)
329
+ with self.source_reference_context(phase_op.source_ref):
330
+ for expr_var in self._extract_expr_vars(phase_op):
331
+ self._validate_modifier(expr_var, TypeModifier.Const)
302
332
 
303
333
  def visit_Control(self, control: Control) -> None:
304
- for control_var in self._extract_expr_vars(control):
305
- self._validate_qualifier(control_var, TypeQualifier.Const)
306
- self.visit(control.body)
307
- if control.else_block is not None:
308
- self.visit(control.else_block)
334
+ with self.source_reference_context(control.source_ref):
335
+ for control_var in self._extract_expr_vars(control):
336
+ self._validate_modifier(control_var, TypeModifier.Const)
337
+ self.visit(control.body)
338
+ if control.else_block is not None:
339
+ self.visit(control.else_block)
309
340
 
310
341
  def visit_Invert(self, invert: Invert) -> None:
311
- self.visit(invert.body)
342
+ with self.source_reference_context(invert.source_ref):
343
+ self.visit(invert.body)
312
344
 
313
345
  def visit_Power(self, power: Power) -> None:
314
- self.visit(power.body)
346
+ with self.source_reference_context(power.source_ref):
347
+ self.visit(power.body)
315
348
 
316
349
  def visit_WithinApply(self, within_apply: WithinApply) -> None:
317
- with self.conjugation_context():
318
- self.visit(within_apply.compute)
319
- self.visit(within_apply.action)
350
+ with self.source_reference_context(within_apply.source_ref):
351
+ with self.conjugation_context():
352
+ self.visit(within_apply.compute)
353
+ self.visit(within_apply.action)
320
354
 
321
355
 
322
356
  def _merge_overlapping(bound_vars: Sequence[Collection[str]]) -> list[set[str]]:
@@ -10,7 +10,6 @@ from classiq.interface.generator.expressions.atomic_expression_functions import
10
10
  from classiq.interface.generator.expressions.expression import Expression
11
11
  from classiq.interface.generator.functions.classical_type import (
12
12
  ClassicalArray,
13
- ClassicalList,
14
13
  ClassicalTuple,
15
14
  ClassicalType,
16
15
  )
@@ -37,6 +36,13 @@ from classiq.interface.model.quantum_lambda_function import (
37
36
  from classiq.model_expansions.visitors.variable_references import VarRefCollector
38
37
 
39
38
 
39
+ def handle_is_directly_used_var(handle: HandleBinding, scope_vars: set[str]) -> bool:
40
+ return handle.name in scope_vars and (
41
+ not isinstance(handle, FieldHandleBinding)
42
+ or handle.field not in CLASSICAL_ATTRIBUTES
43
+ )
44
+
45
+
40
46
  def set_generative_recursively(classical_type: ClassicalType) -> None:
41
47
  if (
42
48
  isinstance(classical_type, TypeName)
@@ -46,7 +52,7 @@ def set_generative_recursively(classical_type: ClassicalType) -> None:
46
52
  set_generative_recursively(field_type)
47
53
  return
48
54
  classical_type.set_generative()
49
- if isinstance(classical_type, (ClassicalArray, ClassicalList)):
55
+ if isinstance(classical_type, ClassicalArray):
50
56
  set_generative_recursively(classical_type.element_type)
51
57
  if isinstance(classical_type, ClassicalTuple):
52
58
  for element_type in classical_type.element_types:
@@ -148,7 +154,7 @@ class SymbolicParamInference(ModelVisitor):
148
154
  for param, arg in zip_longest(params, call.positional_args):
149
155
  if (
150
156
  not isinstance(param, AnonClassicalParameterDeclaration)
151
- or param.classical_type.is_purely_generative
157
+ or not param.classical_type.is_purely_declarative
152
158
  ):
153
159
  self._process_compile_time_expressions(arg)
154
160
  else:
@@ -178,10 +184,7 @@ class SymbolicParamInference(ModelVisitor):
178
184
  )
179
185
  vrc.visit(ast.parse(expr))
180
186
  for handle in vrc.var_handles:
181
- if handle.name in self._scope and (
182
- not isinstance(handle, FieldHandleBinding)
183
- or handle.field not in CLASSICAL_ATTRIBUTES
184
- ):
187
+ if handle_is_directly_used_var(handle, set(self._scope)):
185
188
  set_generative_recursively(self._scope[handle.name])
186
189
 
187
190
  def _process_nested_compile_time_expression(self, expr: str) -> None:
@@ -6,6 +6,7 @@ from .amplitude_estimation import *
6
6
  from .discrete_sine_cosine_transform import *
7
7
  from .discrete_sine_cosine_transform import _qct_d_operator, _qct_pi_operator
8
8
  from .grover import *
9
+ from .grover import _cond_phase_flip
9
10
  from .hea import *
10
11
  from .linear_pauli_rotation import *
11
12
  from .linear_pauli_rotation import _single_pauli
@@ -79,6 +80,7 @@ OPEN_LIBRARY_FUNCTIONS = [
79
80
  _check_msb,
80
81
  encode_in_angle,
81
82
  encode_on_bloch,
83
+ _cond_phase_flip,
82
84
  ]
83
85
 
84
86
  __all__ = [
@@ -105,6 +107,7 @@ __all__ = [
105
107
  "modular_increment",
106
108
  "multiswap",
107
109
  "phase_oracle",
110
+ "prepare_basis_state",
108
111
  "prepare_bell_state",
109
112
  "prepare_complex_amplitudes",
110
113
  "prepare_dicke_state",
@@ -1,11 +1,10 @@
1
1
  from classiq.open_library.functions.grover import grover_operator
2
+ from classiq.qmod.builtins.functions.allocation import free
2
3
  from classiq.qmod.builtins.functions.standard_gates import RY
3
4
  from classiq.qmod.builtins.operations import (
4
5
  allocate,
5
- bind,
6
6
  control,
7
7
  power,
8
- within_apply,
9
8
  )
10
9
  from classiq.qmod.cparam import CInt, CReal
11
10
  from classiq.qmod.qfunc import qfunc
@@ -71,21 +70,14 @@ def exact_amplitude_amplification(
71
70
  theta = pi / (4 * k + 2)
72
71
  rot_phase = 2 * acos(sin(theta) / amplitude)
73
72
 
74
- extended_qvars: QArray = QArray()
75
- within_apply(
76
- lambda: [
77
- allocate(aux),
78
- bind([aux, packed_qvars], extended_qvars),
73
+ allocate(aux)
74
+ amplitude_amplification(
75
+ k,
76
+ lambda qvars_: control(qvars_[0] == 0, lambda: oracle(qvars_[1 : qvars_.size])),
77
+ lambda qvars_: [
78
+ space_transform(qvars_[1 : qvars_.size]),
79
+ RY(rot_phase, qvars_[0]),
79
80
  ],
80
- lambda: amplitude_amplification(
81
- k,
82
- lambda qvars_: control(
83
- qvars_[0] == 0, lambda: oracle(qvars_[1 : qvars_.size])
84
- ),
85
- lambda qvars_: [
86
- space_transform(qvars_[1 : qvars_.size]),
87
- RY(rot_phase, qvars_[0]),
88
- ],
89
- extended_qvars,
90
- ),
81
+ [aux, packed_qvars],
91
82
  )
83
+ free(aux)
@@ -11,7 +11,7 @@ from classiq.qmod.builtins.operations import (
11
11
  within_apply,
12
12
  )
13
13
  from classiq.qmod.qfunc import qfunc
14
- from classiq.qmod.qmod_variable import QArray, QBit, QNum
14
+ from classiq.qmod.qmod_variable import Const, Permutable, QArray, QBit, QNum
15
15
  from classiq.qmod.symbolic import pi
16
16
 
17
17
 
@@ -21,13 +21,13 @@ def _b_operator(q: QBit) -> None:
21
21
 
22
22
 
23
23
  @qfunc
24
- def _qct_d_operator(x: QNum, q: QBit) -> None:
24
+ def _qct_d_operator(x: Const[QNum], q: QBit) -> None:
25
25
  _b_operator(q)
26
26
  control(x == 0, lambda: invert(lambda: _b_operator(q)))
27
27
 
28
28
 
29
29
  @qfunc
30
- def _qct_pi_operator(x: QArray[QBit], q: QBit) -> None:
30
+ def _qct_pi_operator(x: Permutable[QArray[QBit]], q: Const[QBit]) -> None:
31
31
  control(
32
32
  q == 1,
33
33
  lambda: [
@@ -120,8 +120,8 @@ def qct_qst_type1(x: QArray[QBit]) -> None:
120
120
  within_apply(lambda: _t_operator(x), lambda: qft(x))
121
121
 
122
122
 
123
- @qfunc
124
- def qct_qst_type2(x: QArray[QBit], q: QBit) -> None:
123
+ @qfunc(unchecked=["q"])
124
+ def qct_qst_type2(x: QArray[QBit], q: Const[QBit]) -> None:
125
125
  """
126
126
  [Qmod Classiq-library function]
127
127
 
@@ -10,14 +10,22 @@ from classiq.qmod.builtins.operations import (
10
10
  )
11
11
  from classiq.qmod.qfunc import qfunc
12
12
  from classiq.qmod.qmod_parameter import CInt
13
- from classiq.qmod.qmod_variable import QArray, QBit, QNum
13
+ from classiq.qmod.qmod_variable import Const, Permutable, QArray, QBit, QNum
14
14
  from classiq.qmod.quantum_callable import QCallable
15
15
  from classiq.qmod.symbolic import pi
16
16
 
17
17
 
18
+ @qfunc(unchecked=["target"])
19
+ def _cond_phase_flip(
20
+ predicate: QCallable[Permutable[QBit]], target: Const[QBit]
21
+ ) -> None:
22
+ within_apply(lambda: H(target), lambda: predicate(target))
23
+
24
+
18
25
  @qfunc
19
26
  def phase_oracle(
20
- predicate: QCallable[QArray[QBit], QBit], target: QArray[QBit]
27
+ predicate: QCallable[Const[QArray[QBit]], Permutable[QBit]],
28
+ target: Const[QArray[QBit]],
21
29
  ) -> None:
22
30
  """
23
31
  [Qmod Classiq-library function]
@@ -42,13 +50,13 @@ def phase_oracle(
42
50
  """
43
51
  aux = QBit()
44
52
  within_apply(
45
- within=lambda: (allocate(aux), X(aux), H(aux)),
46
- apply=lambda: predicate(target, aux),
53
+ lambda: [allocate(aux), X(aux)],
54
+ lambda: _cond_phase_flip(lambda x: predicate(target, x), aux),
47
55
  )
48
56
 
49
57
 
50
- @qfunc
51
- def reflect_about_zero(packed_vars: QArray[QBit]) -> None:
58
+ @qfunc(unchecked=["packed_vars"])
59
+ def reflect_about_zero(packed_vars: Const[QArray[QBit]]) -> None:
52
60
  """
53
61
  [Qmod Classiq-library function]
54
62