classiq 0.75.0__py3-none-any.whl → 0.77.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/_internals/api_wrapper.py +36 -0
- classiq/analyzer/show_interactive_hack.py +58 -2
- classiq/applications/chemistry/chemistry_model_constructor.py +15 -7
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +11 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -7
- classiq/applications/qnn/gradients/quantum_gradient.py +3 -5
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -2
- classiq/applications/qnn/qlayer.py +14 -19
- classiq/applications/qnn/types.py +1 -4
- classiq/execution/__init__.py +3 -0
- classiq/execution/execution_session.py +3 -16
- classiq/execution/qnn.py +2 -2
- classiq/execution/user_budgets.py +38 -0
- classiq/executor.py +7 -19
- classiq/interface/_version.py +1 -1
- classiq/interface/debug_info/debug_info.py +16 -2
- classiq/interface/executor/user_budget.py +56 -0
- classiq/interface/generator/application_apis/finance_declarations.py +3 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +3 -0
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +30 -124
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +45 -21
- classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +12 -11
- classiq/interface/generator/expressions/proxies/quantum/qmod_qarray_proxy.py +6 -15
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +22 -6
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +9 -4
- classiq/interface/generator/expressions/sympy_supported_expressions.py +1 -0
- classiq/interface/generator/functions/classical_type.py +6 -1
- classiq/interface/generator/functions/type_name.py +7 -2
- classiq/interface/generator/functions/type_qualifier.py +15 -0
- classiq/interface/generator/model/preferences/preferences.py +7 -0
- classiq/interface/generator/quantum_program.py +5 -19
- classiq/interface/helpers/backward_compatibility.py +9 -0
- classiq/interface/helpers/datastructures.py +6 -0
- classiq/interface/model/handle_binding.py +8 -0
- classiq/interface/model/model.py +3 -6
- classiq/interface/model/port_declaration.py +1 -2
- classiq/interface/model/quantum_function_call.py +31 -1
- classiq/interface/model/quantum_lambda_function.py +2 -1
- classiq/interface/model/quantum_statement.py +14 -1
- classiq/interface/server/routes.py +6 -0
- classiq/interface/source_reference.py +7 -2
- classiq/model_expansions/atomic_expression_functions_defs.py +62 -19
- classiq/model_expansions/capturing/captured_vars.py +18 -6
- classiq/model_expansions/closure.py +5 -0
- classiq/model_expansions/evaluators/arg_type_match.py +2 -2
- classiq/model_expansions/evaluators/argument_types.py +3 -3
- classiq/model_expansions/evaluators/classical_expression.py +9 -9
- classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
- classiq/model_expansions/evaluators/parameter_types.py +45 -24
- classiq/model_expansions/expression_evaluator.py +21 -12
- classiq/model_expansions/function_builder.py +45 -0
- classiq/model_expansions/generative_functions.py +62 -35
- classiq/model_expansions/interpreters/base_interpreter.py +32 -7
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +9 -3
- classiq/model_expansions/interpreters/generative_interpreter.py +17 -5
- classiq/model_expansions/quantum_operations/allocate.py +8 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +221 -20
- classiq/model_expansions/quantum_operations/bind.py +54 -30
- classiq/model_expansions/quantum_operations/block_evaluator.py +42 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +35 -18
- classiq/model_expansions/quantum_operations/composite_emitter.py +1 -1
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +23 -9
- classiq/model_expansions/quantum_operations/emitter.py +21 -9
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
- classiq/model_expansions/scope.py +63 -10
- classiq/model_expansions/sympy_conversion/arithmetics.py +18 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +2 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +10 -1
- classiq/model_expansions/transformers/model_renamer.py +45 -7
- classiq/model_expansions/utils/handles_collector.py +1 -1
- classiq/model_expansions/visitors/symbolic_param_inference.py +3 -3
- classiq/model_expansions/visitors/variable_references.py +45 -9
- classiq/open_library/functions/lookup_table.py +1 -1
- classiq/open_library/functions/state_preparation.py +1 -1
- classiq/qmod/builtins/functions/allocation.py +2 -2
- classiq/qmod/builtins/functions/arithmetic.py +14 -12
- classiq/qmod/builtins/functions/standard_gates.py +23 -23
- classiq/qmod/create_model_function.py +21 -3
- classiq/qmod/declaration_inferrer.py +19 -7
- classiq/qmod/generative.py +9 -1
- classiq/qmod/global_declarative_switch.py +19 -0
- classiq/qmod/native/expression_to_qmod.py +4 -0
- classiq/qmod/native/pretty_printer.py +12 -3
- classiq/qmod/pretty_print/pretty_printer.py +5 -1
- classiq/qmod/python_classical_type.py +4 -5
- classiq/qmod/qfunc.py +31 -23
- classiq/qmod/qmod_constant.py +15 -7
- classiq/qmod/qmod_variable.py +7 -1
- classiq/qmod/quantum_expandable.py +29 -1
- classiq/qmod/quantum_function.py +45 -25
- classiq/qmod/semantics/lambdas.py +6 -2
- classiq/qmod/semantics/validation/main_validation.py +17 -4
- classiq/qmod/symbolic.py +8 -19
- classiq/qmod/symbolic_expr.py +26 -0
- classiq/qmod/write_qmod.py +36 -10
- classiq/synthesis.py +24 -37
- classiq/visualization.py +35 -0
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/METADATA +1 -1
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/RECORD +101 -96
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/WHEEL +0 -0
@@ -28,6 +28,7 @@ from classiq.interface.generator.functions.concrete_types import (
|
|
28
28
|
from classiq.interface.model.classical_parameter_declaration import (
|
29
29
|
AnonClassicalParameterDeclaration,
|
30
30
|
)
|
31
|
+
from classiq.interface.model.handle_binding import GeneralHandle, HandlesList
|
31
32
|
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
32
33
|
from classiq.interface.model.quantum_function_call import (
|
33
34
|
ArgValue,
|
@@ -52,6 +53,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
52
53
|
from classiq.interface.source_reference import SourceReference
|
53
54
|
|
54
55
|
from classiq.qmod.generative import generative_mode_context, is_generative_mode
|
56
|
+
from classiq.qmod.global_declarative_switch import get_global_declarative_switch
|
55
57
|
from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
|
56
58
|
from classiq.qmod.qmod_constant import QConstant
|
57
59
|
from classiq.qmod.qmod_parameter import (
|
@@ -84,6 +86,11 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
84
86
|
self._py_callable: Callable = py_callable
|
85
87
|
self._body: list[QuantumStatement] = list()
|
86
88
|
|
89
|
+
def __eq__(self, other: Any) -> bool:
|
90
|
+
return (
|
91
|
+
isinstance(other, QExpandable) and self._py_callable is other._py_callable
|
92
|
+
)
|
93
|
+
|
87
94
|
@property
|
88
95
|
def body(self) -> list[QuantumStatement]:
|
89
96
|
return self._body
|
@@ -317,8 +324,10 @@ def prepare_arg(
|
|
317
324
|
def prepare_arg(
|
318
325
|
arg_decl: AnonPositionalArg, val: Any, func_name: Optional[str], param_name: str
|
319
326
|
) -> ArgValue:
|
320
|
-
from classiq.qmod.quantum_function import BaseQFunc, GenerativeQFunc
|
327
|
+
from classiq.qmod.quantum_function import BaseQFunc, GenerativeQFunc, QFunc
|
321
328
|
|
329
|
+
if get_global_declarative_switch() and isinstance(val, GenerativeQFunc):
|
330
|
+
val = QFunc(val._py_callable)
|
322
331
|
if isinstance(val, BaseQFunc):
|
323
332
|
val.add_function_dependencies()
|
324
333
|
if isinstance(val, GenerativeQFunc):
|
@@ -330,6 +339,9 @@ def prepare_arg(
|
|
330
339
|
_validate_classical_arg(val, arg_decl, func_name)
|
331
340
|
return Expression(expr=qmod_val_to_expr_str(val))
|
332
341
|
elif isinstance(arg_decl, AnonPortDeclaration):
|
342
|
+
handles_list = _try_preparing_handles_list(val)
|
343
|
+
if handles_list is not None:
|
344
|
+
return handles_list
|
333
345
|
if not isinstance(val, QVar):
|
334
346
|
func_name_message = (
|
335
347
|
"" if func_name is None else f" of function {func_name!r}"
|
@@ -505,3 +517,19 @@ def _is_legal_iterable_element(arg: Any) -> bool:
|
|
505
517
|
if isinstance(arg, Iterable):
|
506
518
|
return all(_is_legal_iterable_element(e) for e in arg)
|
507
519
|
return True
|
520
|
+
|
521
|
+
|
522
|
+
def _try_preparing_handles_list(val: Any) -> Optional[HandlesList]:
|
523
|
+
if not isinstance(val, list):
|
524
|
+
return None
|
525
|
+
items = [
|
526
|
+
(
|
527
|
+
item.get_handle_binding()
|
528
|
+
if isinstance(item, QVar)
|
529
|
+
else _try_preparing_handles_list(item)
|
530
|
+
)
|
531
|
+
for item in val
|
532
|
+
]
|
533
|
+
if any(item is None for item in items):
|
534
|
+
return None
|
535
|
+
return HandlesList(handles=cast(list[GeneralHandle], items))
|
classiq/qmod/quantum_function.py
CHANGED
@@ -14,7 +14,7 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
14
14
|
from classiq.interface.generator.model.constraints import Constraints
|
15
15
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
16
16
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
17
|
-
from classiq.interface.model.model import Model
|
17
|
+
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
18
18
|
from classiq.interface.model.native_function_definition import (
|
19
19
|
NativeFunctionDefinition,
|
20
20
|
)
|
@@ -26,11 +26,13 @@ from classiq.qmod.classical_function import CFunc
|
|
26
26
|
from classiq.qmod.cparam import CParamAbstract
|
27
27
|
from classiq.qmod.declaration_inferrer import infer_func_decl, is_qvar
|
28
28
|
from classiq.qmod.generative import set_frontend_interpreter
|
29
|
+
from classiq.qmod.global_declarative_switch import get_global_declarative_switch
|
29
30
|
from classiq.qmod.qmod_constant import QConstant
|
30
31
|
from classiq.qmod.qmod_parameter import CArray
|
31
32
|
from classiq.qmod.quantum_callable import QCallable, QCallableList
|
32
33
|
from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
|
33
34
|
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
35
|
+
from classiq.qmod.semantics.validation.main_validation import validate_main_function
|
34
36
|
from classiq.qmod.utilities import mangle_keyword
|
35
37
|
|
36
38
|
|
@@ -48,6 +50,18 @@ class BaseQFunc(QExpandable):
|
|
48
50
|
def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
49
51
|
raise NotImplementedError
|
50
52
|
|
53
|
+
@property
|
54
|
+
def pure_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
55
|
+
if type(self.func_decl) is NamedParamsQuantumFunctionDeclaration:
|
56
|
+
return self.func_decl
|
57
|
+
return NamedParamsQuantumFunctionDeclaration(
|
58
|
+
**{
|
59
|
+
k: v
|
60
|
+
for k, v in self.func_decl.model_dump().items()
|
61
|
+
if k in NamedParamsQuantumFunctionDeclaration.model_fields
|
62
|
+
}
|
63
|
+
)
|
64
|
+
|
51
65
|
@property
|
52
66
|
def _has_inputs(self) -> bool:
|
53
67
|
return any(
|
@@ -89,22 +103,10 @@ class QFunc(BaseQFunc):
|
|
89
103
|
super().__init__(py_callable, compilation_metadata)
|
90
104
|
self.compilation_metadata: Optional[CompilationMetadata] = None
|
91
105
|
|
92
|
-
@property
|
93
|
-
def pure_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
94
|
-
if type(self.func_decl) is NamedParamsQuantumFunctionDeclaration:
|
95
|
-
return self.func_decl
|
96
|
-
return NamedParamsQuantumFunctionDeclaration(
|
97
|
-
**{
|
98
|
-
k: v
|
99
|
-
for k, v in self.func_decl.model_dump().items()
|
100
|
-
if k in NamedParamsQuantumFunctionDeclaration.model_fields
|
101
|
-
}
|
102
|
-
)
|
103
|
-
|
104
106
|
@property
|
105
107
|
def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
106
108
|
name = self._py_callable.__name__
|
107
|
-
if
|
109
|
+
if name in self._qmodule.native_defs:
|
108
110
|
return self._qmodule.native_defs[name]
|
109
111
|
return infer_func_decl(self._py_callable, qmodule=self._qmodule)
|
110
112
|
|
@@ -141,7 +143,10 @@ class QFunc(BaseQFunc):
|
|
141
143
|
functions_compilation_metadata=self._qmodule.functions_compilation_metadata,
|
142
144
|
**{key: value for key, value in model_extra_settings if value},
|
143
145
|
)
|
144
|
-
if
|
146
|
+
if (
|
147
|
+
not get_global_declarative_switch()
|
148
|
+
and len(self._qmodule.generative_functions) > 0
|
149
|
+
):
|
145
150
|
return self._create_generative_model(model)
|
146
151
|
return model
|
147
152
|
|
@@ -232,12 +237,6 @@ class ExternalQFunc(QTerminalCallable):
|
|
232
237
|
def pure_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
233
238
|
return self.func_decl
|
234
239
|
|
235
|
-
def get_implementation(self) -> NativeFunctionDefinition:
|
236
|
-
model = QFunc(self._py_callable).create_model()
|
237
|
-
return [
|
238
|
-
func for func in model.functions if func.name == self._py_callable.__name__
|
239
|
-
][0]
|
240
|
-
|
241
240
|
|
242
241
|
class GenerativeQFunc(BaseQFunc):
|
243
242
|
FRAME_DEPTH = 3
|
@@ -250,15 +249,25 @@ class GenerativeQFunc(BaseQFunc):
|
|
250
249
|
) -> None:
|
251
250
|
super().__init__(py_callable, compilation_metadata)
|
252
251
|
self._func_decl = func_decl
|
252
|
+
self._inferred_func_decl: Optional[NamedParamsQuantumFunctionDeclaration] = None
|
253
253
|
|
254
254
|
@property
|
255
255
|
def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
256
|
-
if self._func_decl is None:
|
257
|
-
self._func_decl
|
258
|
-
|
256
|
+
if self._func_decl is not None:
|
257
|
+
return self._func_decl
|
258
|
+
if self._inferred_func_decl is None:
|
259
|
+
self._inferred_func_decl = infer_func_decl(self._py_callable, self._qmodule)
|
260
|
+
return self._inferred_func_decl
|
259
261
|
|
260
262
|
def __call__(self, *args: Any, **kwargs: Any) -> None:
|
261
|
-
|
263
|
+
if get_global_declarative_switch():
|
264
|
+
return QFunc(self._py_callable)(*args, **kwargs)
|
265
|
+
if self.func_decl.name not in self._qmodule.generative_functions:
|
266
|
+
self._qmodule.generative_functions[self.func_decl.name] = self
|
267
|
+
if self._func_decl is None:
|
268
|
+
self._inferred_func_decl = infer_func_decl(
|
269
|
+
self._py_callable, self._qmodule
|
270
|
+
)
|
262
271
|
super().__call__(*args, **kwargs)
|
263
272
|
|
264
273
|
def create_model(
|
@@ -268,6 +277,17 @@ class GenerativeQFunc(BaseQFunc):
|
|
268
277
|
preferences: Optional[Preferences] = None,
|
269
278
|
classical_execution_function: Optional[CFunc] = None,
|
270
279
|
) -> Model:
|
280
|
+
if get_global_declarative_switch():
|
281
|
+
return QFunc(self._py_callable).create_model(
|
282
|
+
constraints,
|
283
|
+
execution_preferences,
|
284
|
+
preferences,
|
285
|
+
classical_execution_function,
|
286
|
+
)
|
287
|
+
self._qmodule.reset()
|
288
|
+
if self.func_decl.name == MAIN_FUNCTION_NAME:
|
289
|
+
validate_main_function(self.func_decl)
|
290
|
+
|
271
291
|
def _dec_main(*args: Any, **kwargs: Any) -> None:
|
272
292
|
self(*args, **kwargs)
|
273
293
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from classiq.interface.helpers.backward_compatibility import zip_strict
|
1
2
|
from classiq.interface.model.port_declaration import PortDeclaration
|
2
3
|
from classiq.interface.model.quantum_function_declaration import (
|
3
4
|
AnonQuantumOperandDeclaration,
|
@@ -14,8 +15,11 @@ def get_renamed_parameters(
|
|
14
15
|
renamed_parameters: list[str] = []
|
15
16
|
renamed_operands: dict[str, QuantumOperandDeclaration] = {}
|
16
17
|
renamed_ports: list[PortDeclaration] = []
|
17
|
-
for
|
18
|
-
|
18
|
+
for param, param_name in zip_strict(
|
19
|
+
lambda_func.func_decl.positional_arg_declarations,
|
20
|
+
lambda_func.pos_rename_params,
|
21
|
+
strict=False,
|
22
|
+
):
|
19
23
|
if isinstance(param, AnonClassicalParameterDeclaration):
|
20
24
|
renamed_parameters.append(param_name)
|
21
25
|
elif isinstance(param, AnonQuantumOperandDeclaration):
|
@@ -1,16 +1,22 @@
|
|
1
|
-
from classiq.interface.exceptions import ClassiqExpansionError
|
1
|
+
from classiq.interface.exceptions import ClassiqExpansionError, ClassiqValueError
|
2
2
|
from classiq.interface.generator.functions.classical_type import (
|
3
3
|
ClassicalArray,
|
4
4
|
ClassicalList,
|
5
5
|
)
|
6
6
|
from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
|
7
|
-
from classiq.interface.
|
8
|
-
|
7
|
+
from classiq.interface.generator.functions.port_declaration import (
|
8
|
+
PortDeclarationDirection,
|
9
|
+
)
|
10
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
11
|
+
from classiq.interface.model.quantum_function_declaration import (
|
12
|
+
NamedParamsQuantumFunctionDeclaration,
|
13
|
+
PositionalArg,
|
14
|
+
)
|
9
15
|
|
10
16
|
from classiq import ClassicalParameterDeclaration
|
11
17
|
|
12
18
|
|
13
|
-
def validate_main_function(func:
|
19
|
+
def validate_main_function(func: NamedParamsQuantumFunctionDeclaration) -> None:
|
14
20
|
for param in func.positional_arg_declarations:
|
15
21
|
_validate_main_param(param)
|
16
22
|
|
@@ -18,6 +24,8 @@ def validate_main_function(func: NativeFunctionDefinition) -> None:
|
|
18
24
|
def _validate_main_param(param: PositionalArg) -> None:
|
19
25
|
if isinstance(param, ClassicalParameterDeclaration):
|
20
26
|
_validate_main_classical_param_type(param.classical_type, param.name)
|
27
|
+
if isinstance(param, PortDeclaration):
|
28
|
+
_validate_main_quantum_param_type(param)
|
21
29
|
|
22
30
|
|
23
31
|
def _validate_main_classical_param_type(
|
@@ -30,3 +38,8 @@ def _validate_main_classical_param_type(
|
|
30
38
|
)
|
31
39
|
if isinstance(param, ClassicalArray):
|
32
40
|
_validate_main_classical_param_type(param.element_type, param_name)
|
41
|
+
|
42
|
+
|
43
|
+
def _validate_main_quantum_param_type(param: PortDeclaration) -> None:
|
44
|
+
if param.direction != PortDeclarationDirection.Output:
|
45
|
+
raise ClassiqValueError("Function 'main' cannot declare quantum inputs")
|
classiq/qmod/symbolic.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import sys
|
2
|
-
from collections.abc import Sequence
|
3
2
|
from typing import (
|
4
3
|
TYPE_CHECKING,
|
5
4
|
Any,
|
@@ -12,6 +11,9 @@ from typing import (
|
|
12
11
|
import numpy as np
|
13
12
|
|
14
13
|
from classiq.interface.exceptions import ClassiqValueError
|
14
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
15
|
+
subscript_to_str,
|
16
|
+
)
|
15
17
|
|
16
18
|
from classiq.qmod import model_state_container
|
17
19
|
from classiq.qmod.declaration_inferrer import python_type_to_qmod
|
@@ -24,6 +26,7 @@ from classiq.qmod.qmod_parameter import (
|
|
24
26
|
)
|
25
27
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
26
28
|
from classiq.qmod.symbolic_type import SymbolicTypes
|
29
|
+
from classiq.qmod.utilities import qmod_val_to_expr_str
|
27
30
|
|
28
31
|
pi = SymbolicExpr("pi", False)
|
29
32
|
E = SymbolicExpr("E", False)
|
@@ -306,27 +309,13 @@ def sum(arr: SymbolicTypes) -> CParamScalar:
|
|
306
309
|
return symbolic_function(arr)
|
307
310
|
|
308
311
|
|
309
|
-
def _subscript_to_str(index: Any) -> str:
|
310
|
-
if not isinstance(index, slice):
|
311
|
-
return str(index)
|
312
|
-
expr = ""
|
313
|
-
if index.start is not None:
|
314
|
-
expr += str(index.start)
|
315
|
-
expr += ":"
|
316
|
-
if index.stop is not None:
|
317
|
-
expr += str(index.stop)
|
318
|
-
if index.step is not None:
|
319
|
-
expr += f":{index.step}"
|
320
|
-
return expr
|
321
|
-
|
322
|
-
|
323
312
|
def subscript(
|
324
|
-
array: Union[
|
325
|
-
Sequence[Union[float, CReal, CParamScalar]], CArray[CReal], np.ndarray
|
326
|
-
],
|
313
|
+
array: Union[list, CArray[CReal], np.ndarray],
|
327
314
|
index: Any,
|
328
315
|
) -> CParamScalar:
|
329
|
-
return CParamScalar(
|
316
|
+
return CParamScalar(
|
317
|
+
expr=f"{qmod_val_to_expr_str(_unwrap_numpy(array))}[{subscript_to_str(index)}]"
|
318
|
+
)
|
330
319
|
|
331
320
|
|
332
321
|
__all__ = [
|
classiq/qmod/symbolic_expr.py
CHANGED
@@ -177,3 +177,29 @@ class SymbolicEquality(SymbolicExpr):
|
|
177
177
|
super().__init__(sym_expr._expr, sym_expr.is_quantum)
|
178
178
|
self.lhs = lhs
|
179
179
|
self.rhs = rhs
|
180
|
+
|
181
|
+
|
182
|
+
class SymbolicSubscriptAndField(SymbolicExpr):
|
183
|
+
def __getattr__(self, item: str) -> SymbolicSubscriptAndField:
|
184
|
+
return SymbolicSubscriptAndField(f"{self}.{item}", is_quantum=self.is_quantum)
|
185
|
+
|
186
|
+
def __getitem__(self, item: Any) -> SymbolicExpr:
|
187
|
+
if isinstance(item, slice):
|
188
|
+
start = item.start
|
189
|
+
stop = item.stop
|
190
|
+
step = item.step
|
191
|
+
item_is_quantum = (
|
192
|
+
(isinstance(start, SymbolicExpr) and start.is_quantum)
|
193
|
+
or (isinstance(stop, SymbolicExpr) and stop.is_quantum)
|
194
|
+
or (isinstance(step, SymbolicExpr) and step.is_quantum)
|
195
|
+
)
|
196
|
+
start_str = "" if start is None else qmod_val_to_expr_str(start)
|
197
|
+
stop_str = "" if stop is None else qmod_val_to_expr_str(stop)
|
198
|
+
step_str = "" if step is None else qmod_val_to_expr_str(step)
|
199
|
+
item_str = f"{start_str}:{stop_str}:{step_str}"
|
200
|
+
else:
|
201
|
+
item_is_quantum = isinstance(item, SymbolicExpr) and item.is_quantum
|
202
|
+
item_str = qmod_val_to_expr_str(item)
|
203
|
+
return SymbolicSubscriptAndField(
|
204
|
+
f"{self}[{item_str}]", is_quantum=self.is_quantum or item_is_quantum
|
205
|
+
)
|
classiq/qmod/write_qmod.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
import json
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import
|
3
|
+
from typing import Optional, Union
|
4
4
|
|
5
5
|
from classiq.interface.model.model import Model, SerializedModel
|
6
6
|
|
7
|
+
from classiq.qmod.global_declarative_switch import set_global_declarative_switch
|
7
8
|
from classiq.qmod.native.pretty_printer import DSLPrettyPrinter
|
8
9
|
from classiq.qmod.quantum_function import GenerativeQFunc, QFunc
|
9
10
|
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
@@ -17,8 +18,7 @@ def write_qmod(
|
|
17
18
|
name: str,
|
18
19
|
directory: Optional[Path] = None,
|
19
20
|
decimal_precision: int = DEFAULT_DECIMAL_PRECISION,
|
20
|
-
|
21
|
-
**kwargs: Any,
|
21
|
+
symbolic_only: bool = True,
|
22
22
|
) -> None:
|
23
23
|
"""
|
24
24
|
Creates a native Qmod file from a serialized model and outputs the synthesis options (Preferences and Constraints) to a file.
|
@@ -29,20 +29,15 @@ def write_qmod(
|
|
29
29
|
name: The name to save the file by.
|
30
30
|
directory: The directory to save the files in. If None, the current working directory is used.
|
31
31
|
decimal_precision: The number of decimal places to use for numbers, set to 4 by default.
|
32
|
-
|
33
|
-
kwargs: (placeholder)
|
32
|
+
symbolic_only: If True keep function definitions un-expanded and symbolic (note that Qmod functions with parameters of Python types are not supported in this mode)
|
34
33
|
|
35
34
|
Returns:
|
36
35
|
None
|
37
36
|
"""
|
38
|
-
|
39
|
-
model_obj = model.create_model()
|
40
|
-
else:
|
41
|
-
model_obj = Model.model_validate_json(model)
|
37
|
+
model_obj = prepare_write_qmod_model(model, symbolic_only)
|
42
38
|
pretty_printed_model = DSLPrettyPrinter(decimal_precision=decimal_precision).visit(
|
43
39
|
model_obj
|
44
40
|
)
|
45
|
-
|
46
41
|
synthesis_options = model_obj.model_dump(
|
47
42
|
include={"constraints", "preferences"}, exclude_none=True
|
48
43
|
)
|
@@ -58,3 +53,34 @@ def write_qmod(
|
|
58
53
|
native_qmod_path = directory / native_qmod_path
|
59
54
|
|
60
55
|
native_qmod_path.write_text(pretty_printed_model)
|
56
|
+
|
57
|
+
|
58
|
+
def prepare_write_qmod_model(
|
59
|
+
model: Union[SerializedModel, QFunc, GenerativeQFunc], symbolic_only: bool
|
60
|
+
) -> Model:
|
61
|
+
if isinstance(model, str) and hasattr(model, "entry_point") and symbolic_only:
|
62
|
+
model_obj = Model.model_validate_json(model)
|
63
|
+
with set_global_declarative_switch():
|
64
|
+
dec_model_obj = model.entry_point.create_model(
|
65
|
+
constraints=model_obj.constraints,
|
66
|
+
execution_preferences=model_obj.execution_preferences,
|
67
|
+
preferences=model_obj.preferences,
|
68
|
+
)
|
69
|
+
dec_constant_names = {const.name for const in dec_model_obj.constants}
|
70
|
+
all_constants = dec_model_obj.constants + [
|
71
|
+
const
|
72
|
+
for const in model_obj.constants
|
73
|
+
if const.name not in dec_constant_names
|
74
|
+
]
|
75
|
+
return dec_model_obj.model_copy(
|
76
|
+
update={
|
77
|
+
"constants": all_constants,
|
78
|
+
"classical_execution_code": model_obj.classical_execution_code,
|
79
|
+
}
|
80
|
+
)
|
81
|
+
if isinstance(model, (QFunc, GenerativeQFunc)):
|
82
|
+
if symbolic_only:
|
83
|
+
with set_global_declarative_switch():
|
84
|
+
return model.create_model()
|
85
|
+
return model.create_model()
|
86
|
+
return Model.model_validate_json(model)
|
classiq/synthesis.py
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
from typing import Any,
|
2
|
-
|
3
|
-
import pydantic
|
1
|
+
from typing import Any, Optional, Union
|
4
2
|
|
5
3
|
from classiq.interface.analyzer.result import QasmCode
|
6
4
|
from classiq.interface.exceptions import ClassiqError, ClassiqValueError
|
@@ -12,43 +10,34 @@ from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model, SerializedM
|
|
12
10
|
from classiq import QuantumProgram
|
13
11
|
from classiq._internals import async_utils
|
14
12
|
from classiq._internals.api_wrapper import ApiWrapper
|
15
|
-
from classiq.qmod.
|
16
|
-
|
17
|
-
SerializedQuantumProgram = NewType("SerializedQuantumProgram", str)
|
13
|
+
from classiq.qmod.create_model_function import add_entry_point
|
14
|
+
from classiq.qmod.quantum_function import BaseQFunc
|
18
15
|
|
19
|
-
|
20
|
-
"Can not parse quantum_program into GeneratedCircuit, \n"
|
21
|
-
)
|
16
|
+
SerializedQuantumProgram = QuantumProgram
|
22
17
|
|
23
18
|
|
24
|
-
def show(quantum_program:
|
19
|
+
def show(quantum_program: QuantumProgram, display_url: bool = True) -> None:
|
25
20
|
"""
|
26
21
|
Displays the interactive representation of the quantum program in the Classiq IDE.
|
27
22
|
|
28
23
|
Args:
|
29
24
|
quantum_program:
|
30
|
-
The
|
25
|
+
The quantum program to be displayed.
|
31
26
|
display_url:
|
32
27
|
Whether to print the url
|
33
28
|
|
34
29
|
Links:
|
35
30
|
[Visualization tool](https://docs.classiq.io/latest/reference-manual/analyzer/quantum-program-visualization-tool/)
|
36
31
|
"""
|
37
|
-
|
38
|
-
|
39
|
-
except pydantic.ValidationError as exc:
|
40
|
-
raise ClassiqValueError(CANT_PARSE_QUANTUM_PROGRAM_MSG) from exc
|
41
|
-
circuit.show() # type: ignore[attr-defined]
|
32
|
+
QuantumProgram.model_validate(quantum_program)
|
33
|
+
quantum_program.show() # type: ignore[attr-defined]
|
42
34
|
|
43
35
|
|
44
|
-
async def quantum_program_from_qasm_async(qasm: str) ->
|
45
|
-
|
46
|
-
QasmCode(code=qasm)
|
47
|
-
)
|
48
|
-
return SerializedQuantumProgram(quantum_program.model_dump_json())
|
36
|
+
async def quantum_program_from_qasm_async(qasm: str) -> QuantumProgram:
|
37
|
+
return await ApiWrapper.get_generated_circuit_from_qasm(QasmCode(code=qasm))
|
49
38
|
|
50
39
|
|
51
|
-
def quantum_program_from_qasm(qasm: str) ->
|
40
|
+
def quantum_program_from_qasm(qasm: str) -> QuantumProgram:
|
52
41
|
"""
|
53
42
|
generate a quantum program from a QASM file.
|
54
43
|
|
@@ -56,25 +45,24 @@ def quantum_program_from_qasm(qasm: str) -> SerializedQuantumProgram:
|
|
56
45
|
qasm: A QASM2/3 string.
|
57
46
|
|
58
47
|
Returns:
|
59
|
-
|
48
|
+
QuantumProgram: Quantum program. (See: QuantumProgram)
|
60
49
|
"""
|
61
50
|
return async_utils.run(quantum_program_from_qasm_async(qasm))
|
62
51
|
|
63
52
|
|
64
53
|
async def synthesize_async(
|
65
54
|
serialized_model: SerializedModel,
|
66
|
-
) ->
|
55
|
+
) -> QuantumProgram:
|
67
56
|
model = Model.model_validate_json(serialized_model)
|
68
|
-
|
69
|
-
return SerializedQuantumProgram(quantum_program.model_dump_json(indent=2))
|
57
|
+
return await ApiWrapper.call_generation_task(model)
|
70
58
|
|
71
59
|
|
72
60
|
def synthesize(
|
73
|
-
model: Union[SerializedModel,
|
61
|
+
model: Union[SerializedModel, BaseQFunc],
|
74
62
|
auto_show: bool = False,
|
75
63
|
constraints: Optional[Constraints] = None,
|
76
64
|
preferences: Optional[Preferences] = None,
|
77
|
-
) ->
|
65
|
+
) -> QuantumProgram:
|
78
66
|
"""
|
79
67
|
Synthesize a model with the Classiq engine to receive a quantum program.
|
80
68
|
[More details](https://docs.classiq.io/latest/reference-manual/synthesis/)
|
@@ -86,9 +74,9 @@ def synthesize(
|
|
86
74
|
preferences: Preferences for the synthesis of the model. See Preferences (Optional).
|
87
75
|
|
88
76
|
Returns:
|
89
|
-
|
77
|
+
QuantumProgram: Quantum program. (See: QuantumProgram)
|
90
78
|
"""
|
91
|
-
if isinstance(model,
|
79
|
+
if isinstance(model, BaseQFunc):
|
92
80
|
func_name = model._py_callable.__name__
|
93
81
|
if func_name != MAIN_FUNCTION_NAME:
|
94
82
|
raise ClassiqError(
|
@@ -129,7 +117,7 @@ def set_preferences(
|
|
129
117
|
|
130
118
|
model = Model.model_validate_json(serialized_model)
|
131
119
|
model.preferences = preferences
|
132
|
-
return model.get_model()
|
120
|
+
return add_entry_point(model.get_model(), serialized_model)
|
133
121
|
|
134
122
|
|
135
123
|
def update_preferences(
|
@@ -149,7 +137,7 @@ def update_preferences(
|
|
149
137
|
|
150
138
|
for key, value in kwargs.items():
|
151
139
|
setattr(model.preferences, key, value)
|
152
|
-
return model.get_model()
|
140
|
+
return add_entry_point(model.get_model(), serialized_model)
|
153
141
|
|
154
142
|
|
155
143
|
def set_constraints(
|
@@ -177,7 +165,7 @@ def set_constraints(
|
|
177
165
|
|
178
166
|
model = Model.model_validate_json(serialized_model)
|
179
167
|
model.constraints = constraints
|
180
|
-
return model.get_model()
|
168
|
+
return add_entry_point(model.get_model(), serialized_model)
|
181
169
|
|
182
170
|
|
183
171
|
def update_constraints(
|
@@ -197,7 +185,7 @@ def update_constraints(
|
|
197
185
|
|
198
186
|
for key, value in kwargs.items():
|
199
187
|
setattr(model.constraints, key, value)
|
200
|
-
return model.get_model()
|
188
|
+
return add_entry_point(model.get_model(), serialized_model)
|
201
189
|
|
202
190
|
|
203
191
|
def set_execution_preferences(
|
@@ -226,7 +214,7 @@ def set_execution_preferences(
|
|
226
214
|
|
227
215
|
model = Model.model_validate_json(serialized_model)
|
228
216
|
model.execution_preferences = execution_preferences
|
229
|
-
return model.get_model()
|
217
|
+
return add_entry_point(model.get_model(), serialized_model)
|
230
218
|
|
231
219
|
|
232
220
|
def update_execution_preferences(
|
@@ -247,12 +235,11 @@ def update_execution_preferences(
|
|
247
235
|
for key, value in kwargs.items():
|
248
236
|
setattr(model.execution_preferences, key, value)
|
249
237
|
|
250
|
-
return model.get_model()
|
238
|
+
return add_entry_point(model.get_model(), serialized_model)
|
251
239
|
|
252
240
|
|
253
241
|
__all__ = [
|
254
242
|
"SerializedModel",
|
255
|
-
"SerializedQuantumProgram",
|
256
243
|
"set_constraints",
|
257
244
|
"set_execution_preferences",
|
258
245
|
"set_preferences",
|
classiq/visualization.py
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
from typing import NewType
|
2
|
+
|
3
|
+
from classiq.interface.analyzer.result import DataID
|
4
|
+
from classiq.interface.exceptions import ClassiqAPIError
|
5
|
+
|
6
|
+
from classiq._internals import async_utils
|
7
|
+
from classiq._internals.api_wrapper import ApiWrapper
|
8
|
+
|
9
|
+
SerializedVisualModel = NewType("SerializedVisualModel", str)
|
10
|
+
|
11
|
+
|
12
|
+
async def visualize_async(
|
13
|
+
data_id: DataID,
|
14
|
+
) -> SerializedVisualModel:
|
15
|
+
try:
|
16
|
+
visual_model = await ApiWrapper.call_get_visual_model(data_id.id)
|
17
|
+
except ClassiqAPIError as error:
|
18
|
+
if error.status_code != 404:
|
19
|
+
raise error
|
20
|
+
analyzer_data = await ApiWrapper.get_analyzer_app_data(data_id)
|
21
|
+
visual_model = await ApiWrapper.call_visualization_task(analyzer_data)
|
22
|
+
return SerializedVisualModel(visual_model.model_dump_json(indent=2))
|
23
|
+
|
24
|
+
|
25
|
+
def visualize(
|
26
|
+
data_id: DataID,
|
27
|
+
) -> SerializedVisualModel:
|
28
|
+
result = async_utils.run(visualize_async(data_id))
|
29
|
+
return result
|
30
|
+
|
31
|
+
|
32
|
+
__all__ = [
|
33
|
+
"SerializedVisualModel",
|
34
|
+
"visualize",
|
35
|
+
]
|