classiq 0.37.1__py3-none-any.whl → 0.39.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 (280) hide show
  1. classiq/__init__.py +23 -24
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +1 -1
  3. classiq/_analyzer_extras/interactive_hardware.py +3 -3
  4. classiq/_internals/api_wrapper.py +37 -17
  5. classiq/_internals/async_utils.py +1 -74
  6. classiq/_internals/authentication/device.py +9 -4
  7. classiq/_internals/authentication/password_manager.py +25 -10
  8. classiq/_internals/authentication/token_manager.py +2 -2
  9. classiq/_internals/client.py +24 -6
  10. classiq/_internals/jobs.py +10 -7
  11. classiq/analyzer/analyzer.py +29 -29
  12. classiq/analyzer/analyzer_utilities.py +5 -5
  13. classiq/analyzer/rb.py +4 -5
  14. classiq/analyzer/show_interactive_hack.py +6 -6
  15. classiq/applications/__init__.py +1 -8
  16. classiq/applications/chemistry/__init__.py +6 -0
  17. classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +9 -16
  18. classiq/applications/combinatorial_helpers/allowed_constraints.py +20 -0
  19. classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
  20. classiq/applications/combinatorial_helpers/arithmetic/isolation.py +42 -0
  21. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +150 -0
  22. classiq/applications/combinatorial_helpers/encoding_mapping.py +107 -0
  23. classiq/applications/combinatorial_helpers/encoding_utils.py +122 -0
  24. classiq/applications/combinatorial_helpers/memory.py +77 -0
  25. classiq/applications/combinatorial_helpers/optimization_model.py +162 -0
  26. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
  27. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +75 -0
  28. classiq/applications/combinatorial_helpers/py.typed +0 -0
  29. classiq/applications/combinatorial_helpers/pyomo_utils.py +245 -0
  30. classiq/applications/combinatorial_helpers/solvers/__init__.py +0 -0
  31. classiq/applications/combinatorial_helpers/sympy_utils.py +22 -0
  32. classiq/applications/combinatorial_helpers/transformations/__init__.py +0 -0
  33. classiq/applications/combinatorial_helpers/transformations/encoding.py +187 -0
  34. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +142 -0
  35. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +122 -0
  36. classiq/applications/combinatorial_helpers/transformations/penalty.py +32 -0
  37. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +37 -0
  38. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +75 -0
  39. classiq/applications/combinatorial_helpers/transformations/slack_variables.py +88 -0
  40. classiq/applications/combinatorial_optimization/__init__.py +13 -2
  41. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +134 -0
  42. classiq/applications/finance/__init__.py +3 -2
  43. classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +27 -30
  44. classiq/applications/grover/__init__.py +11 -0
  45. classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +20 -91
  46. classiq/applications/libraries/__init__.py +0 -0
  47. classiq/applications/libraries/qmci_library.py +35 -0
  48. classiq/applications/qnn/circuit_utils.py +2 -2
  49. classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
  50. classiq/applications/qnn/types.py +2 -2
  51. classiq/applications/qsvm/__init__.py +5 -1
  52. classiq/applications/qsvm/qsvm.py +4 -7
  53. classiq/applications/qsvm/qsvm_data_generation.py +2 -5
  54. classiq/exceptions.py +43 -1
  55. classiq/execution/all_hardware_devices.py +13 -0
  56. classiq/executor.py +12 -10
  57. classiq/interface/_version.py +1 -1
  58. classiq/interface/analyzer/analysis_params.py +6 -3
  59. classiq/interface/analyzer/result.py +12 -8
  60. classiq/interface/applications/qsvm.py +17 -3
  61. classiq/interface/ast_node.py +23 -0
  62. classiq/interface/backend/backend_preferences.py +4 -2
  63. classiq/interface/backend/pydantic_backend.py +3 -1
  64. classiq/interface/backend/quantum_backend_providers.py +1 -0
  65. classiq/interface/chemistry/fermionic_operator.py +15 -13
  66. classiq/interface/chemistry/ground_state_problem.py +18 -3
  67. classiq/interface/chemistry/molecule.py +8 -6
  68. classiq/interface/chemistry/operator.py +20 -14
  69. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
  70. classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
  71. classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
  72. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
  73. classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
  74. classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
  75. classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
  76. classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
  77. classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
  78. classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
  79. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
  80. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
  81. classiq/interface/executor/aws_execution_cost.py +4 -3
  82. classiq/interface/executor/estimation.py +2 -2
  83. classiq/interface/executor/execution_preferences.py +5 -34
  84. classiq/interface/executor/execution_request.py +15 -48
  85. classiq/interface/executor/optimizer_preferences.py +22 -13
  86. classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
  87. classiq/interface/executor/quantum_instruction_set.py +2 -1
  88. classiq/interface/executor/register_initialization.py +1 -3
  89. classiq/interface/executor/result.py +41 -10
  90. classiq/interface/executor/vqe_result.py +2 -2
  91. classiq/interface/finance/function_input.py +17 -4
  92. classiq/interface/finance/gaussian_model_input.py +3 -1
  93. classiq/interface/finance/log_normal_model_input.py +3 -1
  94. classiq/interface/finance/model_input.py +2 -0
  95. classiq/interface/generator/amplitude_loading.py +6 -3
  96. classiq/interface/generator/application_apis/__init__.py +1 -0
  97. classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
  98. classiq/interface/generator/arith/argument_utils.py +14 -4
  99. classiq/interface/generator/arith/arithmetic.py +3 -1
  100. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
  101. classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
  102. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
  103. classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
  104. classiq/interface/generator/arith/arithmetic_operations.py +5 -10
  105. classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
  106. classiq/interface/generator/arith/binary_ops.py +202 -54
  107. classiq/interface/generator/arith/extremum_operations.py +5 -3
  108. classiq/interface/generator/arith/logical_ops.py +4 -2
  109. classiq/interface/generator/arith/machine_precision.py +3 -0
  110. classiq/interface/generator/arith/number_utils.py +34 -44
  111. classiq/interface/generator/arith/register_user_input.py +21 -1
  112. classiq/interface/generator/arith/unary_ops.py +16 -25
  113. classiq/interface/generator/builtin_api_builder.py +0 -5
  114. classiq/interface/generator/chemistry_function_params.py +4 -4
  115. classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
  116. classiq/interface/generator/compiler_keywords.py +4 -0
  117. classiq/interface/generator/complex_type.py +3 -10
  118. classiq/interface/generator/constant.py +2 -3
  119. classiq/interface/generator/control_state.py +5 -3
  120. classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
  121. classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
  122. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
  123. classiq/interface/generator/expressions/evaluated_expression.py +18 -4
  124. classiq/interface/generator/expressions/expression.py +3 -5
  125. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
  126. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  127. classiq/interface/generator/finance.py +1 -1
  128. classiq/interface/generator/function_params.py +7 -6
  129. classiq/interface/generator/functions/__init__.py +2 -2
  130. classiq/interface/generator/functions/builtins/__init__.py +15 -0
  131. classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
  132. classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
  133. classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
  134. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +612 -219
  135. classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
  136. classiq/interface/generator/functions/classical_type.py +2 -4
  137. classiq/interface/generator/functions/foreign_function_definition.py +12 -4
  138. classiq/interface/generator/functions/function_declaration.py +2 -2
  139. classiq/interface/generator/functions/function_implementation.py +8 -4
  140. classiq/interface/generator/functions/native_function_definition.py +4 -2
  141. classiq/interface/generator/functions/register.py +4 -2
  142. classiq/interface/generator/functions/register_mapping_data.py +14 -10
  143. classiq/interface/generator/generated_circuit_data.py +2 -2
  144. classiq/interface/generator/grover_operator.py +5 -3
  145. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
  146. classiq/interface/generator/hardware/hardware_data.py +6 -4
  147. classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
  148. classiq/interface/generator/hartree_fock.py +13 -3
  149. classiq/interface/generator/linear_pauli_rotations.py +3 -1
  150. classiq/interface/generator/mcu.py +5 -3
  151. classiq/interface/generator/mcx.py +7 -5
  152. classiq/interface/generator/model/classical_main_validator.py +1 -1
  153. classiq/interface/generator/model/constraints.py +2 -1
  154. classiq/interface/generator/model/model.py +12 -20
  155. classiq/interface/generator/model/preferences/preferences.py +4 -3
  156. classiq/interface/generator/oracles/custom_oracle.py +4 -2
  157. classiq/interface/generator/oracles/oracle_abc.py +2 -2
  158. classiq/interface/generator/qpe.py +6 -4
  159. classiq/interface/generator/qsvm.py +5 -8
  160. classiq/interface/generator/quantum_function_call.py +21 -16
  161. classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
  162. classiq/interface/generator/range_types.py +3 -1
  163. classiq/interface/generator/slice_parsing_utils.py +8 -3
  164. classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
  165. classiq/interface/generator/state_preparation/metrics.py +2 -1
  166. classiq/interface/generator/state_preparation/state_preparation.py +7 -5
  167. classiq/interface/generator/state_propagator.py +16 -5
  168. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
  169. classiq/interface/generator/types/struct_declaration.py +10 -7
  170. classiq/interface/generator/ucc.py +6 -4
  171. classiq/interface/generator/unitary_gate.py +7 -3
  172. classiq/interface/generator/validations/flow_graph.py +6 -4
  173. classiq/interface/generator/validations/validator_functions.py +6 -4
  174. classiq/interface/hardware.py +2 -2
  175. classiq/interface/helpers/custom_encoders.py +3 -0
  176. classiq/interface/helpers/pydantic_model_helpers.py +0 -6
  177. classiq/interface/helpers/validation_helpers.py +1 -1
  178. classiq/interface/helpers/versioned_model.py +4 -1
  179. classiq/interface/ide/show.py +2 -2
  180. classiq/interface/jobs.py +72 -3
  181. classiq/interface/model/bind_operation.py +18 -11
  182. classiq/interface/model/call_synthesis_data.py +68 -0
  183. classiq/interface/model/classical_if.py +13 -0
  184. classiq/interface/model/classical_parameter_declaration.py +2 -3
  185. classiq/interface/model/control.py +16 -0
  186. classiq/interface/model/handle_binding.py +3 -2
  187. classiq/interface/model/inplace_binary_operation.py +2 -2
  188. classiq/interface/model/invert.py +10 -0
  189. classiq/interface/model/model.py +29 -22
  190. classiq/interface/model/native_function_definition.py +3 -5
  191. classiq/interface/model/power.py +12 -0
  192. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
  193. classiq/interface/model/quantum_expressions/control_state.py +2 -2
  194. classiq/interface/model/quantum_function_call.py +33 -142
  195. classiq/interface/model/quantum_function_declaration.py +8 -0
  196. classiq/interface/model/quantum_if_operation.py +4 -5
  197. classiq/interface/model/quantum_lambda_function.py +58 -0
  198. classiq/{quantum_register.py → interface/model/quantum_register.py} +17 -9
  199. classiq/interface/model/quantum_statement.py +3 -2
  200. classiq/interface/model/quantum_type.py +58 -59
  201. classiq/interface/model/quantum_variable_declaration.py +3 -3
  202. classiq/interface/model/repeat.py +13 -0
  203. classiq/interface/model/resolvers/function_call_resolver.py +26 -0
  204. classiq/interface/model/statement_block.py +49 -0
  205. classiq/interface/model/validations/handles_validator.py +16 -18
  206. classiq/interface/model/within_apply_operation.py +11 -0
  207. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
  208. classiq/interface/server/routes.py +5 -4
  209. classiq/qmod/__init__.py +13 -6
  210. classiq/qmod/builtins/classical_execution_primitives.py +27 -36
  211. classiq/qmod/builtins/classical_functions.py +22 -12
  212. classiq/qmod/builtins/functions.py +272 -328
  213. classiq/qmod/builtins/operations.py +171 -35
  214. classiq/qmod/builtins/structs.py +15 -15
  215. classiq/qmod/cfunc.py +42 -0
  216. classiq/qmod/classical_function.py +6 -14
  217. classiq/qmod/declaration_inferrer.py +12 -21
  218. classiq/qmod/expression_query.py +23 -0
  219. classiq/qmod/model_state_container.py +2 -0
  220. classiq/qmod/native/__init__.py +0 -0
  221. classiq/qmod/native/expression_to_qmod.py +189 -0
  222. classiq/qmod/native/pretty_printer.py +340 -0
  223. classiq/qmod/qfunc.py +27 -0
  224. classiq/qmod/qmod_constant.py +100 -0
  225. classiq/qmod/qmod_parameter.py +36 -13
  226. classiq/qmod/qmod_struct.py +3 -3
  227. classiq/qmod/qmod_variable.py +148 -31
  228. classiq/qmod/quantum_callable.py +1 -0
  229. classiq/qmod/quantum_expandable.py +18 -19
  230. classiq/qmod/quantum_function.py +41 -8
  231. classiq/qmod/symbolic.py +48 -5
  232. classiq/qmod/symbolic_expr.py +9 -0
  233. classiq/qmod/utilities.py +13 -0
  234. classiq/qmod/write_qmod.py +39 -0
  235. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/METADATA +2 -1
  236. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/RECORD +244 -225
  237. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/WHEEL +1 -1
  238. classiq/applications/benchmarking/__init__.py +0 -9
  239. classiq/applications/benchmarking/mirror_benchmarking.py +0 -67
  240. classiq/applications/numpy_utils.py +0 -37
  241. classiq/applications_model_constructors/__init__.py +0 -17
  242. classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +0 -178
  243. classiq/applications_model_constructors/libraries/qmci_library.py +0 -109
  244. classiq/builtin_functions/__init__.py +0 -43
  245. classiq/builtin_functions/amplitude_loading.py +0 -3
  246. classiq/builtin_functions/binary_ops.py +0 -1
  247. classiq/builtin_functions/exponentiation.py +0 -5
  248. classiq/builtin_functions/qpe.py +0 -4
  249. classiq/builtin_functions/qsvm.py +0 -7
  250. classiq/builtin_functions/range_types.py +0 -5
  251. classiq/builtin_functions/standard_gates.py +0 -1
  252. classiq/builtin_functions/state_preparation.py +0 -6
  253. classiq/builtin_functions/suzuki_trotter.py +0 -3
  254. classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
  255. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
  256. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -169
  257. classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
  258. classiq/interface/generator/types/combinatorial_problem.py +0 -26
  259. classiq/interface/model/numeric_reinterpretation.py +0 -25
  260. classiq/interface/model/operator_synthesis_data.py +0 -48
  261. classiq/model/__init__.py +0 -14
  262. classiq/model/composite_function_generator.py +0 -33
  263. classiq/model/function_handler.py +0 -466
  264. classiq/model/function_handler.pyi +0 -152
  265. classiq/model/logic_flow.py +0 -149
  266. classiq/model/logic_flow_change_handler.py +0 -71
  267. classiq/model/model.py +0 -246
  268. classiq/quantum_functions/__init__.py +0 -17
  269. classiq/quantum_functions/annotation_parser.py +0 -207
  270. classiq/quantum_functions/decorators.py +0 -22
  271. classiq/quantum_functions/function_library.py +0 -181
  272. classiq/quantum_functions/function_parser.py +0 -74
  273. classiq/quantum_functions/quantum_function.py +0 -236
  274. /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers}/__init__.py +0 -0
  275. /classiq/{interface/generator/functions/core_lib_declarations → applications/combinatorial_helpers/arithmetic}/__init__.py +0 -0
  276. /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → applications/combinatorial_helpers/pauli_helpers/__init__.py} +0 -0
  277. /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
  278. /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
  279. /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +0 -0
  280. /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +0 -0
