classiq 0.52.0__py3-none-any.whl → 0.54.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. classiq/__init__.py +1 -3
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +2 -1
  3. classiq/_internals/__init__.py +0 -20
  4. classiq/_internals/api_wrapper.py +23 -17
  5. classiq/_internals/async_utils.py +1 -3
  6. classiq/_internals/authentication/auth0.py +5 -5
  7. classiq/_internals/authentication/device.py +5 -4
  8. classiq/_internals/authentication/password_manager.py +3 -3
  9. classiq/_internals/authentication/token_manager.py +3 -2
  10. classiq/_internals/client.py +11 -13
  11. classiq/_internals/config.py +2 -2
  12. classiq/_internals/jobs.py +7 -6
  13. classiq/_internals/type_validation.py +9 -9
  14. classiq/analyzer/__init__.py +1 -3
  15. classiq/analyzer/analyzer.py +8 -7
  16. classiq/analyzer/analyzer_utilities.py +8 -8
  17. classiq/analyzer/rb.py +11 -11
  18. classiq/applications/__init__.py +1 -3
  19. classiq/applications/chemistry/__init__.py +1 -3
  20. classiq/applications/chemistry/ansatz_parameters.py +4 -4
  21. classiq/applications/chemistry/chemistry_model_constructor.py +10 -9
  22. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -9
  23. classiq/applications/combinatorial_helpers/encoding_mapping.py +10 -10
  24. classiq/applications/combinatorial_helpers/encoding_utils.py +4 -4
  25. classiq/applications/combinatorial_helpers/memory.py +5 -7
  26. classiq/applications/combinatorial_helpers/optimization_model.py +43 -24
  27. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +4 -6
  28. classiq/applications/combinatorial_helpers/pyomo_utils.py +95 -24
  29. classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
  30. classiq/applications/combinatorial_helpers/transformations/encoding.py +8 -8
  31. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +5 -5
  32. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +7 -9
  33. classiq/applications/combinatorial_helpers/transformations/penalty.py +1 -2
  34. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +1 -2
  35. classiq/applications/combinatorial_helpers/transformations/slack_variables.py +1 -2
  36. classiq/applications/combinatorial_optimization/__init__.py +1 -3
  37. classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -2
  38. classiq/applications/combinatorial_optimization/examples/__init__.py +1 -3
  39. classiq/applications/finance/__init__.py +1 -3
  40. classiq/applications/grover/__init__.py +1 -3
  41. classiq/applications/grover/grover_model_constructor.py +7 -9
  42. classiq/applications/hamiltonian/pauli_decomposition.py +6 -6
  43. classiq/applications/qnn/__init__.py +1 -3
  44. classiq/applications/qnn/circuit_utils.py +5 -5
  45. classiq/applications/qnn/datasets/__init__.py +1 -3
  46. classiq/applications/qnn/datasets/dataset_base_classes.py +5 -4
  47. classiq/applications/qnn/datasets/dataset_parity.py +2 -2
  48. classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -1
  49. classiq/applications/qnn/qlayer.py +25 -6
  50. classiq/applications/qnn/torch_utils.py +2 -2
  51. classiq/applications/qnn/types.py +5 -5
  52. classiq/applications/qsvm/qsvm.py +1 -3
  53. classiq/applications/qsvm/qsvm_data_generation.py +3 -3
  54. classiq/applications/qsvm/qsvm_model_constructor.py +5 -5
  55. classiq/execution/__init__.py +3 -3
  56. classiq/execution/all_hardware_devices.py +1 -3
  57. classiq/execution/execution_session.py +57 -16
  58. classiq/execution/iqcc.py +1 -1
  59. classiq/execution/jobs.py +4 -4
  60. classiq/execution/qaoa.py +84 -0
  61. classiq/execution/qnn.py +3 -3
  62. classiq/executor.py +4 -4
  63. classiq/interface/_version.py +1 -1
  64. classiq/interface/analyzer/analysis_params.py +9 -10
  65. classiq/interface/analyzer/cytoscape_graph.py +5 -5
  66. classiq/interface/analyzer/result.py +17 -17
  67. classiq/interface/applications/qsvm.py +6 -10
  68. classiq/interface/backend/backend_preferences.py +4 -3
  69. classiq/interface/backend/ionq/ionq_quantum_program.py +4 -5
  70. classiq/interface/backend/pydantic_backend.py +1 -2
  71. classiq/interface/chemistry/fermionic_operator.py +5 -5
  72. classiq/interface/chemistry/ground_state_problem.py +7 -8
  73. classiq/interface/chemistry/molecule.py +4 -4
  74. classiq/interface/chemistry/operator.py +11 -13
  75. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -3
  76. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -4
  77. classiq/interface/combinatorial_optimization/examples/knapsack.py +3 -3
  78. classiq/interface/combinatorial_optimization/examples/mht.py +2 -3
  79. classiq/interface/combinatorial_optimization/examples/portfolio_variations.py +2 -2
  80. classiq/interface/combinatorial_optimization/examples/set_cover.py +1 -2
  81. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +5 -7
  82. classiq/interface/combinatorial_optimization/optimization_problem.py +2 -2
  83. classiq/interface/combinatorial_optimization/result.py +1 -3
  84. classiq/interface/debug_info/debug_info.py +8 -7
  85. classiq/interface/exceptions.py +11 -7
  86. classiq/interface/execution/iqcc.py +1 -3
  87. classiq/interface/execution/jobs.py +2 -2
  88. classiq/interface/execution/primitives.py +3 -3
  89. classiq/interface/executor/aws_execution_cost.py +4 -4
  90. classiq/interface/executor/execution_request.py +2 -3
  91. classiq/interface/executor/execution_result.py +3 -3
  92. classiq/interface/executor/iqae_result.py +3 -5
  93. classiq/interface/executor/optimizer_preferences.py +2 -2
  94. classiq/interface/executor/quantum_code.py +6 -6
  95. classiq/interface/executor/register_initialization.py +2 -4
  96. classiq/interface/executor/result.py +35 -28
  97. classiq/interface/executor/vqe_result.py +8 -8
  98. classiq/interface/finance/function_input.py +2 -2
  99. classiq/interface/finance/gaussian_model_input.py +5 -5
  100. classiq/interface/finance/log_normal_model_input.py +2 -2
  101. classiq/interface/finance/model_input.py +1 -2
  102. classiq/interface/generator/adjacency.py +1 -3
  103. classiq/interface/generator/ansatz_library.py +4 -4
  104. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  105. classiq/interface/generator/arith/argument_utils.py +3 -3
  106. classiq/interface/generator/arith/arithmetic.py +7 -7
  107. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +5 -5
  108. classiq/interface/generator/arith/arithmetic_expression_abc.py +11 -11
  109. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -7
  110. classiq/interface/generator/arith/arithmetic_expression_validator.py +8 -8
  111. classiq/interface/generator/arith/arithmetic_operations.py +4 -3
  112. classiq/interface/generator/arith/arithmetic_param_getters.py +6 -6
  113. classiq/interface/generator/arith/arithmetic_result_builder.py +9 -9
  114. classiq/interface/generator/arith/ast_node_rewrite.py +2 -1
  115. classiq/interface/generator/arith/binary_ops.py +10 -13
  116. classiq/interface/generator/arith/extremum_operations.py +3 -2
  117. classiq/interface/generator/arith/logical_ops.py +7 -6
  118. classiq/interface/generator/arith/number_utils.py +4 -4
  119. classiq/interface/generator/arith/register_user_input.py +4 -4
  120. classiq/interface/generator/arith/unary_ops.py +2 -1
  121. classiq/interface/generator/builtin_api_builder.py +2 -1
  122. classiq/interface/generator/circuit_code/circuit_code.py +4 -4
  123. classiq/interface/generator/circuit_code/types_and_constants.py +3 -5
  124. classiq/interface/generator/complex_type.py +1 -2
  125. classiq/interface/generator/control_state.py +2 -2
  126. classiq/interface/generator/custom_ansatz.py +1 -3
  127. classiq/interface/generator/distance.py +3 -5
  128. classiq/interface/generator/excitations.py +3 -2
  129. classiq/interface/generator/expressions/enums/finance_functions.py +1 -3
  130. classiq/interface/generator/expressions/evaluated_expression.py +4 -3
  131. classiq/interface/generator/expressions/expression.py +4 -5
  132. classiq/interface/generator/expressions/expression_constants.py +4 -4
  133. classiq/interface/generator/expressions/qmod_qarray_proxy.py +2 -1
  134. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +2 -1
  135. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +2 -1
  136. classiq/interface/generator/expressions/qmod_sized_proxy.py +2 -1
  137. classiq/interface/generator/expressions/qmod_struct_instance.py +2 -1
  138. classiq/interface/generator/expressions/sympy_supported_expressions.py +11 -13
  139. classiq/interface/generator/finance.py +2 -2
  140. classiq/interface/generator/function_param_library.py +6 -6
  141. classiq/interface/generator/function_params.py +13 -19
  142. classiq/interface/generator/functions/classical_function_declaration.py +4 -3
  143. classiq/interface/generator/functions/classical_type.py +13 -13
  144. classiq/interface/generator/functions/concrete_types.py +1 -2
  145. classiq/interface/generator/functions/function_declaration.py +1 -1
  146. classiq/interface/generator/functions/qmod_python_interface.py +2 -1
  147. classiq/interface/generator/functions/type_name.py +3 -2
  148. classiq/interface/generator/generated_circuit_data.py +34 -22
  149. classiq/interface/generator/grover_diffuser.py +7 -7
  150. classiq/interface/generator/grover_operator.py +2 -2
  151. classiq/interface/generator/hardware/hardware_data.py +7 -6
  152. classiq/interface/generator/hardware_efficient_ansatz.py +8 -8
  153. classiq/interface/generator/identity.py +5 -6
  154. classiq/interface/generator/linear_pauli_rotations.py +6 -6
  155. classiq/interface/generator/mcu.py +2 -2
  156. classiq/interface/generator/mcx.py +6 -6
  157. classiq/interface/generator/model/__init__.py +1 -3
  158. classiq/interface/generator/model/constraints.py +2 -2
  159. classiq/interface/generator/model/model.py +5 -6
  160. classiq/interface/generator/model/preferences/preferences.py +7 -6
  161. classiq/interface/generator/model/quantum_register.py +6 -11
  162. classiq/interface/generator/oracles/arithmetic_oracle.py +1 -2
  163. classiq/interface/generator/oracles/custom_oracle.py +2 -2
  164. classiq/interface/generator/oracles/oracle_abc.py +6 -5
  165. classiq/interface/generator/partitioned_register.py +6 -5
  166. classiq/interface/generator/piecewise_linear_amplitude_loading.py +8 -7
  167. classiq/interface/generator/qpe.py +4 -4
  168. classiq/interface/generator/qsvm.py +3 -3
  169. classiq/interface/generator/quantum_function_call.py +24 -29
  170. classiq/interface/generator/quantum_program.py +9 -9
  171. classiq/interface/generator/register_role.py +2 -4
  172. classiq/interface/generator/slice_parsing_utils.py +4 -3
  173. classiq/interface/generator/standard_gates/standard_gates.py +3 -3
  174. classiq/interface/generator/state_preparation/bell_state_preparation.py +3 -3
  175. classiq/interface/generator/state_preparation/distributions.py +6 -5
  176. classiq/interface/generator/state_preparation/metrics.py +2 -4
  177. classiq/interface/generator/state_preparation/state_preparation.py +4 -4
  178. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +3 -3
  179. classiq/interface/generator/transpiler_basis_gates.py +2 -2
  180. classiq/interface/generator/types/enum_declaration.py +2 -3
  181. classiq/interface/generator/types/qstruct_declaration.py +2 -1
  182. classiq/interface/generator/types/struct_declaration.py +3 -2
  183. classiq/interface/generator/ucc.py +2 -1
  184. classiq/interface/generator/unitary_gate.py +2 -2
  185. classiq/interface/generator/user_defined_function_params.py +1 -1
  186. classiq/interface/generator/validations/flow_graph.py +6 -5
  187. classiq/interface/generator/validations/validator_functions.py +3 -2
  188. classiq/interface/generator/visitor.py +9 -14
  189. classiq/interface/hardware.py +5 -6
  190. classiq/interface/helpers/custom_encoders.py +2 -2
  191. classiq/interface/helpers/custom_pydantic_types.py +8 -9
  192. classiq/interface/helpers/dotdict.py +18 -0
  193. classiq/interface/helpers/hashable_mixin.py +3 -2
  194. classiq/interface/helpers/hashable_pydantic_base_model.py +2 -1
  195. classiq/interface/helpers/pydantic_model_helpers.py +4 -3
  196. classiq/interface/helpers/validation_helpers.py +2 -2
  197. classiq/interface/ide/ide_data.py +11 -15
  198. classiq/interface/ide/visual_model.py +33 -22
  199. classiq/interface/jobs.py +2 -2
  200. classiq/interface/model/bind_operation.py +5 -4
  201. classiq/interface/model/classical_parameter_declaration.py +2 -2
  202. classiq/interface/model/handle_binding.py +3 -2
  203. classiq/interface/model/inplace_binary_operation.py +2 -1
  204. classiq/interface/model/model.py +12 -11
  205. classiq/interface/model/native_function_definition.py +10 -0
  206. classiq/interface/model/port_declaration.py +2 -2
  207. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +3 -2
  208. classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -2
  209. classiq/interface/model/quantum_expressions/quantum_expression.py +8 -7
  210. classiq/interface/model/quantum_function_call.py +9 -14
  211. classiq/interface/model/quantum_function_declaration.py +10 -12
  212. classiq/interface/model/quantum_lambda_function.py +3 -16
  213. classiq/interface/model/quantum_statement.py +4 -3
  214. classiq/interface/model/quantum_type.py +5 -5
  215. classiq/interface/model/statement_block.py +2 -3
  216. classiq/interface/model/validation_handle.py +5 -4
  217. classiq/interface/server/global_versions.py +3 -3
  218. classiq/model_expansions/atomic_expression_functions_defs.py +3 -2
  219. classiq/model_expansions/call_to_model_converter.py +190 -0
  220. classiq/model_expansions/capturing/captured_var_manager.py +4 -6
  221. classiq/model_expansions/capturing/propagated_var_stack.py +7 -7
  222. classiq/model_expansions/closure.py +17 -9
  223. classiq/model_expansions/evaluators/arg_type_match.py +3 -2
  224. classiq/model_expansions/evaluators/argument_types.py +3 -3
  225. classiq/model_expansions/evaluators/control.py +3 -3
  226. classiq/model_expansions/evaluators/parameter_types.py +7 -7
  227. classiq/model_expansions/evaluators/quantum_type_utils.py +2 -1
  228. classiq/model_expansions/evaluators/type_type_match.py +1 -1
  229. classiq/model_expansions/expression_evaluator.py +10 -9
  230. classiq/model_expansions/expression_renamer.py +6 -6
  231. classiq/model_expansions/function_builder.py +19 -12
  232. classiq/model_expansions/generative_functions.py +3 -2
  233. classiq/model_expansions/interpreter.py +31 -19
  234. classiq/model_expansions/model_tables.py +14 -14
  235. classiq/model_expansions/quantum_operations/bind.py +2 -4
  236. classiq/model_expansions/quantum_operations/classicalif.py +1 -1
  237. classiq/model_expansions/quantum_operations/control.py +2 -4
  238. classiq/model_expansions/quantum_operations/emitter.py +10 -13
  239. classiq/model_expansions/quantum_operations/expression_operation.py +23 -16
  240. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +164 -38
  241. classiq/model_expansions/quantum_operations/phase.py +6 -6
  242. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +25 -5
  243. classiq/model_expansions/quantum_operations/quantum_function_call.py +41 -2
  244. classiq/model_expansions/quantum_operations/repeat.py +1 -3
  245. classiq/model_expansions/scope.py +11 -10
  246. classiq/model_expansions/scope_initialization.py +6 -5
  247. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +6 -6
  248. classiq/model_expansions/sympy_conversion/sympy_to_python.py +2 -2
  249. classiq/model_expansions/visitors/variable_references.py +5 -4
  250. classiq/qmod/__init__.py +2 -0
  251. classiq/qmod/builtins/classical_execution_primitives.py +9 -9
  252. classiq/qmod/builtins/functions/__init__.py +75 -53
  253. classiq/qmod/builtins/functions/amplitude_estimation.py +4 -1
  254. classiq/qmod/builtins/functions/arithmetic.py +14 -1
  255. classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +86 -6
  256. classiq/qmod/builtins/functions/grover.py +41 -45
  257. classiq/qmod/builtins/functions/hea.py +60 -4
  258. classiq/qmod/builtins/functions/linear_pauli_rotation.py +26 -4
  259. classiq/qmod/builtins/functions/modular_exponentiation.py +90 -29
  260. classiq/qmod/builtins/functions/operators.py +1 -1
  261. classiq/qmod/builtins/functions/qaoa_penalty.py +14 -5
  262. classiq/qmod/builtins/functions/qft_functions.py +57 -0
  263. classiq/qmod/builtins/functions/qpe.py +20 -4
  264. classiq/qmod/builtins/functions/qsvt.py +49 -4
  265. classiq/qmod/builtins/functions/standard_gates.py +18 -18
  266. classiq/qmod/builtins/functions/state_preparation.py +92 -10
  267. classiq/qmod/builtins/functions/swap_test.py +7 -1
  268. classiq/qmod/builtins/functions/utility_functions.py +43 -0
  269. classiq/qmod/builtins/functions/variational.py +53 -0
  270. classiq/qmod/builtins/operations.py +4 -5
  271. classiq/qmod/cfunc.py +2 -2
  272. classiq/qmod/classical_function.py +3 -7
  273. classiq/qmod/create_model_function.py +19 -8
  274. classiq/qmod/declaration_inferrer.py +7 -10
  275. classiq/qmod/expression_query.py +3 -3
  276. classiq/qmod/generative.py +2 -1
  277. classiq/qmod/model_state_container.py +5 -7
  278. classiq/qmod/native/__init__.py +1 -3
  279. classiq/qmod/native/expression_to_qmod.py +9 -8
  280. classiq/qmod/native/pretty_printer.py +6 -5
  281. classiq/qmod/pretty_print/__init__.py +1 -3
  282. classiq/qmod/pretty_print/expression_to_python.py +13 -12
  283. classiq/qmod/pretty_print/pretty_printer.py +13 -12
  284. classiq/qmod/python_classical_type.py +8 -4
  285. classiq/qmod/qfunc.py +4 -4
  286. classiq/qmod/qmod_parameter.py +3 -1
  287. classiq/qmod/qmod_variable.py +11 -10
  288. classiq/qmod/quantum_expandable.py +32 -15
  289. classiq/qmod/quantum_function.py +34 -5
  290. classiq/qmod/semantics/annotation.py +1 -1
  291. classiq/qmod/semantics/error_manager.py +8 -7
  292. classiq/qmod/semantics/static_semantics_visitor.py +19 -24
  293. classiq/qmod/semantics/validation/constants_validation.py +1 -1
  294. classiq/qmod/semantics/validation/func_call_validation.py +2 -2
  295. classiq/qmod/semantics/validation/main_validation.py +33 -0
  296. classiq/qmod/semantics/validation/types_validation.py +2 -1
  297. classiq/qmod/symbolic.py +5 -8
  298. classiq/qmod/symbolic_type.py +2 -2
  299. classiq/qmod/synthesize_separately.py +16 -0
  300. {classiq-0.52.0.dist-info → classiq-0.54.0.dist-info}/METADATA +1 -1
  301. {classiq-0.52.0.dist-info → classiq-0.54.0.dist-info}/RECORD +302 -295
  302. classiq/qmod/builtins/functions/qft.py +0 -23
  303. {classiq-0.52.0.dist-info → classiq-0.54.0.dist-info}/WHEEL +0 -0
