classiq 0.42.2__py3-none-any.whl → 0.43.1__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.
- classiq/__init__.py +2 -6
- classiq/_internals/api_wrapper.py +6 -12
- classiq/_internals/authentication/token_manager.py +5 -2
- classiq/_internals/jobs.py +5 -10
- classiq/analyzer/rb.py +3 -3
- classiq/applications/chemistry/chemistry_model_constructor.py +12 -8
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +2 -2
- classiq/applications/finance/finance_model_constructor.py +16 -13
- classiq/applications/qsvm/__init__.py +1 -3
- classiq/applications/qsvm/qsvm_model_constructor.py +7 -6
- classiq/exceptions.py +9 -4
- classiq/execution/execution_session.py +5 -2
- classiq/execution/qnn.py +1 -1
- classiq/executor.py +0 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/chemistry/operator.py +19 -5
- classiq/interface/executor/constants.py +1 -0
- classiq/interface/finance/function_input.py +16 -10
- classiq/interface/generator/application_apis/chemistry_declarations.py +2 -2
- classiq/interface/generator/application_apis/qsvm_declarations.py +4 -2
- classiq/interface/generator/arith/argument_utils.py +20 -3
- classiq/interface/generator/arith/arithmetic_expression_validator.py +3 -26
- classiq/interface/generator/arith/binary_ops.py +8 -14
- classiq/interface/generator/arith/extremum_operations.py +30 -0
- classiq/interface/generator/arith/number_utils.py +1 -1
- classiq/interface/generator/arith/unary_ops.py +1 -3
- classiq/interface/generator/compiler_keywords.py +1 -1
- classiq/interface/generator/expressions/atomic_expression_functions.py +13 -3
- classiq/interface/generator/expressions/enums/__init__.py +0 -20
- classiq/interface/generator/expressions/enums/finance_functions.py +11 -18
- classiq/interface/generator/expressions/non_symbolic_expr.py +119 -0
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +52 -37
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +16 -11
- classiq/interface/generator/expressions/qmod_sized_proxy.py +5 -5
- classiq/interface/generator/function_param_list_without_self_reference.py +0 -10
- classiq/interface/generator/function_params.py +0 -4
- classiq/interface/generator/functions/__init__.py +0 -20
- classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +2 -2
- classiq/interface/generator/functions/builtins/open_lib_functions.py +530 -1
- classiq/interface/generator/functions/classical_type.py +22 -69
- classiq/interface/generator/functions/port_declaration.py +0 -11
- classiq/interface/generator/model/__init__.py +0 -1
- classiq/interface/generator/model/model.py +9 -185
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +3 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +69 -0
- classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +2 -2
- classiq/interface/generator/types/enum_declaration.py +57 -0
- classiq/interface/jobs.py +36 -65
- classiq/interface/model/bind_operation.py +3 -0
- classiq/interface/model/classical_parameter_declaration.py +3 -0
- classiq/interface/model/handle_binding.py +7 -0
- classiq/interface/model/inplace_binary_operation.py +13 -15
- classiq/interface/model/model.py +8 -20
- classiq/interface/model/native_function_definition.py +0 -17
- classiq/interface/model/quantum_function_call.py +63 -182
- classiq/interface/model/quantum_type.py +71 -10
- classiq/interface/server/routes.py +0 -6
- classiq/qmod/__init__.py +3 -3
- classiq/qmod/builtins/__init__.py +10 -1
- classiq/qmod/builtins/classical_execution_primitives.py +4 -2
- classiq/qmod/builtins/enums.py +177 -0
- classiq/qmod/builtins/functions.py +1 -2
- classiq/qmod/builtins/operations.py +2 -4
- classiq/qmod/builtins/structs.py +16 -17
- classiq/qmod/declaration_inferrer.py +23 -20
- classiq/qmod/model_state_container.py +2 -0
- classiq/qmod/native/pretty_printer.py +31 -13
- classiq/qmod/pretty_print/pretty_printer.py +52 -27
- classiq/qmod/qmod_constant.py +7 -3
- classiq/qmod/qmod_parameter.py +2 -1
- classiq/qmod/qmod_struct.py +9 -33
- classiq/qmod/qmod_variable.py +55 -22
- classiq/qmod/quantum_callable.py +6 -1
- classiq/qmod/quantum_expandable.py +29 -11
- classiq/qmod/quantum_function.py +8 -4
- classiq/qmod/semantics/annotation.py +38 -0
- classiq/qmod/semantics/error_manager.py +49 -0
- classiq/qmod/semantics/static_semantics_visitor.py +308 -0
- classiq/qmod/semantics/validation/func_call_validation.py +149 -0
- classiq/qmod/semantics/validation/types_validation.py +21 -0
- classiq/qmod/symbolic.py +6 -6
- classiq/qmod/symbolic_expr.py +26 -11
- classiq/qmod/utilities.py +23 -1
- {classiq-0.42.2.dist-info → classiq-0.43.1.dist-info}/METADATA +2 -2
- {classiq-0.42.2.dist-info → classiq-0.43.1.dist-info}/RECORD +88 -103
- classiq/_internals/_qfunc_ext.py +0 -6
- classiq/applications/libraries/ampltitude_estimation_library.py +0 -11
- classiq/interface/generator/credit_risk_example/linear_gci.py +0 -122
- classiq/interface/generator/credit_risk_example/weighted_adder.py +0 -69
- classiq/interface/generator/expressions/enums/chemistry.py +0 -28
- classiq/interface/generator/expressions/enums/classical_enum.py +0 -20
- classiq/interface/generator/expressions/enums/ladder_operator.py +0 -6
- classiq/interface/generator/expressions/enums/optimizers.py +0 -9
- classiq/interface/generator/expressions/enums/pauli.py +0 -8
- classiq/interface/generator/expressions/enums/qsvm_feature_map_entanglement.py +0 -9
- classiq/interface/generator/functions/foreign_function_definition.py +0 -114
- classiq/interface/generator/functions/function_implementation.py +0 -107
- classiq/interface/generator/functions/native_function_definition.py +0 -155
- classiq/interface/generator/functions/quantum_function_declaration.py +0 -69
- classiq/interface/generator/functions/register.py +0 -44
- classiq/interface/generator/functions/register_mapping_data.py +0 -106
- classiq/interface/generator/inequality_mixer.py +0 -51
- classiq/interface/generator/model/classical_main_validator.py +0 -106
- classiq/interface/generator/range_mixer.py +0 -56
- classiq/interface/generator/state_propagator.py +0 -74
- classiq/interface/model/resolvers/function_call_resolver.py +0 -64
- classiq/interface/model/validations/__init__.py +0 -0
- classiq/interface/model/validations/handle_validation_base.py +0 -55
- classiq/interface/model/validations/handles_validator.py +0 -153
- classiq/interface/model/validations/port_to_wire_name_generator.py +0 -12
- /classiq/{interface/generator/credit_risk_example → qmod/semantics}/__init__.py +0 -0
- /classiq/{interface/model/resolvers → qmod/semantics/validation}/__init__.py +0 -0
- {classiq-0.42.2.dist-info → classiq-0.43.1.dist-info}/WHEEL +0 -0
@@ -5,10 +5,12 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
5
5
|
from classiq.interface.generator.functions.classical_type import (
|
6
6
|
ClassicalArray,
|
7
7
|
ConcreteClassicalType,
|
8
|
+
TypeName,
|
8
9
|
)
|
9
10
|
from classiq.interface.generator.functions.port_declaration import (
|
10
11
|
PortDeclarationDirection,
|
11
12
|
)
|
13
|
+
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
12
14
|
from classiq.interface.generator.visitor import NodeType, Visitor
|
13
15
|
from classiq.interface.model.bind_operation import BindOperation
|
14
16
|
from classiq.interface.model.classical_if import ClassicalIf
|
@@ -57,8 +59,11 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
57
59
|
)
|
58
60
|
from classiq.interface.model.within_apply_operation import WithinApply
|
59
61
|
|
60
|
-
from classiq import Bool, ClassicalList, Integer,
|
62
|
+
from classiq import Bool, ClassicalList, Integer, Real, StructDeclaration
|
61
63
|
from classiq.qmod.native.expression_to_qmod import transform_expression
|
64
|
+
from classiq.qmod.semantics.static_semantics_visitor import (
|
65
|
+
static_semantics_analysis_pass,
|
66
|
+
)
|
62
67
|
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
63
68
|
|
64
69
|
|
@@ -76,6 +81,9 @@ class DSLPrettyPrinter(Visitor):
|
|
76
81
|
return res
|
77
82
|
|
78
83
|
def visit_Model(self, model: Model) -> str:
|
84
|
+
# FIXME - CAD-20149: Remove this line once the froggies are removed, and the visit of lambdas can be done without accessing the func_decl property (with rename_params values only).
|
85
|
+
static_semantics_analysis_pass(model)
|
86
|
+
enum_decls = [self.visit(enum_decl) for enum_decl in model.enums]
|
79
87
|
struct_decls = [self.visit(struct_decl) for struct_decl in model.types]
|
80
88
|
func_defs = [self.visit(func_def) for func_def in model.functions]
|
81
89
|
constants = [self.visit(constant) for constant in model.constants]
|
@@ -84,7 +92,9 @@ class DSLPrettyPrinter(Visitor):
|
|
84
92
|
if model.classical_execution_code
|
85
93
|
else ""
|
86
94
|
)
|
87
|
-
return "\n".join(
|
95
|
+
return "\n".join(
|
96
|
+
[*constants, *enum_decls, *struct_decls, *func_defs, classical_code]
|
97
|
+
)
|
88
98
|
|
89
99
|
def visit_Constant(self, constant: Constant) -> str:
|
90
100
|
return f"{self._indent}{self.visit(constant.name)}: {self.visit(constant.const_type)} = {self.visit(constant.value)};\n"
|
@@ -108,6 +118,18 @@ class DSLPrettyPrinter(Visitor):
|
|
108
118
|
) -> str:
|
109
119
|
return f"qfunc {func_decl.name}{self._visit_arg_decls(func_decl)}"
|
110
120
|
|
121
|
+
def visit_EnumDeclaration(self, enum_decl: EnumDeclaration) -> str:
|
122
|
+
return f"enum {enum_decl.name} {{\n{self._visit_members(enum_decl.members)}}}\n"
|
123
|
+
|
124
|
+
def _visit_members(self, members: Dict[str, int]) -> str:
|
125
|
+
self._level += 1
|
126
|
+
members_str = "".join(
|
127
|
+
f"{self._indent}{self.visit(member_name)} = {member_value};\n"
|
128
|
+
for member_name, member_value in members.items()
|
129
|
+
)
|
130
|
+
self._level -= 1
|
131
|
+
return members_str
|
132
|
+
|
111
133
|
def visit_StructDeclaration(self, struct_decl: StructDeclaration) -> str:
|
112
134
|
return f"struct {struct_decl.name} {{\n{self._visit_variables(struct_decl.variables)}}}\n"
|
113
135
|
|
@@ -137,9 +159,10 @@ class DSLPrettyPrinter(Visitor):
|
|
137
159
|
return "qbit"
|
138
160
|
|
139
161
|
def visit_QuantumBitvector(self, qtype: QuantumBitvector) -> str:
|
162
|
+
element_type = self.visit(qtype.element_type)
|
140
163
|
if qtype.length is not None:
|
141
|
-
return f"
|
142
|
-
return "
|
164
|
+
return f"{element_type}[{self.visit(qtype.length)}]"
|
165
|
+
return f"{element_type}[]"
|
143
166
|
|
144
167
|
def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
|
145
168
|
params = ""
|
@@ -170,17 +193,14 @@ class DSLPrettyPrinter(Visitor):
|
|
170
193
|
def visit_Bool(self, ctbool: Bool) -> str:
|
171
194
|
return "bool"
|
172
195
|
|
173
|
-
def visit_Pauli(self, ctbool: Pauli) -> str:
|
174
|
-
return "Pauli"
|
175
|
-
|
176
196
|
def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
|
177
197
|
return f"{self.visit(ctlist.element_type)}[]"
|
178
198
|
|
179
199
|
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
180
200
|
return f"{self.visit(ctarray.element_type)}[{ctarray.size}]"
|
181
201
|
|
182
|
-
def
|
183
|
-
return
|
202
|
+
def visit_TypeName(self, type_: TypeName) -> str:
|
203
|
+
return type_.name
|
184
204
|
|
185
205
|
def visit_VariableDeclarationStatement(
|
186
206
|
self, local_decl: VariableDeclarationStatement
|
@@ -266,9 +286,7 @@ class DSLPrettyPrinter(Visitor):
|
|
266
286
|
return code
|
267
287
|
|
268
288
|
def visit_InplaceBinaryOperation(self, op: InplaceBinaryOperation) -> str:
|
269
|
-
return (
|
270
|
-
f"{self._indent}{op.operation.value}({op.value.name}, {op.target.name});\n"
|
271
|
-
)
|
289
|
+
return f"{self._indent}{op.operation.value}({self.visit(op.value)}, {self.visit(op.target)});\n"
|
272
290
|
|
273
291
|
def _visit_pack_expr(self, vars: List[HandleBinding]) -> str:
|
274
292
|
if len(vars) == 1:
|
@@ -290,7 +308,7 @@ class DSLPrettyPrinter(Visitor):
|
|
290
308
|
if not isinstance(arg_decl, PortDeclaration)
|
291
309
|
)
|
292
310
|
quantum_args = ", ".join(
|
293
|
-
arg_decl.name
|
311
|
+
qlambda.rename_params.get(arg_decl.name, arg_decl.name)
|
294
312
|
for arg_decl in qlambda.func_decl.get_positional_arg_decls()
|
295
313
|
if isinstance(arg_decl, PortDeclaration)
|
296
314
|
)
|
@@ -7,10 +7,12 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
7
7
|
from classiq.interface.generator.functions.classical_type import (
|
8
8
|
ClassicalArray,
|
9
9
|
ConcreteClassicalType,
|
10
|
+
TypeName,
|
10
11
|
)
|
11
12
|
from classiq.interface.generator.functions.port_declaration import (
|
12
13
|
PortDeclarationDirection,
|
13
14
|
)
|
15
|
+
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
14
16
|
from classiq.interface.generator.visitor import NodeType, Visitor
|
15
17
|
from classiq.interface.model.bind_operation import BindOperation
|
16
18
|
from classiq.interface.model.classical_if import ClassicalIf
|
@@ -64,7 +66,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
64
66
|
from classiq.interface.model.within_apply_operation import WithinApply
|
65
67
|
|
66
68
|
import classiq
|
67
|
-
from classiq import Bool, ClassicalList, Integer,
|
69
|
+
from classiq import Bool, ClassicalList, Integer, Real, StructDeclaration
|
68
70
|
from classiq.qmod.pretty_print.expression_to_python import transform_expression
|
69
71
|
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
70
72
|
|
@@ -110,7 +112,10 @@ class PythonPrettyPrinter(Visitor):
|
|
110
112
|
self._level = 0
|
111
113
|
self._decimal_precision = decimal_precision
|
112
114
|
self._imports = {"qfunc": 1}
|
115
|
+
self._import_enum = False
|
116
|
+
self._import_dataclass = False
|
113
117
|
self._symbolic_imports: Dict[str, int] = dict()
|
118
|
+
self._functions: Optional[Dict[str, QuantumFunctionDeclaration]] = None
|
114
119
|
|
115
120
|
def visit(self, node: NodeType) -> str:
|
116
121
|
res = super().visit(node)
|
@@ -119,12 +124,17 @@ class PythonPrettyPrinter(Visitor):
|
|
119
124
|
return res
|
120
125
|
|
121
126
|
def visit_Model(self, model: Model) -> str:
|
127
|
+
self._functions = {
|
128
|
+
**model.function_dict,
|
129
|
+
**QuantumFunctionDeclaration.BUILTIN_FUNCTION_DECLARATIONS,
|
130
|
+
}
|
131
|
+
enum_decls = [self.visit(decl) for decl in model.enums]
|
122
132
|
struct_decls = [self.visit(decl) for decl in model.types]
|
123
133
|
func_defs = [self.visit(func) for func in model.functions]
|
124
134
|
constants = [self.visit(const) for const in model.constants]
|
125
135
|
classical_code = self.format_classical_code(model.classical_execution_code)
|
126
136
|
|
127
|
-
code = f"{self.format_imports()}\n\n{self.join_code_parts(*constants, *struct_decls, *func_defs, classical_code)}"
|
137
|
+
code = f"{self.format_imports()}\n\n{self.join_code_parts(*constants, *enum_decls, *struct_decls, *func_defs, classical_code)}"
|
128
138
|
return black.format_str(code, mode=black.FileMode())
|
129
139
|
|
130
140
|
def format_classical_code(self, code: str) -> str:
|
@@ -147,7 +157,16 @@ class PythonPrettyPrinter(Visitor):
|
|
147
157
|
if self._symbolic_imports
|
148
158
|
else ""
|
149
159
|
)
|
150
|
-
return imports + symbolic_imports
|
160
|
+
return self.special_imports + imports + symbolic_imports
|
161
|
+
|
162
|
+
@property
|
163
|
+
def special_imports(self) -> str:
|
164
|
+
imports = ""
|
165
|
+
if self._import_dataclass:
|
166
|
+
imports += "from dataclasses import dataclass\n"
|
167
|
+
if self._import_enum:
|
168
|
+
imports += "from enum import IntEnum\n"
|
169
|
+
return imports
|
151
170
|
|
152
171
|
def join_code_parts(self, *code_parts: str) -> str:
|
153
172
|
return "\n".join(code_parts)
|
@@ -169,9 +188,22 @@ class PythonPrettyPrinter(Visitor):
|
|
169
188
|
f"@qfunc\ndef {func_decl.name}({self._visit_arg_decls(func_decl)}) -> None:"
|
170
189
|
)
|
171
190
|
|
191
|
+
def visit_EnumDeclaration(self, enum_decl: EnumDeclaration) -> str:
|
192
|
+
self._import_enum = True
|
193
|
+
return f"class {enum_decl.name}(IntEnum):\n{self._visit_members(enum_decl.members)}\n"
|
194
|
+
|
195
|
+
def _visit_members(self, members: Dict[str, int]) -> str:
|
196
|
+
self._level += 1
|
197
|
+
members_str = "".join(
|
198
|
+
f"{self._indent}{self.visit(member_name)} = {member_value}\n"
|
199
|
+
for member_name, member_value in members.items()
|
200
|
+
)
|
201
|
+
self._level -= 1
|
202
|
+
return members_str
|
203
|
+
|
172
204
|
def visit_StructDeclaration(self, struct_decl: StructDeclaration) -> str:
|
173
|
-
self.
|
174
|
-
return f"@
|
205
|
+
self._import_dataclass = True
|
206
|
+
return f"@dataclass\nclass {struct_decl.name}:\n{self._visit_variables(struct_decl.variables)}\n"
|
175
207
|
|
176
208
|
def _visit_variables(self, variables: Dict[str, ConcreteClassicalType]) -> str:
|
177
209
|
self._level += 1
|
@@ -205,9 +237,10 @@ class PythonPrettyPrinter(Visitor):
|
|
205
237
|
|
206
238
|
def visit_QuantumBitvector(self, qtype: QuantumBitvector) -> str:
|
207
239
|
self._imports.update({"QArray": 1, "QBit": 1})
|
240
|
+
element_type = self.visit(qtype.element_type)
|
208
241
|
if qtype.length is not None:
|
209
|
-
return f"QArray[
|
210
|
-
return "QArray[
|
242
|
+
return f"QArray[{element_type}, {_add_quotes(self.visit(qtype.length))}]"
|
243
|
+
return f"QArray[{element_type}]"
|
211
244
|
|
212
245
|
def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
|
213
246
|
params = ""
|
@@ -242,10 +275,6 @@ class PythonPrettyPrinter(Visitor):
|
|
242
275
|
self._imports["CBool"] = 1
|
243
276
|
return "CBool"
|
244
277
|
|
245
|
-
def visit_Pauli(self, ctbool: Pauli) -> str:
|
246
|
-
self._imports["Pauli"] = 1
|
247
|
-
return "Pauli"
|
248
|
-
|
249
278
|
def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
|
250
279
|
self._imports["CArray"] = 1
|
251
280
|
return f"CArray[{self.visit(ctlist.element_type)}]"
|
@@ -254,10 +283,12 @@ class PythonPrettyPrinter(Visitor):
|
|
254
283
|
self._imports["CArray"] = 1
|
255
284
|
return f"CArray[{self.visit(ctarray.element_type)}, {ctarray.size}]"
|
256
285
|
|
257
|
-
def
|
258
|
-
if
|
259
|
-
|
260
|
-
|
286
|
+
def visit_TypeName(self, type_: TypeName) -> str:
|
287
|
+
if type_.name in dir(classiq.qmod.builtins.enums) + dir(
|
288
|
+
classiq.qmod.builtins.structs
|
289
|
+
):
|
290
|
+
self._imports[type_.name] = 1
|
291
|
+
return type_.name
|
261
292
|
|
262
293
|
def visit_VariableDeclarationStatement(
|
263
294
|
self, local_decl: VariableDeclarationStatement
|
@@ -299,13 +330,14 @@ class PythonPrettyPrinter(Visitor):
|
|
299
330
|
return f"{self.visit_QuantumFunctionDeclaration(func_def)} \n{body}\n"
|
300
331
|
|
301
332
|
def visit_QuantumFunctionCall(self, func_call: QuantumFunctionCall) -> str:
|
302
|
-
if len(func_call.get_positional_args()) <= 2:
|
333
|
+
if len(func_call.get_positional_args()) <= 2 or self._functions is None:
|
303
334
|
args = ", ".join(self.visit(arg) for arg in func_call.get_positional_args())
|
304
335
|
else:
|
336
|
+
func_decl = self._functions[func_call.func_name]
|
305
337
|
args = ", ".join(
|
306
338
|
f"{self.visit(arg_decl.name)}={self.visit(arg)}"
|
307
339
|
for arg_decl, arg in zip(
|
308
|
-
|
340
|
+
func_decl.get_positional_arg_decls(),
|
309
341
|
func_call.get_positional_args(),
|
310
342
|
)
|
311
343
|
)
|
@@ -343,9 +375,7 @@ class PythonPrettyPrinter(Visitor):
|
|
343
375
|
if len(body) == 0:
|
344
376
|
return "None"
|
345
377
|
argument_string = (
|
346
|
-
(" " + ", ".join(operand_arguments))
|
347
|
-
if operand_arguments is not None
|
348
|
-
else ""
|
378
|
+
(" " + ", ".join(operand_arguments)) if operand_arguments else ""
|
349
379
|
)
|
350
380
|
code = f"lambda{argument_string}: {'[' if len(body) > 1 else ''}\n"
|
351
381
|
self._level += 1
|
@@ -364,9 +394,7 @@ class PythonPrettyPrinter(Visitor):
|
|
364
394
|
|
365
395
|
def visit_InplaceBinaryOperation(self, op: InplaceBinaryOperation) -> str:
|
366
396
|
self._imports[op.operation.value] = 1
|
367
|
-
return (
|
368
|
-
f"{self._indent}{op.operation.value}({op.value.name}, {op.target.name})\n"
|
369
|
-
)
|
397
|
+
return f"{self._indent}{op.operation.value}({self.visit(op.value)}, {self.visit(op.target)})\n"
|
370
398
|
|
371
399
|
def visit_Expression(self, expr: Expression) -> str:
|
372
400
|
return transform_expression(
|
@@ -381,10 +409,7 @@ class PythonPrettyPrinter(Visitor):
|
|
381
409
|
assert qlambda.func_decl is not None
|
382
410
|
return self._visit_body(
|
383
411
|
qlambda.body,
|
384
|
-
|
385
|
-
self.visit(arg_decl.name)
|
386
|
-
for arg_decl in qlambda.func_decl.get_positional_arg_decls()
|
387
|
-
],
|
412
|
+
list(qlambda.rename_params.values()),
|
388
413
|
)
|
389
414
|
|
390
415
|
def visit_HandleBinding(self, var_ref: HandleBinding) -> str:
|
classiq/qmod/qmod_constant.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import inspect
|
2
|
+
from dataclasses import is_dataclass
|
2
3
|
from typing import Any, Optional
|
3
4
|
|
4
5
|
from classiq.interface.generator.constant import Constant
|
@@ -6,7 +7,6 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
6
7
|
from classiq.interface.generator.functions.classical_type import (
|
7
8
|
ClassicalArray,
|
8
9
|
ClassicalList,
|
9
|
-
CStructBase,
|
10
10
|
)
|
11
11
|
|
12
12
|
from classiq.exceptions import ClassiqError
|
@@ -14,6 +14,7 @@ from classiq.qmod.declaration_inferrer import python_type_to_qmod
|
|
14
14
|
from classiq.qmod.model_state_container import ModelStateContainer
|
15
15
|
from classiq.qmod.qmod_parameter import CParam, CParamList, CParamStruct
|
16
16
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
17
|
+
from classiq.qmod.utilities import qmod_val_to_expr_str
|
17
18
|
|
18
19
|
|
19
20
|
class QConstant(SymbolicExpr):
|
@@ -34,7 +35,7 @@ class QConstant(SymbolicExpr):
|
|
34
35
|
"Error trying to add a constant to a model without a current QModule."
|
35
36
|
)
|
36
37
|
|
37
|
-
expr =
|
38
|
+
expr = qmod_val_to_expr_str(self._value)
|
38
39
|
if (
|
39
40
|
self.name in QConstant.CURRENT_QMODULE.constants
|
40
41
|
and expr != QConstant.CURRENT_QMODULE.constants[self.name].value.expr
|
@@ -65,11 +66,14 @@ class QConstant(SymbolicExpr):
|
|
65
66
|
def __getattr__(self, name: str) -> CParam:
|
66
67
|
self.add_to_model()
|
67
68
|
|
69
|
+
if name == "is_quantum":
|
70
|
+
return False # type:ignore[return-value]
|
71
|
+
|
68
72
|
py_type = type(self._value)
|
69
73
|
if (
|
70
74
|
QConstant.CURRENT_QMODULE is None
|
71
75
|
or not inspect.isclass(py_type)
|
72
|
-
or not
|
76
|
+
or not is_dataclass(py_type)
|
73
77
|
):
|
74
78
|
return self.__getattribute__(name)
|
75
79
|
|
classiq/qmod/qmod_parameter.py
CHANGED
classiq/qmod/qmod_struct.py
CHANGED
@@ -1,37 +1,13 @@
|
|
1
|
-
import
|
2
|
-
from
|
1
|
+
import warnings
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Type
|
3
4
|
|
4
|
-
from typing_extensions import dataclass_transform
|
5
5
|
|
6
|
-
from classiq.interface.generator.functions.classical_type import CStructBase
|
7
|
-
|
8
|
-
|
9
|
-
def _qmod_val_to_expr_str(val: Any) -> str:
|
10
|
-
if dataclasses.is_dataclass(type(val)):
|
11
|
-
kwargs_str = ", ".join(
|
12
|
-
[
|
13
|
-
f"{field.name}={_qmod_val_to_expr_str(vars(val)[field.name])}"
|
14
|
-
for field in dataclasses.fields(val)
|
15
|
-
]
|
16
|
-
)
|
17
|
-
return f"struct_literal({type(val).__name__}, {kwargs_str})"
|
18
|
-
|
19
|
-
if isinstance(val, list):
|
20
|
-
elements_str = ", ".join([_qmod_val_to_expr_str(elem) for elem in val])
|
21
|
-
return f"[{elements_str}]"
|
22
|
-
|
23
|
-
return str(val)
|
24
|
-
|
25
|
-
|
26
|
-
@dataclass_transform()
|
27
6
|
def struct(user_class: Type) -> Type:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
(CStructBase, dataclasses.dataclass(user_class)),
|
34
|
-
dict(),
|
7
|
+
warnings.warn(
|
8
|
+
"@struct is deprecated and will be removed in a future release. "
|
9
|
+
"Use @dataclass instead.",
|
10
|
+
DeprecationWarning,
|
11
|
+
stacklevel=2,
|
35
12
|
)
|
36
|
-
|
37
|
-
return user_dataclass
|
13
|
+
return dataclass(user_class)
|
classiq/qmod/qmod_variable.py
CHANGED
@@ -54,7 +54,7 @@ from classiq.qmod.utilities import get_source_ref, version_portable_get_args
|
|
54
54
|
|
55
55
|
ILLEGAL_SLICING_STEP_MSG = "Slicing with a step of a quantum variable is not supported"
|
56
56
|
SLICE_OUT_OF_BOUNDS_MSG = "Slice end index out of bounds"
|
57
|
-
UNSUPPORTED_ELEMENT_TYPE = "Only QBit
|
57
|
+
UNSUPPORTED_ELEMENT_TYPE = "Only QBit and QNum are supported as element type for QArray"
|
58
58
|
QARRAY_ELEMENT_NOT_SUBSCRIPTABLE = "Subscripting an element in QArray is illegal"
|
59
59
|
|
60
60
|
|
@@ -84,12 +84,13 @@ def _no_current_expandable() -> Iterator[None]:
|
|
84
84
|
|
85
85
|
|
86
86
|
class QVar(Symbolic):
|
87
|
-
def __init__(self, name: str) -> None:
|
88
|
-
super().__init__(name)
|
87
|
+
def __init__(self, name: str, depth: int = 2) -> None:
|
88
|
+
super().__init__(name, True)
|
89
89
|
self._name = name
|
90
|
+
source_ref = get_source_ref(sys._getframe(depth))
|
90
91
|
if QCallable.CURRENT_EXPANDABLE is not None:
|
91
92
|
QCallable.CURRENT_EXPANDABLE.add_local_handle(
|
92
|
-
self._name, self.get_qmod_type()
|
93
|
+
self._name, self.get_qmod_type(), source_ref
|
93
94
|
)
|
94
95
|
|
95
96
|
@abc.abstractmethod
|
@@ -132,9 +133,9 @@ Input = Annotated[_Q, PortDeclarationDirection.Input]
|
|
132
133
|
|
133
134
|
|
134
135
|
class QScalar(QVar, SymbolicExpr):
|
135
|
-
def __init__(self, name: str) -> None:
|
136
|
-
QVar.__init__(self, name)
|
137
|
-
SymbolicExpr.__init__(self, name)
|
136
|
+
def __init__(self, name: str, depth: int = 2) -> None:
|
137
|
+
QVar.__init__(self, name, depth)
|
138
|
+
SymbolicExpr.__init__(self, name, True)
|
138
139
|
|
139
140
|
def _insert_arith_operation(
|
140
141
|
self, expr: SymbolicTypes, inplace: bool, source_ref: SourceReference
|
@@ -245,7 +246,7 @@ class QNum(Generic[_P], QScalar):
|
|
245
246
|
self._fraction_digits = (
|
246
247
|
None if fraction_digits is None else Expression(expr=str(fraction_digits))
|
247
248
|
)
|
248
|
-
super().__init__(name)
|
249
|
+
super().__init__(name, 3)
|
249
250
|
|
250
251
|
@classmethod
|
251
252
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
@@ -300,7 +301,7 @@ class QArray(ArrayBase[_P], QVar):
|
|
300
301
|
slice_: Optional[Tuple[int, int]] = None,
|
301
302
|
index_: Optional[Union[int, CInt]] = None,
|
302
303
|
) -> None:
|
303
|
-
if element_type
|
304
|
+
if not issubclass(get_origin(element_type) or element_type, (QBit, QNum)):
|
304
305
|
raise ClassiqValueError(UNSUPPORTED_ELEMENT_TYPE)
|
305
306
|
self._element_type = element_type
|
306
307
|
self._length = length
|
@@ -324,7 +325,7 @@ class QArray(ArrayBase[_P], QVar):
|
|
324
325
|
|
325
326
|
return HandleBinding(name=self._name)
|
326
327
|
|
327
|
-
def __getitem__(self, key: Union[slice, int, CInt]) ->
|
328
|
+
def __getitem__(self, key: Union[slice, int, CInt]) -> Any:
|
328
329
|
if self._index is not None:
|
329
330
|
raise ClassiqValueError(QARRAY_ELEMENT_NOT_SUBSCRIPTABLE)
|
330
331
|
|
@@ -356,7 +357,11 @@ class QArray(ArrayBase[_P], QVar):
|
|
356
357
|
raise ClassiqValueError(SLICE_OUT_OF_BOUNDS_MSG)
|
357
358
|
# prevent addition to local handles, since this is used for slicing existing local handles
|
358
359
|
with _no_current_expandable():
|
359
|
-
|
360
|
+
if new_index is None:
|
361
|
+
array_class = QArray
|
362
|
+
else:
|
363
|
+
array_class = QArraySubscript
|
364
|
+
return array_class(
|
360
365
|
self._name, length=self._length, slice_=new_slice, index_=new_index
|
361
366
|
)
|
362
367
|
|
@@ -386,27 +391,55 @@ class QArray(ArrayBase[_P], QVar):
|
|
386
391
|
|
387
392
|
@classmethod
|
388
393
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
394
|
+
type_args = version_portable_get_args(type_hint)
|
395
|
+
if len(type_args) == 1 and isinstance(type_args[0], (str, int)):
|
396
|
+
type_args = (QBit, type_args[0])
|
397
|
+
|
398
|
+
api_element_type = QBit if len(type_args) == 0 else type_args[0]
|
399
|
+
api_element_class = get_origin(api_element_type) or api_element_type
|
400
|
+
element_type = api_element_class.to_qmod_quantum_type(api_element_type)
|
401
|
+
|
389
402
|
length_expr: Optional[Expression] = None
|
390
|
-
if len(
|
391
|
-
length_expr = Expression(
|
392
|
-
|
393
|
-
|
394
|
-
return QuantumBitvector(length=length_expr)
|
403
|
+
if len(type_args) == 2:
|
404
|
+
length_expr = Expression(expr=get_type_hint_expr(type_args[1]))
|
405
|
+
|
406
|
+
return QuantumBitvector(element_type=element_type, length=length_expr)
|
395
407
|
|
396
408
|
def get_qmod_type(self) -> QuantumType:
|
409
|
+
element_class = get_origin(self._element_type) or self._element_type
|
410
|
+
length = None
|
397
411
|
if self._length is not None:
|
398
|
-
|
399
|
-
return QuantumBitvector(
|
412
|
+
length = Expression(expr=str(self._length))
|
413
|
+
return QuantumBitvector(
|
414
|
+
element_type=element_class.to_qmod_quantum_type(self._element_type),
|
415
|
+
length=length,
|
416
|
+
)
|
417
|
+
|
418
|
+
|
419
|
+
class QArraySubscript(QArray, QScalar):
|
420
|
+
@property
|
421
|
+
def size(self) -> CParamScalar:
|
422
|
+
return CParamScalar(f"get_field({self.get_handle_binding()}, 'size')")
|
423
|
+
|
424
|
+
@property
|
425
|
+
def fraction_digits(self) -> CParamScalar:
|
426
|
+
return CParamScalar(
|
427
|
+
f"get_field({self.get_handle_binding()}, 'fraction_digits')"
|
428
|
+
)
|
429
|
+
|
430
|
+
@property
|
431
|
+
def is_signed(self) -> CParamScalar:
|
432
|
+
return CParamScalar(f"get_field({self.get_handle_binding()}, 'is_signed')")
|
400
433
|
|
401
434
|
|
402
|
-
def create_qvar_for_port_decl(port: PortDeclaration) -> QVar:
|
435
|
+
def create_qvar_for_port_decl(port: PortDeclaration, name: str) -> QVar:
|
403
436
|
# prevent addition to local handles, since this is used for ports
|
404
437
|
with _no_current_expandable():
|
405
438
|
if _is_single_qbit_vector(port):
|
406
|
-
return QBit(
|
439
|
+
return QBit(name)
|
407
440
|
elif isinstance(port.quantum_type, QuantumNumeric):
|
408
|
-
return QNum(
|
409
|
-
return QArray(
|
441
|
+
return QNum(name)
|
442
|
+
return QArray(name)
|
410
443
|
|
411
444
|
|
412
445
|
def _is_single_qbit_vector(port: PortDeclaration) -> bool:
|
classiq/qmod/quantum_callable.py
CHANGED
@@ -35,7 +35,12 @@ class QExpandableInterface(ABC):
|
|
35
35
|
raise NotImplementedError()
|
36
36
|
|
37
37
|
@abstractmethod
|
38
|
-
def add_local_handle(
|
38
|
+
def add_local_handle(
|
39
|
+
self,
|
40
|
+
name: str,
|
41
|
+
qtype: QuantumType,
|
42
|
+
source_ref: Optional[SourceReference] = None,
|
43
|
+
) -> None:
|
39
44
|
raise NotImplementedError()
|
40
45
|
|
41
46
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import inspect
|
2
2
|
from abc import ABC
|
3
|
+
from dataclasses import is_dataclass
|
4
|
+
from enum import Enum as PythonEnum
|
3
5
|
from types import TracebackType
|
4
6
|
from typing import (
|
5
7
|
TYPE_CHECKING,
|
@@ -51,7 +53,7 @@ from classiq.qmod.qmod_parameter import CInt, CParam, CParamScalar, create_param
|
|
51
53
|
from classiq.qmod.qmod_variable import QVar, create_qvar_for_port_decl
|
52
54
|
from classiq.qmod.quantum_callable import QCallable, QExpandableInterface
|
53
55
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
54
|
-
from classiq.qmod.utilities import mangle_keyword
|
56
|
+
from classiq.qmod.utilities import mangle_keyword, qmod_val_to_expr_str
|
55
57
|
|
56
58
|
ArgType = Union[CParam, QVar, QCallable]
|
57
59
|
|
@@ -93,8 +95,17 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
93
95
|
def infer_rename_params(self) -> Dict[str, str]:
|
94
96
|
return {}
|
95
97
|
|
96
|
-
def add_local_handle(
|
97
|
-
self
|
98
|
+
def add_local_handle(
|
99
|
+
self,
|
100
|
+
name: str,
|
101
|
+
qtype: QuantumType,
|
102
|
+
source_ref: Optional[SourceReference] = None,
|
103
|
+
) -> None:
|
104
|
+
self._body.append(
|
105
|
+
VariableDeclarationStatement(
|
106
|
+
name=name, quantum_type=qtype, source_ref=source_ref
|
107
|
+
)
|
108
|
+
)
|
98
109
|
|
99
110
|
def append_statement_to_body(self, stmt: QuantumStatement) -> None:
|
100
111
|
self._body.append(stmt)
|
@@ -102,14 +113,14 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
102
113
|
def _get_positional_args(self) -> List[ArgType]:
|
103
114
|
result: List[ArgType] = []
|
104
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)
|
105
118
|
if isinstance(arg, ClassicalParameterDeclaration):
|
106
|
-
rename_dict = self.infer_rename_params()
|
107
|
-
actual_name = rename_dict.get(arg.name, arg.name)
|
108
119
|
result.append(
|
109
120
|
create_param(actual_name, arg.classical_type, self._qmodule)
|
110
121
|
)
|
111
122
|
elif isinstance(arg, PortDeclaration):
|
112
|
-
result.append(create_qvar_for_port_decl(arg))
|
123
|
+
result.append(create_qvar_for_port_decl(arg, actual_name))
|
113
124
|
else:
|
114
125
|
assert isinstance(arg, QuantumOperandDeclaration)
|
115
126
|
result.append(QTerminalCallable(arg))
|
@@ -135,11 +146,11 @@ class QLambdaFunction(QExpandable):
|
|
135
146
|
|
136
147
|
def infer_rename_params(self) -> Dict[str, str]:
|
137
148
|
py_params = inspect.getfullargspec(self._py_callable)
|
138
|
-
decl_params = self.func_decl.
|
149
|
+
decl_params = self.func_decl.get_positional_arg_decls()
|
139
150
|
return {
|
140
|
-
decl_param: py_param
|
151
|
+
decl_param.name: py_param
|
141
152
|
for decl_param, py_param in zip(decl_params, py_params.args)
|
142
|
-
if decl_param != py_param
|
153
|
+
if decl_param.name != py_param
|
143
154
|
}
|
144
155
|
|
145
156
|
|
@@ -215,7 +226,7 @@ def prepare_arg(arg_decl: PositionalArg, val: Any, func_name: str) -> ArgValue:
|
|
215
226
|
return Expression(expr=str(val.name))
|
216
227
|
if isinstance(arg_decl, ClassicalParameterDeclaration):
|
217
228
|
_validate_classical_arg(val, arg_decl, func_name)
|
218
|
-
return Expression(expr=
|
229
|
+
return Expression(expr=qmod_val_to_expr_str(val))
|
219
230
|
elif isinstance(arg_decl, PortDeclaration):
|
220
231
|
if not isinstance(val, QVar):
|
221
232
|
raise ClassiqValueError(
|
@@ -249,7 +260,14 @@ def prepare_arg(arg_decl: PositionalArg, val: Any, func_name: str) -> ArgValue:
|
|
249
260
|
def _validate_classical_arg(
|
250
261
|
arg: Any, arg_decl: ClassicalParameterDeclaration, func_name: str
|
251
262
|
) -> None:
|
252
|
-
if
|
263
|
+
if (
|
264
|
+
not isinstance(
|
265
|
+
arg, (*PythonClassicalTypes, CParam, SymbolicExpr, Basic, PythonEnum)
|
266
|
+
)
|
267
|
+
and not is_dataclass(arg) # type:ignore[unreachable]
|
268
|
+
or isinstance(arg, SymbolicExpr)
|
269
|
+
and arg.is_quantum
|
270
|
+
):
|
253
271
|
raise ClassiqValueError(
|
254
272
|
f"Argument {str(arg)!r} to parameter {arg_decl.name!r} of function "
|
255
273
|
f"{func_name!r} has incompatible type; expected "
|