@@ -1,67 +1,96 @@
1
- from typing import Callable, List, Union
1
+ import inspect
2
+ from types import FrameType
3
+ from typing import Any, Callable, Final, List, Mapping, Union
2
4
 
3
5
  from classiq.interface.generator.expressions.expression import Expression
4
- from classiq.interface.generator.functions.core_lib_declarations.quantum_operators import (
5
- OPERAND_FIELD_NAME,
6
+ from classiq.interface.generator.functions.builtins.internal_operators import (
7
+ REPEAT_OPERATOR,
6
8
  )
7
9
  from classiq.interface.model.bind_operation import BindOperation
10
+ from classiq.interface.model.classical_if import ClassicalIf
11
+ from classiq.interface.model.control import Control
8
12
  from classiq.interface.model.inplace_binary_operation import (
9
13
  BinaryOperation,
10
14
  InplaceBinaryOperation,
11
15
  )
12
- from classiq.interface.model.numeric_reinterpretation import (
13
- NumericReinterpretationOperation,
14
- )
16
+ from classiq.interface.model.invert import Invert
17
+ from classiq.interface.model.power import Power
18
+ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
15
19
  from classiq.interface.model.quantum_function_declaration import (
16
20
  QuantumOperandDeclaration,
17
21
  )
18
- from classiq.interface.model.quantum_if_operation import QuantumIfOperation
19
-
20
- from classiq.qmod.builtins.functions import (
21
- apply,
22
- compute as compute_operator,
23
- uncompute,
24
- )
25
- from classiq.qmod.qmod_parameter import QParam
26
- from classiq.qmod.qmod_variable import Input, Output, QNum, QVar
22
+ from classiq.interface.model.quantum_if_operation import QuantumIf
23
+ from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
24
+ from classiq.interface.model.repeat import Repeat
25
+ from classiq.interface.model.statement_block import StatementBlock
26
+ from classiq.interface.model.within_apply_operation import WithinApply
27
+
28
+ from classiq.exceptions import ClassiqValueError
29
+ from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QNum, QVar
27
30
  from classiq.qmod.quantum_callable import QCallable
28
31
  from classiq.qmod.quantum_expandable import prepare_arg
29
32
  from classiq.qmod.symbolic_expr import SymbolicExpr
30
33
 
34
+ _MISSING_VALUE: Final[int] = -1
35
+
31
36
 
32
- def bind(source: Input[QVar], destination: Output[QVar]) -> None:
37
+ def bind(
38
+ source: Union[Input[QVar], List[Input[QVar]]],
39
+ destination: Union[Output[QVar], List[Output[QVar]]],
40
+ ) -> None:
33
41
  assert QCallable.CURRENT_EXPANDABLE is not None
42
+ if not isinstance(source, list):
43
+ source = [source]
44
+ if not isinstance(destination, list):
45
+ destination = [destination]
34
46
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
35
47
  BindOperation(
36
- in_handle=source.get_handle_binding(),
37
- out_handle=destination.get_handle_binding(),
48
+ in_handles=[src_var.get_handle_binding() for src_var in source],
49
+ out_handles=[dst_var.get_handle_binding() for dst_var in destination],
38
50
  )
39
51
  )
