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
@@ -1,23 +1,22 @@
1
- from typing import Dict, Literal, Mapping, Union
1
+ from typing import Dict, Literal, Mapping, Sequence
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.exceptions import ClassiqValueError
5
6
  from classiq.interface.generator.amplitude_loading import (
6
7
  AMPLITUDE_IO_NAME,
7
8
  TARGET_OUTPUT_NAME,
8
9
  )
9
10
  from classiq.interface.model.handle_binding import (
11
+ ConcreteHandleBinding,
10
12
  HandleBinding,
11
- SlicedHandleBinding,
12
- SubscriptHandleBinding,
13
13
  )
14
14
  from classiq.interface.model.quantum_expressions.quantum_expression import (
15
15
  QuantumAssignmentOperation,
16
16
  )
17
+ from classiq.interface.model.quantum_statement import HandleMetadata
17
18
  from classiq.interface.model.quantum_type import QuantumBit, QuantumNumeric, QuantumType
18
19
 
19
- from classiq.exceptions import ClassiqValueError
20
-
21
20
  MULTI_VARS_UNSUPPORTED_ERROR = (
22
21
  "Amplitude Loading with more than one input variable is unsupported."
23
22
  )
@@ -33,14 +32,29 @@ class AmplitudeLoadingOperation(QuantumAssignmentOperation):
33
32
  @property
34
33
  def wiring_inouts(
35
34
  self,
36
- ) -> Mapping[
37
- str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
38
- ]:
35
+ ) -> Mapping[str, ConcreteHandleBinding]:
39
36
  inouts = {self.result_name(): self.result_var}
40
37
  if len(self.var_handles) == 1:
41
38
  inouts[AMPLITUDE_IO_NAME] = self.var_handles[0]
42
39
  return inouts
43
40
 
41
+ @property
42
+ def readable_inouts(self) -> Sequence[HandleMetadata]:
43
+ inouts = [
44
+ HandleMetadata(
45
+ handle=self.result_var,
46
+ readable_location="on the left-hand side of an in-place assignment",
47
+ )
48
+ ]
49
+ if len(self.var_handles) == 1:
50
+ inouts.append(
51
+ HandleMetadata(
52
+ handle=self.var_handles[0],
53
+ readable_location="in an expression",
54
+ )
55
+ )
56
+ return inouts
57
+
44
58
  @property
45
59
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
46
60
  return {}
@@ -1,4 +1,4 @@
1
- from typing import Dict, Literal, Mapping, Union
1
+ from typing import Dict, Literal, Mapping, Sequence
2
2
 
3
3
  import pydantic
4
4
 
@@ -7,13 +7,13 @@ from classiq.interface.generator.arith.arithmetic import (
7
7
  compute_arithmetic_result_type,
8
8
  )
9
9
  from classiq.interface.model.handle_binding import (
10
+ ConcreteHandleBinding,
10
11
  HandleBinding,
11
- SlicedHandleBinding,
12
- SubscriptHandleBinding,
13
12
  )
14
13
  from classiq.interface.model.quantum_expressions.quantum_expression import (
15
14
  QuantumAssignmentOperation,
16
15
  )
16
+ from classiq.interface.model.quantum_statement import HandleMetadata
17
17
  from classiq.interface.model.quantum_type import QuantumType
18
18
 
19
19
 
@@ -37,20 +37,44 @@ class ArithmeticOperation(QuantumAssignmentOperation):
37
37
  @property
38
38
  def wiring_inouts(
39
39
  self,
40
- ) -> Mapping[
41
- str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
42
- ]:
40
+ ) -> Mapping[str, ConcreteHandleBinding]:
43
41
  inouts = dict(super().wiring_inouts)
44
42
  if self.inplace_result:
45
43
  inouts[self.result_name()] = self.result_var
46
44
  return inouts
47
45
 
46
+ @property
47
+ def readable_inouts(self) -> Sequence[HandleMetadata]:
48
+ inouts = [
49
+ HandleMetadata(handle=handle, readable_location="in an expression")
50
+ for handle in self.var_handles
51
+ ]
52
+ if self.inplace_result:
53
+ inouts.append(
54
+ HandleMetadata(
55
+ handle=self.result_var,
56
+ readable_location="on the left-hand side of an in-place assignment",
57
+ )
58
+ )
59
+ return inouts
60
+
48
61
  @property
49
62
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
50
63
  if self.inplace_result:
