classiq 0.37.1__py3-none-any.whl → 0.65.3__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 (516) hide show
  1. classiq/__init__.py +49 -34
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +3 -2
  3. classiq/_analyzer_extras/interactive_hardware.py +3 -3
  4. classiq/_internals/api_wrapper.py +241 -95
  5. classiq/_internals/async_utils.py +2 -77
  6. classiq/_internals/authentication/auth0.py +26 -10
  7. classiq/_internals/authentication/authentication.py +11 -0
  8. classiq/_internals/authentication/device.py +18 -8
  9. classiq/_internals/authentication/password_manager.py +40 -13
  10. classiq/_internals/authentication/token_manager.py +11 -6
  11. classiq/_internals/client.py +106 -37
  12. classiq/_internals/config.py +3 -4
  13. classiq/_internals/host_checker.py +38 -15
  14. classiq/_internals/jobs.py +56 -50
  15. classiq/_internals/type_validation.py +9 -9
  16. classiq/analyzer/__init__.py +1 -3
  17. classiq/analyzer/analyzer.py +50 -47
  18. classiq/analyzer/analyzer_utilities.py +15 -15
  19. classiq/analyzer/rb.py +19 -20
  20. classiq/analyzer/show_interactive_hack.py +30 -7
  21. classiq/analyzer/url_utils.py +2 -3
  22. classiq/applications/__init__.py +3 -12
  23. classiq/applications/chemistry/__init__.py +14 -10
  24. classiq/applications/chemistry/ansatz_parameters.py +4 -4
  25. classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +170 -170
  26. classiq/applications/chemistry/ground_state_problem.py +1 -1
  27. classiq/applications/combinatorial_helpers/allowed_constraints.py +23 -0
  28. classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
  29. classiq/applications/combinatorial_helpers/arithmetic/isolation.py +42 -0
  30. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +166 -0
  31. classiq/applications/combinatorial_helpers/encoding_mapping.py +107 -0
  32. classiq/applications/combinatorial_helpers/encoding_utils.py +124 -0
  33. classiq/applications/combinatorial_helpers/memory.py +75 -0
  34. classiq/applications/combinatorial_helpers/optimization_model.py +193 -0
  35. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
  36. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +46 -0
  37. classiq/applications/combinatorial_helpers/pyomo_utils.py +447 -0
  38. classiq/applications/combinatorial_helpers/sympy_utils.py +22 -0
  39. classiq/applications/combinatorial_helpers/transformations/encoding.py +189 -0
  40. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +143 -0
  41. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +120 -0
  42. classiq/applications/combinatorial_helpers/transformations/penalty.py +31 -0
  43. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +37 -0
  44. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +74 -0
  45. classiq/applications/combinatorial_helpers/transformations/slack_variables.py +87 -0
  46. classiq/applications/combinatorial_optimization/__init__.py +24 -5
  47. classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -2
  48. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +137 -0
  49. classiq/applications/combinatorial_optimization/combinatorial_problem.py +229 -0
  50. classiq/applications/combinatorial_optimization/examples/__init__.py +1 -3
  51. classiq/applications/finance/__init__.py +4 -5
  52. classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +50 -57
  53. classiq/applications/grover/__init__.py +9 -0
  54. classiq/applications/grover/grover_model_constructor.py +157 -0
  55. classiq/applications/hamiltonian/__init__.py +0 -0
  56. classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
  57. classiq/applications/libraries/__init__.py +0 -0
  58. classiq/applications/libraries/qmci_library.py +22 -0
  59. classiq/applications/qnn/__init__.py +2 -4
  60. classiq/applications/qnn/circuit_utils.py +8 -8
  61. classiq/applications/qnn/datasets/__init__.py +9 -11
  62. classiq/applications/qnn/datasets/dataset_base_classes.py +7 -5
  63. classiq/applications/qnn/datasets/dataset_not.py +2 -1
  64. classiq/applications/qnn/datasets/dataset_parity.py +2 -2
  65. classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
  66. classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -1
  67. classiq/applications/qnn/qlayer.py +30 -10
  68. classiq/applications/qnn/torch_utils.py +4 -3
  69. classiq/applications/qnn/types.py +7 -7
  70. classiq/applications/qsvm/__init__.py +6 -4
  71. classiq/applications/qsvm/qsvm.py +4 -10
  72. classiq/applications/qsvm/qsvm_data_generation.py +5 -8
  73. classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +30 -28
  74. classiq/execution/__init__.py +8 -3
  75. classiq/execution/all_hardware_devices.py +11 -0
  76. classiq/execution/execution_session.py +400 -0
  77. classiq/execution/iqcc.py +63 -0
  78. classiq/execution/jobs.py +197 -25
  79. classiq/execution/qnn.py +79 -0
  80. classiq/executor.py +23 -117
  81. classiq/interface/_version.py +1 -1
  82. classiq/interface/analyzer/analysis_params.py +49 -16
  83. classiq/interface/analyzer/cytoscape_graph.py +15 -9
  84. classiq/interface/analyzer/result.py +36 -32
  85. classiq/interface/applications/qsvm.py +28 -25
  86. classiq/interface/ast_node.py +16 -0
  87. classiq/interface/backend/backend_preferences.py +390 -119
  88. classiq/interface/backend/ionq/ionq_quantum_program.py +15 -23
  89. classiq/interface/backend/pydantic_backend.py +27 -22
  90. classiq/interface/backend/quantum_backend_providers.py +70 -16
  91. classiq/interface/chemistry/fermionic_operator.py +43 -32
  92. classiq/interface/chemistry/ground_state_problem.py +42 -24
  93. classiq/interface/chemistry/molecule.py +20 -14
  94. classiq/interface/chemistry/operator.py +75 -236
  95. classiq/interface/combinatorial_optimization/encoding_types.py +1 -1
  96. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +2 -4
  97. classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
  98. classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
  99. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -4
  100. classiq/interface/combinatorial_optimization/examples/knapsack.py +3 -3
  101. classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
  102. classiq/interface/combinatorial_optimization/examples/mht.py +10 -6
  103. classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
  104. classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
  105. classiq/interface/combinatorial_optimization/examples/portfolio_variations.py +2 -2
  106. classiq/interface/combinatorial_optimization/examples/set_cover.py +3 -3
  107. classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
  108. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
  109. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +14 -9
  110. classiq/interface/combinatorial_optimization/optimization_problem.py +2 -2
  111. classiq/interface/combinatorial_optimization/result.py +1 -3
  112. classiq/interface/combinatorial_optimization/solver_types.py +1 -1
  113. classiq/interface/debug_info/__init__.py +0 -0
  114. classiq/interface/debug_info/debug_info.py +86 -0
  115. classiq/interface/exceptions.py +201 -0
  116. classiq/interface/execution/iqcc.py +19 -0
  117. classiq/interface/execution/jobs.py +15 -12
  118. classiq/interface/execution/primitives.py +18 -0
  119. classiq/interface/executor/constants.py +1 -0
  120. classiq/interface/executor/estimation.py +2 -2
  121. classiq/interface/executor/execution_preferences.py +26 -143
  122. classiq/interface/executor/execution_request.py +36 -56
  123. classiq/interface/executor/execution_result.py +30 -8
  124. classiq/interface/executor/iqae_result.py +4 -6
  125. classiq/interface/executor/optimizer_preferences.py +34 -22
  126. classiq/interface/executor/{quantum_program.py → quantum_code.py} +44 -34
  127. classiq/interface/executor/quantum_instruction_set.py +3 -2
  128. classiq/interface/executor/register_initialization.py +12 -17
  129. classiq/interface/executor/result.py +122 -64
  130. classiq/interface/executor/vqe_result.py +11 -11
  131. classiq/interface/finance/function_input.py +42 -19
  132. classiq/interface/finance/gaussian_model_input.py +7 -5
  133. classiq/interface/finance/log_normal_model_input.py +6 -4
  134. classiq/interface/finance/model_input.py +6 -4
  135. classiq/interface/generator/adjacency.py +1 -3
  136. classiq/interface/generator/amplitude_loading.py +27 -14
  137. classiq/interface/generator/ansatz_library.py +5 -5
  138. classiq/interface/generator/application_apis/__init__.py +1 -0
  139. classiq/interface/generator/application_apis/arithmetic_declarations.py +17 -0
  140. classiq/interface/generator/application_apis/chemistry_declarations.py +27 -187
  141. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +18 -21
  142. classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
  143. classiq/interface/generator/application_apis/finance_declarations.py +48 -69
  144. classiq/interface/generator/application_apis/qsvm_declarations.py +0 -70
  145. classiq/interface/generator/arith/argument_utils.py +57 -6
  146. classiq/interface/generator/arith/arithmetic.py +37 -16
  147. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +15 -17
  148. classiq/interface/generator/arith/arithmetic_expression_abc.py +70 -26
  149. classiq/interface/generator/arith/arithmetic_expression_parser.py +18 -12
  150. classiq/interface/generator/arith/arithmetic_expression_validator.py +61 -43
  151. classiq/interface/generator/arith/arithmetic_operations.py +19 -16
  152. classiq/interface/generator/arith/arithmetic_param_getters.py +7 -8
  153. classiq/interface/generator/arith/arithmetic_result_builder.py +21 -17
  154. classiq/interface/generator/arith/ast_node_rewrite.py +4 -3
  155. classiq/interface/generator/arith/binary_ops.py +375 -139
  156. classiq/interface/generator/arith/endianness.py +1 -1
  157. classiq/interface/generator/arith/extremum_operations.py +96 -23
  158. classiq/interface/generator/arith/logical_ops.py +16 -12
  159. classiq/interface/generator/arith/machine_precision.py +3 -0
  160. classiq/interface/generator/arith/number_utils.py +44 -48
  161. classiq/interface/generator/arith/register_user_input.py +70 -27
  162. classiq/interface/generator/arith/unary_ops.py +57 -46
  163. classiq/interface/generator/arith/uncomputation_methods.py +1 -1
  164. classiq/interface/generator/builtin_api_builder.py +2 -9
  165. classiq/interface/generator/chemistry_function_params.py +5 -5
  166. classiq/interface/generator/circuit_code/circuit_code.py +7 -7
  167. classiq/interface/generator/circuit_code/types_and_constants.py +4 -7
  168. classiq/interface/generator/commuting_pauli_exponentiation.py +8 -6
  169. classiq/interface/generator/compiler_keywords.py +8 -0
  170. classiq/interface/generator/complex_type.py +13 -25
  171. classiq/interface/generator/constant.py +3 -4
  172. classiq/interface/generator/control_state.py +35 -28
  173. classiq/interface/generator/copy.py +47 -0
  174. classiq/interface/generator/custom_ansatz.py +2 -5
  175. classiq/interface/generator/distance.py +3 -5
  176. classiq/interface/generator/excitations.py +3 -2
  177. classiq/interface/generator/expressions/atomic_expression_functions.py +26 -8
  178. classiq/interface/generator/expressions/enums/__init__.py +0 -10
  179. classiq/interface/generator/expressions/enums/finance_functions.py +12 -22
  180. classiq/interface/generator/expressions/evaluated_expression.py +21 -7
  181. classiq/interface/generator/expressions/expression.py +27 -15
  182. classiq/interface/generator/expressions/expression_constants.py +9 -3
  183. classiq/interface/generator/expressions/non_symbolic_expr.py +119 -0
  184. classiq/interface/generator/expressions/qmod_qarray_proxy.py +99 -0
  185. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +59 -0
  186. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +36 -0
  187. classiq/interface/generator/expressions/qmod_sized_proxy.py +30 -2
  188. classiq/interface/generator/expressions/qmod_struct_instance.py +14 -2
  189. classiq/interface/generator/expressions/sympy_supported_expressions.py +20 -11
  190. classiq/interface/generator/finance.py +3 -3
  191. classiq/interface/generator/function_param_library.py +6 -6
  192. classiq/interface/generator/function_param_list_without_self_reference.py +2 -10
  193. classiq/interface/generator/function_params.py +42 -69
  194. classiq/interface/generator/functions/__init__.py +0 -22
  195. classiq/interface/generator/functions/builtins/__init__.py +0 -0
  196. classiq/interface/generator/functions/builtins/internal_operators.py +16 -0
  197. classiq/interface/generator/functions/classical_function_declaration.py +18 -9
  198. classiq/interface/generator/functions/classical_type.py +47 -166
  199. classiq/interface/generator/functions/concrete_types.py +55 -0
  200. classiq/interface/generator/functions/function_declaration.py +13 -14
  201. classiq/interface/generator/functions/port_declaration.py +1 -13
  202. classiq/interface/generator/functions/qmod_python_interface.py +2 -1
  203. classiq/interface/generator/functions/type_name.py +90 -0
  204. classiq/interface/generator/generated_circuit_data.py +155 -22
  205. classiq/interface/generator/grover_diffuser.py +32 -25
  206. classiq/interface/generator/grover_operator.py +34 -23
  207. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +4 -6
  208. classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
  209. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +12 -8
  210. classiq/interface/generator/hardware/hardware_data.py +76 -36
  211. classiq/interface/generator/hardware_efficient_ansatz.py +38 -17
  212. classiq/interface/generator/hartree_fock.py +14 -4
  213. classiq/interface/generator/identity.py +10 -6
  214. classiq/interface/generator/linear_pauli_rotations.py +33 -19
  215. classiq/interface/generator/mcmt_method.py +1 -1
  216. classiq/interface/generator/mcu.py +20 -16
  217. classiq/interface/generator/mcx.py +29 -20
  218. classiq/interface/generator/model/__init__.py +2 -5
  219. classiq/interface/generator/model/constraints.py +27 -8
  220. classiq/interface/generator/model/model.py +32 -203
  221. classiq/interface/generator/model/preferences/preferences.py +118 -43
  222. classiq/{quantum_register.py → interface/generator/model/quantum_register.py} +27 -22
  223. classiq/interface/generator/oracles/arithmetic_oracle.py +2 -4
  224. classiq/interface/generator/oracles/custom_oracle.py +17 -13
  225. classiq/interface/generator/oracles/oracle_abc.py +9 -9
  226. classiq/interface/generator/partitioned_register.py +7 -7
  227. classiq/interface/generator/piecewise_linear_amplitude_loading.py +45 -29
  228. classiq/interface/generator/preferences/optimization.py +1 -2
  229. classiq/interface/generator/qpe.py +47 -34
  230. classiq/interface/generator/qsvm.py +13 -17
  231. classiq/interface/generator/quantum_function_call.py +107 -87
  232. classiq/interface/generator/{generated_circuit.py → quantum_program.py} +50 -37
  233. classiq/interface/generator/range_types.py +13 -12
  234. classiq/interface/generator/register_role.py +18 -6
  235. classiq/interface/generator/slice_parsing_utils.py +11 -6
  236. classiq/interface/generator/standard_gates/controlled_standard_gates.py +32 -39
  237. classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
  238. classiq/interface/generator/standard_gates/standard_gates.py +3 -3
  239. classiq/interface/generator/standard_gates/u_gate.py +7 -10
  240. classiq/interface/generator/state_preparation/bell_state_preparation.py +3 -3
  241. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
  242. classiq/interface/generator/state_preparation/distributions.py +16 -15
  243. classiq/interface/generator/state_preparation/metrics.py +5 -7
  244. classiq/interface/generator/state_preparation/state_preparation.py +30 -23
  245. classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
  246. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +20 -6
  247. classiq/interface/generator/transpiler_basis_gates.py +7 -3
  248. classiq/interface/generator/types/builtin_enum_declarations.py +178 -0
  249. classiq/interface/generator/types/compilation_metadata.py +6 -0
  250. classiq/interface/generator/types/enum_declaration.py +54 -0
  251. classiq/interface/generator/types/qstruct_declaration.py +18 -0
  252. classiq/interface/generator/types/struct_declaration.py +15 -14
  253. classiq/interface/generator/ucc.py +9 -6
  254. classiq/interface/generator/unitary_gate.py +10 -6
  255. classiq/interface/generator/user_defined_function_params.py +4 -1
  256. classiq/interface/generator/validations/flow_graph.py +11 -9
  257. classiq/interface/generator/validations/validator_functions.py +8 -6
  258. classiq/interface/generator/visitor.py +23 -16
  259. classiq/interface/hardware.py +31 -10
  260. classiq/interface/helpers/classproperty.py +8 -0
  261. classiq/interface/helpers/custom_encoders.py +3 -0
  262. classiq/interface/helpers/custom_pydantic_types.py +40 -50
  263. classiq/interface/helpers/datastructures.py +26 -0
  264. classiq/interface/helpers/hashable_mixin.py +3 -2
  265. classiq/interface/helpers/hashable_pydantic_base_model.py +2 -1
  266. classiq/interface/helpers/pydantic_model_helpers.py +7 -11
  267. classiq/interface/helpers/validation_helpers.py +4 -21
  268. classiq/interface/helpers/versioned_model.py +1 -1
  269. classiq/interface/ide/ide_data.py +16 -20
  270. classiq/interface/ide/visual_model.py +130 -0
  271. classiq/interface/interface_version.py +1 -0
  272. classiq/interface/jobs.py +35 -6
  273. classiq/interface/model/allocate.py +16 -0
  274. classiq/interface/model/bind_operation.py +44 -14
  275. classiq/interface/model/classical_if.py +15 -0
  276. classiq/interface/model/classical_parameter_declaration.py +33 -3
  277. classiq/interface/model/control.py +45 -0
  278. classiq/interface/model/handle_binding.py +298 -20
  279. classiq/interface/model/inplace_binary_operation.py +31 -26
  280. classiq/interface/model/invert.py +12 -0
  281. classiq/interface/model/model.py +87 -73
  282. classiq/interface/model/native_function_definition.py +16 -21
  283. classiq/interface/model/parameter.py +13 -0
  284. classiq/interface/model/phase_operation.py +11 -0
  285. classiq/interface/model/port_declaration.py +27 -9
  286. classiq/interface/model/power.py +14 -0
  287. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +38 -21
  288. classiq/interface/model/quantum_expressions/arithmetic_operation.py +51 -14
  289. classiq/interface/model/quantum_expressions/quantum_expression.py +12 -35
  290. classiq/interface/model/quantum_function_call.py +146 -462
  291. classiq/interface/model/quantum_function_declaration.py +193 -152
  292. classiq/interface/model/quantum_lambda_function.py +65 -0
  293. classiq/interface/model/quantum_statement.py +71 -12
  294. classiq/interface/model/quantum_type.py +205 -67
  295. classiq/interface/model/quantum_variable_declaration.py +4 -26
  296. classiq/interface/model/repeat.py +15 -0
  297. classiq/interface/model/statement_block.py +58 -0
  298. classiq/interface/model/validation_handle.py +13 -6
  299. classiq/interface/model/variable_declaration_statement.py +3 -1
  300. classiq/interface/model/within_apply_operation.py +13 -0
  301. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
  302. classiq/interface/server/global_versions.py +6 -7
  303. classiq/interface/server/routes.py +22 -21
  304. classiq/interface/source_reference.py +59 -0
  305. classiq/model_expansions/__init__.py +0 -0
  306. classiq/model_expansions/atomic_expression_functions_defs.py +253 -0
  307. classiq/model_expansions/capturing/__init__.py +0 -0
  308. classiq/model_expansions/capturing/captured_vars.py +435 -0
  309. classiq/model_expansions/capturing/mangling_utils.py +56 -0
  310. classiq/model_expansions/closure.py +171 -0
  311. classiq/model_expansions/debug_flag.py +3 -0
  312. classiq/model_expansions/evaluators/__init__.py +0 -0
  313. classiq/model_expansions/evaluators/arg_type_match.py +158 -0
  314. classiq/model_expansions/evaluators/argument_types.py +42 -0
  315. classiq/model_expansions/evaluators/classical_expression.py +36 -0
  316. classiq/model_expansions/evaluators/control.py +144 -0
  317. classiq/model_expansions/evaluators/parameter_types.py +226 -0
  318. classiq/model_expansions/evaluators/quantum_type_utils.py +239 -0
  319. classiq/model_expansions/evaluators/type_type_match.py +90 -0
  320. classiq/model_expansions/expression_evaluator.py +135 -0
  321. classiq/model_expansions/expression_renamer.py +76 -0
  322. classiq/model_expansions/function_builder.py +247 -0
  323. classiq/model_expansions/generative_functions.py +158 -0
  324. classiq/model_expansions/interpreters/__init__.py +0 -0
  325. classiq/model_expansions/interpreters/base_interpreter.py +263 -0
  326. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
  327. classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
  328. classiq/model_expansions/model_tables.py +18 -0
  329. classiq/model_expansions/quantum_operations/__init__.py +9 -0
  330. classiq/model_expansions/quantum_operations/bind.py +60 -0
  331. classiq/model_expansions/quantum_operations/call_emitter.py +266 -0
  332. classiq/model_expansions/quantum_operations/classicalif.py +53 -0
  333. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
  334. classiq/model_expansions/quantum_operations/emitter.py +181 -0
  335. classiq/model_expansions/quantum_operations/quantum_function_call.py +33 -0
  336. classiq/model_expansions/quantum_operations/repeat.py +56 -0
  337. classiq/model_expansions/quantum_operations/shallow_emitter.py +180 -0
  338. classiq/model_expansions/quantum_operations/variable_decleration.py +28 -0
  339. classiq/model_expansions/scope.py +240 -0
  340. classiq/model_expansions/scope_initialization.py +150 -0
  341. classiq/model_expansions/sympy_conversion/__init__.py +0 -0
  342. classiq/model_expansions/sympy_conversion/arithmetics.py +49 -0
  343. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +179 -0
  344. classiq/model_expansions/sympy_conversion/sympy_to_python.py +123 -0
  345. classiq/model_expansions/transformers/__init__.py +0 -0
  346. classiq/model_expansions/transformers/ast_renamer.py +26 -0
  347. classiq/model_expansions/transformers/var_splitter.py +299 -0
  348. classiq/model_expansions/utils/__init__.py +0 -0
  349. classiq/model_expansions/utils/counted_name_allocator.py +11 -0
  350. classiq/model_expansions/utils/handles_collector.py +33 -0
  351. classiq/model_expansions/visitors/__init__.py +0 -0
  352. classiq/model_expansions/visitors/boolean_expression_transformers.py +214 -0
  353. classiq/model_expansions/visitors/variable_references.py +144 -0
  354. classiq/open_library/__init__.py +4 -0
  355. classiq/open_library/functions/__init__.py +130 -0
  356. classiq/open_library/functions/amplitude_estimation.py +30 -0
  357. classiq/open_library/functions/discrete_sine_cosine_transform.py +181 -0
  358. classiq/open_library/functions/grover.py +157 -0
  359. classiq/open_library/functions/hea.py +115 -0
  360. classiq/open_library/functions/linear_pauli_rotation.py +82 -0
  361. classiq/open_library/functions/modular_exponentiation.py +201 -0
  362. classiq/open_library/functions/qaoa_penalty.py +117 -0
  363. classiq/open_library/functions/qft_functions.py +54 -0
  364. classiq/open_library/functions/qpe.py +46 -0
  365. classiq/open_library/functions/qsvt.py +331 -0
  366. classiq/open_library/functions/state_preparation.py +301 -0
  367. classiq/open_library/functions/swap_test.py +27 -0
  368. classiq/open_library/functions/utility_functions.py +81 -0
  369. classiq/open_library/functions/variational.py +52 -0
  370. classiq/qmod/__init__.py +17 -10
  371. classiq/qmod/builtins/__init__.py +19 -2
  372. classiq/qmod/builtins/classical_execution_primitives.py +60 -47
  373. classiq/qmod/builtins/classical_functions.py +44 -38
  374. classiq/qmod/builtins/constants.py +10 -0
  375. classiq/qmod/builtins/enums.py +208 -0
  376. classiq/qmod/builtins/functions/__init__.py +137 -0
  377. classiq/qmod/builtins/functions/allocation.py +150 -0
  378. classiq/qmod/builtins/functions/arithmetic.py +55 -0
  379. classiq/qmod/builtins/functions/benchmarking.py +8 -0
  380. classiq/qmod/builtins/functions/chemistry.py +91 -0
  381. classiq/qmod/builtins/functions/exponentiation.py +105 -0
  382. classiq/qmod/builtins/functions/finance.py +34 -0
  383. classiq/qmod/builtins/functions/operators.py +16 -0
  384. classiq/qmod/builtins/functions/qsvm.py +24 -0
  385. classiq/qmod/builtins/functions/standard_gates.py +651 -0
  386. classiq/qmod/builtins/operations.py +379 -57
  387. classiq/qmod/builtins/structs.py +103 -80
  388. classiq/qmod/cfunc.py +42 -0
  389. classiq/qmod/classical_function.py +8 -20
  390. classiq/qmod/cparam.py +64 -0
  391. classiq/qmod/create_model_function.py +56 -0
  392. classiq/qmod/declaration_inferrer.py +145 -112
  393. classiq/qmod/expression_query.py +39 -0
  394. classiq/qmod/generative.py +42 -0
  395. classiq/qmod/model_state_container.py +19 -5
  396. classiq/qmod/native/__init__.py +7 -0
  397. classiq/qmod/native/expression_to_qmod.py +194 -0
  398. classiq/qmod/native/pretty_printer.py +401 -0
  399. classiq/qmod/pretty_print/__init__.py +7 -0
  400. classiq/qmod/pretty_print/expression_to_python.py +222 -0
  401. classiq/qmod/pretty_print/pretty_printer.py +572 -0
  402. classiq/qmod/python_classical_type.py +67 -0
  403. classiq/qmod/qfunc.py +79 -0
  404. classiq/qmod/qmod_constant.py +143 -0
  405. classiq/qmod/qmod_parameter.py +84 -53
  406. classiq/qmod/qmod_variable.py +497 -100
  407. classiq/qmod/quantum_callable.py +17 -7
  408. classiq/qmod/quantum_expandable.py +278 -105
  409. classiq/qmod/quantum_function.py +232 -48
  410. classiq/qmod/semantics/__init__.py +0 -0
  411. classiq/qmod/semantics/annotation/__init__.py +0 -0
  412. classiq/qmod/semantics/annotation/call_annotation.py +92 -0
  413. classiq/qmod/semantics/annotation/qstruct_annotator.py +23 -0
  414. classiq/qmod/semantics/error_manager.py +88 -0
  415. classiq/qmod/semantics/lambdas.py +25 -0
  416. classiq/qmod/semantics/static_semantics_visitor.py +384 -0
  417. classiq/qmod/semantics/validation/__init__.py +0 -0
  418. classiq/qmod/semantics/validation/constants_validation.py +16 -0
  419. classiq/qmod/semantics/validation/func_call_validation.py +99 -0
  420. classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
  421. classiq/qmod/semantics/validation/handle_validation.py +85 -0
  422. classiq/qmod/semantics/validation/main_validation.py +33 -0
  423. classiq/qmod/semantics/validation/types_validation.py +128 -0
  424. classiq/qmod/symbolic.py +178 -111
  425. classiq/qmod/symbolic_expr.py +36 -12
  426. classiq/qmod/symbolic_type.py +2 -5
  427. classiq/qmod/type_attribute_remover.py +32 -0
  428. classiq/qmod/utilities.py +108 -1
  429. classiq/qmod/write_qmod.py +53 -0
  430. classiq/synthesis.py +210 -22
  431. {classiq-0.37.1.dist-info → classiq-0.65.3.dist-info}/METADATA +16 -8
  432. classiq-0.65.3.dist-info/RECORD +521 -0
  433. {classiq-0.37.1.dist-info → classiq-0.65.3.dist-info}/WHEEL +1 -1
  434. classiq/_internals/_qfunc_ext.py +0 -6
  435. classiq/applications/benchmarking/__init__.py +0 -9
  436. classiq/applications/benchmarking/mirror_benchmarking.py +0 -67
  437. classiq/applications/numpy_utils.py +0 -37
  438. classiq/applications_model_constructors/__init__.py +0 -17
  439. classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +0 -178
  440. classiq/applications_model_constructors/grover_model_constructor.py +0 -227
  441. classiq/applications_model_constructors/libraries/ampltitude_estimation_library.py +0 -11
  442. classiq/applications_model_constructors/libraries/qmci_library.py +0 -109
  443. classiq/builtin_functions/__init__.py +0 -43
  444. classiq/builtin_functions/amplitude_loading.py +0 -3
  445. classiq/builtin_functions/binary_ops.py +0 -1
  446. classiq/builtin_functions/exponentiation.py +0 -5
  447. classiq/builtin_functions/qpe.py +0 -4
  448. classiq/builtin_functions/qsvm.py +0 -7
  449. classiq/builtin_functions/range_types.py +0 -5
  450. classiq/builtin_functions/standard_gates.py +0 -1
  451. classiq/builtin_functions/state_preparation.py +0 -6
  452. classiq/builtin_functions/suzuki_trotter.py +0 -3
  453. classiq/exceptions.py +0 -131
  454. classiq/interface/executor/aws_execution_cost.py +0 -72
  455. classiq/interface/executor/error_mitigation.py +0 -6
  456. classiq/interface/generator/credit_risk_example/linear_gci.py +0 -115
  457. classiq/interface/generator/credit_risk_example/weighted_adder.py +0 -59
  458. classiq/interface/generator/expressions/enums/chemistry.py +0 -28
  459. classiq/interface/generator/expressions/enums/classical_enum.py +0 -5
  460. classiq/interface/generator/expressions/enums/ladder_operator.py +0 -16
  461. classiq/interface/generator/expressions/enums/optimizers.py +0 -9
  462. classiq/interface/generator/expressions/enums/pauli.py +0 -8
  463. classiq/interface/generator/expressions/enums/qsvm_feature_map_entanglement.py +0 -9
  464. classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
  465. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
  466. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +0 -641
  467. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/exponentiation_functions.py +0 -89
  468. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +0 -862
  469. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -169
  470. classiq/interface/generator/functions/foreign_function_definition.py +0 -106
  471. classiq/interface/generator/functions/function_implementation.py +0 -103
  472. classiq/interface/generator/functions/native_function_definition.py +0 -153
  473. classiq/interface/generator/functions/quantum_function_declaration.py +0 -69
  474. classiq/interface/generator/functions/register.py +0 -42
  475. classiq/interface/generator/functions/register_mapping_data.py +0 -102
  476. classiq/interface/generator/inequality_mixer.py +0 -51
  477. classiq/interface/generator/model/classical_main_validator.py +0 -106
  478. classiq/interface/generator/range_mixer.py +0 -56
  479. classiq/interface/generator/state_propagator.py +0 -63
  480. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -2
  481. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +0 -22
  482. classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
  483. classiq/interface/generator/types/combinatorial_problem.py +0 -26
  484. classiq/interface/ide/show.py +0 -34
  485. classiq/interface/model/common_model_types.py +0 -23
  486. classiq/interface/model/numeric_reinterpretation.py +0 -25
  487. classiq/interface/model/operator_synthesis_data.py +0 -48
  488. classiq/interface/model/quantum_expressions/control_state.py +0 -38
  489. classiq/interface/model/quantum_if_operation.py +0 -95
  490. classiq/interface/model/resolvers/function_call_resolver.py +0 -43
  491. classiq/interface/model/validations/handle_validation_base.py +0 -55
  492. classiq/interface/model/validations/handles_validator.py +0 -154
  493. classiq/interface/model/validations/port_to_wire_name_generator.py +0 -12
  494. classiq/model/__init__.py +0 -14
  495. classiq/model/composite_function_generator.py +0 -33
  496. classiq/model/function_handler.py +0 -466
  497. classiq/model/function_handler.pyi +0 -152
  498. classiq/model/logic_flow.py +0 -149
  499. classiq/model/logic_flow_change_handler.py +0 -71
  500. classiq/model/model.py +0 -246
  501. classiq/qmod/builtins/functions.py +0 -896
  502. classiq/qmod/qmod_struct.py +0 -37
  503. classiq/quantum_functions/__init__.py +0 -17
  504. classiq/quantum_functions/annotation_parser.py +0 -207
  505. classiq/quantum_functions/decorators.py +0 -22
  506. classiq/quantum_functions/function_library.py +0 -181
  507. classiq/quantum_functions/function_parser.py +0 -74
  508. classiq/quantum_functions/quantum_function.py +0 -236
  509. classiq-0.37.1.dist-info/RECORD +0 -418
  510. /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers}/__init__.py +0 -0
  511. /classiq/{interface/generator/credit_risk_example → applications/combinatorial_helpers/arithmetic}/__init__.py +0 -0
  512. /classiq/{interface/generator/functions/core_lib_declarations → applications/combinatorial_helpers/pauli_helpers}/__init__.py +0 -0
  513. /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → applications/combinatorial_helpers/py.typed} +0 -0
  514. /classiq/{interface/model/resolvers → applications/combinatorial_helpers/solvers}/__init__.py +0 -0
  515. /classiq/{interface/model/validations → applications/combinatorial_helpers/transformations}/__init__.py +0 -0
  516. /classiq/{_internals → interface}/enum_utils.py +0 -0
