classiq 0.37.1__py3-none-any.whl → 0.38.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 (228) hide show
  1. classiq/__init__.py +2 -2
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +1 -1
  3. classiq/_analyzer_extras/interactive_hardware.py +3 -3
  4. classiq/_internals/api_wrapper.py +24 -16
  5. classiq/_internals/async_utils.py +1 -74
  6. classiq/_internals/authentication/device.py +9 -4
  7. classiq/_internals/authentication/password_manager.py +25 -10
  8. classiq/_internals/authentication/token_manager.py +2 -2
  9. classiq/_internals/client.py +13 -5
  10. classiq/_internals/jobs.py +10 -7
  11. classiq/analyzer/analyzer.py +26 -28
  12. classiq/analyzer/analyzer_utilities.py +5 -5
  13. classiq/analyzer/rb.py +4 -5
  14. classiq/analyzer/show_interactive_hack.py +6 -6
  15. classiq/applications/benchmarking/mirror_benchmarking.py +9 -6
  16. classiq/applications/combinatorial_optimization/__init__.py +5 -0
  17. classiq/applications/qnn/circuit_utils.py +2 -2
  18. classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
  19. classiq/applications/qnn/types.py +2 -2
  20. classiq/applications/qsvm/qsvm.py +4 -7
  21. classiq/applications/qsvm/qsvm_data_generation.py +2 -5
  22. classiq/applications_model_constructors/__init__.py +9 -1
  23. classiq/applications_model_constructors/chemistry_model_constructor.py +9 -16
  24. classiq/applications_model_constructors/combinatorial_helpers/__init__.py +0 -0
  25. classiq/applications_model_constructors/combinatorial_helpers/allowed_constraints.py +20 -0
  26. classiq/applications_model_constructors/combinatorial_helpers/arithmetic/__init__.py +0 -0
  27. classiq/applications_model_constructors/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
  28. classiq/applications_model_constructors/combinatorial_helpers/arithmetic/isolation.py +42 -0
  29. classiq/applications_model_constructors/combinatorial_helpers/combinatorial_problem_utils.py +130 -0
  30. classiq/applications_model_constructors/combinatorial_helpers/encoding_mapping.py +107 -0
  31. classiq/applications_model_constructors/combinatorial_helpers/encoding_utils.py +122 -0
  32. classiq/applications_model_constructors/combinatorial_helpers/memory.py +79 -0
  33. classiq/applications_model_constructors/combinatorial_helpers/multiple_comp_basis_sp.py +34 -0
  34. classiq/applications_model_constructors/combinatorial_helpers/optimization_model.py +166 -0
  35. classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/__init__.py +0 -0
  36. classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
  37. classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/pauli_utils.py +65 -0
  38. classiq/applications_model_constructors/combinatorial_helpers/py.typed +0 -0
  39. classiq/applications_model_constructors/combinatorial_helpers/pyomo_utils.py +243 -0
  40. classiq/applications_model_constructors/combinatorial_helpers/sympy_utils.py +22 -0
  41. classiq/applications_model_constructors/combinatorial_helpers/transformations/__init__.py +0 -0
  42. classiq/applications_model_constructors/combinatorial_helpers/transformations/encoding.py +194 -0
  43. classiq/applications_model_constructors/combinatorial_helpers/transformations/fixed_variables.py +144 -0
  44. classiq/applications_model_constructors/combinatorial_helpers/transformations/ising_converter.py +124 -0
  45. classiq/applications_model_constructors/combinatorial_helpers/transformations/penalty.py +32 -0
  46. classiq/applications_model_constructors/combinatorial_helpers/transformations/penalty_support.py +41 -0
  47. classiq/applications_model_constructors/combinatorial_helpers/transformations/sign_seperation.py +75 -0
  48. classiq/applications_model_constructors/combinatorial_helpers/transformations/slack_variables.py +90 -0
  49. classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +48 -91
  50. classiq/applications_model_constructors/finance_model_constructor.py +4 -17
  51. classiq/applications_model_constructors/grover_model_constructor.py +20 -91
  52. classiq/applications_model_constructors/libraries/qmci_library.py +17 -19
  53. classiq/builtin_functions/standard_gates.py +1 -1
  54. classiq/exceptions.py +43 -1
  55. classiq/executor.py +10 -9
  56. classiq/interface/_version.py +1 -1
  57. classiq/interface/analyzer/analysis_params.py +6 -3
  58. classiq/interface/analyzer/result.py +12 -4
  59. classiq/interface/applications/qsvm.py +13 -1
  60. classiq/interface/backend/backend_preferences.py +4 -2
  61. classiq/interface/backend/pydantic_backend.py +3 -1
  62. classiq/interface/backend/quantum_backend_providers.py +1 -0
  63. classiq/interface/chemistry/fermionic_operator.py +15 -13
  64. classiq/interface/chemistry/ground_state_problem.py +18 -3
  65. classiq/interface/chemistry/molecule.py +8 -6
  66. classiq/interface/chemistry/operator.py +20 -14
  67. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
  68. classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
  69. classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
  70. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
  71. classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
  72. classiq/interface/combinatorial_optimization/examples/mht.py +3 -3
  73. classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
  74. classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
  75. classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
  76. classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
  77. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
  78. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
  79. classiq/interface/executor/aws_execution_cost.py +4 -3
  80. classiq/interface/executor/estimation.py +2 -2
  81. classiq/interface/executor/execution_preferences.py +5 -34
  82. classiq/interface/executor/execution_request.py +19 -17
  83. classiq/interface/executor/optimizer_preferences.py +22 -13
  84. classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
  85. classiq/interface/executor/quantum_instruction_set.py +2 -1
  86. classiq/interface/executor/register_initialization.py +1 -3
  87. classiq/interface/executor/result.py +41 -10
  88. classiq/interface/executor/vqe_result.py +1 -1
  89. classiq/interface/finance/function_input.py +17 -4
  90. classiq/interface/finance/gaussian_model_input.py +3 -1
  91. classiq/interface/finance/log_normal_model_input.py +3 -1
  92. classiq/interface/finance/model_input.py +2 -0
  93. classiq/interface/generator/amplitude_loading.py +6 -3
  94. classiq/interface/generator/application_apis/__init__.py +1 -0
  95. classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
  96. classiq/interface/generator/arith/argument_utils.py +14 -4
  97. classiq/interface/generator/arith/arithmetic.py +3 -1
  98. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
  99. classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
  100. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
  101. classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
  102. classiq/interface/generator/arith/arithmetic_operations.py +5 -10
  103. classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
  104. classiq/interface/generator/arith/binary_ops.py +202 -54
  105. classiq/interface/generator/arith/extremum_operations.py +5 -3
  106. classiq/interface/generator/arith/logical_ops.py +4 -2
  107. classiq/interface/generator/arith/machine_precision.py +3 -0
  108. classiq/interface/generator/arith/number_utils.py +34 -44
  109. classiq/interface/generator/arith/register_user_input.py +21 -1
  110. classiq/interface/generator/arith/unary_ops.py +16 -25
  111. classiq/interface/generator/chemistry_function_params.py +4 -4
  112. classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
  113. classiq/interface/generator/compiler_keywords.py +4 -0
  114. classiq/interface/generator/complex_type.py +3 -10
  115. classiq/interface/generator/control_state.py +5 -3
  116. classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
  117. classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
  118. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
  119. classiq/interface/generator/expressions/evaluated_expression.py +18 -4
  120. classiq/interface/generator/expressions/expression.py +1 -1
  121. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
  122. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  123. classiq/interface/generator/finance.py +1 -1
  124. classiq/interface/generator/function_params.py +7 -6
  125. classiq/interface/generator/functions/__init__.py +1 -1
  126. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +505 -138
  127. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +25 -99
  128. classiq/interface/generator/functions/foreign_function_definition.py +12 -4
  129. classiq/interface/generator/functions/function_implementation.py +8 -4
  130. classiq/interface/generator/functions/native_function_definition.py +4 -2
  131. classiq/interface/generator/functions/register.py +4 -2
  132. classiq/interface/generator/functions/register_mapping_data.py +14 -10
  133. classiq/interface/generator/generated_circuit_data.py +2 -2
  134. classiq/interface/generator/grover_operator.py +5 -3
  135. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
  136. classiq/interface/generator/hardware/hardware_data.py +6 -4
  137. classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
  138. classiq/interface/generator/hartree_fock.py +3 -1
  139. classiq/interface/generator/linear_pauli_rotations.py +3 -1
  140. classiq/interface/generator/mcu.py +5 -3
  141. classiq/interface/generator/mcx.py +7 -5
  142. classiq/interface/generator/model/constraints.py +2 -1
  143. classiq/interface/generator/model/model.py +11 -19
  144. classiq/interface/generator/model/preferences/preferences.py +4 -3
  145. classiq/interface/generator/oracles/custom_oracle.py +4 -2
  146. classiq/interface/generator/oracles/oracle_abc.py +2 -2
  147. classiq/interface/generator/qpe.py +6 -4
  148. classiq/interface/generator/qsvm.py +5 -8
  149. classiq/interface/generator/quantum_function_call.py +21 -16
  150. classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
  151. classiq/interface/generator/range_types.py +3 -1
  152. classiq/interface/generator/slice_parsing_utils.py +8 -3
  153. classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
  154. classiq/interface/generator/state_preparation/metrics.py +2 -1
  155. classiq/interface/generator/state_preparation/state_preparation.py +7 -5
  156. classiq/interface/generator/state_propagator.py +16 -5
  157. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
  158. classiq/interface/generator/types/struct_declaration.py +8 -3
  159. classiq/interface/generator/ucc.py +6 -4
  160. classiq/interface/generator/unitary_gate.py +7 -3
  161. classiq/interface/generator/validations/flow_graph.py +6 -4
  162. classiq/interface/generator/validations/validator_functions.py +6 -4
  163. classiq/interface/hardware.py +2 -2
  164. classiq/interface/helpers/custom_encoders.py +3 -0
  165. classiq/interface/helpers/pydantic_model_helpers.py +0 -6
  166. classiq/interface/helpers/validation_helpers.py +1 -1
  167. classiq/interface/helpers/versioned_model.py +4 -1
  168. classiq/interface/ide/show.py +2 -2
  169. classiq/interface/jobs.py +72 -3
  170. classiq/interface/model/bind_operation.py +18 -11
  171. classiq/interface/model/call_synthesis_data.py +68 -0
  172. classiq/interface/model/inplace_binary_operation.py +2 -2
  173. classiq/interface/model/model.py +27 -21
  174. classiq/interface/model/native_function_definition.py +3 -5
  175. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
  176. classiq/interface/model/quantum_expressions/control_state.py +2 -2
  177. classiq/interface/model/quantum_function_call.py +25 -139
  178. classiq/interface/model/quantum_function_declaration.py +8 -0
  179. classiq/interface/model/quantum_if_operation.py +2 -3
  180. classiq/interface/model/quantum_lambda_function.py +64 -0
  181. classiq/interface/model/quantum_type.py +57 -56
  182. classiq/interface/model/quantum_variable_declaration.py +1 -1
  183. classiq/interface/model/statement_block.py +32 -0
  184. classiq/interface/model/validations/handles_validator.py +14 -12
  185. classiq/interface/model/within_apply_operation.py +11 -0
  186. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
  187. classiq/interface/server/routes.py +5 -0
  188. classiq/model/function_handler.py +5 -9
  189. classiq/model/model.py +2 -19
  190. classiq/qmod/__init__.py +13 -6
  191. classiq/qmod/builtins/classical_execution_primitives.py +27 -36
  192. classiq/qmod/builtins/classical_functions.py +24 -14
  193. classiq/qmod/builtins/functions.py +162 -145
  194. classiq/qmod/builtins/operations.py +24 -35
  195. classiq/qmod/builtins/structs.py +15 -15
  196. classiq/qmod/cfunc.py +42 -0
  197. classiq/qmod/classical_function.py +6 -14
  198. classiq/qmod/declaration_inferrer.py +12 -21
  199. classiq/qmod/expression_query.py +23 -0
  200. classiq/qmod/model_state_container.py +2 -0
  201. classiq/qmod/native/__init__.py +0 -0
  202. classiq/qmod/native/expression_to_qmod.py +189 -0
  203. classiq/qmod/native/pretty_printer.py +311 -0
  204. classiq/qmod/qfunc.py +27 -0
  205. classiq/qmod/qmod_constant.py +76 -0
  206. classiq/qmod/qmod_parameter.py +34 -12
  207. classiq/qmod/qmod_struct.py +3 -3
  208. classiq/qmod/qmod_variable.py +102 -18
  209. classiq/qmod/quantum_expandable.py +16 -16
  210. classiq/qmod/quantum_function.py +37 -8
  211. classiq/qmod/symbolic.py +47 -4
  212. classiq/qmod/symbolic_expr.py +9 -0
  213. classiq/qmod/utilities.py +13 -0
  214. classiq/qmod/write_qmod.py +39 -0
  215. classiq/quantum_functions/__init__.py +2 -2
  216. classiq/quantum_functions/annotation_parser.py +9 -11
  217. classiq/quantum_functions/function_parser.py +1 -1
  218. classiq/quantum_functions/quantum_function.py +3 -3
  219. classiq/quantum_register.py +17 -9
  220. {classiq-0.37.1.dist-info → classiq-0.38.0.dist-info}/METADATA +2 -1
  221. {classiq-0.37.1.dist-info → classiq-0.38.0.dist-info}/RECORD +222 -186
  222. {classiq-0.37.1.dist-info → classiq-0.38.0.dist-info}/WHEEL +1 -1
  223. classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
  224. classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
  225. classiq/interface/generator/types/combinatorial_problem.py +0 -26
  226. classiq/interface/model/numeric_reinterpretation.py +0 -25
  227. classiq/interface/model/operator_synthesis_data.py +0 -48
  228. classiq/model/function_handler.pyi +0 -152
@@ -2,7 +2,7 @@ from typing import Dict, List, Union
2
2
 
3
3
  from classiq.interface.analyzer import analysis_params
4
4
  from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
5
- from classiq.interface.generator.generated_circuit import GeneratedCircuit
5
+ from classiq.interface.generator.quantum_program import QuantumProgram
6
6
 
7
7
  from classiq._internals.api_wrapper import ApiWrapper
8
8
  from classiq.exceptions import ClassiqAnalyzerError
@@ -22,16 +22,16 @@ class AnalyzerUtilities:
22
22
  def __init__(
23
23
  self,
24
24
  params: analysis_params.AnalysisParams,
25
- circuit: GeneratedCircuit,
25
+ circuit: QuantumProgram,
26
26
  available_devices: ProviderAvailableDevices,
27
27
  hardware_graphs: HardwareGraphs,
28
28
  ) -> None:
29
29
  self._params: analysis_params.AnalysisParams = params
30
- self.circuit: GeneratedCircuit = circuit
30
+ self.circuit: QuantumProgram = circuit
31
31
  self.available_devices = available_devices
32
32
  self.hardware_graphs = hardware_graphs
33
33
 
34
- async def request_available_devices_async(
34
+ async def _request_available_devices_async(
35
35
  self, providers: List[ProviderNameEnum]
36
36
  ) -> None:
37
37
  requested_providers = self._requested_providers_filter(providers)
@@ -58,7 +58,7 @@ class AnalyzerUtilities:
58
58
  async def _device_validation_async(
59
59
  self, provider: ProviderNameEnum, device: DeviceName
60
60
  ) -> None:
61
- await self.request_available_devices_async(providers=[provider])
61
+ await self._request_available_devices_async(providers=[provider])
62
62
  provider_lower_name = _to_lower_case(provider)
63
63
  available_device_dict = self.available_devices
64
64
  if available_device_dict[provider_lower_name].get(device) is False:
classiq/analyzer/rb.py CHANGED
@@ -10,12 +10,11 @@ from classiq.interface.analyzer.analysis_params import AnalysisRBParams
10
10
  from classiq.interface.analyzer.result import RbResults
11
11
 
12
12
  from classiq._internals.api_wrapper import ApiWrapper
13
- from classiq._internals.async_utils import Asyncify
14
13
  from classiq.exceptions import ClassiqAnalyzerError
15
14
  from classiq.executor import BackendPreferencesAndResult
16
15
 
17
16
 
18
- class RBAnalysis(metaclass=Asyncify):
17
+ class RBAnalysis:
19
18
  def __init__(self, experiments_data: List[AnalysisRBParams]) -> None:
20
19
  """Init self.
21
20
 
@@ -67,9 +66,9 @@ class RBAnalysis(metaclass=Asyncify):
67
66
  df = self._total_results.loc[["mean_fidelity", "average_error"]].transpose()
68
67
  hardware = list(df.index)
69
68
  params = list(df.columns)
70
- data = []
71
- for param in params:
72
- data.append(go.Bar(name=param, x=hardware, y=df[param].values * 100))
69
+ data = [
70
+ go.Bar(name=param, x=hardware, y=df[param].values * 100) for param in params
71
+ ]
73
72
  fig = go.Figure(data).update_layout(
74
73
  title="RB hardware comparison",
75
74
  barmode="group",
@@ -1,26 +1,26 @@
1
1
  import webbrowser
2
2
  from urllib.parse import urljoin
3
3
 
4
- from classiq.interface.generator.generated_circuit import GeneratedCircuit
4
+ from classiq.interface.generator.quantum_program import QuantumProgram
5
5
 
6
6
  from classiq._internals.api_wrapper import ApiWrapper
7
7
  from classiq._internals.async_utils import syncify_function
8
8
  from classiq.analyzer.url_utils import circuit_page_uri, client_ide_base_url
9
9
 
10
10
 
11
- async def handle_remote_app(circuit: GeneratedCircuit) -> None:
11
+ async def handle_remote_app(circuit: QuantumProgram) -> None:
12
12
  circuit_dataid = await ApiWrapper.call_analyzer_app(circuit)
13
13
  app_url = urljoin(
14
14
  client_ide_base_url(),
15
15
  circuit_page_uri(circuit_id=circuit_dataid.id, circuit_version=circuit.version),
16
16
  )
17
- print(f"Opening: {app_url}")
17
+ print(f"Opening: {app_url}") # noqa: T201
18
18
  webbrowser.open_new_tab(app_url)
19
19
 
20
20
 
21
- async def _show_interactive(self: GeneratedCircuit) -> None:
21
+ async def _show_interactive(self: QuantumProgram) -> None:
22
22
  await handle_remote_app(circuit=self)
23
23
 
24
24
 
25
- GeneratedCircuit.show = syncify_function(_show_interactive) # type: ignore[attr-defined]
26
- GeneratedCircuit.show_async = _show_interactive # type: ignore[attr-defined]
25
+ QuantumProgram.show = syncify_function(_show_interactive) # type: ignore[attr-defined]
26
+ QuantumProgram.show_async = _show_interactive # type: ignore[attr-defined]
@@ -1,15 +1,15 @@
1
1
  from copy import deepcopy
2
2
 
3
- from classiq.interface.generator.generated_circuit import GeneratedCircuit
4
3
  from classiq.interface.generator.model.preferences.preferences import (
5
4
  Preferences,
6
5
  QuantumFormat,
7
6
  TranspilationOption,
8
7
  )
8
+ from classiq.interface.generator.quantum_program import QuantumProgram
9
9
 
10
- from classiq._internals.async_utils import Asyncify
10
+ from classiq._internals import async_utils
11
11
  from classiq.model.model import Model
12
- from classiq.quantum_functions.decorators import quantum_function as qfunc
12
+ from classiq.quantum_functions.decorators import quantum_function
13
13
  from classiq.quantum_functions.function_library import QASM_INTRO, FunctionLibrary
14
14
  from classiq.quantum_register import QReg, ZeroQReg
15
15
  from classiq.synthesis import synthesize_async
@@ -18,7 +18,7 @@ _MB_NAME: str = "mirror_benchmarking"
18
18
  _MB_FUNCTION_LIBRARY_NAME: str = f"{_MB_NAME}_function_library"
19
19
 
20
20
 
21
- class MirrorBenchmarking(metaclass=Asyncify):
21
+ class MirrorBenchmarking:
22
22
  def __init__(self, model: Model) -> None:
23
23
  self.functional_model: Model = model
24
24
  self.functional_model._model.preferences = self.get_functional_preferences(
@@ -26,7 +26,7 @@ class MirrorBenchmarking(metaclass=Asyncify):
26
26
  )
27
27
 
28
28
  async def mirror_benchmarking_model_async(self) -> Model:
29
- functional_circuit: GeneratedCircuit = GeneratedCircuit.parse_raw(
29
+ functional_circuit: QuantumProgram = QuantumProgram.parse_raw(
30
30
  await synthesize_async(self.functional_model.get_model())
31
31
  )
32
32
 
@@ -38,7 +38,7 @@ class MirrorBenchmarking(metaclass=Asyncify):
38
38
  )
39
39
  circuit_qasm: str = circuit_qasm_list[-1]
40
40
 
41
- @qfunc
41
+ @quantum_function
42
42
  def functional_model_function(reg: ZeroQReg[num_qubits]) -> QReg[num_qubits]: # type: ignore[type-arg, valid-type]
43
43
  return QASM_INTRO + circuit_qasm # type: ignore[return-value]
44
44
 
@@ -54,6 +54,9 @@ class MirrorBenchmarking(metaclass=Asyncify):
54
54
  mb_model.functional_model_function(in_wires=inner_wires, is_inverse=True)
55
55
  return mb_model
56
56
 
57
+ def mirror_benchmarking_model(self) -> Model:
58
+ return async_utils.run(self.mirror_benchmarking_model_async())
59
+
57
60
  @staticmethod
58
61
  def get_functional_preferences(preferences: Preferences) -> Preferences:
59
62
  functional_preferences = deepcopy(preferences)
@@ -3,6 +3,10 @@ from typing import List
3
3
  from classiq.interface.combinatorial_optimization import examples
4
4
  from classiq.interface.combinatorial_optimization.solver_types import QSolver
5
5
 
6
+ from classiq.applications_model_constructors.combinatorial_helpers.combinatorial_problem_utils import (
7
+ get_optimization_solution_from_pyo,
8
+ )
9
+
6
10
  from .combinatorial_optimization_config import OptimizerConfig, QAOAConfig
7
11
 
8
12
  __all__ = [
@@ -10,6 +14,7 @@ __all__ = [
10
14
  "examples",
11
15
  "QAOAConfig",
12
16
  "OptimizerConfig",
17
+ "get_optimization_solution_from_pyo",
13
18
  ]
14
19
 
15
20
 
@@ -5,8 +5,8 @@ from typing import Iterable, List, Tuple, Union
5
5
  from torch import Tensor
6
6
 
7
7
  from classiq.interface.generator.circuit_code.types_and_constants import QasmVersion
8
- from classiq.interface.generator.generated_circuit import GeneratedCircuit
9
8
  from classiq.interface.generator.model.preferences.preferences import QuantumFormat
9
+ from classiq.interface.generator.quantum_program import QuantumProgram
10
10
 
11
11
  from classiq.applications.qnn.types import Arguments, Circuit
12
12
  from classiq.exceptions import ClassiqQNNError, ClassiqValueError
@@ -95,7 +95,7 @@ def _get_extracted_parameters(obj: CircuitOrExtractedParameters) -> ParametersTu
95
95
  # This `if` is for caching
96
96
  if isinstance(obj, tuple):
97
97
  weight_params, input_params = obj
98
- elif isinstance(obj, GeneratedCircuit):
98
+ elif isinstance(obj, QuantumProgram):
99
99
  weight_params, input_params = extract_parameters(obj)
100
100
  else:
101
101
  raise ClassiqValueError("Invalid object passed to `map_parameters`")
@@ -4,7 +4,7 @@ from typing import Any
4
4
 
5
5
  from torch import Tensor
6
6
 
7
- from classiq.interface.generator.generated_circuit import GeneratedCircuit
7
+ from classiq.interface.generator.quantum_program import QuantumProgram
8
8
 
9
9
  from classiq.applications.qnn.circuit_utils import extract_parameters, validate_circuit
10
10
  from classiq.applications.qnn.types import ExecuteFunction, PostProcessFunction
@@ -23,7 +23,7 @@ class QuantumGradient(abc.ABC):
23
23
  self._execute = execute
24
24
  self._post_process = post_process
25
25
 
26
- circuit = GeneratedCircuit.parse_raw(quantum_program)
26
+ circuit = QuantumProgram.parse_raw(quantum_program)
27
27
  validate_circuit(circuit)
28
28
  self._quantum_program = quantum_program
29
29
  self._parameters_names = extract_parameters(circuit)
@@ -5,13 +5,13 @@ from torch import Tensor
5
5
 
6
6
  from classiq.interface.executor.execution_result import ResultsCollection, SavedResult
7
7
 
8
- from classiq import GeneratedCircuit
8
+ from classiq import QuantumProgram
9
9
  from classiq.synthesis import SerializedQuantumProgram
10
10
 
11
11
  Arguments = Dict[str, float]
12
12
  MultipleArguments = Tuple[Arguments, ...]
13
13
 
14
- Circuit = GeneratedCircuit
14
+ Circuit = QuantumProgram
15
15
  ExecuteFunction = Callable[
16
16
  [SerializedQuantumProgram, MultipleArguments], ResultsCollection
17
17
  ]
@@ -1,15 +1,12 @@
1
- from typing import Any, List, Union
1
+ from typing import List
2
2
 
3
- import numpy as np
4
-
5
- from classiq.interface.applications.qsvm import DataList, QSVMData, QSVMPreferences
6
-
7
- Data = Union[DataList, np.ndarray]
8
- Labels = Union[List[Any], np.ndarray]
3
+ from classiq.interface.applications.qsvm import Data, Labels, QSVMData, QSVMPreferences
9
4
 
10
5
  __all__ = [
11
6
  "QSVMData",
12
7
  "QSVMPreferences",
8
+ "Data",
9
+ "Labels",
13
10
  ]
14
11
 
15
12
 
@@ -24,11 +24,8 @@ def generate_data(
24
24
 
25
25
  results = {}
26
26
  for index, s in enumerate(sources):
27
- temp = []
28
- # for each dimension
29
- for point in s:
30
- # draw from a gaussian distribution
31
- temp.append(np.random.normal(point, std, amount))
27
+ # for each dimension draw from a gaussian distribution
28
+ temp = [np.random.normal(point, std, amount) for point in s]
32
29
  # combine the list of np.arrays
33
30
  results[index] = np.array(list(zip(*temp)))
34
31
 
@@ -1,6 +1,9 @@
1
1
  from typing import List
2
2
 
3
- from .chemistry_model_constructor import construct_chemistry_model
3
+ from .chemistry_model_constructor import (
4
+ construct_chemistry_model,
5
+ molecule_problem_to_qmod,
6
+ )
4
7
  from .combinatorial_optimization_model_constructor import (
5
8
  construct_combinatorial_optimization_model,
6
9
  )
@@ -14,4 +17,9 @@ __all__: List[str] = [
14
17
  "construct_chemistry_model",
15
18
  "construct_finance_model",
16
19
  "construct_grover_model",
20
+ "molecule_problem_to_qmod",
17
21
  ]
22
+
23
+
24
+ def __dir__():
25
+ return __all__
@@ -30,10 +30,8 @@ from classiq.interface.model.handle_binding import HandleBinding
30
30
  from classiq.interface.model.model import Model, SerializedModel
31
31
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
32
32
  from classiq.interface.model.port_declaration import PortDeclaration
33
- from classiq.interface.model.quantum_function_call import (
34
- QuantumFunctionCall,
35
- QuantumLambdaFunction,
36
- )
33
+ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
34
+ from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
37
35
 
38
36
  from classiq.applications.chemistry.ansatz_parameters import (
39
37
  AnsatzParameters,
@@ -219,7 +217,7 @@ def _atoms_to_qmod_atoms(atoms: List[Atom]) -> str:
219
217
  return ",".join(atom_struct_literals)
220
218
 
221
219
 
222
- def _molecule_problem_to_qmod_molecule_problem(
220
+ def molecule_problem_to_qmod(
223
221
  molecule_problem: MoleculeProblem,
224
222
  ) -> str:
225
223
  # fmt: off
@@ -288,7 +286,7 @@ def _hamiltonian_problem_to_qmod_fock_hamiltonian_problem(
288
286
 
289
287
  def _convert_library_problem_to_qmod_problem(problem: CHEMISTRY_PROBLEMS_TYPE) -> str:
290
288
  if isinstance(problem, MoleculeProblem):
291
- return _molecule_problem_to_qmod_molecule_problem(problem)
289
+ return molecule_problem_to_qmod(problem)
292
290
  elif isinstance(problem, HamiltonianProblem):
293
291
  return _hamiltonian_problem_to_qmod_fock_hamiltonian_problem(problem)
294
292
  else:
@@ -305,10 +303,10 @@ def _get_chemistry_function(
305
303
  return QuantumFunctionCall(
306
304
  function=f"{problem_prefix}_{chemistry_function_name}",
307
305
  params={
308
- **(ansatz_parameters_expressions or dict()),
309
306
  f"{problem_prefix}_problem": Expression(
310
307
  expr=_convert_library_problem_to_qmod_problem(chemistry_problem)
311
308
  ),
309
+ **(ansatz_parameters_expressions or dict()),
312
310
  },
313
311
  inouts=inouts,
314
312
  )
@@ -332,11 +330,11 @@ def _get_hea_function(hea_parameters: HEAParameters) -> QuantumFunctionCall:
332
330
  "is_parametrized": Expression(
333
331
  expr=f"{[int(_is_parametric_gate(_HAE_GATE_MAPPING[gate])) for gate in hea_parameters.one_qubit_gates+hea_parameters.two_qubit_gates]}"
334
332
  ),
333
+ "angle_params": Expression(expr="t"),
335
334
  "connectivity_map": Expression(
336
335
  expr=f"{[list(connectivity_pair) for connectivity_pair in hea_parameters.connectivity_map]}"
337
336
  ),
338
337
  "reps": Expression(expr=f"{hea_parameters.reps}"),
339
- "angle_params": Expression(expr="t"),
340
338
  },
341
339
  operands={
342
340
  "operands_1qubit": [
@@ -387,17 +385,11 @@ def _get_molecule_problem_execution_post_processing(
387
385
  molecule_problem: MoleculeProblem,
388
386
  ) -> str:
389
387
  return f"""
390
- {_MOLECULE_PROBLEM_RESULT} = molecule_ground_state_solution_post_process({_molecule_problem_to_qmod_molecule_problem(molecule_problem)},{_EXECUTION_RESULT})
388
+ {_MOLECULE_PROBLEM_RESULT} = molecule_ground_state_solution_post_process({molecule_problem_to_qmod(molecule_problem)},{_EXECUTION_RESULT})
391
389
  save({{{_MOLECULE_PROBLEM_RESULT!r}: {_MOLECULE_PROBLEM_RESULT}}})
392
390
  """
393
391
 
394
392
 
395
- def _get_fock_hamiltonian_problem_execution_post_processing(
396
- hamiltonian_problem: HamiltonianProblem,
397
- ) -> str:
398
- return f"save({{{_EXECUTION_RESULT!r}: {_EXECUTION_RESULT}}})"
399
-
400
-
401
393
  def _is_parametric_gate(call: QuantumFunctionCall) -> bool:
402
394
  return len(call.params) > 0
403
395
 
@@ -408,7 +400,7 @@ def _get_execution_result_post_processing_statements(
408
400
  if isinstance(problem, MoleculeProblem):
409
401
  return _get_molecule_problem_execution_post_processing(problem)
410
402
  elif isinstance(problem, HamiltonianProblem):
411
- return _get_fock_hamiltonian_problem_execution_post_processing(problem)
403
+ return ""
412
404
  else:
413
405
  raise ClassiqError(f"Invalid problem type: {problem}")
414
406
 
@@ -488,6 +480,7 @@ def _get_chemistry_classical_code(
488
480
  {_EXECUTION_RESULT} = vqe(
489
481
  hamiltonian={_get_problem_to_hamiltonian_name(chemistry_problem)}({qmod_problem}), {_get_chemistry_vqe_additional_params(execution_parameters)}
490
482
  )
483
+ save({{{_EXECUTION_RESULT!r}: {_EXECUTION_RESULT}}})
491
484
  """ + _get_execution_result_post_processing_statements(
492
485
  chemistry_problem
493
486
  )
@@ -0,0 +1,20 @@
1
+ from typing import Optional
2
+
3
+ from sympy import Add, Expr, LessThan, Symbol
4
+
5
+ from classiq.interface.combinatorial_optimization.encoding_types import EncodingType
6
+
7
+ _INEQUALITY_UPPER_LIMIT = 1
8
+
9
+
10
+ def is_constraint_sum_less_than_one(
11
+ expression: Expr, encoding_type: Optional[EncodingType] = None
12
+ ) -> bool:
13
+ # tests the case: x_1 + ... + x_n <= 1
14
+ return (
15
+ isinstance(expression, LessThan)
16
+ and isinstance(expression.args[0], Add)
17
+ and all(isinstance(arg, Symbol) for arg in expression.args[0].args)
18
+ and expression.args[1] == _INEQUALITY_UPPER_LIMIT
19
+ and encoding_type is None
20
+ )
@@ -0,0 +1,35 @@
1
+ from typing import Any
2
+
3
+ import sympy
4
+ from pyomo.core.expr.sympy_tools import PyomoSympyBimap
5
+ from scipy.optimize import differential_evolution
6
+ from sympy import Expr
7
+
8
+ from classiq.applications_model_constructors.combinatorial_helpers import encoding_utils
9
+
10
+
11
+ def sympy_lambdify(*args: Any, **kwargs: Any) -> Any:
12
+ new_kwargs = kwargs
13
+ new_kwargs["modules"] = ["sympy"]
14
+ return sympy.lambdify(*args, **new_kwargs)
15
+
16
+
17
+ def multivariate_extremum(
18
+ expr: Expr, symbols_map: PyomoSympyBimap, is_min: bool
19
+ ) -> float:
20
+ if expr.is_number:
21
+ return float(expr)
22
+
23
+ free_symbols = tuple(expr.free_symbols)
24
+ bounds = [
25
+ (0, encoding_utils.get_var_span(symbols_map.sympy2pyomo[sym]))
26
+ for sym in free_symbols
27
+ ]
28
+
29
+ # differential_evolution finds the global minimum, where we looking for the minimum or the maximum
30
+ extremum_type_coeff = 1 if is_min else -1
31
+
32
+ # Should be used only with sanitized imports due to use could be a potential risk to exec function https://docs.sympy.org/latest/modules/utilities/lambdify.html
33
+ func = sympy_lambdify([free_symbols], expr=extremum_type_coeff * expr)
34
+ result = differential_evolution(func, bounds)
35
+ return result.fun * extremum_type_coeff
@@ -0,0 +1,42 @@
1
+ from sympy import Eq, Expr, GreaterThan, LessThan, Rational, Symbol, solve
2
+ from sympy.core.relational import Relational
3
+
4
+ from classiq.exceptions import ClassiqCombOptNoSolutionError
5
+
6
+
7
+ def isolate(expression: Expr, var: Symbol) -> Expr:
8
+ isolated_exp = solve(expression, var)
9
+ # This converts Rationals to Floats which is needed since we don't support division in arithmetic
10
+ if isinstance(isolated_exp, Relational) and _has_rational_atom(isolated_exp):
11
+ isolated_exp = isolated_exp.evalf()
12
+
13
+ if isinstance(expression, Eq):
14
+ if len(isolated_exp) == 1:
15
+ isolated_exp = type(expression)(var, isolated_exp[0])
16
+ elif len(isolated_exp) > 1:
17
+ # sympy didn't manage to isolate an expression
18
+ isolated_exp = expression
19
+ else:
20
+ raise ClassiqCombOptNoSolutionError
21
+
22
+ else:
23
+ if _is_symbol_in_right_hand_side(isolated_exp):
24
+ isolated_exp = _reverse_ineq_exp(isolated_exp)
25
+
26
+ return isolated_exp
27
+
28
+
29
+ def _has_rational_atom(expression: Relational) -> bool:
30
+ return any(type(atom) is Rational for atom in expression.atoms())
31
+
32
+
33
+ def _is_symbol_in_right_hand_side(expression: Expr) -> bool:
34
+ return isinstance(expression.args[1], Symbol) and not isinstance(
35
+ expression.args[0], Symbol
36
+ )
37
+
38
+
39
+ def _reverse_ineq_exp(expression: Expr) -> Expr:
40
+ original_relation = type(expression)
41
+ reverse_relation = LessThan if original_relation is GreaterThan else GreaterThan
42
+ return reverse_relation(expression.args[1], expression.args[0])
@@ -0,0 +1,130 @@
1
+ import itertools
2
+ from typing import List, Union
3
+
4
+ import numpy as np
5
+ import pyomo.environ as pyo
6
+
7
+ from classiq.interface.combinatorial_optimization.sense import is_maximization
8
+ from classiq.interface.combinatorial_optimization.solver_types import QSolver
9
+ from classiq.interface.executor.vqe_result import VQESolverResult
10
+ from classiq.interface.generator.functions.qmod_python_interface import QmodPyStruct
11
+
12
+ from classiq.applications_model_constructors.combinatorial_helpers.optimization_model import (
13
+ OptimizationModel,
14
+ )
15
+ from classiq.applications_model_constructors.combinatorial_helpers.pauli_helpers.pauli_sparsing import (
16
+ SparsePauliOp,
17
+ )
18
+ from classiq.applications_model_constructors.combinatorial_helpers.pauli_helpers.pauli_utils import (
19
+ pauli_operator_to_hamiltonian,
20
+ )
21
+ from classiq.applications_model_constructors.combinatorial_helpers.pyomo_utils import (
22
+ convert_pyomo_to_global_presentation,
23
+ )
24
+
25
+
26
+ def compute_qaoa_initial_point(
27
+ hamiltonian: List[QmodPyStruct],
28
+ repetitions: int,
29
+ ) -> List[float]:
30
+ coeffs_ising = [pauli_term["coefficient"] for pauli_term in hamiltonian[1:]]
31
+ # the first coeff is the II...I term
32
+ coeffs_abs = np.abs(coeffs_ising)
33
+ coeffs_largest = np.sort(coeffs_abs)[len(coeffs_ising) // 2 :]
34
+ operator_norm = np.mean(coeffs_largest)
35
+ time_step = 1 / (2 * operator_norm) # adapted such that for MAXCUT time_step = 1
36
+
37
+ beta_params: np.ndarray = np.linspace(1, 0, repetitions) * time_step
38
+ gamma_params: np.ndarray = np.linspace(0, 1, repetitions) * time_step
39
+ return list(itertools.chain(*zip(gamma_params, beta_params)))
40
+
41
+
42
+ def pyo_model_to_hamiltonian(
43
+ pyo_model: pyo.ConcreteModel, penalty_energy: float
44
+ ) -> List[QmodPyStruct]:
45
+ pauli_list = OptimizationModel(
46
+ pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
47
+ ).ising.pauli_list
48
+ return pauli_operator_to_hamiltonian(pauli_list)
49
+
50
+
51
+ def _str_to_list_int(str_ints: str) -> List[int]:
52
+ return list(map(int, list(str_ints)))
53
+
54
+
55
+ def _decode_vector_str(
56
+ optimization_model: OptimizationModel, vector_str: str
57
+ ) -> List[int]:
58
+ return optimization_model.decode(
59
+ _str_to_list_int(vector_str[::-1])
60
+ ) # reverse qubit order
61
+
62
+
63
+ def _evaluate_operator(operator: SparsePauliOp, state: Union[List[int], str]) -> float:
64
+ if isinstance(state, list):
65
+ state = "".join([str(x) for x in state])
66
+
67
+ cost = 0.0
68
+ for pauli, coeff in zip(operator.paulis, operator.coeffs):
69
+ expectation = 1
70
+ for qubit, pauli_char in enumerate(pauli):
71
+ if pauli_char != "I" and state[qubit] == "1" and pauli_char in ["Z", "Y"]:
72
+ expectation *= -1
73
+ cost += expectation * coeff.real
74
+
75
+ return cost
76
+
77
+
78
+ def _eigenstate_to_solution(
79
+ optimization_model: OptimizationModel,
80
+ eigenvector: str,
81
+ probability: float,
82
+ num_shots: int,
83
+ ) -> QmodPyStruct:
84
+ pauli = optimization_model.get_operator().pauli_list
85
+
86
+ paulis = [item[0] for item in pauli]
87
+ coeffs = [item[1] for item in pauli]
88
+
89
+ operator = SparsePauliOp(paulis, coeffs)
90
+ cost = _evaluate_operator(operator, eigenvector)
91
+
92
+ if is_maximization(optimization_model._model_original):
93
+ cost *= -1
94
+
95
+ return {
96
+ "probability": probability,
97
+ "cost": cost,
98
+ "solution": _decode_vector_str(optimization_model, eigenvector),
99
+ "count": round(probability * num_shots),
100
+ }
101
+
102
+
103
+ def _get_combi_solution_histogram(
104
+ optimization_model: OptimizationModel,
105
+ vqe_result: VQESolverResult,
106
+ ) -> List[QmodPyStruct]:
107
+ if vqe_result.reduced_probabilities is None:
108
+ raise ValueError(
109
+ "reduced_probabilities is optional only for backwards compatibility, but it should always be present here"
110
+ )
111
+ return [
112
+ _eigenstate_to_solution(
113
+ optimization_model, eigenvector, probability, vqe_result.num_shots
114
+ )
115
+ for eigenvector, probability in vqe_result.reduced_probabilities.items()
116
+ ]
117
+
118
+
119
+ def get_optimization_solution_from_pyo(
120
+ pyo_model: pyo.ConcreteModel,
121
+ vqe_result: VQESolverResult,
122
+ penalty_energy: float,
123
+ ) -> List[QmodPyStruct]:
124
+ converted_pyo_model = convert_pyomo_to_global_presentation(pyo_model)
125
+ optimization_model = OptimizationModel(
126
+ converted_pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
127
+ )
128
+ histogram = _get_combi_solution_histogram(optimization_model, vqe_result)
129
+ histogram.sort(key=lambda x: x["probability"], reverse=True)
130
+ return histogram