classiq 0.43.2__py3-none-any.whl → 0.44.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 (112) hide show
  1. classiq/__init__.py +7 -1
  2. classiq/_internals/client.py +4 -7
  3. classiq/_internals/host_checker.py +34 -12
  4. classiq/_internals/jobs.py +2 -2
  5. classiq/applications/chemistry/chemistry_model_constructor.py +12 -6
  6. classiq/applications/combinatorial_helpers/allowed_constraints.py +4 -1
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  8. classiq/applications/finance/finance_model_constructor.py +3 -2
  9. classiq/applications/grover/grover_model_constructor.py +7 -5
  10. classiq/applications/hamiltonian/__init__.py +0 -0
  11. classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
  12. classiq/applications/qnn/qlayer.py +1 -1
  13. classiq/exceptions.py +4 -0
  14. classiq/interface/_version.py +1 -1
  15. classiq/interface/ast_node.py +1 -18
  16. classiq/interface/backend/backend_preferences.py +15 -16
  17. classiq/interface/backend/ionq/ionq_quantum_program.py +1 -1
  18. classiq/interface/backend/pydantic_backend.py +0 -5
  19. classiq/interface/backend/quantum_backend_providers.py +3 -2
  20. classiq/interface/chemistry/operator.py +5 -1
  21. classiq/interface/debug_info/__init__.py +0 -0
  22. classiq/interface/debug_info/debug_info.py +32 -0
  23. classiq/interface/executor/execution_preferences.py +1 -45
  24. classiq/interface/executor/result.py +25 -12
  25. classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
  26. classiq/interface/generator/application_apis/chemistry_declarations.py +78 -60
  27. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +19 -10
  28. classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
  29. classiq/interface/generator/application_apis/finance_declarations.py +36 -22
  30. classiq/interface/generator/application_apis/qsvm_declarations.py +21 -15
  31. classiq/interface/generator/arith/arithmetic_expression_abc.py +21 -1
  32. classiq/interface/generator/arith/binary_ops.py +5 -4
  33. classiq/interface/generator/arith/extremum_operations.py +43 -19
  34. classiq/interface/generator/constant.py +1 -1
  35. classiq/interface/generator/expressions/atomic_expression_functions.py +1 -0
  36. classiq/interface/generator/expressions/expression_constants.py +3 -1
  37. classiq/interface/generator/expressions/qmod_qarray_proxy.py +52 -66
  38. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +35 -0
  39. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  40. classiq/interface/generator/functions/builtins/core_library/__init__.py +4 -2
  41. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +41 -41
  42. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +52 -42
  43. classiq/interface/generator/functions/builtins/open_lib_functions.py +1095 -3347
  44. classiq/interface/generator/functions/builtins/quantum_operators.py +9 -22
  45. classiq/interface/generator/functions/classical_function_declaration.py +14 -6
  46. classiq/interface/generator/functions/classical_type.py +7 -76
  47. classiq/interface/generator/functions/concrete_types.py +55 -0
  48. classiq/interface/generator/functions/function_declaration.py +10 -10
  49. classiq/interface/generator/functions/type_name.py +104 -0
  50. classiq/interface/generator/generated_circuit_data.py +3 -3
  51. classiq/interface/generator/model/model.py +11 -0
  52. classiq/interface/generator/model/preferences/preferences.py +5 -0
  53. classiq/interface/generator/quantum_function_call.py +3 -0
  54. classiq/interface/generator/quantum_program.py +2 -2
  55. classiq/interface/generator/register_role.py +7 -1
  56. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +1 -3
  57. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +1 -2
  58. classiq/interface/generator/types/qstruct_declaration.py +17 -0
  59. classiq/interface/generator/types/struct_declaration.py +1 -1
  60. classiq/interface/helpers/validation_helpers.py +1 -17
  61. classiq/interface/ide/visual_model.py +9 -2
  62. classiq/interface/interface_version.py +1 -0
  63. classiq/interface/model/bind_operation.py +25 -5
  64. classiq/interface/model/classical_parameter_declaration.py +8 -5
  65. classiq/interface/model/control.py +5 -5
  66. classiq/interface/model/handle_binding.py +185 -12
  67. classiq/interface/model/inplace_binary_operation.py +16 -4
  68. classiq/interface/model/model.py +28 -5
  69. classiq/interface/model/native_function_definition.py +8 -4
  70. classiq/interface/model/parameter.py +14 -0
  71. classiq/interface/model/port_declaration.py +20 -2
  72. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +21 -6
  73. classiq/interface/model/quantum_expressions/arithmetic_operation.py +30 -6
  74. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -9
  75. classiq/interface/model/quantum_function_call.py +135 -192
  76. classiq/interface/model/quantum_function_declaration.py +147 -165
  77. classiq/interface/model/quantum_lambda_function.py +24 -6
  78. classiq/interface/model/quantum_statement.py +34 -8
  79. classiq/interface/model/quantum_type.py +61 -10
  80. classiq/interface/model/quantum_variable_declaration.py +1 -1
  81. classiq/interface/model/statement_block.py +2 -0
  82. classiq/interface/model/validation_handle.py +7 -0
  83. classiq/interface/server/global_versions.py +4 -4
  84. classiq/interface/server/routes.py +2 -0
  85. classiq/interface/source_reference.py +59 -0
  86. classiq/qmod/__init__.py +2 -3
  87. classiq/qmod/builtins/functions.py +39 -11
  88. classiq/qmod/builtins/operations.py +171 -40
  89. classiq/qmod/declaration_inferrer.py +99 -56
  90. classiq/qmod/expression_query.py +1 -1
  91. classiq/qmod/model_state_container.py +2 -0
  92. classiq/qmod/native/pretty_printer.py +71 -53
  93. classiq/qmod/pretty_print/pretty_printer.py +98 -52
  94. classiq/qmod/qfunc.py +11 -5
  95. classiq/qmod/qmod_parameter.py +1 -2
  96. classiq/qmod/qmod_variable.py +364 -172
  97. classiq/qmod/quantum_callable.py +3 -3
  98. classiq/qmod/quantum_expandable.py +119 -65
  99. classiq/qmod/quantum_function.py +15 -3
  100. classiq/qmod/semantics/annotation.py +12 -13
  101. classiq/qmod/semantics/error_manager.py +36 -10
  102. classiq/qmod/semantics/static_semantics_visitor.py +163 -75
  103. classiq/qmod/semantics/validation/func_call_validation.py +42 -96
  104. classiq/qmod/semantics/validation/handle_validation.py +85 -0
  105. classiq/qmod/semantics/validation/types_validation.py +108 -1
  106. classiq/qmod/type_attribute_remover.py +32 -0
  107. classiq/qmod/utilities.py +26 -5
  108. {classiq-0.43.2.dist-info → classiq-0.44.0.dist-info}/METADATA +3 -3
  109. {classiq-0.43.2.dist-info → classiq-0.44.0.dist-info}/RECORD +111 -99
  110. classiq/qmod/qmod_struct.py +0 -13
  111. /classiq/{interface/ide/show.py → show.py} +0 -0
  112. {classiq-0.43.2.dist-info → classiq-0.44.0.dist-info}/WHEEL +0 -0
