classiq 0.38.0__py3-none-any.whl → 0.40.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 (154) hide show
  1. classiq/__init__.py +22 -22
  2. classiq/_internals/api_wrapper.py +13 -1
  3. classiq/_internals/client.py +12 -2
  4. classiq/analyzer/analyzer.py +3 -1
  5. classiq/applications/__init__.py +1 -8
  6. classiq/applications/chemistry/__init__.py +6 -0
  7. classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +1 -1
  8. classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/arithmetic_expression.py +1 -1
  9. classiq/{applications_model_constructors → applications}/combinatorial_helpers/combinatorial_problem_utils.py +25 -6
  10. classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_mapping.py +1 -1
  11. classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_utils.py +1 -1
  12. classiq/{applications_model_constructors → applications}/combinatorial_helpers/memory.py +2 -4
  13. classiq/{applications_model_constructors → applications}/combinatorial_helpers/optimization_model.py +13 -16
  14. classiq/{applications_model_constructors → applications}/combinatorial_helpers/pyomo_utils.py +4 -2
  15. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/encoding.py +3 -10
  16. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/fixed_variables.py +4 -6
  17. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/ising_converter.py +3 -5
  18. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty_support.py +3 -7
  19. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/slack_variables.py +4 -6
  20. classiq/applications/combinatorial_optimization/__init__.py +11 -3
  21. classiq/{applications_model_constructors → applications/combinatorial_optimization}/combinatorial_optimization_model_constructor.py +9 -10
  22. classiq/applications/finance/__init__.py +3 -2
  23. classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +24 -14
  24. classiq/applications/grover/__init__.py +11 -0
  25. classiq/applications/libraries/qmci_library.py +35 -0
  26. classiq/applications/qsvm/__init__.py +5 -1
  27. classiq/execution/all_hardware_devices.py +13 -0
  28. classiq/executor.py +2 -1
  29. classiq/interface/_version.py +1 -1
  30. classiq/interface/analyzer/result.py +1 -5
  31. classiq/interface/applications/qsvm.py +4 -2
  32. classiq/interface/ast_node.py +23 -0
  33. classiq/interface/backend/backend_preferences.py +5 -5
  34. classiq/interface/backend/quantum_backend_providers.py +7 -7
  35. classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
  36. classiq/interface/executor/execution_preferences.py +4 -9
  37. classiq/interface/executor/execution_request.py +2 -37
  38. classiq/interface/executor/vqe_result.py +1 -1
  39. classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
  40. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  41. classiq/interface/generator/arith/arithmetic_expression_validator.py +2 -0
  42. classiq/interface/generator/builtin_api_builder.py +0 -5
  43. classiq/interface/generator/constant.py +2 -3
  44. classiq/interface/generator/expressions/expression.py +2 -4
  45. classiq/interface/generator/expressions/qmod_qarray_proxy.py +82 -0
  46. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +22 -1
  47. classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
  48. classiq/interface/generator/functions/__init__.py +2 -2
  49. classiq/interface/generator/functions/builtins/__init__.py +15 -0
  50. classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
  51. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +8 -6
  52. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +10 -4
  53. classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
  54. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +893 -319
  55. classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
  56. classiq/interface/generator/functions/classical_type.py +31 -21
  57. classiq/interface/generator/functions/function_declaration.py +2 -2
  58. classiq/interface/generator/hartree_fock.py +10 -2
  59. classiq/interface/generator/model/classical_main_validator.py +1 -1
  60. classiq/interface/generator/model/model.py +1 -1
  61. classiq/interface/generator/model/preferences/preferences.py +4 -2
  62. classiq/interface/generator/quantum_function_call.py +1 -1
  63. classiq/interface/generator/types/struct_declaration.py +2 -4
  64. classiq/interface/model/call_synthesis_data.py +3 -3
  65. classiq/interface/model/classical_if.py +13 -0
  66. classiq/interface/model/classical_parameter_declaration.py +2 -3
  67. classiq/interface/model/{quantum_if_operation.py → control.py} +39 -21
  68. classiq/interface/model/handle_binding.py +3 -2
  69. classiq/interface/model/invert.py +10 -0
  70. classiq/interface/model/model.py +2 -1
  71. classiq/interface/model/power.py +12 -0
  72. classiq/interface/model/quantum_function_call.py +9 -4
  73. classiq/interface/model/quantum_lambda_function.py +3 -9
  74. classiq/interface/model/quantum_statement.py +3 -2
  75. classiq/interface/model/quantum_type.py +8 -9
  76. classiq/interface/model/quantum_variable_declaration.py +2 -2
  77. classiq/interface/model/repeat.py +13 -0
  78. classiq/interface/model/resolvers/function_call_resolver.py +21 -0
  79. classiq/interface/model/statement_block.py +18 -4
  80. classiq/interface/model/validations/handles_validator.py +8 -12
  81. classiq/interface/model/within_apply_operation.py +4 -4
  82. classiq/interface/server/routes.py +0 -4
  83. classiq/qmod/__init__.py +6 -2
  84. classiq/qmod/builtins/classical_functions.py +34 -39
  85. classiq/qmod/builtins/functions.py +287 -300
  86. classiq/qmod/builtins/operations.py +217 -16
  87. classiq/qmod/builtins/structs.py +50 -48
  88. classiq/qmod/declaration_inferrer.py +30 -18
  89. classiq/qmod/native/expression_to_qmod.py +5 -4
  90. classiq/qmod/native/pretty_printer.py +48 -26
  91. classiq/qmod/qmod_constant.py +29 -5
  92. classiq/qmod/qmod_parameter.py +56 -34
  93. classiq/qmod/qmod_struct.py +2 -2
  94. classiq/qmod/qmod_variable.py +87 -43
  95. classiq/qmod/quantum_callable.py +8 -4
  96. classiq/qmod/quantum_expandable.py +25 -20
  97. classiq/qmod/quantum_function.py +29 -2
  98. classiq/qmod/symbolic.py +79 -69
  99. classiq/qmod/symbolic_expr.py +1 -1
  100. classiq/qmod/symbolic_type.py +1 -4
  101. classiq/qmod/utilities.py +29 -0
  102. {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/METADATA +1 -1
  103. {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/RECORD +122 -141
  104. classiq/applications/benchmarking/__init__.py +0 -9
  105. classiq/applications/benchmarking/mirror_benchmarking.py +0 -70
  106. classiq/applications/numpy_utils.py +0 -37
  107. classiq/applications_model_constructors/__init__.py +0 -25
  108. classiq/applications_model_constructors/combinatorial_helpers/multiple_comp_basis_sp.py +0 -34
  109. classiq/applications_model_constructors/libraries/qmci_library.py +0 -107
  110. classiq/builtin_functions/__init__.py +0 -43
  111. classiq/builtin_functions/amplitude_loading.py +0 -3
  112. classiq/builtin_functions/binary_ops.py +0 -1
  113. classiq/builtin_functions/exponentiation.py +0 -5
  114. classiq/builtin_functions/qpe.py +0 -4
  115. classiq/builtin_functions/qsvm.py +0 -7
  116. classiq/builtin_functions/range_types.py +0 -5
  117. classiq/builtin_functions/standard_gates.py +0 -1
  118. classiq/builtin_functions/state_preparation.py +0 -6
  119. classiq/builtin_functions/suzuki_trotter.py +0 -3
  120. classiq/interface/executor/error_mitigation.py +0 -6
  121. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
  122. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py +0 -0
  123. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -95
  124. classiq/model/__init__.py +0 -14
  125. classiq/model/composite_function_generator.py +0 -33
  126. classiq/model/function_handler.py +0 -462
  127. classiq/model/logic_flow.py +0 -149
  128. classiq/model/logic_flow_change_handler.py +0 -71
  129. classiq/model/model.py +0 -229
  130. classiq/quantum_functions/__init__.py +0 -17
  131. classiq/quantum_functions/annotation_parser.py +0 -205
  132. classiq/quantum_functions/decorators.py +0 -22
  133. classiq/quantum_functions/function_library.py +0 -181
  134. classiq/quantum_functions/function_parser.py +0 -74
  135. classiq/quantum_functions/quantum_function.py +0 -236
  136. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/__init__.py +0 -0
  137. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/allowed_constraints.py +0 -0
  138. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/__init__.py +0 -0
  139. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/isolation.py +0 -0
  140. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/__init__.py +0 -0
  141. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +0 -0
  142. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/pauli_utils.py +0 -0
  143. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/py.typed +0 -0
  144. /classiq/{applications_model_constructors/combinatorial_helpers/transformations → applications/combinatorial_helpers/solvers}/__init__.py +0 -0
  145. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/sympy_utils.py +0 -0
  146. /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers/transformations}/__init__.py +0 -0
  147. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty.py +0 -0
  148. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/sign_seperation.py +0 -0
  149. /classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +0 -0
  150. /classiq/{interface/generator/functions/core_lib_declarations → applications/libraries}/__init__.py +0 -0
  151. /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
  152. /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
  153. /classiq/{quantum_register.py → interface/model/quantum_register.py} +0 -0
  154. {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/WHEEL +0 -0
@@ -1,22 +1,39 @@
1
- from typing import Callable, List, Union
1
+ import inspect
2
+ import sys
3
+ import warnings
4
+ from types import FrameType
5
+ from typing import Any, Callable, Final, List, Mapping, Union, overload
2
6
 
3
7
  from classiq.interface.generator.expressions.expression import Expression
8
+ from classiq.interface.generator.functions.builtins.internal_operators import (
9
+ REPEAT_OPERATOR,
10
+ )
4
11
  from classiq.interface.model.bind_operation import BindOperation
12
+ from classiq.interface.model.classical_if import ClassicalIf
13
+ from classiq.interface.model.control import Control
5
14
  from classiq.interface.model.inplace_binary_operation import (
6
15
  BinaryOperation,
7
16
  InplaceBinaryOperation,
8
17
  )
9
- from classiq.interface.model.quantum_function_call import ArgValue
18
+ from classiq.interface.model.invert import Invert
19
+ from classiq.interface.model.power import Power
20
+ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
10
21
  from classiq.interface.model.quantum_function_declaration import (
11
22
  QuantumOperandDeclaration,
12
23
  )
13
- from classiq.interface.model.quantum_if_operation import QuantumIfOperation
14
- from classiq.interface.model.within_apply_operation import WithinApplyOperation
24
+ from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
25
+ from classiq.interface.model.repeat import Repeat
26
+ from classiq.interface.model.statement_block import StatementBlock
27
+ from classiq.interface.model.within_apply_operation import WithinApply
15
28
 
16
- from classiq.qmod.qmod_variable import Input, Output, QNum, QVar
29
+ from classiq.exceptions import ClassiqValueError
30
+ from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QNum, QVar
17
31
  from classiq.qmod.quantum_callable import QCallable
18
32
  from classiq.qmod.quantum_expandable import prepare_arg
19
33
  from classiq.qmod.symbolic_expr import SymbolicExpr
34
+ from classiq.qmod.utilities import get_source_ref
35
+
36
+ _MISSING_VALUE: Final[int] = -1
20
37
 
21
38
 
22
39
  def bind(
@@ -24,6 +41,7 @@ def bind(
24
41
  destination: Union[Output[QVar], List[Output[QVar]]],
25
42
  ) -> None:
26
43
  assert QCallable.CURRENT_EXPANDABLE is not None
44
+ source_ref = get_source_ref(sys._getframe(1))
27
45
  if not isinstance(source, list):
28
46
  source = [source]
29
47
  if not isinstance(destination, list):
@@ -32,32 +50,104 @@ def bind(
32
50
  BindOperation(
33
51
  in_handles=[src_var.get_handle_binding() for src_var in source],
34
52
  out_handles=[dst_var.get_handle_binding() for dst_var in destination],
53
+ source_ref=source_ref,
35
54
  )
36
55
  )
37
56
 
38
57
 
39
- def quantum_if(
40
- condition: SymbolicExpr, then: Union[QCallable, Callable[[], None]]
58
+ def if_(
59
+ condition: SymbolicExpr,
60
+ then: Union[QCallable, Callable[[], None]],
61
+ else_: Union[QCallable, Callable[[], None], int] = _MISSING_VALUE,
41
62
  ) -> None:
63
+ _validate_operand(then)
64
+ if else_ != _MISSING_VALUE:
65
+ _validate_operand(else_)
42
66
  assert QCallable.CURRENT_EXPANDABLE is not None
67
+ source_ref = get_source_ref(sys._getframe(1))
43
68
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
44
- QuantumIfOperation(
45
- expression=Expression(expr=str(condition)),
46
- then=_to_operand(then),
69
+ ClassicalIf(
70
+ 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]
73
+ source_ref=source_ref,
47
74
  )
48
75
  )
49
76
 
50
77
 
78
+ @overload
79
+ def control(
80
+ ctrl: Union[QBit, QArray[QBit]], operand: Union[QCallable, Callable[[], None]]
81
+ ) -> None:
82
+ pass
83
+
84
+
85
+ @overload
86
+ def control(ctrl: SymbolicExpr, operand: Union[QCallable, Callable[[], None]]) -> None:
87
+ pass
88
+
89
+
90
+ def control(
91
+ ctrl: Union[SymbolicExpr, QBit, QArray[QBit]],
92
+ operand: Union[QCallable, Callable[[], None]],
93
+ ) -> None:
94
+ if isinstance(operand, (SymbolicExpr, QVar)) and isinstance(
95
+ control, (QCallable, Callable)
96
+ ): # type:ignore[unreachable]
97
+ warnings.warn( # type:ignore[unreachable]
98
+ "The `control` syntax has changed. Switch the `ctrl` and "
99
+ "`operand` arguments. The old syntax will not be supported in the future.",
100
+ category=DeprecationWarning,
101
+ stacklevel=2,
102
+ )
103
+ ctrl, operand = operand, ctrl
104
+ if isinstance(ctrl, QNum):
105
+ warnings.warn(
106
+ "The `control` semantics has changed. Applying `control` to "
107
+ "a `QNum` without comparing it to an integer will not be supported in the "
108
+ "future.\nTips:\n 1. Use a `bind` statement to cast `ctrl` into a "
109
+ "QArray.\n 2.`control(n, ...)` is equivalent to "
110
+ "`ctrl(n == 2 ** n.size - 1, ...)` if n>=0 or to `ctrl(n == -1, ...)` if "
111
+ "n<0.",
112
+ category=DeprecationWarning,
113
+ stacklevel=2,
114
+ )
115
+ _validate_operand(operand)
116
+ assert QCallable.CURRENT_EXPANDABLE is not None
117
+ source_ref = get_source_ref(sys._getframe(1))
118
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
119
+ Control(
120
+ expression=Expression(expr=str(ctrl)),
121
+ body=_operand_to_body(operand),
122
+ source_ref=source_ref,
123
+ )
124
+ )
125
+
126
+
127
+ def quantum_if(
128
+ ctrl: SymbolicExpr, operand: Union[QCallable, Callable[[], None]]
129
+ ) -> None:
130
+ warnings.warn(
131
+ "`quantum_if` is no longer supported, use `control` instead (with the "
132
+ "same arguments). `quantum_if` will be removed in a future release.",
133
+ category=DeprecationWarning,
134
+ stacklevel=2,
135
+ )
136
+ control(ctrl, operand)
137
+
138
+
51
139
  def inplace_add(
52
140
  value: QNum,
53
141
  target: QNum,
54
142
  ) -> None:
55
143
  assert QCallable.CURRENT_EXPANDABLE is not None
144
+ source_ref = get_source_ref(sys._getframe(1))
56
145
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
57
146
  InplaceBinaryOperation(
58
147
  target=target.get_handle_binding(),
59
148
  value=value.get_handle_binding(),
60
149
  operation=BinaryOperation.Addition,
150
+ source_ref=source_ref,
61
151
  )
62
152
  )
63
153
 
@@ -67,11 +157,13 @@ def inplace_xor(
67
157
  target: QNum,
68
158
  ) -> None:
69
159
  assert QCallable.CURRENT_EXPANDABLE is not None
160
+ source_ref = get_source_ref(sys._getframe(1))
70
161
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
71
162
  InplaceBinaryOperation(
72
163
  target=target.get_handle_binding(),
73
164
  value=value.get_handle_binding(),
74
165
  operation=BinaryOperation.Xor,
166
+ source_ref=source_ref,
75
167
  )
76
168
  )
