classiq 0.84.0__py3-none-any.whl → 0.86.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 (87) hide show
  1. classiq/applications/combinatorial_optimization/combinatorial_problem.py +24 -45
  2. classiq/evaluators/classical_expression.py +32 -15
  3. classiq/evaluators/qmod_annotated_expression.py +207 -0
  4. classiq/evaluators/qmod_expression_visitors/__init__.py +0 -0
  5. classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +134 -0
  6. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +232 -0
  7. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +44 -0
  8. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +308 -0
  9. classiq/evaluators/qmod_node_evaluators/__init__.py +0 -0
  10. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +112 -0
  11. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +132 -0
  12. classiq/evaluators/qmod_node_evaluators/bool_op_evaluation.py +70 -0
  13. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +311 -0
  14. classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +107 -0
  15. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +67 -0
  16. classiq/evaluators/qmod_node_evaluators/list_evaluation.py +107 -0
  17. classiq/evaluators/qmod_node_evaluators/measurement_evaluation.py +25 -0
  18. classiq/evaluators/qmod_node_evaluators/name_evaluation.py +50 -0
  19. classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +66 -0
  20. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +225 -0
  21. classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +58 -0
  22. classiq/evaluators/qmod_node_evaluators/utils.py +80 -0
  23. classiq/execution/execution_session.py +53 -6
  24. classiq/interface/_version.py +1 -1
  25. classiq/interface/analyzer/analysis_params.py +1 -1
  26. classiq/interface/analyzer/result.py +1 -1
  27. classiq/interface/debug_info/debug_info.py +0 -4
  28. classiq/interface/executor/quantum_code.py +2 -2
  29. classiq/interface/generator/arith/arithmetic_expression_validator.py +5 -1
  30. classiq/interface/generator/arith/binary_ops.py +43 -51
  31. classiq/interface/generator/arith/number_utils.py +3 -2
  32. classiq/interface/generator/arith/register_user_input.py +15 -0
  33. classiq/interface/generator/arith/unary_ops.py +32 -28
  34. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -0
  35. classiq/interface/generator/expressions/expression_types.py +2 -2
  36. classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
  37. classiq/interface/generator/functions/builtins/internal_operators.py +2 -0
  38. classiq/interface/generator/functions/classical_function_declaration.py +0 -4
  39. classiq/interface/generator/functions/classical_type.py +0 -32
  40. classiq/interface/generator/functions/concrete_types.py +20 -0
  41. classiq/interface/generator/generated_circuit_data.py +7 -10
  42. classiq/interface/generator/quantum_program.py +6 -1
  43. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +29 -0
  44. classiq/interface/ide/operation_registry.py +45 -0
  45. classiq/interface/ide/visual_model.py +84 -2
  46. classiq/interface/model/bounds.py +12 -2
  47. classiq/interface/model/quantum_expressions/arithmetic_operation.py +7 -4
  48. classiq/interface/model/quantum_type.py +67 -33
  49. classiq/interface/model/variable_declaration_statement.py +33 -6
  50. classiq/model_expansions/arithmetic.py +115 -0
  51. classiq/model_expansions/arithmetic_compute_result_attrs.py +71 -0
  52. classiq/model_expansions/atomic_expression_functions_defs.py +10 -6
  53. classiq/model_expansions/function_builder.py +4 -1
  54. classiq/model_expansions/generative_functions.py +15 -2
  55. classiq/model_expansions/interpreters/base_interpreter.py +7 -0
  56. classiq/model_expansions/interpreters/generative_interpreter.py +18 -1
  57. classiq/model_expansions/quantum_operations/assignment_result_processor.py +63 -21
  58. classiq/model_expansions/quantum_operations/bounds.py +7 -1
  59. classiq/model_expansions/quantum_operations/call_emitter.py +5 -2
  60. classiq/model_expansions/quantum_operations/classical_var_emitter.py +16 -0
  61. classiq/model_expansions/quantum_operations/variable_decleration.py +30 -10
  62. classiq/model_expansions/scope.py +7 -0
  63. classiq/model_expansions/scope_initialization.py +2 -0
  64. classiq/model_expansions/sympy_conversion/sympy_to_python.py +1 -1
  65. classiq/model_expansions/transformers/type_modifier_inference.py +5 -0
  66. classiq/model_expansions/transformers/var_splitter.py +1 -1
  67. classiq/model_expansions/visitors/boolean_expression_transformers.py +1 -1
  68. classiq/open_library/functions/__init__.py +0 -2
  69. classiq/open_library/functions/qaoa_penalty.py +8 -1
  70. classiq/open_library/functions/state_preparation.py +1 -32
  71. classiq/qmod/__init__.py +2 -0
  72. classiq/qmod/builtins/operations.py +66 -2
  73. classiq/qmod/classical_variable.py +74 -0
  74. classiq/qmod/declaration_inferrer.py +5 -3
  75. classiq/qmod/native/pretty_printer.py +18 -14
  76. classiq/qmod/pretty_print/pretty_printer.py +34 -15
  77. classiq/qmod/qfunc.py +2 -19
  78. classiq/qmod/qmod_variable.py +5 -8
  79. classiq/qmod/quantum_expandable.py +1 -1
  80. classiq/qmod/quantum_function.py +42 -2
  81. classiq/qmod/symbolic_type.py +2 -1
  82. classiq/qmod/write_qmod.py +3 -1
  83. {classiq-0.84.0.dist-info → classiq-0.86.0.dist-info}/METADATA +1 -1
  84. {classiq-0.84.0.dist-info → classiq-0.86.0.dist-info}/RECORD +86 -62
  85. classiq/interface/model/quantum_variable_declaration.py +0 -7
  86. /classiq/{model_expansions/sympy_conversion/arithmetics.py → evaluators/qmod_expression_visitors/sympy_wrappers.py} +0 -0
  87. {classiq-0.84.0.dist-info → classiq-0.86.0.dist-info}/WHEEL +0 -0
@@ -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
@@ -186,7 +189,7 @@ def if_(
186
189
 
187
190
  @suppress_return_value
188
191
  def control(
189
- ctrl: Union[SymbolicExpr, QBit, QArray[QBit]],
192
+ ctrl: Union[SymbolicExpr, QBit, QArray[QBit], list[QVar]],
190
193
  stmt_block: Union[QCallable, Callable[[], Statements]],
191
194
  else_block: Union[QCallable, Callable[[], Statements], None] = None,
192
195
  ) -> None:
@@ -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
 
@@ -0,0 +1,74 @@
1
+ import sys
2
+ from typing import TYPE_CHECKING, Any
3
+
4
+ from classiq.interface.exceptions import ClassiqInternalError
5
+ from classiq.interface.generator.expressions.expression import Expression
6
+ from classiq.interface.generator.functions.classical_type import Bool, ClassicalType
7
+ from classiq.interface.model.handle_binding import HandleBinding
8
+ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
9
+ ArithmeticOperation,
10
+ ArithmeticOperationKind,
11
+ )
12
+ from classiq.interface.model.variable_declaration_statement import (
13
+ VariableDeclarationStatement,
14
+ )
15
+
16
+ from classiq.qmod.cparam import CBool, CParam, CParamScalar
17
+ from classiq.qmod.qmod_variable import QBit, _infer_variable_name
18
+ from classiq.qmod.quantum_callable import QCallable
19
+ from classiq.qmod.symbolic import symbolic_function
20
+ from classiq.qmod.symbolic_type import SYMBOLIC_TYPES
21
+ from classiq.qmod.utilities import get_source_ref
22
+
23
+
24
+ def declare_classical_variable(
25
+ name: str, classical_type: ClassicalType, frame_depth: int
26
+ ) -> None:
27
+ if TYPE_CHECKING:
28
+ assert QCallable.CURRENT_EXPANDABLE is not None
29
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
30
+ VariableDeclarationStatement(
31
+ name=name,
32
+ qmod_type=classical_type,
33
+ source_ref=get_source_ref(sys._getframe(frame_depth)),
34
+ )
35
+ )
36
+
37
+
38
+ def assign_classical_variable(target: CParam, value: Any, frame_depth: int) -> None:
39
+ if not isinstance(value, SYMBOLIC_TYPES):
40
+ raise TypeError(f"Invalid argument {value!r} for classical variable assignment")
41
+
42
+ if TYPE_CHECKING:
43
+ assert QCallable.CURRENT_EXPANDABLE is not None
44
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
45
+ ArithmeticOperation(
46
+ expression=Expression(expr=str(value)),
47
+ result_var=HandleBinding(name=str(target)),
48
+ operation_kind=ArithmeticOperationKind.Assignment,
49
+ source_ref=get_source_ref(sys._getframe(frame_depth)),
50
+ )
51
+ )
52
+
53
+
54
+ def measure(var: QBit) -> CParamScalar:
55
+ """
56
+ Measures the given qubit. `measure` is a non-unitary operation.
57
+
58
+ Args:
59
+ var: a qubit variable
60
+
61
+ Returns:
62
+ the measurement result (a symbolic boolean variable)
63
+ """
64
+ name = _infer_variable_name(None, 2)
65
+ if name is None:
66
+ raise ClassiqInternalError("Could not infer measure var name")
67
+ declare_classical_variable(name, Bool(), 2)
68
+ res_var = CParamScalar(name)
69
+ res_val = symbolic_function(
70
+ var,
71
+ return_type=CBool, # type:ignore[type-abstract]
72
+ )
73
+ assign_classical_variable(res_var, res_val, 2)
74
+ return res_var
@@ -40,6 +40,7 @@ from classiq.qmod.model_state_container import ModelStateContainer
40
40
  from classiq.qmod.python_classical_type import PythonClassicalType