@@ -1,13 +1,13 @@
1
- from datetime import datetime
2
- from typing import Any, Dict
1
+ from datetime import date, datetime
2
+ from typing import Any, Dict, Union
3
3
 
4
4
  import pydantic
5
5
  from pydantic import BaseModel
6
6
 
7
7
 
8
8
  class DeprecationInfo(BaseModel):
9
- deprecation_date: datetime = pydantic.Field()
10
- removal_date: datetime = pydantic.Field()
9
+ deprecation_date: Union[date, datetime] = pydantic.Field()
10
+ removal_date: Union[date, datetime] = pydantic.Field()
11
11
 
12
12
 
13
13
  class GlobalVersions(BaseModel):
@@ -72,3 +72,5 @@ CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_SUFFIX = "/execution_input"
72
72
  CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_FULL = (
73
73
  CONVERSION_PREFIX + CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_SUFFIX
74
74
  )
75
+
76
+ STATIC_SEMANTICS_VALIDATION_PATH = "/validate_static_semantics"
@@ -0,0 +1,59 @@
1
+ import os
2
+ import re
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ import pydantic
7
+
8
+ from classiq.interface.helpers.hashable_pydantic_base_model import (
9
+ HashablePydanticBaseModel,
10
+ )
11
+
12
+
13
+ def _identify_ipynb_cell(file_name: str) -> bool:
14
+ file_path = Path(file_name)
15
+ base_file = file_path.name
16
+ if re.fullmatch(r"\d*\.py", base_file) is None:
17
+ return False
18
+ parent_folder = file_path.parent
19
+ return re.fullmatch(r"ipykernel_\d*", parent_folder.name) is not None
20
+
21
+
22
+ def _prepare_file_string(file_name: str) -> str:
23
+ if _identify_ipynb_cell(file_name):
24
+ return "ipynb cell "
25
+ return f"file {os.path.basename(file_name)} "
26
+
27
+
28
+ class SourceReference(HashablePydanticBaseModel):
29
+ start_line: int
30
+ start_column: int
31
+ end_line: int
32
+ end_column: int
33
+ file_name: Optional[str] = pydantic.Field(default=None)
34
+
35
+ def __str__(self) -> str:
36
+ file_string = _prepare_file_string(self.file_name) if self.file_name else ""
37
+ start_character_string = (
38
+ f" character {self.start_column + 1}" if self.start_column > 0 else ""
39
+ )
40
+ return f"{file_string}line {self.start_line + 1}{start_character_string}"
41
+
42
+
43
+ class SourceReferencedError(pydantic.BaseModel):
44
+ error: str
45
+ source_ref: Optional[SourceReference] = None
46
+ function: Optional[str] = None
47
+
48
+ def __str__(self) -> str:
49
+ source_referenced_error = (
50
+ f"{self.error}\n\t\tat {self.source_ref}"
51
+ if self.source_ref is not None
52
+ else self.error
53
+ )
54
+ function_scoped_error = (
55
+ f"{source_referenced_error} in function {self.function}"
56
+ if self.function is not None
57
+ else source_referenced_error
58
+ )
59
+ return function_scoped_error
classiq/qmod/__init__.py CHANGED
@@ -6,8 +6,7 @@ from .expression_query import get_expression_numeric_attributes
6
6
  from .qfunc import qfunc