51
64
  return {}
52
65
  return super().wiring_outputs
53
66
 
67
+ @property
68
+ def readable_outputs(self) -> Sequence[HandleMetadata]:
69
+ if self.inplace_result:
70
+ return []
71
+ return [
72
+ HandleMetadata(
73
+ handle=self.result_var,
74
+ readable_location="on the left-hand side of an assignment",
75
+ )
76
+ ]
77
+
54
78
  @classmethod
55
79
  def result_name(cls) -> str:
56
80
  return ARITHMETIC_EXPRESSION_RESULT_NAME
@@ -1,14 +1,13 @@
1
1
  import abc
2
- from typing import Dict, List, Mapping, Optional, Union
2
+ from typing import Dict, List, Mapping, Optional
3
3
 
4
4
  import pydantic
5
5
 
6
6
  from classiq.interface.generator.expressions.expression import Expression
7
7
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
8
8
  from classiq.interface.model.handle_binding import (
9
+ ConcreteHandleBinding,
9
10
  HandleBinding,
10
- SlicedHandleBinding,
11
- SubscriptHandleBinding,
12
11
  )
13
12
  from classiq.interface.model.quantum_statement import QuantumOperation
14
13
  from classiq.interface.model.quantum_type import QuantumType
@@ -43,16 +42,12 @@ class QuantumExpressionOperation(QuantumOperation):
43
42
  self._var_types = var_types
44
43
 
45
44
  @property
46
- def wiring_inouts(
47
- self,
48
- ) -> Mapping[
49
- str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
50
- ]:
45
+ def wiring_inouts(self) -> Mapping[str, ConcreteHandleBinding]:
51
46
  return nameables_to_dict(self.var_handles)
52
47
 
53
48
 
54
49
  class QuantumAssignmentOperation(QuantumExpressionOperation):
