classiq 0.65.4__py3-none-any.whl → 0.66.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/_internals/api_wrapper.py +43 -0
- classiq/applications/qnn/qlayer.py +65 -3
- classiq/execution/execution_session.py +0 -2
- classiq/execution/iqcc.py +66 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +15 -1
- classiq/interface/backend/backend_preferences.py +0 -14
- classiq/interface/debug_info/debug_info.py +2 -0
- classiq/interface/execution/iqcc.py +25 -0
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +1 -13
- classiq/interface/generator/visitor.py +7 -4
- classiq/interface/model/classical_if.py +4 -0
- classiq/interface/model/control.py +4 -0
- classiq/interface/model/invert.py +4 -0
- classiq/interface/model/model.py +3 -1
- classiq/interface/model/model_visitor.py +14 -0
- classiq/interface/model/power.py +4 -0
- classiq/interface/model/quantum_statement.py +3 -3
- classiq/interface/model/repeat.py +4 -0
- classiq/interface/model/within_apply_operation.py +4 -0
- classiq/interface/server/routes.py +6 -0
- classiq/model_expansions/closure.py +0 -11
- classiq/model_expansions/evaluators/quantum_type_utils.py +6 -6
- classiq/model_expansions/expression_evaluator.py +10 -1
- classiq/model_expansions/interpreters/base_interpreter.py +28 -18
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +58 -1
- classiq/model_expansions/interpreters/generative_interpreter.py +7 -13
- classiq/model_expansions/quantum_operations/allocate.py +69 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +7 -6
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +4 -4
- classiq/model_expansions/quantum_operations/emitter.py +2 -15
- classiq/model_expansions/quantum_operations/quantum_function_call.py +22 -0
- classiq/model_expansions/quantum_operations/shallow_emitter.py +21 -35
- classiq/model_expansions/scope_initialization.py +49 -34
- classiq/model_expansions/transformers/model_renamer.py +98 -0
- classiq/model_expansions/transformers/var_splitter.py +7 -82
- classiq/open_library/functions/__init__.py +8 -0
- classiq/open_library/functions/amplitude_amplification.py +92 -0
- classiq/open_library/functions/grover.py +5 -5
- classiq/qmod/builtins/__init__.py +1 -1
- classiq/qmod/builtins/functions/__init__.py +0 -2
- classiq/qmod/builtins/functions/allocation.py +1 -26
- classiq/qmod/builtins/operations.py +12 -6
- classiq/qmod/generative.py +6 -4
- classiq/qmod/native/pretty_printer.py +3 -2
- classiq/qmod/pretty_print/pretty_printer.py +3 -1
- classiq/qmod/qmod_variable.py +6 -1
- classiq/qmod/semantics/annotation/call_annotation.py +30 -2
- classiq/qmod/semantics/annotation/qstruct_annotator.py +2 -2
- classiq/qmod/semantics/error_manager.py +20 -6
- classiq/qmod/semantics/static_semantics_visitor.py +3 -40
- classiq/qmod/semantics/validation/constants_validation.py +2 -3
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +6 -9
- classiq/qmod/semantics/validation/main_validation.py +2 -3
- classiq/qmod/semantics/validation/model_validation.py +25 -0
- classiq/qmod/semantics/validation/signature_validation.py +24 -0
- classiq/qmod/semantics/validation/types_validation.py +45 -46
- classiq/qmod/utilities.py +12 -0
- {classiq-0.65.4.dist-info → classiq-0.66.1.dist-info}/METADATA +1 -1
- {classiq-0.65.4.dist-info → classiq-0.66.1.dist-info}/RECORD +61 -56
- classiq/model_expansions/expression_renamer.py +0 -76
- {classiq-0.65.4.dist-info → classiq-0.66.1.dist-info}/WHEEL +0 -0
classiq/qmod/qmod_variable.py
CHANGED
@@ -22,6 +22,7 @@ from typing_extensions import ParamSpec, Self, _AnnotatedAlias
|
|
22
22
|
|
23
23
|
from classiq.interface.exceptions import ClassiqValueError
|
24
24
|
from classiq.interface.generator.expressions.expression import Expression
|
25
|
+
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
25
26
|
from classiq.interface.generator.expressions.qmod_qarray_proxy import (
|
26
27
|
ILLEGAL_SLICE_MSG,
|
27
28
|
ILLEGAL_SLICING_STEP_MSG,
|
@@ -185,6 +186,10 @@ class QVar(Symbolic):
|
|
185
186
|
return interpret_expression(str(self.size))
|
186
187
|
return CParamScalar(f"get_field({self}, 'size')")
|
187
188
|
|
189
|
+
@property
|
190
|
+
def type_name(self) -> str:
|
191
|
+
return self.get_qmod_type().type_name
|
192
|
+
|
188
193
|
|
189
194
|
_Q = TypeVar("_Q", bound=QVar)
|
190
195
|
Output = Annotated[_Q, PortDeclarationDirection.Output]
|
@@ -414,7 +419,7 @@ class QNum(Generic[_P], QScalar):
|
|
414
419
|
return _GenericAlias(cls, args)
|
415
420
|
|
416
421
|
|
417
|
-
class QArray(ArrayBase[_P], QVar):
|
422
|
+
class QArray(ArrayBase[_P], QVar, NonSymbolicExpr):
|
418
423
|
CONSTRUCTOR_DEPTH: int = 3
|
419
424
|
|
420
425
|
# TODO [CAD-18620]: improve type hints
|
@@ -3,8 +3,17 @@ from contextlib import contextmanager
|
|
3
3
|
from typing import Any
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqError
|
6
|
-
from classiq.interface.generator.
|
6
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
|
+
from classiq.interface.generator.functions.classical_type import Integer
|
8
|
+
from classiq.interface.generator.functions.port_declaration import (
|
9
|
+
PortDeclarationDirection,
|
10
|
+
)
|
11
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
12
|
+
ClassicalParameterDeclaration,
|
13
|
+
)
|
14
|
+
from classiq.interface.model.model_visitor import ModelVisitor
|
7
15
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
16
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
8
17
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
9
18
|
from classiq.interface.model.quantum_function_declaration import (
|
10
19
|
AnonQuantumOperandDeclaration,
|
@@ -14,17 +23,36 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
14
23
|
from classiq.interface.model.quantum_lambda_function import (
|
15
24
|
QuantumLambdaFunction,
|
16
25
|
)
|
26
|
+
from classiq.interface.model.quantum_type import QuantumBitvector
|
17
27
|
|
18
28
|
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
19
29
|
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
20
30
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
21
31
|
from classiq.qmod.semantics.lambdas import get_renamed_parameters
|
22
32
|
|
33
|
+
ALLOCATE_DECL_FOR_COMPATIBILITY = QuantumFunctionDeclaration(
|
34
|
+
name="allocate",
|
35
|
+
positional_arg_declarations=[
|
36
|
+
ClassicalParameterDeclaration(
|
37
|
+
name="num_qubits",
|
38
|
+
classical_type=Integer(),
|
39
|
+
),
|
40
|
+
PortDeclaration(
|
41
|
+
name="out",
|
42
|
+
quantum_type=QuantumBitvector(length=Expression(expr="num_qubits")),
|
43
|
+
direction=PortDeclarationDirection.Output,
|
44
|
+
),
|
45
|
+
],
|
46
|
+
)
|
47
|
+
|
23
48
|
|
24
49
|
def _annotate_function_call_decl(
|
25
50
|
fc: QuantumFunctionCall,
|
26
51
|
function_dict: Mapping[str, QuantumFunctionDeclaration],
|
27
52
|
) -> None:
|
53
|
+
if fc.function == "allocate": # FIXME: Remove compatibility (CAD-25935)
|
54
|
+
fc.set_func_decl(ALLOCATE_DECL_FOR_COMPATIBILITY)
|
55
|
+
return
|
28
56
|
if fc._func_decl is None:
|
29
57
|
func_decl = function_dict.get(fc.func_name)
|
30
58
|
if func_decl is None:
|
@@ -46,7 +74,7 @@ def _annotate_function_call_decl(
|
|
46
74
|
qlambda.set_op_decl(param)
|
47
75
|
|
48
76
|
|
49
|
-
class _CallLambdaAnnotator(
|
77
|
+
class _CallLambdaAnnotator(ModelVisitor):
|
50
78
|
def __init__(
|
51
79
|
self, quantum_functions: Mapping[str, QuantumFunctionDeclaration]
|
52
80
|
) -> None:
|
@@ -1,10 +1,10 @@
|
|
1
1
|
from classiq.interface.generator.functions.type_name import TypeName
|
2
|
-
from classiq.interface.
|
2
|
+
from classiq.interface.model.model_visitor import ModelVisitor
|
3
3
|
|
4
4
|
from classiq.qmod.model_state_container import QMODULE
|
5
5
|
|
6
6
|
|
7
|
-
class QStructAnnotator(
|
7
|
+
class QStructAnnotator(ModelVisitor):
|
8
8
|
def __init__(self) -> None:
|
9
9
|
self._visited: set[TypeName] = set()
|
10
10
|
|
@@ -4,7 +4,7 @@ from typing import Optional
|
|
4
4
|
|
5
5
|
from classiq.interface.ast_node import ASTNode
|
6
6
|
from classiq.interface.exceptions import CLASSIQ_SLACK_COMMUNITY_LINK
|
7
|
-
from classiq.interface.source_reference import SourceReferencedError
|
7
|
+
from classiq.interface.source_reference import SourceReference, SourceReferencedError
|
8
8
|
|
9
9
|
|
10
10
|
class ErrorManager:
|
@@ -22,6 +22,12 @@ class ErrorManager:
|
|
22
22
|
self._call_stack: list[str] = []
|
23
23
|
self._ignore_errors: bool = False
|
24
24
|
|
25
|
+
@property
|
26
|
+
def _current_source_ref(self) -> Optional[SourceReference]:
|
27
|
+
if self._current_nodes_stack:
|
28
|
+
return self._current_nodes_stack[-1].source_ref
|
29
|
+
return None
|
30
|
+
|
25
31
|
@contextmanager
|
26
32
|
def ignore_errors_context(self) -> Iterator[None]:
|
27
33
|
previous = self._ignore_errors
|
@@ -35,17 +41,25 @@ class ErrorManager:
|
|
35
41
|
def annotated_errors(self) -> list[str]:
|
36
42
|
return [str(error) for error in self._errors]
|
37
43
|
|
38
|
-
def add_error(
|
44
|
+
def add_error(
|
45
|
+
self,
|
46
|
+
error: str,
|
47
|
+
*,
|
48
|
+
source_ref: Optional[SourceReference] = None,
|
49
|
+
function: Optional[str] = None
|
50
|
+
) -> None:
|
39
51
|
if not self._ignore_errors:
|
40
52
|
self._errors.append(
|
41
53
|
SourceReferencedError(
|
42
54
|
error=error.replace(CLASSIQ_SLACK_COMMUNITY_LINK, ""),
|
43
55
|
source_ref=(
|
44
|
-
|
45
|
-
if
|
46
|
-
else
|
56
|
+
source_ref
|
57
|
+
if source_ref is not None
|
58
|
+
else self._current_source_ref
|
59
|
+
),
|
60
|
+
function=(
|
61
|
+
function if function is not None else self.current_function
|
47
62
|
),
|
48
|
-
function=self.current_function,
|
49
63
|
)
|
50
64
|
)
|
51
65
|
|
@@ -13,7 +13,6 @@ from classiq.interface.generator.functions.concrete_types import ConcreteQuantum
|
|
13
13
|
from classiq.interface.generator.functions.port_declaration import (
|
14
14
|
PortDeclarationDirection,
|
15
15
|
)
|
16
|
-
from classiq.interface.generator.visitor import Visitor
|
17
16
|
from classiq.interface.model.handle_binding import (
|
18
17
|
FieldHandleBinding,
|
19
18
|
HandleBinding,
|
@@ -22,6 +21,7 @@ from classiq.interface.model.handle_binding import (
|
|
22
21
|
)
|
23
22
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
24
23
|
from classiq.interface.model.model import Model
|
24
|
+
from classiq.interface.model.model_visitor import ModelVisitor
|
25
25
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
26
26
|
from classiq.interface.model.port_declaration import PortDeclaration
|
27
27
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
@@ -50,26 +50,11 @@ from classiq.qmod.semantics.annotation.call_annotation import resolve_function_c
|
|
50
50
|
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
51
51
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
52
52
|
from classiq.qmod.semantics.lambdas import get_renamed_parameters
|
53
|
-
from classiq.qmod.semantics.validation.constants_validation import (
|
54
|
-
check_duplicate_constants,
|
55
|
-
)
|
56
53
|
from classiq.qmod.semantics.validation.func_call_validation import (
|
57
54
|
check_no_overlapping_quantum_args,
|
58
55
|
validate_call_arguments,
|
59
56
|
)
|
60
|
-
from classiq.qmod.semantics.validation.function_name_collisions_validation import (
|
61
|
-
_check_function_name_collisions,
|
62
|
-
)
|
63
57
|
from classiq.qmod.semantics.validation.handle_validation import resolve_handle
|
64
|
-
from classiq.qmod.semantics.validation.main_validation import validate_main_function
|
65
|
-
from classiq.qmod.semantics.validation.types_validation import (
|
66
|
-
check_cstruct_has_fields,
|
67
|
-
check_duplicate_types,
|
68
|
-
check_qstruct_fields_are_defined,
|
69
|
-
check_qstruct_flexibility,
|
70
|
-
check_qstruct_has_fields,
|
71
|
-
check_qstruct_is_not_recursive,
|
72
|
-
)
|
73
58
|
|
74
59
|
HANDLE_BINDING_PART_MESSAGE = {
|
75
60
|
SubscriptHandleBinding: "array subscript",
|
@@ -92,7 +77,7 @@ class StaticScope:
|
|
92
77
|
self.variables_to_types = variables_to_types
|
93
78
|
|
94
79
|
|
95
|
-
class StaticSemanticsVisitor(
|
80
|
+
class StaticSemanticsVisitor(ModelVisitor):
|
96
81
|
def __init__(
|
97
82
|
self,
|
98
83
|
functions_dict: Mapping[str, QuantumFunctionDeclaration],
|
@@ -114,17 +99,6 @@ class StaticSemanticsVisitor(Visitor):
|
|
114
99
|
self._scope.pop()
|
115
100
|
|
116
101
|
def visit_Model(self, model: Model) -> None:
|
117
|
-
check_duplicate_types([*model.enums, *model.types, *model.qstructs])
|
118
|
-
check_duplicate_constants(model.constants)
|
119
|
-
for qstruct in model.qstructs:
|
120
|
-
check_qstruct_has_fields(qstruct)
|
121
|
-
if check_qstruct_fields_are_defined(
|
122
|
-
qstruct
|
123
|
-
) and check_qstruct_is_not_recursive(qstruct):
|
124
|
-
check_qstruct_flexibility(qstruct)
|
125
|
-
for cstruct in model.types:
|
126
|
-
check_cstruct_has_fields(cstruct)
|
127
|
-
validate_main_function(model.main_func)
|
128
102
|
self.visit_BaseModel(model)
|
129
103
|
|
130
104
|
def visit_NativeFunctionDefinition(
|
@@ -141,16 +115,6 @@ class StaticSemanticsVisitor(Visitor):
|
|
141
115
|
},
|
142
116
|
)
|
143
117
|
with self.scoped_visit(scope), self._error_manager.call(func_def.name):
|
144
|
-
parameter_declaration_names = [
|
145
|
-
decl.name for decl in func_def.positional_arg_declarations
|
146
|
-
]
|
147
|
-
seen_names: set[str] = set()
|
148
|
-
for name in parameter_declaration_names:
|
149
|
-
if name in seen_names:
|
150
|
-
self._error_manager.add_error(
|
151
|
-
f"duplicate parameter declaration name {name!r}"
|
152
|
-
)
|
153
|
-
seen_names.add(name)
|
154
118
|
if len(func_def.body) == 0:
|
155
119
|
return
|
156
120
|
self.visit(func_def.body)
|
@@ -165,7 +129,7 @@ class StaticSemanticsVisitor(Visitor):
|
|
165
129
|
and handle_state is not expected_terminal_state
|
166
130
|
):
|
167
131
|
self._error_manager.add_error(
|
168
|
-
f"At the end of the function,
|
132
|
+
f"At the end of the function, variable {port_decl.name!r} is expected to be {expected_terminal_state.name.lower()} but it isn't"
|
169
133
|
)
|
170
134
|
|
171
135
|
def visit_WithinApply(self, within_apply: WithinApply) -> None:
|
@@ -351,7 +315,6 @@ class StaticSemanticsVisitor(Visitor):
|
|
351
315
|
def static_semantics_analysis_pass(
|
352
316
|
model: Model, error_type: Optional[type[Exception]] = ClassiqSemanticError
|
353
317
|
) -> None:
|
354
|
-
_check_function_name_collisions(model, error_type)
|
355
318
|
QStructAnnotator().visit(model)
|
356
319
|
functions = {**BUILTIN_FUNCTION_DECLARATIONS, **model.function_dict}
|
357
320
|
resolve_function_calls(model, functions)
|
@@ -1,16 +1,15 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
2
|
|
3
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
3
4
|
from classiq.interface.generator.constant import Constant
|
4
5
|
|
5
6
|
from classiq.qmod.builtins import BUILTIN_CONSTANTS
|
6
|
-
from classiq.qmod.semantics.error_manager import ErrorManager
|
7
7
|
|
8
8
|
|
9
9
|
def check_duplicate_constants(constants: Sequence[Constant]) -> None:
|
10
10
|
known_constants = {constant.name: constant for constant in BUILTIN_CONSTANTS}
|
11
11
|
for constant in constants:
|
12
12
|
if constant.name in known_constants:
|
13
|
-
|
14
|
-
ErrorManager().add_error(f"Constant {constant.name!r} already exists")
|
13
|
+
raise ClassiqExpansionError(f"Constant {constant.name!r} already exists")
|
15
14
|
else:
|
16
15
|
known_constants[constant.name] = constant
|
@@ -1,23 +1,20 @@
|
|
1
|
-
from
|
2
|
-
|
1
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
3
2
|
from classiq.interface.model.model import Model
|
4
3
|
|
5
4
|
from classiq.qmod.builtins.functions import CORE_LIB_DECLS
|
6
5
|
|
7
6
|
|
8
|
-
def
|
9
|
-
model: Model, error_type: Optional[type[Exception]]
|
10
|
-
) -> None:
|
11
|
-
if error_type is None:
|
12
|
-
return
|
7
|
+
def check_function_name_collisions(model: Model) -> None:
|
13
8
|
redefined_functions = [
|
14
9
|
function.name
|
15
10
|
for function in CORE_LIB_DECLS
|
16
11
|
if function.name in model.function_dict
|
17
12
|
]
|
18
13
|
if len(redefined_functions) == 1:
|
19
|
-
raise
|
14
|
+
raise ClassiqExpansionError(
|
20
15
|
f"Cannot redefine built-in function {redefined_functions[0]!r}"
|
21
16
|
)
|
22
17
|
elif len(redefined_functions) > 1:
|
23
|
-
raise
|
18
|
+
raise ClassiqExpansionError(
|
19
|
+
f"Cannot redefine built-in functions: {redefined_functions}"
|
20
|
+
)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
1
2
|
from classiq.interface.generator.functions.classical_type import (
|
2
3
|
ClassicalArray,
|
3
4
|
ClassicalList,
|
@@ -7,7 +8,6 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
|
|
7
8
|
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
8
9
|
|
9
10
|
from classiq import ClassicalParameterDeclaration
|
10
|
-
from classiq.qmod.semantics.error_manager import append_error
|
11
11
|
|
12
12
|
|
13
13
|
def validate_main_function(func: NativeFunctionDefinition) -> None:
|
@@ -24,8 +24,7 @@ def _validate_main_classical_param_type(
|
|
24
24
|
param: ConcreteClassicalType, param_name: str
|
25
25
|
) -> None:
|
26
26
|
if isinstance(param, ClassicalList):
|
27
|
-
|
28
|
-
param,
|
27
|
+
raise ClassiqExpansionError(
|
29
28
|
f"Classical array parameter {param_name!r} of function 'main' must must "
|
30
29
|
f"specify array length",
|
31
30
|
)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from classiq.interface.model.model import Model
|
2
|
+
|
3
|
+
from classiq.qmod.semantics.validation.constants_validation import (
|
4
|
+
check_duplicate_constants,
|
5
|
+
)
|
6
|
+
from classiq.qmod.semantics.validation.function_name_collisions_validation import (
|
7
|
+
check_function_name_collisions,
|
8
|
+
)
|
9
|
+
from classiq.qmod.semantics.validation.main_validation import validate_main_function
|
10
|
+
from classiq.qmod.semantics.validation.types_validation import (
|
11
|
+
check_duplicate_types,
|
12
|
+
validate_cstruct,
|
13
|
+
validate_qstruct,
|
14
|
+
)
|
15
|
+
|
16
|
+
|
17
|
+
def validate_model(model: Model) -> None:
|
18
|
+
check_duplicate_types([*model.enums, *model.types, *model.qstructs])
|
19
|
+
check_duplicate_constants(model.constants)
|
20
|
+
for qstruct in model.qstructs:
|
21
|
+
validate_qstruct(qstruct)
|
22
|
+
for cstruct in model.types:
|
23
|
+
validate_cstruct(cstruct)
|
24
|
+
validate_main_function(model.main_func)
|
25
|
+
check_function_name_collisions(model)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
from collections import Counter
|
2
|
+
from collections.abc import Sequence
|
3
|
+
|
4
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
5
|
+
from classiq.interface.model.quantum_function_declaration import (
|
6
|
+
AnonPositionalArg,
|
7
|
+
AnonQuantumOperandDeclaration,
|
8
|
+
)
|
9
|
+
|
10
|
+
|
11
|
+
def _check_duplicate_param_names(params: Sequence[AnonPositionalArg]) -> None:
|
12
|
+
param_names = [param.name for param in params if param.name is not None]
|
13
|
+
duplicates = [
|
14
|
+
param_name for param_name, count in Counter(param_names).items() if count > 1
|
15
|
+
]
|
16
|
+
if len(duplicates) > 0:
|
17
|
+
raise ClassiqExpansionError(f"Duplicate parameter name {duplicates[0]!r}")
|
18
|
+
|
19
|
+
|
20
|
+
def validate_function_signature(params: Sequence[AnonPositionalArg]) -> None:
|
21
|
+
_check_duplicate_param_names(params)
|
22
|
+
for param in params:
|
23
|
+
if isinstance(param, AnonQuantumOperandDeclaration):
|
24
|
+
validate_function_signature(param.positional_arg_declarations)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
2
|
from typing import Union
|
3
3
|
|
4
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
4
5
|
from classiq.interface.generator.functions.type_name import TypeName
|
5
6
|
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
6
7
|
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
@@ -10,7 +11,8 @@ from classiq.interface.model.quantum_type import QuantumBitvector
|
|
10
11
|
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
11
12
|
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
12
13
|
from classiq.qmod.model_state_container import QMODULE
|
13
|
-
|
14
|
+
|
15
|
+
TYPE_EXISTS_ERROR_MESSAGE = "Type {!r} already exists"
|
14
16
|
|
15
17
|
|
16
18
|
def check_duplicate_types(
|
@@ -20,13 +22,12 @@ def check_duplicate_types(
|
|
20
22
|
known_types |= {type_.name for type_ in BUILTIN_STRUCT_DECLARATIONS.values()}
|
21
23
|
for type_ in types:
|
22
24
|
if type_.name in known_types:
|
23
|
-
|
24
|
-
ErrorManager().add_error(f"Type {type_.name!r} already exists")
|
25
|
+
raise ClassiqExpansionError(TYPE_EXISTS_ERROR_MESSAGE.format(type_.name))
|
25
26
|
else:
|
26
27
|
known_types.add(type_.name)
|
27
28
|
|
28
29
|
|
29
|
-
def
|
30
|
+
def _check_qstruct_flexibility(qstruct: QStructDeclaration) -> None:
|
30
31
|
_check_qstruct_no_array_without_size_and_element_size(qstruct)
|
31
32
|
_check_qstruct_at_most_one_type_without_size(qstruct)
|
32
33
|
|
@@ -42,12 +43,11 @@ def _check_qstruct_no_array_without_size_and_element_size(
|
|
42
43
|
and not field_type.element_type.has_size_in_bits
|
43
44
|
]
|
44
45
|
if len(offending_array_fields) > 0:
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
)
|
46
|
+
raise ClassiqExpansionError(
|
47
|
+
f"Quantum struct {qstruct.name} contains arrays whose neither length "
|
48
|
+
f"nor element size are constants. Offending fields: "
|
49
|
+
f"{', '.join(offending_array_fields)}"
|
50
|
+
)
|
51
51
|
|
52
52
|
|
53
53
|
def _check_qstruct_at_most_one_type_without_size(qstruct: QStructDeclaration) -> None:
|
@@ -57,46 +57,31 @@ def _check_qstruct_at_most_one_type_without_size(qstruct: QStructDeclaration) ->
|
|
57
57
|
if not field_type.has_size_in_bits
|
58
58
|
]
|
59
59
|
if len(fields_without_size) > 1:
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
)
|
60
|
+
raise ClassiqExpansionError(
|
61
|
+
f"Quantum struct {qstruct.name} has more than one field whose size is "
|
62
|
+
f"not constant. Offending fields: {', '.join(fields_without_size)}"
|
63
|
+
)
|
65
64
|
|
66
65
|
|
67
|
-
def
|
68
|
-
all_defined = True
|
66
|
+
def _check_qstruct_fields_are_defined(qstruct: QStructDeclaration) -> None:
|
69
67
|
for field_type in qstruct.fields.values():
|
70
68
|
if (
|
71
69
|
isinstance(field_type, TypeName)
|
72
70
|
and field_type.name not in QMODULE.qstruct_decls
|
73
71
|
):
|
74
|
-
|
75
|
-
|
76
|
-
f"Quantum struct {field_type.name!r} is not defined."
|
77
|
-
)
|
78
|
-
all_defined = False
|
79
|
-
return all_defined
|
80
|
-
|
81
|
-
|
82
|
-
def check_qstruct_has_fields(qstruct: QStructDeclaration) -> None:
|
83
|
-
if len(qstruct.fields) == 0:
|
84
|
-
with ErrorManager().node_context(qstruct):
|
85
|
-
ErrorManager().add_error(
|
86
|
-
f"Quantum struct {qstruct.name!r} must have at least one field."
|
72
|
+
raise ClassiqExpansionError(
|
73
|
+
f"Quantum struct {field_type.name!r} is not defined."
|
87
74
|
)
|
88
75
|
|
89
76
|
|
90
|
-
def
|
91
|
-
if len(
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
)
|
77
|
+
def _check_qstruct_has_fields(qstruct: QStructDeclaration) -> None:
|
78
|
+
if len(qstruct.fields) == 0:
|
79
|
+
raise ClassiqExpansionError(
|
80
|
+
f"Quantum struct {qstruct.name!r} must have at least one field."
|
81
|
+
)
|
96
82
|
|
97
83
|
|
98
|
-
def
|
99
|
-
non_recursive = True
|
84
|
+
def _check_qstruct_is_not_recursive(qstruct: QStructDeclaration) -> None:
|
100
85
|
for main_field_name, main_field in qstruct.fields.items():
|
101
86
|
if (
|
102
87
|
not isinstance(main_field, TypeName)
|
@@ -109,13 +94,10 @@ def check_qstruct_is_not_recursive(qstruct: QStructDeclaration) -> bool:
|
|
109
94
|
while stack:
|
110
95
|
qstruct = stack.pop()
|
111
96
|
if qstruct.name in seen_qstructs:
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
)
|
117
|
-
non_recursive = False
|
118
|
-
break
|
97
|
+
raise ClassiqExpansionError(
|
98
|
+
f"Declaration of field {main_field_name!r} in quantum struct "
|
99
|
+
f"{qstruct.name!r} creates a recursive definition."
|
100
|
+
)
|
119
101
|
seen_qstructs.add(qstruct.name)
|
120
102
|
stack.extend(
|
121
103
|
[
|
@@ -125,4 +107,21 @@ def check_qstruct_is_not_recursive(qstruct: QStructDeclaration) -> bool:
|
|
125
107
|
and field.name in QMODULE.qstruct_decls
|
126
108
|
]
|
127
109
|
)
|
128
|
-
|
110
|
+
|
111
|
+
|
112
|
+
def validate_qstruct(qstruct: QStructDeclaration) -> None:
|
113
|
+
_check_qstruct_has_fields(qstruct)
|
114
|
+
_check_qstruct_fields_are_defined(qstruct)
|
115
|
+
_check_qstruct_is_not_recursive(qstruct)
|
116
|
+
_check_qstruct_flexibility(qstruct)
|
117
|
+
|
118
|
+
|
119
|
+
def _check_cstruct_has_fields(cstruct: StructDeclaration) -> None:
|
120
|
+
if len(cstruct.variables) == 0:
|
121
|
+
raise ClassiqExpansionError(
|
122
|
+
f"Classical struct {cstruct.name!r} must have at least one field."
|
123
|
+
)
|
124
|
+
|
125
|
+
|
126
|
+
def validate_cstruct(cstruct: StructDeclaration) -> None:
|
127
|
+
_check_cstruct_has_fields(cstruct)
|
classiq/qmod/utilities.py
CHANGED
@@ -7,6 +7,9 @@ from enum import Enum as PythonEnum
|
|
7
7
|
from types import FrameType
|
8
8
|
from typing import Any, ForwardRef, Literal, Optional, get_args, get_origin, overload
|
9
9
|
|
10
|
+
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
11
|
+
QmodStructInstance,
|
12
|
+
)
|
10
13
|
from classiq.interface.source_reference import SourceReference
|
11
14
|
|
12
15
|
DEFAULT_DECIMAL_PRECISION = 4
|
@@ -89,6 +92,15 @@ def qmod_val_to_expr_str(val: Any) -> str:
|
|
89
92
|
)
|
90
93
|
return f"struct_literal({type(val).__name__}, {kwargs_str})"
|
91
94
|
|
95
|
+
if isinstance(val, QmodStructInstance):
|
96
|
+
kwargs_str = ", ".join(
|
97
|
+
[
|
98
|
+
f"{field_name}={qmod_val_to_expr_str(field_val)}"
|
99
|
+
for field_name, field_val in val.fields.items()
|
100
|
+
]
|
101
|
+
)
|
102
|
+
return f"struct_literal({val.struct_declaration.name}, {kwargs_str})"
|
103
|
+
|
92
104
|
if isinstance(val, list):
|
93
105
|
elements_str = ", ".join([qmod_val_to_expr_str(elem) for elem in val])
|
94
106
|
return f"[{elements_str}]"
|