41
41
  from classiq.qmod.qmod_variable import QVar, get_port_from_type_hint
42
42
  from classiq.qmod.quantum_callable import QCallableList
43
+ from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
43
44
  from classiq.qmod.semantics.validation.type_hints import validate_annotation
44
45
  from classiq.qmod.semantics.validation.types_validation import (
45
46
  check_duplicate_types,
@@ -74,9 +75,9 @@ class _PythonClassicalType(PythonClassicalType):
74
75
  return classical_type
75
76
  all_decls = BUILTIN_STRUCT_DECLARATIONS | self.qmodule.type_decls
76
77
  if py_type.__name__ in all_decls:
77
- classical_type.set_classical_struct_decl(
78
- all_decls[py_type.__name__].model_copy(deep=True)
79
- )
78
+ decl = all_decls[py_type.__name__].model_copy(deep=True)
79
+ QStructAnnotator().visit(decl)
80
+ classical_type.set_classical_struct_decl(decl)
80
81
  return classical_type
81
82
 
82
83
  struct_decl = StructDeclaration(
@@ -89,6 +90,7 @@ class _PythonClassicalType(PythonClassicalType):
89
90
  check_duplicate_types([struct_decl, *self.qmodule.user_types()])
90
91
  self.qmodule.type_decls[py_type.__name__] = struct_decl
91
92
  validate_cstruct(struct_decl)
93
+ QStructAnnotator().visit(struct_decl)
92
94
 
93
95
  classical_type.set_classical_struct_decl(struct_decl)
94
96
  return classical_type
@@ -29,6 +29,7 @@ from classiq.interface.generator.visitor import NodeType
29
29
  from classiq.interface.model.allocate import Allocate
30
30
  from classiq.interface.model.bind_operation import BindOperation
31
31
  from classiq.interface.model.block import Block
32
+ from classiq.interface.model.bounds import SetBoundsStatement
32
33
  from classiq.interface.model.classical_if import ClassicalIf
33
34
  from classiq.interface.model.classical_parameter_declaration import (
34
35
  AnonClassicalParameterDeclaration,
@@ -76,9 +77,6 @@ from classiq.interface.model.quantum_type import (
76
77
  QuantumBitvector,
77
78
  QuantumNumeric,
78
79
  )
79
- from classiq.interface.model.quantum_variable_declaration import (
80
- QuantumVariableDeclaration,
81
- )
82
80
  from classiq.interface.model.repeat import Repeat
83
81
  from classiq.interface.model.statement_block import StatementBlock
84
82
  from classiq.interface.model.variable_declaration_statement import (
@@ -189,11 +187,6 @@ class DSLPrettyPrinter(ModelVisitor):
189
187
  self._level -= 1
190
188
  return variables_str
191
189
 
192
- def visit_QuantumVariableDeclaration(
193
- self, var_decl: QuantumVariableDeclaration
194
- ) -> str:
195
- return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
196
-
197
190
  def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
198
191
  modifier_str = (
199
192
  f"{port_decl.type_modifier} "
@@ -263,9 +256,9 @@ class DSLPrettyPrinter(ModelVisitor):
263
256
  return type_.name
264
257
 
265
258
  def visit_VariableDeclarationStatement(
266
- self, local_decl: VariableDeclarationStatement
259
+ self, var_decl: VariableDeclarationStatement
267
260
  ) -> str:
268
- return f"{self._indent}{self.visit_QuantumVariableDeclaration(local_decl)};\n"
261
+ return f"{self._indent}{var_decl.name}: {self.visit(var_decl.qmod_type)};\n"
269
262
 
270
263
  def visit_AnonQuantumOperandDeclaration(
271
264
  self, op_decl: AnonQuantumOperandDeclaration
@@ -361,10 +354,10 @@ class DSLPrettyPrinter(ModelVisitor):
361
354
  return invert_code
362
355
 
363
356
  def visit_Block(self, block: Block) -> str:
364
- invert_code = f"{self._indent}block {{\n"
365
- invert_code += self._visit_body(block.statements)
366
- invert_code += f"{self._indent}}}\n"
367
- return invert_code
357
+ block_code = f"{self._indent}{{\n"
358
+ block_code += self._visit_body(block.statements)
359
+ block_code += f"{self._indent}}}\n"
360
+ return block_code
368
361
 
369
362
  def _visit_body(self, body: StatementBlock) -> str:
370
363
  code = ""
@@ -443,6 +436,17 @@ class DSLPrettyPrinter(ModelVisitor):
443
436
  def visit_OperandIdentifier(self, op: OperandIdentifier) -> str:
444
437
  return str(op)
445
438
 
439
+ def visit_SetBoundsStatement(self, op: SetBoundsStatement) -> str:
440
+ target = self.visit(op.target)
441
+ if op.lower_bound is None or op.upper_bound is None:
442
+ return f"{self._indent}reset_bounds({target});\n"
443
+ else:
444
+ lower_bound = self.visit(op.lower_bound)
445
+ upper_bound = self.visit(op.upper_bound)
446
+ return (
447
+ f"{self._indent}reset_bounds({target}, {lower_bound}, {upper_bound});\n"
448
+ )
449
+
446
450
  @property
447
451
  def _indent(self) -> str:
448
452
  return " " * self._level
@@ -30,6 +30,8 @@ from classiq.interface.generator.types.struct_declaration import StructDeclarati
30
30
  from classiq.interface.generator.visitor import NodeType, Visitor
31
31
  from classiq.interface.model.allocate import Allocate
32
32
  from classiq.interface.model.bind_operation import BindOperation
33
+ from classiq.interface.model.block import Block
34
+ from classiq.interface.model.bounds import SetBoundsStatement
33
35
  from classiq.interface.model.classical_if import ClassicalIf
34
36
  from classiq.interface.model.classical_parameter_declaration import (
35
37
  AnonClassicalParameterDeclaration,
@@ -75,9 +77,6 @@ from classiq.interface.model.quantum_type import (
75
77
  QuantumBitvector,
76
78
  QuantumNumeric,
77
79
  )
78
- from classiq.interface.model.quantum_variable_declaration import (
79
- QuantumVariableDeclaration,
80
- )
81
80
  from classiq.interface.model.repeat import Repeat
82
81
  from classiq.interface.model.statement_block import StatementBlock
83
82
  from classiq.interface.model.variable_declaration_statement import (
@@ -91,6 +90,8 @@ from classiq.qmod.pretty_print.expression_to_python import transform_expression
91
90
 
92
91
 
93
92
  class VariableDeclarationAssignment(Visitor):
93
+ # FIXME: Support classical variable types
94
+
94
95
  def __init__(self, pretty_printer: "PythonPrettyPrinter") -> None:
95
96
  self.pretty_printer = pretty_printer
96
97
 
@@ -251,11 +252,6 @@ class PythonPrettyPrinter(ModelVisitor):
251
252
  self._level -= 1
252
253
  return variables_str
253
254
 
254
- def visit_QuantumVariableDeclaration(
255
- self, var_decl: QuantumVariableDeclaration
256
- ) -> str:
257
- return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
258
-
259
255
  def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
260
256
  var_type = self._extract_port_type(port_decl)
261
257
  return f"{port_decl.name}: {var_type}"
@@ -361,14 +357,23 @@ class PythonPrettyPrinter(ModelVisitor):
361
357
  self._imports[type_.name] = 1
362
358
 
363
359
  def visit_VariableDeclarationStatement(
364
- self, local_decl: VariableDeclarationStatement
360
+ self,
361
+ local_decl: VariableDeclarationStatement,
362
+ walrus: bool = False,
365
363
  ) -> str:
366
364
  type_name, params = VariableDeclarationAssignment(self).visit(
367
- local_decl.quantum_type
365
+ local_decl.qmod_type
368
366
  )
369
367
  params = [f'"{local_decl.name}"'] + params
370
368
  param_args = ", ".join(params)
371
- return f"{self._indent}{self.visit_QuantumVariableDeclaration(local_decl)} = {type_name}({param_args})\n"
369
+
370
+ res = f"{self._indent}{local_decl.name}"
371
+ if walrus:
372
+ res += " := "
373
+ else:
374
+ res += f": {self.visit(local_decl.qmod_type)} = "
375
+ res += f"{type_name}({param_args})\n"
376
+ return res
372
377
 
373
378
  def _visit_operand_arg_decl(self, arg_decl: AnonPositionalArg) -> str:
374
379
  if isinstance(arg_decl, AnonPortDeclaration):
@@ -476,6 +481,10 @@ class PythonPrettyPrinter(ModelVisitor):
476
481
  self._imports["invert"] = 1
477
482
  return f"{self._indent}invert({self._visit_body(invert.body)})\n"
478
483
 
484
+ def visit_Block(self, block: Block) -> str:
485
+ self._imports["block"] = 1
486
+ return f"{self._indent}block({self._visit_body(block.statements)})\n"
487
+
479
488
  def _visit_body(
480
489
  self, body: StatementBlock, operand_arguments: Optional[list[str]] = None
481
490
  ) -> str:
@@ -488,10 +497,8 @@ class PythonPrettyPrinter(ModelVisitor):
488
497
  self._level += 1
489
498
  for i, statement in enumerate(body):
490
499
  if isinstance(statement, VariableDeclarationStatement):
491
- raise AssertionError(
492
- "pretty printing variable declaration statements in quantum lambda function is unsupported."
493
- )
494
- if isinstance(statement, AmplitudeLoadingOperation):
500
+ code += self.visit_VariableDeclarationStatement(statement, walrus=True)
501
+ elif isinstance(statement, AmplitudeLoadingOperation):
495
502
  code += self.visit_AmplitudeLoadingOperation(statement, in_lambda=True)
496
503
  elif isinstance(statement, ArithmeticOperation):
497
504
  code += self.visit_ArithmeticOperation(statement, in_lambda=True)
@@ -574,6 +581,18 @@ class PythonPrettyPrinter(ModelVisitor):
574
581
  def visit_OperandIdentifier(self, op: OperandIdentifier) -> str:
575
582
  return str(op)
576
583
 
584
+ def visit_SetBoundsStatement(self, op: SetBoundsStatement) -> str:
585
+ self._imports["reset_bounds"] = 1
586
+ target = self.visit(op.target)
587
+ if op.lower_bound is None or op.upper_bound is None:
588
+ return f"{self._indent}reset_bounds({target})\n"
589
+ else:
590
+ lower_bound = self.visit(op.lower_bound)
591
+ upper_bound = self.visit(op.upper_bound)
592
+ return (
593
+ f"{self._indent}reset_bounds({target}, {lower_bound}, {upper_bound})\n"
594
+ )
595
+
577
596
  @property
578
597
  def _indent(self) -> str:
579
598
  return " " * self._level
classiq/qmod/qfunc.py CHANGED
@@ -1,7 +1,6 @@
1
- import warnings
2
1
  from typing import Callable, Literal, Optional, Union, overload
3
2
 
4
- from classiq.interface.exceptions import ClassiqDeprecationWarning, ClassiqInternalError
3
+ from classiq.interface.exceptions import ClassiqInternalError
5
4
 
6
5
  from classiq.qmod.global_declarative_switch import get_global_declarative_switch
7
6
  from classiq.qmod.quantum_callable import QCallable
@@ -57,23 +56,7 @@ def qfunc(
57
56
  synthesize_separately: bool = False,
58
57
  unchecked: Optional[list[str]] = None,
59
58
  ) -> Union[Callable[[Callable], QCallable], QCallable]:
60
- if generative is True:
61
- warnings.warn(
62
- "The use of `generative=True` is no longer required. Note that the "
63
- "treatment of parameters of Qmod types will change from Python value to "
64
- "symbolic in a near release. Change Qmod types to the corresponding Python "
65
- "built-in types in order to use the parameters in Python expression "
66
- "contexts.\n"
67
- "Recommended changes:\n"
68
- "@qfunc(generative=True) -> @qfunc\n"
69
- "CInt->int\n"
70
- "CReal->float\n"
71
- "CArray->list\n\n"
72
- "For more information see https://docs.classiq.io/latest/qmod-reference/language-reference/generative-descriptions/",
73
- ClassiqDeprecationWarning,
74
- stacklevel=2,
75
- )
76
- elif generative is None:
59
+ if generative is None:
77
60
  generative = True
78
61
  if get_global_declarative_switch():
79
62
  generative = False
@@ -74,7 +74,7 @@ from classiq.qmod.quantum_callable import QCallable
74
74
  from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
75
75
  from classiq.qmod.semantics.validation.types_validation import validate_qstruct
76
76
  from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
77
- from classiq.qmod.symbolic_type import SymbolicTypes
77
+ from classiq.qmod.symbolic_type import SYMBOLIC_TYPES, SymbolicTypes
78
78
  from classiq.qmod.utilities import (
79
79
  get_source_ref,
80
80
  unwrap_forward_ref,
@@ -104,9 +104,6 @@ def _infer_variable_name(name: Any, depth: int) -> Any:
104
104
  return name
105
105
 
106
106
 
107
- _SYMBOLIC_TYPES = tuple(get_origin(t) or t for t in get_args(SymbolicTypes))
108
-
109
-
110
107
  class QVar(Symbolic):
111
108
  CONSTRUCTOR_DEPTH: int = 1
112
109
 
@@ -230,7 +227,7 @@ class QScalar(QVar, SymbolicExpr):
230
227
  )
231
228
 
232
229
  def __ior__(self, other: Any) -> Self:
233
- if not isinstance(other, _SYMBOLIC_TYPES):
230
+ if not isinstance(other, SYMBOLIC_TYPES):
234
231
  raise TypeError(
235
232
  f"Invalid argument {other!r} for out-of-place arithmetic operation"
236
233
  )
@@ -241,7 +238,7 @@ class QScalar(QVar, SymbolicExpr):
241
238
  return self
242
239
 
243
240
  def __ixor__(self, other: Any) -> Self:
244
- if not isinstance(other, _SYMBOLIC_TYPES):
241
+ if not isinstance(other, SYMBOLIC_TYPES):
245
242
  raise TypeError(
246
243
  f"Invalid argument {other!r} for in-place arithmetic operation"
247
244
  )
@@ -252,7 +249,7 @@ class QScalar(QVar, SymbolicExpr):
252
249
  return self
253
250
 
254
251
  def __iadd__(self, other: Any) -> Self:
255
- if not isinstance(other, _SYMBOLIC_TYPES):
252
+ if not isinstance(other, SYMBOLIC_TYPES):
256
253
  raise TypeError(
257
254
  f"Invalid argument {other!r} for in-place arithmetic operation"
258
255
  )
@@ -263,7 +260,7 @@ class QScalar(QVar, SymbolicExpr):
263
260
  return self
264
261
 
265
262
  def __imul__(self, other: Any) -> Self:
266
- if not isinstance(other, _SYMBOLIC_TYPES):
263
+ if not isinstance(other, SYMBOLIC_TYPES):
267
264
  raise TypeError(
268
265
  f"Invalid argument {other!r} for out of ampltiude encoding operation"
269
266
  )
@@ -135,7 +135,7 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
135
135
  ) -> None:
136
136
  self.append_statement_to_body(
137
137
  VariableDeclarationStatement(
138
- name=name, quantum_type=qtype, source_ref=source_ref
138
+ name=name, qmod_type=qtype, source_ref=source_ref
139
139
  )
140
140
  )
141
141
 
@@ -1,12 +1,13 @@
1
1
  import ast
2
2
  import functools
3
+ import warnings
3
4
  from abc import abstractmethod
4
5
  from dataclasses import is_dataclass
5
6
  from enum import EnumMeta
6
7
  from inspect import isclass
7
8
  from typing import Any, Callable, Optional, get_origin
8
9
 
9
- from classiq.interface.exceptions import ClassiqError
10
+ from classiq.interface.exceptions import ClassiqDeprecationWarning, ClassiqError
10
11
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
11
12
  from classiq.interface.generator.functions.port_declaration import (
12
13
  PortDeclarationDirection,
@@ -28,7 +29,7 @@ from classiq.qmod.declaration_inferrer import infer_func_decl, is_qvar
28
29
  from classiq.qmod.generative import set_frontend_interpreter
29
30
  from classiq.qmod.global_declarative_switch import get_global_declarative_switch
30
31
  from classiq.qmod.qmod_constant import QConstant
31
- from classiq.qmod.qmod_parameter import CArray
32
+ from classiq.qmod.qmod_parameter import CArray, CParamList
32
33
  from classiq.qmod.quantum_callable import QCallable, QCallableList
33
34
  from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
34
35
  from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
@@ -218,6 +219,7 @@ class QFunc(BaseQFunc):
218
219
 
219
220
 
220
221
  class ExternalQFunc(QTerminalCallable):
222
+ FRAME_DEPTH = 2 # FIXME: Remove (CLS-2912)
221
223
  _decl: NamedParamsQuantumFunctionDeclaration
222
224
 
223
225
  def __init__(self, py_callable: Callable) -> None:
@@ -242,6 +244,44 @@ class ExternalQFunc(QTerminalCallable):
242
244
  def pure_decl(self) -> NamedParamsQuantumFunctionDeclaration:
243
245
  return self.func_decl
244
246
 
247
+ def __call__(self, *args: Any, **kwargs: Any) -> None:
248
+ if self._py_callable.__name__ == "parametric_suzuki_trotter":
249
+ warnings.warn(
250
+ (
251
+ "Function 'parametric_suzuki_trotter' is deprecated and will no "
252
+ "longer be supported starting on 21/7/2025 at the earliest. "
253
+ "Instead, use 'multi_suzuki_trotter'."
254
+ ),
255
+ ClassiqDeprecationWarning,
256
+ stacklevel=2,
257
+ )
258
+ if self._py_callable.__name__ == "sparse_suzuki_trotter":
259
+ warnings.warn(
260
+ (
261
+ "Function 'sparse_suzuki_trotter' is deprecated and will no "
262
+ "longer be supported starting on 21/7/2025 at the earliest. "
263
+ "Instead, use 'suzuki_trotter'."
264
+ ),
265
+ ClassiqDeprecationWarning,
266
+ stacklevel=2,
267
+ )
268
+ if (
269
+ self._py_callable.__name__ == "suzuki_trotter"
270
+ and len(args) > 0
271
+ and isinstance(args[0], (list, CParamList))
272
+ ):
273
+ warnings.warn(
274
+ (
275
+ "Parameter type CArray[PauliTerm] to function 'suzuki_trotter' is "
276
+ "deprecated and will no longer be supported starting on 21/7/2025 "
277
+ "at the earliest. Instead, send a 'SparsePauliOp' (see "
278
+ "https://docs.classiq.io/latest/qmod-reference/language-reference/classical-types/#hamiltonians)."
279
+ ),
280
+ ClassiqDeprecationWarning,
281
+ stacklevel=2,
282
+ )
283
+ super().__call__(*args, **kwargs)
284
+
245
285
 
246
286
  class GenerativeQFunc(BaseQFunc):
247
287
  FRAME_DEPTH = 3