@@ -1,12 +1,14 @@
1
1
  import abc
2
2
  import ast
3
3
  import re
4
- from typing import Any, Dict, Optional, Set, Tuple, Union
4
+ from typing import Any, Optional, Union
5
5
 
6
6
  import networkx as nx
7
7
  import pydantic
8
+ from pydantic import TypeAdapter
8
9
  from typing_extensions import TypeAlias
9
10
 
11
+ from classiq.interface.exceptions import ClassiqValueError
10
12
  from classiq.interface.generator.arith import number_utils
11
13
  from classiq.interface.generator.arith.arithmetic_expression_parser import (
12
14
  parse_expression,
@@ -17,6 +19,9 @@ from classiq.interface.generator.arith.arithmetic_expression_validator import (
17
19
  from classiq.interface.generator.arith.arithmetic_result_builder import (
18
20
  validate_arithmetic_result_type,
19
21
  )
22
+ from classiq.interface.generator.arith.machine_precision import (
23
+ DEFAULT_MACHINE_PRECISION,
24
+ )
20
25
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
21
26
  from classiq.interface.generator.arith.uncomputation_methods import UncomputationMethods
22
27
  from classiq.interface.generator.expressions.expression_constants import (
@@ -27,8 +32,6 @@ from classiq.interface.generator.expressions.expression_constants import (
27
32
  from classiq.interface.generator.function_params import FunctionParams
28
33
  from classiq.interface.helpers.custom_pydantic_types import PydanticExpressionStr
29
34
 
30
- from classiq.exceptions import ClassiqValueError
31
-
32
35
  ValidDefinitions: TypeAlias = Union[
33
36
  pydantic.StrictInt, pydantic.StrictFloat, RegisterArithmeticInfo
34
37
  ]
@@ -36,22 +39,18 @@ ValidDefinitions: TypeAlias = Union[
36
39
 
37
40
  class ArithmeticExpressionABC(abc.ABC, FunctionParams):
38
41
  uncomputation_method: UncomputationMethods = UncomputationMethods.optimized
39
- machine_precision: pydantic.NonNegativeInt = number_utils.MAX_FRACTION_PLACES
42
+ machine_precision: pydantic.NonNegativeInt = DEFAULT_MACHINE_PRECISION
40
43
  expression: PydanticExpressionStr
41
- definitions: Dict[str, ValidDefinitions]
44
+ definitions: dict[str, ValidDefinitions]
42
45
  qubit_count: Optional[pydantic.NonNegativeInt] = None
43
46
 
44
- def _get_literal_set(self) -> Set[str]:
47
+ def _get_literal_set(self) -> set[str]:
45
48
  return _extract_literals(self.expression)
46
49
 
47
- @pydantic.validator("definitions")
50
+ @classmethod
48
51
  def _validate_expression_literals_and_definitions(
49
- cls, definitions: Dict[str, ValidDefinitions], values: Dict[str, Any]
50
- ) -> Dict[str, ValidDefinitions]:
51
- expression = values.get("expression")
52
- if expression is None:
53
- return definitions
54
-
52
+ cls, definitions: dict[str, ValidDefinitions], expression: PydanticExpressionStr
53
+ ) -> dict[str, ValidDefinitions]:
55
54
  literals = _extract_literals(expression)
56
55
 
57
56
  forbidden = literals.intersection(FORBIDDEN_LITERALS)
@@ -68,12 +67,33 @@ class ArithmeticExpressionABC(abc.ABC, FunctionParams):
68
67
  raise ClassiqValueError(f"The following names are undefined: {undefined}")
69
68
  return definitions
70
69
 
71
- @pydantic.root_validator
72
- def _validate_expression(cls, values: Dict[str, Any]) -> Dict[str, Any]:
73
- expression: Optional[str] = values.get("expression")
74
- definitions: Optional[Dict[str, ValidDefinitions]] = values.get("definitions")
75
- machine_precision: Optional[int] = values.get("machine_precision")
76
- if expression is None or definitions is None or machine_precision is None:
70
+ @pydantic.model_validator(mode="before")
71
+ @classmethod
72
+ def _validate_expression(cls, values: Any) -> dict[str, Any]:
73
+ if not isinstance(values, dict):
74
+ return values
75
+ expression_adapter: TypeAdapter = TypeAdapter(Optional[PydanticExpressionStr])
76
+ expression = expression_adapter.validate_python(values.get("expression"))
77
+ definitions_adapter: TypeAdapter = TypeAdapter(
78
+ Optional[dict[str, ValidDefinitions]]
79
+ )
80
+ definition_dict = values.get("definitions")
81
+ if (
82
+ isinstance(definition_dict, list)
83
+ and len(definition_dict) > 0
84
+ and isinstance(definition_dict[0], tuple)
85
+ ):
86
+ definition_dict = dict(definition_dict)
87
+ definitions = definitions_adapter.validate_python(definition_dict)
88
+ machine_precision: Optional[int] = values.get(
89
+ "machine_precision", DEFAULT_MACHINE_PRECISION
90
+ )
91
+ if (
92
+ expression is None
93
+ or expression == ""
94
+ or definitions is None
95
+ or machine_precision is None
96
+ ):
77
97
  return values
78
98
 
79
99
  try:
@@ -85,15 +105,39 @@ class ArithmeticExpressionABC(abc.ABC, FunctionParams):
85
105
  cls._validate_ast_obj(ast_obj)
86
106
 
87
107
  graph = parse_expression(expression)
88
- cls._validate_expression_graph(graph, values)
108
+ try:
109
+ cls._validate_expression_graph(graph, values)
110
+ except ClassiqValueError as e:
111
+ # This flow was created specifically for inplace Boolean XOR operations like q1 ^ q2.
112
+ # We can't plug equality in previous stages due to SymPy restrictions.
113
+ # Note that we don't validate that the expression itself is Boolean (passing non-Boolean expressions
114
+ # as inplace is currently not supported, so it's a bug).
115
+ if not e.raw_message == "Expression does not support target assignment":
116
+ raise
117
+ ast_parsed_expression = ast.parse(expression)
118
+ ast_expr = ast_parsed_expression.body[0]
119
+ if (
120
+ not isinstance(ast_expr, ast.Expr)
121
+ or not isinstance(ast_expr.value, ast.BinOp)
122
+ or not isinstance(ast_expr.value.op, ast.BitXor)
123
+ ):
124
+ raise
125
+ expression = f"({expression}) == 1"
126
+ graph = parse_expression(expression)
127
+ cls._validate_expression_graph(graph, values)
128
+
129
+ validated_defs = cls._validate_expression_literals_and_definitions(
130
+ definitions, expression
131
+ )
132
+
89
133
  validate_arithmetic_result_type(
90
134
  graph=graph,
91
- definitions=definitions,
135
+ definitions=validated_defs,
92
136
  machine_precision=machine_precision,
93
137
  )
94
138
 
95
139
  new_expr, new_defs = cls._replace_const_definitions_in_expression(
96
- expression, definitions, machine_precision
140
+ expression, validated_defs, machine_precision
97
141
  )
98
142
  values["expression"] = new_expr
99
143
  values["definitions"] = new_defs
@@ -104,16 +148,16 @@ class ArithmeticExpressionABC(abc.ABC, FunctionParams):
104
148
  pass
105
149
 
106
150
  @staticmethod
107
- def _validate_expression_graph(graph: nx.DiGraph, values: Dict[str, Any]) -> None:
151
+ def _validate_expression_graph(graph: nx.DiGraph, values: dict[str, Any]) -> None:
108
152
  pass
109
153
 
110
154
  @classmethod
111
155
  def _replace_const_definitions_in_expression(
112
156
  cls,
113
157
  expression: str,
114
- definitions: Dict[str, ValidDefinitions],
158
+ definitions: dict[str, ValidDefinitions],
115
159
  machine_precision: int,
116
- ) -> Tuple[str, Dict[str, RegisterArithmeticInfo]]:
160
+ ) -> tuple[str, dict[str, RegisterArithmeticInfo]]:
117
161
  new_definitions = dict()
118
162
  for var_name, value in definitions.items():
119
163
  if isinstance(value, RegisterArithmeticInfo):
@@ -138,5 +182,5 @@ class ArithmeticExpressionABC(abc.ABC, FunctionParams):
138
182
  return re.sub(r"\b" + var + r"\b", str(value), expression)
139
183
 
140
184
 
141
- def _extract_literals(expression: str) -> Set[str]:
185
+ def _extract_literals(expression: str) -> set[str]:
142
186
  return set(re.findall(SUPPORTED_VAR_NAMES_REG, expression)) - SUPPORTED_FUNC_NAMES
@@ -1,9 +1,11 @@
1
1
  import ast
2
2
  from _ast import AST
3
- from typing import Collection, List, Optional, Set, Tuple, Type, Union, cast
3
+ from collections.abc import Collection
4
+ from typing import Optional, Union, cast
4
5
 
5
6
  import networkx as nx
6
7
 
8
+ from classiq.interface.exceptions import ClassiqArithmeticError
7
9
  from classiq.interface.generator.arith.arithmetic_expression_validator import (
8
10
  DEFAULT_EXPRESSION_TYPE,
9
11
  DEFAULT_SUPPORTED_FUNC_NAMES,
@@ -16,10 +18,10 @@ from classiq.interface.generator.arith.ast_node_rewrite import (
16
18
  AstNodeRewrite,
17
19
  )
18
20
 
19
- from classiq.exceptions import ClassiqArithmeticError
20
-
21
- _MULTIPLE_RESULTS_ERROR_MESSAGE: str = "Expression cannot contain multiple result"
22
- _TRIVIAL_ARITHMETIC_ERROR_MESSAGE: str = "Expression must be nontrivial"
21
+ _MULTIPLE_RESULTS_ERROR_MESSAGE: str = "Expression cannot contain multiple results"
22
+ _UNEXPECTED_ARITHMETIC_ERROR_MESSAGE: str = (
23
+ "Quantum expressions that evaluate to a classical value are not supported"
24
+ )
23
25
  _ALLOWED_MULTI_ARGUMENT_FUNCTIONS = ("min", "max")
24
26
  Node = Union[str, float, int]
25
27
 
@@ -27,13 +29,17 @@ Node = Union[str, float, int]
27
29
  class ExpressionVisitor(ExpressionValidator):
28
30
  def __init__(
29
31
  self,
30
- supported_nodes: Tuple[Type[AST], ...],
32
+ supported_nodes: tuple[type[AST], ...],
31
33
  expression_type: str = DEFAULT_EXPRESSION_TYPE,
32
- supported_functions: Optional[Set[str]] = None,
34
+ supported_functions: Optional[set[str]] = None,
33
35
  ) -> None:
34
36
  super().__init__(supported_nodes, expression_type, supported_functions)
35
37
  self.graph = nx.DiGraph()
36
38
 
39
+ @classmethod
40
+ def rewrite_ast(cls, expression_ast: AST) -> AST:
41
+ return AstNodeRewrite().visit(expression_ast)
42
+
37
43
  def visit_Compare(self, node: ast.Compare) -> None:
38
44
  self.validate_Compare(node)
39
45
  self.update_graph(node, node.left, node.comparators[0])
@@ -85,8 +91,8 @@ class ExpressionVisitor(ExpressionValidator):
85
91
  class InDegreeLimiter:
86
92
  @staticmethod
87
93
  def _sort_in_edges(
88
- in_edges: Collection[Tuple[Node, str]]
89
- ) -> List[Tuple[Node, str]]:
94
+ in_edges: Collection[tuple[Node, str]]
95
+ ) -> list[tuple[Node, str]]:
90
96
  return sorted(
91
97
  in_edges,
92
98
  key=lambda edge_tuple: isinstance(edge_tuple[0], str), # vars before consts
@@ -122,16 +128,16 @@ class InDegreeLimiter:
122
128
  if num_results > 1:
123
129
  raise ClassiqArithmeticError(_MULTIPLE_RESULTS_ERROR_MESSAGE)
124
130
  elif num_results == 0:
125
- raise ClassiqArithmeticError(_TRIVIAL_ARITHMETIC_ERROR_MESSAGE)
131
+ raise ClassiqArithmeticError(_UNEXPECTED_ARITHMETIC_ERROR_MESSAGE)
126
132
  return graph
127
133
 
128
134
 
129
135
  def parse_expression(
130
136
  expression: str,
131
137
  *,
132
- supported_nodes: Tuple[Type[AST], ...] = DEFAULT_SUPPORTED_NODE_TYPES,
138
+ supported_nodes: tuple[type[AST], ...] = DEFAULT_SUPPORTED_NODE_TYPES,
133
139
  expression_type: str = DEFAULT_EXPRESSION_TYPE,
134
- supported_functions: Optional[Set[str]] = None,
140
+ supported_functions: Optional[set[str]] = None,
135
141
  ) -> nx.DiGraph:
136
142
  supported_functions = supported_functions or DEFAULT_SUPPORTED_FUNC_NAMES
137
143
 
@@ -1,24 +1,23 @@
1
1
  import ast
2
- import builtins
2
+ import re
3
3
  from _ast import AST
4
- from typing import Any, Optional, Set, Tuple, Type, Union
4
+ from typing import Any, Optional, Union
5
5
 
6
- from typing_extensions import get_args
6
+ from sympy import Expr
7
+ from typing_extensions import TypeAlias, get_args
7
8
 
9
+ from classiq.interface.exceptions import ClassiqArithmeticError, ClassiqValueError
8
10
  from classiq.interface.generator.arith.ast_node_rewrite import AstNodeRewrite
9
11
  from classiq.interface.generator.expressions.sympy_supported_expressions import (
10
12
  SYMPY_SUPPORTED_EXPRESSIONS,
11
13
  )
12
14
 
13
- from classiq.exceptions import ClassiqArithmeticError, ClassiqValueError
14
-
15
- DEFAULT_SUPPORTED_FUNC_NAMES: Set[str] = {"CLShift", "CRShift", "min", "max"}
15
+ DEFAULT_SUPPORTED_FUNC_NAMES: set[str] = {"CLShift", "CRShift", "min", "max"}
16
16
 
17
17
  DEFAULT_EXPRESSION_TYPE = "arithmetic"
18
+ IDENITIFIER_REGEX = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
18
19
 
19
- _REPEATED_VARIABLES_ERROR_MESSAGE: str = (
20
- "Repeated variables in the beginning of an arithmetic expression are not allowed."
21
- )
20
+ ValidKeyValuePairs: TypeAlias = dict[str, set[str]]
22
21
 
23
22
  SupportedNodesTypes = Union[
24
23
  ast.Expression,
@@ -56,49 +55,75 @@ SupportedNodesTypes = Union[
56
55
  DEFAULT_SUPPORTED_NODE_TYPES = get_args(SupportedNodesTypes)
57
56
 
58
57
 
58
+ def is_constant(expr: Union[str, Expr]) -> bool:
59
+ try:
60
+ float(expr)
61
+ return True
62
+ except (ValueError, TypeError):
63
+ return False
64
+
65
+
59
66
  class ExpressionValidator(ast.NodeVisitor):
60
67
  def __init__(
61
68
  self,
62
- supported_nodes: Tuple[Type[AST], ...],
69
+ supported_nodes: tuple[type[AST], ...],
63
70
  expression_type: str = DEFAULT_EXPRESSION_TYPE,
64
- supported_functions: Optional[Set[str]] = None,
65
- supported_attr_values: Optional[Set[str]] = None,
71
+ supported_functions: Optional[set[str]] = None,
66
72
  mode: str = "eval",
67
73
  ) -> None:
68
74
  super().__init__()
69
75
  self.supported_nodes = supported_nodes
70
76
  self._expression_type = expression_type
71
77
  self._supported_functions = supported_functions or DEFAULT_SUPPORTED_FUNC_NAMES
72
- self._supported_attr_values = supported_attr_values or set()
73
78
  self._mode = mode
74
79
  self._ast_obj: Optional[ast.AST] = None
75
80
 
76
81
  def validate(self, expression: str) -> None:
77
82
  try:
78
- ast_expr = ast.parse(expression, filename="", mode=self._mode)
83
+ adjusted_expression = self._get_adjusted_expression(expression)
84
+ ast_expr = ast.parse(adjusted_expression, filename="", mode=self._mode)
79
85
  except SyntaxError as e:
80
86
  raise ClassiqValueError(f"Failed to parse expression {expression!r}") from e
81
87
  try:
82
- self._ast_obj = AstNodeRewrite().visit(ast_expr)
88
+ self._ast_obj = self.rewrite_ast(ast_expr)
83
89
  self.visit(self._ast_obj)
84
90
  except RecursionError as e:
85
91
  raise ClassiqValueError(
86
92
  f"Failed to parse expression since it is too long: {expression}"
87
93
  ) from e
88
94
 
95
+ @staticmethod
96
+ def _get_adjusted_expression(expression: str) -> str:
97
+ # This works around the simplification of the trivial expressions such as a + 0, 1 * a, etc.
98
+ if IDENITIFIER_REGEX.fullmatch(expression) or is_constant(expression):
99
+ return f"0 + {expression}"
100
+ return expression
101
+
89
102
  @property
90
103
  def ast_obj(self) -> ast.AST:
91
104
  if not self._ast_obj:
92
105
  raise ClassiqArithmeticError("Must call `validate` before getting ast_obj")
93
106
  return self._ast_obj
94
107
 
95
- @staticmethod
96
- def _check_repeated_variables(variables: Tuple[Any, Any]) -> None:
108
+ def _check_repeated_variables(
109
+ self, variables: tuple[Any, Any], expr: ast.AST, error_suffix: str
110
+ ) -> None:
111
+ if (
112
+ isinstance(expr, ast.BinOp)
113
+ and isinstance(expr.op, ast.Pow)
114
+ and ast.Pow not in self.supported_nodes
115
+ ):
116
+ raise ClassiqValueError(
117
+ "Raising to a power (<var> ** <exp>) and multiplying a variable by "
118
+ "itself (<var> * <var>) are not supported"
119
+ )
97
120
  if (
98
121
  all(isinstance(var, ast.Name) for var in variables)
99
122
  and variables[0].id == variables[1].id
100
123
  ):
101
- raise ClassiqValueError(_REPEATED_VARIABLES_ERROR_MESSAGE)
124
+ raise ClassiqValueError(
125
+ f"Expression {ast.unparse(expr)!r} is not supported ({error_suffix})"
126
+ )
102
127
 
103
128
  @staticmethod
104
129
  def _check_multiple_comparators(node: ast.Compare) -> None:
@@ -120,7 +145,11 @@ class ExpressionValidator(ast.NodeVisitor):
120
145
  )
121
146
 
122
147
  def validate_Compare(self, node: ast.Compare) -> None: # noqa: N802
123
- self._check_repeated_variables((node.left, node.comparators[0]))
148
+ self._check_repeated_variables(
149
+ (node.left, node.comparators[0]),
150
+ node,
151
+ "both sides of the comparison are identical",
152
+ )
124
153
  self._check_multiple_comparators(node)
125
154
 
126
155
  def visit_Compare(self, node: ast.Compare) -> None:
@@ -128,7 +157,9 @@ class ExpressionValidator(ast.NodeVisitor):
128
157
  self.generic_visit(node)
129
158
 
130
159
  def validate_BinOp(self, node: ast.BinOp) -> None: # noqa: N802
131
- self._check_repeated_variables((node.left, node.right))
160
+ self._check_repeated_variables(
161
+ (node.left, node.right), node, "both sides of the operation are identical"
162
+ )
132
163
 
133
164
  def visit_BinOp(self, node: ast.BinOp) -> None:
134
165
  self.validate_BinOp(node)
@@ -136,7 +167,11 @@ class ExpressionValidator(ast.NodeVisitor):
136
167
 
137
168
  def validate_Call(self, node: ast.Call) -> None: # noqa: N802
138
169
  if len(node.args) >= 2:
139
- self._check_repeated_variables((node.args[0], node.args[1]))
170
+ self._check_repeated_variables(
171
+ (node.args[0], node.args[1]),
172
+ node,
173
+ "the first two call arguments are identical",
174
+ )
140
175
  node_id = AstNodeRewrite().extract_node_id(node)
141
176
  if node_id not in self._supported_functions:
142
177
  raise ClassiqValueError(f"{node_id} not in supported functions")
@@ -160,36 +195,20 @@ class ExpressionValidator(ast.NodeVisitor):
160
195
  self.validate_Constant(node)
161
196
  self.generic_visit(node)
162
197
 
163
- def validate_Attribute(self, node: ast.Attribute) -> None: # noqa: N802
164
- if not (
165
- isinstance(node.value, ast.Name)
166
- and node.value.id in self._supported_attr_values
167
- ):
168
- raise ClassiqValueError(
169
- f"Attribute is not supported for value {node.value}"
170
- )
171
-
172
198
  def visit_Attribute(self, node: ast.Attribute) -> None:
173
- self.validate_Attribute(node)
174
199
  self.generic_visit(node)
175
200
 
176
- def visit_FunctionDef(self, node: ast.FunctionDef) -> Any:
177
- if self._mode == "exec":
178
- if hasattr(builtins, node.name):
179
- raise ClassiqValueError(
180
- f"Defining a function named {node.name} is forbidden"
181
- )
182
- self._supported_functions.add(node.name)
183
- self.generic_visit(node)
201
+ @classmethod
202
+ def rewrite_ast(cls, expression_ast: AST) -> AST:
203
+ return expression_ast
184
204
 
185
205
 
186
206
  def validate_expression(
187
207
  expression: str,
188
208
  *,
189
- supported_nodes: Tuple[Type[AST], ...] = DEFAULT_SUPPORTED_NODE_TYPES,
209
+ supported_nodes: tuple[type[AST], ...] = DEFAULT_SUPPORTED_NODE_TYPES,
190
210
  expression_type: str = DEFAULT_EXPRESSION_TYPE,
191
- supported_functions: Optional[Set[str]] = None,
192
- supported_attr_values: Optional[Set[str]] = None,
211
+ supported_functions: Optional[set[str]] = None,
193
212
  mode: str = "eval",
194
213
  ) -> ast.AST:
195
214
  supported_functions = supported_functions or set(SYMPY_SUPPORTED_EXPRESSIONS).union(
@@ -199,7 +218,6 @@ def validate_expression(
199
218
  supported_nodes,
200
219
  expression_type,
201
220
  supported_functions,
202
- supported_attr_values,
203
221
  mode,
204
222
  )
205
223
  validator.validate(expression)
@@ -1,20 +1,25 @@
1
- from __future__ import annotations
2
-
3
1
  import abc
4
- from typing import ClassVar, Iterable, Optional, Tuple
2
+ from collections.abc import Iterable
3
+ from typing import ClassVar, Final, Optional
5
4
 
6
5
  import pydantic
7
6
 
8
- from classiq.interface.generator.arith import argument_utils, number_utils
7
+ from classiq.interface.generator.arith.machine_precision import (
8
+ DEFAULT_MACHINE_PRECISION,
9
+ )
9
10
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
10
11
  from classiq.interface.generator.function_params import FunctionParams
11
12
 
12
- DEFAULT_GARBAGE_OUT_NAME: str = "extra_qubits"
13
+ IMPLICIT_OUTPUTS: Final[str] = "implicit_outputs"
14
+ DEFAULT_GARBAGE_OUT_NAME: Final[str] = "extra_qubits"
15
+ MODULO_WITH_FRACTION_PLACES_ERROR_MSG: Final[str] = (
16
+ "Modulo with fraction places not supported"
17
+ )
13
18
 
14
19
 
15
20
  class ArithmeticOperationParams(FunctionParams):
16
- output_size: Optional[pydantic.PositiveInt]
17
- machine_precision: pydantic.PositiveInt = number_utils.MAX_FRACTION_PLACES
21
+ output_size: Optional[pydantic.PositiveInt] = pydantic.Field(default=None)
22
+ machine_precision: pydantic.PositiveInt = DEFAULT_MACHINE_PRECISION
18
23
  output_name: ClassVar[str]
19
24
  garbage_output_name: ClassVar[str] = DEFAULT_GARBAGE_OUT_NAME
20
25
  _result_register: Optional[RegisterArithmeticInfo] = pydantic.PrivateAttr(
@@ -40,17 +45,15 @@ class ArithmeticOperationParams(FunctionParams):
40
45
  return self.output_size is None
41
46
 
42
47
  def _legal_bounds(
43
- self, suggested_bounds: Tuple[float, float]
44
- ) -> Optional[Tuple[float, float]]:
45
- if self._include_sign or min(suggested_bounds) >= 0:
48
+ self, suggested_bounds: tuple[float, float], max_bounds: tuple[float, float]
49
+ ) -> Optional[tuple[float, float]]:
50
+ if self.output_size is None or (
51
+ suggested_bounds[0] >= max_bounds[0]
52
+ and suggested_bounds[1] <= max_bounds[1]
53
+ ):
46
54
  return suggested_bounds
47
55
  return None
48
56
 
49
- def _compute_fraction_places(self, argument: argument_utils.RegisterOrConst) -> int:
50
- return argument_utils.fraction_places(
51
- argument, machine_precision=self.machine_precision
52
- )
53
-
54
57
  @abc.abstractmethod
55
- def get_params_inplace_options(self) -> Iterable[ArithmeticOperationParams]:
58
+ def get_params_inplace_options(self) -> Iterable["ArithmeticOperationParams"]:
56
59
  pass
@@ -1,5 +1,6 @@
1
- from typing import Callable, Dict, FrozenSet, List, Optional
1
+ from typing import Callable, Optional
2
2
 
3
+ from classiq.interface.exceptions import ClassiqArithmeticError
3
4
  from classiq.interface.generator.arith.argument_utils import (
4
5
  RegisterOrConst as RegisterOrFloat,
5
6
  )
@@ -35,12 +36,10 @@ from classiq.interface.generator.arith.logical_ops import LogicalAnd, LogicalOr
35
36
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
36
37
  from classiq.interface.generator.arith.unary_ops import BitwiseInvert, Negation
37
38
 
38
- from classiq.exceptions import ClassiqArithmeticError
39
-
40
39
  ParamsGetter = Callable[..., ArithmeticOperationParams] # Argument vary
41
40
 
42
41
  _TARGET_ERROR_MESSAGE: str = "Target unavailable for the requested operation"
43
- _OPERATIONS_ALLOWING_TARGET: FrozenSet = frozenset(
42
+ _OPERATIONS_ALLOWING_TARGET: frozenset = frozenset(
44
43
  {"And", "Or", "Eq", "NotEq", "Lt", "Gt", "LtE", "GtE"}
45
44
  )
46
45
 
@@ -56,7 +55,7 @@ def operation_allows_target(operation: str) -> bool:
56
55
  def get_params(
57
56
  *,
58
57
  node_id: str,
59
- args: List[RegisterOrFloat],
58
+ args: list[RegisterOrFloat],
60
59
  machine_precision: int,
61
60
  output_size: Optional[int] = None,
62
61
  inplace_arg: Optional[str] = None,
@@ -331,7 +330,7 @@ def less_equal_params_getter(
331
330
 
332
331
 
333
332
  def logical_and_params_getter(
334
- *arg: List[RegisterOrFloat],
333
+ *arg: list[RegisterOrFloat],
335
334
  machine_precision: int,
336
335
  output_size: Optional[int] = None,
337
336
  inplace_arg: Optional[str] = None,
@@ -341,7 +340,7 @@ def logical_and_params_getter(
341
340
 
342
341
 
343
342
  def logical_or_params_getter(
344
- *arg: List[RegisterOrFloat],
343
+ *arg: list[RegisterOrFloat],
345
344
  machine_precision: int,
346
345
  output_size: Optional[int] = None,
347
346
  inplace_arg: Optional[str] = None,
@@ -435,7 +434,7 @@ def modulo_params_getter(
435
434
  )
436
435
 
437
436
 
438
- params_getter_map: Dict[str, ParamsGetter] = dict(
437
+ params_getter_map: dict[str, ParamsGetter] = dict(
439
438
  BitOr=or_params_getter,
440
439
  BitAnd=and_params_getter,
441
440
  BitXor=xor_params_getter,
@@ -1,15 +1,14 @@
1
- from typing import Any, Dict, List, Optional, Set
1
+ from typing import Any, Optional
2
2
 
3
3
  import networkx as nx
4
4
 
5
+ from classiq.interface.exceptions import ClassiqArithmeticError
5
6
  from classiq.interface.generator.arith import arithmetic_param_getters, number_utils
6
7
  from classiq.interface.generator.arith.argument_utils import RegisterOrConst
7
8
  from classiq.interface.generator.arith.ast_node_rewrite import OUTPUT_SIZE
8
9
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
9
10
 
10
- from classiq.exceptions import ClassiqArithmeticError
11
-
12
- ArithmeticDefinitions = Dict[str, RegisterOrConst]
11
+ ArithmeticDefinitions = dict[str, RegisterOrConst]
13
12
 
14
13
 
15
14
  class ArithmeticResultBuilder:
@@ -20,7 +19,7 @@ class ArithmeticResultBuilder:
20
19
  definitions: ArithmeticDefinitions,
21
20
  machine_precision: int,
22
21
  ) -> None:
23
- self.result = self._fill_operation_results(
22
+ self.result, self.garbage = self._fill_operation_results(
24
23
  graph=graph,
25
24
  result_definitions=definitions,
26
25
  machine_precision=machine_precision,
@@ -44,10 +43,10 @@ class ArithmeticResultBuilder:
44
43
  def _compute_inputs_data(
45
44
  cls,
46
45
  *,
47
- inputs_node_set: Set[Any],
46
+ inputs_node_set: set[Any],
48
47
  result_definitions: ArithmeticDefinitions,
49
48
  machine_precision: int,
50
- ) -> Dict[str, RegisterOrConst]:
49
+ ) -> dict[str, RegisterOrConst]:
51
50
  return {
52
51
  cls._convert_int_to_float_str(node): cls.convert_result_definition(
53
52
  node, result_definitions.get(node), machine_precision
@@ -62,11 +61,11 @@ class ArithmeticResultBuilder:
62
61
  graph: nx.DiGraph,
63
62
  result_definitions: ArithmeticDefinitions,
64
63
  machine_precision: int,
65
- ) -> RegisterArithmeticInfo:
66
- inputs_node_set: Set[str] = {
64
+ ) -> tuple[RegisterArithmeticInfo, Optional[RegisterArithmeticInfo]]:
65
+ inputs_node_set: set[str] = {
67
66
  vertex for vertex, deg in graph.in_degree if deg == 0
68
67
  }
69
- node_results: Dict[str, RegisterOrConst] = cls._compute_inputs_data(
68
+ node_results: dict[str, RegisterOrConst] = cls._compute_inputs_data(
70
69
  inputs_node_set=inputs_node_set,
71
70
  result_definitions=result_definitions,
72
71
  machine_precision=machine_precision,
@@ -80,29 +79,34 @@ class ArithmeticResultBuilder:
80
79
  for predecessor_node in graph.predecessors(node)
81
80
  ]
82
81
  if graph.out_degree(node) == 0:
83
- return cls._get_node_result(
82
+ return cls._get_node_result_and_garbage(
84
83
  graph, args, node, machine_precision=machine_precision
85
84
  )
86
- node_results[node] = cls._get_node_result(
85
+ node_results[node], _ = cls._get_node_result_and_garbage(
87
86
  graph, args, node, machine_precision=machine_precision
88
87
  )
89
88
  raise ClassiqArithmeticError("Expression has no result")
90
89
 
91
90
  @classmethod
92
- def _get_node_result(
91
+ def _get_node_result_and_garbage(
93
92
  cls,
94
93
  graph: nx.DiGraph,
95
- args: List[RegisterOrConst],
94
+ args: list[RegisterOrConst],
96
95
  node: str,
97
96
  *,
98
97
  machine_precision: int,
99
- ) -> RegisterArithmeticInfo:
100
- return arithmetic_param_getters.get_params(
98
+ ) -> tuple[RegisterArithmeticInfo, Optional[RegisterArithmeticInfo]]:
99
+ node_params = arithmetic_param_getters.get_params(
101
100
  node_id=node,
102
101
  args=args,
103
102
  output_size=graph.nodes[node].get(OUTPUT_SIZE, None),
104
103
  machine_precision=machine_precision,
105
- ).result_register
104
+ )
105
+
106
+ return (
107
+ node_params.outputs[node_params.output_name],
108
+ node_params.outputs.get(node_params.garbage_output_name),
109
+ )
106
110
 
107
111
  @staticmethod
108
112
  def _convert_int_to_float_str(node: Any) -> str: