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,23 +1,29 @@
1
1
  import math
2
+ from collections.abc import Iterable
2
3
  from typing import (
3
4
  Any,
4
5
  ClassVar,
5
- Dict,
6
6
  Generic,
7
- Iterable,
8
7
  Literal,
9
8
  Optional,
10
- Tuple,
11
9
  TypeVar,
12
10
  Union,
13
11
  )
14
12
 
15
13
  import pydantic
16
- from pydantic.generics import GenericModel
14
+ from pydantic import BaseModel
15
+ from pydantic_core.core_schema import ValidationInfo
16
+ from typing_extensions import Self
17
17
 
18
+ from classiq.interface.enum_utils import StrEnum
19
+ from classiq.interface.exceptions import ClassiqValueError
18
20
  from classiq.interface.generator.arith import argument_utils, number_utils
19
- from classiq.interface.generator.arith.argument_utils import RegisterOrConst
21
+ from classiq.interface.generator.arith.argument_utils import (
22
+ RegisterOrConst,
23
+ as_arithmetic_info,
24
+ )
20
25
  from classiq.interface.generator.arith.arithmetic_operations import (
26
+ MODULO_WITH_FRACTION_PLACES_ERROR_MSG,
21
27
  ArithmeticOperationParams,
22
28
  )
23
29
  from classiq.interface.generator.arith.ast_node_rewrite import (
@@ -27,8 +33,6 @@ from classiq.interface.generator.arith.register_user_input import RegisterArithm
27
33
  from classiq.interface.generator.arith.unary_ops import Negation
28
34
  from classiq.interface.generator.function_params import get_zero_input_name
29
35
 
30
- from classiq._internals.enum_utils import StrEnum
31
-
32
36
  LeftDataT = TypeVar("LeftDataT")
33
37
  RightDataT = TypeVar("RightDataT")
34
38
  _NumericArgumentInplaceErrorMessage: str = "Cannot inplace the numeric argument {}"
@@ -49,35 +53,49 @@ class ArgToInplace(StrEnum):
49
53
 
50
54
 
51
55
  class BinaryOpParams(
52
- ArithmeticOperationParams, GenericModel, Generic[LeftDataT, RightDataT]
56
+ ArithmeticOperationParams, BaseModel, Generic[LeftDataT, RightDataT]
53
57
  ):
54
58
  left_arg: LeftDataT
55
59
  right_arg: RightDataT
56
60
  left_arg_name: ClassVar[str] = DEFAULT_LEFT_ARG_NAME
57
61
  right_arg_name: ClassVar[str] = DEFAULT_RIGHT_ARG_NAME
58
62
 
59
- @pydantic.root_validator(pre=True)
60
- def _validate_one_is_register(cls, values: Dict[str, Any]) -> Dict[str, Any]:
61
- left_arg = values.get("left_arg")
62
- right_arg = values.get("right_arg")
63
- if isinstance(left_arg, Numeric) and isinstance(right_arg, Numeric):
64
- raise ValueError("One argument must be a register")
65
- if left_arg is right_arg and isinstance(left_arg, pydantic.BaseModel):
66
- # In case both arguments refer to the same object, copy it.
67
- # This prevents changes performed on one argument to affect the other.
68
- values["right_arg"] = left_arg.copy(deep=True)
63
+ @pydantic.model_validator(mode="before")
64
+ @classmethod
65
+ def _clone_repeated_arg(cls, values: Any) -> dict[str, Any]:
66
+ if isinstance(values, dict):
67
+ left_arg = values.get("left_arg")
68
+ right_arg = values.get("right_arg")
69
+
70
+ if left_arg is right_arg and isinstance(left_arg, pydantic.BaseModel):
71
+ # In case both arguments refer to the same object, copy it.
72
+ # This prevents changes performed on one argument to affect the other.
73
+ values["right_arg"] = left_arg.model_copy(deep=True)
69
74
  return values
70
75
 
76
+ def garbage_output_size(self) -> pydantic.NonNegativeInt:
77
+ return 0
78
+
71
79
  def _create_ios(self) -> None:
72
80
  self._inputs = dict()
73
81
  if isinstance(self.left_arg, RegisterArithmeticInfo):
74
82
  self._inputs[self.left_arg_name] = self.left_arg
75
83
  if isinstance(self.right_arg, RegisterArithmeticInfo):
76
84
  self._inputs[self.right_arg_name] = self.right_arg
77
- zero_input_name = get_zero_input_name(self.output_name)
78
- self._zero_inputs = {zero_input_name: self.result_register}
79
85
  self._outputs = {**self._inputs, self.output_name: self.result_register}
80
86
 
87
+ garbage_size = self.garbage_output_size()
88
+ if garbage_size > 0:
89
+ self._outputs[self.garbage_output_name] = RegisterArithmeticInfo(
90
+ size=garbage_size
91
+ )
92
+
93
+ zero_input_name = get_zero_input_name(self.output_name)
94
+ zero_input_size = self.result_register.size + garbage_size
95
+ self._zero_inputs = {
96
+ zero_input_name: RegisterArithmeticInfo(size=zero_input_size)
97
+ }
98
+
81
99
  def is_inplaced(self) -> bool:
82
100
  return False
83
101
 
@@ -90,24 +108,25 @@ class InplacableBinaryOpParams(
90
108
  ):
91
109
  inplace_arg: Optional[ArgToInplace] = None
92
110
 
93
- @pydantic.root_validator(pre=True)
94
- def _validate_inplace_arg(cls, values: Dict[str, Any]) -> Dict[str, Any]:
95
- left_arg = values.get("left_arg")
96
- right_arg = values.get("right_arg")
97
- inplace_arg: Optional[ArgToInplace] = values.get("inplace_arg")
98
- if inplace_arg == ArgToInplace.RIGHT and isinstance(right_arg, Numeric):
99
- raise ValueError(_NumericArgumentInplaceErrorMessage.format(right_arg))
100
- elif inplace_arg == ArgToInplace.LEFT and isinstance(left_arg, Numeric):
101
- raise ValueError(_NumericArgumentInplaceErrorMessage.format(left_arg))
111
+ @pydantic.model_validator(mode="before")
112
+ @classmethod
113
+ def _validate_inplace_arg(cls, values: Any) -> dict[str, Any]:
114
+ if isinstance(values, dict):
115
+ left_arg = values.get("left_arg")
116
+ right_arg = values.get("right_arg")
117
+ inplace_arg: Optional[ArgToInplace] = values.get("inplace_arg")
118
+ if inplace_arg == ArgToInplace.RIGHT and isinstance(right_arg, Numeric):
119
+ raise ClassiqValueError(
120
+ _NumericArgumentInplaceErrorMessage.format(right_arg)
121
+ )
122
+ elif inplace_arg == ArgToInplace.LEFT and isinstance(left_arg, Numeric):
123
+ raise ClassiqValueError(
124
+ _NumericArgumentInplaceErrorMessage.format(left_arg)
125
+ )
102
126
  return values
103
127
 
104
128
  def _create_ios(self) -> None:
105
129
  BinaryOpParams._create_ios(self)
106
- garbage_size = self.garbage_output_size()
107
- if garbage_size > 0:
108
- self._outputs[self.garbage_output_name] = RegisterArithmeticInfo(
109
- size=garbage_size
110
- )
111
130
  if self.inplace_arg is None:
112
131
  return
113
132
  inplace_arg_name = (
@@ -117,7 +136,7 @@ class InplacableBinaryOpParams(
117
136
  )
118
137
  self._outputs.pop(inplace_arg_name)
119
138
 
120
- self._set_inplace_zero_inputs(inplace_arg_name, garbage_size)
139
+ self._set_inplace_zero_inputs(inplace_arg_name, self.garbage_output_size())
121
140
 
122
141
  def _set_inplace_zero_inputs(
123
142
  self, inplace_arg_name: str, garbage_size: int
@@ -140,9 +159,13 @@ class InplacableBinaryOpParams(
140
159
  if self.inplace_arg is None:
141
160
  return 0
142
161
  arg = self.left_arg if self.inplace_arg == ArgToInplace.LEFT else self.right_arg
143
- return max(0, arg.integer_part_size - self.result_register.integer_part_size) # type: ignore[attr-defined]
162
+ return max(
163
+ 0, arg.integer_part_size - self.result_register.integer_part_size # type: ignore[attr-defined]
164
+ ) + max(
165
+ 0, arg.fraction_places - self.result_register.fraction_places # type: ignore[attr-defined]
166
+ )
144
167
 
145
- def _carried_arguments(self) -> Tuple[Optional[LeftDataT], Optional[RightDataT]]:
168
+ def _carried_arguments(self) -> tuple[Optional[LeftDataT], Optional[RightDataT]]:
146
169
  if self.inplace_arg == ArgToInplace.RIGHT and isinstance(
147
170
  self.left_arg, RegisterArithmeticInfo
148
171
  ):
@@ -173,28 +196,28 @@ class InplacableBinaryOpParams(
173
196
  yield ArgToInplace.LEFT
174
197
 
175
198
  def get_params_inplace_options(self) -> Iterable["InplacableBinaryOpParams"]:
176
- params_kwargs = self.copy().__dict__
199
+ params_kwargs = self.model_copy().__dict__
177
200
  for inplace_arg in self._get_binary_op_inplace_options():
178
201
  params_kwargs["inplace_arg"] = inplace_arg
179
202
  yield self.__class__(**params_kwargs)
180
203
 
181
204
 
182
205
  class BinaryOpWithIntInputs(BinaryOpParams[RegisterOrInt, RegisterOrInt]):
183
- @pydantic.root_validator()
184
- def validate_int_registers(cls, values: Dict[str, Any]) -> Dict[str, Any]:
185
- left_arg = values.get("left_arg")
206
+ @pydantic.model_validator(mode="after")
207
+ def validate_int_registers(self) -> Self:
208
+ left_arg = self.left_arg
186
209
  is_left_arg_float_register = (
187
210
  isinstance(left_arg, RegisterArithmeticInfo)
188
211
  and left_arg.fraction_places > 0
189
212
  )
190
- right_arg = values.get("right_arg")
213
+ right_arg = self.right_arg
191
214
  is_right_arg_float_register = (
192
215
  isinstance(right_arg, RegisterArithmeticInfo)
193
216
  and right_arg.fraction_places > 0
194
217
  )
195
218
  if is_left_arg_float_register or is_right_arg_float_register:
196
- raise ValueError(BOOLEAN_OP_WITH_FRACTIONS_ERROR)
197
- return values
219
+ raise ClassiqValueError(BOOLEAN_OP_WITH_FRACTIONS_ERROR)
220
+ return self
198
221
 
199
222
  @staticmethod
200
223
  def _is_signed(arg: Union[int, RegisterArithmeticInfo]) -> bool:
@@ -245,74 +268,160 @@ class Adder(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
245
268
  output_name = "sum"
246
269
 
247
270
  def _get_result_register(self) -> RegisterArithmeticInfo:
248
- lb = argument_utils.lower_bound(self.left_arg) + argument_utils.lower_bound(
249
- self.right_arg
271
+ left_arg = argument_utils.limit_fraction_places(
272
+ self.left_arg, self.machine_precision
250
273
  )
251
- ub = argument_utils.upper_bound(self.left_arg) + argument_utils.upper_bound(
252
- self.right_arg
274
+ right_arg = argument_utils.limit_fraction_places(
275
+ self.right_arg, self.machine_precision
276
+ )
277
+ lb = argument_utils.lower_bound(left_arg) + argument_utils.lower_bound(
278
+ right_arg
279
+ )
280
+ ub = argument_utils.upper_bound(left_arg) + argument_utils.upper_bound(
281
+ right_arg
253
282
  )
254
- integer_part_size = number_utils.bounds_to_integer_part_size(lb, ub)
255
283
  fraction_places = max(
256
- self._compute_fraction_places(self.left_arg),
257
- self._compute_fraction_places(self.right_arg),
284
+ argument_utils.fraction_places(left_arg),
285
+ argument_utils.fraction_places(right_arg),
258
286
  )
259
- size_needed = integer_part_size + fraction_places
260
287
  return RegisterArithmeticInfo(
261
- size=self.output_size or size_needed,
288
+ size=self.output_size or self._get_output_size(ub, lb, fraction_places),
262
289
  fraction_places=fraction_places,
263
290
  is_signed=self._include_sign and lb < 0,
264
291
  bounds=(lb, ub) if self._include_sign else None,
265
292
  )
266
293
 
294
+ def _get_output_size(self, ub: float, lb: float, fraction_places: int) -> int:
295
+ if isinstance(self.left_arg, float) and self.left_arg == 0.0:
296
+ if isinstance(self.right_arg, RegisterArithmeticInfo):
297
+ return self.right_arg.size
298
+ return as_arithmetic_info(self.right_arg).size
299
+ elif isinstance(self.right_arg, float) and self.right_arg == 0.0:
300
+ assert isinstance(self.left_arg, RegisterArithmeticInfo)
301
+ return self.left_arg.size
302
+
303
+ integer_part_size = number_utils.bounds_to_integer_part_size(lb, ub)
304
+ return integer_part_size + fraction_places
305
+
267
306
 
268
307
  class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
269
308
  output_name = "difference"
270
309
 
310
+ @staticmethod
311
+ def _get_effective_arg(
312
+ arg: RegisterOrConst, machine_precision: int
313
+ ) -> RegisterOrConst:
314
+ return argument_utils.limit_fraction_places(arg, machine_precision)
315
+
316
+ @property
317
+ def effective_left_arg(self) -> RegisterOrConst:
318
+ return self._get_effective_arg(self.left_arg, self.machine_precision)
319
+
320
+ @property
321
+ def effective_right_arg(self) -> RegisterOrConst:
322
+ return self._get_effective_arg(self.right_arg, self.machine_precision)
323
+
324
+ @staticmethod
325
+ def _is_arg_trimmed_register(arg: RegisterOrConst, machine_precision: int) -> bool:
326
+ return (
327
+ isinstance(arg, RegisterArithmeticInfo)
328
+ and arg.fraction_places > machine_precision
329
+ )
330
+
331
+ @property
332
+ def left_arg_is_trimmed_register(self) -> bool:
333
+ return self._is_arg_trimmed_register(self.left_arg, self.machine_precision)
334
+
335
+ @property
336
+ def right_arg_is_trimmed_register(self) -> bool:
337
+ return self._is_arg_trimmed_register(self.right_arg, self.machine_precision)
338
+
271
339
  def _get_result_register(self) -> RegisterArithmeticInfo:
272
340
  bounds = (
273
- argument_utils.lower_bound(self.left_arg)
274
- - argument_utils.upper_bound(self.right_arg),
275
- argument_utils.upper_bound(self.left_arg)
276
- - argument_utils.lower_bound(self.right_arg),
341
+ argument_utils.lower_bound(self.effective_left_arg)
342
+ - argument_utils.upper_bound(self.effective_right_arg),
343
+ argument_utils.upper_bound(self.effective_left_arg)
344
+ - argument_utils.lower_bound(self.effective_right_arg),
277
345
  )
278
- integer_part_size = number_utils.bounds_to_integer_part_size(*bounds)
279
346
  fraction_places = max(
280
- self._compute_fraction_places(self.left_arg),
281
- self._compute_fraction_places(self.right_arg),
347
+ argument_utils.fraction_places(self.effective_left_arg),
348
+ argument_utils.fraction_places(self.effective_right_arg),
282
349
  )
283
- size_needed = integer_part_size + fraction_places
350
+
351
+ size = self.output_size or self._get_output_size(bounds, fraction_places)
352
+ is_signed = self._include_sign and min(bounds) < 0
284
353
  return RegisterArithmeticInfo(
285
- size=self.output_size or size_needed,
354
+ size=size,
286
355
  fraction_places=fraction_places,
287
- is_signed=self._include_sign and min(bounds) < 0,
288
- bounds=self._legal_bounds(bounds),
356
+ is_signed=is_signed,
357
+ bounds=self._legal_bounds(
358
+ bounds,
359
+ RegisterArithmeticInfo.get_maximal_bounds(
360
+ size=size, is_signed=is_signed, fraction_places=fraction_places
361
+ ),
362
+ ),
289
363
  )
290
364
 
365
+ def _get_output_size(
366
+ self, bounds: tuple[float, float], fraction_places: int
367
+ ) -> int:
368
+ if isinstance(self.right_arg, float) and self.effective_right_arg == 0:
369
+ assert isinstance(self.effective_left_arg, RegisterArithmeticInfo)
370
+ return self.effective_left_arg.size
371
+ integer_part_size = number_utils.bounds_to_integer_part_size(*bounds)
372
+ size_needed = integer_part_size + fraction_places
373
+ return size_needed
374
+
291
375
  def garbage_output_size(self) -> pydantic.NonNegativeInt:
292
- if not isinstance(self.right_arg, RegisterArithmeticInfo):
376
+ if (
377
+ not self.left_arg_is_trimmed_register
378
+ and not self.right_arg_is_trimmed_register
379
+ ):
380
+ return self._untrimmed_garbage_output_size()
381
+ if not self.is_inplaced():
382
+ return 0
383
+ inplace_arg_name = (
384
+ self.left_arg_name
385
+ if self.inplace_arg == ArgToInplace.LEFT
386
+ else self.right_arg_name
387
+ )
388
+ return max(
389
+ 0,
390
+ self._inputs[inplace_arg_name].fraction_places
391
+ - self.result_register.fraction_places,
392
+ )
393
+
394
+ def _untrimmed_garbage_output_size(self) -> pydantic.NonNegativeInt:
395
+ if not isinstance(self.effective_right_arg, RegisterArithmeticInfo):
293
396
  adder_params = Adder(
294
- left_arg=self.left_arg,
295
- right_arg=-self.right_arg,
397
+ left_arg=self.effective_left_arg,
398
+ right_arg=-self.effective_right_arg,
296
399
  output_size=self.output_size,
297
400
  inplace_arg=self.inplace_arg,
298
401
  )
299
402
  return adder_params.garbage_output_size()
300
403
 
301
404
  negation_params = Negation(
302
- arg=self.right_arg,
405
+ arg=self.effective_right_arg,
303
406
  output_size=self.negation_output_size,
304
407
  inplace=self.should_inplace_negation,
408
+ bypass_bounds_validation=True,
305
409
  )
306
410
  negation_result = negation_params.result_register
307
- if self.output_size is None and max(self.right_arg.bounds) > 0:
308
- negation_result = negation_result.copy(
309
- update=dict(
310
- is_signed=True,
311
- bounds=(-max(self.right_arg.bounds), -min(self.right_arg.bounds)),
312
- )
411
+ if self.output_size is None and max(self.effective_right_arg.bounds) > 0:
412
+ bounds = (
413
+ -max(self.effective_right_arg.bounds),
414
+ -min(self.effective_right_arg.bounds),
415
+ )
416
+ negation_result = RegisterArithmeticInfo(
417
+ size=negation_result.size,
418
+ fraction_places=negation_result.fraction_places,
419
+ is_signed=True,
420
+ bounds=bounds,
421
+ bypass_bounds_validation=True,
313
422
  )
314
423
  adder_params = Adder(
315
- left_arg=self.left_arg,
424
+ left_arg=self.effective_left_arg,
316
425
  right_arg=negation_result,
317
426
  output_size=self.output_size,
318
427
  inplace_arg=self.arg_to_inplace_adder,
@@ -327,10 +436,10 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
327
436
  return self.inplace_arg == ArgToInplace.LEFT
328
437
 
329
438
  def _expected_negation_output_size(self) -> int:
330
- return self._compute_fraction_places(self.right_arg) + min(
439
+ return argument_utils.fraction_places(self.effective_right_arg) + min(
331
440
  self.result_register.integer_part_size,
332
441
  number_utils.bounds_to_integer_part_size(
333
- *(-bound for bound in argument_utils.bounds(self.right_arg))
442
+ *(-bound for bound in argument_utils.bounds(self.effective_right_arg))
334
443
  ),
335
444
  )
336
445
 
@@ -356,29 +465,85 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
356
465
  class Multiplier(BinaryOpWithFloatInputs):
357
466
  output_name = "product"
358
467
 
359
- def _get_result_register(self) -> RegisterArithmeticInfo:
360
- fraction_places = self._compute_fraction_places(
361
- self.left_arg
362
- ) + self._compute_fraction_places(self.right_arg)
468
+ def expected_fraction_places(self) -> int:
469
+ return argument_utils.fraction_places(
470
+ argument_utils.limit_fraction_places(self.left_arg, self.machine_precision)
471
+ ) + argument_utils.fraction_places(
472
+ argument_utils.limit_fraction_places(self.right_arg, self.machine_precision)
473
+ )
474
+
475
+ @staticmethod
476
+ def _get_bounds(
477
+ args: tuple[RegisterOrConst, RegisterOrConst], machine_precision: int
478
+ ) -> tuple[float, float]:
363
479
  extremal_values = [
364
480
  left * right
365
- for left in argument_utils.bounds(self.left_arg)
366
- for right in argument_utils.bounds(self.right_arg)
481
+ for left in argument_utils.bounds(args[0])
482
+ for right in argument_utils.bounds(args[1])
367
483
  ]
368
- bounds = (min(extremal_values), max(extremal_values))
484
+ return (
485
+ number_utils.limit_fraction_places(min(extremal_values), machine_precision),
486
+ number_utils.limit_fraction_places(max(extremal_values), machine_precision),
487
+ )
488
+
489
+ def _get_result_register(self) -> RegisterArithmeticInfo:
490
+ fraction_places = min(self.machine_precision, self.expected_fraction_places())
491
+ left_arg = argument_utils.limit_fraction_places(
492
+ self.left_arg, self.machine_precision
493
+ )
494
+ right_arg = argument_utils.limit_fraction_places(
495
+ self.right_arg, self.machine_precision
496
+ )
497
+ bounds = self._get_bounds((left_arg, right_arg), self.machine_precision)
498
+ if self.output_size:
499
+ if fraction_places:
500
+ raise ValueError(MODULO_WITH_FRACTION_PLACES_ERROR_MSG)
501
+ max_bounds = RegisterArithmeticInfo.get_maximal_bounds(
502
+ size=self.output_size, is_signed=False, fraction_places=0
503
+ )
504
+ bounds = number_utils.bounds_cut(bounds, max_bounds)
505
+
506
+ size = self.output_size or self._get_output_size(
507
+ bounds, fraction_places, left_arg, right_arg
508
+ )
509
+ is_signed = self._include_sign and min(bounds) < 0
510
+ return RegisterArithmeticInfo(
511
+ size=size,
512
+ fraction_places=fraction_places,
513
+ is_signed=is_signed,
514
+ bounds=self._legal_bounds(
515
+ bounds,
516
+ RegisterArithmeticInfo.get_maximal_bounds(
517
+ size=size, is_signed=is_signed, fraction_places=fraction_places
518
+ ),
519
+ ),
520
+ )
521
+
522
+ @staticmethod
523
+ def _get_output_size(
524
+ bounds: tuple[float, float],
525
+ fraction_places: int,
526
+ left_arg: Union[RegisterArithmeticInfo, float],
527
+ right_arg: Union[RegisterArithmeticInfo, float],
528
+ ) -> int:
529
+ if isinstance(left_arg, float) and left_arg == 1.0:
530
+ assert isinstance(right_arg, RegisterArithmeticInfo)
531
+ return right_arg.size
532
+ elif isinstance(right_arg, float) and right_arg == 1.0:
533
+ assert isinstance(left_arg, RegisterArithmeticInfo)
534
+ return left_arg.size
369
535
  largest_bound = max(bounds, key=abs)
370
536
  integer_places = int(largest_bound).bit_length() + int(largest_bound < 0)
371
537
  extra_sign_bit = int(
372
- argument_utils.is_signed(self.left_arg)
373
- and argument_utils.is_signed(self.right_arg)
538
+ argument_utils.is_signed(left_arg)
539
+ and argument_utils.is_signed(right_arg)
374
540
  and largest_bound > 0
375
541
  )
376
- return RegisterArithmeticInfo(
377
- size=self.output_size
378
- or max(1, integer_places + fraction_places + extra_sign_bit),
379
- fraction_places=fraction_places,
380
- is_signed=self._include_sign and min(bounds) < 0,
381
- bounds=self._legal_bounds(bounds),
542
+ return max(1, integer_places + fraction_places + extra_sign_bit)
543
+
544
+ def garbage_output_size(self) -> pydantic.NonNegativeInt:
545
+ return max(
546
+ 0, self.expected_fraction_places() - self.result_register.fraction_places
382
547
  )
383
548
 
384
549
 
@@ -416,29 +581,57 @@ class LessEqual(Comparator):
416
581
  class Power(BinaryOpParams[RegisterArithmeticInfo, pydantic.PositiveInt]):
417
582
  output_name = "powered"
418
583
 
419
- @pydantic.validator("right_arg", pre=True)
584
+ @pydantic.field_validator("right_arg", mode="before")
585
+ @classmethod
420
586
  def _validate_legal_power(cls, right_arg: Any) -> pydantic.PositiveInt:
421
587
  if not float(right_arg).is_integer():
422
- raise ValueError("Power must be an integer")
588
+ raise ClassiqValueError("Power must be an integer")
423
589
  if right_arg <= 0:
424
- raise ValueError("Power must be greater than one")
590
+ raise ClassiqValueError("Power must be greater than one")
425
591
  return int(right_arg)
426
592
 
427
- def _get_result_bounds(self) -> Tuple[float, float]:
428
- if (self.right_arg % 2) or min(self.left_arg.bounds) >= 0:
593
+ def expected_fraction_places(self) -> int:
594
+ return (
595
+ argument_utils.fraction_places(
596
+ argument_utils.limit_fraction_places(
597
+ self.left_arg, self.machine_precision
598
+ )
599
+ )
600
+ * self.right_arg
601
+ )
602
+
603
+ def _get_result_bounds(self) -> tuple[float, float]:
604
+ bounds = [
605
+ number_utils.limit_fraction_places(
606
+ bound, machine_precision=self.machine_precision
607
+ )
608
+ for bound in self.left_arg.bounds
609
+ ]
610
+ if (self.right_arg % 2) or min(bounds) >= 0:
429
611
  return (
430
- self.left_arg.bounds[0] ** self.right_arg,
431
- self.left_arg.bounds[1] ** self.right_arg,
612
+ number_utils.limit_fraction_places(
613
+ bounds[0] ** self.right_arg,
614
+ machine_precision=self.machine_precision,
615
+ ),
616
+ number_utils.limit_fraction_places(
617
+ bounds[1] ** self.right_arg,
618
+ machine_precision=self.machine_precision,
619
+ ),
432
620
  )
433
- return 0.0, max(abs(bound) for bound in self.left_arg.bounds) ** self.right_arg
621
+ return 0.0, number_utils.limit_fraction_places(
622
+ max(abs(bound) for bound in bounds) ** self.right_arg,
623
+ machine_precision=self.machine_precision,
624
+ )
434
625
 
435
626
  def _get_result_register(self) -> RegisterArithmeticInfo:
436
627
  if self.output_size:
437
628
  return RegisterArithmeticInfo(size=self.output_size)
438
629
 
439
- fraction_places: int = self.left_arg.fraction_places * self.right_arg
630
+ fraction_places = min(self.machine_precision, self.expected_fraction_places())
440
631
  bounds = self._get_result_bounds()
441
632
  size = number_utils.bounds_to_integer_part_size(*bounds) + fraction_places
633
+ if bounds[0] == bounds[1]:
634
+ size = 1
442
635
  return RegisterArithmeticInfo(
443
636
  size=size,
444
637
  is_signed=self.left_arg.is_signed and (self.right_arg % 2 == 1),
@@ -446,6 +639,50 @@ class Power(BinaryOpParams[RegisterArithmeticInfo, pydantic.PositiveInt]):
446
639
  bounds=bounds,
447
640
  )
448
641
 
642
+ def _get_inner_action_garbage_size(
643
+ self,
644
+ action_type: Union[type["Power"], type[Multiplier]],
645
+ *,
646
+ arg: RegisterArithmeticInfo,
647
+ action_right_arg: RegisterOrConst,
648
+ compute_power: int,
649
+ ) -> pydantic.NonNegativeInt:
650
+ inner_compute_power_params = Power(
651
+ left_arg=arg,
652
+ right_arg=compute_power,
653
+ output_size=self.output_size,
654
+ machine_precision=self.machine_precision,
655
+ )
656
+ return action_type(
657
+ left_arg=inner_compute_power_params.result_register,
658
+ right_arg=action_right_arg,
659
+ output_size=self.output_size,
660
+ machine_precision=self.machine_precision,
661
+ ).garbage_output_size()
662
+
663
+ def garbage_output_size(self) -> pydantic.NonNegativeInt:
664
+ arg = self.left_arg
665
+ power = self.right_arg
666
+ if power == 1:
667
+ return 0
668
+ if (
669
+ power == 2
670
+ or (arg.size == 1 and arg.fraction_places == 0)
671
+ or self.output_size == 1
672
+ ):
673
+ return max(
674
+ 0,
675
+ self.expected_fraction_places() - self.result_register.fraction_places,
676
+ )
677
+
678
+ if power % 2 == 0:
679
+ return self._get_inner_action_garbage_size(
680
+ Power, arg=arg, action_right_arg=power // 2, compute_power=2
681
+ )
682
+ return self._get_inner_action_garbage_size(
683
+ Multiplier, arg=arg, action_right_arg=arg, compute_power=power - 1
684
+ )
685
+
449
686
 
450
687
  class EffectiveUnaryOpParams(
451
688
  InplacableBinaryOpParams[RegisterArithmeticInfo, RightDataT], Generic[RightDataT]
@@ -457,19 +694,19 @@ class LShift(EffectiveUnaryOpParams[pydantic.NonNegativeInt]):
457
694
  output_name = "left_shifted"
458
695
  inplace_arg: Optional[ArgToInplace] = ArgToInplace.LEFT
459
696
 
460
- @pydantic.root_validator()
461
- def _validate_legal_modulo(cls, values: Dict[str, Any]) -> Dict[str, Any]:
462
- output_size = values.get("output_size")
697
+ @pydantic.model_validator(mode="after")
698
+ def _validate_legal_modulo(self) -> Self:
699
+ output_size = self.output_size
463
700
  if output_size is None:
464
- return values
465
- arg = values.get("left_arg")
466
- shift = values.get("right_arg")
701
+ return self
702
+ arg = self.left_arg
703
+ shift = self.right_arg
467
704
  if not isinstance(arg, RegisterArithmeticInfo):
468
- raise ValueError("left arg must be a RegisterArithmeticInfo")
705
+ raise ClassiqValueError("left arg must be a RegisterArithmeticInfo")
469
706
  if not isinstance(shift, int):
470
- raise ValueError("Shift must be an integer")
707
+ raise ClassiqValueError("Shift must be an integer")
471
708
  assert arg.fraction_places - shift <= 0, _FLOATING_POINT_MODULO_ERROR_MESSAGE
472
- return values
709
+ return self
473
710
 
474
711
  def garbage_output_size(self) -> pydantic.NonNegativeInt:
475
712
  if self.inplace_arg is None or self.output_size is None:
@@ -498,21 +735,21 @@ class RShift(EffectiveUnaryOpParams[pydantic.NonNegativeInt]):
498
735
  def _shifted_fraction_places(*, arg: RegisterArithmeticInfo, shift: int) -> int:
499
736
  return arg.fraction_places * int(arg.is_signed or shift < arg.size)
500
737
 
501
- @pydantic.root_validator()
502
- def _validate_legal_modulo(cls, values: Dict[str, Any]) -> Dict[str, Any]:
503
- output_size = values.get("output_size")
738
+ @pydantic.model_validator(mode="after")
739
+ def _validate_legal_modulo(self) -> Self:
740
+ output_size = self.output_size
504
741
  if output_size is None:
505
- return values
506
- arg = values.get("left_arg")
507
- shift = values.get("right_arg")
742
+ return self
743
+ arg = self.left_arg
744
+ shift = self.right_arg
508
745
  if not isinstance(arg, RegisterArithmeticInfo):
509
- raise ValueError("left arg must be a RegisterArithmeticInfo")
746
+ raise ClassiqValueError("left arg must be a RegisterArithmeticInfo")
510
747
  if not isinstance(shift, int):
511
- raise ValueError("Shift must be an integer")
748
+ raise ClassiqValueError("Shift must be an integer")
512
749
  assert (
513
- cls._shifted_fraction_places(arg=arg, shift=shift) == 0
750
+ self._shifted_fraction_places(arg=arg, shift=shift) == 0
514
751
  ), _FLOATING_POINT_MODULO_ERROR_MESSAGE
515
- return values
752
+ return self
516
753
 
517
754
  def garbage_output_size(self) -> pydantic.NonNegativeInt:
518
755
  if self.inplace_arg is None:
@@ -542,16 +779,16 @@ class CyclicShift(EffectiveUnaryOpParams[int]):
542
779
  output_name = "cyclic_shifted"
543
780
  inplace_arg: Optional[ArgToInplace] = ArgToInplace.LEFT
544
781
 
545
- @pydantic.root_validator()
546
- def _validate_legal_modulo(cls, values: Dict[str, Any]) -> Dict[str, Any]:
547
- output_size = values.get("output_size")
782
+ @pydantic.model_validator(mode="after")
783
+ def _validate_legal_modulo(self) -> Self:
784
+ output_size = self.output_size
548
785
  if output_size is None:
549
- return values
550
- arg = values.get("left_arg")
786
+ return self
787
+ arg = self.left_arg
551
788
  if not isinstance(arg, RegisterArithmeticInfo):
552
- raise ValueError("left arg must be a RegisterArithmeticInfo")
789
+ raise ClassiqValueError("left arg must be a RegisterArithmeticInfo")
553
790
  assert arg.fraction_places == 0, _FLOATING_POINT_MODULO_ERROR_MESSAGE
554
- return values
791
+ return self
555
792
 
556
793
  def garbage_output_size(self) -> pydantic.NonNegativeInt:
557
794
  if self.inplace_arg is None:
@@ -570,31 +807,30 @@ class Modulo(EffectiveUnaryOpParams[int]):
570
807
  output_name = "modulus"
571
808
  inplace_arg: Optional[ArgToInplace] = ArgToInplace.LEFT
572
809
 
573
- @pydantic.validator("left_arg")
810
+ @pydantic.field_validator("left_arg", mode="before")
811
+ @classmethod
574
812
  def _validate_left_arg_is_integer(
575
813
  cls, left_arg: RegisterArithmeticInfo
576
814
  ) -> RegisterArithmeticInfo:
577
815
  assert left_arg.fraction_places == 0, _FLOATING_POINT_MODULO_ERROR_MESSAGE
578
816
  return left_arg
579
817
 
580
- @pydantic.validator("right_arg")
818
+ @pydantic.field_validator("right_arg", mode="before")
819
+ @classmethod
581
820
  def _validate_right_arg_is_a_power_of_two(
582
- cls, right_arg: int, values: Dict[str, Any]
821
+ cls, right_arg: int, info: ValidationInfo
583
822
  ) -> int:
584
823
  repr_qubits_float = math.log2(right_arg)
585
824
  repr_qubits = round(repr_qubits_float)
586
825
  assert abs(repr_qubits - repr_qubits_float) < 10**-8, NOT_POWER_OF_TWO_ERROR_MSG
587
- output_size = values.get("output_size")
826
+ output_size = info.data.get("output_size")
588
827
  if output_size is not None:
589
828
  repr_qubits = min(repr_qubits, output_size)
590
- values["output_size"] = None
829
+ info.data["output_size"] = None
591
830
  return 2 ** (repr_qubits)
592
831
 
593
- @property
594
- def result_size(self) -> int:
595
- return round(math.log2(self.right_arg))
596
-
597
832
  def _get_result_register(self) -> RegisterArithmeticInfo:
598
- return RegisterArithmeticInfo(
599
- size=self.result_size, is_signed=False, fraction_places=0
600
- )
833
+ size = round(math.log2(self.right_arg))
834
+ if size <= 0:
835
+ raise ClassiqValueError("Cannot use a quantum expression with zero size")
836
+ return RegisterArithmeticInfo(size=size, is_signed=False, fraction_places=0)