classiq 0.43.3__py3-none-any.whl → 0.45.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 (220) hide show
  1. classiq/__init__.py +8 -3
  2. classiq/_internals/api_wrapper.py +2 -2
  3. classiq/_internals/authentication/auth0.py +1 -1
  4. classiq/_internals/authentication/device.py +5 -1
  5. classiq/_internals/authentication/token_manager.py +5 -4
  6. classiq/_internals/client.py +5 -8
  7. classiq/_internals/config.py +1 -2
  8. classiq/_internals/host_checker.py +34 -13
  9. classiq/_internals/jobs.py +3 -3
  10. classiq/analyzer/analyzer.py +1 -1
  11. classiq/analyzer/analyzer_utilities.py +1 -1
  12. classiq/analyzer/rb.py +1 -1
  13. classiq/applications/chemistry/chemistry_model_constructor.py +13 -7
  14. classiq/applications/combinatorial_helpers/allowed_constraints.py +4 -1
  15. classiq/applications/combinatorial_helpers/arithmetic/isolation.py +1 -1
  16. classiq/applications/combinatorial_helpers/encoding_mapping.py +1 -1
  17. classiq/applications/combinatorial_helpers/encoding_utils.py +2 -1
  18. classiq/applications/combinatorial_helpers/optimization_model.py +1 -1
  19. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +1 -1
  20. classiq/applications/combinatorial_helpers/pyomo_utils.py +1 -2
  21. classiq/applications/combinatorial_helpers/transformations/encoding.py +1 -1
  22. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +5 -4
  23. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +1 -1
  24. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +1 -1
  25. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  26. classiq/applications/finance/finance_model_constructor.py +4 -3
  27. classiq/applications/grover/grover_model_constructor.py +7 -5
  28. classiq/applications/hamiltonian/__init__.py +0 -0
  29. classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
  30. classiq/applications/qnn/circuit_utils.py +1 -1
  31. classiq/applications/qnn/datasets/dataset_base_classes.py +2 -1
  32. classiq/applications/qnn/datasets/dataset_not.py +2 -1
  33. classiq/applications/qnn/qlayer.py +3 -2
  34. classiq/applications/qnn/torch_utils.py +2 -1
  35. classiq/applications/qsvm/qsvm_model_constructor.py +1 -1
  36. classiq/execution/execution_session.py +1 -1
  37. classiq/execution/jobs.py +5 -2
  38. classiq/interface/_version.py +1 -1
  39. classiq/interface/analyzer/cytoscape_graph.py +1 -2
  40. classiq/interface/analyzer/result.py +2 -3
  41. classiq/interface/ast_node.py +1 -18
  42. classiq/interface/backend/backend_preferences.py +11 -18
  43. classiq/interface/backend/ionq/ionq_quantum_program.py +1 -1
  44. classiq/interface/backend/pydantic_backend.py +0 -5
  45. classiq/interface/backend/quantum_backend_providers.py +4 -3
  46. classiq/interface/chemistry/fermionic_operator.py +1 -2
  47. classiq/interface/chemistry/ground_state_problem.py +2 -3
  48. classiq/interface/chemistry/molecule.py +1 -2
  49. classiq/interface/chemistry/operator.py +8 -10
  50. classiq/interface/combinatorial_optimization/encoding_types.py +1 -1
  51. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +1 -1
  52. classiq/interface/combinatorial_optimization/solver_types.py +1 -1
  53. classiq/interface/debug_info/__init__.py +0 -0
  54. classiq/interface/debug_info/debug_info.py +32 -0
  55. classiq/{exceptions.py → interface/exceptions.py} +4 -0
  56. classiq/interface/executor/aws_execution_cost.py +2 -2
  57. classiq/interface/executor/execution_preferences.py +2 -47
  58. classiq/interface/executor/execution_result.py +1 -2
  59. classiq/interface/executor/optimizer_preferences.py +2 -3
  60. classiq/interface/executor/quantum_code.py +1 -2
  61. classiq/interface/executor/quantum_instruction_set.py +2 -2
  62. classiq/interface/executor/register_initialization.py +1 -2
  63. classiq/interface/executor/result.py +29 -14
  64. classiq/interface/finance/function_input.py +6 -11
  65. classiq/interface/generator/amplitude_loading.py +2 -3
  66. classiq/interface/generator/ansatz_library.py +1 -1
  67. classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
  68. classiq/interface/generator/application_apis/chemistry_declarations.py +78 -60
  69. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +19 -10
  70. classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
  71. classiq/interface/generator/application_apis/finance_declarations.py +37 -44
  72. classiq/interface/generator/application_apis/qsvm_declarations.py +21 -15
  73. classiq/interface/generator/arith/arithmetic.py +10 -8
  74. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +1 -2
  75. classiq/interface/generator/arith/arithmetic_expression_abc.py +22 -3
  76. classiq/interface/generator/arith/arithmetic_expression_parser.py +3 -4
  77. classiq/interface/generator/arith/arithmetic_expression_validator.py +1 -2
  78. classiq/interface/generator/arith/arithmetic_param_getters.py +1 -2
  79. classiq/interface/generator/arith/arithmetic_result_builder.py +15 -11
  80. classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
  81. classiq/interface/generator/arith/binary_ops.py +7 -7
  82. classiq/interface/generator/arith/endianness.py +1 -1
  83. classiq/interface/generator/arith/extremum_operations.py +44 -21
  84. classiq/interface/generator/arith/logical_ops.py +1 -2
  85. classiq/interface/generator/arith/register_user_input.py +1 -2
  86. classiq/interface/generator/arith/unary_ops.py +1 -2
  87. classiq/interface/generator/arith/uncomputation_methods.py +1 -1
  88. classiq/interface/generator/chemistry_function_params.py +1 -2
  89. classiq/interface/generator/circuit_code/circuit_code.py +1 -2
  90. classiq/interface/generator/circuit_code/types_and_constants.py +1 -2
  91. classiq/interface/generator/commuting_pauli_exponentiation.py +1 -2
  92. classiq/interface/generator/constant.py +1 -1
  93. classiq/interface/generator/control_state.py +1 -2
  94. classiq/interface/generator/custom_ansatz.py +1 -2
  95. classiq/interface/generator/expressions/atomic_expression_functions.py +1 -0
  96. classiq/interface/generator/expressions/enums/finance_functions.py +4 -5
  97. classiq/interface/generator/expressions/evaluated_expression.py +1 -2
  98. classiq/interface/generator/expressions/expression.py +1 -2
  99. classiq/interface/generator/expressions/expression_constants.py +3 -1
  100. classiq/interface/generator/expressions/non_symbolic_expr.py +1 -1
  101. classiq/interface/generator/expressions/qmod_qarray_proxy.py +53 -70
  102. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +2 -7
  103. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +35 -0
  104. classiq/interface/generator/expressions/qmod_sized_proxy.py +1 -1
  105. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  106. classiq/interface/generator/function_params.py +2 -3
  107. classiq/interface/generator/functions/builtins/core_library/__init__.py +4 -2
  108. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +41 -41
  109. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +52 -42
  110. classiq/interface/generator/functions/builtins/open_lib_functions.py +1095 -3347
  111. classiq/interface/generator/functions/builtins/quantum_operators.py +9 -22
  112. classiq/interface/generator/functions/classical_function_declaration.py +14 -6
  113. classiq/interface/generator/functions/classical_type.py +7 -114
  114. classiq/interface/generator/functions/concrete_types.py +55 -0
  115. classiq/interface/generator/functions/function_declaration.py +10 -10
  116. classiq/interface/generator/functions/port_declaration.py +1 -2
  117. classiq/interface/generator/functions/type_name.py +80 -0
  118. classiq/interface/generator/generated_circuit_data.py +3 -3
  119. classiq/interface/generator/grover_diffuser.py +1 -2
  120. classiq/interface/generator/grover_operator.py +1 -2
  121. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +1 -2
  122. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +1 -2
  123. classiq/interface/generator/hardware/hardware_data.py +1 -2
  124. classiq/interface/generator/hardware_efficient_ansatz.py +2 -3
  125. classiq/interface/generator/hartree_fock.py +1 -2
  126. classiq/interface/generator/linear_pauli_rotations.py +1 -2
  127. classiq/interface/generator/mcmt_method.py +1 -1
  128. classiq/interface/generator/mcu.py +1 -2
  129. classiq/interface/generator/mcx.py +1 -2
  130. classiq/interface/generator/model/constraints.py +2 -3
  131. classiq/interface/generator/model/model.py +12 -2
  132. classiq/interface/generator/model/preferences/preferences.py +7 -3
  133. classiq/interface/generator/model/quantum_register.py +1 -2
  134. classiq/interface/generator/oracles/arithmetic_oracle.py +1 -2
  135. classiq/interface/generator/oracles/custom_oracle.py +1 -2
  136. classiq/interface/generator/oracles/oracle_abc.py +1 -2
  137. classiq/interface/generator/partitioned_register.py +1 -2
  138. classiq/interface/generator/piecewise_linear_amplitude_loading.py +1 -2
  139. classiq/interface/generator/preferences/optimization.py +1 -2
  140. classiq/interface/generator/qpe.py +1 -2
  141. classiq/interface/generator/qsvm.py +2 -3
  142. classiq/interface/generator/quantum_function_call.py +4 -2
  143. classiq/interface/generator/quantum_program.py +6 -7
  144. classiq/interface/generator/range_types.py +1 -1
  145. classiq/interface/generator/register_role.py +8 -2
  146. classiq/interface/generator/slice_parsing_utils.py +1 -2
  147. classiq/interface/generator/standard_gates/controlled_standard_gates.py +1 -2
  148. classiq/interface/generator/state_preparation/metrics.py +2 -3
  149. classiq/interface/generator/state_preparation/state_preparation.py +1 -2
  150. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +1 -3
  151. classiq/interface/generator/transpiler_basis_gates.py +1 -1
  152. classiq/interface/generator/types/builtin_enum_declarations.py +38 -45
  153. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +1 -2
  154. classiq/interface/generator/types/enum_declaration.py +1 -2
  155. classiq/interface/generator/types/qstruct_declaration.py +17 -0
  156. classiq/interface/generator/types/struct_declaration.py +2 -3
  157. classiq/interface/generator/ucc.py +1 -2
  158. classiq/interface/generator/unitary_gate.py +1 -2
  159. classiq/interface/generator/validations/flow_graph.py +1 -2
  160. classiq/interface/generator/validations/validator_functions.py +1 -2
  161. classiq/interface/hardware.py +1 -1
  162. classiq/interface/helpers/validation_helpers.py +2 -19
  163. classiq/interface/ide/visual_model.py +10 -4
  164. classiq/interface/interface_version.py +1 -0
  165. classiq/interface/jobs.py +2 -3
  166. classiq/interface/model/bind_operation.py +26 -7
  167. classiq/interface/model/classical_parameter_declaration.py +8 -5
  168. classiq/interface/model/control.py +5 -5
  169. classiq/interface/model/handle_binding.py +185 -12
  170. classiq/interface/model/inplace_binary_operation.py +17 -6
  171. classiq/interface/model/model.py +29 -7
  172. classiq/interface/model/native_function_definition.py +8 -4
  173. classiq/interface/model/parameter.py +13 -0
  174. classiq/interface/model/port_declaration.py +21 -4
  175. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +22 -8
  176. classiq/interface/model/quantum_expressions/arithmetic_operation.py +30 -6
  177. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -9
  178. classiq/interface/model/quantum_function_call.py +136 -194
  179. classiq/interface/model/quantum_function_declaration.py +147 -165
  180. classiq/interface/model/quantum_lambda_function.py +23 -6
  181. classiq/interface/model/quantum_statement.py +34 -8
  182. classiq/interface/model/quantum_type.py +41 -11
  183. classiq/interface/model/quantum_variable_declaration.py +1 -1
  184. classiq/interface/model/statement_block.py +2 -0
  185. classiq/interface/model/validation_handle.py +8 -2
  186. classiq/interface/server/global_versions.py +4 -4
  187. classiq/interface/server/routes.py +2 -0
  188. classiq/interface/source_reference.py +59 -0
  189. classiq/qmod/__init__.py +2 -3
  190. classiq/qmod/builtins/classical_execution_primitives.py +1 -1
  191. classiq/qmod/builtins/functions.py +39 -11
  192. classiq/qmod/builtins/operations.py +172 -41
  193. classiq/qmod/classical_function.py +1 -1
  194. classiq/qmod/declaration_inferrer.py +102 -57
  195. classiq/qmod/expression_query.py +1 -1
  196. classiq/qmod/model_state_container.py +2 -0
  197. classiq/qmod/native/pretty_printer.py +71 -53
  198. classiq/qmod/pretty_print/pretty_printer.py +98 -52
  199. classiq/qmod/qfunc.py +11 -5
  200. classiq/qmod/qmod_constant.py +1 -1
  201. classiq/qmod/qmod_parameter.py +27 -4
  202. classiq/qmod/qmod_variable.py +405 -174
  203. classiq/qmod/quantum_callable.py +3 -3
  204. classiq/qmod/quantum_expandable.py +128 -68
  205. classiq/qmod/quantum_function.py +24 -5
  206. classiq/qmod/semantics/annotation.py +13 -15
  207. classiq/qmod/semantics/error_manager.py +36 -10
  208. classiq/qmod/semantics/static_semantics_visitor.py +164 -76
  209. classiq/qmod/semantics/validation/func_call_validation.py +43 -97
  210. classiq/qmod/semantics/validation/handle_validation.py +85 -0
  211. classiq/qmod/semantics/validation/types_validation.py +108 -1
  212. classiq/qmod/symbolic.py +2 -1
  213. classiq/qmod/type_attribute_remover.py +32 -0
  214. classiq/qmod/utilities.py +26 -5
  215. classiq/{interface/ide/show.py → show.py} +1 -1
  216. {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/METADATA +3 -3
  217. {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/RECORD +219 -207
  218. classiq/qmod/qmod_struct.py +0 -13
  219. /classiq/{_internals → interface}/enum_utils.py +0 -0
  220. {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/WHEEL +0 -0
@@ -12,13 +12,13 @@ from typing import ( # type: ignore[attr-defined]
12
12
 
13
13
  from typing_extensions import ParamSpec
14
14
 
15
- from classiq.interface.ast_node import SourceReference
16
15
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
17
16
  from classiq.interface.model.quantum_function_declaration import (
18
- QuantumFunctionDeclaration,
17
+ AnonQuantumFunctionDeclaration,
19
18
  )
20
19
  from classiq.interface.model.quantum_statement import QuantumStatement
21
20
  from classiq.interface.model.quantum_type import QuantumType
21
+ from classiq.interface.source_reference import SourceReference
22
22
 
23
23
  from classiq.qmod.qmod_parameter import CInt
24
24
  from classiq.qmod.utilities import get_source_ref
@@ -58,7 +58,7 @@ class QCallable(Generic[P], ABC):
58
58
 
59
59
  @property
60
60
  @abstractmethod
61
- def func_decl(self) -> QuantumFunctionDeclaration:
61
+ def func_decl(self) -> AnonQuantumFunctionDeclaration:
62
62
  raise NotImplementedError
63
63
 
64
64
  # Support comma-separated generic args in older Python versions
@@ -20,24 +20,23 @@ from typing import (
20
20
  from sympy import Basic
21
21
  from typing_extensions import Self
22
22
 
23
- from classiq.interface.ast_node import SourceReference
23
+ from classiq.interface.exceptions import ClassiqValueError
24
24
  from classiq.interface.generator.expressions.expression import Expression
25
- from classiq.interface.generator.functions.classical_type import (
26
- PythonClassicalTypes,
27
- )
25
+ from classiq.interface.generator.functions.concrete_types import PythonClassicalTypes
28
26
  from classiq.interface.model.classical_parameter_declaration import (
29
- ClassicalParameterDeclaration,
27
+ AnonClassicalParameterDeclaration,
30
28
  )
31
- from classiq.interface.model.port_declaration import PortDeclaration
29
+ from classiq.interface.model.port_declaration import AnonPortDeclaration
32
30
  from classiq.interface.model.quantum_function_call import (
33
31
  ArgValue,
34
32
  OperandIdentifier,
35
33
  QuantumFunctionCall,
36
34
  )
37
35
  from classiq.interface.model.quantum_function_declaration import (
38
- PositionalArg,
36
+ AnonPositionalArg,
37
+ AnonQuantumFunctionDeclaration,
38
+ AnonQuantumOperandDeclaration,
39
39
  QuantumFunctionDeclaration,
40
- QuantumOperandDeclaration,
41
40
  )
42
41
  from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
43
42
  from classiq.interface.model.quantum_statement import QuantumStatement
@@ -45,14 +44,25 @@ from classiq.interface.model.quantum_type import QuantumType
45
44
  from classiq.interface.model.variable_declaration_statement import (
46
45
  VariableDeclarationStatement,
47
46
  )
47
+ from classiq.interface.source_reference import SourceReference
48
48
 
49
- from classiq.exceptions import ClassiqValueError
50
49
  from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
51
50
  from classiq.qmod.qmod_constant import QConstant
52
- from classiq.qmod.qmod_parameter import CInt, CParam, CParamScalar, create_param
53
- from classiq.qmod.qmod_variable import QVar, create_qvar_for_port_decl
51
+ from classiq.qmod.qmod_parameter import (
52
+ CInt,
53
+ CParam,
54
+ CParamScalar,
55
+ create_param,
56
+ get_qmod_type,
57
+ )
58
+ from classiq.qmod.qmod_variable import (
59
+ QVar,
60
+ create_qvar_for_port_decl,
61
+ set_symbolic_qvar_properties,
62
+ )
54
63
  from classiq.qmod.quantum_callable import QCallable, QExpandableInterface
55
64
  from classiq.qmod.symbolic_expr import SymbolicExpr
65
+ from classiq.qmod.type_attribute_remover import decl_without_type_attributes
56
66
  from classiq.qmod.utilities import mangle_keyword, qmod_val_to_expr_str
57
67
 
58
68
  ArgType = Union[CParam, QVar, QCallable]
@@ -89,11 +99,11 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
89
99
 
90
100
  def expand(self) -> None:
91
101
  if self not in QExpandable.STACK:
92
- with self:
102
+ with self, set_symbolic_qvar_properties(True):
93
103
  self._py_callable(*self._get_positional_args())
94
104
 
95
- def infer_rename_params(self) -> Dict[str, str]:
96
- return {}
105
+ def infer_rename_params(self) -> Optional[List[str]]:
106
+ return None
97
107
 
98
108
  def add_local_handle(
99
109
  self,
@@ -112,60 +122,94 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
112
122
 
113
123
  def _get_positional_args(self) -> List[ArgType]:
114
124
  result: List[ArgType] = []
115
- for arg in self.func_decl.get_positional_arg_decls():
116
- rename_dict = self.infer_rename_params()
117
- actual_name = rename_dict.get(arg.name, arg.name)
118
- if isinstance(arg, ClassicalParameterDeclaration):
125
+ for idx, arg in enumerate(self.func_decl.positional_arg_declarations):
126
+ rename_params = self.infer_rename_params()
127
+ actual_name = (
128
+ rename_params[idx] if rename_params is not None else arg.get_name()
129
+ )
130
+ if isinstance(arg, AnonClassicalParameterDeclaration):
119
131
  result.append(
120
132
  create_param(actual_name, arg.classical_type, self._qmodule)
121
133
  )
122
- elif isinstance(arg, PortDeclaration):
134
+ elif isinstance(arg, AnonPortDeclaration):
123
135
  result.append(create_qvar_for_port_decl(arg, actual_name))
124
136
  else:
125
- assert isinstance(arg, QuantumOperandDeclaration)
126
- result.append(QTerminalCallable(arg))
137
+ assert isinstance(arg, AnonQuantumOperandDeclaration)
138
+ result.append(QTerminalCallable(arg, idx))
127
139
  return result
128
140
 
129
141
  def create_quantum_function_call(
130
142
  self, source_ref_: SourceReference, *args: Any, **kwargs: Any
131
143
  ) -> QuantumFunctionCall:
144
+ func_decl = self.func_decl
145
+ if not isinstance(func_decl, QuantumFunctionDeclaration):
146
+ raise NotImplementedError
132
147
  return _create_quantum_function_call(
133
- self.func_decl, None, source_ref_, *args, **kwargs
148
+ func_decl, None, source_ref_, *args, **kwargs
134
149
  )
135
150
 
136
151
 
137
152
  class QLambdaFunction(QExpandable):
138
- def __init__(self, decl: QuantumFunctionDeclaration, py_callable: Callable) -> None:
153
+ def __init__(
154
+ self, decl: AnonQuantumFunctionDeclaration, py_callable: Callable
155
+ ) -> None:
139
156
  py_callable.__annotations__.pop("return", None)
140
157
  super().__init__(py_callable)
141
158
  self._decl = decl
142
159
 
143
160
  @property
144
- def func_decl(self) -> QuantumFunctionDeclaration:
161
+ def func_decl(self) -> AnonQuantumFunctionDeclaration:
145
162
  return self._decl
146
163
 
147
- def infer_rename_params(self) -> Dict[str, str]:
148
- py_params = inspect.getfullargspec(self._py_callable)
149
- decl_params = self.func_decl.get_positional_arg_decls()
150
- return {
151
- decl_param.name: py_param
152
- for decl_param, py_param in zip(decl_params, py_params.args)
153
- if decl_param.name != py_param
154
- }
164
+ def infer_rename_params(self) -> List[str]:
165
+ return inspect.getfullargspec(self._py_callable).args
155
166
 
156
167
 
157
168
  class QTerminalCallable(QCallable):
169
+ @overload
158
170
  def __init__(
159
171
  self,
160
172
  decl: QuantumFunctionDeclaration,
173
+ param_idx: Optional[int] = None,
161
174
  index_: Optional[Union[int, CParamScalar]] = None,
162
175
  ) -> None:
163
- self._decl = decl
176
+ pass
177
+
178
+ @overload
179
+ def __init__(
180
+ self,
181
+ decl: AnonQuantumFunctionDeclaration,
182
+ param_idx: int,
183
+ index_: Optional[Union[int, CParamScalar]] = None,
184
+ ) -> None:
185
+ pass
186
+
187
+ def __init__(
188
+ self,
189
+ decl: AnonQuantumFunctionDeclaration,
190
+ param_idx: Optional[int] = None,
191
+ index_: Optional[Union[int, CParamScalar]] = None,
192
+ ) -> None:
193
+ self._decl = self._override_decl_name(decl, param_idx)
164
194
  self._index = index_
165
195
 
196
+ @staticmethod
197
+ def _override_decl_name(
198
+ decl: AnonQuantumFunctionDeclaration, param_idx: Optional[int]
199
+ ) -> QuantumFunctionDeclaration:
200
+ if (
201
+ not isinstance(QCallable.CURRENT_EXPANDABLE, QLambdaFunction)
202
+ or param_idx is None
203
+ ):
204
+ return decl.rename(decl.get_name())
205
+ rename_params = QCallable.CURRENT_EXPANDABLE.infer_rename_params()
206
+ return decl.rename(new_name=rename_params[param_idx])
207
+
166
208
  @property
167
209
  def is_list(self) -> bool:
168
- return isinstance(self._decl, QuantumOperandDeclaration) and self._decl.is_list
210
+ return (
211
+ isinstance(self._decl, AnonQuantumOperandDeclaration) and self._decl.is_list
212
+ )
169
213
 
170
214
  def __getitem__(self, key: Union[slice, int, CInt]) -> "QTerminalCallable":
171
215
  if not self.is_list:
@@ -174,7 +218,7 @@ class QTerminalCallable(QCallable):
174
218
  raise NotImplementedError("Operand lists don't support slicing")
175
219
  if isinstance(key, CParam) and not isinstance(key, CParamScalar):
176
220
  raise ClassiqValueError("Non-classical parameter for slicing")
177
- return QTerminalCallable(self._decl, key)
221
+ return QTerminalCallable(self._decl, index_=key)
178
222
 
179
223
  def __len__(self) -> int:
180
224
  raise ClassiqValueError(
@@ -212,43 +256,54 @@ class QTerminalCallable(QCallable):
212
256
 
213
257
  @overload
214
258
  def prepare_arg(
215
- arg_decl: PositionalArg, val: Union[QCallable, Callable[..., None]], func_name: str
259
+ arg_decl: AnonPositionalArg,
260
+ val: Union[QCallable, Callable[..., None]],
261
+ func_name: Optional[str],
262
+ param_name: str,
216
263
  ) -> QuantumLambdaFunction: ...
217
264
 
218
265
 
219
266
  @overload
220
- def prepare_arg(arg_decl: PositionalArg, val: Any, func_name: str) -> ArgValue: ...
267
+ def prepare_arg(
268
+ arg_decl: AnonPositionalArg, val: Any, func_name: Optional[str], param_name: str
269
+ ) -> ArgValue: ...
221
270
 
222
271
 
223
- def prepare_arg(arg_decl: PositionalArg, val: Any, func_name: str) -> ArgValue:
272
+ def prepare_arg(
273
+ arg_decl: AnonPositionalArg, val: Any, func_name: Optional[str], param_name: str
274
+ ) -> ArgValue:
224
275
  if isinstance(val, QConstant):
225
276
  val.add_to_model()
226
277
  return Expression(expr=str(val.name))
227
- if isinstance(arg_decl, ClassicalParameterDeclaration):
278
+ if isinstance(arg_decl, AnonClassicalParameterDeclaration):
228
279
  _validate_classical_arg(val, arg_decl, func_name)
229
280
  return Expression(expr=qmod_val_to_expr_str(val))
230
- elif isinstance(arg_decl, PortDeclaration):
281
+ elif isinstance(arg_decl, AnonPortDeclaration):
231
282
  if not isinstance(val, QVar):
283
+ func_name_message = (
284
+ "" if func_name is None else f" of function {func_name!r}"
285
+ )
232
286
  raise ClassiqValueError(
233
- f"Argument {str(val)!r} to parameter {arg_decl.name!r} of function "
234
- f"{func_name!r} has incompatible type; expected quantum variable"
287
+ f"Argument {str(val)!r} to parameter {param_name!r}{func_name_message} "
288
+ f"has incompatible type; expected quantum variable"
235
289
  )
236
290
  return val.get_handle_binding()
237
291
  else:
238
292
  if isinstance(val, list):
239
293
  if not all(isinstance(v, QCallable) or callable(v) for v in val):
240
294
  raise ClassiqValueError(
241
- f"Quantum operand {arg_decl.name!r} cannot be initialized with a "
295
+ f"Quantum operand {param_name!r} cannot be initialized with a "
242
296
  f"list of non-callables"
243
297
  )
244
298
  val = cast(List[Union[QCallable, Callable[[Any], None]]], val)
245
- return [prepare_arg(arg_decl, v, func_name) for v in val]
299
+ return [prepare_arg(arg_decl, v, func_name, param_name) for v in val]
246
300
 
247
301
  if not isinstance(val, QCallable):
248
- val = QLambdaFunction(arg_decl, val)
302
+ new_arg_decl = decl_without_type_attributes(arg_decl)
303
+ val = QLambdaFunction(new_arg_decl, val)
249
304
  val.expand()
250
305
  return QuantumLambdaFunction(
251
- rename_params=val.infer_rename_params(),
306
+ pos_rename_params=val.infer_rename_params(),
252
307
  body=val.body,
253
308
  )
254
309
 
@@ -258,7 +313,7 @@ def prepare_arg(arg_decl: PositionalArg, val: Any, func_name: str) -> ArgValue:
258
313
 
259
314
 
260
315
  def _validate_classical_arg(
261
- arg: Any, arg_decl: ClassicalParameterDeclaration, func_name: str
316
+ arg: Any, arg_decl: AnonClassicalParameterDeclaration, func_name: Optional[str]
262
317
  ) -> None:
263
318
  if (
264
319
  not isinstance(
@@ -268,15 +323,16 @@ def _validate_classical_arg(
268
323
  or isinstance(arg, SymbolicExpr)
269
324
  and arg.is_quantum
270
325
  ):
326
+ func_name_message = "" if func_name is None else f" of function {func_name!r}"
271
327
  raise ClassiqValueError(
272
- f"Argument {str(arg)!r} to parameter {arg_decl.name!r} of function "
273
- f"{func_name!r} has incompatible type; expected "
274
- f"{arg_decl.classical_type.qmod_type.__name__}"
328
+ f"Argument {str(arg)!r} to parameter {arg_decl.name!r}{func_name_message} "
329
+ f"has incompatible type; expected "
330
+ f"{get_qmod_type(arg_decl.classical_type).__name__}"
275
331
  )
276
332
 
277
333
 
278
334
  def _get_operand_hint_args(
279
- func: QuantumFunctionDeclaration, param: PositionalArg, param_value: str
335
+ func: AnonQuantumFunctionDeclaration, param: AnonPositionalArg, param_value: str
280
336
  ) -> str:
281
337
  return ", ".join(
282
338
  [
@@ -285,39 +341,43 @@ def _get_operand_hint_args(
285
341
  if decl.name == param.name
286
342
  else f"{decl.name}=..."
287
343
  )
288
- for decl in func.get_positional_arg_decls()
344
+ for decl in func.positional_arg_declarations
289
345
  ]
290
346
  )
291
347
 
292
348
 
293
- def _get_operand_hint(func: QuantumFunctionDeclaration, param: PositionalArg) -> str:
349
+ def _get_operand_hint(
350
+ func: AnonQuantumFunctionDeclaration, param: AnonPositionalArg
351
+ ) -> str:
294
352
  return (
295
- f"\nHint: To create an operand, do not call quantum gates directly "
296
- f"`{func.name}({_get_operand_hint_args(func, param, 'H(q)')})`. "
297
- f"Instead, use a lambda function "
298
- f"`{func.name}({_get_operand_hint_args(func, param, 'lambda: H(q)')})` "
299
- f"or a quantum function "
300
- f"`{func.name}({_get_operand_hint_args(func, param, 'my_func')})`"
353
+ f"\nHint: To call a function under {func.name!r} use a lambda function as in "
354
+ f"'{func.name}({_get_operand_hint_args(func, param, 'lambda: f(q)')})' "
355
+ f"or pass the quantum function directly as in "
356
+ f"'{func.name}({_get_operand_hint_args(func, param, 'f')})'."
301
357
  )
302
358
 
303
359
 
304
360
  def _prepare_args(
305
- decl: QuantumFunctionDeclaration, arg_list: List[Any], kwargs: Dict[str, Any]
361
+ decl: AnonQuantumFunctionDeclaration, arg_list: List[Any], kwargs: Dict[str, Any]
306
362
  ) -> List[ArgValue]:
307
363
  result = []
308
- for arg_decl in decl.get_positional_arg_decls():
364
+ for idx, arg_decl in enumerate(decl.positional_arg_declarations):
365
+ arg = None
309
366
  if arg_list:
310
367
  arg = arg_list.pop(0)
311
- else:
368
+ elif arg_decl.name is not None:
312
369
  arg = kwargs.pop(mangle_keyword(arg_decl.name), None)
313
370
  if arg is None:
314
- error_message = (
315
- f"{decl.name!r} is missing required argument for {arg_decl.name!r}"
316
- )
317
- if isinstance(arg_decl, QuantumOperandDeclaration):
371
+ if arg_decl.name is not None:
372
+ param_name = repr(arg_decl.name)
373
+ else:
374
+ param_name = f"#{idx + 1}"
375
+ error_message = f"Missing required argument for parameter {param_name}"
376
+ if isinstance(arg_decl, AnonQuantumOperandDeclaration):
318
377
  error_message += _get_operand_hint(decl, arg_decl)
319
378
  raise ClassiqValueError(error_message)
320
- result.append(prepare_arg(arg_decl, arg, decl.name))
379
+ param_name = arg_decl.name if arg_decl.name is not None else f"#{idx + 1}"
380
+ result.append(prepare_arg(arg_decl, arg, decl.name, param_name))
321
381
 
322
382
  return result
323
383
 
@@ -329,7 +389,7 @@ def _create_quantum_function_call(
329
389
  *args: Any,
330
390
  **kwargs: Any,
331
391
  ) -> QuantumFunctionCall:
332
- arg_decls = decl_.get_positional_arg_decls()
392
+ arg_decls = decl_.positional_arg_declarations
333
393
  arg_list = list(args)
334
394
  prepared_args = _prepare_args(decl_, arg_list, kwargs)
335
395
 
@@ -5,27 +5,30 @@ from enum import EnumMeta
5
5
  from inspect import isclass
6
6
  from typing import Any, Callable, Dict, List, Optional, Tuple, get_origin
7
7
 
8
+ from classiq.interface.exceptions import ClassiqError
8
9
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
9
10
  from classiq.interface.generator.model.constraints import Constraints
10
11
  from classiq.interface.generator.model.preferences.preferences import Preferences
11
12
  from classiq.interface.model.model import Model, SerializedModel
12
13
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
13
14
  from classiq.interface.model.quantum_function_declaration import (
15
+ NamedParamsQuantumFunctionDeclaration,
14
16
  QuantumFunctionDeclaration,
15
17
  )
16
18
 
17
- from classiq.exceptions import ClassiqError
18
19
  from classiq.qmod.classical_function import CFunc
19
20
  from classiq.qmod.declaration_inferrer import infer_func_decl
21
+ from classiq.qmod.model_state_container import QMODULE
20
22
  from classiq.qmod.qmod_constant import QConstant
21
23
  from classiq.qmod.qmod_parameter import CArray, CParam
22
24
  from classiq.qmod.qmod_variable import QVar
23
25
  from classiq.qmod.quantum_callable import QCallable, QCallableList
24
26
  from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
25
27
  from classiq.qmod.utilities import mangle_keyword, unmangle_keyword
28
+ from classiq.qmod.write_qmod import write_qmod
26
29
 
27
30
 
28
- def _lookup_qfunc(name: str) -> Optional[QuantumFunctionDeclaration]:
31
+ def _lookup_qfunc(name: str) -> Optional[NamedParamsQuantumFunctionDeclaration]:
29
32
  # FIXME: to be generalized to existing user-defined functions
30
33
  return QuantumFunctionDeclaration.BUILTIN_FUNCTION_DECLARATIONS.get(name)
31
34
 
@@ -36,15 +39,21 @@ def create_model(
36
39
  execution_preferences: Optional[ExecutionPreferences] = None,
37
40
  preferences: Optional[Preferences] = None,
38
41
  classical_execution_function: Optional[CFunc] = None,
42
+ out_file: Optional[str] = None,
39
43
  ) -> SerializedModel:
40
44
  if entry_point.func_decl.name != "main":
41
45
  raise ClassiqError(
42
46
  f"The entry point function must be named 'main', got '{entry_point.func_decl.name}'"
43
47
  )
44
- return entry_point.create_model(
48
+ result = entry_point.create_model(
45
49
  constraints, execution_preferences, preferences, classical_execution_function
46
50
  ).get_model()
47
51
 
52
+ if out_file is not None:
53
+ write_qmod(result, out_file)
54
+
55
+ return result
56
+
48
57
 
49
58
  class QFunc(QExpandable):
50
59
  FRAME_DEPTH = 2
@@ -55,7 +64,7 @@ class QFunc(QExpandable):
55
64
  functools.update_wrapper(self, py_callable)
56
65
 
57
66
  @property
58
- def func_decl(self) -> QuantumFunctionDeclaration:
67
+ def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
59
68
  return self._qmodule.native_defs.get(
60
69
  self._py_callable.__name__,
61
70
  infer_func_decl(self._py_callable, qmodule=self._qmodule),
@@ -74,6 +83,7 @@ class QFunc(QExpandable):
74
83
  ) -> Model:
75
84
  self._qmodule.enum_decls = dict()
76
85
  self._qmodule.type_decls = dict()
86
+ self._qmodule.qstruct_decls = dict()
77
87
  self._qmodule.native_defs = dict()
78
88
  self._qmodule.constants = dict()
79
89
  QConstant.set_current_model(self._qmodule)
@@ -93,6 +103,7 @@ class QFunc(QExpandable):
93
103
  functions=list(self._qmodule.native_defs.values()),
94
104
  enums=list(self._qmodule.enum_decls.values()),
95
105
  types=list(self._qmodule.type_decls.values()),
106
+ qstructs=list(self._qmodule.qstruct_decls.values()),
96
107
  **{key: value for key, value in model_extra_settings if value},
97
108
  )
98
109
 
@@ -138,7 +149,7 @@ class ExternalQFunc(QTerminalCallable):
138
149
 
139
150
  py_callable.__annotations__.pop("return", None)
140
151
  if py_callable.__annotations__.keys() != {
141
- mangle_keyword(arg.name) for arg in decl.get_positional_arg_decls()
152
+ mangle_keyword(arg.name) for arg in decl.positional_arg_declarations
142
153
  }:
143
154
  raise ClassiqError(
144
155
  f"Parameter type hints for {py_callable.__name__!r} do not match imported declaration"
@@ -147,6 +158,14 @@ class ExternalQFunc(QTerminalCallable):
147
158
  functools.update_wrapper(self, py_callable)
148
159
 
149
160
 
161
+ class GenerativeQFunc(QTerminalCallable):
162
+ func_decl: NamedParamsQuantumFunctionDeclaration
163
+
164
+ def __init__(self, py_callable: Callable) -> None:
165
+ super().__init__(infer_func_decl(py_callable, QMODULE))
166
+ self.py_callable = py_callable
167
+
168
+
150
169
  ILLEGAL_PARAM_ERROR = "Unsupported type hint '{annotation}' for argument '{name}'."
151
170
 
152
171
 
@@ -1,17 +1,15 @@
1
- from typing import List, Mapping
1
+ from typing import Mapping
2
2
 
3
+ from classiq.interface.exceptions import ClassiqError
3
4
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
4
5
  from classiq.interface.model.quantum_function_declaration import (
6
+ AnonQuantumOperandDeclaration,
5
7
  QuantumFunctionDeclaration,
6
8
  )
7
9
  from classiq.interface.model.quantum_lambda_function import (
8
- QuantumCallable,
9
10
  QuantumLambdaFunction,
10
- QuantumOperand,
11
11
  )
12
12
 
13
- from classiq.exceptions import ClassiqError
14
-
15
13
 
16
14
  def annotate_function_call_decl(
17
15
  fc: QuantumFunctionCall,
@@ -25,14 +23,14 @@ def annotate_function_call_decl(
25
23
  )
26
24
  fc.set_func_decl(func_decl)
27
25
 
28
- for name, op in fc.operands.items():
29
- op_decl = fc.func_decl.operand_declarations[name]
30
- for qlambda in _get_lambda_defs(op):
26
+ for arg, param in zip(fc.positional_args, fc.func_decl.positional_arg_declarations):
27
+ if not isinstance(param, AnonQuantumOperandDeclaration):
28
+ continue
29
+ args: list
30
+ if isinstance(arg, list):
31
+ args = arg
32
+ else:
33
+ args = [arg]
34
+ for qlambda in args:
31
35
  if isinstance(qlambda, QuantumLambdaFunction):
32
- qlambda.set_op_decl(op_decl)
33
-
34
-
35
- def _get_lambda_defs(operand: QuantumOperand) -> List[QuantumCallable]:
36
- if isinstance(operand, list):
37
- return operand
38
- return [operand]
36
+ qlambda.set_op_decl(param)
@@ -1,7 +1,8 @@
1
1
  from contextlib import contextmanager
2
- from typing import Iterator, List, Type
2
+ from typing import Iterator, List, Optional, Type
3
3
 
4
4
  from classiq.interface.ast_node import ASTNode
5
+ from classiq.interface.source_reference import SourceReferencedError
5
6
 
6
7
 
7
8
  class ErrorManager:
@@ -14,19 +15,28 @@ class ErrorManager:
14
15
  if hasattr(self, "_instantiated"):
15
16
  return
16
17
  self._instantiated = True
17
- self._errors: List[str] = []
18
+ self._errors: List[SourceReferencedError] = []
18
19
  self._current_nodes_stack: List[ASTNode] = []
20
+ self._call_stack: List[str] = []
21
+
22
+ @property
23
+ def annotated_errors(self) -> List[str]:
24
+ return [str(error) for error in self._errors]
19
25
 
20
26
  def add_error(self, error: str) -> None:
21
- source_referenced_error = (
22
- f"{error}\n\t\tat {self._current_nodes_stack[-1].source_ref}"
23
- if self._current_nodes_stack
24
- and self._current_nodes_stack[-1].source_ref is not None
25
- else error
27
+ self._errors.append(
28
+ SourceReferencedError(
29
+ error=error,
30
+ source_ref=(
31
+ self._current_nodes_stack[-1].source_ref
32
+ if self._current_nodes_stack
33
+ else None
34
+ ),
35
+ function=self.current_function,
36
+ )
26
37
  )
27
- self._errors.append(source_referenced_error)
28
38
 
29
- def get_errors(self) -> List[str]:
39
+ def get_errors(self) -> List[SourceReferencedError]:
30
40
  return self._errors
31
41
 
32
42
  def clear(self) -> None:
@@ -38,12 +48,28 @@ class ErrorManager:
38
48
 
39
49
  def report_errors(self, error_type: Type[Exception]) -> None:
40
50
  if self.has_errors():
41
- errors = self._errors
51
+ errors = self.annotated_errors
42
52
  self.clear()
43
53
  raise error_type("\n\t" + "\n\t".join(errors))
44
54
 
55
+ @property
56
+ def current_function(self) -> Optional[str]:
57
+ return self._call_stack[-1] if self._call_stack else None
58
+
45
59
  @contextmanager
46
60
  def node_context(self, node: ASTNode) -> Iterator[None]:
47
61
  self._current_nodes_stack.append(node)
48
62
  yield
49
63
  self._current_nodes_stack.pop()
64
+
65
+ @contextmanager
66
+ def call(self, func_name: str) -> Iterator[None]:
67
+ self._call_stack.append(func_name)
68
+ yield
69
+ self._call_stack.pop()
70
+
71
+
72
+ def append_error(node: ASTNode, message: str) -> None:
73
+ instance = ErrorManager()
74
+ with instance.node_context(node):
75
+ instance.add_error(message)