classiq 0.43.3__py3-none-any.whl → 0.44.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 (112) hide show
  1. classiq/__init__.py +7 -1
  2. classiq/_internals/client.py +4 -7
  3. classiq/_internals/host_checker.py +34 -12
  4. classiq/_internals/jobs.py +2 -2
  5. classiq/applications/chemistry/chemistry_model_constructor.py +12 -6
  6. classiq/applications/combinatorial_helpers/allowed_constraints.py +4 -1
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  8. classiq/applications/finance/finance_model_constructor.py +3 -2
  9. classiq/applications/grover/grover_model_constructor.py +7 -5
  10. classiq/applications/hamiltonian/__init__.py +0 -0
  11. classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
  12. classiq/applications/qnn/qlayer.py +1 -1
  13. classiq/exceptions.py +4 -0
  14. classiq/interface/_version.py +1 -1
  15. classiq/interface/ast_node.py +1 -18
  16. classiq/interface/backend/backend_preferences.py +10 -16
  17. classiq/interface/backend/ionq/ionq_quantum_program.py +1 -1
  18. classiq/interface/backend/pydantic_backend.py +0 -5
  19. classiq/interface/backend/quantum_backend_providers.py +3 -2
  20. classiq/interface/chemistry/operator.py +5 -1
  21. classiq/interface/debug_info/__init__.py +0 -0
  22. classiq/interface/debug_info/debug_info.py +32 -0
  23. classiq/interface/executor/execution_preferences.py +1 -45
  24. classiq/interface/executor/result.py +25 -12
  25. classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
  26. classiq/interface/generator/application_apis/chemistry_declarations.py +78 -60
  27. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +19 -10
  28. classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
  29. classiq/interface/generator/application_apis/finance_declarations.py +36 -22
  30. classiq/interface/generator/application_apis/qsvm_declarations.py +21 -15
  31. classiq/interface/generator/arith/arithmetic_expression_abc.py +21 -1
  32. classiq/interface/generator/arith/binary_ops.py +5 -4
  33. classiq/interface/generator/arith/extremum_operations.py +43 -19
  34. classiq/interface/generator/constant.py +1 -1
  35. classiq/interface/generator/expressions/atomic_expression_functions.py +1 -0
  36. classiq/interface/generator/expressions/expression_constants.py +3 -1
  37. classiq/interface/generator/expressions/qmod_qarray_proxy.py +52 -66
  38. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +35 -0
  39. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  40. classiq/interface/generator/functions/builtins/core_library/__init__.py +4 -2
  41. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +41 -41
  42. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +52 -42
  43. classiq/interface/generator/functions/builtins/open_lib_functions.py +1095 -3347
  44. classiq/interface/generator/functions/builtins/quantum_operators.py +9 -22
  45. classiq/interface/generator/functions/classical_function_declaration.py +14 -6
  46. classiq/interface/generator/functions/classical_type.py +7 -76
  47. classiq/interface/generator/functions/concrete_types.py +55 -0
  48. classiq/interface/generator/functions/function_declaration.py +10 -10
  49. classiq/interface/generator/functions/type_name.py +104 -0
  50. classiq/interface/generator/generated_circuit_data.py +3 -3
  51. classiq/interface/generator/model/model.py +11 -0
  52. classiq/interface/generator/model/preferences/preferences.py +5 -0
  53. classiq/interface/generator/quantum_function_call.py +3 -0
  54. classiq/interface/generator/quantum_program.py +2 -2
  55. classiq/interface/generator/register_role.py +7 -1
  56. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +1 -3
  57. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +1 -2
  58. classiq/interface/generator/types/qstruct_declaration.py +17 -0
  59. classiq/interface/generator/types/struct_declaration.py +1 -1
  60. classiq/interface/helpers/validation_helpers.py +1 -17
  61. classiq/interface/ide/visual_model.py +9 -2
  62. classiq/interface/interface_version.py +1 -0
  63. classiq/interface/model/bind_operation.py +25 -5
  64. classiq/interface/model/classical_parameter_declaration.py +8 -5
  65. classiq/interface/model/control.py +5 -5
  66. classiq/interface/model/handle_binding.py +185 -12
  67. classiq/interface/model/inplace_binary_operation.py +16 -4
  68. classiq/interface/model/model.py +28 -5
  69. classiq/interface/model/native_function_definition.py +8 -4
  70. classiq/interface/model/parameter.py +14 -0
  71. classiq/interface/model/port_declaration.py +20 -2
  72. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +21 -6
  73. classiq/interface/model/quantum_expressions/arithmetic_operation.py +30 -6
  74. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -9
  75. classiq/interface/model/quantum_function_call.py +135 -192
  76. classiq/interface/model/quantum_function_declaration.py +147 -165
  77. classiq/interface/model/quantum_lambda_function.py +24 -6
  78. classiq/interface/model/quantum_statement.py +34 -8
  79. classiq/interface/model/quantum_type.py +61 -10
  80. classiq/interface/model/quantum_variable_declaration.py +1 -1
  81. classiq/interface/model/statement_block.py +2 -0
  82. classiq/interface/model/validation_handle.py +7 -0
  83. classiq/interface/server/global_versions.py +4 -4
  84. classiq/interface/server/routes.py +2 -0
  85. classiq/interface/source_reference.py +59 -0
  86. classiq/qmod/__init__.py +2 -3
  87. classiq/qmod/builtins/functions.py +39 -11
  88. classiq/qmod/builtins/operations.py +171 -40
  89. classiq/qmod/declaration_inferrer.py +99 -56
  90. classiq/qmod/expression_query.py +1 -1
  91. classiq/qmod/model_state_container.py +2 -0
  92. classiq/qmod/native/pretty_printer.py +71 -53
  93. classiq/qmod/pretty_print/pretty_printer.py +98 -52
  94. classiq/qmod/qfunc.py +11 -5
  95. classiq/qmod/qmod_parameter.py +1 -2
  96. classiq/qmod/qmod_variable.py +364 -172
  97. classiq/qmod/quantum_callable.py +3 -3
  98. classiq/qmod/quantum_expandable.py +119 -65
  99. classiq/qmod/quantum_function.py +15 -3
  100. classiq/qmod/semantics/annotation.py +12 -13
  101. classiq/qmod/semantics/error_manager.py +36 -10
  102. classiq/qmod/semantics/static_semantics_visitor.py +163 -75
  103. classiq/qmod/semantics/validation/func_call_validation.py +42 -96
  104. classiq/qmod/semantics/validation/handle_validation.py +85 -0
  105. classiq/qmod/semantics/validation/types_validation.py +108 -1
  106. classiq/qmod/type_attribute_remover.py +32 -0
  107. classiq/qmod/utilities.py +26 -5
  108. {classiq-0.43.3.dist-info → classiq-0.44.0.dist-info}/METADATA +3 -3
  109. {classiq-0.43.3.dist-info → classiq-0.44.0.dist-info}/RECORD +111 -99
  110. classiq/qmod/qmod_struct.py +0 -13
  111. /classiq/{interface/ide/show.py → show.py} +0 -0
  112. {classiq-0.43.3.dist-info → classiq-0.44.0.dist-info}/WHEEL +0 -0