77
169
 
@@ -80,25 +172,134 @@ def within_apply(
80
172
  compute: Callable[[], None],
81
173
  action: Callable[[], None],
82
174
  ) -> None:
175
+ _validate_operand(compute)
176
+ _validate_operand(action)
177
+ assert QCallable.CURRENT_EXPANDABLE is not None
178
+ source_ref = get_source_ref(sys._getframe(1))
179
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
180
+ WithinApply(
181
+ compute=_operand_to_body(compute),
182
+ action=_operand_to_body(action),
183
+ source_ref=source_ref,
184
+ )
185
+ )
186
+
187
+
188
+ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) -> None:
189
+ _validate_operand(iteration)
190
+ assert QCallable.CURRENT_EXPANDABLE is not None
191
+ source_ref = get_source_ref(sys._getframe(1))
192
+ iteration_operand = prepare_arg(
193
+ REPEAT_OPERATOR.operand_declarations["iteration"], iteration
194
+ )
195
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
196
+ Repeat(
197
+ iter_var=inspect.getfullargspec(iteration).args[0],
198
+ count=Expression(expr=str(count)),
199
+ body=iteration_operand.body,
200
+ source_ref=source_ref,
201
+ )
202
+ )
203
+
204
+
205
+ def power(
206
+ power: Union[SymbolicExpr, int],
207
+ operand: Union[QCallable, Callable[[], None]],
208
+ ) -> None:
209
+ _validate_operand(operand)
83
210
  assert QCallable.CURRENT_EXPANDABLE is not None
