classiq 0.37.1__py3-none-any.whl → 0.39.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 (280) hide show
  1. classiq/__init__.py +23 -24
  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 +37 -17
  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 +24 -6
  10. classiq/_internals/jobs.py +10 -7
  11. classiq/analyzer/analyzer.py +29 -29
  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/__init__.py +1 -8
  16. classiq/applications/chemistry/__init__.py +6 -0
  17. classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +9 -16
  18. classiq/applications/combinatorial_helpers/allowed_constraints.py +20 -0
  19. classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
  20. classiq/applications/combinatorial_helpers/arithmetic/isolation.py +42 -0
  21. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +150 -0
  22. classiq/applications/combinatorial_helpers/encoding_mapping.py +107 -0
  23. classiq/applications/combinatorial_helpers/encoding_utils.py +122 -0
  24. classiq/applications/combinatorial_helpers/memory.py +77 -0
  25. classiq/applications/combinatorial_helpers/optimization_model.py +162 -0
  26. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
  27. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +75 -0
  28. classiq/applications/combinatorial_helpers/py.typed +0 -0
  29. classiq/applications/combinatorial_helpers/pyomo_utils.py +245 -0
  30. classiq/applications/combinatorial_helpers/solvers/__init__.py +0 -0
  31. classiq/applications/combinatorial_helpers/sympy_utils.py +22 -0
  32. classiq/applications/combinatorial_helpers/transformations/__init__.py +0 -0
  33. classiq/applications/combinatorial_helpers/transformations/encoding.py +187 -0
  34. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +142 -0
  35. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +122 -0
  36. classiq/applications/combinatorial_helpers/transformations/penalty.py +32 -0
  37. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +37 -0
  38. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +75 -0
  39. classiq/applications/combinatorial_helpers/transformations/slack_variables.py +88 -0
  40. classiq/applications/combinatorial_optimization/__init__.py +13 -2
  41. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +134 -0
  42. classiq/applications/finance/__init__.py +3 -2
  43. classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +27 -30
  44. classiq/applications/grover/__init__.py +11 -0
  45. classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +20 -91
  46. classiq/applications/libraries/__init__.py +0 -0
  47. classiq/applications/libraries/qmci_library.py +35 -0
  48. classiq/applications/qnn/circuit_utils.py +2 -2
  49. classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
  50. classiq/applications/qnn/types.py +2 -2
  51. classiq/applications/qsvm/__init__.py +5 -1
  52. classiq/applications/qsvm/qsvm.py +4 -7
  53. classiq/applications/qsvm/qsvm_data_generation.py +2 -5
  54. classiq/exceptions.py +43 -1
  55. classiq/execution/all_hardware_devices.py +13 -0
  56. classiq/executor.py +12 -10
  57. classiq/interface/_version.py +1 -1
  58. classiq/interface/analyzer/analysis_params.py +6 -3
  59. classiq/interface/analyzer/result.py +12 -8
  60. classiq/interface/applications/qsvm.py +17 -3
  61. classiq/interface/ast_node.py +23 -0
  62. classiq/interface/backend/backend_preferences.py +4 -2
  63. classiq/interface/backend/pydantic_backend.py +3 -1
  64. classiq/interface/backend/quantum_backend_providers.py +1 -0
  65. classiq/interface/chemistry/fermionic_operator.py +15 -13
  66. classiq/interface/chemistry/ground_state_problem.py +18 -3
  67. classiq/interface/chemistry/molecule.py +8 -6
  68. classiq/interface/chemistry/operator.py +20 -14
  69. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
  70. classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
  71. classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
  72. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
  73. classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
  74. classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
  75. classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
  76. classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
  77. classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
  78. classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
  79. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
  80. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
  81. classiq/interface/executor/aws_execution_cost.py +4 -3
  82. classiq/interface/executor/estimation.py +2 -2
  83. classiq/interface/executor/execution_preferences.py +5 -34
  84. classiq/interface/executor/execution_request.py +15 -48
  85. classiq/interface/executor/optimizer_preferences.py +22 -13
  86. classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
  87. classiq/interface/executor/quantum_instruction_set.py +2 -1
  88. classiq/interface/executor/register_initialization.py +1 -3
  89. classiq/interface/executor/result.py +41 -10
  90. classiq/interface/executor/vqe_result.py +2 -2
  91. classiq/interface/finance/function_input.py +17 -4
  92. classiq/interface/finance/gaussian_model_input.py +3 -1
  93. classiq/interface/finance/log_normal_model_input.py +3 -1
  94. classiq/interface/finance/model_input.py +2 -0
  95. classiq/interface/generator/amplitude_loading.py +6 -3
  96. classiq/interface/generator/application_apis/__init__.py +1 -0
  97. classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
  98. classiq/interface/generator/arith/argument_utils.py +14 -4
  99. classiq/interface/generator/arith/arithmetic.py +3 -1
  100. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
  101. classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
  102. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
  103. classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
  104. classiq/interface/generator/arith/arithmetic_operations.py +5 -10
  105. classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
  106. classiq/interface/generator/arith/binary_ops.py +202 -54
  107. classiq/interface/generator/arith/extremum_operations.py +5 -3
  108. classiq/interface/generator/arith/logical_ops.py +4 -2
  109. classiq/interface/generator/arith/machine_precision.py +3 -0
  110. classiq/interface/generator/arith/number_utils.py +34 -44
  111. classiq/interface/generator/arith/register_user_input.py +21 -1
  112. classiq/interface/generator/arith/unary_ops.py +16 -25
  113. classiq/interface/generator/builtin_api_builder.py +0 -5
  114. classiq/interface/generator/chemistry_function_params.py +4 -4
  115. classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
  116. classiq/interface/generator/compiler_keywords.py +4 -0
  117. classiq/interface/generator/complex_type.py +3 -10
  118. classiq/interface/generator/constant.py +2 -3
  119. classiq/interface/generator/control_state.py +5 -3
  120. classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
  121. classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
  122. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
  123. classiq/interface/generator/expressions/evaluated_expression.py +18 -4
  124. classiq/interface/generator/expressions/expression.py +3 -5
  125. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
  126. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  127. classiq/interface/generator/finance.py +1 -1
  128. classiq/interface/generator/function_params.py +7 -6
  129. classiq/interface/generator/functions/__init__.py +2 -2
  130. classiq/interface/generator/functions/builtins/__init__.py +15 -0
  131. classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
  132. classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
  133. classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
  134. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +612 -219
  135. classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
  136. classiq/interface/generator/functions/classical_type.py +2 -4
  137. classiq/interface/generator/functions/foreign_function_definition.py +12 -4
  138. classiq/interface/generator/functions/function_declaration.py +2 -2
  139. classiq/interface/generator/functions/function_implementation.py +8 -4
  140. classiq/interface/generator/functions/native_function_definition.py +4 -2
  141. classiq/interface/generator/functions/register.py +4 -2
  142. classiq/interface/generator/functions/register_mapping_data.py +14 -10
  143. classiq/interface/generator/generated_circuit_data.py +2 -2
  144. classiq/interface/generator/grover_operator.py +5 -3
  145. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
  146. classiq/interface/generator/hardware/hardware_data.py +6 -4
  147. classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
  148. classiq/interface/generator/hartree_fock.py +13 -3
  149. classiq/interface/generator/linear_pauli_rotations.py +3 -1
  150. classiq/interface/generator/mcu.py +5 -3
  151. classiq/interface/generator/mcx.py +7 -5
  152. classiq/interface/generator/model/classical_main_validator.py +1 -1
  153. classiq/interface/generator/model/constraints.py +2 -1
  154. classiq/interface/generator/model/model.py +12 -20
  155. classiq/interface/generator/model/preferences/preferences.py +4 -3
  156. classiq/interface/generator/oracles/custom_oracle.py +4 -2
  157. classiq/interface/generator/oracles/oracle_abc.py +2 -2
  158. classiq/interface/generator/qpe.py +6 -4
  159. classiq/interface/generator/qsvm.py +5 -8
  160. classiq/interface/generator/quantum_function_call.py +21 -16
  161. classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
  162. classiq/interface/generator/range_types.py +3 -1
  163. classiq/interface/generator/slice_parsing_utils.py +8 -3
  164. classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
  165. classiq/interface/generator/state_preparation/metrics.py +2 -1
  166. classiq/interface/generator/state_preparation/state_preparation.py +7 -5
  167. classiq/interface/generator/state_propagator.py +16 -5
  168. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
  169. classiq/interface/generator/types/struct_declaration.py +10 -7
  170. classiq/interface/generator/ucc.py +6 -4
  171. classiq/interface/generator/unitary_gate.py +7 -3
  172. classiq/interface/generator/validations/flow_graph.py +6 -4
  173. classiq/interface/generator/validations/validator_functions.py +6 -4
  174. classiq/interface/hardware.py +2 -2
  175. classiq/interface/helpers/custom_encoders.py +3 -0
  176. classiq/interface/helpers/pydantic_model_helpers.py +0 -6
  177. classiq/interface/helpers/validation_helpers.py +1 -1
  178. classiq/interface/helpers/versioned_model.py +4 -1
  179. classiq/interface/ide/show.py +2 -2
  180. classiq/interface/jobs.py +72 -3
  181. classiq/interface/model/bind_operation.py +18 -11
  182. classiq/interface/model/call_synthesis_data.py +68 -0
  183. classiq/interface/model/classical_if.py +13 -0
  184. classiq/interface/model/classical_parameter_declaration.py +2 -3
  185. classiq/interface/model/control.py +16 -0
  186. classiq/interface/model/handle_binding.py +3 -2
  187. classiq/interface/model/inplace_binary_operation.py +2 -2
  188. classiq/interface/model/invert.py +10 -0
  189. classiq/interface/model/model.py +29 -22
  190. classiq/interface/model/native_function_definition.py +3 -5
  191. classiq/interface/model/power.py +12 -0
  192. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
  193. classiq/interface/model/quantum_expressions/control_state.py +2 -2
  194. classiq/interface/model/quantum_function_call.py +33 -142
  195. classiq/interface/model/quantum_function_declaration.py +8 -0
  196. classiq/interface/model/quantum_if_operation.py +4 -5
  197. classiq/interface/model/quantum_lambda_function.py +58 -0
  198. classiq/{quantum_register.py → interface/model/quantum_register.py} +17 -9
  199. classiq/interface/model/quantum_statement.py +3 -2
  200. classiq/interface/model/quantum_type.py +58 -59
  201. classiq/interface/model/quantum_variable_declaration.py +3 -3
  202. classiq/interface/model/repeat.py +13 -0
  203. classiq/interface/model/resolvers/function_call_resolver.py +26 -0
  204. classiq/interface/model/statement_block.py +49 -0
  205. classiq/interface/model/validations/handles_validator.py +16 -18
  206. classiq/interface/model/within_apply_operation.py +11 -0
  207. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
  208. classiq/interface/server/routes.py +5 -4
  209. classiq/qmod/__init__.py +13 -6
  210. classiq/qmod/builtins/classical_execution_primitives.py +27 -36
  211. classiq/qmod/builtins/classical_functions.py +22 -12
  212. classiq/qmod/builtins/functions.py +272 -328
  213. classiq/qmod/builtins/operations.py +171 -35
  214. classiq/qmod/builtins/structs.py +15 -15
  215. classiq/qmod/cfunc.py +42 -0
  216. classiq/qmod/classical_function.py +6 -14
  217. classiq/qmod/declaration_inferrer.py +12 -21
  218. classiq/qmod/expression_query.py +23 -0
  219. classiq/qmod/model_state_container.py +2 -0
  220. classiq/qmod/native/__init__.py +0 -0
  221. classiq/qmod/native/expression_to_qmod.py +189 -0
  222. classiq/qmod/native/pretty_printer.py +340 -0
  223. classiq/qmod/qfunc.py +27 -0
  224. classiq/qmod/qmod_constant.py +100 -0
  225. classiq/qmod/qmod_parameter.py +36 -13
  226. classiq/qmod/qmod_struct.py +3 -3
  227. classiq/qmod/qmod_variable.py +148 -31
  228. classiq/qmod/quantum_callable.py +1 -0
  229. classiq/qmod/quantum_expandable.py +18 -19
  230. classiq/qmod/quantum_function.py +41 -8
  231. classiq/qmod/symbolic.py +48 -5
  232. classiq/qmod/symbolic_expr.py +9 -0
  233. classiq/qmod/utilities.py +13 -0
  234. classiq/qmod/write_qmod.py +39 -0
  235. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/METADATA +2 -1
  236. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/RECORD +244 -225
  237. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/WHEEL +1 -1
  238. classiq/applications/benchmarking/__init__.py +0 -9
  239. classiq/applications/benchmarking/mirror_benchmarking.py +0 -67
  240. classiq/applications/numpy_utils.py +0 -37
  241. classiq/applications_model_constructors/__init__.py +0 -17
  242. classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +0 -178
  243. classiq/applications_model_constructors/libraries/qmci_library.py +0 -109
  244. classiq/builtin_functions/__init__.py +0 -43
  245. classiq/builtin_functions/amplitude_loading.py +0 -3
  246. classiq/builtin_functions/binary_ops.py +0 -1
  247. classiq/builtin_functions/exponentiation.py +0 -5
  248. classiq/builtin_functions/qpe.py +0 -4
  249. classiq/builtin_functions/qsvm.py +0 -7
  250. classiq/builtin_functions/range_types.py +0 -5
  251. classiq/builtin_functions/standard_gates.py +0 -1
  252. classiq/builtin_functions/state_preparation.py +0 -6
  253. classiq/builtin_functions/suzuki_trotter.py +0 -3
  254. classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
  255. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
  256. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -169
  257. classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
  258. classiq/interface/generator/types/combinatorial_problem.py +0 -26
  259. classiq/interface/model/numeric_reinterpretation.py +0 -25
  260. classiq/interface/model/operator_synthesis_data.py +0 -48
  261. classiq/model/__init__.py +0 -14
  262. classiq/model/composite_function_generator.py +0 -33
  263. classiq/model/function_handler.py +0 -466
  264. classiq/model/function_handler.pyi +0 -152
  265. classiq/model/logic_flow.py +0 -149
  266. classiq/model/logic_flow_change_handler.py +0 -71
  267. classiq/model/model.py +0 -246
  268. classiq/quantum_functions/__init__.py +0 -17
  269. classiq/quantum_functions/annotation_parser.py +0 -207
  270. classiq/quantum_functions/decorators.py +0 -22
  271. classiq/quantum_functions/function_library.py +0 -181
  272. classiq/quantum_functions/function_parser.py +0 -74
  273. classiq/quantum_functions/quantum_function.py +0 -236
  274. /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers}/__init__.py +0 -0
  275. /classiq/{interface/generator/functions/core_lib_declarations → applications/combinatorial_helpers/arithmetic}/__init__.py +0 -0
  276. /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → applications/combinatorial_helpers/pauli_helpers/__init__.py} +0 -0
  277. /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
  278. /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
  279. /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +0 -0
  280. /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +0 -0
@@ -1,149 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Any, Optional, Tuple
3
-
4
- import networkx as nx
5
-
6
- from classiq.interface.generator.function_params import PortDirection
7
- from classiq.interface.generator.quantum_function_call import (
8
- ZERO_INDICATOR,
9
- SynthesisQuantumFunctionCall,
10
- )
11
-
12
- from classiq.exceptions import ClassiqWiringError
13
- from classiq.model import logic_flow_change_handler
14
- from classiq.quantum_register import QReg, Qubit
15
-
16
-
17
- # We need the dataclass to be hashable for inserting it into the graph,
18
- # hence the dataclass is frozen.
19
- @dataclass(frozen=True)
20
- class _Pin:
21
- pin_name: str
22
- index: int
23
- func_call: Optional[SynthesisQuantumFunctionCall]
24
- io: PortDirection # We need to store PortDirection because a function may have an input and an output pin with the same name
25
-
26
- def __str__(self) -> str:
27
- return f"{self.pin_name}[{self.index}]"
28
-
29
-
30
- @dataclass(frozen=True)
31
- class _ZeroPin(_Pin):
32
- def __init__(self, io: PortDirection) -> None:
33
- super().__init__(pin_name=ZERO_INDICATOR, index=0, func_call=None, io=io)
34
-
35
- def __str__(self) -> str:
36
- return ZERO_INDICATOR
37
-
38
-
39
- class _StrictDiGraph(nx.DiGraph):
40
- def add_edge(self, u_of_edge: Any, v_of_edge: Any, **attr: Any) -> None:
41
- if u_of_edge in self and v_of_edge in self[u_of_edge]:
42
- raise ClassiqWiringError(
43
- f"Cannot reconnect an already connected edge: {u_of_edge}, {v_of_edge}"
44
- )
45
- super().add_edge(u_of_edge, v_of_edge, **attr)
46
-
47
-
48
- INVALID_QUBITS_ERROR_MESSAGE = (
49
- "Cannot use a QReg with consumed or uninitialized qubits:"
50
- )
51
-
52
-
53
- class LogicFlowBuilder:
54
- def __init__(self) -> None:
55
- self._logic_flow_graph = _StrictDiGraph()
56
- self._connect_qubit_func = {
57
- PortDirection.Input: self._connect_qubit_to_func_call,
58
- PortDirection.Output: self._connect_func_call_to_qubit,
59
- }
60
-
61
- def _is_qubit_available(self, qubit: Qubit) -> bool:
62
- return qubit in self._logic_flow_graph.nodes
63
-
64
- def _validate_qreg(self, qreg: QReg) -> None:
65
- invalid_qubit_indices = [
66
- i
67
- for i, qubit in enumerate(qreg.qubits)
68
- if not self._is_qubit_available(qubit)
69
- ]
70
- if invalid_qubit_indices:
71
- raise ClassiqWiringError(
72
- f"{INVALID_QUBITS_ERROR_MESSAGE} {invalid_qubit_indices}"
73
- )
74
-
75
- def _verify_no_loops(self, dest_node: SynthesisQuantumFunctionCall) -> None:
76
- if not nx.is_directed_acyclic_graph(self._logic_flow_graph):
77
- raise ClassiqWiringError(f"Cannot wire function {dest_node} to itself")
78
-
79
- def _connect_qubit_to_func_call(
80
- self,
81
- qubit: Qubit,
82
- dest_pin: _Pin,
83
- dest_node: Optional[SynthesisQuantumFunctionCall],
84
- ) -> None:
85
- if dest_node is not None:
86
- self._logic_flow_graph.add_edge(dest_pin, dest_node)
87
- source_node, source_pin = self._get_source_node_and_pin(qubit)
88
- # relabel_nodes replaces a node with another (inplace and keeping the edges)
89
- nx.relabel_nodes(self._logic_flow_graph, {qubit: dest_pin}, copy=False)
90
- logic_flow_change_handler.handle_inner_connection(
91
- source_node,
92
- str(source_pin),
93
- str(dest_pin),
94
- dest_node,
95
- )
96
-
97
- def _get_source_node_and_pin(
98
- self, qubit: Qubit
99
- ) -> Tuple[SynthesisQuantumFunctionCall, _Pin]:
100
- source_pin = next(self._logic_flow_graph.predecessors(qubit))
101
- source_node = next(self._logic_flow_graph.predecessors(source_pin))
102
- return source_node, source_pin
103
-
104
- def _connect_func_call_to_qubit(
105
- self, qubit: Qubit, source_pin: _Pin, source_node: SynthesisQuantumFunctionCall
106
- ) -> None:
107
- self._logic_flow_graph.add_edge(source_node, source_pin)
108
- self._logic_flow_graph.add_edge(source_pin, qubit)
109
-
110
- def _connect_io(
111
- self,
112
- io: PortDirection,
113
- func_node: SynthesisQuantumFunctionCall,
114
- pin_name: str,
115
- qreg: QReg,
116
- pin_indices: Optional[range] = None,
117
- ) -> None:
118
- if pin_indices is None:
119
- pin_indices = range(len(qreg))
120
- pins = [_Pin(pin_name, i, func_node, io) for i in pin_indices]
121
- for pin, qubit in zip(pins, qreg.qubits):
122
- self._connect_qubit_func[io](qubit, pin, func_node)
123
-
124
- def connect_qreg_to_func_call(
125
- self,
126
- source: QReg,
127
- dest_pin_name: str,
128
- dest_func_call: SynthesisQuantumFunctionCall,
129
- pin_indices: Optional[range] = None,
130
- ) -> None:
131
- self._validate_qreg(source)
132
- self._connect_io(
133
- PortDirection.Input, dest_func_call, dest_pin_name, source, pin_indices
134
- )
135
- self._verify_no_loops(dest_func_call)
136
-
137
- def connect_func_call_to_qreg(
138
- self,
139
- source_func_call: SynthesisQuantumFunctionCall,
140
- source_pin_name: str,
141
- dest: QReg,
142
- ) -> None:
143
- self._connect_io(PortDirection.Output, source_func_call, source_pin_name, dest)
144
-
145
- def connect_qreg_to_zero(self, source: QReg) -> None:
146
- for qubit in source.qubits:
147
- self._connect_qubit_to_func_call(
148
- qubit, _ZeroPin(PortDirection.Output), None
149
- )
@@ -1,71 +0,0 @@
1
- from typing import Optional
2
-
3
- from classiq.interface.generator.function_params import PortDirection
4
- from classiq.interface.generator.quantum_function_call import (
5
- ZERO_INDICATOR,
6
- SynthesisQuantumFunctionCall,
7
- )
8
-
9
-
10
- def _get_io_wire_name(
11
- name: str, call: SynthesisQuantumFunctionCall, io: PortDirection
12
- ) -> str:
13
- if io == PortDirection.Input:
14
- return f"{io.name}:{name}->{call.name}:{name}"
15
- else:
16
- return f"{call.name}:{name}->{io.name}:{name}"
17
-
18
-
19
- def _get_wire_name(
20
- source_call: SynthesisQuantumFunctionCall,
21
- source_pin_name: str,
22
- dest_pin_name: str,
23
- dest_call: Optional[SynthesisQuantumFunctionCall],
24
- ) -> str:
25
- if dest_call is None:
26
- assert dest_pin_name == ZERO_INDICATOR
27
- return ZERO_INDICATOR
28
- return f"{source_call.name}:{source_pin_name}->{dest_call.name}:{dest_pin_name}"
29
-
30
-
31
- def _set_model_output(
32
- call: SynthesisQuantumFunctionCall, pin_name: str, wire_name: str
33
- ) -> None:
34
- call_outputs = dict(call.outputs_dict)
35
- call_outputs[pin_name] = wire_name
36
- call.outputs = call_outputs
37
- if wire_name != ZERO_INDICATOR:
38
- call.non_zero_output_wires.append(wire_name)
39
-
40
-
41
- def _set_model_input(
42
- call: Optional[SynthesisQuantumFunctionCall], pin_name: str, wire_name: str
43
- ) -> None:
44
- if call is None:
45
- return
46
- call_inputs = dict(call.inputs_dict)
47
- call_inputs[pin_name] = wire_name
48
- call.inputs = call_inputs
49
- call.non_zero_input_wires.append(wire_name)
50
-
51
-
52
- def handle_inner_connection(
53
- source_call: SynthesisQuantumFunctionCall,
54
- source_pin_name: str,
55
- dest_pin_name: str,
56
- dest_call: Optional[SynthesisQuantumFunctionCall],
57
- ) -> None:
58
- wire_name = _get_wire_name(source_call, source_pin_name, dest_pin_name, dest_call)
59
- _set_model_output(source_call, source_pin_name, wire_name)
60
- _set_model_input(dest_call, dest_pin_name, wire_name)
61
-
62
-
63
- def handle_io_connection(
64
- io_dir: PortDirection, call: SynthesisQuantumFunctionCall, io_name: str
65
- ) -> str:
66
- wire_name = _get_io_wire_name(io_name, call, io_dir)
67
- if io_dir == PortDirection.Input:
68
- _set_model_input(call, io_name, wire_name)
69
- else:
70
- _set_model_output(call, io_name, wire_name)
71
- return wire_name
classiq/model/model.py DELETED
@@ -1,246 +0,0 @@
1
- """Model module, implementing facilities for designing models and generating circuits using Classiq platform."""
2
-
3
- from __future__ import annotations
4
-
5
- import logging
6
- import tempfile
7
- from contextlib import nullcontext
8
- from typing import IO, Any, ContextManager, Dict, List, Mapping, Optional, Union, cast
9
-
10
- from classiq.interface.chemistry.operator import PauliOperator
11
- from classiq.interface.executor.execution_preferences import (
12
- ExecutionPreferences,
13
- QaeWithQpeEstimationMethod,
14
- )
15
- from classiq.interface.generator.expressions.enums import Optimizer
16
- from classiq.interface.generator.function_params import IOName
17
- from classiq.interface.generator.functions import SynthesisNativeFunctionDefinition
18
- from classiq.interface.generator.model import (
19
- Constraints,
20
- Preferences,
21
- SynthesisModel as APIModel,
22
- )
23
- from classiq.interface.generator.model.model import MAIN_FUNCTION_NAME, SerializedModel
24
- from classiq.interface.generator.quantum_function_call import (
25
- SynthesisQuantumFunctionCall,
26
- )
27
-
28
- from classiq._internals.async_utils import AsyncifyABC
29
- from classiq.exceptions import ClassiqError, ClassiqValueError
30
- from classiq.model import function_handler
31
- from classiq.quantum_functions.function_library import FunctionLibrary
32
- from classiq.quantum_register import QReg, QRegGenericAlias
33
-
34
- _logger = logging.getLogger(__name__)
35
-
36
- _SupportedIO = Union[IO, str]
37
-
38
- # TODO: Add docstrings for auto generated methods.
39
-
40
-
41
- ILLEGAL_SETTING_MSG = "Illegal value type provided"
42
-
43
-
44
- def _pauli_str_to_enums(pauli_str: str) -> str:
45
- return ", ".join(f"Pauli.{pauli_term}" for pauli_term in pauli_str)
46
-
47
-
48
- def _pauli_operator_to_qmod(hamiltonian: PauliOperator) -> str:
49
- if not all(isinstance(summand[1], complex) for summand in hamiltonian.pauli_list):
50
- raise ClassiqValueError(
51
- "Supporting only Hamiltonian with numeric coefficients."
52
- )
53
- return ", ".join(
54
- f"struct_literal(PauliTerm, pauli=[{_pauli_str_to_enums(pauli)}], coefficient={cast(complex, coeff).real})"
55
- for pauli, coeff in hamiltonian.pauli_list
56
- )
57
-
58
-
59
- def _file_handler(fp: Optional[_SupportedIO], mode: str = "r") -> ContextManager[IO]:
60
- if fp is None:
61
- temp_file = tempfile.NamedTemporaryFile(mode, suffix=".qmod", delete=False)
62
- print(f"Using temporary file: {temp_file.name!r}")
63
- return temp_file
64
-
65
- if isinstance(fp, str):
66
- return open(fp, mode)
67
-
68
- return nullcontext(fp)
69
-
70
-
71
- DEFAULT_RESULT_NAME = "result"
72
- DEFAULT_AMPLITUDE_ESTIMATION_RESULT_NAME = "estimation"
73
-
74
-
75
- class Model(function_handler.FunctionHandler, metaclass=AsyncifyABC):
76
- """Facility to generate circuits, based on the model."""
77
-
78
- def __init__(self, **kwargs: Any) -> None:
79
- """Init self."""
80
- super().__init__()
81
- self._model = APIModel(**kwargs)
82
-
83
- @classmethod
84
- def from_model(cls, model: APIModel) -> Model:
85
- return cls(**dict(model))
86
-
87
- @property
88
- def _body(
89
- self,
90
- ) -> List[SynthesisQuantumFunctionCall]:
91
- return self._model.body
92
-
93
- @property
94
- def constraints(self) -> Constraints:
95
- """Get the constraints aggregated in self.
96
-
97
- Returns:
98
- The constraints data.
99
- """
100
- return self._model.constraints
101
-
102
- @constraints.setter
103
- def constraints(self, value: Any) -> None:
104
- if not isinstance(value, Constraints):
105
- raise ClassiqError(ILLEGAL_SETTING_MSG)
106
- self._model.constraints = value
107
-
108
- @property
109
- def preferences(self) -> Preferences:
110
- """Get the preferences aggregated in self.
111
-
112
- Returns:
113
- The preferences data.
114
- """
115
- return self._model.preferences
116
-
117
- @preferences.setter
118
- def preferences(self, value: Any) -> None:
119
- if not isinstance(value, Preferences):
120
- raise ClassiqError(ILLEGAL_SETTING_MSG)
121
- self._model.preferences = value
122
-
123
- @property
124
- def execution_preferences(self) -> ExecutionPreferences:
125
- return self._model.execution_preferences
126
-
127
- @execution_preferences.setter
128
- def execution_preferences(self, value: Any) -> None:
129
- if not isinstance(value, ExecutionPreferences):
130
- raise ClassiqError(ILLEGAL_SETTING_MSG)
131
- self._model.execution_preferences = value
132
-
133
- def create_inputs(
134
- self, inputs: Mapping[IOName, QRegGenericAlias]
135
- ) -> Dict[IOName, QReg]:
136
- qregs = super().create_inputs(inputs=inputs)
137
- self._model.set_inputs(inputs, self.input_wires)
138
- return qregs
139
-
140
- def set_outputs(self, outputs: Mapping[IOName, QReg]) -> None:
141
- super().set_outputs(outputs=outputs)
142
- self._model.set_outputs(outputs, self.output_wires)
143
-
144
- def include_library(self, library: FunctionLibrary) -> None:
145
- """Includes a user-defined custom function library.
146
-
147
- Args:
148
- library (FunctionLibrary): The custom function library.
149
- """
150
- super().include_library(library=library)
151
- # It is important that the .functions list is shared between the library and
152
- # the model, as it is modified in-place
153
- self._model.functions = library._data
154
- library.remove_function_definition(MAIN_FUNCTION_NAME)
155
- self._model.functions.append(
156
- SynthesisNativeFunctionDefinition(name=MAIN_FUNCTION_NAME)
157
- )
158
-
159
- def get_model(self) -> SerializedModel:
160
- return self._model.get_model()
161
-
162
- def create_library(self) -> None:
163
- self._function_library = FunctionLibrary(*self._model.functions)
164
- self._model.functions = self._function_library._data
165
-
166
- def sample(
167
- self,
168
- execution_params: Optional[Dict[str, float]] = None,
169
- ) -> None:
170
- execution_params = execution_params or dict()
171
-
172
- self._model.classical_execution_code += classical_sample_function(
173
- execution_params=execution_params
174
- )
175
-
176
- def vqe(
177
- self,
178
- hamiltonian: PauliOperator,
179
- maximize: bool,
180
- optimizer: Optimizer,
181
- max_iteration: int,
182
- initial_point: Optional[List[int]] = None,
183
- tolerance: float = 0,
184
- step_size: float = 0,
185
- skip_compute_variance: bool = False,
186
- alpha_cvar: float = 1,
187
- ) -> None:
188
- initial_point = initial_point or []
189
- vqe_classical_code = f"""
190
- {DEFAULT_RESULT_NAME} = vqe(
191
- hamiltonian=[{_pauli_operator_to_qmod(hamiltonian)}],
192
- maximize={maximize},
193
- initial_point={initial_point},
194
- optimizer=Optimizer.{optimizer.name},
195
- max_iteration={max_iteration},
196
- tolerance={tolerance},
197
- step_size={step_size},
198
- skip_compute_variance={skip_compute_variance},
199
- alpha_cvar={alpha_cvar}
200
- )
201
- save({{{DEFAULT_RESULT_NAME!r}: {DEFAULT_RESULT_NAME}}})
202
- """
203
-
204
- self._model.classical_execution_code += vqe_classical_code
205
-
206
- def iqae(
207
- self,
208
- epsilon: float,
209
- alpha: float,
210
- execution_params: Optional[Dict[str, float]] = None,
211
- ) -> None:
212
- execution_params = execution_params or {}
213
-
214
- iqae_classical_code = f"""
215
- {DEFAULT_RESULT_NAME} = iqae(
216
- epsilon={epsilon},
217
- alpha={alpha},
218
- execution_params={execution_params}
219
- )
220
- save({{{DEFAULT_RESULT_NAME!r}: {DEFAULT_RESULT_NAME}}})
221
- """
222
-
223
- self._model.classical_execution_code += iqae_classical_code
224
-
225
- def post_process_amplitude_estimation(
226
- self,
227
- estimation_register_size: int,
228
- estimation_method: QaeWithQpeEstimationMethod,
229
- ) -> None:
230
- postprocess_classical_code = f"""
231
- {DEFAULT_AMPLITUDE_ESTIMATION_RESULT_NAME} = qae_with_qpe_result_post_processing(
232
- {estimation_register_size},
233
- {estimation_method},
234
- {DEFAULT_RESULT_NAME}
235
- )
236
- save({{{DEFAULT_AMPLITUDE_ESTIMATION_RESULT_NAME!r}: {DEFAULT_AMPLITUDE_ESTIMATION_RESULT_NAME}}})
237
- """
238
-
239
- self._model.classical_execution_code += postprocess_classical_code
240
-
241
-
242
- def classical_sample_function(execution_params: Dict[str, float]) -> str:
243
- return f"""
244
- {DEFAULT_RESULT_NAME} = sample({execution_params})
245
- save({{{DEFAULT_RESULT_NAME!r}: {DEFAULT_RESULT_NAME}}})
246
- """
@@ -1,17 +0,0 @@
1
- from classiq.quantum_functions.decorators import quantum_function as qfunc
2
- from classiq.quantum_functions.function_library import (
3
- QASM3_INTRO,
4
- QASM_INTRO,
5
- FunctionLibrary,
6
- QuantumFunction,
7
- QuantumFunctionFactory,
8
- )
9
-
10
- __all__ = [
11
- "qfunc",
12
- "QASM_INTRO",
13
- "QASM3_INTRO",
14
- "FunctionLibrary",
15
- "QuantumFunction",
16
- "QuantumFunctionFactory",
17
- ]
@@ -1,207 +0,0 @@
1
- # type: ignore
2
- # We can either ignore each line individually, or ignore the entire file and wait until mypy can ignore
3
- # specific errors per-file.
4
- import inspect
5
- import sys
6
- from types import FunctionType
7
- from typing import Any, Dict, List, Tuple, Union, _GenericAlias
8
-
9
- from classiq.interface.generator.register_role import RegisterRole as Role
10
-
11
- from classiq.exceptions import ClassiqQFuncError
12
- from classiq.quantum_register import AuxQReg, QReg, QRegGenericAlias, QSFixed, ZeroQReg
13
-
14
- if sys.version_info >= (3, 9):
15
- from types import GenericAlias
16
- else:
17
- GenericAlias = _GenericAlias
18
-
19
- GenericAliasUnion = Union[GenericAlias, _GenericAlias]
20
-
21
-
22
- class AnnotationParser:
23
- def __init__(self, func: FunctionType) -> None:
24
- self._func = func
25
-
26
- self.output_types: Dict[str, GenericAlias] = {}
27
-
28
- def parse(self) -> None:
29
- annotations = self._func.__annotations__.copy()
30
-
31
- # Todo: remove this `if` after introducing `Inplace`
32
- if "return" not in annotations:
33
- raise ClassiqQFuncError("Return value annotations not found")
34
-
35
- self.output_values = self._unpack_output_values(annotations.pop("return"))
36
- self.input_names, self.input_values = self._unpack_input_values(annotations)
37
-
38
- self._validate()
39
-
40
- def _validate(self) -> None:
41
- self._validate_type_hints()
42
- self._validate_qubit_amount()
43
- self._validate_io_length()
44
- self._validate_io_correlation()
45
-
46
- def _validate_type_hints(self) -> None:
47
- # Validate type of type-hints
48
- if not all(
49
- map(
50
- self.is_valid_generic_alias_of_qreg,
51
- self.input_values + self.output_values,
52
- )
53
- ):
54
- raise ClassiqQFuncError("Invalid GenericAlias convection")
55
-
56
- def _validate_qubit_amount(self) -> None:
57
- # Validate qubit amount
58
- if sum(i.size for i in self.output_values) != sum(
59
- i.size for i in self.input_values
60
- ):
61
- raise ClassiqQFuncError(
62
- "Input and output values have different amounts of qubits"
63
- )
64
-
65
- # Todo: Remove this validation by introducing better heuristics
66
- # Or after introducing Inplace
67
- def _validate_io_length(self) -> None:
68
- # Validate amount of inputs and outputs
69
- if len(self.input_values) != len(self.output_values):
70
- raise ClassiqQFuncError(
71
- "Inputs and outputs must have the same number of QRegs"
72
- )
73
-
74
- def _validate_io_correlation(self) -> None:
75
- # Validate correspondence between inputs and outputs
76
- for input_name, input_type, output_type in zip(
77
- self.input_names, self.input_values, self.output_values
78
- ):
79
- # Is arithmetic QReg
80
- if issubclass(input_type.__origin__, QSFixed):
81
- if input_type != output_type:
82
- raise ClassiqQFuncError(
83
- f"Arithmetic QReg must be of the same type and size in both the input and the output. Got {input_type} and {output_type}"
84
- )
85
-
86
- # Is Auxillary QReg
87
- if issubclass(input_type.__origin__, AuxQReg):
88
- if input_type != output_type:
89
- raise ClassiqQFuncError(
90
- f"Auxillary QReg must be of the same type and size in both the input and the output. Got {input_type} and {output_type}"
91
- )
92
-
93
- # Is Zero QReg
94
- if input_type.__origin__ is ZeroQReg:
95
- if output_type.__origin__ is QReg or issubclass(
96
- output_type.__origin__, QSFixed
97
- ):
98
- self.output_types[input_name] = output_type
99
- else:
100
- raise ClassiqQFuncError(
101
- "Invalid output type. Any ZeroQReg in the input must have a corresponding QReg in the output"
102
- )
103
-
104
- @classmethod
105
- def _unpack_output_values(
106
- cls, output_value_type_hint: Any
107
- ) -> Tuple[GenericAlias, ...]:
108
- # Handle QReg type hints
109
- if cls.is_subclass_qreg(output_value_type_hint):
110
- return (cls.to_generic_alias(output_value_type_hint),)
111
-
112
- # Supporting both `typing._GenericAlias` and `types.GenericAlias`
113
- if not cls.is_instance_generic_alias(output_value_type_hint):
114
- raise ClassiqQFuncError(
115
- "Output value type hint must be either a single QReg, `typing.Tuple[QReg, ...]` or, for python>=3.9, `tuple[QReg, ...]`"
116
- )
117
-
118
- # Allowing only a tuple of outputs:
119
- if not cls.is_tuple_generic_alias(output_value_type_hint):
120
- raise ClassiqQFuncError(
121
- "Output value type hint must be either Tuple[QReg, ...] or tuple[QReg, ...]"
122
- )
123
-
124
- # This line may raise ClassiqQFuncError
125
- return tuple(map(cls.to_generic_alias, output_value_type_hint.__args__))
126
-
127
- def _unpack_input_values(
128
- self, annotations: Dict[str, Any]
129
- ) -> Tuple[List[str], Tuple[GenericAlias, ...]]:
130
- input_names = list(annotations.keys())
131
- input_values = tuple(map(self.to_generic_alias, annotations.values()))
132
- return input_names, input_values
133
-
134
- @staticmethod
135
- def to_generic_alias(obj: Any) -> GenericAlias:
136
- # Handle GenericAlias
137
- if isinstance(obj, (QRegGenericAlias, GenericAlias)):
138
- return obj
139
- # Handle _GenericAlias, for python>3.9, i.e. when GenericAlias != _GenericAlias
140
- if isinstance(obj, _GenericAlias):
141
- return GenericAlias(obj.__origin__, obj.__args__)
142
- # Handle a single QReg (not GenericAlias of QReg)
143
- elif inspect.isclass(obj) and issubclass(obj, QReg):
144
- return GenericAlias(obj, tuple())
145
-
146
- raise ClassiqQFuncError(f"Invalid type hint object: {obj.__class__.__name__}")
147
-
148
- @staticmethod
149
- def is_instance_generic_alias(obj: Any) -> bool:
150
- return isinstance(obj, (GenericAlias, _GenericAlias))
151
-
152
- @classmethod
153
- def is_subclass_qreg(cls, obj: Any) -> bool:
154
- if inspect.isclass(obj):
155
- return issubclass(obj, QReg)
156
- elif cls.is_instance_generic_alias(obj):
157
- return issubclass(obj.__origin__, QReg)
158
- return False
159
-
160
- @staticmethod
161
- def is_tuple_generic_alias(obj: GenericAliasUnion) -> bool:
162
- return obj.__origin__.__name__.lower() == "tuple"
163
-
164
- @staticmethod
165
- def is_valid_generic_alias_of_qreg(obj: GenericAlias) -> bool:
166
- return isinstance(obj, QRegGenericAlias)
167
-
168
-
169
- def get_annotation_role(annotation: GenericAlias, default_role: Role) -> Role:
170
- """
171
- Note: this function cannot distinguish between inputs and outputs.
172
- Thus, for inputs, all 3 options are valid
173
- However, for outputs:
174
- a) we don't expect to get ZERO
175
- b) We treat INPUT as OUTPUT
176
- """
177
- ret = None
178
-
179
- if getattr(annotation, "role", None) is not None:
180
- ret = annotation.role
181
- if getattr(annotation.__origin__, "role", None) is not None:
182
- ret = annotation.role
183
-
184
- if issubclass(annotation.__origin__, QReg) and not issubclass(
185
- annotation.__origin__, ZeroQReg
186
- ):
187
- ret = default_role
188
-
189
- if issubclass(annotation.__origin__, ZeroQReg) and not issubclass(
190
- annotation.__origin__, AuxQReg
191
- ):
192
- ret = Role.ZERO_INPUT
193
-
194
- if issubclass(annotation.__origin__, AuxQReg):
195
- ret = Role.AUXILIARY
196
-
197
- # Didn't match anything so far
198
- if ret is None:
199
- raise ClassiqQFuncError("Invalid annotation role")
200
-
201
- if default_role == Role.INPUT and ret == Role.OUTPUT:
202
- raise ClassiqQFuncError("input should not have Role.OUTPUT")
203
-
204
- if default_role == Role.OUTPUT and ret in (Role.ZERO_INPUT, Role.INPUT):
205
- raise ClassiqQFuncError("output should not have Role.ZERO / Role.INPUT")
206
-
207
- return ret