@@ -2,18 +2,16 @@ from typing import (
2
2
  Any,
3
3
  ClassVar,
4
4
  Dict,
5
- List,
6
5
  Literal,
7
- Mapping,
8
6
  Sequence,
9
7
  Set,
10
- Type,
11
8
  Union,
12
9
  )
13
10
 
14
11
  import pydantic
15
12
  from typing_extensions import Annotated
16
13
 
14
+ from classiq.interface.generator.arith.register_user_input import RegisterUserInput
17
15
  from classiq.interface.generator.function_params import ArithmeticIODict, PortDirection
18
16
  from classiq.interface.generator.functions.function_declaration import (
19
17
  FunctionDeclaration,
@@ -22,218 +20,122 @@ from classiq.interface.generator.functions.port_declaration import (
22
20
  PortDeclarationDirection,
23
21
  )
24
22
  from classiq.interface.helpers.pydantic_model_helpers import (
25
- Nameable,
26
23
  values_with_discriminator,
27
24
  )
28
- from classiq.interface.helpers.validation_helpers import (
29
- validate_nameables_mapping,
30
- validate_nameables_no_overlap,
31
- )
32
25
  from classiq.interface.model.classical_parameter_declaration import (
26
+ AnonClassicalParameterDeclaration,
33
27
  ClassicalParameterDeclaration,
34
28
  )
35
- from classiq.interface.model.port_declaration import PortDeclaration
29
+ from classiq.interface.model.port_declaration import (
30
+ AnonPortDeclaration,
31
+ PortDeclaration,
32
+ )
36
33
  from classiq.interface.model.quantum_type import quantum_var_to_register
37
34
 
38
- from classiq.exceptions import ClassiqValueError
39
-
40
-
41
- def _is_equiv_kw_and_pos_decl(kw_decl: Nameable, pos_decl: Nameable) -> bool:
42
- if isinstance(pos_decl, ClassicalParameterDeclaration):
43
- return pos_decl.classical_type == kw_decl
44
- return pos_decl == kw_decl
45
-
46
-
47
- def _populate_declaration_dicts_with_positional_lists(
48
- pos_decls: Sequence[Nameable],
49
- kw_decls: Dict[str, Nameable],
50
- param_type: Type[Nameable],
51
- ) -> None:
52
- for pos_decl in pos_decls:
53
- if not isinstance(pos_decl, param_type):
54
- continue
55
- kw_decl = kw_decls.get(pos_decl.name)
56
- if kw_decl is not None and not _is_equiv_kw_and_pos_decl(kw_decl, pos_decl):
57
- raise ClassiqValueError(
58
- f"{param_type.__name__} parameter with name {pos_decl.name} already declared"
59
- )
60
- kw_decls[pos_decl.name] = (
61
- pos_decl.classical_type # type:ignore[assignment]
62
- if isinstance(pos_decl, ClassicalParameterDeclaration)
63
- else pos_decl
64
- )
65
-
66
-
67
- PositionalArg = Annotated[
68
- Union[ClassicalParameterDeclaration, "QuantumOperandDeclaration", PortDeclaration],
35
+ AnonPositionalArg = Annotated[
36
+ Union[
37
+ AnonClassicalParameterDeclaration,
38
+ "AnonQuantumOperandDeclaration",
39
+ AnonPortDeclaration,
40
+ ],
69
41
  pydantic.Field(..., discriminator="kind"),
70
42
  ]
71
43
 
72
44
 
73
45
  def _ports_to_registers(
74
- port_declarations: Dict[str, PortDeclaration], direction: PortDirection
75
- ) -> ArithmeticIODict:
76
- return {
77
- name: quantum_var_to_register(name, port_decl.quantum_type)
78
- for name, port_decl in port_declarations.items()
46
+ port_declarations: Sequence[AnonPortDeclaration], direction: PortDirection
47
+ ) -> Sequence[RegisterUserInput]:
48
+ return [
49
+ quantum_var_to_register(port_decl.get_name(), port_decl.quantum_type)
50
+ for port_decl in port_declarations
79
51
  if port_decl.direction.includes_port_direction(direction)
80
- }
52
+ ]
81
53
 
82
54
 
83
- class QuantumFunctionDeclaration(FunctionDeclaration):
55
+ class AnonQuantumFunctionDeclaration(FunctionDeclaration):
84
56
  """
85
57
  Facilitates the creation of a common quantum function interface object.
86
58
  """
87
59
 
88
- port_declarations: Dict[str, PortDeclaration] = pydantic.Field(
89
- description="The input and output ports of the function.",
90
- default_factory=dict,
60
+ positional_arg_declarations: Sequence[AnonPositionalArg] = pydantic.Field(
61
+ default_factory=list
91
62
  )
92
63
 
93
- operand_declarations: Mapping[str, "QuantumOperandDeclaration"] = pydantic.Field(
94
- description="The expected interface of the quantum function operands",
95
- default_factory=dict,
96
- )
64
+ @property
65
+ def port_declarations(self) -> Sequence[AnonPortDeclaration]:
66
+ return [
67
+ arg
68
+ for arg in self.positional_arg_declarations
69
+ if isinstance(arg, AnonPortDeclaration)
70
+ ]
97
71
 
98
- positional_arg_declarations: List[PositionalArg] = pydantic.Field(
99
- default_factory=list
100
- )
72
+ @property
73
+ def operand_declarations(self) -> Sequence["AnonQuantumOperandDeclaration"]:
74
+ return [
75
+ arg
76
+ for arg in self.positional_arg_declarations
77
+ if isinstance(arg, AnonQuantumOperandDeclaration)
78
+ ]
101
79
 
102
- BUILTIN_FUNCTION_DECLARATIONS: ClassVar[Dict[str, "QuantumFunctionDeclaration"]] = (
103
- {}
104
- )
80
+ @property
81
+ def param_decls(self) -> Sequence[AnonClassicalParameterDeclaration]:
82
+ return [
83
+ arg
84
+ for arg in self.positional_arg_declarations
85
+ if isinstance(arg, AnonClassicalParameterDeclaration)
86
+ ]
87
+
88
+ @property
89
+ def param_names(self) -> Sequence[str]:
90
+ return [param.get_name() for param in self.param_decls]
105
91
 
106
92
  @property
107
93
  def input_set(self) -> Set[str]:
108
- return set(self.inputs.keys())
94
+ return {inp.name for inp in self.inputs}
109
95
 
110
96
  @property
111
97
  def output_set(self) -> Set[str]:
112
- return set(self.outputs.keys())
98
+ return {output.name for output in self.outputs}
113
99
 
114
100
  @property
115
- def inputs(self) -> ArithmeticIODict:
101
+ def inputs(self) -> Sequence[RegisterUserInput]:
116
102
  return _ports_to_registers(self.port_declarations, PortDirection.Input)
117
103
 
118
104
  @property
119
- def outputs(self) -> ArithmeticIODict:
105
+ def outputs(self) -> Sequence[RegisterUserInput]:
120
106
  return _ports_to_registers(self.port_declarations, PortDirection.Output)
121
107
 
122
- def update_logic_flow(
123
- self, function_dict: Mapping[str, "QuantumFunctionDeclaration"]
124
- ) -> None:
125
- pass
126
-
127
108
  @property
128
- def port_names(self) -> List[str]:
129
- return list(self.port_declarations.keys())
109
+ def port_names(self) -> Sequence[str]:
110
+ return [port.get_name() for port in self.port_declarations]
130
111
 
131
112
  @property
132
- def operand_names(self) -> List[str]:
133
- return list(self.operand_declarations.keys())
113
+ def operand_names(self) -> Sequence[str]:
114
+ return [operand.get_name() for operand in self.operand_declarations]
134
115
 
135
116
  def ports_by_direction(
136
117
  self, direction: PortDirection
137
- ) -> Mapping[str, PortDeclaration]:
138
- return {
139
- name: port
140
- for name, port in self.port_declarations.items()
118
+ ) -> Sequence[AnonPortDeclaration]:
119
+ return [
120
+ port
121
+ for port in self.port_declarations
141
122
  if port.direction.includes_port_direction(direction)
142
- }
123
+ ]
143
124
 
144
125
  def ports_by_declaration_direction(
145
126
  self, direction: PortDeclarationDirection
146
127
  ) -> Set[str]:
147
128
  return {
148
- name
149
- for name, port in self.port_declarations.items()
129
+ port.get_name()
130
+ for port in self.port_declarations
150
131
  if port.direction == direction
151
132
  }
152
133
 
153
- def get_positional_arg_decls(self) -> List[PositionalArg]:
154
- result: List[PositionalArg] = self.positional_arg_declarations
155
- if not result:
156
- result = [
157
- ClassicalParameterDeclaration(name=name, classical_type=ctype)
158
- for name, ctype in self.param_decls.items()
159
- ]
160
- result.extend(self.operand_declarations.values())
161
- result.extend(self.port_declarations.values())
162
- return result
163
-
164
- @pydantic.validator("operand_declarations")
165
- def _validate_operand_declarations_names(
166
- cls, operand_declarations: Dict[str, "QuantumOperandDeclaration"]
167
- ) -> Dict[str, "QuantumOperandDeclaration"]:
168
- validate_nameables_mapping(operand_declarations, "Operand")
169
- return operand_declarations
170
-
171
- @pydantic.validator("port_declarations")
172
- def _validate_port_declarations_names(
173
- cls, port_declarations: Dict[str, PortDeclaration]
174
- ) -> Dict[str, PortDeclaration]:
175
- validate_nameables_mapping(port_declarations, "Port")
176
- return port_declarations
177
-
178
- @pydantic.root_validator()
179
- def _validate_params_and_operands_uniqueness(
180
- cls, values: Dict[str, Any]
181
- ) -> Dict[str, Any]:
182
- operand_declarations = values.get("operand_declarations")
183
- parameter_declarations = values.get("param_decls")
184
- port_declarations = values.get("port_declarations")
185
- operand_parameter = validate_nameables_no_overlap(
186
- operand_declarations, parameter_declarations, "operand", "parameter"
187
- )
188
- operand_port = validate_nameables_no_overlap(
189
- operand_declarations, port_declarations, "operand", "port"
190
- )
191
- parameter_port = validate_nameables_no_overlap(
192
- parameter_declarations, port_declarations, "parameter", "port"
193
- )
194
- error_message = ",".join(
195
- msg
196
- for msg in [operand_parameter, operand_port, parameter_port]
197
- if msg is not None
198
- )
199
-
200
- if error_message:
201
- raise ClassiqValueError(error_message)
202
-
203
- return values
204
-
205
- @pydantic.root_validator()
206
- def _reduce_positional_declarations_to_keyword(
207
- cls, values: Dict[str, Any]
208
- ) -> Dict[str, Any]:
209
- operand_declarations = values.get("operand_declarations", dict())
210
- parameter_declarations = values.get("param_decls", dict())
211
- port_declarations = values.get("port_declarations", dict())
212
-
213
- positional_arg_declarations = values.get("positional_arg_declarations", list())
214
-
215
- _populate_declaration_dicts_with_positional_lists(
216
- positional_arg_declarations,
217
- parameter_declarations,
218
- ClassicalParameterDeclaration,
219
- )
220
- _populate_declaration_dicts_with_positional_lists(
221
- positional_arg_declarations,
222
- operand_declarations,
223
- QuantumOperandDeclaration,
224
- )
225
- _populate_declaration_dicts_with_positional_lists(
226
- positional_arg_declarations, port_declarations, PortDeclaration
227
- )
228
-
229
- values["operand_declarations"] = operand_declarations
230
- values["param_decls"] = parameter_declarations
231
- values["port_declarations"] = port_declarations
232
-
233
- return values
234
-
235
-
236
- class QuantumOperandDeclaration(QuantumFunctionDeclaration):
134
+ def rename(self, new_name: str) -> "QuantumFunctionDeclaration":
135
+ return QuantumFunctionDeclaration(**{**self.__dict__, "name": new_name})
136
+
137
+
138
+ class AnonQuantumOperandDeclaration(AnonQuantumFunctionDeclaration):
237
139
  kind: Literal["QuantumOperandDeclaration"]
238
140
 
239
141
  is_list: bool = pydantic.Field(
@@ -245,5 +147,85 @@ class QuantumOperandDeclaration(QuantumFunctionDeclaration):
245
147
  def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
246
148
  return values_with_discriminator(values, "kind", "QuantumOperandDeclaration")
247
149
 
150
+ def rename(self, new_name: str) -> "QuantumOperandDeclaration":
151
+ return QuantumOperandDeclaration(**{**self.__dict__, "name": new_name})
152
+
153
+
154
+ AnonQuantumFunctionDeclaration.update_forward_refs()
155
+
156
+
157
+ class QuantumFunctionDeclaration(AnonQuantumFunctionDeclaration):
158
+ name: str
159
+
160
+ BUILTIN_FUNCTION_DECLARATIONS: ClassVar[
161
+ Dict[str, "NamedParamsQuantumFunctionDeclaration"]
162
+ ] = {}
163
+
164
+
165
+ class QuantumOperandDeclaration(
166
+ QuantumFunctionDeclaration, AnonQuantumOperandDeclaration
167
+ ):
168
+ pass
248
169
 
249
- QuantumFunctionDeclaration.update_forward_refs()
170
+
171
+ PositionalArg = Annotated[
172
+ Union[
173
+ ClassicalParameterDeclaration,
174
+ QuantumOperandDeclaration,
175
+ PortDeclaration,
176
+ ],
177
+ pydantic.Field(..., discriminator="kind"),
178
+ ]
179
+
180
+
181
+ class NamedParamsQuantumFunctionDeclaration(QuantumFunctionDeclaration):
182
+
183
+ positional_arg_declarations: Sequence[PositionalArg] = pydantic.Field(
184
+ default_factory=list
185
+ )
186
+
187
+ @property
188
+ def port_declarations_dict(self) -> Dict[str, PortDeclaration]:
189
+ return {port.name: port for port in self.port_declarations}
190
+
191
+ @property
192
+ def operand_declarations_dict(self) -> Dict[str, QuantumOperandDeclaration]:
193
+ return {op.name: op for op in self.operand_declarations}
194
+
195
+ @property
196
+ def param_decls_dict(self) -> Dict[str, ClassicalParameterDeclaration]:
197
+ return {param.name: param for param in self.param_decls}
198
+
199
+ @property
200
+ def inputs_dict(self) -> ArithmeticIODict:
201
+ return _ports_to_registers_dict(self.port_declarations, PortDirection.Input)
202
+
203
+ @property
204
+ def inouts_dict(self) -> ArithmeticIODict:
205
+ return _ports_to_registers_dict(self.port_declarations, PortDirection.Inout)
206
+
207
+ @property
208
+ def outputs_dict(self) -> ArithmeticIODict:
209
+ return _ports_to_registers_dict(self.port_declarations, PortDirection.Output)
210
+
211
+ @property
212
+ def port_declarations(self) -> Sequence[PortDeclaration]:
213
+ return super().port_declarations # type:ignore[return-value]
214
+
215
+ @property
216
+ def operand_declarations(self) -> Sequence[QuantumOperandDeclaration]:
217
+ return super().operand_declarations # type:ignore[return-value]
218
+
219
+ @property
220
+ def param_decls(self) -> Sequence[ClassicalParameterDeclaration]:
221
+ return super().param_decls # type:ignore[return-value]
222
+
223
+
224
+ def _ports_to_registers_dict(
225
+ port_declarations: Sequence[PortDeclaration], direction: PortDirection
226
+ ) -> ArithmeticIODict:
227
+ return {
228
+ port_decl.name: quantum_var_to_register(port_decl.name, port_decl.quantum_type)
229
+ for port_decl in port_declarations
230
+ if port_decl.direction.includes_port_direction(direction)
231
+ }
@@ -1,12 +1,14 @@
1
- from typing import TYPE_CHECKING, Dict, List, Optional, Union
1
+ from typing import TYPE_CHECKING, Dict, List, Optional, Union, cast
2
2
 
3
3
  import pydantic
4
4
 
5
5
  from classiq.interface.ast_node import ASTNode
6
6
  from classiq.interface.model.quantum_function_declaration import (
7
- QuantumOperandDeclaration,
7
+ AnonQuantumOperandDeclaration,
8
8
  )
9
9
 
10
+ from classiq.exceptions import ClassiqError
11
+
10
12
  if TYPE_CHECKING:
11
13
  from classiq.interface.model.statement_block import StatementBlock
12
14
 
@@ -18,22 +20,38 @@ class QuantumLambdaFunction(ASTNode):
18
20
 
19
21
  rename_params: Dict[str, str] = pydantic.Field(
20
22
  default_factory=dict,
21
- description="Mapping of the declared param to the actual variable name used ",
23
+ )
24
+
25
+ pos_rename_params: List[str] = pydantic.Field(
26
+ default_factory=list,
27
+ description="Mapping of the declared param to the actual variable name used",
22
28
  )
23
29
 
24
30
  body: "StatementBlock" = pydantic.Field(
25
31
  description="A list of function calls passed to the operator"
26
32
  )
27
33
 
28
- _func_decl: Optional[QuantumOperandDeclaration] = pydantic.PrivateAttr(default=None)
34
+ _func_decl: Optional[AnonQuantumOperandDeclaration] = pydantic.PrivateAttr(
35
+ default=None
36
+ )
29
37
 
30
38
  @property
31
- def func_decl(self) -> Optional[QuantumOperandDeclaration]:
39
+ def func_decl(self) -> AnonQuantumOperandDeclaration:
40
+ if self._func_decl is None:
41
+ raise ClassiqError("Could not resolve lambda signature.")
32
42
  return self._func_decl
33
43
 
34
- def set_op_decl(self, fd: QuantumOperandDeclaration) -> None:
44
+ def set_op_decl(self, fd: AnonQuantumOperandDeclaration) -> None:
35
45
  self._func_decl = fd
36
46
 
47
+ def get_rename_params(self) -> List[str]:
48
+ if self.pos_rename_params:
49
+ return self.pos_rename_params
50
+ return [
51
+ self.rename_params.get(cast(str, param.name), cast(str, param.name))
52
+ for param in self.func_decl.positional_arg_declarations
53
+ ]
54
+
37
55
 
38
56
  QuantumCallable = Union[str, QuantumLambdaFunction]
39
57
  QuantumOperand = Union[QuantumCallable, List[QuantumCallable]]
@@ -1,13 +1,13 @@
1
- from typing import Any, Dict, Mapping, Union
1
+ from dataclasses import dataclass
2
+ from typing import Any, Dict, Mapping, Optional, Sequence
2
3
 
3
4
  from pydantic import Extra, root_validator
4
5
 
5
6
  from classiq.interface.ast_node import ASTNode
6
7
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
7
8
  from classiq.interface.model.handle_binding import (
9
+ ConcreteHandleBinding,
8
10
  HandleBinding,
9
- SlicedHandleBinding,
10
- SubscriptHandleBinding,
11
11
  )
12
12
 
13
13
 
@@ -22,19 +22,45 @@ class QuantumStatement(ASTNode):
22
22
  return values_with_discriminator(values, "kind", cls.__name__) # type: ignore[attr-defined]
23
23
 
24
24
 
25
+ @dataclass
26
+ class HandleMetadata:
27
+ handle: HandleBinding
28
+ readable_location: Optional[str] = None
29
+
30
+
25
31
  class QuantumOperation(QuantumStatement):
26
32
  @property
27
33
  def wiring_inputs(self) -> Mapping[str, HandleBinding]:
28
34
  return dict()
29
35
 
30
36
  @property
31
- def wiring_inouts(
32
- self,
33
- ) -> Mapping[
34
- str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
35
- ]:
37
+ def inputs(self) -> Sequence[HandleBinding]:
38
+ return list(self.wiring_inputs.values())
39
+
40
+ @property
41
+ def wiring_inouts(self) -> Mapping[str, ConcreteHandleBinding]:
36
42
  return dict()
37
43
 
44
+ @property
45
+ def inouts(self) -> Sequence[HandleBinding]:
46
+ return list(self.wiring_inouts.values())
47
+
38
48
  @property
39
49
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
40
50
  return dict()
51
+
52
+ @property
53
+ def outputs(self) -> Sequence[HandleBinding]:
54
+ return list(self.wiring_outputs.values())
55
+
56
+ @property
57
+ def readable_inputs(self) -> Sequence[HandleMetadata]:
58
+ return [HandleMetadata(handle=handle) for handle in self.inputs]
59
+
60
+ @property
61
+ def readable_inouts(self) -> Sequence[HandleMetadata]:
62
+ return [HandleMetadata(handle=handle) for handle in self.inouts]
63
+
64
+ @property
65
+ def readable_outputs(self) -> Sequence[HandleMetadata]:
66
+ return [HandleMetadata(handle=handle) for handle in self.outputs]
@@ -1,8 +1,7 @@
1
- from typing import Any, Dict, Literal, Optional, Union
1
+ from typing import TYPE_CHECKING, Any, Dict, Literal, Optional
2
2
 
3
3
  import pydantic
4
- from pydantic import Extra, Field
5
- from typing_extensions import Annotated
4
+ from pydantic import BaseModel, Extra, Field
6
5
 
7
6
  from classiq.interface.ast_node import HashableASTNode
8
7
  from classiq.interface.generator.arith.register_user_input import (
@@ -22,6 +21,11 @@ from classiq.interface.model.handle_binding import HandleBinding
22
21
 
23
22
  from classiq.exceptions import ClassiqValueError
24
23
 
24
+ if TYPE_CHECKING:
25
+ from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
26
+
27
+ from classiq.qmod.qmod_variable import QArray, QBit, QNum, QVar
28
+
25
29
 
26
30
  class QuantumType(HashableASTNode):
27
31
  class Config:
@@ -56,7 +60,10 @@ class QuantumType(HashableASTNode):
56
60
 
57
61
  @property
58
62
  def type_name(self) -> str:
59
- return self.get_proxy(HandleBinding(name="DUMMY")).type_name
63
+ raise NotImplementedError
64
+
65
+ def to_qvar(self, origin: HandleBinding) -> "QVar":
66
+ raise NotImplementedError
60
67
 
61
68
 
62
69
  class QuantumScalar(QuantumType):
@@ -82,6 +89,15 @@ class QuantumBit(QuantumScalar):
82
89
  def get_proxy(self, handle: "HandleBinding") -> QmodQBitProxy:
83
90
  return QmodQBitProxy(handle)
84
91
 
92
+ @property
93
+ def type_name(self) -> str:
94
+ return "Quantum bit"
95
+
96
+ def to_qvar(self, origin: HandleBinding) -> "QBit":
97
+ from classiq.qmod.qmod_variable import QBit
98
+
99
+ return QBit(origin)
100
+
85
101
 
86
102
  class QuantumBitvector(QuantumType):
87
103
  kind: Literal["qvec"]
@@ -120,7 +136,7 @@ class QuantumBitvector(QuantumType):
120
136
  assert self.size_in_bits % element_size == 0
121
137
  return QmodQArrayProxy(
122
138
  handle,
123
- self.element_type.get_proxy,
139
+ self.element_type,
124
140
  element_size,
125
141
  self.size_in_bits // element_size,
126
142
  )
@@ -131,6 +147,15 @@ class QuantumBitvector(QuantumType):
131
147
  length = [self.length.expr] if self.length is not None else []
132
148
  return f"QArray[{', '.join(element_type + length)}]"
133
149
 
150
+ @property
151
+ def type_name(self) -> str:
152
+ return "Quantum array"
153
+
154
+ def to_qvar(self, origin: HandleBinding) -> "QArray":
155
+ from classiq.qmod.qmod_variable import QArray
156
+
157
+ return QArray(origin, element_type=self.element_type, length=self.length)
158
+
134
159
 
135
160
  class QuantumNumeric(QuantumScalar):
136
161
  kind: Literal["qnum"]
@@ -193,12 +218,29 @@ class QuantumNumeric(QuantumScalar):
193
218
  return f"QNum[{self.size.expr}, {self.is_signed.expr}, {self.fraction_digits.expr}]"
194
219
  return "QNum"
195
220
 
221
+ @property
222
+ def type_name(self) -> str:
223
+ return "Quantum numeric"
224
+
225
+ def to_qvar(self, origin: HandleBinding) -> "QNum":
226
+ from classiq.qmod.qmod_variable import QNum
227
+
228
+ return QNum(origin, self.size, self.is_signed, self.fraction_digits)
229
+
230
+
231
+ class RegisterQuantumType(BaseModel):
232
+ quantum_types: "ConcreteQuantumType"
233
+ size: int = Field(default=1)
196
234
 
197
- ConcreteQuantumType = Annotated[
198
- Union[QuantumBit, QuantumBitvector, QuantumNumeric],
199
- Field(discriminator="kind", default_factory=QuantumBitvector),
200
- ]
201
- QuantumBitvector.update_forward_refs()
235
+ @property
236
+ def qmod_type_name(self) -> str:
237
+ try:
238
+ return self.quantum_types.qmod_type_name.split("[")[0]
239
+ except AttributeError:
240
+ return "default"
241
+
242
+
243
+ RegisterQuantumTypeDict = Dict[str, RegisterQuantumType]
202
244
 
203
245
 
204
246
  def register_info_to_quantum_type(reg_info: RegisterArithmeticInfo) -> QuantumNumeric:
@@ -225,3 +267,12 @@ def quantum_var_to_register(name: str, qtype: QuantumType) -> RegisterUserInput:
225
267
  is_signed=signed,
226
268
  fraction_places=fraction_places,
227
269
  )
270
+
271
+
272
+ def quantum_type_to_register_quantum_type(
273
+ qtype: QuantumType, size: int
274
+ ) -> RegisterQuantumType:
275
+ return RegisterQuantumType(
276
+ quantum_types=qtype,
277
+ size=size,
278
+ )
@@ -4,8 +4,8 @@ import pydantic
4
4
 
5
5
  from classiq.interface.ast_node import ASTNode
6
6
  from classiq.interface.generator.expressions.expression import Expression
7
+ from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
7
8
  from classiq.interface.model.quantum_type import (
8
- ConcreteQuantumType,
9
9
  QuantumBitvector,
10
10
  QuantumNumeric,
11
11
  )
@@ -8,6 +8,7 @@ from classiq.interface.model.classical_if import ClassicalIf
8
8
  from classiq.interface.model.control import Control
9
9
  from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
10
10
  from classiq.interface.model.invert import Invert
11
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
11
12
  from classiq.interface.model.power import Power
12
13
  from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
13
14
  AmplitudeLoadingOperation,
@@ -50,3 +51,4 @@ Power.update_forward_refs(StatementBlock=StatementBlock)
50
51
  Invert.update_forward_refs(StatementBlock=StatementBlock)
51
52
  WithinApply.update_forward_refs(StatementBlock=StatementBlock)
52
53
  ClassicalIf.update_forward_refs(StatementBlock=StatementBlock)
54
+ NativeFunctionDefinition.update_forward_refs(StatementBlock=StatementBlock)
@@ -12,6 +12,13 @@ class HandleState(Enum):
12
12
  UNINITIALIZED = 1
13
13
  ERRORED = 2
14
14
 
15
+ def __invert__(self) -> "HandleState":
16
+ if self == HandleState.INITIALIZED:
17
+ return HandleState.UNINITIALIZED
18
+ if self == HandleState.UNINITIALIZED:
19
+ return HandleState.INITIALIZED
20
+ return self
21
+
15
22
 
16
23
  @dataclasses.dataclass
17
24
  class ValidationHandle: