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
@@ -0,0 +1,447 @@
1
+ import math
2
+ import re
3
+ from collections import defaultdict
4
+ from collections.abc import Iterator
5
+ from contextlib import contextmanager
6
+ from enum import Enum
7
+ from functools import reduce
8
+ from operator import mul
9
+ from typing import Any, Optional, TypeVar, Union
10
+
11
+ import pydantic
12
+ import pyomo.core.expr.numeric_expr as pyo_expr
13
+ import pyomo.environ as pyo
14
+ import sympy
15
+ from pyomo.core import ConcreteModel, Constraint, Objective, Var, maximize
16
+ from pyomo.core.base import _GeneralVarData
17
+ from pyomo.core.base.component import ComponentData
18
+ from pyomo.core.base.constraint import _GeneralConstraintData
19
+ from pyomo.core.base.indexed_component import IndexedComponent
20
+ from pyomo.core.base.objective import ScalarObjective
21
+ from pyomo.core.expr.base import ExpressionBase
22
+ from pyomo.core.expr.sympy_tools import (
23
+ Pyomo2SympyVisitor,
24
+ PyomoSympyBimap,
25
+ Sympy2PyomoVisitor,
26
+ )
27
+
28
+ from classiq.interface.exceptions import ClassiqValueError
29
+ from classiq.interface.generator.expressions.expression import Expression
30
+ from classiq.interface.generator.functions.classical_type import Integer
31
+ from classiq.interface.generator.types.struct_declaration import StructDeclaration
32
+
33
+ from classiq.qmod.qmod_variable import QArray, QBit, QNum, QStruct, QVar
34
+ from classiq.qmod.symbolic_expr import SymbolicExpr
35
+
36
+ ListVars = list[_GeneralVarData]
37
+ SUPPORTED_TYPES = [
38
+ pyo.Binary,
39
+ pyo.Integers,
40
+ pyo.NegativeIntegers,
41
+ pyo.NonNegativeIntegers,
42
+ pyo.NonPositiveIntegers,
43
+ pyo.PositiveIntegers,
44
+ ]
45
+
46
+
47
+ class ObjectiveType(Enum):
48
+ Min = "Min"
49
+ Max = "Max"
50
+
51
+
52
+ class CombinatorialOptimizationStructDeclaration(StructDeclaration):
53
+ variable_lower_bound: int = pydantic.Field(default=0)
54
+ variable_upper_bound: int = pydantic.Field(default=1)
55
+ constraints: list[Expression] = pydantic.Field(
56
+ default_factory=list, description="List of constraint expressions"
57
+ )
58
+ objective_type: ObjectiveType = pydantic.Field(
59
+ description="Specify whether the optimization problem is Min or Max"
60
+ )
61
+ objective_function: Expression = pydantic.Field(
62
+ description="The expression to optimize, according to the objective type"
63
+ )
64
+
65
+
66
+ def contains(var_data: _GeneralVarData, vars_data: ListVars) -> bool:
67
+ # HACK: standard "__containts__ (in)" method doesn't work, because pyomo overrode the __eq__ method (IMO)
68
+ return any(var_data is var_data_temp for var_data_temp in vars_data)
69
+
70
+
71
+ def remove(var_data: _GeneralVarData, vars_data: ListVars) -> ListVars:
72
+ # HACK: standard "list method remove" method doesn't work, because pyomo overrode the __eq__ method (IMO)
73
+ assert contains(var_data, vars_data), "var not in list"
74
+ vars_data = vars_data.copy()
75
+ for idx, var_data_temp in enumerate(vars_data):
76
+ if var_data_temp is var_data:
77
+ del vars_data[idx]
78
+ break
79
+ return vars_data
80
+
81
+
82
+ def index(var_data: _GeneralVarData, vars_data: ListVars) -> int:
83
+ # HACK: standard "index method" doesn't work.
84
+ assert contains(var_data, vars_data), "var not in list"
85
+ idxs = [
86
+ idx for idx, var_data_temp in enumerate(vars_data) if var_data is var_data_temp
87
+ ]
88
+ return idxs[0]
89
+
90
+
91
+ T = TypeVar("T")
92
+
93
+
94
+ def extract(model: ConcreteModel, type_: type[T]) -> list[T]:
95
+ if type_ == _GeneralVarData:
96
+ type_ = Var
97
+
98
+ elif type_ == _GeneralConstraintData:
99
+ type_ = Constraint
100
+
101
+ components = model.component_objects(type_)
102
+ return [
103
+ component[component_idx]
104
+ for component in components
105
+ for component_idx in component
106
+ ]
107
+
108
+
109
+ def delete_component(model: ConcreteModel, component: ComponentData) -> None:
110
+ parent_ref = component._component
111
+
112
+ if parent_ref is None:
113
+ return
114
+
115
+ parent_component = parent_ref()
116
+
117
+ if component is parent_component:
118
+ model.del_component(component)
119
+ else:
120
+ _delete_element_by_value(parent_component, component)
121
+
122
+ if not parent_component:
123
+ model.del_component(parent_component)
124
+
125
+
126
+ def _delete_element_by_value(dict_: dict, value: Any) -> None:
127
+ iter_dict = {**dict_}
128
+ for k, v in iter_dict.items():
129
+ if v is value and k in dict_:
130
+ del dict_[k]
131
+
132
+
133
+ def get_name(component: Union[IndexedComponent, ComponentData]) -> str:
134
+ if isinstance(component, IndexedComponent):
135
+ return component._name # constraint.name returns "'{name}'"
136
+ else:
137
+ return component.name
138
+
139
+
140
+ class FixedSympy2PyomoVisitor(Sympy2PyomoVisitor):
141
+ def beforeChild( # noqa: N802
142
+ self, node: Optional[sympy.Expr], child: sympy.Expr, child_idx: Optional[int]
143
+ ) -> tuple[bool, Union[int, float, None]]:
144
+ if not child._args:
145
+ item = self.object_map.getPyomoSymbol(child, None)
146
+ if item is None:
147
+ if isinstance(child, sympy.Integer): # addition to base implementation
148
+ item = int(child.evalf())
149
+ else:
150
+ item = float(child.evalf())
151
+ return False, item
152
+ return True, None
153
+
154
+
155
+ def sympy2pyomo_expression(
156
+ expr: sympy.core.Basic, object_map: PyomoSympyBimap
157
+ ) -> pyo_expr.ExpressionBase:
158
+ return FixedSympy2PyomoVisitor(object_map).walk_expression(expr)
159
+
160
+
161
+ def convert_pyomo_to_global_presentation(
162
+ pyo_model: pyo.ConcreteModel,
163
+ ) -> pyo.ConcreteModel:
164
+ problem_struct = pyomo2qmod("nativePyoModel", pyo_model)
165
+
166
+ pyomo_model = pyo.ConcreteModel()
167
+
168
+ var_names = list(problem_struct.variables.keys())
169
+ pyomo_model.var_set = pyo.Var(
170
+ var_names,
171
+ domain=pyo.NonNegativeIntegers,
172
+ bounds=(
173
+ problem_struct.variable_lower_bound,
174
+ problem_struct.variable_upper_bound,
175
+ ),
176
+ )
177
+ obj_map = PyomoSympyBimap()
178
+ var_dict = {
179
+ var_name: obj_map.getSympySymbol(pyomo_model.var_set[var_name])
180
+ for var_name in var_names
181
+ }
182
+
183
+ def expr2pyomo(expr: Expression) -> pyo_expr.ExpressionBase:
184
+ sp_expr = sympy.sympify(expr.expr, locals=var_dict)
185
+ if isinstance(sp_expr, sympy.core.relational.Equality):
186
+ return sympy2pyomo_expression(
187
+ sp_expr.args[0], obj_map
188
+ ) == sympy2pyomo_expression(sp_expr.args[1], obj_map)
189
+
190
+ # Note that strict greater/less than are not supported by Pyomo
191
+ return sympy2pyomo_expression(sp_expr, obj_map)
192
+
193
+ pyomo_model.constraints = pyo.Constraint(
194
+ pyo.RangeSet(0, len(problem_struct.constraints) - 1),
195
+ rule=lambda model, i: expr2pyomo(problem_struct.constraints[i]),
196
+ )
197
+ pyomo_model.objective = pyo.Objective(
198
+ expr=expr2pyomo(problem_struct.objective_function),
199
+ sense=(
200
+ pyo.maximize
201
+ if problem_struct.objective_type == ObjectiveType.Max
202
+ else pyo.minimize
203
+ ),
204
+ )
205
+
206
+ return pyomo_model
207
+
208
+
209
+ def pyomo2qmod(
210
+ struct_name: str, pyo_model: ConcreteModel
211
+ ) -> CombinatorialOptimizationStructDeclaration:
212
+ symbols_map = PyomoSympyBimap()
213
+
214
+ variables: list[sympy.Symbol] = []
215
+
216
+ bounds_set = False
217
+ lower_bound = None
218
+ upper_bound = None
219
+
220
+ for var_dict in pyo_model.component_objects(Var):
221
+ for key in var_dict:
222
+ var = Pyomo2SympyVisitor(symbols_map).walk_expression(var_dict[key])
223
+ var.name = var.name.replace(",", "_")
224
+ variables.append(var)
225
+ if bounds_set:
226
+ if lower_bound != var_dict[key].lb:
227
+ raise ClassiqValueError(
228
+ "All problem variables must agree on lower bound"
229
+ )
230
+ if upper_bound != var_dict[key].ub:
231
+ raise ClassiqValueError(
232
+ "All problem variables must agree on upper bound"
233
+ )
234
+ else:
235
+ lower_bound = var_dict[key].lb
236
+ upper_bound = var_dict[key].ub
237
+ bounds_set = True
238
+
239
+ constraint_exprs: list[sympy.Expr] = []
240
+
241
+ constraint_exprs.extend(
242
+ Pyomo2SympyVisitor(symbols_map).walk_expression(constraint_dict[key].expr)
243
+ for constraint_dict in pyo_model.component_objects(Constraint)
244
+ for key in constraint_dict
245
+ )
246
+
247
+ pyo_objective: ScalarObjective = next(pyo_model.component_objects(Objective))
248
+ objective_type_str = "Max" if pyo_objective.sense == maximize else "Min"
249
+ objective_expr: sympy.Expr = Pyomo2SympyVisitor(symbols_map).walk_expression(
250
+ pyo_objective
251
+ )
252
+
253
+ return CombinatorialOptimizationStructDeclaration(
254
+ name=struct_name,
255
+ variables={str(variable): Integer() for variable in variables},
256
+ variable_lower_bound=lower_bound,
257
+ variable_upper_bound=upper_bound,
258
+ constraints=[
259
+ Expression(expr=str(constraint_expr))
260
+ for constraint_expr in constraint_exprs
261
+ ],
262
+ objective_type=objective_type_str,
263
+ objective_function=Expression(expr=str(objective_expr)),
264
+ )
265
+
266
+
267
+ def pyomo_to_qmod_qstruct(
268
+ struct_name: str, vars: list[_GeneralVarData]
269
+ ) -> type[QStruct]:
270
+ qmod_struct = type(struct_name, (QStruct,), {})
271
+ qmod_struct.__annotations__ = _get_qstruct_fields(vars)
272
+ return qmod_struct
273
+
274
+
275
+ def _get_qstruct_fields(vars: list[_GeneralVarData]) -> dict[str, type[QVar]]:
276
+ array_type_sizes = _get_array_sizes(vars)
277
+ fields: dict[str, type[QVar]] = {}
278
+ for var in vars:
279
+ _add_qmod_field(var, array_type_sizes, fields)
280
+ return fields
281
+
282
+
283
+ def _get_array_sizes(vars: list[_GeneralVarData]) -> dict[str, tuple[int, ...]]:
284
+ array_types: dict[str, set[tuple]] = defaultdict(set)
285
+ for var in vars:
286
+ if is_index_var(var):
287
+ array_types[get_field_name(var.parent_component())].add(
288
+ index_as_tuple(var.index())
289
+ )
290
+ return {
291
+ name: dimensions
292
+ for name, indices in array_types.items()
293
+ if (dimensions := _get_indices_dimensions(indices)) is not None
294
+ }
295
+
296
+
297
+ def _get_indices_dimensions(indices: set[tuple[int, ...]]) -> Optional[tuple[int, ...]]:
298
+ indices_list = list(indices)
299
+ if len(indices) == 0:
300
+ return None
301
+ first_idx = indices_list[0]
302
+ if len(first_idx) == 0:
303
+ return None
304
+ if any(len(idx) != len(first_idx) for idx in indices_list[1:]):
305
+ return None
306
+ dimension_bounds = [(idx, idx) for idx in first_idx]
307
+ for multi_idx in indices_list[1:]:
308
+ for dim_idx, idx in enumerate(multi_idx):
309
+ dimension_bounds[dim_idx] = (
310
+ min(dimension_bounds[dim_idx][0], idx),
311
+ max(dimension_bounds[dim_idx][1], idx),
312
+ )
313
+ if any(lb != 0 for lb, ub in dimension_bounds):
314
+ return None
315
+ dimensions = tuple(ub + 1 for _, ub in dimension_bounds)
316
+ if reduce(mul, dimensions) != len(indices_list):
317
+ return None
318
+ return dimensions
319
+
320
+
321
+ def _add_qmod_field(
322
+ var: _GeneralVarData,
323
+ array_type_sizes: dict[str, tuple[int, ...]],
324
+ fields: dict[str, type[QVar]],
325
+ ) -> None:
326
+ parent_name = get_field_name(var.parent_component())
327
+ if parent_name not in array_type_sizes:
328
+ var_name = get_field_name(var)
329
+ fields[var_name] = _get_qmod_field_type(var_name, var)
330
+ return
331
+ dimensions = array_type_sizes[parent_name]
332
+ if index_as_tuple(var.index()) == tuple(0 for _ in range(len(dimensions))):
333
+ qmod_type: type[QVar] = _get_qmod_field_type(parent_name, var)
334
+ for dim in reversed(dimensions):
335
+ qmod_type = QArray[qmod_type, dim] # type:ignore[valid-type]
336
+ fields[parent_name] = qmod_type
337
+
338
+
339
+ def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]:
340
+ if var_data.domain not in SUPPORTED_TYPES:
341
+ raise ClassiqValueError(
342
+ f"Type {str(var_data.domain)!r} of variable {var_name!r} is not supported"
343
+ )
344
+
345
+ if var_data.domain == pyo.Binary:
346
+ return QBit
347
+
348
+ bounds = var_data.bounds
349
+ if bounds is None:
350
+ raise ClassiqValueError(f"Variable {var_name!r} has no bounds")
351
+ lb, ub = bounds
352
+ if not isinstance(lb, int) or not isinstance(ub, int):
353
+ raise ClassiqValueError(
354
+ f"Non-integer bounds for variable {var_name!r} are not supported"
355
+ )
356
+ qnum: Any = QNum # mypy shenanigans
357
+ return qnum[math.ceil(math.log2(ub - lb + 1)), False, 0]
358
+
359
+
360
+ def evaluate_objective(
361
+ var_mapping: dict[Any, Union[str, tuple[str, tuple[int, ...]]]],
362
+ sympy_expr: sympy.Expr,
363
+ struct_obj: Any,
364
+ ) -> Any:
365
+ sympy_assignment = {
366
+ sympy_var: (
367
+ getattr(struct_obj, field_accessor)
368
+ if isinstance(field_accessor, str)
369
+ else _get_item(getattr(struct_obj, field_accessor[0]), field_accessor[1])
370
+ )
371
+ for sympy_var, field_accessor in var_mapping.items()
372
+ }
373
+
374
+ # classical objective evaluation
375
+ if not isinstance(struct_obj, QStruct):
376
+ return float(sympy_expr.evalf(subs=sympy_assignment))
377
+
378
+ # quantum objective evaluation
379
+ expr_str = str(sympy_expr).replace("'", "")
380
+ for var_name, var_value in sympy_assignment.items():
381
+ var_name = str(var_name).replace("'", "")
382
+ expr_str = re.sub(rf"\b{var_name}\b", str(var_value), expr_str)
383
+ return SymbolicExpr(expr=expr_str, is_quantum=True)
384
+
385
+
386
+ def _get_item(obj: Any, multi_index: tuple[int, ...]) -> Any:
387
+ for idx in multi_index:
388
+ obj = obj[idx]
389
+ return obj
390
+
391
+
392
+ def get_field_name(var: _GeneralVarData) -> str:
393
+ return var.local_name.replace("[", "_").replace("]", "").replace(",", "_")
394
+
395
+
396
+ def is_index_var(var: _GeneralVarData) -> bool:
397
+ index = var.index()
398
+ return isinstance(index, int) or (
399
+ isinstance(index, tuple) and all(isinstance(idx, int) for idx in index)
400
+ )
401
+
402
+
403
+ def index_as_tuple(index: Union[int, tuple[int, ...]]) -> tuple[int, ...]:
404
+ if isinstance(index, int):
405
+ return (index,)
406
+ return index
407
+
408
+
409
+ @contextmanager
410
+ def add_var_domain_constraints(model: ConcreteModel) -> Iterator[None]:
411
+ vars = extract(model, _GeneralVarData)
412
+ constraints = [
413
+ constraint
414
+ for var in vars
415
+ if (constraint := _get_var_domain_constraint(var)) is not None
416
+ ]
417
+ if len(constraints) == 0:
418
+ yield
419
+ return
420
+ model.var_domain_constraints = pyo.ConstraintList()
421
+ for constraint in constraints:
422
+ model.var_domain_constraints.add(constraint)
423
+ yield
424
+ model.del_component("var_domain_constraints")
425
+
426
+
427
+ def _get_var_domain_constraint(var: _GeneralVarData) -> Optional[ExpressionBase]:
428
+ bounds = var.bounds
429
+ if (
430
+ type(bounds) is not tuple
431
+ or len(bounds) != 2
432
+ or not all(isinstance(bounds[idx], int) for idx in (0, 1))
433
+ ):
434
+ raise ClassiqValueError(
435
+ f"Missing bounds for variable {var.local_name}. Expected both lower and "
436
+ f"upper bounds, got {bounds}"
437
+ )
438
+ lb, ub = bounds
439
+ if ub < lb:
440
+ raise ClassiqValueError(
441
+ f"Illegal bounds for variable {var.local_name}. The upper bound ({ub}) is "
442
+ f"lesser than the lower bound ({lb})"
443
+ )
444
+ ub_norm = ub - lb + 1
445
+ if ub_norm & (ub_norm - 1) == 0:
446
+ return None
447
+ return var <= ub
@@ -0,0 +1,22 @@
1
+ from typing import Optional
2
+
3
+ import pyomo.core as pyo
4
+ from pyomo.core.base import _GeneralVarData
5
+ from pyomo.core.expr.sympy_tools import Pyomo2SympyVisitor, PyomoSympyBimap
6
+ from sympy import Expr
7
+
8
+
9
+ def sympyify_vars(variables: list[_GeneralVarData]) -> PyomoSympyBimap:
10
+ symbols_map = PyomoSympyBimap()
11
+ for var in variables:
12
+ Pyomo2SympyVisitor(symbols_map).walk_expression(var)
13
+ return symbols_map
14
+
15
+
16
+ def sympyify_expression(
17
+ expression: pyo.Expression, symbols_map: Optional[PyomoSympyBimap] = None
18
+ ) -> Expr:
19
+ if symbols_map is None:
20
+ symbols_map = PyomoSympyBimap()
21
+
22
+ return Pyomo2SympyVisitor(symbols_map).walk_expression(expression)
@@ -0,0 +1,189 @@
1
+ import copy
2
+ from itertools import chain, product
3
+ from typing import Callable, Union
4
+
5
+ import pyomo.environ as pyo
6
+ from pyomo.core.base import _GeneralVarData
7
+ from pyomo.core.expr.numeric_expr import ExpressionBase
8
+ from pyomo.core.expr.relational_expr import EqualityExpression
9
+
10
+ from classiq.interface.combinatorial_optimization.encoding_types import EncodingType
11
+ from classiq.interface.combinatorial_optimization.solver_types import QSolver
12
+ from classiq.interface.exceptions import ClassiqCombOptInvalidEncodingTypeError
13
+
14
+ from classiq.applications.combinatorial_helpers import encoding_utils, pyomo_utils
15
+ from classiq.applications.combinatorial_helpers.encoding_mapping import EncodingMapping
16
+ from classiq.applications.combinatorial_helpers.encoding_utils import ONE_HOT_SUFFIX
17
+
18
+
19
+ def _make_invalid_encoding_type_error(
20
+ encoding_type: EncodingType,
21
+ ) -> ClassiqCombOptInvalidEncodingTypeError:
22
+ return ClassiqCombOptInvalidEncodingTypeError(
23
+ encoding_type=encoding_type,
24
+ valid_types=EncodingType.__members__.keys(),
25
+ )
26
+
27
+
28
+ def encoding_length(
29
+ var: _GeneralVarData, encoding_type: Union[EncodingType, None]
30
+ ) -> int:
31
+ if encoding_type is None:
32
+ return 1
33
+
34
+ var_span = encoding_utils.get_var_span(var)
35
+
36
+ if encoding_type == EncodingType.BINARY:
37
+ return var_span.bit_length()
38
+
39
+ elif encoding_type == EncodingType.ONE_HOT:
40
+ return var_span + 1
41
+
42
+ else:
43
+ raise _make_invalid_encoding_type_error(encoding_type)
44
+
45
+
46
+ class ModelEncoder:
47
+ def __init__(
48
+ self,
49
+ model: pyo.ConcreteModel,
50
+ qsolver: QSolver,
51
+ encoding_type: EncodingType = EncodingType.BINARY,
52
+ ) -> None:
53
+ self.encoding_type = encoding_type
54
+ self.encoded_model = copy.deepcopy(model)
55
+ self.qsolver = qsolver
56
+ self.vars_original = list(self.encoded_model.component_objects(pyo.Var))
57
+ self.vars_encoding_mapping = self._encode_variables()
58
+ if self.encoding_type == EncodingType.ONE_HOT:
59
+ self._add_one_hot_constraints()
60
+ self._encode_constraints()
61
+ self._encode_objective()
62
+
63
+ @property
64
+ def _shift_substitution_dict(self) -> dict[int, pyo.Expression]:
65
+ variables = pyomo_utils.extract(self.encoded_model, pyo.Var)
66
+ return {id(var): var + var.lb for var in variables}
67
+
68
+ def _encode_variables(self) -> EncodingMapping:
69
+ vars_encoding_mapping = EncodingMapping(self.encoding_type)
70
+ for variable in self.vars_original:
71
+ # encode variables
72
+ encoded_var_name = encoding_utils.encoded_obj_name(variable.name)
73
+ encoded_var = pyo.Var(self._get_encoding_idxs(variable), domain=pyo.Binary)
74
+ setattr(self.encoded_model, encoded_var_name, encoded_var)
75
+
76
+ # create mapping between original variables and their encodings
77
+ for var_idx, var_data in variable.items():
78
+ encoding_vars = [
79
+ encoded_var[var_idx, encoding_idx]
80
+ for encoding_idx in range(
81
+ encoding_length(var_data, self.encoding_type)
82
+ )
83
+ ]
84
+
85
+ encoding_expr = self._get_encoding_expr(var_data, encoding_vars)
86
+
87
+ self._add_expr_constraint(
88
+ constraint_name=var_data.name
89
+ + encoding_utils.ENCODED_SUFFIX
90
+ + encoding_utils.CONSTRAINT_SUFFIX,
91
+ expr=EqualityExpression(args=[var_data, encoding_expr]),
92
+ )
93
+
94
+ vars_encoding_mapping.add(
95
+ original_var=var_data,
96
+ encoding_expr=encoding_expr,
97
+ encodings_vars=encoding_vars,
98
+ )
99
+ return vars_encoding_mapping
100
+
101
+ def _get_encoding_expr(
102
+ self, var_data: _GeneralVarData, encoding_vars: list[_GeneralVarData]
103
+ ) -> pyo.Expression:
104
+ if self.encoding_type == EncodingType.BINARY:
105
+ var_span = encoding_utils.get_var_span(var_data)
106
+ coeffs = self._get_binary_coeffs(encoding_vars, var_span)
107
+
108
+ elif self.encoding_type == EncodingType.ONE_HOT:
109
+ coeffs = list(range(len(encoding_vars)))
110
+ else:
111
+ raise _make_invalid_encoding_type_error(self.encoding_type)
112
+
113
+ encoding_expr = sum(
114
+ coeff * encoding_var for coeff, encoding_var in zip(coeffs, encoding_vars)
115
+ )
116
+
117
+ # Encodes variable shift
118
+ encoding_expr += var_data.lb
119
+ return encoding_expr
120
+
121
+ def _get_binary_coeffs(
122
+ self, encoding_vars: list[_GeneralVarData], var_span: int
123
+ ) -> list[int]:
124
+ num_vars = len(encoding_vars)
125
+ if self.qsolver == QSolver.QAOAMixer:
126
+ return [2**idx for idx in range(num_vars)]
127
+
128
+ else: # self.qsolver == QSolver.QAOAPenalty:
129
+ coeffs = [2**idx for idx in range(num_vars - 1)]
130
+ coeffs += [var_span - sum(coeffs)]
131
+ return coeffs
132
+
133
+ def _get_encoding_idxs(self, variable: pyo.Var) -> list[tuple[int, int]]:
134
+ return list(
135
+ chain(
136
+ *[
137
+ product(
138
+ [var_idx], range(encoding_length(var_data, self.encoding_type))
139
+ )
140
+ for var_idx, var_data in variable.items()
141
+ ]
142
+ )
143
+ )
144
+
145
+ def _add_one_hot_constraints(self) -> None:
146
+ for variable in self.vars_original:
147
+ # potential bug with creating function inside a loop.
148
+ # solved with early binding - https://stackoverflow.com/questions/3431676/creating-functions-in-a-loop
149
+ def one_hot_rule(var_idx: int, var: pyo.Var = variable) -> ExpressionBase:
150
+ var_data = var[var_idx]
151
+ return sum(self.vars_encoding_mapping.get_encoding_vars(var_data)) == 1
152
+
153
+ self._add_rule_constraint(
154
+ constraint_name=variable.name + ONE_HOT_SUFFIX,
155
+ idxs=getattr(self.encoded_model, variable.index),
156
+ rule=one_hot_rule,
157
+ )
158
+
159
+ def _add_rule_constraint(
160
+ self, constraint_name: str, idxs: list[int], rule: Callable
161
+ ) -> None:
162
+ encoding_constraint = pyo.Constraint(idxs, rule=rule)
163
+
164
+ setattr(self.encoded_model, constraint_name, encoding_constraint)
165
+
166
+ def _add_expr_constraint(self, constraint_name: str, expr: ExpressionBase) -> None:
167
+ setattr(self.encoded_model, constraint_name, pyo.Constraint(expr=expr))
168
+
169
+ def _encode_objective(self) -> None:
170
+ encoding_utils.encode_objective(
171
+ self.encoded_model, self.vars_encoding_mapping.substitution_dict
172
+ )
173
+
174
+ def encode_expr(
175
+ self,
176
+ expr: pyo.Expression,
177
+ substitution_dict: Union[dict[int, pyo.Expression], None] = None,
178
+ ) -> pyo.Expression:
179
+ if substitution_dict is None:
180
+ substitution_dict = self.vars_encoding_mapping.substitution_dict
181
+ return encoding_utils.encode_expr(expr, substitution_dict)
182
+
183
+ def _encode_constraints(self) -> None:
184
+ if self.qsolver == QSolver.QAOAPenalty:
185
+ return
186
+
187
+ encoding_utils.encode_constraints(
188
+ self.encoded_model, self._shift_substitution_dict
189
+ )