classiq 0.84.0__py3-none-any.whl → 0.85.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 (40) hide show
  1. classiq/applications/combinatorial_optimization/combinatorial_problem.py +20 -42
  2. classiq/evaluators/classical_expression.py +32 -15
  3. classiq/execution/execution_session.py +49 -6
  4. classiq/interface/_version.py +1 -1
  5. classiq/interface/debug_info/debug_info.py +0 -4
  6. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -0
  7. classiq/interface/generator/functions/builtins/internal_operators.py +2 -0
  8. classiq/interface/generator/functions/concrete_types.py +20 -0
  9. classiq/interface/generator/generated_circuit_data.py +5 -10
  10. classiq/interface/ide/operation_registry.py +45 -0
  11. classiq/interface/ide/visual_model.py +62 -1
  12. classiq/interface/model/bounds.py +12 -2
  13. classiq/interface/model/quantum_expressions/arithmetic_operation.py +7 -4
  14. classiq/interface/model/variable_declaration_statement.py +33 -6
  15. classiq/model_expansions/atomic_expression_functions_defs.py +5 -1
  16. classiq/model_expansions/function_builder.py +4 -1
  17. classiq/model_expansions/interpreters/generative_interpreter.py +16 -1
  18. classiq/model_expansions/quantum_operations/assignment_result_processor.py +63 -21
  19. classiq/model_expansions/quantum_operations/bounds.py +7 -1
  20. classiq/model_expansions/quantum_operations/classical_var_emitter.py +16 -0
  21. classiq/model_expansions/quantum_operations/variable_decleration.py +30 -10
  22. classiq/model_expansions/scope.py +7 -0
  23. classiq/model_expansions/transformers/var_splitter.py +1 -1
  24. classiq/open_library/functions/__init__.py +0 -2
  25. classiq/open_library/functions/qaoa_penalty.py +8 -1
  26. classiq/open_library/functions/state_preparation.py +1 -32
  27. classiq/qmod/__init__.py +2 -0
  28. classiq/qmod/builtins/operations.py +65 -1
  29. classiq/qmod/classical_variable.py +74 -0
  30. classiq/qmod/native/pretty_printer.py +18 -14
  31. classiq/qmod/pretty_print/pretty_printer.py +34 -15
  32. classiq/qmod/qfunc.py +2 -19
  33. classiq/qmod/qmod_variable.py +5 -8
  34. classiq/qmod/quantum_expandable.py +1 -1
  35. classiq/qmod/quantum_function.py +42 -2
  36. classiq/qmod/symbolic_type.py +2 -1
  37. {classiq-0.84.0.dist-info → classiq-0.85.0.dist-info}/METADATA +1 -1
  38. {classiq-0.84.0.dist-info → classiq-0.85.0.dist-info}/RECORD +39 -37
  39. classiq/interface/model/quantum_variable_declaration.py +0 -7
  40. {classiq-0.84.0.dist-info → classiq-0.85.0.dist-info}/WHEEL +0 -0
@@ -1,15 +1,42 @@
1
- from typing import Literal
1
+ from typing import Any, Literal, Optional
2
+
3
+ import pydantic
2
4
 
3
5
  from classiq.interface.generator.expressions.expression import Expression
4
- from classiq.interface.model.quantum_statement import QuantumStatement
5
- from classiq.interface.model.quantum_variable_declaration import (
6
- QuantumVariableDeclaration,
6
+ from classiq.interface.generator.functions.concrete_types import (
7
+ ConcreteQuantumType,
8
+ ConcreteType,
7
9
  )
10
+ from classiq.interface.model.quantum_statement import QuantumStatement
11
+ from classiq.interface.model.quantum_type import QuantumType
8
12
 
9
13
 
10
- class VariableDeclarationStatement(QuantumStatement, QuantumVariableDeclaration):
14
+ class VariableDeclarationStatement(QuantumStatement):
11
15
  kind: Literal["VariableDeclarationStatement"]
12
16
 
17
+ name: str
18
+ quantum_type: Optional[ConcreteQuantumType] = None
19
+ qmod_type: ConcreteType
20
+
21
+ @pydantic.model_validator(mode="before")
22
+ @classmethod
23
+ def _set_qmod_type(cls, values: Any) -> dict[str, Any]:
24
+ if isinstance(values, dict):
25
+ if "quantum_type" in values and (
26
+ "qmod_type" not in values or values["qmod_type"] is None
27
+ ):
28
+ values["qmod_type"] = values["quantum_type"]
29
+ values["quantum_type"] = None
30
+ return values
31
+ if values.quantum_type is not None and values.qmod_type is None:
32
+ values.qmod_type = values.quantum_type
33
+ values.quantum_type = None
34
+ return values
35
+
13
36
  @property
14
37
  def expressions(self) -> list[Expression]:
15
- return self.quantum_type.expressions
38
+ return self.qmod_type.expressions
39
+
40
+ @property
41
+ def is_quantum(self) -> bool:
42
+ return isinstance(self.qmod_type, QuantumType)
@@ -9,6 +9,9 @@ from classiq.interface.exceptions import (
9
9
  ClassiqExpansionError,
10
10
  ClassiqInternalExpansionError,
11
11
  )
12
+ from classiq.interface.generator.expressions.atomic_expression_functions import (
13
+ MEASUREMENT_FUNCTIONS,
14
+ )
12
15
  from classiq.interface.generator.expressions.expression_types import (
13
16
  ExpressionValue,
14
17
  QmodStructInstance,
@@ -398,7 +401,8 @@ def _symbolic_function(func: str) -> Callable:
398
401
 
399
402
 
400
403
  QMOD_CLASSICAL_FUNCTIONS = [
401
- _symbolic_function(func) for func in qmod_classical_functions
404
+ _symbolic_function(func)
405
+ for func in qmod_classical_functions + list(MEASUREMENT_FUNCTIONS)
402
406
  ]
403
407
 
404
408
  ATOMIC_EXPRESSION_FUNCTIONS = {
@@ -9,6 +9,7 @@ from classiq.interface.generator.compiler_keywords import (
9
9
  LAMBDA_KEYWORD,
10
10
  )
11
11
  from classiq.interface.generator.functions.builtins.internal_operators import (
12
+ BLOCK_OPERATOR_NAME,
12
13
  WITHIN_APPLY_NAME,
13
14
  )
14
15
  from classiq.interface.model.model import MAIN_FUNCTION_NAME
@@ -35,6 +36,8 @@ from classiq.model_expansions.utils.counted_name_allocator import CountedNameAll
35
36
 
36
37
  ClosureType = TypeVar("ClosureType", bound=Closure)
37
38
 
39
+ BLOCKS_ALLOWED_CAPTURING = (WITHIN_APPLY_NAME, BLOCK_OPERATOR_NAME)
40
+
38
41
 
39
42
  @dataclass
40
43
  class Block:
@@ -142,7 +145,7 @@ class OperationBuilder:
142
145
  captured_vars = self.current_block.captured_vars
143
146
  if (
144
147
  not isinstance(self.current_operation, FunctionClosure)
145
- and self.current_operation.name != WITHIN_APPLY_NAME
148
+ and self.current_operation.name not in BLOCKS_ALLOWED_CAPTURING
146
149
  ):
147
150
  validate_captured_directions(
148
151
  captured_vars.filter_var_decls(
@@ -7,6 +7,7 @@ from numpy.random import permutation
7
7
  from classiq.interface.generator.constant import Constant
8
8
  from classiq.interface.generator.expressions.expression import Expression
9
9
  from classiq.interface.generator.functions.builtins.internal_operators import (
10
+ BLOCK_OPERATOR_NAME,
10
11
  CLASSICAL_IF_OPERATOR_NAME,
11
12
  CONTROL_OPERATOR_NAME,
12
13
  INVERT_OPERATOR_NAME,
@@ -15,6 +16,7 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
15
16
  )
16
17
  from classiq.interface.model.allocate import Allocate
17
18
  from classiq.interface.model.bind_operation import BindOperation
19
+ from classiq.interface.model.block import Block
18
20
  from classiq.interface.model.bounds import SetBoundsStatement
19
21
  from classiq.interface.model.classical_if import ClassicalIf
20
22
  from classiq.interface.model.control import Control
@@ -68,6 +70,9 @@ from classiq.model_expansions.quantum_operations.block_evaluator import (
68
70
  RepeatElimination,
69
71
  )
70
72
  from classiq.model_expansions.quantum_operations.bounds import SetBoundsEmitter
73
+ from classiq.model_expansions.quantum_operations.classical_var_emitter import (
74
+ ClassicalVarEmitter,
75
+ )
71
76
  from classiq.model_expansions.quantum_operations.composite_emitter import (
72
77
  CompositeEmitter,
73
78
  )
@@ -192,6 +197,7 @@ class GenerativeInterpreter(BaseInterpreter):
192
197
  [
193
198
  HandleEvaluator(self, "result_var"),
194
199
  ExpressionEvaluator(self, "expression"),
200
+ ClassicalVarEmitter(self),
195
201
  AssignmentResultProcessor(self),
196
202
  ],
197
203
  ).emit(op)
@@ -303,9 +309,18 @@ class GenerativeInterpreter(BaseInterpreter):
303
309
  def emit_set_bounds(self, op: SetBoundsStatement) -> None:
304
310
  CompositeEmitter[SetBoundsStatement](
305
311
  self,
306
- [HandleEvaluator(self, "target"), SetBoundsEmitter(self)],
312
+ [
313
+ ExpressionEvaluator(self, "lower_bound"),
314
+ ExpressionEvaluator(self, "upper_bound"),
315
+ HandleEvaluator(self, "target"),
316
+ SetBoundsEmitter(self),
317
+ ],
307
318
  ).emit(op)
308
319
 
320
+ @emit.register
321
+ def emit_block(self, block: Block) -> None:
322
+ BlockEvaluator(self, BLOCK_OPERATOR_NAME, "statements").emit(block)
323
+
309
324
  def _expand_body(self, operation: Closure) -> None:
310
325
  if isinstance(operation, FunctionClosure) and operation.name == "permute":
311
326
  # special expansion since permute is generative
@@ -1,10 +1,12 @@
1
- from typing import Optional
1
+ from typing import TYPE_CHECKING, Optional
2
2
 
3
3
  from classiq.interface.exceptions import ClassiqExpansionError
4
4
  from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
5
5
  from classiq.interface.generator.expressions.expression import Expression
6
6
  from classiq.interface.model.allocate import Allocate
7
7
  from classiq.interface.model.bind_operation import BindOperation
8
+ from classiq.interface.model.block import Block
9
+ from classiq.interface.model.bounds import SetBoundsStatement
8
10
  from classiq.interface.model.handle_binding import (
9
11
  ConcreteHandleBinding,
10
12
  HandleBinding,
@@ -19,6 +21,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
19
21
  )
20
22
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
21
23
  from classiq.interface.model.quantum_type import QuantumBitvector, QuantumNumeric
24
+ from classiq.interface.model.statement_block import StatementBlock
22
25
  from classiq.interface.model.variable_declaration_statement import (
23
26
  VariableDeclarationStatement,
24
27
  )
@@ -30,14 +33,25 @@ from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_exp
30
33
  validate_assignment_bool_expression,
31
34
  )
32
35
  from classiq.model_expansions.quantum_operations.emitter import Emitter
33
- from classiq.model_expansions.scope import QuantumSymbol
36
+ from classiq.model_expansions.scope import ClassicalSymbol
34
37
  from classiq.model_expansions.transformers.ast_renamer import rename_variables
35
38
  from classiq.qmod.builtins.functions.standard_gates import CX
36
39
 
40
+ if TYPE_CHECKING:
41
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
42
+
37
43
 
38
44
  class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
45
+ def __init__(
46
+ self, interpreter: "BaseInterpreter", replace_assignment_if_needed: bool = False
47
+ ) -> None:
48
+ super().__init__(interpreter)
49
+ self._replace_assignment_if_needed = replace_assignment_if_needed
50
+
39
51
  def emit(self, op: QuantumAssignmentOperation, /) -> bool:
40
- result_symbol = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
52
+ result_symbol = self._interpreter.evaluate(op.result_var).value
53
+ if isinstance(result_symbol, ClassicalSymbol):
54
+ return False
41
55
  result_type = result_symbol.quantum_type
42
56
 
43
57
  if not (
@@ -70,9 +84,11 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
70
84
  self._validate_declared_attributes(
71
85
  result_type, inferred_result_type, str(op.result_var)
72
86
  )
73
- self._assign_to_inferred_var_and_bind(op, result_type, inferred_result_type)
74
- result_type.set_bounds(inferred_result_type.get_bounds())
75
- return True
87
+ if self._replace_assignment_if_needed:
88
+ self._assign_to_inferred_var_and_bind(op, result_type, inferred_result_type)
89
+ return True
90
+ else:
91
+ return False
76
92
 
77
93
  def _infer_result_type(self, op: ArithmeticOperation) -> Optional[QuantumNumeric]:
78
94
  expr = self._evaluate_expression(op.expression)
@@ -182,6 +198,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
182
198
  result_type: QuantumNumeric,
183
199
  inferred_result_type: QuantumNumeric,
184
200
  ) -> None:
201
+ stmts: StatementBlock = []
185
202
  handles: list[HandleBinding] = []
186
203
 
187
204
  extra_fraction_digits = (
@@ -190,20 +207,22 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
190
207
  )
191
208
  if extra_fraction_digits > 0:
192
209
  handles.append(
193
- self._declare_qarray("extra_fraction_digits", extra_fraction_digits)
210
+ self._declare_qarray(
211
+ "extra_fraction_digits", extra_fraction_digits, stmts
212
+ )
194
213
  )
195
214
 
196
215
  inferred_result_name = self._counted_name_allocator.allocate("inferred_result")
197
216
  inferred_result_handle = HandleBinding(name=inferred_result_name)
198
- self._interpreter.emit(
217
+ stmts.append(
199
218
  VariableDeclarationStatement(
200
- name=inferred_result_name, quantum_type=inferred_result_type
219
+ name=inferred_result_name, qmod_type=inferred_result_type
201
220
  )
202
221
  )
203
222
  handles.append(inferred_result_handle)
204
223
  modified_op = op.model_copy(update={"result_var": inferred_result_handle})
205
224
  self._interpreter.add_to_debug_info(modified_op)
206
- self._interpreter.emit(modified_op)
225
+ stmts.append(modified_op)
207
226
 
208
227
  result_integer_size = (
209
228
  result_type.size_in_bits - result_type.fraction_digits_value
@@ -214,11 +233,11 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
214
233
  )
215
234
  extra_integers = result_integer_size - inferred_result_integer_size
216
235
  if extra_integers > 0:
217
- handles.append(self._declare_qarray("extra_integers", extra_integers))
236
+ handles.append(
237
+ self._declare_qarray("extra_integers", extra_integers, stmts)
238
+ )
218
239
 
219
- self._interpreter.emit(
220
- BindOperation(in_handles=handles, out_handles=[op.result_var])
221
- )
240
+ stmts.append(BindOperation(in_handles=handles, out_handles=[op.result_var]))
222
241
 
223
242
  if (
224
243
  result_type.sign_value
@@ -226,22 +245,44 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
226
245
  and extra_integers > 0
227
246
  ):
228
247
  sign_idx = result_type.size_in_bits - extra_integers - 1
229
- self._sign_extension(op.result_var, sign_idx, result_type.size_in_bits)
248
+ self._sign_extension(
249
+ op.result_var, sign_idx, result_type.size_in_bits, stmts
250
+ )
251
+
252
+ if (inferred_bounds := inferred_result_type.get_bounds()) is not None:
253
+ lower_bound = Expression(expr=str(inferred_bounds[0]))
254
+ upper_bound = Expression(expr=str(inferred_bounds[1]))
255
+ else:
256
+ lower_bound, upper_bound = None, None
257
+ stmts.append(
258
+ SetBoundsStatement(
259
+ target=op.result_var,
260
+ lower_bound=lower_bound,
261
+ upper_bound=upper_bound,
262
+ )
263
+ )
264
+
265
+ self._interpreter.emit(
266
+ Block(
267
+ statements=stmts,
268
+ uuid=op.uuid,
269
+ back_ref=op.back_ref,
270
+ )
271
+ )
230
272
 
231
273
  def _declare_qarray(
232
274
  self,
233
275
  prefix: str,
234
276
  size: int,
277
+ stmts: StatementBlock,
235
278
  allocate: bool = True,
236
279
  ) -> HandleBinding:
237
280
  name = self._counted_name_allocator.allocate(prefix)
238
281
  handle = HandleBinding(name=name)
239
282
  quantum_type = QuantumBitvector(length=Expression(expr=str(size)))
240
- self._interpreter.emit(
241
- VariableDeclarationStatement(name=name, quantum_type=quantum_type)
242
- )
283
+ stmts.append(VariableDeclarationStatement(name=name, qmod_type=quantum_type))
243
284
  if allocate:
244
- self._interpreter.emit(Allocate(target=handle))
285
+ stmts.append(Allocate(target=handle))
245
286
  return handle
246
287
 
247
288
  def _sign_extension(
@@ -249,9 +290,10 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
249
290
  result_var: ConcreteHandleBinding,
250
291
  sign_idx: int,
251
292
  size: int,
293
+ stmts: StatementBlock,
252
294
  ) -> None:
253
- aux = self._declare_qarray("inferred_result_aux", size, allocate=False)
254
- self._interpreter.emit(
295
+ aux = self._declare_qarray("inferred_result_aux", size, stmts, allocate=False)
296
+ stmts.append(
255
297
  WithinApply(
256
298
  compute=[BindOperation(in_handles=[result_var], out_handles=[aux])],
257
299
  action=[
@@ -24,7 +24,13 @@ class SetBoundsEmitter(Emitter[SetBoundsStatement]):
24
24
  raise ClassiqExpansionError(
25
25
  f"Cannot set bounds of a non-numeric variable {op.target.qmod_expr!r}"
26
26
  )
27
- target.quantum_type.set_bounds(op.bounds)
27
+
28
+ if op.lower_bound is not None and op.upper_bound is not None:
29
+ target.quantum_type.set_bounds(
30
+ (op.lower_bound.to_float_value(), op.upper_bound.to_float_value())
31
+ )
32
+ else:
33
+ target.quantum_type.reset_bounds()
28
34
  if self._keep_statement:
29
35
  self.emit_statement(op)
30
36
  return True
@@ -0,0 +1,16 @@
1
+ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
2
+ ArithmeticOperation,
3
+ )
4
+
5
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
6
+ from classiq.model_expansions.scope import ClassicalSymbol
7
+
8
+
9
+ class ClassicalVarEmitter(Emitter[ArithmeticOperation]):
10
+ def emit(self, op: ArithmeticOperation, /) -> bool:
11
+ result_symbol = self._interpreter.evaluate(op.result_var).value
12
+ if not isinstance(result_symbol, ClassicalSymbol):
13
+ return False
14
+ op._classical_assignment = True
15
+ self.emit_statement(op)
16
+ return True
@@ -1,14 +1,19 @@
1
+ from typing import TYPE_CHECKING, Union
2
+
1
3
  from classiq.interface.exceptions import ClassiqExpansionError
4
+ from classiq.interface.generator.functions.classical_type import ClassicalType
2
5
  from classiq.interface.model.handle_binding import HandleBinding
6
+ from classiq.interface.model.quantum_type import QuantumType
3
7
  from classiq.interface.model.variable_declaration_statement import (
4
8
  VariableDeclarationStatement,
5
9
  )
6
10
 
7
11
  from classiq.evaluators.parameter_types import (
12
+ evaluate_type_in_classical_symbol,
8
13
  evaluate_type_in_quantum_symbol,
9
14
  )
10
15
  from classiq.model_expansions.quantum_operations.emitter import Emitter
11
- from classiq.model_expansions.scope import Evaluated, QuantumSymbol
16
+ from classiq.model_expansions.scope import ClassicalSymbol, Evaluated, QuantumSymbol
12
17
 
13
18
 
14
19
  class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
@@ -16,24 +21,39 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
16
21
  var_decl = variable_declaration.model_copy(
17
22
  update=dict(back_ref=variable_declaration.uuid)
18
23
  )
19
- var_decl.quantum_type = variable_declaration.quantum_type.model_copy()
24
+ var_decl.qmod_type = variable_declaration.qmod_type.model_copy()
20
25
  if variable_declaration.name in self._current_scope:
21
26
  raise ClassiqExpansionError(
22
27
  f"Variable {variable_declaration.name!r} is already defined"
23
28
  )
24
- self._current_scope[variable_declaration.name] = Evaluated(
25
- value=QuantumSymbol(
29
+ var_value: Union[QuantumSymbol, ClassicalSymbol]
30
+ if variable_declaration.is_quantum:
31
+ if TYPE_CHECKING:
32
+ assert isinstance(var_decl.qmod_type, QuantumType)
33
+ var_value = QuantumSymbol(
26
34
  handle=HandleBinding(name=var_decl.name),
27
35
  quantum_type=evaluate_type_in_quantum_symbol(
28
- var_decl.quantum_type,
36
+ var_decl.qmod_type,
29
37
  self._current_scope,
30
38
  var_decl.name,
31
39
  ),
32
- ),
33
- defining_function=self._builder.current_function,
34
- )
35
- self._builder.current_block.captured_vars.init_var(
36
- var_decl.name, self._builder.current_function
40
+ )
41
+ self._builder.current_block.captured_vars.init_var(
42
+ var_decl.name, self._builder.current_function
43
+ )
44
+ else:
45
+ if TYPE_CHECKING:
46
+ assert isinstance(var_decl.qmod_type, ClassicalType)
47
+ var_value = ClassicalSymbol(
48
+ handle=HandleBinding(name=var_decl.name),
49
+ classical_type=evaluate_type_in_classical_symbol(
50
+ var_decl.qmod_type,
51
+ self._current_scope,
52
+ var_decl.name,
53
+ ),
54
+ )
55
+ self._current_scope[variable_declaration.name] = Evaluated(
56
+ value=var_value, defining_function=self._builder.current_function
37
57
  )
38
58
  self.emit_statement(var_decl)
39
59
  return True
@@ -21,6 +21,7 @@ from classiq.interface.generator.expressions.proxies.classical.classical_scalar_
21
21
  from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
22
22
  QmodStructInstance,
23
23
  )
24
+ from classiq.interface.generator.functions.classical_type import ClassicalType
24
25
  from classiq.interface.generator.functions.type_name import TypeName
25
26
  from classiq.interface.helpers.text_utils import readable_list, s
26
27
  from classiq.interface.model.handle_binding import (
@@ -202,6 +203,12 @@ class QuantumSymbolList(QuantumVariable):
202
203
  return str(self.handles)
203
204
 
204
205
 
206
+ @dataclass(frozen=True)
207
+ class ClassicalSymbol:
208
+ handle: HandleBinding
209
+ classical_type: ClassicalType
210
+
211
+
205
212
  @singledispatch
206
213
  def evaluated_to_str(value: Any) -> str:
207
214
  return str(value)
@@ -218,7 +218,7 @@ class VarSplitter(ModelRenamer):
218
218
  return [
219
219
  VariableDeclarationStatement(
220
220
  name=part.target_var_name,
221
- quantum_type=part.target_var_type,
221
+ qmod_type=part.target_var_type,
222
222
  )
223
223
  for part in chain.from_iterable(symbol_parts.values())
224
224
  ]
@@ -52,7 +52,6 @@ OPEN_LIBRARY_FUNCTIONS = [
52
52
  qsvt_inversion,
53
53
  qsvt_lcu,
54
54
  qsvt_lcu_step,
55
- allocate_num,
56
55
  qaoa_mixer_layer,
57
56
  qaoa_cost_layer,
58
57
  qaoa_layer,
@@ -85,7 +84,6 @@ OPEN_LIBRARY_FUNCTIONS = [
85
84
 
86
85
  __all__ = [
87
86
  "_single_pauli",
88
- "allocate_num",
89
87
  "amplitude_amplification",
90
88
  "amplitude_estimation",
91
89
  "apply_to_all",
@@ -1,5 +1,8 @@
1
+ import warnings
1
2
  from typing import Literal
2
3
 
4
+ from classiq.interface.exceptions import ClassiqDeprecationWarning
5
+
3
6
  from classiq.qmod.builtins.functions import RX, H, suzuki_trotter
4
7
  from classiq.qmod.builtins.operations import repeat
5
8
  from classiq.qmod.builtins.structs import PauliTerm
@@ -42,7 +45,11 @@ def qaoa_cost_layer(
42
45
  hamiltonian: The Hamiltonian terms for the QAOA model.
43
46
  target: The target quantum array variable.
44
47
  """
45
- suzuki_trotter(hamiltonian, g, 1, 1, target)
48
+ with warnings.catch_warnings(): # FIXME: Remove (CLS-2912)
49
+ warnings.simplefilter(
50
+ "ignore", category=ClassiqDeprecationWarning
51
+ ) # FIXME: Remove (CLS-2912)
52
+ suzuki_trotter(hamiltonian, g, 1, 1, target)
46
53
 
47
54
 
48
55
  @qfunc
@@ -27,7 +27,7 @@ from classiq.qmod.builtins.operations import (
27
27
  repeat,
28
28
  within_apply,
29
29
  )
30
- from classiq.qmod.cparam import CArray, CBool, CInt, CReal
30
+ from classiq.qmod.cparam import CArray, CInt, CReal
31
31
  from classiq.qmod.qfunc import qfunc
32
32
  from classiq.qmod.qmod_variable import Output, QArray, QBit, QNum
33
33
  from classiq.qmod.symbolic import (
@@ -45,37 +45,6 @@ from classiq.qmod.symbolic import (
45
45
  )
46
46
 
47
47
 
48
- @qfunc
49
- def allocate_num(
50
- num_qubits: CInt,
51
- is_signed: CBool,
52
- fraction_digits: CInt,
53
- out: Output[
54
- QNum[Literal["num_qubits"], Literal["is_signed"], Literal["fraction_digits"]]
55
- ],
56
- ) -> None:
57
- """
58
- [Qmod Classiq-library function]
59
-
60
- This function is **deprecated** and will no longer be supported starting on
61
- 16/06/2025 at the earliest. Instead, use `allocate` which supports the same
62
- parameters.
63
-
64
- Initializes a quantum number with the given number of qubits, sign, and fractional digits.
65
-
66
- Args:
67
- num_qubits: The number of qubits to allocate.
68
- is_signed: Whether the number is signed or unsigned.
69
- fraction_digits: The number of fractional digits.
70
- """
71
- warnings.warn(
72
- "Function `allocate_num` is deprecated and will no longer be supported starting on 16/06/2025 at the earliest. Instead, use `allocate` which supports the same parameters. ",
73
- ClassiqDeprecationWarning,
74
- stacklevel=1,
75
- )
76
- allocate(num_qubits, out)
77
-
78
-
79
48
  def _prepare_uniform_trimmed_state_apply_rotation(
80
49
  size_lsb: CInt, lsbs_val: CInt, rotation_var: QBit
81
50
  ) -> None:
classiq/qmod/__init__.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from .builtins import * # noqa: F403
2
2
  from .builtins import __all__ as _builtins_all
3
3
  from .cfunc import cfunc
4
+ from .classical_variable import measure
4
5
  from .create_model_function import create_model
5
6
  from .expression_query import get_expression_numeric_attributes
6
7
  from .qfunc import qfunc
@@ -29,6 +30,7 @@ __all__ = [
29
30
  "QStruct",
30
31
  "cfunc",
31
32
  "create_model",
33
+ "measure",
32
34
  "get_expression_numeric_attributes",
33
35
  "qfunc",
34
36
  "write_qmod",
@@ -7,6 +7,7 @@ from typing import (
7
7
  Callable,
8
8
  Final,
9
9
  NoReturn,
10
+ Optional,
10
11
  Union,
11
12
  overload,
12
13
  )
@@ -20,6 +21,8 @@ from classiq.interface.generator.functions.classical_type import Integer
20
21
  from classiq.interface.helpers.text_utils import s
21
22
  from classiq.interface.model.allocate import Allocate
22
23
  from classiq.interface.model.bind_operation import BindOperation
24
+ from classiq.interface.model.block import Block
25
+ from classiq.interface.model.bounds import SetBoundsStatement
23
26
  from classiq.interface.model.classical_if import ClassicalIf
24
27
  from classiq.interface.model.classical_parameter_declaration import (
25
28
  ClassicalParameterDeclaration,
@@ -46,7 +49,7 @@ from classiq.interface.model.within_apply_operation import WithinApply
46
49
 
47
50
  from classiq.qmod.generative import is_generative_mode
48
51
  from classiq.qmod.qmod_constant import QConstant
49
- from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QScalar, QVar
52
+ from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QNum, QScalar, QVar
50
53
  from classiq.qmod.quantum_callable import QCallable
51
54
  from classiq.qmod.quantum_expandable import prepare_arg
52
55
  from classiq.qmod.symbolic_expr import SymbolicExpr
@@ -398,6 +401,65 @@ def phase(expr: SymbolicExpr, theta: float = 1.0) -> None:
398
401
  )
399
402
 
400
403
 
404
+ @suppress_return_value
405
+ def block(
406
+ statements: Union[QCallable, Callable[[], Statements]],
407
+ ) -> None:
408
+ _validate_operand(statements)
409
+ assert QCallable.CURRENT_EXPANDABLE is not None
410
+ source_ref = get_source_ref(sys._getframe(1))
411
+
412
+ block_stmt = Block(
413
+ statements=_operand_to_body(statements, "statements"),
414
+ source_ref=source_ref,
415
+ )
416
+ if is_generative_mode():
417
+ block_stmt.set_generative_block("statements", statements)
418
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(block_stmt)
419
+
420
+
421
+ @overload
422
+ def reset_bounds(
423
+ target_var: QNum,
424
+ ) -> None:
425
+ pass
426
+
427
+
428
+ @overload
429
+ def reset_bounds(
430
+ target_var: QNum,
431
+ lower_bound: Union[float, SymbolicExpr],
432
+ upper_bound: Union[float, SymbolicExpr],
433
+ ) -> None:
434
+ pass
435
+
436
+
437
+ @suppress_return_value
438
+ def reset_bounds(
439
+ target_var: QNum,
440
+ lower_bound: Optional[Union[float, SymbolicExpr]] = None,
441
+ upper_bound: Optional[Union[float, SymbolicExpr]] = None,
442
+ ) -> None:
443
+ assert QCallable.CURRENT_EXPANDABLE is not None
444
+ source_ref = get_source_ref(sys._getframe(1))
445
+
446
+ lower_bound_expr = (
447
+ None if lower_bound is None else Expression(expr=str(lower_bound))
448
+ )
449
+ upper_bound_expr = (
450
+ None if upper_bound is None else Expression(expr=str(upper_bound))
451
+ )
452
+
453
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
454
+ SetBoundsStatement(
455
+ target=target_var.get_handle_binding(),
456
+ lower_bound=lower_bound_expr,
457
+ upper_bound=upper_bound_expr,
458
+ source_ref=source_ref,
459
+ )
460
+ )
461
+
462
+
401
463
  def _validate_operand(stmt_block: Any, num_params: int = 0) -> None:
402
464
  if stmt_block is None:
403
465
  _raise_operand_error(
@@ -502,6 +564,7 @@ __all__ = [
502
564
  "assign",
503
565
  "assign_amplitude",
504
566
  "bind",
567
+ "block",
505
568
  "control",
506
569
  "if_",
507
570
  "inplace_add",
@@ -510,6 +573,7 @@ __all__ = [
510
573
  "phase",
511
574
  "power",
512
575
  "repeat",
576
+ "reset_bounds",
513
577
  "within_apply",
514
578
  ]
515
579