55
- result_var: HandleBinding = pydantic.Field(
50
+ result_var: ConcreteHandleBinding = pydantic.Field(
56
51
  description="The variable storing the expression result"
57
52
  )
58
53
  _result_type: Optional[QuantumType] = pydantic.PrivateAttr(
@@ -1,104 +1,39 @@
1
- import itertools
2
- from typing import Any, Dict, List, Literal, Mapping, Optional, Type, Union
1
+ from typing import (
2
+ Dict,
3
+ Iterable,
4
+ List,
5
+ Literal,
6
+ Mapping,
7
+ Optional,
8
+ Sequence,
9
+ Tuple,
10
+ Union,
11
+ )
12
+ from uuid import UUID, uuid4
3
13
 
4
14
  import pydantic
5
15
 
6
16
  from classiq.interface.ast_node import ASTNode
17
+ from classiq.interface.exceptions import ClassiqError, ClassiqValueError
7
18
  from classiq.interface.generator.expressions.expression import Expression
8
- from classiq.interface.generator.functions.function_declaration import (
9
- FunctionDeclaration,
10
- )
11
19
  from classiq.interface.generator.functions.port_declaration import (
12
20
  PortDeclarationDirection,
13
21
  )
14
22
  from classiq.interface.model.handle_binding import (
23
+ ConcreteHandleBinding,
15
24
  HandleBinding,
16
- SlicedHandleBinding,
17
- SubscriptHandleBinding,
18
25
  )
26
+ from classiq.interface.model.port_declaration import AnonPortDeclaration
19
27
  from classiq.interface.model.quantum_function_declaration import (
20
28
  QuantumFunctionDeclaration,
21
29
  )
22
- from classiq.interface.model.quantum_lambda_function import (
23
- QuantumOperand,
24
- )
25
- from classiq.interface.model.quantum_statement import QuantumOperation
26
- from classiq.interface.model.validation_handle import get_unique_handle_names
27
-
28
- from classiq.exceptions import ClassiqError, ClassiqValueError
29
-
30
-
31
- def _validate_no_duplicated_ports(
32
- inputs: Mapping[str, HandleBinding],
33
- outputs: Mapping[str, HandleBinding],
34
- inouts: Mapping[str, HandleBinding],
35
- ) -> None:
36
- inputs_and_inouts = inputs.keys() & inouts.keys()
37
- if inputs_and_inouts:
38
- raise ClassiqValueError(
39
- f"{inputs_and_inouts} are used as ports in both inputs and inouts"
40
- )
41
-
42
- outputs_and_inouts = outputs.keys() & inouts.keys()
43
- if outputs_and_inouts:
44
- raise ClassiqValueError(
45
- f"{outputs_and_inouts} are used as ports in both outputs and inouts"
46
- )
47
-
48
-
49
- def _validate_no_duplicated_handles(
50
- inputs: Mapping[str, HandleBinding],
51
- outputs: Mapping[str, HandleBinding],
52
- inouts: Mapping[str, HandleBinding],
53
- ) -> None:
54
- inputs_and_inouts = get_unique_handle_names(inputs) & get_unique_handle_names(
55
- inouts
56
- )
57
- if inputs_and_inouts:
58
- raise ClassiqValueError(
59
- f"{inputs_and_inouts} are used as handles in both inputs and inouts"
60
- )
61
-
62
- outputs_and_inouts = get_unique_handle_names(outputs) & get_unique_handle_names(
63
- inouts
64
- )
65
- if outputs_and_inouts:
66
- raise ClassiqValueError(
67
- f"{outputs_and_inouts} are used as handles in both outputs and inouts"
68
- )
69
-
70
-
71
- def _validate_no_mixing_sliced_and_whole_handles(
72
- inouts: Mapping[str, HandleBinding],
73
- ) -> None:
74
- def _treat_subscript_as_slice(type_: Type[HandleBinding]) -> Type[HandleBinding]:
75
- if type_ == SubscriptHandleBinding:
76
- return SlicedHandleBinding
77
- return type_
78
-
79
- inout_handle_names_to_types = {
80
- handle_name: {_treat_subscript_as_slice(type(handle)) for handle in handles}
81
- for handle_name, handles in itertools.groupby(
82
- inouts.values(), lambda handle: handle.name
83
- )
84
- }
85
- invalid_handles = [
86
- handle
87
- for handle, types in inout_handle_names_to_types.items()
88
- if len(types) > 1
89
- ]
90
- if invalid_handles:
91
- raise ClassiqValueError(
92
- f"Inout handles {', '.join(invalid_handles)} mix sliced and whole handles"
93
- )
94
-
30
+ from classiq.interface.model.quantum_lambda_function import QuantumOperand
31
+ from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
95
32
 
96
33
  ArgValue = Union[
97
34
  Expression,
98
35
  QuantumOperand,
99
- SlicedHandleBinding,
100
- SubscriptHandleBinding,
101
- HandleBinding,
36
+ ConcreteHandleBinding,
102
37
  ]
103
38
 
104
39
 
@@ -113,26 +48,10 @@ class QuantumFunctionCall(QuantumOperation):
113
48
  function: Union[str, OperandIdentifier] = pydantic.Field(
114
49
  description="The function that is called"
115
50
  )
116
- designated_params: Dict[str, Expression] = pydantic.Field(default_factory=dict)
117
- designated_inputs: Dict[str, HandleBinding] = pydantic.Field(
118
- default_factory=dict,
119
- description="A mapping from the input name to the wire it connects to",
120
- )
121
- designated_inouts: Dict[
122
- str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
123
- ] = pydantic.Field(
124
- default_factory=dict,
125
- description="A mapping from in/out name to the wires that connect to it",
126
- )
127
- designated_outputs: Dict[str, HandleBinding] = pydantic.Field(
128
- default_factory=dict,
129
- description="A mapping from the output name to the wire it connects to",
130
- )
131
- designated_operands: Dict[str, QuantumOperand] = pydantic.Field(
132
- description="Function calls passed to the operator",
133
- default_factory=dict,
134
- )
135
51
  positional_args: List[ArgValue] = pydantic.Field(default_factory=list)
52
+ uuid: UUID = pydantic.Field(
53
+ description="A unique identifier for this call", default_factory=uuid4
54
+ )
136
55
 
137
56
  _func_decl: Optional[QuantumFunctionDeclaration] = pydantic.PrivateAttr(
138
57
  default=None
@@ -145,7 +64,7 @@ class QuantumFunctionCall(QuantumOperation):
145
64
 
146
65
  return self._func_decl
147
66
 
148
- def set_func_decl(self, fd: Optional[FunctionDeclaration]) -> None:
67
+ def set_func_decl(self, fd: Optional[QuantumFunctionDeclaration]) -> None:
149
68
  if fd is not None and not isinstance(fd, QuantumFunctionDeclaration):
150
69
  raise ClassiqValueError(
151
70
  "the declaration of a quantum function call cannot be set to a non-quantum function declaration."
@@ -160,76 +79,113 @@ class QuantumFunctionCall(QuantumOperation):
160
79
 
161
80
  @property
162
81
  def wiring_inputs(self) -> Mapping[str, HandleBinding]:
163
- return self.inputs
82
+ return self._get_pos_port_args_by_direction(PortDeclarationDirection.Input)
83
+
84
+ @property
85
+ def inputs(self) -> Sequence[HandleBinding]:
86
+ return [
87
+ handle
88
+ for _, _, handle in self._get_handles_by_direction(
89
+ PortDeclarationDirection.Input
90
+ )
91
+ ]
92
+
93
+ @property
94
+ def readable_inputs(self) -> Sequence[HandleMetadata]:
95
+ return [
96
+ HandleMetadata(
97
+ handle=handle,
98
+ readable_location=self._get_readable_location(param_idx, param),
99
+ )
100
+ for param_idx, param, handle in self._get_handles_by_direction(
101
+ PortDeclarationDirection.Input
102
+ )
103
+ ]
164
104
 
165
105
  @property
166
106
  def wiring_inouts(
167
107
  self,
168
- ) -> Mapping[
169
- str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
170
- ]:
171
- return self.inouts
108
+ ) -> Mapping[str, ConcreteHandleBinding]:
109
+ return self._get_pos_port_args_by_direction(PortDeclarationDirection.Inout)
110
+
111
+ @property
112
+ def inouts(self) -> Sequence[HandleBinding]:
113
+ return [
114
+ handle
115
+ for _, _, handle in self._get_handles_by_direction(
116
+ PortDeclarationDirection.Inout
117
+ )
118
+ ]
119
+
120
+ @property
121
+ def readable_inouts(self) -> Sequence[HandleMetadata]:
122
+ return [
123
+ HandleMetadata(
124
+ handle=handle,
125
+ readable_location=self._get_readable_location(param_idx, param),
126
+ )
127
+ for param_idx, param, handle in self._get_handles_by_direction(
128
+ PortDeclarationDirection.Inout
129
+ )
130
+ ]
172
131
 
173
132
  @property
174
133
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
175
- return self.outputs
134
+ return self._get_pos_port_args_by_direction(PortDeclarationDirection.Output)
176
135
 
177
- def get_positional_args(self) -> List[ArgValue]:
178
- result: List[ArgValue] = self.positional_args
179
- if not result:
180
- result = list(self.designated_params.values())
181
- result.extend(self.designated_operands.values())
182
- result.extend(self.designated_inputs.values())
183
- result.extend(self.designated_inouts.values())
184
- result.extend(self.designated_outputs.values())
185
- return result
136
+ @property
137
+ def outputs(self) -> Sequence[HandleBinding]:
138
+ return [
139
+ handle
140
+ for _, _, handle in self._get_handles_by_direction(
141
+ PortDeclarationDirection.Output
142
+ )
143
+ ]
186
144
 
187
145
  @property
188
- def positional_params(self) -> Dict[str, Expression]:
189
- return dict(
190
- zip(
191
- self.func_decl.param_decls.keys(),
192
- (
193
- param
194
- for param in self.positional_args
195
- if isinstance(param, Expression)
196
- ),
146
+ def readable_outputs(self) -> Sequence[HandleMetadata]:
147
+ return [
148
+ HandleMetadata(
149
+ handle=handle,
150
+ readable_location=self._get_readable_location(param_idx, param),
197
151
  )
198
- )
152
+ for param_idx, param, handle in self._get_handles_by_direction(
153
+ PortDeclarationDirection.Output
154
+ )
155
+ ]
199
156
 
200
157
  @property
201
- def params(self) -> Dict[str, Expression]:
202
- return self.positional_params or self.designated_params
158
+ def params(self) -> List[Expression]:
159
+ return [
160
+ param for param in self.positional_args if isinstance(param, Expression)
161
+ ]
203
162
 
204
163
  @property
205
- def positional_operands(self) -> Dict[str, "QuantumOperand"]:
206
- return dict(
207
- zip(
208
- self.func_decl.operand_declarations.keys(),
209
- (
210
- param
211
- for param in self.positional_args
212
- if not isinstance(param, (Expression, HandleBinding))
213
- ),
214
- )
215
- )
164
+ def params_dict(self) -> Dict[str, Expression]:
165
+ return dict(zip(self.func_decl.param_names, self.params))
216
166
 
217
167
  @property
218
- def operands(self) -> Dict[str, "QuantumOperand"]:
219
- return self.positional_operands or self.designated_operands
168
+ def operands(self) -> List["QuantumOperand"]:
169
+ return [
170
+ param
171
+ for param in self.positional_args
172
+ if not isinstance(param, (Expression, HandleBinding))
173
+ ]
220
174
 
221
175
  @property
222
- def pos_port_args(self) -> Dict[str, HandleBinding]:
223
- return dict(
224
- zip(
225
- self.func_decl.port_declarations.keys(),
226
- (
227
- param
228
- for param in self.positional_args
229
- if isinstance(param, HandleBinding)
230
- ),
231
- )
232
- )
176
+ def ports(self) -> List[HandleBinding]:
177
+ return [
178
+ param for param in self.positional_args if isinstance(param, HandleBinding)
179
+ ]
180
+
181
+ def _get_handles_by_direction(
182
+ self, direction: PortDeclarationDirection
183
+ ) -> List[Tuple[int, AnonPortDeclaration, HandleBinding]]:
184
+ return [
185
+ (idx, port_decl, handle)
186
+ for idx, port_decl, handle in self._get_handles_with_declarations()
187
+ if direction == port_decl.direction
188
+ ]
233
189
 
234
190
  def _get_pos_port_args_by_direction(
235
191
  self, direction: PortDeclarationDirection
@@ -240,49 +196,35 @@ class QuantumFunctionCall(QuantumOperation):
240
196
  if self._func_decl is None:
241
197
  return dict()
242
198
  return {
243
- port_decl.name: port
244
- for port_decl, port in zip(
245
- self.func_decl.port_declarations.values(),
246
- (
247
- param
248
- for param in self.positional_args
249
- if isinstance(param, HandleBinding)
250
- ),
251
- )
199
+ port_decl.get_name(): handle
200
+ for _, port_decl, handle in self._get_handles_with_declarations()
252
201
  if direction == port_decl.direction
253
202
  }
254
203
 
255
- @property
256
- def inputs(self) -> Dict[str, HandleBinding]:
257
- return (
258
- self._get_pos_port_args_by_direction(PortDeclarationDirection.Input)
259
- or self.designated_inputs
260
- )
261
-
262
- @property
263
- def inouts(
204
+ def _get_handles_with_declarations(
264
205
  self,
265
- ) -> Dict[str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]]:
266
- return (
267
- self._get_pos_port_args_by_direction(PortDeclarationDirection.Inout)
268
- or self.designated_inouts
269
- )
206
+ ) -> Iterable[Tuple[int, AnonPortDeclaration, HandleBinding]]:
207
+ return [
208
+ (idx, port, handle)
209
+ for idx, (port, handle) in enumerate(
210
+ zip(
211
+ (port_decl for port_decl in self.func_decl.port_declarations),
212
+ (
213
+ param
214
+ for param in self.positional_args
215
+ if isinstance(param, HandleBinding)
216
+ ),
217
+ )
218
+ )
219
+ ]
270
220
 
271
- @property
272
- def outputs(self) -> Dict[str, HandleBinding]:
273
- return (
274
- self._get_pos_port_args_by_direction(PortDeclarationDirection.Output)
275
- or self.designated_outputs
221
+ def _get_readable_location(
222
+ self, param_index: int, param_decl: AnonPortDeclaration
223
+ ) -> str:
224
+ param_name = (
225
+ repr(param_decl.name) if param_decl.name is not None else f"#{param_index}"
276
226
  )
277
-
278
- @pydantic.root_validator()
279
- def validate_handles(cls, values: Dict[str, Any]) -> Dict[str, Any]:
280
- inputs = values.get("designated_inputs", dict())
281
- outputs = values.get("designated_outputs", dict())
282
- inouts = values.get("designated_inouts", dict())
283
-
284
- _validate_no_duplicated_ports(inputs, outputs, inouts)
285
- _validate_no_duplicated_handles(inputs, outputs, inouts)
286
- _validate_no_mixing_sliced_and_whole_handles(inouts)
287
-
288
- return values
227
+ param_text = (
228
+ f" for parameter {param_name}" if len(self.positional_args) > 1 else ""
229
+ )
230
+ return f"as an argument{param_text} of function {self.func_name!r}"