classiq 0.68.0__py3-none-any.whl → 0.70.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 +4 -8
- classiq/analyzer/analyzer.py +0 -18
- classiq/analyzer/url_utils.py +9 -4
- classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -11
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/torch_utils.py +1 -1
- classiq/execution/jobs.py +2 -5
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +8 -3
- classiq/interface/chemistry/operator.py +12 -28
- classiq/interface/debug_info/back_ref_util.py +22 -0
- classiq/interface/debug_info/debug_info.py +11 -21
- classiq/interface/executor/optimizer_preferences.py +1 -0
- classiq/interface/executor/quantum_instruction_set.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +21 -6
- classiq/interface/generator/arith/arithmetic_param_getters.py +3 -3
- classiq/interface/generator/circuit_code/circuit_code.py +4 -0
- classiq/interface/generator/circuit_code/types_and_constants.py +1 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +1 -2
- classiq/interface/generator/expressions/expression_types.py +8 -2
- classiq/interface/generator/expressions/proxies/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +75 -0
- classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +26 -0
- classiq/interface/generator/expressions/proxies/classical/classical_scalar_proxy.py +32 -0
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +31 -0
- classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
- classiq/interface/generator/expressions/{qmod_qarray_proxy.py → proxies/quantum/qmod_qarray_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qscalar_proxy.py → proxies/quantum/qmod_qscalar_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qstruct_proxy.py → proxies/quantum/qmod_qstruct_proxy.py} +3 -1
- classiq/interface/generator/functions/classical_type.py +34 -29
- classiq/interface/generator/functions/type_name.py +26 -2
- classiq/interface/generator/generated_circuit_data.py +84 -27
- classiq/interface/generator/model/preferences/preferences.py +1 -0
- classiq/interface/generator/quantum_program.py +0 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/interface/generator/types/enum_declaration.py +12 -1
- classiq/interface/ide/visual_model.py +0 -2
- classiq/interface/model/native_function_definition.py +0 -10
- classiq/interface/model/quantum_statement.py +1 -1
- classiq/interface/model/quantum_type.py +15 -3
- classiq/interface/server/routes.py +0 -6
- classiq/model_expansions/atomic_expression_functions_defs.py +9 -3
- classiq/model_expansions/evaluators/arg_type_match.py +4 -2
- classiq/model_expansions/evaluators/classical_expression.py +2 -2
- classiq/model_expansions/evaluators/control.py +1 -1
- classiq/model_expansions/evaluators/parameter_types.py +58 -16
- classiq/model_expansions/evaluators/quantum_type_utils.py +7 -57
- classiq/model_expansions/expression_evaluator.py +3 -1
- classiq/model_expansions/generative_functions.py +67 -7
- classiq/model_expansions/quantum_operations/arithmetic/__init__.py +0 -0
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +60 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +9 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +0 -13
- classiq/model_expansions/quantum_operations/quantum_function_call.py +0 -22
- classiq/model_expansions/scope.py +7 -6
- classiq/model_expansions/scope_initialization.py +20 -33
- classiq/model_expansions/transformers/model_renamer.py +13 -4
- classiq/model_expansions/visitors/variable_references.py +8 -4
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/amplitude_amplification.py +3 -7
- classiq/open_library/functions/discrete_sine_cosine_transform.py +4 -4
- classiq/open_library/functions/grover.py +2 -2
- classiq/open_library/functions/hea.py +3 -3
- classiq/open_library/functions/lookup_table.py +58 -0
- classiq/open_library/functions/modular_exponentiation.py +10 -20
- classiq/open_library/functions/qft_functions.py +2 -2
- classiq/open_library/functions/qsvt.py +8 -8
- classiq/open_library/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/classical_functions.py +24 -7
- classiq/qmod/builtins/enums.py +1 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/exponentiation.py +24 -0
- classiq/qmod/builtins/operations.py +26 -11
- classiq/qmod/cparam.py +32 -5
- classiq/qmod/declaration_inferrer.py +3 -1
- classiq/qmod/python_classical_type.py +10 -4
- classiq/qmod/qmod_parameter.py +8 -0
- classiq/qmod/qmod_variable.py +11 -14
- classiq/qmod/quantum_callable.py +2 -1
- classiq/qmod/quantum_function.py +3 -2
- classiq/qmod/semantics/annotation/call_annotation.py +0 -28
- classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
- classiq/qmod/semantics/error_manager.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -1
- classiq/qmod/semantics/validation/type_hints.py +29 -0
- classiq/qmod/utilities.py +67 -2
- classiq/synthesis.py +9 -6
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/METADATA +10 -12
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/RECORD +95 -84
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/WHEEL +1 -1
- classiq/interface/execution/jobs.py +0 -31
- /classiq/interface/generator/expressions/{qmod_struct_instance.py → proxies/classical/qmod_struct_instance.py} +0 -0
- /classiq/interface/generator/expressions/{qmod_sized_proxy.py → proxies/quantum/qmod_sized_proxy.py} +0 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from typing import TYPE_CHECKING, Union
|
3
|
+
|
4
|
+
from sympy import Integer
|
5
|
+
|
6
|
+
from classiq.interface.exceptions import ClassiqValueError
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
8
|
+
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
9
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
10
|
+
ClassicalProxy,
|
11
|
+
)
|
12
|
+
from classiq.interface.model.handle_binding import (
|
13
|
+
HandleBinding,
|
14
|
+
SlicedHandleBinding,
|
15
|
+
SubscriptHandleBinding,
|
16
|
+
)
|
17
|
+
|
18
|
+
if TYPE_CHECKING:
|
19
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
20
|
+
from classiq.interface.generator.functions.concrete_types import (
|
21
|
+
ConcreteClassicalType,
|
22
|
+
)
|
23
|
+
|
24
|
+
|
25
|
+
class ClassicalArrayProxy(NonSymbolicExpr, ClassicalProxy):
|
26
|
+
def __init__(
|
27
|
+
self, handle: HandleBinding, element_type: "ConcreteClassicalType", length: int
|
28
|
+
) -> None:
|
29
|
+
super().__init__(handle)
|
30
|
+
self._element_type = element_type
|
31
|
+
self._length = length
|
32
|
+
|
33
|
+
@property
|
34
|
+
def fields(self) -> Mapping[str, "ExpressionValue"]:
|
35
|
+
return {"len": self._length}
|
36
|
+
|
37
|
+
@property
|
38
|
+
def type_name(self) -> str:
|
39
|
+
return "Array"
|
40
|
+
|
41
|
+
def __getitem__(self, key: Union[slice, int, Integer]) -> ClassicalProxy:
|
42
|
+
return (
|
43
|
+
self._get_slice(key) if isinstance(key, slice) else self._get_subscript(key)
|
44
|
+
)
|
45
|
+
|
46
|
+
def _get_slice(self, slice_: slice) -> ClassicalProxy:
|
47
|
+
start = int(slice_.start)
|
48
|
+
stop = int(slice_.stop)
|
49
|
+
if start >= stop:
|
50
|
+
raise ClassiqValueError("Array slice has non-positive length")
|
51
|
+
if start < 0 or stop > self._length:
|
52
|
+
raise ClassiqValueError("Array slice is out of bounds")
|
53
|
+
return ClassicalArrayProxy(
|
54
|
+
SlicedHandleBinding(
|
55
|
+
base_handle=self.handle,
|
56
|
+
start=Expression(expr=str(start)),
|
57
|
+
end=Expression(expr=str(stop)),
|
58
|
+
),
|
59
|
+
self._element_type,
|
60
|
+
stop - start,
|
61
|
+
)
|
62
|
+
|
63
|
+
def _get_subscript(self, index_: Union[int, Integer]) -> ClassicalProxy:
|
64
|
+
index = int(index_)
|
65
|
+
if index < 0:
|
66
|
+
raise ClassiqValueError(
|
67
|
+
"Array index is out of bounds (negative indices are not supported)"
|
68
|
+
)
|
69
|
+
if index >= self._length:
|
70
|
+
raise ClassiqValueError("Array index is out of bounds")
|
71
|
+
return self._element_type.get_classical_proxy(
|
72
|
+
SubscriptHandleBinding(
|
73
|
+
base_handle=self._handle, index=Expression(expr=str(index_))
|
74
|
+
)
|
75
|
+
)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
6
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
7
|
+
|
8
|
+
|
9
|
+
class ClassicalProxy:
|
10
|
+
def __init__(self, handle: "HandleBinding") -> None:
|
11
|
+
self._handle = handle
|
12
|
+
|
13
|
+
@property
|
14
|
+
def handle(self) -> "HandleBinding":
|
15
|
+
return self._handle
|
16
|
+
|
17
|
+
def __str__(self) -> str:
|
18
|
+
return str(self.handle)
|
19
|
+
|
20
|
+
@property
|
21
|
+
def fields(self) -> Mapping[str, "ExpressionValue"]:
|
22
|
+
raise NotImplementedError
|
23
|
+
|
24
|
+
@property
|
25
|
+
def type_name(self) -> str:
|
26
|
+
raise NotImplementedError
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from typing import TYPE_CHECKING, Any
|
3
|
+
|
4
|
+
from sympy import Symbol
|
5
|
+
|
6
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
7
|
+
ClassicalProxy,
|
8
|
+
)
|
9
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
13
|
+
from classiq.interface.generator.functions.classical_type import ClassicalType
|
14
|
+
|
15
|
+
|
16
|
+
class ClassicalScalarProxy(Symbol, ClassicalProxy):
|
17
|
+
def __new__(
|
18
|
+
cls, handle: HandleBinding, *args: Any, **assumptions: bool
|
19
|
+
) -> "ClassicalScalarProxy":
|
20
|
+
return super().__new__(cls, str(handle), **assumptions)
|
21
|
+
|
22
|
+
def __init__(self, handle: HandleBinding, classical_type: "ClassicalType") -> None:
|
23
|
+
super().__init__(handle)
|
24
|
+
self._classical_type = classical_type
|
25
|
+
|
26
|
+
@property
|
27
|
+
def fields(self) -> Mapping[str, "ExpressionValue"]:
|
28
|
+
return {}
|
29
|
+
|
30
|
+
@property
|
31
|
+
def type_name(self) -> str:
|
32
|
+
return type(self._classical_type).__name__
|
@@ -0,0 +1,31 @@
|
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
5
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
6
|
+
ClassicalProxy,
|
7
|
+
)
|
8
|
+
from classiq.interface.model.handle_binding import FieldHandleBinding, HandleBinding
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
12
|
+
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
13
|
+
|
14
|
+
|
15
|
+
class ClassicalStructProxy(NonSymbolicExpr, ClassicalProxy):
|
16
|
+
def __init__(self, handle: HandleBinding, decl: "StructDeclaration") -> None:
|
17
|
+
super().__init__(handle)
|
18
|
+
self._decl = decl
|
19
|
+
|
20
|
+
@property
|
21
|
+
def fields(self) -> Mapping[str, "ExpressionValue"]:
|
22
|
+
return {
|
23
|
+
field_name: field_type.get_classical_proxy(
|
24
|
+
FieldHandleBinding(base_handle=self.handle, field_name=field_name)
|
25
|
+
)
|
26
|
+
for field_name, field_type in self._decl.variables.items()
|
27
|
+
}
|
28
|
+
|
29
|
+
@property
|
30
|
+
def type_name(self) -> str:
|
31
|
+
return f"Struct {self._decl.name}"
|
File without changes
|
@@ -6,7 +6,9 @@ from sympy import Integer
|
|
6
6
|
from classiq.interface.exceptions import ClassiqValueError
|
7
7
|
from classiq.interface.generator.expressions.expression import Expression
|
8
8
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
9
|
-
from classiq.interface.generator.expressions.qmod_sized_proxy import
|
9
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
10
|
+
QmodSizedProxy,
|
11
|
+
)
|
10
12
|
from classiq.interface.model.handle_binding import (
|
11
13
|
HandleBinding,
|
12
14
|
SlicedHandleBinding,
|
@@ -4,7 +4,9 @@ from typing import Any
|
|
4
4
|
from sympy import Symbol
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import ClassiqValueError
|
7
|
-
from classiq.interface.generator.expressions.qmod_sized_proxy import
|
7
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
8
|
+
QmodSizedProxy,
|
9
|
+
)
|
8
10
|
from classiq.interface.model.handle_binding import HandleBinding
|
9
11
|
|
10
12
|
|
@@ -2,7 +2,9 @@ from collections.abc import Mapping
|
|
2
2
|
from typing import TYPE_CHECKING
|
3
3
|
|
4
4
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
5
|
-
from classiq.interface.generator.expressions.qmod_sized_proxy import
|
5
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
6
|
+
QmodSizedProxy,
|
7
|
+
)
|
6
8
|
from classiq.interface.model.handle_binding import (
|
7
9
|
FieldHandleBinding,
|
8
10
|
HandleBinding,
|
@@ -1,39 +1,51 @@
|
|
1
|
-
from typing import TYPE_CHECKING, Any, Literal
|
1
|
+
from typing import TYPE_CHECKING, Any, Literal
|
2
2
|
|
3
3
|
import pydantic
|
4
|
-
from pydantic import ConfigDict
|
5
|
-
from
|
4
|
+
from pydantic import ConfigDict, PrivateAttr
|
5
|
+
from typing_extensions import Self
|
6
6
|
|
7
7
|
from classiq.interface.ast_node import HashableASTNode
|
8
|
-
from classiq.interface.generator.expressions.
|
8
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
9
|
+
ClassicalArrayProxy,
|
10
|
+
)
|
11
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
12
|
+
ClassicalProxy,
|
13
|
+
)
|
14
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
15
|
+
ClassicalScalarProxy,
|
16
|
+
)
|
9
17
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
18
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
10
19
|
|
11
20
|
if TYPE_CHECKING:
|
12
21
|
from classiq.interface.generator.functions.concrete_types import (
|
13
22
|
ConcreteClassicalType,
|
14
23
|
)
|
15
24
|
|
16
|
-
CLASSICAL_ATTRIBUTES = {"len", "size", "is_signed", "fraction_digits"}
|
17
|
-
|
18
|
-
NamedSymbol = Union[IndexedBase, Symbol]
|
19
|
-
|
20
25
|
|
21
26
|
class ClassicalType(HashableASTNode):
|
22
|
-
|
23
|
-
return Symbol(name)
|
27
|
+
_is_generative: bool = PrivateAttr(default=False)
|
24
28
|
|
25
29
|
model_config = ConfigDict(extra="forbid")
|
26
30
|
|
27
31
|
def __str__(self) -> str:
|
28
32
|
return str(type(self).__name__)
|
29
33
|
|
34
|
+
def set_generative(self) -> Self:
|
35
|
+
self._is_generative = True
|
36
|
+
return self
|
37
|
+
|
38
|
+
@property
|
39
|
+
def is_generative(self) -> bool:
|
40
|
+
return self._is_generative
|
41
|
+
|
42
|
+
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
43
|
+
return ClassicalScalarProxy(handle, self)
|
44
|
+
|
30
45
|
|
31
46
|
class Integer(ClassicalType):
|
32
47
|
kind: Literal["int"]
|
33
48
|
|
34
|
-
def as_symbolic(self, name: str) -> Symbol:
|
35
|
-
return Symbol(name, integer=True)
|
36
|
-
|
37
49
|
@pydantic.model_validator(mode="before")
|
38
50
|
@classmethod
|
39
51
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
@@ -43,9 +55,6 @@ class Integer(ClassicalType):
|
|
43
55
|
class Real(ClassicalType):
|
44
56
|
kind: Literal["real"]
|
45
57
|
|
46
|
-
def as_symbolic(self, name: str) -> Symbol:
|
47
|
-
return Symbol(name, real=True)
|
48
|
-
|
49
58
|
@pydantic.model_validator(mode="before")
|
50
59
|
@classmethod
|
51
60
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
@@ -65,14 +74,14 @@ class ClassicalList(ClassicalType):
|
|
65
74
|
kind: Literal["list"]
|
66
75
|
element_type: "ConcreteClassicalType"
|
67
76
|
|
68
|
-
def as_symbolic(self, name: str) -> Symbol:
|
69
|
-
return IndexedBase(name)
|
70
|
-
|
71
77
|
@pydantic.model_validator(mode="before")
|
72
78
|
@classmethod
|
73
79
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
74
80
|
return values_with_discriminator(values, "kind", "list")
|
75
81
|
|
82
|
+
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
83
|
+
raise NotImplementedError
|
84
|
+
|
76
85
|
|
77
86
|
class StructMetaType(ClassicalType):
|
78
87
|
kind: Literal["type_proxy"]
|
@@ -82,20 +91,23 @@ class StructMetaType(ClassicalType):
|
|
82
91
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
83
92
|
return values_with_discriminator(values, "kind", "type_proxy")
|
84
93
|
|
94
|
+
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
95
|
+
raise NotImplementedError
|
96
|
+
|
85
97
|
|
86
98
|
class ClassicalArray(ClassicalType):
|
87
99
|
kind: Literal["array"]
|
88
100
|
element_type: "ConcreteClassicalType"
|
89
101
|
size: pydantic.PositiveInt
|
90
102
|
|
91
|
-
def as_symbolic(self, name: str) -> list:
|
92
|
-
return [self.element_type.as_symbolic(f"{name}_{i}") for i in range(self.size)]
|
93
|
-
|
94
103
|
@pydantic.model_validator(mode="before")
|
95
104
|
@classmethod
|
96
105
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
97
106
|
return values_with_discriminator(values, "kind", "array")
|
98
107
|
|
108
|
+
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
109
|
+
return ClassicalArrayProxy(handle, self.element_type, self.size)
|
110
|
+
|
99
111
|
|
100
112
|
class OpaqueHandle(ClassicalType):
|
101
113
|
pass
|
@@ -137,12 +149,5 @@ class IQAERes(OpaqueHandle):
|
|
137
149
|
return values_with_discriminator(values, "kind", "iqae_result")
|
138
150
|
|
139
151
|
|
140
|
-
def as_symbolic(symbols: dict[str, ClassicalType]) -> dict[str, RuntimeExpression]:
|
141
|
-
return {
|
142
|
-
param_name: param_type.as_symbolic(param_name)
|
143
|
-
for param_name, param_type in symbols.items()
|
144
|
-
}
|
145
|
-
|
146
|
-
|
147
152
|
class QmodPyObject:
|
148
153
|
pass
|
@@ -4,7 +4,15 @@ from typing import TYPE_CHECKING, Any, Literal, Optional
|
|
4
4
|
import pydantic
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import ClassiqExpansionError
|
7
|
-
from classiq.interface.generator.expressions.
|
7
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
8
|
+
ClassicalProxy,
|
9
|
+
)
|
10
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
11
|
+
ClassicalStructProxy,
|
12
|
+
)
|
13
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
14
|
+
QmodQStructProxy,
|
15
|
+
)
|
8
16
|
from classiq.interface.generator.functions.classical_type import (
|
9
17
|
ClassicalType,
|
10
18
|
)
|
@@ -16,6 +24,7 @@ from classiq.interface.model.quantum_type import (
|
|
16
24
|
|
17
25
|
if TYPE_CHECKING:
|
18
26
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
27
|
+
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
19
28
|
|
20
29
|
|
21
30
|
class TypeName(ClassicalType, QuantumType):
|
@@ -24,6 +33,9 @@ class TypeName(ClassicalType, QuantumType):
|
|
24
33
|
_assigned_fields: Optional[Mapping[str, "ConcreteQuantumType"]] = (
|
25
34
|
pydantic.PrivateAttr(default=None)
|
26
35
|
)
|
36
|
+
_classical_struct_decl: Optional["StructDeclaration"] = pydantic.PrivateAttr(
|
37
|
+
default=None
|
38
|
+
)
|
27
39
|
|
28
40
|
@pydantic.model_validator(mode="before")
|
29
41
|
@classmethod
|
@@ -40,7 +52,7 @@ class TypeName(ClassicalType, QuantumType):
|
|
40
52
|
)
|
41
53
|
|
42
54
|
def get_proxy(self, handle: "HandleBinding") -> "QmodQStructProxy":
|
43
|
-
from classiq.interface.generator.expressions.qmod_qstruct_proxy import (
|
55
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
44
56
|
QmodQStructProxy,
|
45
57
|
)
|
46
58
|
|
@@ -81,6 +93,18 @@ class TypeName(ClassicalType, QuantumType):
|
|
81
93
|
field_type.is_evaluated for field_type in self.fields.values()
|
82
94
|
)
|
83
95
|
|
96
|
+
@property
|
97
|
+
def has_classical_struct_decl(self) -> bool:
|
98
|
+
return self._classical_struct_decl is not None
|
99
|
+
|
100
|
+
def set_classical_struct_decl(self, decl: "StructDeclaration") -> None:
|
101
|
+
self._classical_struct_decl = decl
|
102
|
+
|
103
|
+
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
104
|
+
if self._classical_struct_decl is None:
|
105
|
+
raise ClassiqExpansionError(f"Type {self.name!r} is undefined")
|
106
|
+
return ClassicalStructProxy(handle, self._classical_struct_decl)
|
107
|
+
|
84
108
|
|
85
109
|
class Enum(TypeName):
|
86
110
|
pass
|
@@ -1,17 +1,29 @@
|
|
1
1
|
import logging
|
2
|
+
import re
|
2
3
|
from typing import Literal, Optional, Union
|
3
4
|
|
4
5
|
import pydantic
|
5
|
-
from pydantic import ConfigDict
|
6
|
+
from pydantic import ConfigDict, Field
|
6
7
|
from typing_extensions import TypeAlias
|
7
8
|
|
9
|
+
from classiq.interface.debug_info.back_ref_util import is_allocate_or_free_by_backref
|
8
10
|
from classiq.interface.enum_utils import StrEnum
|
11
|
+
from classiq.interface.generator.compiler_keywords import (
|
12
|
+
generate_original_function_name,
|
13
|
+
)
|
9
14
|
from classiq.interface.generator.control_state import ControlState
|
10
15
|
from classiq.interface.generator.register_role import RegisterRole
|
11
16
|
from classiq.interface.generator.synthesis_metadata.synthesis_execution_data import (
|
12
17
|
ExecutionData,
|
13
18
|
)
|
14
|
-
from classiq.interface.model.
|
19
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
20
|
+
QuantumExpressionOperation,
|
21
|
+
)
|
22
|
+
from classiq.interface.model.statement_block import (
|
23
|
+
ConcreteQuantumStatement,
|
24
|
+
QuantumFunctionCall,
|
25
|
+
StatementBlock,
|
26
|
+
)
|
15
27
|
|
16
28
|
from classiq.model_expansions.capturing.mangling_utils import (
|
17
29
|
demangle_capture_name,
|
@@ -24,6 +36,11 @@ ParameterName = str
|
|
24
36
|
IOQubitMapping: TypeAlias = dict[str, tuple[int, ...]]
|
25
37
|
|
26
38
|
CLASSIQ_HIERARCHY_SEPARATOR: Literal["__"] = "__"
|
39
|
+
QASM_SEPARATOR = "_"
|
40
|
+
SPLIT_MARKER: str = "part"
|
41
|
+
PART_SUFFIX_REGEX = re.compile(
|
42
|
+
rf".+{QASM_SEPARATOR}{SPLIT_MARKER}{QASM_SEPARATOR}(\d+)$"
|
43
|
+
)
|
27
44
|
|
28
45
|
VISUALIZATION_HIDE_LIST = [
|
29
46
|
"apply_to_all",
|
@@ -120,34 +137,83 @@ class OperationLevel(StrEnum):
|
|
120
137
|
UNKNOWN = "UNKNOWN"
|
121
138
|
|
122
139
|
|
123
|
-
class
|
124
|
-
|
125
|
-
|
140
|
+
class StatementType(StrEnum):
|
141
|
+
CONTROL = "control"
|
142
|
+
POWER = "power"
|
143
|
+
INVERT = "invert"
|
144
|
+
WITHIN_APPLY = "within_apply"
|
145
|
+
ASSIGNMENT = "assignment"
|
146
|
+
REPEAT = "repeat"
|
126
147
|
|
127
148
|
|
128
149
|
class FunctionDebugInfoInterface(pydantic.BaseModel):
|
129
|
-
generated_function: Optional[GeneratedFunction] =
|
150
|
+
generated_function: Optional[GeneratedFunction] = Field(default=None)
|
130
151
|
children: list["FunctionDebugInfoInterface"]
|
131
152
|
relative_qubits: tuple[int, ...]
|
132
|
-
absolute_qubits: Optional[tuple[int, ...]] =
|
133
|
-
is_basis_gate: Optional[bool] =
|
134
|
-
is_inverse: bool =
|
135
|
-
is_allocate_or_free: bool =
|
136
|
-
level: OperationLevel =
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
back_refs: StatementBlock = pydantic.Field(default_factory=list)
|
153
|
+
absolute_qubits: Optional[tuple[int, ...]] = Field(default=None)
|
154
|
+
is_basis_gate: Optional[bool] = Field(default=None)
|
155
|
+
is_inverse: bool = Field(default=False)
|
156
|
+
is_allocate_or_free: bool = Field(default=False)
|
157
|
+
level: OperationLevel = Field(default=OperationLevel.UNKNOWN)
|
158
|
+
port_to_passed_variable_map: dict[str, str] = Field(default={})
|
159
|
+
release_by_inverse: bool = Field(default=False)
|
160
|
+
back_refs: StatementBlock = Field(default_factory=list)
|
141
161
|
|
142
162
|
model_config = ConfigDict(extra="allow")
|
143
163
|
# Temporary field to store the override debug info for parallel old/new visualization
|
144
164
|
override_debug_info: Optional["FunctionDebugInfoInterface"] = None
|
145
165
|
|
166
|
+
@property
|
167
|
+
def is_allocate_or_free_(self) -> bool:
|
168
|
+
"""
|
169
|
+
temporary measure to handle the fact that in the current release we do not have
|
170
|
+
the backref, and therefore fallback to the old field of is_allocate_or_free
|
171
|
+
"""
|
172
|
+
return (
|
173
|
+
is_allocate_or_free_by_backref(self.back_refs)
|
174
|
+
if bool(self.back_refs)
|
175
|
+
else self.is_allocate_or_free
|
176
|
+
)
|
177
|
+
|
146
178
|
@property
|
147
179
|
def name(self) -> str:
|
148
|
-
if self.generated_function
|
149
|
-
|
150
|
-
|
180
|
+
generated_name = self.generated_function.name if self.generated_function else ""
|
181
|
+
# Temp fix for currently "supported" statements (same as for level_ property)
|
182
|
+
if generated_name in {StatementType.CONTROL, StatementType.POWER}:
|
183
|
+
return generated_name
|
184
|
+
if self.first_back_ref and isinstance(self.first_back_ref, QuantumFunctionCall):
|
185
|
+
name = generate_original_function_name(self.first_back_ref.func_name)
|
186
|
+
if part_match := PART_SUFFIX_REGEX.match(generated_name):
|
187
|
+
suffix = f" [{part_match.group(1)}]"
|
188
|
+
else:
|
189
|
+
suffix = ""
|
190
|
+
return f"{name}{suffix}"
|
191
|
+
return generated_name
|
192
|
+
|
193
|
+
@property
|
194
|
+
def first_back_ref(self) -> Optional[ConcreteQuantumStatement]:
|
195
|
+
return self.back_refs[0] if self.back_refs else None
|
196
|
+
|
197
|
+
@property
|
198
|
+
def level_(self) -> OperationLevel:
|
199
|
+
# Temp fix for currently "supported" statements
|
200
|
+
if self.name in {StatementType.CONTROL, StatementType.POWER}:
|
201
|
+
return OperationLevel.QMOD_STATEMENT
|
202
|
+
|
203
|
+
back_ref = self.first_back_ref
|
204
|
+
if back_ref is None:
|
205
|
+
# This is the expected behavior for the case where there's not back ref.
|
206
|
+
# We will use it once we can rely on the existence of the back ref in
|
207
|
+
# all expected cases (non-engine calls)
|
208
|
+
# return OperationLevel.ENGINE_FUNCTION_CALL
|
209
|
+
return self.level
|
210
|
+
if isinstance(back_ref, QuantumFunctionCall):
|
211
|
+
return OperationLevel.QMOD_FUNCTION_CALL
|
212
|
+
# Temp "fix" for assignment statements until we have a way to fully
|
213
|
+
# distinguish them and to properly display them
|
214
|
+
if isinstance(back_ref, QuantumExpressionOperation):
|
215
|
+
return OperationLevel.ENGINE_FUNCTION_CALL
|
216
|
+
return OperationLevel.QMOD_STATEMENT
|
151
217
|
|
152
218
|
@property
|
153
219
|
def registers(self) -> list[GeneratedRegister]:
|
@@ -167,15 +233,6 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
167
233
|
return list()
|
168
234
|
return self.generated_function.control_states
|
169
235
|
|
170
|
-
@staticmethod
|
171
|
-
def create_parameters_from_dict(
|
172
|
-
parameters: dict[str, str],
|
173
|
-
) -> list[OperationParameter]:
|
174
|
-
return [
|
175
|
-
OperationParameter(label=key, value=value)
|
176
|
-
for key, value in parameters.items()
|
177
|
-
]
|
178
|
-
|
179
236
|
def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
|
180
237
|
if self.absolute_qubits is None:
|
181
238
|
return self
|
@@ -117,7 +117,6 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
117
117
|
instruction_set: Optional[QuantumInstructionSet] = None,
|
118
118
|
) -> quantum_code.QuantumCode:
|
119
119
|
initial_values = initial_values or self.initial_values
|
120
|
-
|
121
120
|
if instruction_set is not None:
|
122
121
|
code, syntax = (
|
123
122
|
self.program_circuit.get_code(instruction_set),
|
@@ -75,7 +75,7 @@ class EnumDeclaration(HashableASTNode):
|
|
75
75
|
|
76
76
|
|
77
77
|
def declaration_from_enum(enum_type: EnumMeta) -> EnumDeclaration:
|
78
|
-
members
|
78
|
+
members = _get_members(enum_type)
|
79
79
|
return EnumDeclaration(
|
80
80
|
name=enum_type.__name__,
|
81
81
|
members={
|
@@ -83,3 +83,14 @@ def declaration_from_enum(enum_type: EnumMeta) -> EnumDeclaration:
|
|
83
83
|
for member in sorted(members, key=lambda member: member.value)
|
84
84
|
},
|
85
85
|
)
|
86
|
+
|
87
|
+
|
88
|
+
def _get_members(enum_type: EnumMeta) -> list[Enum]:
|
89
|
+
members: list[Enum] = list(enum_type)
|
90
|
+
for member in members:
|
91
|
+
if not isinstance(member.value, int):
|
92
|
+
raise ClassiqValueError(
|
93
|
+
f"Member {member.name!r} of enum {enum_type.__name__!r} has a "
|
94
|
+
f"non-integer value {member.value!r}"
|
95
|
+
)
|
96
|
+
return members
|
@@ -7,7 +7,6 @@ from pydantic import ConfigDict
|
|
7
7
|
from classiq.interface.enum_utils import StrEnum
|
8
8
|
from classiq.interface.generator.generated_circuit_data import (
|
9
9
|
OperationLevel,
|
10
|
-
OperationParameter,
|
11
10
|
)
|
12
11
|
from classiq.interface.generator.hardware.hardware_data import SynthesisHardwareData
|
13
12
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
@@ -114,7 +113,6 @@ class Operation(pydantic.BaseModel):
|
|
114
113
|
control_qubits: tuple[int, ...] = pydantic.Field(default_factory=tuple)
|
115
114
|
auxiliary_qubits: tuple[int, ...]
|
116
115
|
target_qubits: tuple[int, ...]
|
117
|
-
parameters: list[OperationParameter] = pydantic.Field(default_factory=list)
|
118
116
|
operation_level: OperationLevel
|
119
117
|
operation_type: OperationType = pydantic.Field(
|
120
118
|
description="Identifies unique operations that are visualized differently"
|
@@ -10,13 +10,6 @@ if TYPE_CHECKING:
|
|
10
10
|
from classiq.interface.model.statement_block import StatementBlock
|
11
11
|
|
12
12
|
|
13
|
-
class FunctionSynthesisData(pydantic.BaseModel):
|
14
|
-
should_synthesize_separately: bool = pydantic.Field(
|
15
|
-
default=False,
|
16
|
-
description="Whether the function should be synthesized separately.",
|
17
|
-
)
|
18
|
-
|
19
|
-
|
20
13
|
class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
|
21
14
|
"""
|
22
15
|
Facilitates the creation of a user-defined composite function
|
@@ -28,6 +21,3 @@ class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
|
|
28
21
|
body: "StatementBlock" = pydantic.Field(
|
29
22
|
default_factory=list, description="List of function calls to perform."
|
30
23
|
)
|
31
|
-
synthesis_data: FunctionSynthesisData = pydantic.Field(
|
32
|
-
default_factory=FunctionSynthesisData, deprecated=True, exclude=True
|
33
|
-
)
|