40
52
 
41
53
 
42
- def quantum_if(
43
- condition: SymbolicExpr, then: Union[QCallable, Callable[[], None]]
54
+ def control(
55
+ operand: Union[QCallable, Callable[[], None]], ctrl: Union[QBit, QArray[QBit]]
44
56
  ) -> None:
57
+ _validate_operand(operand)
45
58
  assert QCallable.CURRENT_EXPANDABLE is not None
46
59
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
47
- QuantumIfOperation(
48
- expression=Expression(expr=str(condition)),
49
- then=prepare_arg(QuantumOperandDeclaration(name=OPERAND_FIELD_NAME), then),
60
+ Control(
61
+ control=ctrl.get_handle_binding(),
62
+ body=_operand_to_body(operand),
50
63
  )
51
64
  )
52
65
 
53
66
 
54
- def reinterpret_num(
55
- is_signed: Union[QParam[bool], bool],
56
- fraction_digits: Union[QParam[int], int],
57
- target: QNum,
67
+ def if_(
68
+ condition: SymbolicExpr,
69
+ then: Union[QCallable, Callable[[], None]],
70
+ else_: Union[QCallable, Callable[[], None], int] = _MISSING_VALUE,
58
71
  ) -> None:
72
+ _validate_operand(then)
73
+ if else_ != _MISSING_VALUE:
74
+ _validate_operand(else_)
59
75
  assert QCallable.CURRENT_EXPANDABLE is not None
60
76
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
61
- NumericReinterpretationOperation(
62
- target=target.get_handle_binding(),
63
- is_signed=Expression(expr=str(is_signed)),
64
- fraction_digits=Expression(expr=str(fraction_digits)),
77
+ ClassicalIf(
78
+ condition=Expression(expr=str(condition)),
79
+ then=_operand_to_body(then),
80
+ else_=_operand_to_body(else_) if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
81
+ )
82
+ )
83
+
84
+
85
+ def quantum_if(
86
+ condition: SymbolicExpr, then: Union[QCallable, Callable[[], None]]
87
+ ) -> None:
88
+ _validate_operand(then)
89
+ assert QCallable.CURRENT_EXPANDABLE is not None
90
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
91
+ QuantumIf(
92
+ expression=Expression(expr=str(condition)),
93
+ then=_operand_to_body(then),
65
94
  )
66
95
  )
67
96
 
@@ -98,18 +127,125 @@ def within_apply(
98
127
  compute: Callable[[], None],
99
128
  action: Callable[[], None],
100
129
  ) -> None:
101
- compute_operator(compute)
102
- apply(action)
103
- uncompute(compute)
130
+ _validate_operand(compute)
131
+ _validate_operand(action)
132
+ assert QCallable.CURRENT_EXPANDABLE is not None
133
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
134
+ WithinApply(
135
+ compute=_operand_to_body(compute),
136
+ action=_operand_to_body(action),
137
+ )
138
+ )
139
+
140
+
141
+ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) -> None:
142
+ _validate_operand(iteration)
143
+ assert QCallable.CURRENT_EXPANDABLE is not None
144
+ iteration_operand = prepare_arg(
145
+ REPEAT_OPERATOR.operand_declarations["iteration"], iteration
146
+ )
147
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
148
+ Repeat(
149
+ iter_var=inspect.getfullargspec(iteration).args[0],
150
+ count=Expression(expr=str(count)),
151
+ body=iteration_operand.body,
152
+ )
153
+ )
154
+
155
+
156
+ def power(
157
+ power: Union[SymbolicExpr, int],
158
+ operand: Union[QCallable, Callable[[], None]],
159
+ ) -> None:
160
+ _validate_operand(operand)
161
+ assert QCallable.CURRENT_EXPANDABLE is not None
162
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
163
+ Power(power=Expression(expr=str(power)), body=_operand_to_body(operand))
164
+ )
165
+
166
+
167
+ def invert(
168
+ operand: Union[QCallable, Callable[[], None]],
169
+ ) -> None:
170
+ _validate_operand(operand)
171
+ assert QCallable.CURRENT_EXPANDABLE is not None
172
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
173
+ Invert(body=_operand_to_body(operand))
174
+ )
175
+
176
+
177
+ def _validate_operand(operand: Any) -> None:
178
+ if operand is not None:
179
+ return
180
+ currentframe: FrameType = inspect.currentframe() # type: ignore[assignment]
181
+ operation_frame: FrameType = currentframe.f_back # type: ignore[assignment]
182
+ operation_frame_info: inspect.Traceback = inspect.getframeinfo(operation_frame)
183
+ operation_name: str = operation_frame_info.function
184
+
185
+ context = operation_frame_info.code_context
186
+ assert context is not None
187
+ operand_arg_name = context[0].split("_validate_operand(")[1].split(")")[0]
188
+
189
+ error_message = (
190
+ f"{operation_name} is missing required argument for {operand_arg_name}"
191
+ )
192
+ error_message += _get_operand_hint(
193
+ operation_name=operation_name,
194
+ operand_arg_name=operand_arg_name,
195
+ params=inspect.signature(operation_frame.f_globals[operation_name]).parameters,
196
+ )
197
+ raise ClassiqValueError(error_message)
198
+
199
+
200
+ def _get_operand_hint_args(
201
+ params: Mapping[str, inspect.Parameter], operand_arg_name: str, operand_value: str
202
+ ) -> str:
203
+ return ", ".join(
204
+ [
205
+ (
206
+ f"{param.name}={operand_value}"
207
+ if param.name == operand_arg_name
208
+ else f"{param.name}=..."
209
+ )
210
+ for param in params.values()
211
+ ]
212
+ )
213
+
214
+
215
+ def _get_operand_hint(
216
+ operation_name: str, operand_arg_name: str, params: Mapping[str, inspect.Parameter]
217
+ ) -> str:
218
+ return (
219
+ f"\nHint: To create an operand, do not call quantum gates directly "
220
+ f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'H(q)')})`. "
221
+ f"Instead, use a lambda function "
222
+ f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'lambda: H(q)')})` "
223
+ f"or a quantum function "
224
+ f"`{operation_name}({_get_operand_hint_args(params, operand_arg_name, 'my_func')})`"
225
+ )
226
+
227
+
228
+ def _operand_to_body(callable_: Union[QCallable, Callable[[], None]]) -> StatementBlock:
229
+ to_operand = prepare_arg(QuantumOperandDeclaration(name=""), callable_)
230
+ if isinstance(to_operand, str):
231
+ return [QuantumFunctionCall(function=to_operand)]
232
+ elif isinstance(to_operand, QuantumLambdaFunction):
233
+ return to_operand.body
234
+ else:
235
+ raise ValueError(f"Unexpected operand type: {type(to_operand)}")
104
236
 
