classiq 0.56.1__py3-none-any.whl → 0.58.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.
- classiq/analyzer/show_interactive_hack.py +16 -4
- classiq/applications/combinatorial_helpers/encoding_utils.py +1 -0
- classiq/applications/combinatorial_helpers/transformations/encoding.py +3 -1
- classiq/execution/jobs.py +8 -1
- classiq/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +27 -5
- classiq/interface/backend/pydantic_backend.py +0 -1
- classiq/interface/execution/jobs.py +4 -1
- classiq/interface/executor/execution_request.py +19 -5
- classiq/interface/generator/arith/arithmetic_expression_validator.py +28 -9
- classiq/interface/generator/functions/type_name.py +7 -9
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/model_expansions/closure.py +24 -6
- classiq/model_expansions/evaluators/parameter_types.py +1 -2
- classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
- classiq/model_expansions/function_builder.py +13 -0
- classiq/model_expansions/interpreter.py +9 -14
- classiq/model_expansions/quantum_operations/call_emitter.py +207 -0
- classiq/model_expansions/quantum_operations/classicalif.py +2 -2
- classiq/model_expansions/quantum_operations/control.py +7 -5
- classiq/model_expansions/quantum_operations/emitter.py +1 -186
- classiq/model_expansions/quantum_operations/expression_operation.py +26 -189
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +2 -2
- classiq/model_expansions/quantum_operations/invert.py +2 -2
- classiq/model_expansions/quantum_operations/phase.py +3 -1
- classiq/model_expansions/quantum_operations/power.py +2 -2
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -9
- classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -2
- classiq/model_expansions/quantum_operations/repeat.py +2 -2
- classiq/model_expansions/transformers/__init__.py +0 -0
- classiq/model_expansions/transformers/var_splitter.py +237 -0
- classiq/qmod/builtins/classical_functions.py +1 -0
- classiq/qmod/builtins/functions/state_preparation.py +1 -1
- classiq/qmod/create_model_function.py +25 -20
- classiq/qmod/native/pretty_printer.py +19 -4
- classiq/qmod/pretty_print/pretty_printer.py +53 -28
- classiq/qmod/qfunc.py +18 -16
- classiq/qmod/quantum_function.py +30 -24
- classiq/qmod/semantics/qstruct_annotator.py +23 -0
- classiq/qmod/semantics/static_semantics_visitor.py +4 -1
- classiq/qmod/write_qmod.py +3 -1
- classiq/synthesis.py +3 -1
- {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/METADATA +1 -1
- {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/RECORD +46 -42
- {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/WHEEL +0 -0
@@ -71,7 +71,6 @@ def create_model(
|
|
71
71
|
constraints,
|
72
72
|
execution_preferences,
|
73
73
|
preferences,
|
74
|
-
classical_execution_function,
|
75
74
|
)
|
76
75
|
else:
|
77
76
|
if TYPE_CHECKING:
|
@@ -95,26 +94,21 @@ def _expand_generative_model(
|
|
95
94
|
constraints: Optional[Constraints] = None,
|
96
95
|
execution_preferences: Optional[ExecutionPreferences] = None,
|
97
96
|
preferences: Optional[Preferences] = None,
|
98
|
-
classical_execution_function: Optional[CFunc] = None,
|
99
97
|
) -> Model:
|
100
98
|
@QFunc
|
101
99
|
def _dummy() -> None:
|
102
100
|
pass
|
103
101
|
|
104
|
-
functions_compilation_metadata = {
|
105
|
-
dec_func._py_callable.__name__: dec_func.compilation_metadata
|
106
|
-
for dec_func in DEC_QFUNCS
|
107
|
-
if dec_func.compilation_metadata is not None
|
108
|
-
}
|
109
102
|
model = _dummy.create_model(
|
110
103
|
constraints,
|
111
104
|
execution_preferences,
|
112
105
|
preferences,
|
113
|
-
classical_execution_function,
|
114
|
-
functions_compilation_metadata,
|
115
106
|
)
|
116
|
-
|
117
|
-
model.functions =
|
107
|
+
gen_expand_model = _get_generative_functions(gen_main, preferences)
|
108
|
+
model.functions = gen_expand_model.functions
|
109
|
+
model.functions_compilation_metadata = (
|
110
|
+
gen_expand_model.functions_compilation_metadata
|
111
|
+
)
|
118
112
|
model.types = list(QMODULE.type_decls.values())
|
119
113
|
model.enums = list(QMODULE.enum_decls.values())
|
120
114
|
model.qstructs = list(QMODULE.qstruct_decls.values())
|
@@ -122,8 +116,9 @@ def _expand_generative_model(
|
|
122
116
|
|
123
117
|
|
124
118
|
def _get_generative_functions(
|
125
|
-
gen_main: QFunc,
|
126
|
-
|
119
|
+
gen_main: QFunc,
|
120
|
+
preferences: Optional[Preferences],
|
121
|
+
) -> Model:
|
127
122
|
# The Interpreter accepts a model and a list of generative functions.
|
128
123
|
# Since the main function is generative, it can only be expanded using the
|
129
124
|
# Interpreter.
|
@@ -132,14 +127,21 @@ def _get_generative_functions(
|
|
132
127
|
# passing them to the Interpreter.
|
133
128
|
gen_model = _get_wrapper_main(gen_main, preferences)
|
134
129
|
gen_functions = _get_all_model_functions_as_generative_functions()
|
135
|
-
|
136
|
-
return list(functions_dict.values())
|
130
|
+
return _interpret_generative_model(gen_model, gen_functions)
|
137
131
|
|
138
132
|
|
139
|
-
def _get_wrapper_main(
|
133
|
+
def _get_wrapper_main(
|
134
|
+
gen_main: QFunc,
|
135
|
+
preferences: Optional[Preferences],
|
136
|
+
) -> Model:
|
140
137
|
extra_args = {}
|
141
138
|
if preferences is not None:
|
142
139
|
extra_args["preferences"] = preferences
|
140
|
+
functions_compilation_metadata = {
|
141
|
+
qfunc._py_callable.__name__: qfunc.compilation_metadata
|
142
|
+
for qfunc in DEC_QFUNCS + GEN_QFUNCS
|
143
|
+
if qfunc.compilation_metadata is not None
|
144
|
+
}
|
143
145
|
return Model(
|
144
146
|
functions=[
|
145
147
|
NativeFunctionDefinition(
|
@@ -157,6 +159,7 @@ def _get_wrapper_main(gen_main: QFunc, preferences: Optional[Preferences]) -> Mo
|
|
157
159
|
],
|
158
160
|
),
|
159
161
|
],
|
162
|
+
functions_compilation_metadata=functions_compilation_metadata,
|
160
163
|
**extra_args,
|
161
164
|
)
|
162
165
|
|
@@ -164,7 +167,9 @@ def _get_wrapper_main(gen_main: QFunc, preferences: Optional[Preferences]) -> Mo
|
|
164
167
|
def _get_all_model_functions_as_generative_functions() -> list[GenerativeQFunc]:
|
165
168
|
|
166
169
|
gen_functions = list(GEN_QFUNCS) + [
|
167
|
-
GenerativeQFunc(
|
170
|
+
GenerativeQFunc(
|
171
|
+
dec_func._py_callable, dec_func.func_decl, dec_func.compilation_metadata
|
172
|
+
)
|
168
173
|
for dec_func in DEC_QFUNCS
|
169
174
|
]
|
170
175
|
return [
|
@@ -174,6 +179,7 @@ def _get_all_model_functions_as_generative_functions() -> list[GenerativeQFunc]:
|
|
174
179
|
else GenerativeQFunc(
|
175
180
|
gen_func._py_callable,
|
176
181
|
gen_func.func_decl.model_copy(update={"name": GEN_MAIN_NAME}),
|
182
|
+
gen_func.compilation_metadata,
|
177
183
|
)
|
178
184
|
)
|
179
185
|
for gen_func in gen_functions
|
@@ -183,7 +189,7 @@ def _get_all_model_functions_as_generative_functions() -> list[GenerativeQFunc]:
|
|
183
189
|
|
184
190
|
def _interpret_generative_model(
|
185
191
|
gen_model: Model, gen_functions: list[GenerativeQFunc]
|
186
|
-
) ->
|
192
|
+
) -> Model:
|
187
193
|
resolve_function_calls(
|
188
194
|
gen_model,
|
189
195
|
{gen_func.func_decl.name: gen_func.func_decl for gen_func in gen_functions},
|
@@ -201,5 +207,4 @@ def _interpret_generative_model(
|
|
201
207
|
expanded_gen_main_name
|
202
208
|
].model_copy(update={"name": MAIN_FUNCTION_NAME})
|
203
209
|
functions_dict.pop(expanded_gen_main_name)
|
204
|
-
|
205
|
-
return functions_dict
|
210
|
+
return expand_model.model_copy(update={"functions": list(functions_dict.values())})
|
@@ -83,10 +83,13 @@ from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
|
83
83
|
|
84
84
|
class DSLPrettyPrinter(Visitor):
|
85
85
|
def __init__(
|
86
|
-
self,
|
86
|
+
self,
|
87
|
+
decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION,
|
88
|
+
rename_phase: bool = False,
|
87
89
|
) -> None:
|
88
90
|
self._level = 0
|
89
91
|
self._decimal_precision = decimal_precision
|
92
|
+
self._rename_phase = rename_phase
|
90
93
|
|
91
94
|
def visit(self, node: NodeType) -> str:
|
92
95
|
res = super().visit(node)
|
@@ -165,7 +168,10 @@ class DSLPrettyPrinter(Visitor):
|
|
165
168
|
def visit_QuantumVariableDeclaration(
|
166
169
|
self, var_decl: QuantumVariableDeclaration
|
167
170
|
) -> str:
|
168
|
-
|
171
|
+
var_name = var_decl.name
|
172
|
+
if self._rename_phase and var_name == "phase":
|
173
|
+
var_name = "phase_var"
|
174
|
+
return f"{var_name}: {self.visit(var_decl.quantum_type)}"
|
169
175
|
|
170
176
|
def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
|
171
177
|
dir_str = (
|
@@ -173,7 +179,12 @@ class DSLPrettyPrinter(Visitor):
|
|
173
179
|
if port_decl.direction != PortDeclarationDirection.Inout
|
174
180
|
else ""
|
175
181
|
)
|
176
|
-
|
182
|
+
port_name = (
|
183
|
+
port_decl.name
|
184
|
+
if not (self._rename_phase and port_decl.name == "phase")
|
185
|
+
else "phase_var"
|
186
|
+
)
|
187
|
+
param_name = f"{port_name}: " if port_decl.name is not None else ""
|
177
188
|
return f"{dir_str}{param_name}{self.visit(port_decl.quantum_type)}"
|
178
189
|
|
179
190
|
def visit_QuantumBit(self, qtype: QuantumBit) -> str:
|
@@ -339,7 +350,11 @@ class DSLPrettyPrinter(Visitor):
|
|
339
350
|
return f"lambda({positional_args}) {{\n{body}{self._indent}}}"
|
340
351
|
|
341
352
|
def visit_HandleBinding(self, var_ref: HandleBinding) -> str:
|
342
|
-
return
|
353
|
+
return (
|
354
|
+
var_ref.name
|
355
|
+
if not (self._rename_phase and var_ref.name == "phase")
|
356
|
+
else "phase_var"
|
357
|
+
)
|
343
358
|
|
344
359
|
def visit_SlicedHandleBinding(self, var_ref: SlicedHandleBinding) -> str:
|
345
360
|
return f"{self.visit(var_ref.base_handle)}[{self.visit(var_ref.start)}:{self.visit(var_ref.end)}]"
|
@@ -3,6 +3,7 @@ from typing import Optional, Union, cast
|
|
3
3
|
|
4
4
|
import black
|
5
5
|
|
6
|
+
from classiq.interface.exceptions import ClassiqInternalError
|
6
7
|
from classiq.interface.generator.constant import Constant
|
7
8
|
from classiq.interface.generator.expressions.expression import Expression
|
8
9
|
from classiq.interface.generator.functions.classical_type import (
|
@@ -86,16 +87,15 @@ class VariableDeclarationAssignment(Visitor):
|
|
86
87
|
def __init__(self, pretty_printer: "PythonPrettyPrinter") -> None:
|
87
88
|
self.pretty_printer = pretty_printer
|
88
89
|
|
89
|
-
def visit(self, node: NodeType) -> tuple[str,
|
90
|
+
def visit(self, node: NodeType) -> tuple[str, list[str]]:
|
90
91
|
res = super().visit(node)
|
91
92
|
if not isinstance(res, tuple):
|
92
93
|
raise AssertionError(f"Pretty printing for {type(node)} is not supported ")
|
93
94
|
return res # type: ignore[return-value]
|
94
95
|
|
95
|
-
def visit_QuantumBit(self, qtype: QuantumBit) -> tuple[str,
|
96
|
+
def visit_QuantumBit(self, qtype: QuantumBit) -> tuple[str, list[str]]:
|
96
97
|
self.pretty_printer._imports["QBit"] = 1
|
97
|
-
|
98
|
-
return "QBit", None
|
98
|
+
return "QBit", []
|
99
99
|
|
100
100
|
def visit_QuantumBitvector(
|
101
101
|
self, qtype: QuantumBitvector
|
@@ -111,19 +111,10 @@ class VariableDeclarationAssignment(Visitor):
|
|
111
111
|
self, qtype: QuantumNumeric
|
112
112
|
) -> tuple[str, Optional[list[str]]]:
|
113
113
|
self.pretty_printer._imports["QNum"] = 1
|
114
|
+
return "QNum", self.pretty_printer._get_qnum_properties(qtype)
|
114
115
|
|
115
|
-
|
116
|
-
|
117
|
-
params = [
|
118
|
-
self.pretty_printer.visit(param)
|
119
|
-
for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
|
120
|
-
if param is not None
|
121
|
-
]
|
122
|
-
|
123
|
-
return "QNum", params
|
124
|
-
|
125
|
-
def visit_TypeName(self, qtype: TypeName) -> tuple[str, None]:
|
126
|
-
return qtype.name, None
|
116
|
+
def visit_TypeName(self, qtype: TypeName) -> tuple[str, list[str]]:
|
117
|
+
return qtype.name, []
|
127
118
|
|
128
119
|
|
129
120
|
class PythonPrettyPrinter(Visitor):
|
@@ -269,21 +260,46 @@ class PythonPrettyPrinter(Visitor):
|
|
269
260
|
return f"QArray[{element_type}]"
|
270
261
|
|
271
262
|
def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
|
272
|
-
params = ""
|
273
263
|
self._imports["QNum"] = 1
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
264
|
+
params = ""
|
265
|
+
qnum_properties = self._get_qnum_properties(qtype)
|
266
|
+
if len(qnum_properties) > 0:
|
278
267
|
params = "[{}]".format(
|
279
|
-
", ".join(
|
280
|
-
_add_quotes(self.visit(param))
|
281
|
-
for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
|
282
|
-
)
|
268
|
+
", ".join(_add_quotes(param) for param in qnum_properties)
|
283
269
|
)
|
284
|
-
|
285
270
|
return f"QNum{params}"
|
286
271
|
|
272
|
+
def _get_qnum_properties(self, qtype: QuantumNumeric) -> list[str]:
|
273
|
+
params: list[str] = []
|
274
|
+
if qtype.size is None:
|
275
|
+
return params
|
276
|
+
params.append(self.visit(qtype.size))
|
277
|
+
|
278
|
+
is_signed_expr = qtype.is_signed
|
279
|
+
fraction_digits_expr = qtype.fraction_digits
|
280
|
+
if is_signed_expr is None:
|
281
|
+
if fraction_digits_expr is not None:
|
282
|
+
raise ClassiqInternalError
|
283
|
+
return params
|
284
|
+
if fraction_digits_expr is None:
|
285
|
+
raise ClassiqInternalError
|
286
|
+
|
287
|
+
is_unsigned = (
|
288
|
+
is_signed_expr.is_evaluated()
|
289
|
+
and not is_signed_expr.to_bool_value()
|
290
|
+
or is_signed_expr.expr == "UNSIGNED"
|
291
|
+
)
|
292
|
+
is_integer = (
|
293
|
+
fraction_digits_expr.is_evaluated()
|
294
|
+
and fraction_digits_expr.to_int_value() == 0
|
295
|
+
)
|
296
|
+
if is_unsigned and is_integer:
|
297
|
+
return params
|
298
|
+
params.append(self.visit(is_signed_expr))
|
299
|
+
params.append(self.visit(fraction_digits_expr))
|
300
|
+
|
301
|
+
return params
|
302
|
+
|
287
303
|
def visit_AnonClassicalParameterDeclaration(
|
288
304
|
self, cparam: AnonClassicalParameterDeclaration
|
289
305
|
) -> str:
|
@@ -325,7 +341,7 @@ class PythonPrettyPrinter(Visitor):
|
|
325
341
|
type_name, params = VariableDeclarationAssignment(self).visit(
|
326
342
|
local_decl.quantum_type
|
327
343
|
)
|
328
|
-
params = [f'"{local_decl.name}"'] +
|
344
|
+
params = [f'"{local_decl.name}"'] + params
|
329
345
|
param_args = ", ".join(params)
|
330
346
|
return f"{self._indent}{self.visit_QuantumVariableDeclaration(local_decl)} = {type_name}({param_args})\n"
|
331
347
|
|
@@ -516,7 +532,12 @@ class PythonPrettyPrinter(Visitor):
|
|
516
532
|
|
517
533
|
|
518
534
|
def _add_quotes(exp: str) -> str:
|
519
|
-
if
|
535
|
+
if (
|
536
|
+
exp.lower() == "true"
|
537
|
+
or exp.lower() == "false"
|
538
|
+
or _convertible_to_number(exp)
|
539
|
+
or _is_constant(exp)
|
540
|
+
):
|
520
541
|
return exp
|
521
542
|
|
522
543
|
return f'"{exp}"'
|
@@ -531,3 +552,7 @@ def _convertible_to_number(exp: str) -> bool:
|
|
531
552
|
else:
|
532
553
|
return True
|
533
554
|
return False
|
555
|
+
|
556
|
+
|
557
|
+
def _is_constant(exp: str) -> bool:
|
558
|
+
return exp in ("SIGNED", "UNSIGNED")
|
classiq/qmod/qfunc.py
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
from typing import Callable, Literal, Optional, Union, overload
|
2
2
|
|
3
|
-
from classiq.interface.exceptions import
|
3
|
+
from classiq.interface.exceptions import ClassiqInternalError
|
4
4
|
|
5
5
|
from classiq.qmod.quantum_callable import QCallable
|
6
|
-
from classiq.qmod.quantum_function import
|
6
|
+
from classiq.qmod.quantum_function import (
|
7
|
+
BaseQFunc,
|
8
|
+
ExternalQFunc,
|
9
|
+
GenerativeQFunc,
|
10
|
+
QFunc,
|
11
|
+
)
|
7
12
|
|
8
13
|
GEN_QFUNCS: list[GenerativeQFunc] = []
|
9
14
|
DEC_QFUNCS: list[QFunc] = []
|
@@ -54,25 +59,22 @@ def qfunc(
|
|
54
59
|
synthesize_separately: bool = False,
|
55
60
|
) -> Union[Callable[[Callable], QCallable], QCallable]:
|
56
61
|
def wrapper(func: Callable) -> QCallable:
|
62
|
+
qfunc: BaseQFunc
|
57
63
|
if generative:
|
58
|
-
|
64
|
+
qfunc = GenerativeQFunc(func)
|
65
|
+
GEN_QFUNCS.append(qfunc)
|
66
|
+
elif external:
|
59
67
|
if synthesize_separately:
|
60
|
-
raise
|
61
|
-
"
|
62
|
-
)
|
63
|
-
GEN_QFUNCS.append(gen_qfunc)
|
64
|
-
return gen_qfunc
|
65
|
-
if external:
|
66
|
-
if synthesize_separately:
|
67
|
-
raise ClassiqError(
|
68
|
-
"External functions can not be synthesized separately"
|
68
|
+
raise ClassiqInternalError(
|
69
|
+
"External functions can't be marked as synthesized separately"
|
69
70
|
)
|
70
71
|
return ExternalQFunc(func)
|
71
|
-
|
72
|
+
else:
|
73
|
+
qfunc = QFunc(func)
|
74
|
+
DEC_QFUNCS.append(qfunc)
|
72
75
|
if synthesize_separately:
|
73
|
-
|
74
|
-
|
75
|
-
return dec_qfunc
|
76
|
+
qfunc.update_compilation_metadata(should_synthesize_separately=True)
|
77
|
+
return qfunc
|
76
78
|
|
77
79
|
if func is not None:
|
78
80
|
return wrapper(func)
|
classiq/qmod/quantum_function.py
CHANGED
@@ -28,12 +28,35 @@ from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
|
|
28
28
|
from classiq.qmod.utilities import mangle_keyword
|
29
29
|
|
30
30
|
|
31
|
-
class
|
31
|
+
class BaseQFunc(QExpandable):
|
32
|
+
def __init__(
|
33
|
+
self,
|
34
|
+
py_callable: Callable,
|
35
|
+
compilation_metadata: Optional[CompilationMetadata] = None,
|
36
|
+
) -> None:
|
37
|
+
super().__init__(py_callable)
|
38
|
+
self.compilation_metadata = compilation_metadata
|
39
|
+
|
40
|
+
def update_compilation_metadata(self, **kwargs: Any) -> None:
|
41
|
+
self.compilation_metadata = self._compilation_metadata.model_copy(update=kwargs)
|
42
|
+
|
43
|
+
@property
|
44
|
+
def _compilation_metadata(self) -> CompilationMetadata:
|
45
|
+
if self.compilation_metadata is None:
|
46
|
+
return CompilationMetadata()
|
47
|
+
return self.compilation_metadata
|
48
|
+
|
49
|
+
|
50
|
+
class QFunc(BaseQFunc):
|
32
51
|
FRAME_DEPTH = 2
|
33
52
|
|
34
|
-
def __init__(
|
53
|
+
def __init__(
|
54
|
+
self,
|
55
|
+
py_callable: Callable,
|
56
|
+
compilation_metadata: Optional[CompilationMetadata] = None,
|
57
|
+
) -> None:
|
35
58
|
_validate_no_gen_params(py_callable.__annotations__)
|
36
|
-
super().__init__(py_callable)
|
59
|
+
super().__init__(py_callable, compilation_metadata)
|
37
60
|
functools.update_wrapper(self, py_callable)
|
38
61
|
self.compilation_metadata: Optional[CompilationMetadata] = None
|
39
62
|
|
@@ -44,21 +67,6 @@ class QFunc(QExpandable):
|
|
44
67
|
infer_func_decl(self._py_callable, qmodule=self._qmodule),
|
45
68
|
)
|
46
69
|
|
47
|
-
@property
|
48
|
-
def should_synthesize_separately(self) -> bool:
|
49
|
-
if self.compilation_metadata is None:
|
50
|
-
return False
|
51
|
-
return self.compilation_metadata.should_synthesize_separately
|
52
|
-
|
53
|
-
@should_synthesize_separately.setter
|
54
|
-
def should_synthesize_separately(self, value: bool) -> None:
|
55
|
-
if self.compilation_metadata is None:
|
56
|
-
self.compilation_metadata = CompilationMetadata(
|
57
|
-
should_synthesize_separately=value
|
58
|
-
)
|
59
|
-
else:
|
60
|
-
self.compilation_metadata.should_synthesize_separately = value
|
61
|
-
|
62
70
|
def __call__(self, *args: Any, **kwargs: Any) -> None:
|
63
71
|
super().__call__(*args, **kwargs)
|
64
72
|
self.expand()
|
@@ -69,16 +77,13 @@ class QFunc(QExpandable):
|
|
69
77
|
execution_preferences: Optional[ExecutionPreferences] = None,
|
70
78
|
preferences: Optional[Preferences] = None,
|
71
79
|
classical_execution_function: Optional[CFunc] = None,
|
72
|
-
functions_compilation_metadata: Optional[dict[str, CompilationMetadata]] = None,
|
73
80
|
) -> Model:
|
74
|
-
if functions_compilation_metadata is None:
|
75
|
-
functions_compilation_metadata = dict()
|
76
81
|
self._qmodule.enum_decls = dict()
|
77
82
|
self._qmodule.type_decls = dict()
|
78
83
|
self._qmodule.qstruct_decls = dict()
|
79
84
|
self._qmodule.native_defs = dict()
|
80
85
|
self._qmodule.constants = dict()
|
81
|
-
self._qmodule.functions_compilation_metadata =
|
86
|
+
self._qmodule.functions_compilation_metadata = dict()
|
82
87
|
QConstant.set_current_model(self._qmodule)
|
83
88
|
self.expand()
|
84
89
|
model_extra_settings: list[tuple[str, Any]] = [
|
@@ -167,13 +172,14 @@ class ExternalQFunc(QTerminalCallable):
|
|
167
172
|
][0]
|
168
173
|
|
169
174
|
|
170
|
-
class GenerativeQFunc(
|
175
|
+
class GenerativeQFunc(BaseQFunc):
|
171
176
|
def __init__(
|
172
177
|
self,
|
173
178
|
py_callable: Callable,
|
174
179
|
func_decl: Optional[NamedParamsQuantumFunctionDeclaration] = None,
|
180
|
+
compilation_metadata: Optional[CompilationMetadata] = None,
|
175
181
|
) -> None:
|
176
|
-
super().__init__(py_callable)
|
182
|
+
super().__init__(py_callable, compilation_metadata)
|
177
183
|
self._func_decl = func_decl
|
178
184
|
|
179
185
|
@property
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from classiq.interface.generator.functions.type_name import TypeName
|
2
|
+
from classiq.interface.generator.visitor import Visitor
|
3
|
+
|
4
|
+
from classiq.qmod.model_state_container import QMODULE
|
5
|
+
|
6
|
+
|
7
|
+
class QStructAnnotator(Visitor):
|
8
|
+
def __init__(self) -> None:
|
9
|
+
self._visited: set[TypeName] = set()
|
10
|
+
|
11
|
+
def visit_TypeName(self, type_name: TypeName) -> None:
|
12
|
+
decl = QMODULE.qstruct_decls.get(type_name.name)
|
13
|
+
if decl is None or type_name.has_fields or (type_name in self._visited):
|
14
|
+
return
|
15
|
+
self._visited.add(type_name)
|
16
|
+
new_fields = {
|
17
|
+
field_name: field_type.model_copy()
|
18
|
+
for field_name, field_type in decl.fields.items()
|
19
|
+
}
|
20
|
+
# We first visit the new fields and then set to deal with recursive
|
21
|
+
# qstructs
|
22
|
+
self.visit(new_fields)
|
23
|
+
type_name.set_fields(new_fields)
|
@@ -44,6 +44,7 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
44
44
|
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
45
45
|
from classiq.qmod.semantics.annotation import annotate_function_call_decl
|
46
46
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
47
|
+
from classiq.qmod.semantics.qstruct_annotator import QStructAnnotator
|
47
48
|
from classiq.qmod.semantics.validation.constants_validation import (
|
48
49
|
check_duplicate_constants,
|
49
50
|
)
|
@@ -70,7 +71,6 @@ HANDLE_BINDING_PART_MESSAGE = {
|
|
70
71
|
|
71
72
|
|
72
73
|
class StaticScope:
|
73
|
-
|
74
74
|
def __init__(
|
75
75
|
self,
|
76
76
|
parameters: list[str],
|
@@ -363,6 +363,8 @@ def resolve_function_calls(
|
|
363
363
|
quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
|
364
364
|
) -> None:
|
365
365
|
with ErrorManager().ignore_errors_context():
|
366
|
+
QStructAnnotator().visit(quantum_function_dict)
|
367
|
+
QStructAnnotator().visit(root)
|
366
368
|
StaticSemanticsVisitor(
|
367
369
|
{**BUILTIN_FUNCTION_DECLARATIONS, **quantum_function_dict},
|
368
370
|
[],
|
@@ -372,6 +374,7 @@ def resolve_function_calls(
|
|
372
374
|
def static_semantics_analysis_pass(
|
373
375
|
model: Model, error_type: Optional[type[Exception]] = ClassiqSemanticError
|
374
376
|
) -> None:
|
377
|
+
QStructAnnotator().visit(model)
|
375
378
|
StaticSemanticsVisitor(
|
376
379
|
{**BUILTIN_FUNCTION_DECLARATIONS, **model.function_dict},
|
377
380
|
[const.name for const in model.constants],
|
classiq/qmod/write_qmod.py
CHANGED
@@ -36,7 +36,9 @@ def write_qmod(
|
|
36
36
|
model
|
37
37
|
)
|
38
38
|
|
39
|
-
synthesis_options = model.model_dump(
|
39
|
+
synthesis_options = model.model_dump(
|
40
|
+
include={"constraints", "preferences"}, exclude_none=True
|
41
|
+
)
|
40
42
|
|
41
43
|
synthesis_options_path = Path(f"{name}.{_SYNTHESIS_OPTIONS_SUFFIX}")
|
42
44
|
if directory is not None:
|
classiq/synthesis.py
CHANGED
@@ -20,13 +20,15 @@ CANT_PARSE_QUANTUM_PROGRAM_MSG = (
|
|
20
20
|
)
|
21
21
|
|
22
22
|
|
23
|
-
def show(quantum_program: SerializedQuantumProgram) -> None:
|
23
|
+
def show(quantum_program: SerializedQuantumProgram, display_url: bool = True) -> None:
|
24
24
|
"""
|
25
25
|
Displays the interactive representation of the quantum program in the Classiq IDE.
|
26
26
|
|
27
27
|
Args:
|
28
28
|
quantum_program:
|
29
29
|
The serialized quantum program to be displayed.
|
30
|
+
display_url:
|
31
|
+
Whether to print the url
|
30
32
|
|
31
33
|
Links:
|
32
34
|
[Visualization tool](https://docs.classiq.io/latest/reference-manual/analyzer/quantum-program-visualization-tool/)
|