classiq 0.63.1__py3-none-any.whl → 0.65.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 +30 -0
- classiq/analyzer/url_utils.py +2 -3
- classiq/applications/chemistry/chemistry_model_constructor.py +8 -9
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +2 -5
- classiq/applications/finance/finance_model_constructor.py +7 -12
- classiq/applications/grover/grover_model_constructor.py +4 -6
- classiq/applications/qsvm/qsvm_model_constructor.py +6 -4
- classiq/execution/execution_session.py +14 -13
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/result.py +1 -2
- classiq/interface/backend/backend_preferences.py +1 -9
- classiq/interface/executor/result.py +6 -3
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +11 -13
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/helpers/datastructures.py +26 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/allocate.py +16 -0
- classiq/interface/model/handle_binding.py +11 -3
- classiq/interface/model/quantum_type.py +26 -0
- classiq/interface/model/statement_block.py +2 -0
- classiq/interface/server/routes.py +5 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +6 -6
- classiq/model_expansions/capturing/captured_vars.py +27 -10
- classiq/model_expansions/evaluators/arg_type_match.py +4 -7
- classiq/model_expansions/evaluators/quantum_type_utils.py +25 -8
- classiq/model_expansions/expression_evaluator.py +8 -2
- classiq/model_expansions/function_builder.py +35 -11
- classiq/model_expansions/generative_functions.py +6 -4
- classiq/model_expansions/interpreters/__init__.py +0 -0
- classiq/model_expansions/interpreters/base_interpreter.py +263 -0
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
- classiq/model_expansions/model_tables.py +1 -92
- classiq/model_expansions/quantum_operations/__init__.py +0 -10
- classiq/model_expansions/quantum_operations/call_emitter.py +45 -93
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
- classiq/model_expansions/quantum_operations/emitter.py +7 -2
- classiq/model_expansions/quantum_operations/quantum_function_call.py +11 -2
- classiq/model_expansions/quantum_operations/shallow_emitter.py +22 -3
- classiq/model_expansions/scope.py +15 -15
- classiq/model_expansions/scope_initialization.py +11 -5
- classiq/open_library/functions/discrete_sine_cosine_transform.py +8 -2
- classiq/open_library/functions/grover.py +1 -1
- classiq/open_library/functions/modular_exponentiation.py +8 -2
- classiq/open_library/functions/state_preparation.py +23 -13
- classiq/open_library/functions/swap_test.py +1 -2
- classiq/open_library/functions/variational.py +1 -2
- classiq/qmod/builtins/__init__.py +1 -1
- classiq/qmod/builtins/operations.py +51 -0
- classiq/qmod/declaration_inferrer.py +0 -3
- classiq/qmod/generative.py +4 -4
- classiq/qmod/native/pretty_printer.py +9 -1
- classiq/qmod/pretty_print/pretty_printer.py +12 -1
- classiq/qmod/qfunc.py +4 -2
- classiq/qmod/qmod_variable.py +55 -48
- classiq/qmod/quantum_function.py +7 -5
- classiq/qmod/semantics/annotation/__init__.py +0 -0
- classiq/qmod/semantics/annotation/call_annotation.py +92 -0
- classiq/qmod/semantics/lambdas.py +25 -0
- classiq/qmod/semantics/static_semantics_visitor.py +8 -46
- classiq/qmod/utilities.py +23 -1
- {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/METADATA +1 -1
- {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/RECORD +66 -67
- classiq/interface/helpers/dotdict.py +0 -18
- classiq/model_expansions/interpreter.py +0 -475
- classiq/model_expansions/quantum_operations/control.py +0 -290
- classiq/model_expansions/quantum_operations/expression_operation.py +0 -103
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +0 -535
- classiq/model_expansions/quantum_operations/invert.py +0 -36
- classiq/model_expansions/quantum_operations/phase.py +0 -187
- classiq/model_expansions/quantum_operations/power.py +0 -71
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +0 -230
- classiq/model_expansions/quantum_operations/within_apply.py +0 -25
- classiq/qmod/semantics/annotation.py +0 -36
- /classiq/qmod/semantics/{qstruct_annotator.py → annotation/qstruct_annotator.py} +0 -0
- {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/WHEEL +0 -0
classiq/qmod/qmod_variable.py
CHANGED
@@ -23,11 +23,8 @@ from typing_extensions import ParamSpec, Self, _AnnotatedAlias
|
|
23
23
|
from classiq.interface.exceptions import ClassiqValueError
|
24
24
|
from classiq.interface.generator.expressions.expression import Expression
|
25
25
|
from classiq.interface.generator.expressions.qmod_qarray_proxy import (
|
26
|
-
ILLEGAL_SLICE_BOUNDS_MSG,
|
27
26
|
ILLEGAL_SLICE_MSG,
|
28
27
|
ILLEGAL_SLICING_STEP_MSG,
|
29
|
-
SLICE_OUT_OF_BOUNDS_MSG,
|
30
|
-
SUBSCRIPT_OUT_OF_BOUNDS_MSG,
|
31
28
|
)
|
32
29
|
from classiq.interface.generator.functions.port_declaration import (
|
33
30
|
PortDeclarationDirection,
|
@@ -66,7 +63,12 @@ from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
|
|
66
63
|
from classiq.qmod.quantum_callable import QCallable
|
67
64
|
from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
|
68
65
|
from classiq.qmod.symbolic_type import SymbolicTypes
|
69
|
-
from classiq.qmod.utilities import
|
66
|
+
from classiq.qmod.utilities import (
|
67
|
+
get_source_ref,
|
68
|
+
unwrap_forward_ref,
|
69
|
+
varname,
|
70
|
+
version_portable_get_args,
|
71
|
+
)
|
70
72
|
|
71
73
|
|
72
74
|
def _is_input_output_typehint(type_hint: Any) -> bool:
|
@@ -94,28 +96,42 @@ def _no_current_expandable() -> Iterator[None]:
|
|
94
96
|
QCallable.CURRENT_EXPANDABLE = current_expandable
|
95
97
|
|
96
98
|
|
99
|
+
def _infer_variable_name(name: Any, depth: int) -> Any:
|
100
|
+
if name is not None:
|
101
|
+
return name
|
102
|
+
name = varname(depth + 1)
|
103
|
+
if name is None:
|
104
|
+
raise ClassiqValueError(
|
105
|
+
"Could not infer variable name. Please specify the variable name explicitly"
|
106
|
+
)
|
107
|
+
return name
|
108
|
+
|
109
|
+
|
97
110
|
class QVar(Symbolic):
|
111
|
+
CONSTRUCTOR_DEPTH: int = 1
|
112
|
+
|
98
113
|
def __init__(
|
99
114
|
self,
|
100
|
-
origin: Union[str, HandleBinding],
|
115
|
+
origin: Union[None, str, HandleBinding] = None,
|
101
116
|
*,
|
102
117
|
expr_str: Optional[str] = None,
|
103
118
|
depth: int = 2,
|
104
119
|
) -> None:
|
105
|
-
|
120
|
+
name = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
|
121
|
+
super().__init__(str(name), True)
|
106
122
|
source_ref = (
|
107
123
|
get_source_ref(sys._getframe(depth))
|
108
|
-
if isinstance(
|
109
|
-
else
|
124
|
+
if isinstance(name, str)
|
125
|
+
else name.source_ref
|
110
126
|
)
|
111
127
|
self._base_handle: HandleBinding = (
|
112
|
-
HandleBinding(name=
|
128
|
+
HandleBinding(name=name) if isinstance(name, str) else name
|
113
129
|
)
|
114
|
-
if isinstance(
|
130
|
+
if isinstance(name, str) and QCallable.CURRENT_EXPANDABLE is not None:
|
115
131
|
QCallable.CURRENT_EXPANDABLE.add_local_handle(
|
116
|
-
|
132
|
+
name, self.get_qmod_type(), source_ref
|
117
133
|
)
|
118
|
-
self._expr_str = expr_str if expr_str is not None else str(
|
134
|
+
self._expr_str = expr_str if expr_str is not None else str(name)
|
119
135
|
|
120
136
|
def get_handle_binding(self) -> HandleBinding:
|
121
137
|
return self._base_handle
|
@@ -176,13 +192,16 @@ Input = Annotated[_Q, PortDeclarationDirection.Input]
|
|
176
192
|
|
177
193
|
|
178
194
|
class QScalar(QVar, SymbolicExpr):
|
195
|
+
CONSTRUCTOR_DEPTH: int = 2
|
196
|
+
|
179
197
|
def __init__(
|
180
198
|
self,
|
181
|
-
origin: Union[str, HandleBinding],
|
199
|
+
origin: Union[None, str, HandleBinding] = None,
|
182
200
|
*,
|
183
201
|
_expr_str: Optional[str] = None,
|
184
202
|
depth: int = 2,
|
185
203
|
) -> None:
|
204
|
+
origin = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
|
186
205
|
QVar.__init__(self, origin, expr_str=_expr_str, depth=depth)
|
187
206
|
SymbolicExpr.__init__(self, str(origin), True)
|
188
207
|
|
@@ -282,9 +301,11 @@ _P = ParamSpec("_P")
|
|
282
301
|
|
283
302
|
|
284
303
|
class QNum(Generic[_P], QScalar):
|
304
|
+
CONSTRUCTOR_DEPTH: int = 3
|
305
|
+
|
285
306
|
def __init__(
|
286
307
|
self,
|
287
|
-
name: Union[str, HandleBinding],
|
308
|
+
name: Union[None, str, HandleBinding] = None,
|
288
309
|
size: Union[int, CInt, Expression, SymbolicExpr, None] = None,
|
289
310
|
is_signed: Union[bool, Expression, SymbolicExpr, None] = None,
|
290
311
|
fraction_digits: Union[int, CInt, Expression, None] = None,
|
@@ -330,8 +351,12 @@ class QNum(Generic[_P], QScalar):
|
|
330
351
|
"is_signed: bool | CBool, fraction_digits: int | CInt]"
|
331
352
|
)
|
332
353
|
if len(type_args) == 1:
|
333
|
-
return type_args[0], None, None
|
334
|
-
return
|
354
|
+
return unwrap_forward_ref(type_args[0]), None, None
|
355
|
+
return (
|
356
|
+
unwrap_forward_ref(type_args[0]),
|
357
|
+
unwrap_forward_ref(type_args[1]),
|
358
|
+
unwrap_forward_ref(type_args[2]),
|
359
|
+
)
|
335
360
|
|
336
361
|
@classmethod
|
337
362
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
@@ -390,10 +415,12 @@ class QNum(Generic[_P], QScalar):
|
|
390
415
|
|
391
416
|
|
392
417
|
class QArray(ArrayBase[_P], QVar):
|
418
|
+
CONSTRUCTOR_DEPTH: int = 3
|
419
|
+
|
393
420
|
# TODO [CAD-18620]: improve type hints
|
394
421
|
def __init__(
|
395
422
|
self,
|
396
|
-
name: Union[str, HandleBinding],
|
423
|
+
name: Union[None, str, HandleBinding] = None,
|
397
424
|
element_type: Union[_GenericAlias, QuantumType] = QBit,
|
398
425
|
length: Optional[Union[int, SymbolicExpr, Expression]] = None,
|
399
426
|
_expr_str: Optional[str] = None,
|
@@ -417,14 +444,6 @@ class QArray(ArrayBase[_P], QVar):
|
|
417
444
|
def _get_subscript(self, index: Union[slice, int, SymbolicExpr]) -> Any:
|
418
445
|
if isinstance(index, SymbolicExpr) and index.is_quantum:
|
419
446
|
raise ClassiqValueError("Non-classical parameter for slicing")
|
420
|
-
if (
|
421
|
-
isinstance(index, int)
|
422
|
-
and self._length is not None
|
423
|
-
and self._length.is_evaluated()
|
424
|
-
):
|
425
|
-
length = self._length.to_int_value()
|
426
|
-
if index < 0 or index >= length:
|
427
|
-
raise ClassiqValueError(SUBSCRIPT_OUT_OF_BOUNDS_MSG)
|
428
447
|
|
429
448
|
return _create_qvar_for_qtype(
|
430
449
|
self.get_qmod_type().element_type,
|
@@ -442,20 +461,6 @@ class QArray(ArrayBase[_P], QVar):
|
|
442
461
|
slice_.stop, (int, SymbolicExpr)
|
443
462
|
):
|
444
463
|
raise ClassiqValueError(ILLEGAL_SLICE_MSG)
|
445
|
-
if (
|
446
|
-
isinstance(slice_.start, int)
|
447
|
-
and isinstance(slice_.stop, int)
|
448
|
-
and slice_.start >= slice_.stop
|
449
|
-
):
|
450
|
-
raise ClassiqValueError(
|
451
|
-
ILLEGAL_SLICE_BOUNDS_MSG.format(slice_.start, slice_.stop)
|
452
|
-
)
|
453
|
-
if self._length is not None and self._length.is_evaluated():
|
454
|
-
length = self._length.to_int_value()
|
455
|
-
if (isinstance(slice_.start, int) and slice_.start < 0) or (
|
456
|
-
isinstance(slice_.stop, int) and slice_.stop > length
|
457
|
-
):
|
458
|
-
raise ClassiqValueError(SLICE_OUT_OF_BOUNDS_MSG)
|
459
464
|
|
460
465
|
return QArray(
|
461
466
|
name=SlicedHandleBinding(
|
@@ -492,16 +497,18 @@ class QArray(ArrayBase[_P], QVar):
|
|
492
497
|
type_args = version_portable_get_args(type_hint)
|
493
498
|
if len(type_args) == 0:
|
494
499
|
return QBit, None
|
500
|
+
first_arg = unwrap_forward_ref(type_args[0])
|
495
501
|
if len(type_args) == 1:
|
496
|
-
if isinstance(
|
497
|
-
return QBit,
|
498
|
-
return
|
502
|
+
if isinstance(first_arg, (str, int)):
|
503
|
+
return QBit, first_arg
|
504
|
+
return first_arg, None
|
499
505
|
if len(type_args) != 2:
|
500
506
|
raise ClassiqValueError(
|
501
507
|
"QArray receives two type arguments: QArray[element_type: QVar, "
|
502
508
|
"length: int | CInt]"
|
503
509
|
)
|
504
|
-
|
510
|
+
second_arg = unwrap_forward_ref(type_args[1])
|
511
|
+
return cast(tuple[type[QVar], Any], (first_arg, second_arg))
|
505
512
|
|
506
513
|
@classmethod
|
507
514
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
@@ -537,16 +544,19 @@ class QArray(ArrayBase[_P], QVar):
|
|
537
544
|
|
538
545
|
|
539
546
|
class QStruct(QVar):
|
547
|
+
CONSTRUCTOR_DEPTH: int = 2
|
548
|
+
|
540
549
|
_struct_name: str
|
541
550
|
_fields: Mapping[str, QVar]
|
542
551
|
|
543
552
|
def __init__(
|
544
553
|
self,
|
545
|
-
|
554
|
+
origin: Union[None, str, HandleBinding] = None,
|
546
555
|
_struct_name: Optional[str] = None,
|
547
556
|
_fields: Optional[Mapping[str, QVar]] = None,
|
548
557
|
_expr_str: Optional[str] = None,
|
549
558
|
) -> None:
|
559
|
+
name = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
|
550
560
|
if _struct_name is None or _fields is None:
|
551
561
|
with _no_current_expandable():
|
552
562
|
temp_var = QStruct.to_qvar(name, type(self), _expr_str)
|
@@ -601,15 +611,13 @@ class QStruct(QVar):
|
|
601
611
|
for field_name, (field_class, field_type) in field_types.items()
|
602
612
|
}
|
603
613
|
return QStruct(
|
604
|
-
|
614
|
+
origin,
|
605
615
|
_struct_name=type_hint.__name__,
|
606
616
|
_fields=field_vars,
|
607
617
|
_expr_str=expr_str,
|
608
618
|
)
|
609
619
|
|
610
620
|
def _add_qmod_qstruct(self, *, qmodule: ModelStateContainer) -> None:
|
611
|
-
from classiq.model_expansions.model_tables import SymbolTable
|
612
|
-
|
613
621
|
if self._struct_name in qmodule.qstruct_decls:
|
614
622
|
return
|
615
623
|
|
@@ -618,7 +626,6 @@ class QStruct(QVar):
|
|
618
626
|
fields={name: qvar.get_qmod_type() for name, qvar in self._fields.items()},
|
619
627
|
)
|
620
628
|
qmodule.qstruct_decls[self._struct_name] = struct_decl
|
621
|
-
SymbolTable.qstruct_table[self._struct_name] = struct_decl
|
622
629
|
|
623
630
|
|
624
631
|
def create_qvar_for_port_decl(port: AnonPortDeclaration, name: str) -> QVar:
|
classiq/qmod/quantum_function.py
CHANGED
@@ -153,8 +153,10 @@ class QFunc(BaseQFunc):
|
|
153
153
|
return model
|
154
154
|
|
155
155
|
def _create_generative_model(self, model_stub: Model) -> Model:
|
156
|
-
from classiq.model_expansions.
|
157
|
-
|
156
|
+
from classiq.model_expansions.interpreters.frontend_generative_interpreter import (
|
157
|
+
FrontendGenerativeInterpreter,
|
158
|
+
)
|
159
|
+
from classiq.qmod.semantics.annotation.call_annotation import (
|
158
160
|
resolve_function_calls,
|
159
161
|
)
|
160
162
|
|
@@ -167,9 +169,7 @@ class QFunc(BaseQFunc):
|
|
167
169
|
for gen_func in generative_functions
|
168
170
|
},
|
169
171
|
)
|
170
|
-
interpreter =
|
171
|
-
model_stub, generative_functions, is_normalizer=True, is_shallow=True
|
172
|
-
)
|
172
|
+
interpreter = FrontendGenerativeInterpreter(model_stub, generative_functions)
|
173
173
|
set_frontend_interpreter(interpreter)
|
174
174
|
return interpreter.expand()
|
175
175
|
|
@@ -244,6 +244,8 @@ class ExternalQFunc(QTerminalCallable):
|
|
244
244
|
|
245
245
|
|
246
246
|
class GenerativeQFunc(BaseQFunc):
|
247
|
+
FRAME_DEPTH = 3
|
248
|
+
|
247
249
|
def __init__(
|
248
250
|
self,
|
249
251
|
py_callable: Callable,
|
File without changes
|
@@ -0,0 +1,92 @@
|
|
1
|
+
from collections.abc import Iterator, Mapping
|
2
|
+
from contextlib import contextmanager
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from classiq.interface.exceptions import ClassiqError
|
6
|
+
from classiq.interface.generator.visitor import Visitor
|
7
|
+
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
8
|
+
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
9
|
+
from classiq.interface.model.quantum_function_declaration import (
|
10
|
+
AnonQuantumOperandDeclaration,
|
11
|
+
QuantumFunctionDeclaration,
|
12
|
+
QuantumOperandDeclaration,
|
13
|
+
)
|
14
|
+
from classiq.interface.model.quantum_lambda_function import (
|
15
|
+
QuantumLambdaFunction,
|
16
|
+
)
|
17
|
+
|
18
|
+
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
19
|
+
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
20
|
+
from classiq.qmod.semantics.error_manager import ErrorManager
|
21
|
+
from classiq.qmod.semantics.lambdas import get_renamed_parameters
|
22
|
+
|
23
|
+
|
24
|
+
def _annotate_function_call_decl(
|
25
|
+
fc: QuantumFunctionCall,
|
26
|
+
function_dict: Mapping[str, QuantumFunctionDeclaration],
|
27
|
+
) -> None:
|
28
|
+
if fc._func_decl is None:
|
29
|
+
func_decl = function_dict.get(fc.func_name)
|
30
|
+
if func_decl is None:
|
31
|
+
raise ClassiqError(
|
32
|
+
f"Error resolving function {fc.func_name}, the function is not found in included library."
|
33
|
+
)
|
34
|
+
fc.set_func_decl(func_decl)
|
35
|
+
|
36
|
+
for arg, param in zip(fc.positional_args, fc.func_decl.positional_arg_declarations):
|
37
|
+
if not isinstance(param, AnonQuantumOperandDeclaration):
|
38
|
+
continue
|
39
|
+
args: list
|
40
|
+
if isinstance(arg, list):
|
41
|
+
args = arg
|
42
|
+
else:
|
43
|
+
args = [arg]
|
44
|
+
for qlambda in args:
|
45
|
+
if isinstance(qlambda, QuantumLambdaFunction):
|
46
|
+
qlambda.set_op_decl(param)
|
47
|
+
|
48
|
+
|
49
|
+
class _CallLambdaAnnotator(Visitor):
|
50
|
+
def __init__(
|
51
|
+
self, quantum_functions: Mapping[str, QuantumFunctionDeclaration]
|
52
|
+
) -> None:
|
53
|
+
self._quantum_functions = dict(quantum_functions)
|
54
|
+
self._current_operands: dict[str, QuantumOperandDeclaration] = {}
|
55
|
+
|
56
|
+
@contextmanager
|
57
|
+
def set_operands(
|
58
|
+
self, operands: dict[str, QuantumOperandDeclaration]
|
59
|
+
) -> Iterator[None]:
|
60
|
+
previous_operands = self._current_operands
|
61
|
+
self._current_operands = operands
|
62
|
+
yield
|
63
|
+
self._current_operands = previous_operands
|
64
|
+
|
65
|
+
def visit_NativeFunctionDefinition(self, func: NativeFunctionDefinition) -> None:
|
66
|
+
with self.set_operands(func.operand_declarations_dict):
|
67
|
+
self.generic_visit(func)
|
68
|
+
|
69
|
+
def visit_QuantumLambdaFunction(self, lambda_func: QuantumLambdaFunction) -> None:
|
70
|
+
lambda_operands = get_renamed_parameters(lambda_func)[1]
|
71
|
+
with self.set_operands(self._current_operands | lambda_operands):
|
72
|
+
self.generic_visit(lambda_func)
|
73
|
+
|
74
|
+
def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
|
75
|
+
_annotate_function_call_decl(
|
76
|
+
call, self._quantum_functions | self._current_operands
|
77
|
+
)
|
78
|
+
self.generic_visit(call)
|
79
|
+
|
80
|
+
|
81
|
+
def resolve_function_calls(
|
82
|
+
root: Any,
|
83
|
+
quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
|
84
|
+
) -> None:
|
85
|
+
all_functions: Mapping[str, QuantumFunctionDeclaration] = {
|
86
|
+
**BUILTIN_FUNCTION_DECLARATIONS,
|
87
|
+
**quantum_function_dict,
|
88
|
+
}
|
89
|
+
with ErrorManager().ignore_errors_context():
|
90
|
+
QStructAnnotator().visit(quantum_function_dict)
|
91
|
+
QStructAnnotator().visit(root)
|
92
|
+
_CallLambdaAnnotator(all_functions).visit(root)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
2
|
+
from classiq.interface.model.quantum_function_declaration import (
|
3
|
+
AnonQuantumOperandDeclaration,
|
4
|
+
QuantumOperandDeclaration,
|
5
|
+
)
|
6
|
+
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
7
|
+
|
8
|
+
from classiq import AnonClassicalParameterDeclaration
|
9
|
+
|
10
|
+
|
11
|
+
def get_renamed_parameters(
|
12
|
+
lambda_func: QuantumLambdaFunction,
|
13
|
+
) -> tuple[list[str], dict[str, QuantumOperandDeclaration], list[PortDeclaration]]:
|
14
|
+
renamed_parameters: list[str] = []
|
15
|
+
renamed_operands: dict[str, QuantumOperandDeclaration] = {}
|
16
|
+
renamed_ports: list[PortDeclaration] = []
|
17
|
+
for idx, param in enumerate(lambda_func.func_decl.positional_arg_declarations):
|
18
|
+
param_name = lambda_func.pos_rename_params[idx]
|
19
|
+
if isinstance(param, AnonClassicalParameterDeclaration):
|
20
|
+
renamed_parameters.append(param_name)
|
21
|
+
elif isinstance(param, AnonQuantumOperandDeclaration):
|
22
|
+
renamed_operands[param_name] = param.rename(param_name)
|
23
|
+
else:
|
24
|
+
renamed_ports.append(param.rename(param_name))
|
25
|
+
return renamed_parameters, renamed_operands, renamed_ports
|
@@ -2,7 +2,6 @@ import ast
|
|
2
2
|
from collections.abc import Iterator, Mapping, Sequence
|
3
3
|
from contextlib import contextmanager
|
4
4
|
from typing import (
|
5
|
-
Any,
|
6
5
|
Optional,
|
7
6
|
)
|
8
7
|
|
@@ -15,9 +14,6 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
15
14
|
PortDeclarationDirection,
|
16
15
|
)
|
17
16
|
from classiq.interface.generator.visitor import Visitor
|
18
|
-
from classiq.interface.model.classical_parameter_declaration import (
|
19
|
-
AnonClassicalParameterDeclaration,
|
20
|
-
)
|
21
17
|
from classiq.interface.model.handle_binding import (
|
22
18
|
FieldHandleBinding,
|
23
19
|
HandleBinding,
|
@@ -33,7 +29,6 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
33
29
|
)
|
34
30
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
35
31
|
from classiq.interface.model.quantum_function_declaration import (
|
36
|
-
AnonQuantumOperandDeclaration,
|
37
32
|
QuantumFunctionDeclaration,
|
38
33
|
QuantumOperandDeclaration,
|
39
34
|
)
|
@@ -51,9 +46,10 @@ from classiq.model_expansions.visitors.variable_references import VarRefCollecto
|
|
51
46
|
from classiq.qmod.builtins.functions import (
|
52
47
|
BUILTIN_FUNCTION_DECLARATIONS,
|
53
48
|
)
|
54
|
-
from classiq.qmod.semantics.annotation import
|
49
|
+
from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
|
50
|
+
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
55
51
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
56
|
-
from classiq.qmod.semantics.
|
52
|
+
from classiq.qmod.semantics.lambdas import get_renamed_parameters
|
57
53
|
from classiq.qmod.semantics.validation.constants_validation import (
|
58
54
|
check_duplicate_constants,
|
59
55
|
)
|
@@ -202,13 +198,6 @@ class StaticSemanticsVisitor(Visitor):
|
|
202
198
|
def visit_QuantumOperation(self, op: QuantumOperation) -> None:
|
203
199
|
with self._error_manager.node_context(op):
|
204
200
|
if isinstance(op, QuantumFunctionCall):
|
205
|
-
annotate_function_call_decl(
|
206
|
-
op,
|
207
|
-
{
|
208
|
-
**self._functions_dict,
|
209
|
-
**self.current_scope.operands,
|
210
|
-
},
|
211
|
-
)
|
212
201
|
validate_call_arguments(
|
213
202
|
op,
|
214
203
|
{
|
@@ -243,8 +232,8 @@ class StaticSemanticsVisitor(Visitor):
|
|
243
232
|
)
|
244
233
|
|
245
234
|
def visit_QuantumLambdaFunction(self, lambda_func: QuantumLambdaFunction) -> None:
|
246
|
-
renamed_parameters, renamed_operands, renamed_ports = (
|
247
|
-
|
235
|
+
renamed_parameters, renamed_operands, renamed_ports = get_renamed_parameters(
|
236
|
+
lambda_func
|
248
237
|
)
|
249
238
|
scope = StaticScope(
|
250
239
|
parameters=self.current_scope.parameters + renamed_parameters,
|
@@ -259,22 +248,6 @@ class StaticSemanticsVisitor(Visitor):
|
|
259
248
|
with self.scoped_visit(scope):
|
260
249
|
self.generic_visit(lambda_func)
|
261
250
|
|
262
|
-
def _get_renamed_parameters(
|
263
|
-
self, lambda_func: QuantumLambdaFunction
|
264
|
-
) -> tuple[list[str], dict[str, QuantumOperandDeclaration], list[PortDeclaration]]:
|
265
|
-
renamed_parameters: list[str] = []
|
266
|
-
renamed_operands: dict[str, QuantumOperandDeclaration] = {}
|
267
|
-
renamed_ports: list[PortDeclaration] = []
|
268
|
-
for idx, param in enumerate(lambda_func.func_decl.positional_arg_declarations):
|
269
|
-
param_name = lambda_func.pos_rename_params[idx]
|
270
|
-
if isinstance(param, AnonClassicalParameterDeclaration):
|
271
|
-
renamed_parameters.append(param_name)
|
272
|
-
elif isinstance(param, AnonQuantumOperandDeclaration):
|
273
|
-
renamed_operands[param_name] = param.rename(param_name)
|
274
|
-
else:
|
275
|
-
renamed_ports.append(param.rename(param_name))
|
276
|
-
return renamed_parameters, renamed_operands, renamed_ports
|
277
|
-
|
278
251
|
def visit_HandleBinding(self, handle: HandleBinding) -> None:
|
279
252
|
resolve_handle(self.current_scope, handle)
|
280
253
|
|
@@ -375,26 +348,15 @@ class StaticSemanticsVisitor(Visitor):
|
|
375
348
|
)
|
376
349
|
|
377
350
|
|
378
|
-
def resolve_function_calls(
|
379
|
-
root: Any,
|
380
|
-
quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
|
381
|
-
) -> None:
|
382
|
-
with ErrorManager().ignore_errors_context():
|
383
|
-
QStructAnnotator().visit(quantum_function_dict)
|
384
|
-
QStructAnnotator().visit(root)
|
385
|
-
StaticSemanticsVisitor(
|
386
|
-
{**BUILTIN_FUNCTION_DECLARATIONS, **quantum_function_dict},
|
387
|
-
[],
|
388
|
-
).visit(root)
|
389
|
-
|
390
|
-
|
391
351
|
def static_semantics_analysis_pass(
|
392
352
|
model: Model, error_type: Optional[type[Exception]] = ClassiqSemanticError
|
393
353
|
) -> None:
|
394
354
|
_check_function_name_collisions(model, error_type)
|
395
355
|
QStructAnnotator().visit(model)
|
356
|
+
functions = {**BUILTIN_FUNCTION_DECLARATIONS, **model.function_dict}
|
357
|
+
resolve_function_calls(model, functions)
|
396
358
|
StaticSemanticsVisitor(
|
397
|
-
|
359
|
+
functions,
|
398
360
|
[const.name for const in model.constants],
|
399
361
|
).visit(model)
|
400
362
|
if error_type is not None:
|
classiq/qmod/utilities.py
CHANGED
@@ -5,7 +5,7 @@ import keyword
|
|
5
5
|
import sys
|
6
6
|
from enum import Enum as PythonEnum
|
7
7
|
from types import FrameType
|
8
|
-
from typing import Any, Literal, Optional, get_args, get_origin, overload
|
8
|
+
from typing import Any, ForwardRef, Literal, Optional, get_args, get_origin, overload
|
9
9
|
|
10
10
|
from classiq.interface.source_reference import SourceReference
|
11
11
|
|
@@ -97,3 +97,25 @@ def qmod_val_to_expr_str(val: Any) -> str:
|
|
97
97
|
return f"{type(val).__name__}.{val.name}"
|
98
98
|
|
99
99
|
return str(val)
|
100
|
+
|
101
|
+
|
102
|
+
def unwrap_forward_ref(x: Any) -> Any:
|
103
|
+
if isinstance(x, ForwardRef):
|
104
|
+
return x.__forward_arg__
|
105
|
+
return x
|
106
|
+
|
107
|
+
|
108
|
+
def varname(depth: int) -> Optional[str]:
|
109
|
+
frame = sys._getframe(depth)
|
110
|
+
codes = inspect.getframeinfo(frame).code_context
|
111
|
+
if codes is None or len(codes) != 1:
|
112
|
+
return None
|
113
|
+
code = codes[0]
|
114
|
+
if "=" not in code:
|
115
|
+
return None
|
116
|
+
var_name = code.split("=")[0].strip()
|
117
|
+
if ":" in var_name:
|
118
|
+
var_name = var_name.split(":")[0].strip()
|
119
|
+
if not var_name.isidentifier():
|
120
|
+
return None
|
121
|
+
return var_name
|