211
+ source_ref = get_source_ref(sys._getframe(1))
84
212
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
85
- WithinApplyOperation(
86
- compute=_to_operand(compute),
87
- action=_to_operand(action),
213
+ Power(
214
+ power=Expression(expr=str(power)),
215
+ body=_operand_to_body(operand),
216
+ source_ref=source_ref,
88
217
  )
89
218
  )
90
219
 
91
220
 
92
- def _to_operand(callable_: Union[QCallable, Callable[[], None]]) -> ArgValue:
93
- return prepare_arg(QuantumOperandDeclaration(name=""), callable_)
221
+ def invert(
222
+ operand: Union[QCallable, Callable[[], None]],
223
+ ) -> None:
224
+ _validate_operand(operand)
225
+ assert QCallable.CURRENT_EXPANDABLE is not None
226
+ source_ref = get_source_ref(sys._getframe(1))
227
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
228
+ Invert(body=_operand_to_body(operand), source_ref=source_ref)
229
+ )
230
+
231
+
232
+ def _validate_operand(operand: Any) -> None:
233
+ if operand is not None:
234
+ return
235
+ currentframe: FrameType = inspect.currentframe() # type: ignore[assignment]
236
+ operation_frame: FrameType = currentframe.f_back # type: ignore[assignment]
237
+ operation_frame_info: inspect.Traceback = inspect.getframeinfo(operation_frame)
238
+ operation_name: str = operation_frame_info.function
239
+
240
+ context = operation_frame_info.code_context
241
+ assert context is not None
242
+ operand_arg_name = context[0].split("_validate_operand(")[1].split(")")[0]
243
+
244
+ error_message = (
245
+ f"{operation_name} is missing required argument for {operand_arg_name}"
246
+ )
247
+ error_message += _get_operand_hint(
248
+ operation_name=operation_name,
249
+ operand_arg_name=operand_arg_name,
250
+ params=inspect.signature(operation_frame.f_globals[operation_name]).parameters,
251
+ )
252
+ raise ClassiqValueError(error_message)
253
+
254
+
255
+ def _get_operand_hint_args(
256
+ params: Mapping[str, inspect.Parameter], operand_arg_name: str, operand_value: str
257
+ ) -> str:
258
+ return ", ".join(
259
+ [
260
+ (
261
+ f"{param.name}={operand_value}"
262
+ if param.name == operand_arg_name
263
+ else f"{param.name}=..."
264
+ )
265
+ for param in params.values()
266
+ ]
267
+ )
268
+
269
+
270
+ def _get_operand_hint(
271
+ operation_name: str, operand_arg_name: str, params: Mapping[str, inspect.Parameter]
272
+ ) -> str:
273
+ return (
274
+ f"\nHint: To create an operand, do not call quantum gates directly "
275
+ f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'H(q)')})`. "
276
+ f"Instead, use a lambda function "
277
+ f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'lambda: H(q)')})` "
278
+ f"or a quantum function "
279
+ f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'my_func')})`"
280
+ )
281
+
282
+
283
+ def _operand_to_body(callable_: Union[QCallable, Callable[[], None]]) -> StatementBlock:
284
+ to_operand = prepare_arg(QuantumOperandDeclaration(name=""), callable_)
285
+ if isinstance(to_operand, str):
286
+ return [QuantumFunctionCall(function=to_operand)]
287
+ elif isinstance(to_operand, QuantumLambdaFunction):
288
+ return to_operand.body
289
+ else:
290
+ raise ValueError(f"Unexpected operand type: {type(to_operand)}")
94
291
 
95
292
 
96
293
  __all__ = [
97
294
  "bind",
98
- "quantum_if",
295
+ "control",
296
+ "invert",
297
+ "if_",
99
298
  "inplace_add",
100
299
  "inplace_xor",
300
+ "power",
101
301
  "within_apply",
302
+ "repeat",
102
303
  ]
103
304
 
104
305
 
@@ -1,113 +1,115 @@
1
1
  # This file was generated automatically - do not edit manually
2
2
 
3
- from typing import List
3
+ from classiq.interface.generator.expressions.enums.ladder_operator import LadderOperator
4
+ from classiq.interface.generator.expressions.enums.pauli import Pauli
4
5
 
6
+ from classiq.qmod.qmod_parameter import CArray, CBool, CInt, CReal
5
7
  from classiq.qmod.qmod_struct import struct
6
8
 
7
9
 
8
10
  @struct
9
11
  class PauliTerm:
10
- pauli: List[int]
11
- coefficient: float
12
+ pauli: CArray[Pauli]
13
+ coefficient: CReal
12
14
 
13
15
 
14
16
  @struct
15
17
  class MoleculeProblem:
16
- mapping: int
17
- z2_symmetries: bool
18
+ mapping: CInt
19
+ z2_symmetries: CBool
18
20
  molecule: "Molecule"
19
- freeze_core: bool
20
- remove_orbitals: List[int]
21
+ freeze_core: CBool
22
+ remove_orbitals: CArray[CInt]
21
23
 
22
24
 
23
25
  @struct
24
26
  class Molecule:
25
- atoms: List["ChemistryAtom"]
26
- spin: int
27
- charge: int
27
+ atoms: CArray["ChemistryAtom"]
28
+ spin: CInt
29
+ charge: CInt
28
30
 
29
31
 
30
32
  @struct
31
33
  class ChemistryAtom:
32
- element: int
34
+ element: CInt
33
35
  position: "Position"
34
36
 
35
37
 
36
38
  @struct
37
39
  class Position:
38
- x: float
39
- y: float
40
- z: float
40
+ x: CReal
41
+ y: CReal
42
+ z: CReal
41
43
 
42
44
 
43
45
  @struct
44
46
  class FockHamiltonianProblem:
45
- mapping: int
46
- z2_symmetries: bool
47
- terms: List["LadderTerm"]
48
- num_particles: List[int]
47
+ mapping: CInt
48
+ z2_symmetries: CBool
49
+ terms: CArray["LadderTerm"]
50
+ num_particles: CArray[CInt]
49
51
 
50
52
 
51
53
  @struct
52
54
  class LadderTerm:
53
- coefficient: float
54
- ops: List["LadderOp"]
55
+ coefficient: CReal
56
+ ops: CArray["LadderOp"]
55
57
 
56
58
 
57
59
  @struct
58
60
  class LadderOp:
59
- op: int
60
- index: int
61
+ op: LadderOperator
62
+ index: CInt
61
63
 
62
64
 
63
65
  @struct
64
66
  class CombinatorialOptimizationSolution:
65
- probability: float
66
- cost: float
67
- solution: List[int]
68
- count: int
67
+ probability: CReal
68
+ cost: CReal
69
+ solution: CArray[CInt]
70
+ count: CInt
69
71
 
70
72
 
71
73
  @struct
72
74
  class GaussianModel:
73
- num_qubits: int
74
- normal_max_value: float
75
- default_probabilities: List[float]
76
- rhos: List[float]
77
- loss: List[int]
78
- min_loss: int
75
+ num_qubits: CInt
76
+ normal_max_value: CReal
77
+ default_probabilities: CArray[CReal]
78
+ rhos: CArray[CReal]
79
+ loss: CArray[CInt]
80
+ min_loss: CInt
79
81
 
80
82
 
81
83
  @struct
82
84
  class LogNormalModel:
83
- num_qubits: int
84
- mu: float
85
- sigma: float
85
+ num_qubits: CInt
86
+ mu: CReal
87
+ sigma: CReal
86
88
 
87
89
 
88
90
  @struct
89
91
  class FinanceFunction:
90
- f: int
91
- threshold: float
92
- larger: bool
93
- polynomial_degree: int
94
- use_chebyshev_polynomial_approximation: bool
95
- tail_probability: float
92
+ f: CInt
93
+ threshold: CReal
94
+ larger: CBool
95
+ polynomial_degree: CInt
96
+ use_chebyshev_polynomial_approximation: CBool
97
+ tail_probability: CReal
96
98
 
97
99
 
98
100
  @struct
99
101
  class QsvmResult:
100
- test_score: float
101
- predicted_labels: List[float]
102
+ test_score: CReal
103
+ predicted_labels: CArray[CReal]
102
104
 
103
105
 
104
106
  @struct
105
107
  class QSVMFeatureMapPauli:
106
- feature_dimension: int
107
- reps: int
108
- entanglement: int
109
- alpha: float
110
- paulis: List[List[int]]
108
+ feature_dimension: CInt
109
+ reps: CInt
110
+ entanglement: CInt
111
+ alpha: CReal
112
+ paulis: CArray[CArray[Pauli]]
111
113
 
112
114
 
113
115
  __all__ = [
@@ -9,8 +9,8 @@ from classiq.interface.generator.functions.classical_type import (
9
9
  ClassicalArray,
10
10
  ClassicalList,
11
11
  ConcreteClassicalType,
12
+ CStructBase,
12
13
  Integer,
13
- QStructBase,
14
14
  Real,
15
15
  Struct,
16
16
  )
@@ -27,7 +27,7 @@ from classiq.interface.model.quantum_function_declaration import (
27
27
  from classiq import StructDeclaration
28
28
  from classiq.exceptions import ClassiqValueError
29
29
  from classiq.qmod.model_state_container import ModelStateContainer
30
- from classiq.qmod.qmod_parameter import Array, QParam
30
+ from classiq.qmod.qmod_parameter import CArray, CBool, CInt, CParam, CReal, QParam
31
31
  from classiq.qmod.qmod_variable import QVar, get_type_hint_expr
32
32
  from classiq.qmod.quantum_callable import QCallable, QCallableList
33
33
  from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
@@ -38,34 +38,39 @@ OPERAND_ARG_NAME = "arg{i}"
38
38
  def python_type_to_qmod(
39
39
  py_type: type, *, qmodule: ModelStateContainer
40
40
  ) -> Optional[ConcreteClassicalType]:
41
- if py_type == int:
41
+ if py_type == int or py_type is CInt:
42
42
  return Integer()
43
- elif py_type == float:
43
+ elif py_type == float or py_type is CReal:
44
44
  return Real()
45
- elif py_type == bool:
45
+ elif py_type == bool or py_type is CBool:
46
46
  return Bool()
47
47
  elif get_origin(py_type) == list:
48
48
  return ClassicalList(
49
49
  element_type=python_type_to_qmod(get_args(py_type)[0], qmodule=qmodule)
50
50
  )
51
- elif get_origin(py_type) == Array:
51
+ elif get_origin(py_type) == CArray:
52
52
  array_args = version_portable_get_args(py_type)
53
- if len(array_args) != 2:
54
- raise ClassiqValueError(
55
- "Array accepts two generic parameters in the form 'Array[<element-type>, <size>]'"
53
+ if len(array_args) == 1:
54
+ return ClassicalList(
55
+ element_type=python_type_to_qmod(array_args[0], qmodule=qmodule)
56
56
  )
57
- return ClassicalArray(
58
- element_type=python_type_to_qmod(array_args[0], qmodule=qmodule),
59
- size=get_type_hint_expr(array_args[1]),
57
+ elif len(array_args) == 2:
58
+ return ClassicalArray(
59
+ element_type=python_type_to_qmod(array_args[0], qmodule=qmodule),
60
+ size=get_type_hint_expr(array_args[1]),
61
+ )
62
+ raise ClassiqValueError(
63
+ "CArray accepts one or two generic parameters in the form "
64
+ "`CArray[<element-type>]` or `CArray[<element-type>, <size>]`"
60
65
  )
61
- elif inspect.isclass(py_type) and issubclass(py_type, QStructBase):
66
+ elif inspect.isclass(py_type) and issubclass(py_type, CStructBase):
62
67
  _add_qmod_struct(py_type, qmodule=qmodule)
63
68
  return Struct(name=py_type.__name__)
64
69
  return None
65
70
 
66
71
 
67
72
  def _add_qmod_struct(
68
- py_type: Type[QStructBase], *, qmodule: ModelStateContainer
73
+ py_type: Type[CStructBase], *, qmodule: ModelStateContainer
69
74
  ) -> None:
70
75
  if (
71
76
  py_type.__name__ in StructDeclaration.BUILTIN_STRUCT_DECLARATIONS
@@ -85,9 +90,10 @@ def _add_qmod_struct(
85
90
  def _extract_param_decl(
86
91
  name: str, py_type: Any, *, qmodule: ModelStateContainer
87
92
  ) -> ClassicalParameterDeclaration:
88
- if len(get_args(py_type)) != 1:
89
- raise ClassiqValueError("QParam takes exactly one generic argument")
90
- py_type = get_args(py_type)[0]
93
+ if get_origin(py_type) is QParam:
94
+ if len(get_args(py_type)) != 1:
95
+ raise ClassiqValueError("QParam takes exactly one generic argument")
96
+ py_type = get_args(py_type)[0]
91
97
  return ClassicalParameterDeclaration(
92
98
  name=name, classical_type=python_type_to_qmod(py_type, qmodule=qmodule)
93
99
  )
@@ -128,7 +134,13 @@ def _extract_positional_args(
128
134
  if name == "return":
129
135
  continue
130
136
  name = unmangle_keyword(name)
131
- if get_origin(py_type) is QParam:
137
+ if (
138
+ inspect.isclass(py_type)
139
+ and issubclass(py_type, CParam)
140
+ or inspect.isclass(py_type)
141
+ and issubclass(py_type, CStructBase)
142
+ or get_origin(py_type) in (QParam, CArray)
143
+ ):
132
144
  result.append(_extract_param_decl(name, py_type, qmodule=qmodule))
133
145
  elif QVar.from_type_hint(py_type) is not None:
134
146
  result.append(_extract_port_decl(name, py_type))
@@ -5,6 +5,8 @@ from typing import Callable, Dict, List, Mapping, Type
5
5
 
6
6
  import numpy as np
7
7
 
8
+ from classiq.interface.generator.functions.classical_type import CLASSICAL_ATTRIBUTES
9
+
8
10
  from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
9
11
 
10
12
  IDENTIFIER = re.compile(r"[a-zA-Z_]\w*")
@@ -57,11 +59,10 @@ class ASTToQMODCode:
57
59
  return self.indent.join(self.ast_to_code(child) for child in node.body)
58
60
  elif isinstance(node, ast.Attribute):
59
61
  # Enum attribute access
60
- if not isinstance(node.value, ast.Name) or not isinstance(node.attr, str):
61
- raise AssertionError("Error parsing enum attribute access")
62
- if not (IDENTIFIER.match(node.value.id) and IDENTIFIER.match(node.attr)):
62
+ if not isinstance(node.attr, str):
63
63
  raise AssertionError("Error parsing enum attribute access")
64
- return f"{node.value.id!s}::{node.attr!s}"
64
+ access_operator = "." if node.attr in CLASSICAL_ATTRIBUTES else "::"
65
+ return f"{self.ast_to_code(node.value)!s}{access_operator}{node.attr!s}"
65
66
  elif isinstance(node, ast.Name):
66
67
  return node.id
67
68
  elif isinstance(node, ast.Num):