105
237
 
106
238
  __all__ = [
107
239
  "bind",
240
+ "control",
241
+ "invert",
242
+ "if_",
108
243
  "quantum_if",
109
- "reinterpret_num",
110
244
  "inplace_add",
111
245
  "inplace_xor",
246
+ "power",
112
247
  "within_apply",
248
+ "repeat",
113
249
  ]
114
250
 
115
251
 
@@ -2,16 +2,16 @@
2
2
 
3
3
  from typing import List
4
4
 
5
- from classiq.qmod.qmod_struct import QStruct
5
+ from classiq.qmod.qmod_struct import struct
6
6
 
7
7
 
8
- @QStruct
8
+ @struct
9
9
  class PauliTerm:
10
10
  pauli: List[int]
11
11
  coefficient: float
12
12
 
13
13
 
14
- @QStruct
14
+ @struct
15
15
  class MoleculeProblem:
16
16
  mapping: int
17
17
  z2_symmetries: bool
@@ -20,27 +20,27 @@ class MoleculeProblem:
20
20
  remove_orbitals: List[int]
21
21
 
22
22
 
23
- @QStruct
23
+ @struct
24
24
  class Molecule:
25
25
  atoms: List["ChemistryAtom"]
26
26
  spin: int
27
27
  charge: int
28
28
 
29
29
 
30
- @QStruct
30
+ @struct
31
31
  class ChemistryAtom:
32
32
  element: int
33
33
  position: "Position"
34
34
 
35
35
 
36
- @QStruct
36
+ @struct
37
37
  class Position:
38
38
  x: float
39
39
  y: float
40
40
  z: float
41
41
 
42
42
 
43
- @QStruct
43
+ @struct
44
44
  class FockHamiltonianProblem:
45
45
  mapping: int
46
46
  z2_symmetries: bool
@@ -48,19 +48,19 @@ class FockHamiltonianProblem:
48
48
  num_particles: List[int]
49
49
 
50
50
 
51
- @QStruct
51
+ @struct
52
52
  class LadderTerm:
53
53
  coefficient: float
54
54
  ops: List["LadderOp"]
55
55
 
56
56
 
57
- @QStruct
57
+ @struct
58
58
  class LadderOp:
59
59
  op: int
60
60
  index: int
61
61
 
62
62
 
63
- @QStruct
63
+ @struct
64
64
  class CombinatorialOptimizationSolution:
65
65
  probability: float
66
66
  cost: float
@@ -68,7 +68,7 @@ class CombinatorialOptimizationSolution:
68
68
  count: int
69
69
 
70
70
 
71
- @QStruct
71
+ @struct
72
72
  class GaussianModel:
73
73
  num_qubits: int
74
74
  normal_max_value: float
@@ -78,14 +78,14 @@ class GaussianModel:
78
78
  min_loss: int
79
79
 
80
80
 
81
- @QStruct
81
+ @struct
82
82
  class LogNormalModel:
83
83
  num_qubits: int
84
84
  mu: float
85
85
  sigma: float
86
86
 
87
87
 
88
- @QStruct
88
+ @struct
89
89
  class FinanceFunction:
90
90
  f: int
91
91
  threshold: float
@@ -95,13 +95,13 @@ class FinanceFunction:
95
95
  tail_probability: float
96
96
 
97
97
 
98
- @QStruct
98
+ @struct
99
99
  class QsvmResult:
100
100
  test_score: float
101
101
  predicted_labels: List[float]
102
102
 
103
103
 
104
- @QStruct
104
+ @struct
105
105
  class QSVMFeatureMapPauli:
106
106
  feature_dimension: int
107
107
  reps: int
classiq/qmod/cfunc.py ADDED
@@ -0,0 +1,42 @@
1
+ from typing import Any, Callable, Dict, Optional, Union, overload
2
+
3
+ from classiq.qmod.classical_function import CFunc
4
+
5
+
6
+ def get_caller_locals() -> Dict[str, Any]:
7
+ """Print the local variables in the caller's frame."""
8
+ import inspect
9
+
10
+ frame = inspect.currentframe()
11
+ try:
12
+ assert frame is not None
13
+ cfunc_frame = frame.f_back
14
+ assert cfunc_frame is not None
15
+ caller_frame = cfunc_frame.f_back
16
+ assert caller_frame is not None
17
+
18
+ return caller_frame.f_locals
19
+ finally:
20
+ # See here for information about the `del`
21
+ # https://docs.python.org/3/library/inspect.html#the-interpreter-stack
22
+ del frame
23
+
24
+
25
+ @overload
26
+ def cfunc(func: Callable) -> CFunc: ...
27
+
28
+
29
+ @overload
30
+ def cfunc(func: None = None) -> Callable[[Callable], CFunc]: ...
31
+
32
+
33
+ def cfunc(func: Optional[Callable] = None) -> Union[Callable[[Callable], CFunc], CFunc]:
34
+ caller_locals = get_caller_locals()
35
+
36
+ def wrapper(func: Callable) -> CFunc:
37
+ return CFunc(func, caller_locals)
38
+
39
+ if func is not None:
40
+ return wrapper(func)
41
+
42
+ return wrapper
@@ -2,10 +2,9 @@ import ast
2
2
  import inspect
3
3
  import sys
4
4
  from textwrap import dedent
5
- from typing import Callable
5
+ from typing import Any, Callable, Dict
6
6
 
7
7
  from classiq.exceptions import ClassiqValueError
8
- from classiq.qmod.builtins.classical_execution_primitives import sample, save
9
8
 
10
9
 
11
10
  def _unparse_function_body(code: str, func: ast.FunctionDef) -> str:
@@ -18,23 +17,16 @@ def _unparse_function_body(code: str, func: ast.FunctionDef) -> str:
18
17
 
19
18
 
20
19
  class CFunc:
21
- @staticmethod
22
- def default_cmain() -> "CFunc":
23
- @CFunc
24
- def cmain() -> None:
25
- result = sample()
26
- save({"result": result})
27
-
28
- return cmain
29
-
30
- def __init__(self, py_callable: Callable[[], None]):
20
+ def __init__(self, py_callable: Callable[[], None], caller_locals: Dict[str, Any]):
31
21
  code = dedent(inspect.getsource(py_callable))
32
22
  func = ast.parse(code).body[0]
33
23
  if not isinstance(func, ast.FunctionDef):
34
- raise ClassiqValueError(f"Use @{CFunc.__name__} to decorate a function")
24
+ raise ClassiqValueError("Use @cfunc to decorate a function")
35
25
  if len(func.args.args) > 0:
36
- raise ClassiqValueError(f"A @{CFunc.__name__} must receive no arguments")
26
+ raise ClassiqValueError("A @cfunc must receive no arguments")
37
27
  if sys.version_info >= (3, 9):
38
28
  self.code = "\n".join([ast.unparse(statement) for statement in func.body])
39
29
  else:
40
30
  self.code = _unparse_function_body(code, func)
31
+
32
+ self._caller_constants = caller_locals
@@ -1,6 +1,5 @@
1
1
  import dataclasses
2
2
  import inspect
3
- import sys
4
3
  from typing import Any, Callable, Dict, List, Optional, Type, get_args, get_origin
5
4
 
6
5
  from typing_extensions import _AnnotatedAlias
@@ -26,25 +25,17 @@ from classiq.interface.model.quantum_function_declaration import (
26
25
  )
27
26
 
28
27
  from classiq import StructDeclaration
28
+ from classiq.exceptions import ClassiqValueError
29
29
  from classiq.qmod.model_state_container import ModelStateContainer
30
30
  from classiq.qmod.qmod_parameter import Array, 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
- from classiq.qmod.utilities import unmangle_keyword
33
+ from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
34
34
 
35
35
  OPERAND_ARG_NAME = "arg{i}"
36
36
 
37
37
 