@@ -1,6 +1,7 @@
1
1
  # flake8: noqa
2
2
 
3
- from typing import Dict, List, Mapping, Optional, Type
3
+ from typing import Optional
4
+ from collections.abc import Mapping
4
5
 
5
6
  from classiq.interface.chemistry.fermionic_operator import (
6
7
  FermionicOperator,
@@ -53,17 +54,17 @@ from classiq.applications.chemistry.chemistry_execution_parameters import (
53
54
  from classiq.interface.exceptions import ClassiqError
54
55
  from classiq.qmod.utilities import qmod_val_to_expr_str
55
56
 
56
- _LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: Dict[str, str] = {
57
+ _LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: dict[str, str] = {
57
58
  "+": "PLUS",
58
59
  "-": "MINUS",
59
60
  }
60
61
 
61
- _CHEMISTRY_PROBLEM_PREFIX_MAPPING: Dict[Type[CHEMISTRY_PROBLEMS_TYPE], str] = {
62
+ _CHEMISTRY_PROBLEM_PREFIX_MAPPING: dict[type[CHEMISTRY_PROBLEMS_TYPE], str] = {
62
63
  MoleculeProblem: "molecule",
63
64
  HamiltonianProblem: "fock_hamiltonian",
64
65
  }
65
66
 
66
- _ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING: Dict[Type[AnsatzParameters], str] = {
67
+ _ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING: dict[type[AnsatzParameters], str] = {
67
68
  UCCParameters: "ucc",
68
69
  HVAParameters: "hva",
69
70
  }
@@ -71,7 +72,7 @@ _ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING: Dict[Type[AnsatzParameters], str] = {
71
72
  _EXECUTION_RESULT = "vqe_result"
72
73
  _MOLECULE_PROBLEM_RESULT = "molecule_result"
73
74
 
74
- _HAE_GATE_MAPPING: Dict[str, QuantumFunctionCall] = {
75
+ _HAE_GATE_MAPPING: dict[str, QuantumFunctionCall] = {
75
76
  "h": QuantumFunctionCall(
76
77
  function="H",
77
78
  positional_args=[HandleBinding(name="q")],
@@ -191,7 +192,7 @@ _HAE_GATE_MAPPING: Dict[str, QuantumFunctionCall] = {
191
192
  }
192
193
 
193
194
 
194
- def _atoms_to_qmod_atoms(atoms: List[Atom]) -> List[QmodChemistryAtom]:
195
+ def _atoms_to_qmod_atoms(atoms: list[Atom]) -> list[QmodChemistryAtom]:
195
196
  return [
196
197
  QmodChemistryAtom(
197
198
  element=Element[atom.symbol], # type:ignore[arg-type]
@@ -285,7 +286,7 @@ def _get_chemistry_function(
285
286
  chemistry_problem: CHEMISTRY_PROBLEMS_TYPE,
286
287
  chemistry_function_name: str,
287
288
  inouts: Mapping[IOName, HandleBinding],
288
- ansatz_parameters_expressions: Optional[List[Expression]] = None,
289
+ ansatz_parameters_expressions: Optional[list[Expression]] = None,
289
290
  ) -> QuantumFunctionCall:
290
291
  problem_prefix = _CHEMISTRY_PROBLEM_PREFIX_MAPPING[type(chemistry_problem)]
291
292
  return QuantumFunctionCall(
@@ -400,7 +401,7 @@ def _get_execution_result_post_processing_statements(
400
401
  raise ClassiqError(f"Invalid problem type: {problem}")
401
402
 
402
403
 
403
- def _count_parametric_gates(gates: List[str]) -> int:
404
+ def _count_parametric_gates(gates: list[str]) -> int:
404
405
  return sum(_is_parametric_gate(_HAE_GATE_MAPPING[gate]) for gate in gates)
405
406
 
406
407
 
@@ -415,7 +416,7 @@ def _get_hea_port_size(hea_parameters: HEAParameters) -> int:
415
416
 
416
417
  def _get_chemistry_quantum_main_params(
417
418
  ansatz_parameters: AnsatzParameters,
418
- ) -> List[ClassicalParameterDeclaration]:
419
+ ) -> list[ClassicalParameterDeclaration]:
419
420
  if not isinstance(ansatz_parameters, HEAParameters):
420
421
  return []
421
422
  return [
@@ -1,5 +1,6 @@
1
1
  import itertools
2
- from typing import List, Union
2
+ from functools import partial
3
+ from typing import Callable, Union
3
4
 
4
5
  import numpy as np
5
6
  import pyomo.environ as pyo
@@ -20,14 +21,17 @@ from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import
20
21
  )
21
22
  from classiq.applications.combinatorial_helpers.pyomo_utils import (
22
23
  convert_pyomo_to_global_presentation,
24
+ evaluate_objective,
25
+ pyomo_to_qmod_qstruct,
23
26
  )
24
27
  from classiq.qmod.builtins.structs import PauliTerm
28
+ from classiq.qmod.qmod_variable import QStruct
25
29
 
26
30
 
27
31
  def compute_qaoa_initial_point(
28
- hamiltonian: List[PauliTerm],
32
+ hamiltonian: list[PauliTerm],
29
33
  repetitions: int,
30
- ) -> List[float]:
34
+ ) -> list[float]:
31
35
  coeffs_ising = [pauli_term.coefficient for pauli_term in hamiltonian[1:]]
32
36
  # the first coeff is the II...I term
33
37
  coeffs_abs = np.abs(coeffs_ising) # type: ignore[arg-type]
@@ -42,26 +46,39 @@ def compute_qaoa_initial_point(
42
46
 
43
47
  def pyo_model_to_hamiltonian(
44
48
  pyo_model: pyo.ConcreteModel, penalty_energy: float
45
- ) -> List[PauliTerm]:
49
+ ) -> list[PauliTerm]:
46
50
  pauli_list = OptimizationModel(
47
51
  pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
48
52
  ).ising.pauli_list
49
53
  return pauli_operator_to_hamiltonian(pauli_list)
50
54
 
51
55
 
52
- def _str_to_list_int(str_ints: str) -> List[int]:
56
+ def pyo_model_to_qmod_problem(
57
+ pyo_model: pyo.ConcreteModel, penalty_energy: float
58
+ ) -> tuple[type[QStruct], Callable]:
59
+ optimization_model = OptimizationModel(
60
+ pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
61
+ )
62
+ qmod_struct = pyomo_to_qmod_qstruct("QAOAVars", optimization_model.vars_not_encoded)
63
+ cost_func = partial(
64
+ evaluate_objective, *optimization_model.objective_not_encoded_sympy
65
+ )
66
+ return qmod_struct, cost_func
67
+
68
+
69
+ def _str_to_list_int(str_ints: str) -> list[int]:
53
70
  return list(map(int, list(str_ints)))
54
71
 
55
72
 
56
73
  def _decode_vector_str(
57
74
  optimization_model: OptimizationModel, vector_str: str
58
- ) -> List[int]:
75
+ ) -> list[int]:
59
76
  return optimization_model.decode(
60
77
  _str_to_list_int(vector_str[::-1])
61
78
  ) # reverse qubit order
62
79
 
63
80
 
64
- def _evaluate_operator(operator: SparsePauliOp, state: Union[List[int], str]) -> float:
81
+ def _evaluate_operator(operator: SparsePauliOp, state: Union[list[int], str]) -> float:
65
82
  if isinstance(state, list):
66
83
  state = "".join([str(x) for x in state])
67
84
 
@@ -104,7 +121,7 @@ def _eigenstate_to_solution(
104
121
  def _get_combi_solution_histogram(
105
122
  optimization_model: OptimizationModel,
106
123
  vqe_result: VQESolverResult,
107
- ) -> List[QmodPyStruct]:
124
+ ) -> list[QmodPyStruct]:
108
125
  if vqe_result.reduced_probabilities is None:
109
126
  raise ValueError(
110
127
  "reduced_probabilities is optional only for backwards compatibility, but it should always be present here"
@@ -121,7 +138,7 @@ def get_optimization_solution_from_pyo(
121
138
  pyo_model: pyo.ConcreteModel,
122
139
  vqe_result: VQESolverResult,
123
140
  penalty_energy: float,
124
- ) -> List[QmodPyStruct]:
141
+ ) -> list[QmodPyStruct]:
125
142
  converted_pyo_model = convert_pyomo_to_global_presentation(pyo_model)
126
143
  optimization_model = OptimizationModel(
127
144
  converted_pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
@@ -1,6 +1,6 @@
1
1
  import itertools
2
2
  from dataclasses import dataclass, field
3
- from typing import Dict, List, Optional, Union
3
+ from typing import Optional, Union
4
4
 
5
5
  import pyomo.environ as pyo
6
6
  from pyomo.core.base import _GeneralVarData
@@ -16,20 +16,20 @@ from classiq.applications.combinatorial_helpers import pyomo_utils
16
16
  class VarExpressionMapping:
17
17
  var: _GeneralVarData
18
18
  expr: pyo.Expression
19
- encodings_vars: List[_GeneralVarData] = field(default_factory=list)
19
+ encodings_vars: list[_GeneralVarData] = field(default_factory=list)
20
20
 
21
21
 
22
22
  class EncodingMapping:
23
23
  def __init__(self, encoding_type: EncodingType) -> None:
24
- self._data: List[VarExpressionMapping] = []
24
+ self._data: list[VarExpressionMapping] = []
25
25
  self.encoding_type = encoding_type
26
26
 
27
27
  @property
28
- def original_vars(self) -> List[_GeneralVarData]:
28
+ def original_vars(self) -> list[_GeneralVarData]:
29
29
  return [pair.var for pair in self._data]
30
30
 
31
31
  @property
32
- def encodings_vars(self) -> List[_GeneralVarData]:
32
+ def encodings_vars(self) -> list[_GeneralVarData]:
33
33
  return list(
34
34
  itertools.chain.from_iterable(
35
35
  var_mapping.encodings_vars for var_mapping in self._data
@@ -37,7 +37,7 @@ class EncodingMapping:
37
37
  )
38
38
 
39
39
  @property
40
- def substitution_dict(self) -> Dict[int, pyo.Expression]:
40
+ def substitution_dict(self) -> dict[int, pyo.Expression]:
41
41
  return {id(mapping.var): mapping.expr for mapping in self._data}
42
42
 
43
43
  def __len__(self) -> int:
@@ -47,7 +47,7 @@ class EncodingMapping:
47
47
  self,
48
48
  original_var: _GeneralVarData,
49
49
  encoding_expr: pyo.Expression,
50
- encodings_vars: Union[List[_GeneralVarData], None] = None,
50
+ encodings_vars: Union[list[_GeneralVarData], None] = None,
51
51
  ) -> None:
52
52
  if encodings_vars is None:
53
53
  encodings_vars = list(identify_variables(encoding_expr))
@@ -59,7 +59,7 @@ class EncodingMapping:
59
59
  )
60
60
  )
61
61
 
62
- def _check_unique_encoding_vars(self, variables: List[_GeneralVarData]) -> None:
62
+ def _check_unique_encoding_vars(self, variables: list[_GeneralVarData]) -> None:
63
63
  assert all(
64
64
  not pyomo_utils.contains(var, self.encodings_vars) for var in variables
65
65
  )
@@ -72,7 +72,7 @@ class EncodingMapping:
72
72
  return var_expr_mapping
73
73
  raise ClassiqCombOptError("No variable expression mapping found.")
74
74
 
75
- def get_encoding_vars(self, original_var: _GeneralVarData) -> List[_GeneralVarData]:
75
+ def get_encoding_vars(self, original_var: _GeneralVarData) -> list[_GeneralVarData]:
76
76
  return self.get_var_expr_mapping(original_var).encodings_vars
77
77
 
78
78
  def get_original_var(
@@ -83,7 +83,7 @@ class EncodingMapping:
83
83
  return original_var
84
84
  return None
85
85
 
86
- def decode(self, solution: List[int]) -> List[int]:
86
+ def decode(self, solution: list[int]) -> list[int]:
87
87
  idx = 0
88
88
  decoded_solution = []
89
89
  for var_mapping in self._data:
@@ -1,6 +1,6 @@
1
1
  import math
2
2
  from itertools import filterfalse
3
- from typing import Any, Dict, Union, cast
3
+ from typing import Any, Union, cast
4
4
 
5
5
  import numpy as np
6
6
  import pyomo.environ as pyo
@@ -70,7 +70,7 @@ def recursively_remove_monomial_expr(obj: Any) -> None:
70
70
 
71
71
 
72
72
  def encode_expr(
73
- expr: pyo.Expression, substitution_dict: Dict[int, pyo.Expression]
73
+ expr: pyo.Expression, substitution_dict: dict[int, pyo.Expression]
74
74
  ) -> pyo.Expression:
75
75
  encoded_expr = clone_expression(expr=expr, substitute=substitution_dict)
76
76
  recursively_remove_monomial_expr(encoded_expr)
@@ -78,7 +78,7 @@ def encode_expr(
78
78
 
79
79
 
80
80
  def encode_constraints(
81
- model: pyo.ConcreteModel, substitution_dict: Dict[int, pyo.Expression]
81
+ model: pyo.ConcreteModel, substitution_dict: dict[int, pyo.Expression]
82
82
  ) -> None:
83
83
  all_constraints = pyomo_utils.extract(model, _GeneralConstraintData)
84
84
  constraints = filterfalse(is_obj_encoded, all_constraints)
@@ -107,7 +107,7 @@ def deal_with_trivial_boolean_constraint(
107
107
 
108
108
 
109
109
  def encode_objective(
110
- model: pyo.ConcreteModel, substitution_dict: Dict[int, pyo.Expression]
110
+ model: pyo.ConcreteModel, substitution_dict: dict[int, pyo.Expression]
111
111
  ) -> None:
112
112
  objective = next(model.component_objects(pyo.Objective))
113
113
 
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Dict, List, Tuple
4
-
5
3
  from pyomo.core.base import _GeneralVarData
6
4
 
7
5
  from classiq.interface.generator.function_params import IOName
@@ -21,13 +19,13 @@ class InternalQuantumReg:
21
19
  class MemoryMapping:
22
20
  def __init__(
23
21
  self,
24
- variables: List[_GeneralVarData],
22
+ variables: list[_GeneralVarData],
25
23
  vars_encoding_mapping: EncodingMapping | None = None,
26
24
  ) -> None:
27
- self.substitution_dict: Dict[int, InternalQuantumReg] = dict()
28
- self.qubit_allocation: Dict[IOName, Tuple[int, int]] = dict()
25
+ self.substitution_dict: dict[int, InternalQuantumReg] = dict()
26
+ self.qubit_allocation: dict[IOName, tuple[int, int]] = dict()
29
27
  self.vars_encoding_mapping: EncodingMapping | None = vars_encoding_mapping
30
- self.vars: List[_GeneralVarData] = variables
28
+ self.vars: list[_GeneralVarData] = variables
31
29
  self._allocate_memory()
32
30
 
33
31
  def __len__(self) -> int:
@@ -55,7 +53,7 @@ class MemoryMapping:
55
53
  )
56
54
 
57
55
  @property
58
- def qregs(self) -> List[InternalQuantumReg]:
56
+ def qregs(self) -> list[InternalQuantumReg]:
59
57
  return list(self.substitution_dict.values())
60
58
 
61
59
  @property
@@ -1,11 +1,13 @@
1
1
  import copy
2
+ from functools import cached_property
2
3
  from itertools import filterfalse
3
- from typing import List, Optional, Union
4
+ from typing import Optional, Union
4
5
 
5
6
  import pyomo.environ as pyo
6
7
  from pyomo.core import ConcreteModel
7
8
  from pyomo.core.base import _GeneralVarData
8
9
  from pyomo.core.base.constraint import _GeneralConstraintData
10
+ from pyomo.core.expr.sympy_tools import sympyify_expression
9
11
  from pyomo.environ import Expression
10
12
 
11
13
  from classiq.interface.chemistry.operator import PauliOperator
@@ -21,6 +23,7 @@ from classiq.applications.combinatorial_helpers import (
21
23
  )
22
24
  from classiq.applications.combinatorial_helpers.encoding_mapping import EncodingMapping
23
25
  from classiq.applications.combinatorial_helpers.memory import InternalQuantumReg
26
+ from classiq.applications.combinatorial_helpers.pyomo_utils import get_field_name
24
27
  from classiq.applications.combinatorial_helpers.transformations import (
25
28
  encoding,
26
29
  ising_converter,
@@ -72,23 +75,27 @@ class OptimizationModel:
72
75
  )
73
76
 
74
77
  self.is_maximization = sense.is_maximization(model_copy)
75
- self.objective = next(self._model.component_objects(pyo.Objective))
76
-
77
78
  self.penalty_energy = penalty_energy
78
- self._add_penalty_term()
79
79
 
80
- self.ising: PauliOperator = self._to_ising()
80
+ self.objective = next(self._model.component_objects(pyo.Objective))
81
+ if self.qsolver == QSolver.QAOAPenalty:
82
+ self.objective.expr += self._get_penalty_term(self.constraints)
83
+ if self.is_encoded:
84
+ self.objective.expr = self._model_encoder.encode_expr(
85
+ self.objective.expr
86
+ )
87
+ self._initialize_objective_not_encoded(model_copy)
81
88
 
82
89
  @property
83
- def vars(self) -> List[_GeneralVarData]:
90
+ def vars(self) -> list[_GeneralVarData]:
84
91
  return pyomo_utils.extract(self._model, _GeneralVarData)
85
92
 
86
93
  @property
87
- def vars_not_encoded(self) -> List[_GeneralVarData]:
94
+ def vars_not_encoded(self) -> list[_GeneralVarData]:
88
95
  return list(filterfalse(encoding_utils.is_obj_encoded, self.vars))
89
96
 
90
97
  @property
91
- def _ising_vars(self) -> List[_GeneralVarData]:
98
+ def _ising_vars(self) -> list[_GeneralVarData]:
92
99
  if self.is_encoded:
93
100
  return [
94
101
  var
@@ -100,12 +107,12 @@ class OptimizationModel:
100
107
  return self.vars
101
108
 
102
109
  @property
103
- def constraints(self) -> List[_GeneralConstraintData]:
110
+ def constraints(self) -> list[_GeneralConstraintData]:
104
111
  all_constraints = pyomo_utils.extract(self._model, _GeneralConstraintData)
105
112
  return list(filterfalse(encoding_utils.is_obj_encoded, all_constraints))
106
113
 
107
114
  @property
108
- def qregs(self) -> List[InternalQuantumReg]:
115
+ def qregs(self) -> list[InternalQuantumReg]:
109
116
  return self.memory_mapping.qregs
110
117
 
111
118
  @property
@@ -116,19 +123,14 @@ class OptimizationModel:
116
123
  def sign(self) -> int:
117
124
  return -1 if self.is_maximization else 1
118
125
 
119
- def _add_penalty_term(self) -> None:
120
- if self.qsolver == QSolver.QAOAPenalty:
121
- self.objective.expr += self._get_penalty_term()
122
-
123
- def _get_penalty_term(self) -> Union[int, Expression]:
124
- normalized_penalty_term = penalty.get_penalty_expression(self.constraints)
125
- penalty_term = self.penalty_energy * normalized_penalty_term * self.sign
126
-
127
- if self.is_encoded:
128
- penalty_term = self._model_encoder.encode_expr(penalty_term)
129
- return penalty_term
126
+ def _get_penalty_term(
127
+ self, constraints: list[_GeneralConstraintData]
128
+ ) -> Union[int, Expression]:
129
+ normalized_penalty_term = penalty.get_penalty_expression(constraints)
130
+ return self.penalty_energy * normalized_penalty_term * self.sign
130
131
 
131
- def _to_ising(self) -> PauliOperator:
132
+ @cached_property
133
+ def ising(self) -> PauliOperator:
132
134
  return (
133
135
  ising_converter.convert_pyomo_to_hamiltonian(
134
136
  self.objective.expr, self._ising_vars, self.qregs
@@ -136,11 +138,11 @@ class OptimizationModel:
136
138
  * self.sign
137
139
  )
138
140
 
139
- def _remove_slack_variables_from_solution(self, solution: List[int]) -> List[int]:
141
+ def _remove_slack_variables_from_solution(self, solution: list[int]) -> list[int]:
140
142
  variables = pyomo_utils.extract(self._model_original, pyo.Var)
141
143
  return solution[: len(variables)]
142
144
 
143
- def decode(self, solution: List[int]) -> List[int]:
145
+ def decode(self, solution: list[int]) -> list[int]:
144
146
  if self.is_encoded:
145
147
  solution = self._vars_encoding_mapping.decode(solution)
146
148
 
@@ -161,3 +163,20 @@ class OptimizationModel:
161
163
  self._model
162
164
  ):
163
165
  return slack_variables.slack_vars_convert(self._model)
166
+
167
+ def _initialize_objective_not_encoded(self, model_copy: pyo.ConcreteModel) -> None:
168
+ objective_not_encoded = next(model_copy.component_objects(pyo.Objective))
169
+ objective_map, objective_expr = sympyify_expression(objective_not_encoded)
170
+ objective_expr *= self.sign
171
+ if self.qsolver == QSolver.QAOAPenalty:
172
+ penalty = self._get_penalty_term(self.constraints)
173
+ penalty_map, penalty_expr = sympyify_expression(penalty)
174
+ objective_expr += penalty_expr * self.sign
175
+ objective_map.sympy2pyomo |= penalty_map.sympy2pyomo
176
+ for key, value in penalty_map.pyomo2sympy.items():
177
+ objective_map.pyomo2sympy[key] = value
178
+ sympy_mapping = {
179
+ sympy_var: get_field_name(pyomo_var)
180
+ for pyomo_var, sympy_var in objective_map.pyomo2sympy.items()
181
+ }
182
+ self.objective_not_encoded_sympy = sympy_mapping, objective_expr
@@ -1,5 +1,3 @@
1
- from typing import List
2
-
3
1
  from classiq.interface.exceptions import ClassiqNonNumericCoefficientInPauliError
4
2
  from classiq.interface.generator.functions.qmod_python_interface import QmodPyStruct
5
3
  from classiq.interface.helpers.custom_pydantic_types import PydanticPauliList
@@ -8,8 +6,8 @@ from classiq.qmod.builtins.enums import Pauli
8
6
  from classiq.qmod.builtins.structs import PauliTerm
9
7
 
10
8
 
11
- def pauli_operator_to_hamiltonian(pauli_list: PydanticPauliList) -> List[PauliTerm]:
12
- pauli_terms: List[PauliTerm] = []
9
+ def pauli_operator_to_hamiltonian(pauli_list: PydanticPauliList) -> list[PauliTerm]:
10
+ pauli_terms: list[PauliTerm] = []
13
11
  for pauli_term in pauli_list:
14
12
  if not isinstance(pauli_term[1], complex) or pauli_term[1].imag != 0:
15
13
  raise ClassiqNonNumericCoefficientInPauliError(
@@ -33,7 +31,7 @@ def pauli_enum_to_str(pauli: Pauli) -> str:
33
31
  }[pauli]
34
32
 
35
33
 
36
- def _pauli_terms_to_qmod(hamiltonian: List[PauliTerm]) -> str:
34
+ def _pauli_terms_to_qmod(hamiltonian: list[PauliTerm]) -> str:
37
35
  qmod_strings = []
38
36
  for term in hamiltonian:
39
37
  pauli_str = ", ".join([pauli_enum_to_str(p) for p in term.pauli]) # type: ignore[attr-defined]
@@ -44,5 +42,5 @@ def _pauli_terms_to_qmod(hamiltonian: List[PauliTerm]) -> str:
44
42
  return ", ".join(qmod_strings)
45
43
 
46
44
 
47
- def _pauli_dict_to_pauli_terms(hamiltonian: List[QmodPyStruct]) -> List[PauliTerm]:
45
+ def _pauli_dict_to_pauli_terms(hamiltonian: list[QmodPyStruct]) -> list[PauliTerm]:
48
46
  return [PauliTerm(**struct) for struct in hamiltonian]
@@ -1,6 +1,7 @@
1
- import json
1
+ import math
2
+ import re
2
3
  from enum import Enum
3
- from typing import Any, Dict, List, Optional, Tuple, Type, TypeVar, Union
4
+ from typing import Any, Optional, TypeVar, Union
4
5
 
5
6
  import pydantic
6
7
  import pyomo.core.expr.numeric_expr as pyo_expr
@@ -20,9 +21,21 @@ from pyomo.core.expr.sympy_tools import (
20
21
 
21
22
  from classiq.interface.exceptions import ClassiqValueError
22
23
  from classiq.interface.generator.expressions.expression import Expression
24
+ from classiq.interface.generator.functions.classical_type import Integer
23
25
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
24
26
 
25
- ListVars = List[_GeneralVarData]
27
+ from classiq.qmod.qmod_variable import QBit, QNum, QStruct, QVar
28
+ from classiq.qmod.symbolic_expr import SymbolicExpr
29
+
30
+ ListVars = list[_GeneralVarData]
31
+ SUPPORTED_TYPES = [
32
+ pyo.Binary,
33
+ pyo.Integers,
34
+ pyo.NegativeIntegers,
35
+ pyo.NonNegativeIntegers,
36
+ pyo.NonPositiveIntegers,
37
+ pyo.PositiveIntegers,
38
+ ]
26
39
 
27
40
 
28
41
  class ObjectiveType(Enum):
@@ -33,7 +46,7 @@ class ObjectiveType(Enum):
33
46
  class CombinatorialOptimizationStructDeclaration(StructDeclaration):
34
47
  variable_lower_bound: int = pydantic.Field(default=0)
35
48
  variable_upper_bound: int = pydantic.Field(default=1)
36
- constraints: List[Expression] = pydantic.Field(
49
+ constraints: list[Expression] = pydantic.Field(
37
50
  default_factory=list, description="List of constraint expressions"
38
51
  )
39
52
  objective_type: ObjectiveType = pydantic.Field(
@@ -72,7 +85,7 @@ def index(var_data: _GeneralVarData, vars_data: ListVars) -> int:
72
85
  T = TypeVar("T")
73
86
 
74
87
 
75
- def extract(model: ConcreteModel, type_: Type[T]) -> List[T]:
88
+ def extract(model: ConcreteModel, type_: type[T]) -> list[T]:
76
89
  if type_ == _GeneralVarData:
77
90
  type_ = Var
78
91
 
@@ -104,7 +117,7 @@ def delete_component(model: ConcreteModel, component: ComponentData) -> None:
104
117
  model.del_component(parent_component)
105
118
 
106
119
 
107
- def _delete_element_by_value(dict_: Dict, value: Any) -> None:
120
+ def _delete_element_by_value(dict_: dict, value: Any) -> None:
108
121
  iter_dict = {**dict_}
109
122
  for k, v in iter_dict.items():
110
123
  if v is value and k in dict_:
@@ -121,7 +134,7 @@ def get_name(component: Union[IndexedComponent, ComponentData]) -> str:
121
134
  class FixedSympy2PyomoVisitor(Sympy2PyomoVisitor):
122
135
  def beforeChild( # noqa: N802
123
136
  self, node: Optional[sympy.Expr], child: sympy.Expr, child_idx: Optional[int]
124
- ) -> Tuple[bool, Union[int, float, None]]:
137
+ ) -> tuple[bool, Union[int, float, None]]:
125
138
  if not child._args:
126
139
  item = self.object_map.getPyomoSymbol(child, None)
127
140
  if item is None:
@@ -142,10 +155,7 @@ def sympy2pyomo_expression(
142
155
  def convert_pyomo_to_global_presentation(
143
156
  pyo_model: pyo.ConcreteModel,
144
157
  ) -> pyo.ConcreteModel:
145
- pyo_model_str = pyomo2qmod("nativePyoModel", pyo_model)
146
- problem_struct = CombinatorialOptimizationStructDeclaration.model_validate_json(
147
- pyo_model_str
148
- )
158
+ problem_struct = pyomo2qmod("nativePyoModel", pyo_model)
149
159
 
150
160
  pyomo_model = pyo.ConcreteModel()
151
161
 
@@ -190,10 +200,12 @@ def convert_pyomo_to_global_presentation(
190
200
  return pyomo_model
191
201
 
192
202
 
193
- def pyomo2qmod(struct_name: str, pyo_model: ConcreteModel) -> str:
203
+ def pyomo2qmod(
204
+ struct_name: str, pyo_model: ConcreteModel
205
+ ) -> CombinatorialOptimizationStructDeclaration:
194
206
  symbols_map = PyomoSympyBimap()
195
207
 
196
- variables: List[sympy.Symbol] = []
208
+ variables: list[sympy.Symbol] = []
197
209
 
198
210
  bounds_set = False
199
211
  lower_bound = None
@@ -218,7 +230,7 @@ def pyomo2qmod(struct_name: str, pyo_model: ConcreteModel) -> str:
218
230
  upper_bound = var_dict[key].ub
219
231
  bounds_set = True
220
232
 
221
- constraint_exprs: List[sympy.Expr] = []
233
+ constraint_exprs: list[sympy.Expr] = []
222
234
 
223
235
  constraint_exprs.extend(
224
236
  Pyomo2SympyVisitor(symbols_map).walk_expression(constraint_dict[key].expr)
@@ -232,15 +244,74 @@ def pyomo2qmod(struct_name: str, pyo_model: ConcreteModel) -> str:
232
244
  pyo_objective
233
245
  )
234
246
 
235
- combi_struct_decl = {
236
- "name": struct_name,
237
- "variables": {str(variable): {"kind": "int"} for variable in variables},
238
- "variable_lower_bound": lower_bound,
239
- "variable_upper_bound": upper_bound,
240
- "constraints": [
241
- {"expr": str(constraint_expr)} for constraint_expr in constraint_exprs
247
+ return CombinatorialOptimizationStructDeclaration(
248
+ name=struct_name,
249
+ variables={str(variable): Integer() for variable in variables},
250
+ variable_lower_bound=lower_bound,
251
+ variable_upper_bound=upper_bound,
252
+ constraints=[
253
+ Expression(expr=str(constraint_expr))
254
+ for constraint_expr in constraint_exprs
242
255
  ],
243
- "objective_type": objective_type_str,
244
- "objective_function": {"expr": str(objective_expr)},
256
+ objective_type=objective_type_str,
257
+ objective_function=Expression(expr=str(objective_expr)),
258
+ )
259
+
260
+
261
+ def pyomo_to_qmod_qstruct(
262
+ struct_name: str, vars: list[_GeneralVarData]
263
+ ) -> type[QStruct]:
264
+ qmod_struct = type(struct_name, (QStruct,), {})
265
+ var_names = {get_field_name(var): var for var in vars}
266
+ qmod_struct.__annotations__ = {
267
+ var_name: _get_qmod_field_type(var_name, var_data)
268
+ for var_name, var_data in var_names.items()
245
269
  }
246
- return json.dumps(combi_struct_decl, indent=2)
270
+ return qmod_struct
271
+
272
+
273
+ def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]:
274
+ if var_data.domain not in SUPPORTED_TYPES:
275
+ raise ClassiqValueError(
276
+ f"Type {str(var_data.domain)!r} of variable {var_name!r} is not supported"
277
+ )
278
+
279
+ if var_data.domain == pyo.Binary:
280
+ return QBit
281
+
282
+ bounds = var_data.bounds
283
+ if bounds is None:
284
+ raise ClassiqValueError(f"Variable {var_name!r} has no bounds")
285
+ lb, ub = bounds
286
+ if not isinstance(lb, int) or not isinstance(ub, int):
287
+ raise ClassiqValueError(
288
+ f"Non-integer bounds for variable {var_name!r} are not supported"
289
+ )
290
+ if lb > 0:
291
+ ub -= lb
292
+ qnum: Any = QNum # mypy shenanigans
293
+ return qnum[math.ceil(math.log2(ub - lb)), False, 0]
294
+
295
+
296
+ def evaluate_objective(
297
+ var_mapping: dict, sympy_expr: sympy.Expr, struct_obj: Any
298
+ ) -> Any:
299
+ sympy_assignment = {
300
+ sympy_var: getattr(struct_obj, field_name)
301
+ for sympy_var, field_name in var_mapping.items()
302
+ }
303
+
304
+ # classical objective evaluation
305
+ if not isinstance(struct_obj, QStruct):
306
+ return float(sympy_expr.evalf(subs=sympy_assignment))
307
+
308
+ # quantum objective evaluation
309
+ expr_str = str(sympy_expr).replace("'", "")
310
+ for var_name, var_value in sympy_assignment.items():
311
+ var_name = str(var_name).replace("'", "")
312
+ expr_str = re.sub(rf"\b{var_name}\b", str(var_value), expr_str)
313
+ return SymbolicExpr(expr=expr_str, is_quantum=True)
314
+
315
+
316
+ def get_field_name(var: _GeneralVarData) -> str:
317
+ return var.local_name.replace("[", "_").replace("]", "")
@@ -1,4 +1,4 @@
1
- from typing import List, Optional
1
+ from typing import Optional
2
2
 
3
3
  import pyomo.core as pyo
4
4
  from pyomo.core.base import _GeneralVarData
@@ -6,7 +6,7 @@ from pyomo.core.expr.sympy_tools import Pyomo2SympyVisitor, PyomoSympyBimap
6
6
  from sympy import Expr
7
7
 
8
8
 
9
- def sympyify_vars(variables: List[_GeneralVarData]) -> PyomoSympyBimap:
9
+ def sympyify_vars(variables: list[_GeneralVarData]) -> PyomoSympyBimap:
10
10
  symbols_map = PyomoSympyBimap()
11
11
  for var in variables:
12
12
  Pyomo2SympyVisitor(symbols_map).walk_expression(var)