7
7
  from .qmod_constant import QConstant
8
8
  from .qmod_parameter import Array, CArray, CBool, CInt, CReal
9
- from .qmod_struct import struct
10
- from .qmod_variable import Input, Output, QArray, QBit, QNum
9
+ from .qmod_variable import Input, Output, QArray, QBit, QNum, QStruct
11
10
  from .quantum_callable import QCallable, QCallableList
12
11
  from .quantum_function import create_model
13
12
  from .write_qmod import write_qmod
@@ -26,11 +25,11 @@ __all__ = [
26
25
  "QCallable",
27
26
  "QCallableList",
28
27
  "QConstant",
28
+ "QStruct",
29
29
  "cfunc",
30
30
  "create_model",
31
31
  "get_expression_numeric_attributes",
32
32
  "qfunc",
33
- "struct",
34
33
  "symbolic",
35
34
  "write_qmod",
36
35
  ] + _builtins_all
@@ -473,13 +473,6 @@ def exponentiation_with_depth_constraint(
473
473
  pass
474
474
 
475
475
 
476
- @qfunc(external=True)
477
- def qft(
478
- target: QArray[QBit],
479
- ) -> None:
480
- pass
481
-
482
-
483
476
  @qfunc(external=True)
484
477
  def qpe_flexible(
485
478
  unitary_with_power: QCallable[CInt],
@@ -624,7 +617,6 @@ def cc_modular_add(
624
617
  phi_b: QArray[QBit],
625
618
  c1: QBit,
626
619
  c2: QBit,
627
- aux: QBit,
628
620
  ) -> None:
629
621
  pass
630
622
 
@@ -636,7 +628,6 @@ def c_modular_multiply(
636
628
  b: QArray[QBit],
637
629
  x: QArray[QBit],
638
630
  ctrl: QBit,
639
- aux: QBit,
640
631
  ) -> None:
641
632
  pass
642
633
 
@@ -655,7 +646,6 @@ def inplace_c_modular_multiply(
655
646
  a: CInt,
656
647
  x: QArray[QBit],
657
648
  ctrl: QBit,
658
- aux: QBit,
659
649
  ) -> None:
660
650
  pass
661
651
 
@@ -793,6 +783,34 @@ def swap_test(
793
783
  pass
794
784
 
795
785
 
786
+ @qfunc(external=True)
787
+ def _prepare_uniform_trimmed_state_step(
788
+ size_lsb: CInt,
789
+ ctrl_val: CInt,
790
+ lsbs_val: CInt,
791
+ ctrl_var: QNum,
792
+ rotation_var: QBit,
793
+ ) -> None:
794
+ pass
795
+
796
+
797
+ @qfunc(external=True)
798
+ def prepare_uniform_trimmed_state(
799
+ m: CInt,
800
+ q: QArray[QBit],
801
+ ) -> None:
802
+ pass
803
+
804
+
805
+ @qfunc(external=True)
806
+ def prepare_uniform_interval_state(
807
+ start: CInt,
808
+ end: CInt,
809
+ q: QArray[QBit],
810
+ ) -> None:
811
+ pass
812
+
813
+
796
814
  @qfunc(external=True)
797
815
  def prepare_ghz_state(
798
816
  size: CInt,
@@ -894,6 +912,13 @@ def modular_increment(
894
912
  pass
895
913
 
896
914
 
915
+ @qfunc(external=True)
916
+ def qft(
917
+ target: QArray[QBit],
918
+ ) -> None:
919
+ pass
920
+
921
+
897
922
  __all__ = [
898
923
  "permute",
899
924
  "apply",
@@ -951,7 +976,6 @@ __all__ = [
951
976
  "suzuki_trotter",
952
977
  "qdrift",
953
978
  "exponentiation_with_depth_constraint",
954
- "qft",
955
979
  "qpe_flexible",
956
980
  "qpe",
957
981
  "single_pauli",
@@ -985,6 +1009,9 @@ __all__ = [
985
1009
  "qaoa_penalty",
986
1010
  "full_hea",
987
1011
  "swap_test",
1012
+ "_prepare_uniform_trimmed_state_step",
1013
+ "prepare_uniform_trimmed_state",
1014
+ "prepare_uniform_interval_state",
988
1015
  "prepare_ghz_state",
989
1016
  "prepare_exponential_state",
990
1017
  "prepare_bell_state",
@@ -998,4 +1025,5 @@ __all__ = [
998
1025
  "qct_type2",
999
1026
  "qst_type2",
1000
1027
  "modular_increment",
1028
+ "qft",
1001
1029
  ]
@@ -1,14 +1,29 @@
1
1
  import inspect
2
2
  import sys
3
+ import warnings
3
4
  from types import FrameType
4
- from typing import Any, Callable, Final, List, Mapping, Union, overload
5
+ from typing import (
6
+ TYPE_CHECKING,
7
+ Any,
8
+ Callable,
9
+ Final,
10
+ List,
11
+ Mapping,
12
+ Optional,
13
+ Union,
14
+ overload,
15
+ )
5
16
 
6
17
  from classiq.interface.generator.expressions.expression import Expression
7
18
  from classiq.interface.generator.functions.builtins.internal_operators import (
8
19
  REPEAT_OPERATOR_NAME,
9
20
  )
21
+ from classiq.interface.generator.functions.classical_type import Integer
10
22
  from classiq.interface.model.bind_operation import BindOperation
11
23
  from classiq.interface.model.classical_if import ClassicalIf
24
+ from classiq.interface.model.classical_parameter_declaration import (
25
+ ClassicalParameterDeclaration,
26
+ )
12
27
  from classiq.interface.model.control import Control
13
28
  from classiq.interface.model.inplace_binary_operation import (
14
29
  BinaryOperation,
@@ -25,7 +40,6 @@ from classiq.interface.model.repeat import Repeat
25
40
  from classiq.interface.model.statement_block import StatementBlock
26
41
  from classiq.interface.model.within_apply_operation import WithinApply
27
42
 
28
- from classiq import Integer
29
43
  from classiq.exceptions import ClassiqValueError
30
44
  from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QNum, QVar
31
45
  from classiq.qmod.quantum_callable import QCallable
@@ -68,36 +82,51 @@ def if_(
68
82
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
69
83
  ClassicalIf(
70
84
  condition=Expression(expr=str(condition)),
71
- then=_operand_to_body(then),
72
- else_=_operand_to_body(else_) if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
85
+ then=_operand_to_body(then, "then"),
86
+ else_=_operand_to_body(else_, "else") if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
73
87
  source_ref=source_ref,
74
88
  )
75
89
  )
76
90
 
77
91
 
78
- @overload
92
+ @overload # FIXME: Remove overloading (CAD-21932)
79
93
  def control(
80
- ctrl: Union[QBit, QArray[QBit]], operand: Union[QCallable, Callable[[], None]]
94
+ ctrl: Union[QBit, QArray[QBit]], stmt_block: Union[QCallable, Callable[[], None]]
81
95
  ) -> None:
82
96
  pass
83
97
 
84
98
 
85
99
  @overload
86
- def control(ctrl: SymbolicExpr, operand: Union[QCallable, Callable[[], None]]) -> None:
100
+ def control(
101
+ ctrl: SymbolicExpr, stmt_block: Union[QCallable, Callable[[], None]]
102
+ ) -> None:
87
103
  pass
88
104
 
89
105
 
90
106
  def control(
91
107
  ctrl: Union[SymbolicExpr, QBit, QArray[QBit]],
92
- operand: Union[QCallable, Callable[[], None]],
108
+ stmt_block: Optional[Union[QCallable, Callable[[], None]]] = None,
109
+ operand: Optional[Union[QCallable, Callable[[], None]]] = None,
93
110
  ) -> None:
94
- _validate_operand(operand)
111
+ if operand is not None:
112
+ warnings.warn(
113
+ "Parameter 'operand' of function 'control' has been renamed to "
114
+ "'stmt_block'. Parameter 'operand' will be deprecated in a future "
115
+ "release.\nHint: Change `control(ctrl=..., operand=...)` to "
116
+ "`control(ctrl=..., stmt_block=...)` or `control(..., ...)`.",
117
+ category=DeprecationWarning,
118
+ stacklevel=2,
119
+ )
120
+ stmt_block = operand
121
+ if TYPE_CHECKING:
122
+ assert stmt_block is not None
123
+ _validate_operand(stmt_block)
95
124
  assert QCallable.CURRENT_EXPANDABLE is not None
96
125
  source_ref = get_source_ref(sys._getframe(1))
97
126
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
98
127
  Control(
99
128
  expression=Expression(expr=str(ctrl)),
100
- body=_operand_to_body(operand),
129
+ body=_operand_to_body(stmt_block, "stmt_block"),
101
130
  source_ref=source_ref,
102
131
  )
103
132
  )
@@ -135,18 +164,53 @@ def inplace_xor(
135
164
  )
136
165
 
137
166
 
167
+ @overload # FIXME: Remove overloading (CAD-21932)
138
168
  def within_apply(
139
- compute: Callable[[], None],
140
- action: Callable[[], None],
169
+ within: Callable[[], None],
170
+ apply: Callable[[], None],
141
171
  ) -> None:
142
- _validate_operand(compute)
143
- _validate_operand(action)
172
+ pass
173
+
174
+
175
+ @overload
176
+ def within_apply(
177
+ within: Callable[[], List[None]],
178
+ apply: Callable[[], List[None]],
179
+ ) -> None:
180
+ pass
181
+
182
+
183
+ def within_apply( # type:ignore[misc]
184
+ within: Optional[Callable[[], None]] = None,
185
+ apply: Optional[Callable[[], None]] = None,
186
+ compute: Optional[Callable[[], None]] = None,
187
+ action: Optional[Callable[[], None]] = None,
188
+ ) -> None:
189
+ if compute is not None or action is not None:
190
+ warnings.warn(
191
+ "Parameters 'compute' and 'action' of function 'within_apply' have "
192
+ "been renamed to 'within' and 'apply' respectively. Parameters 'compute' "
193
+ "and 'action' will be deprecated in a future release.\nHint: Change "
194
+ "`within_apply(compute=..., action=...)` to "
195
+ "`within_apply(within=..., apply=...)` or `within_apply(..., ...)`.",
196
+ category=DeprecationWarning,
197
+ stacklevel=2,
198
+ )
199
+ if compute is not None:
200
+ within = compute
201
+ if action is not None:
202
+ apply = action
203
+ if TYPE_CHECKING:
204
+ assert within is not None
205
+ assert apply is not None
206
+ _validate_operand(within)
207
+ _validate_operand(apply)
144
208
  assert QCallable.CURRENT_EXPANDABLE is not None
145
209
  source_ref = get_source_ref(sys._getframe(1))
146
210
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
147
211
  WithinApply(
148
- compute=_operand_to_body(compute),
149
- action=_operand_to_body(action),
212
+ compute=_operand_to_body(within, "within"),
213
+ action=_operand_to_body(apply, "apply"),
150
214
  source_ref=source_ref,
151
215
  )
152
216
  )
@@ -158,13 +222,20 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
158
222
  source_ref = get_source_ref(sys._getframe(1))
159
223
  iteration_operand = prepare_arg(
160
224
  QuantumOperandDeclaration(
161
- name=REPEAT_OPERATOR_NAME, param_decls={"index": Integer()}
225
+ name=REPEAT_OPERATOR_NAME,
226
+ positional_arg_declarations=[
227
+ ClassicalParameterDeclaration(name="index", classical_type=Integer()),
228
+ ],
162
229
  ),
163
230
  iteration,
164
231
  repeat.__name__,
232
+ "iteration",
165
233
  )
166
234
  if not isinstance(iteration_operand, QuantumLambdaFunction):
167
- raise ClassiqValueError("`repeat`'s `iteration` argument must be a callable.")
235
+ raise ClassiqValueError(
236
+ "Argument 'iteration' to 'repeat' should be a callable that takes one integer argument."
237
+ )
238
+
168
239
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
169
240
  Repeat(
170
241
  iter_var=inspect.getfullargspec(iteration).args[0],
@@ -175,35 +246,93 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
175
246
  )
176
247
 
177
248
 
249
+ @overload # FIXME: Remove overloading (CAD-21932)
178
250
  def power(
179
- power: Union[SymbolicExpr, int],
180
- operand: Union[QCallable, Callable[[], None]],
251
+ exponent: SymbolicExpr,
252
+ stmt_block: Union[QCallable, Callable[[], None]],
181
253
  ) -> None:
182
- _validate_operand(operand)
254
+ pass
255
+
256
+
257
+ @overload
258
+ def power(
259
+ exponent: int,
260
+ stmt_block: Union[QCallable, Callable[[], None]],
261
+ ) -> None:
262
+ pass
263
+
264
+
265
+ def power(
266
+ exponent: Optional[Union[SymbolicExpr, int]] = None,
267
+ stmt_block: Optional[Union[QCallable, Callable[[], None]]] = None,
268
+ power: Optional[Union[SymbolicExpr, int]] = None,
269
+ operand: Optional[Union[QCallable, Callable[[], None]]] = None,
270
+ ) -> None:
271
+ if power is not None or operand is not None:
272
+ warnings.warn(
273
+ "Parameters 'exponent' and 'operand' of function 'power' have been "
274
+ "renamed to 'exponent' and 'stmt_block' respectively. Parameters "
275
+ "'exponent' and 'operand' will be deprecated in a future release.\nHint: "
276
+ "Change `power(power=..., operand=...)` to "
277
+ "`power(exponent=..., stmt_block=...)` or `power(..., ...)`.",
278
+ category=DeprecationWarning,
279
+ stacklevel=2,
280
+ )
281
+ if power is not None:
282
+ exponent = power
283
+ if operand is not None:
284
+ stmt_block = operand
285
+ if TYPE_CHECKING:
286
+ assert exponent is not None
287
+ assert stmt_block is not None
288
+ _validate_operand(stmt_block)
183
289
  assert QCallable.CURRENT_EXPANDABLE is not None
184
290
  source_ref = get_source_ref(sys._getframe(1))
185
291
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
186
292
  Power(
187
- power=Expression(expr=str(power)),
188
- body=_operand_to_body(operand),
293
+ power=Expression(expr=str(exponent)),
294
+ body=_operand_to_body(stmt_block, "stmt_block"),
189
295
  source_ref=source_ref,
190
296
  )
191
297
  )
192
298
 
193
299
 
300
+ @overload # FIXME: Remove overloading (CAD-21932)
301
+ def invert(stmt_block: QCallable) -> None:
302
+ pass
303
+
304
+
305
+ @overload
306
+ def invert(stmt_block: Callable[[], None]) -> None:
307
+ pass
308
+
309
+
194
310
  def invert(
195
- operand: Union[QCallable, Callable[[], None]],
311
+ stmt_block: Optional[Union[QCallable, Callable[[], None]]] = None,
312
+ operand: Optional[Union[QCallable, Callable[[], None]]] = None,
196
313
  ) -> None:
197
- _validate_operand(operand)
314
+ if operand is not None:
315
+ warnings.warn(
316
+ "Parameter 'operand' of function 'invert' has been renamed to "
317
+ "'stmt_block'. Parameter 'operand' will be deprecated in a future "
318
+ "release.\nHint: Change `invert(operand=...)` to `invert(stmt_block=...)` "
319
+ "or `invert(...)`.",
320
+ category=DeprecationWarning,
321
+ stacklevel=2,
322
+ )
323
+ stmt_block = operand
324
+ if TYPE_CHECKING:
325
+ assert stmt_block is not None
326
+ _validate_operand(stmt_block)
198
327
  assert QCallable.CURRENT_EXPANDABLE is not None
199
328
  source_ref = get_source_ref(sys._getframe(1))
200
329
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
201
- Invert(body=_operand_to_body(operand), source_ref=source_ref)
330
+ Invert(body=_operand_to_body(stmt_block, "stmt_block"), source_ref=source_ref)
202
331
  )
203
332
 
204
333
 
205
- def _validate_operand(operand: Any) -> None:
206
- if operand is not None:
334
+ def _validate_operand(stmt_block: Any) -> None:
335
+ if stmt_block is not None:
207
336
  return
208
337
  currentframe: FrameType = inspect.currentframe() # type: ignore[assignment]
209
338
  operation_frame: FrameType = currentframe.f_back # type: ignore[assignment]
@@ -215,7 +344,7 @@ def _validate_operand(operand: Any) -> None:
215
344
  operand_arg_name = context[0].split("_validate_operand(")[1].split(")")[0]
216
345
 
217
346
  error_message = (
218
- f"{operation_name} is missing required argument for {operand_arg_name}"
347
+ f"{operation_name!r} is missing required argument for {operand_arg_name!r}."
219
348
  )
220
349
  error_message += _get_operand_hint(
221
350
  operation_name=operation_name,
@@ -236,6 +365,7 @@ def _get_operand_hint_args(
236
365
  else f"{param.name}=..."
237
366
  )
238
367
  for param in params.values()
368
+ if param.name != "operand" # FIXME: Remove compatibility (CAD-21932)
239
369
  ]
240
370
  )
241
371
 
@@ -244,27 +374,28 @@ def _get_operand_hint(
244
374
  operation_name: str, operand_arg_name: str, params: Mapping[str, inspect.Parameter]
245
375
  ) -> str:
246
376
  return (
247
- f"\nHint: To create an operand, do not call quantum gates directly "
248
- f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'H(q)')})`. "
249
- f"Instead, use a lambda function "
250
- f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'lambda: H(q)')})` "
251
- f"or a quantum function "
252
- f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'my_func')})`"
377
+ f"\nHint: To call a function under {operation_name!r} use a lambda function as in "
378
+ f"'{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'lambda: f(q)')})' "
379
+ f"or pass the quantum function directly as in "
380
+ f"'{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'f')})'."
253
381
  )
254
382
 
255
383
 
256
- def _operand_to_body(callable_: Union[QCallable, Callable[[], None]]) -> StatementBlock:
384
+ def _operand_to_body(
385
+ callable_: Union[QCallable, Callable[[], None]], param_name: str
386
+ ) -> StatementBlock:
257
387
  op_name = sys._getframe(1).f_code.co_name
258
388
  if (
259
389
  isinstance(callable_, QCallable)
260
390
  and len(callable_.func_decl.positional_arg_declarations) > 0
261
391
  ):
262
392
  raise ClassiqValueError(
263
- f"Operand argument {callable_.func_decl.name!r} to {op_name!r} should "
264
- f"receive 0 parameters, not "
265
- f"{len(callable_.func_decl.positional_arg_declarations)}"
393
+ f"Callable argument {callable_.func_decl.name!r} to {op_name!r} should "
394
+ f"not accept arguments."
266
395
  )
267
- to_operand = prepare_arg(QuantumOperandDeclaration(name=""), callable_, op_name)
396
+ to_operand = prepare_arg(
397
+ QuantumOperandDeclaration(name=""), callable_, op_name, param_name
398
+ )
268
399
  if isinstance(to_operand, str):
269
400
  return [QuantumFunctionCall(function=to_operand)]
270
401
  elif isinstance(to_operand, QuantumLambdaFunction):