38
- def _version_portable_get_args(py_type: type) -> tuple:
39
- if get_origin(py_type) is None:
40
- return tuple()
41
- if sys.version_info[0:2] < (3, 10):
42
- return get_args(py_type) # The result of __class_getitem__
43
- else:
44
- return get_args(py_type)[0]
45
-
46
-
47
- def _python_type_to_qmod(
38
+ def python_type_to_qmod(
48
39
  py_type: type, *, qmodule: ModelStateContainer
49
40
  ) -> Optional[ConcreteClassicalType]:
50
41
  if py_type == int:
@@ -55,16 +46,16 @@ def _python_type_to_qmod(
55
46
  return Bool()
56
47
  elif get_origin(py_type) == list:
57
48
  return ClassicalList(
58
- element_type=_python_type_to_qmod(get_args(py_type)[0], qmodule=qmodule)
49
+ element_type=python_type_to_qmod(get_args(py_type)[0], qmodule=qmodule)
59
50
  )
60
51
  elif get_origin(py_type) == Array:
61
- array_args = _version_portable_get_args(py_type)
52
+ array_args = version_portable_get_args(py_type)
62
53
  if len(array_args) != 2:
63
- raise ValueError(
54
+ raise ClassiqValueError(
64
55
  "Array accepts two generic parameters in the form 'Array[<element-type>, <size>]'"
65
56
  )
66
57
  return ClassicalArray(
67
- element_type=_python_type_to_qmod(array_args[0], qmodule=qmodule),
58
+ element_type=python_type_to_qmod(array_args[0], qmodule=qmodule),
68
59
  size=get_type_hint_expr(array_args[1]),
69
60
  )
70
61
  elif inspect.isclass(py_type) and issubclass(py_type, QStructBase):
@@ -78,14 +69,14 @@ def _add_qmod_struct(
78
69
  ) -> None:
79
70
  if (
80
71
  py_type.__name__ in StructDeclaration.BUILTIN_STRUCT_DECLARATIONS
81
- or py_type.__name__ in qmodule.type_decls.keys()
72
+ or py_type.__name__ in qmodule.type_decls
82
73
  ):
83
74
  return
84
75
 
85
76
  qmodule.type_decls[py_type.__name__] = StructDeclaration(
86
77
  name=py_type.__name__,
87
78
  variables={
88
- f.name: _python_type_to_qmod(f.type, qmodule=qmodule)
79
+ f.name: python_type_to_qmod(f.type, qmodule=qmodule)
89
80
  for f in dataclasses.fields(py_type)
90
81
  },
91
82
  )
@@ -95,10 +86,10 @@ def _extract_param_decl(
95
86
  name: str, py_type: Any, *, qmodule: ModelStateContainer
96
87
  ) -> ClassicalParameterDeclaration:
97
88
  if len(get_args(py_type)) != 1:
98
- raise ValueError("QParam takes exactly one generic argument")
89
+ raise ClassiqValueError("QParam takes exactly one generic argument")
99
90
  py_type = get_args(py_type)[0]
100
91
  return ClassicalParameterDeclaration(
101
- name=name, classical_type=_python_type_to_qmod(py_type, qmodule=qmodule)
92
+ name=name, classical_type=python_type_to_qmod(py_type, qmodule=qmodule)
102
93
  )
103
94
 
104
95
 
@@ -118,7 +109,7 @@ def _extract_port_decl(name: str, py_type: Any) -> PortDeclaration:
118
109
  def _extract_operand_decl(
119
110
  name: str, py_type: Any, qmodule: ModelStateContainer
120
111
  ) -> QuantumOperandDeclaration:
121
- qc_args = _version_portable_get_args(py_type)
112
+ qc_args = version_portable_get_args(py_type)
122
113
  arg_dict = {
123
114
  OPERAND_ARG_NAME.format(i=i): arg_type for i, arg_type in enumerate(qc_args)
124
115
  }
@@ -0,0 +1,23 @@
1
+ from typing import TYPE_CHECKING, List, Tuple
2
+
3
+ from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
4
+ from classiq.interface.generator.arith.number_utils import MAXIMAL_MACHINE_PRECISION
5
+ from classiq.interface.model.quantum_type import QuantumNumeric
6
+
7
+ from classiq.qmod.qmod_variable import QNum
8
+ from classiq.qmod.symbolic_type import SymbolicTypes
9
+
10
+
11
+ def get_expression_numeric_attributes(
12
+ vars: List[QNum],
13
+ expr: SymbolicTypes,
14
+ machine_precision: int = MAXIMAL_MACHINE_PRECISION,
15
+ ) -> Tuple[int, bool, int]:
16
+ res_type = compute_arithmetic_result_type(
17
+ expr_str=str(expr),
18
+ var_types={var._name: var.get_qmod_type() for var in vars},
19
+ machine_precision=machine_precision,
20
+ )
21
+ if TYPE_CHECKING:
22
+ assert isinstance(res_type, QuantumNumeric)
23
+ return res_type.size_in_bits, res_type.sign_value, res_type.fraction_digits_value
@@ -1,5 +1,6 @@
1
1
  from typing import Dict
2
2
 
3
+ from classiq.interface.generator.constant import Constant
3
4
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
4
5
 
5
6
  from classiq import StructDeclaration
@@ -8,6 +9,7 @@ from classiq import StructDeclaration
8
9
  class ModelStateContainer:
9
10
  type_decls: Dict[str, StructDeclaration]
10
11
  native_defs: Dict[str, NativeFunctionDefinition]
12
+ constants: Dict[str, Constant]
11
13
 
12
14
 
13
15
  QMODULE = ModelStateContainer()
File without changes