classiq 0.76.0__py3-none-any.whl → 0.78.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/applications/chemistry/chemistry_model_constructor.py +7 -6
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +9 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -3
- classiq/applications/iqae/__init__.py +0 -0
- classiq/applications/iqae/iqae.py +207 -0
- classiq/execution/__init__.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/applications/iqae/__init__.py +0 -0
- classiq/interface/applications/iqae/generic_iqae.py +222 -0
- classiq/interface/applications/iqae/iqae_result.py +45 -0
- classiq/interface/debug_info/debug_info.py +3 -0
- classiq/interface/executor/execution_result.py +1 -1
- classiq/interface/executor/user_budget.py +1 -1
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +9 -3
- classiq/interface/generator/expressions/proxies/quantum/qmod_qarray_proxy.py +6 -15
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +14 -5
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +5 -3
- classiq/interface/generator/generated_circuit_data.py +18 -7
- classiq/interface/ide/visual_model.py +2 -0
- classiq/interface/model/handle_binding.py +8 -0
- classiq/interface/model/model.py +3 -6
- classiq/interface/model/quantum_function_call.py +31 -1
- classiq/interface/model/quantum_statement.py +14 -1
- classiq/interface/source_reference.py +7 -2
- classiq/model_expansions/capturing/captured_vars.py +16 -6
- classiq/model_expansions/closure.py +1 -58
- classiq/model_expansions/evaluators/arg_type_match.py +2 -2
- classiq/model_expansions/evaluators/argument_types.py +4 -5
- classiq/model_expansions/evaluators/classical_expression.py +9 -9
- classiq/model_expansions/evaluators/parameter_types.py +19 -11
- classiq/model_expansions/expression_evaluator.py +20 -11
- classiq/model_expansions/generative_functions.py +1 -1
- classiq/model_expansions/interpreters/base_interpreter.py +27 -15
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +0 -16
- classiq/model_expansions/interpreters/generative_interpreter.py +4 -4
- classiq/model_expansions/quantum_operations/allocate.py +2 -2
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +3 -1
- classiq/model_expansions/quantum_operations/call_emitter.py +91 -42
- classiq/model_expansions/quantum_operations/emitter.py +7 -7
- classiq/model_expansions/quantum_operations/function_calls_cache.py +84 -0
- classiq/model_expansions/scope.py +73 -13
- classiq/model_expansions/transformers/model_renamer.py +2 -2
- classiq/model_expansions/transformers/type_qualifier_inference.py +183 -0
- classiq/model_expansions/utils/text_utils.py +4 -2
- classiq/model_expansions/visitors/symbolic_param_inference.py +4 -15
- classiq/open_library/functions/lookup_table.py +1 -1
- classiq/open_library/functions/state_preparation.py +1 -1
- classiq/qmod/builtins/classical_execution_primitives.py +1 -1
- classiq/qmod/create_model_function.py +21 -3
- classiq/qmod/global_declarative_switch.py +19 -0
- classiq/qmod/native/pretty_printer.py +4 -0
- classiq/qmod/pretty_print/pretty_printer.py +4 -0
- classiq/qmod/qfunc.py +31 -23
- classiq/qmod/qmod_variable.py +7 -4
- classiq/qmod/quantum_expandable.py +29 -1
- classiq/qmod/quantum_function.py +26 -19
- classiq/qmod/utilities.py +4 -0
- classiq/qmod/write_qmod.py +36 -10
- classiq/synthesis.py +7 -6
- {classiq-0.76.0.dist-info → classiq-0.78.0.dist-info}/METADATA +1 -1
- {classiq-0.76.0.dist-info → classiq-0.78.0.dist-info}/RECORD +62 -55
- classiq/interface/executor/iqae_result.py +0 -17
- {classiq-0.76.0.dist-info → classiq-0.78.0.dist-info}/WHEEL +0 -0
@@ -20,6 +20,7 @@ from classiq.interface.generator.functions.type_name import (
|
|
20
20
|
from classiq.interface.model.classical_parameter_declaration import (
|
21
21
|
ClassicalParameterDeclaration,
|
22
22
|
)
|
23
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
23
24
|
from classiq.interface.model.port_declaration import PortDeclaration
|
24
25
|
from classiq.interface.model.quantum_function_declaration import (
|
25
26
|
PositionalArg,
|
@@ -46,7 +47,12 @@ from classiq.model_expansions.evaluators.quantum_type_utils import (
|
|
46
47
|
set_length,
|
47
48
|
set_size,
|
48
49
|
)
|
49
|
-
from classiq.model_expansions.scope import
|
50
|
+
from classiq.model_expansions.scope import (
|
51
|
+
Evaluated,
|
52
|
+
QuantumSymbol,
|
53
|
+
QuantumVariable,
|
54
|
+
Scope,
|
55
|
+
)
|
50
56
|
|
51
57
|
|
52
58
|
def evaluate_parameter_types_from_args(
|
@@ -83,10 +89,10 @@ def _update_scope(
|
|
83
89
|
return
|
84
90
|
if parameter.direction is PortDeclarationDirection.Output:
|
85
91
|
return
|
86
|
-
|
92
|
+
quantum_var = argument.as_type(QuantumVariable)
|
87
93
|
casted_argument = _cast(
|
88
94
|
parameter.quantum_type,
|
89
|
-
|
95
|
+
quantum_var.quantum_type,
|
90
96
|
parameter.name,
|
91
97
|
)
|
92
98
|
closure.scope[parameter.name] = Evaluated(
|
@@ -120,12 +126,12 @@ def _update_operand_signature_environment(
|
|
120
126
|
|
121
127
|
|
122
128
|
def _cast(
|
123
|
-
|
129
|
+
parameter_type: QuantumType, argument_type: QuantumType, param_name: str
|
124
130
|
) -> QuantumSymbol:
|
125
|
-
updated_quantum_type =
|
126
|
-
_inject_quantum_arg_info_to_type(updated_quantum_type,
|
131
|
+
updated_quantum_type = parameter_type.model_copy()
|
132
|
+
_inject_quantum_arg_info_to_type(updated_quantum_type, argument_type, param_name)
|
127
133
|
return QuantumSymbol(
|
128
|
-
handle=
|
134
|
+
handle=HandleBinding(name=param_name), quantum_type=updated_quantum_type
|
129
135
|
)
|
130
136
|
|
131
137
|
|
@@ -148,7 +154,9 @@ def _evaluate_type_from_arg(
|
|
148
154
|
)
|
149
155
|
if parameter.direction != PortDeclarationDirection.Output:
|
150
156
|
updated_quantum_type = _inject_quantum_arg_info_to_type(
|
151
|
-
updated_quantum_type,
|
157
|
+
updated_quantum_type,
|
158
|
+
argument.as_type(QuantumVariable).quantum_type,
|
159
|
+
parameter.name,
|
152
160
|
)
|
153
161
|
return parameter.model_copy(update={"quantum_type": updated_quantum_type})
|
154
162
|
|
@@ -280,11 +288,11 @@ def evaluate_types_in_quantum_symbols(
|
|
280
288
|
|
281
289
|
|
282
290
|
def _inject_quantum_arg_info_to_type(
|
283
|
-
parameter_type: QuantumType,
|
291
|
+
parameter_type: QuantumType, argument_type: QuantumType, param_name: str
|
284
292
|
) -> QuantumType:
|
285
|
-
if
|
293
|
+
if argument_type.has_size_in_bits:
|
286
294
|
copy_type_information(
|
287
|
-
|
295
|
+
argument_type,
|
288
296
|
parameter_type,
|
289
297
|
param_name,
|
290
298
|
)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import ast
|
2
2
|
from collections.abc import Mapping
|
3
3
|
from enum import EnumMeta
|
4
|
-
from typing import Any
|
4
|
+
from typing import Any
|
5
5
|
|
6
6
|
from sympy import SympifyError, sympify
|
7
7
|
|
@@ -50,11 +50,25 @@ def evaluate_constants_as_python(constants: list[Constant]) -> dict[str, Any]:
|
|
50
50
|
}
|
51
51
|
|
52
52
|
|
53
|
+
def _quick_eval(expr: str) -> Any:
|
54
|
+
try:
|
55
|
+
return int(expr)
|
56
|
+
except ValueError:
|
57
|
+
pass
|
58
|
+
try:
|
59
|
+
return float(expr)
|
60
|
+
except ValueError:
|
61
|
+
pass
|
62
|
+
return None
|
63
|
+
|
64
|
+
|
53
65
|
def evaluate(
|
54
|
-
expr: Expression,
|
55
|
-
locals_dict: Mapping[str, EvaluatedExpression],
|
56
|
-
uninitialized_locals: Optional[set[str]] = None,
|
66
|
+
expr: Expression, locals_dict: Mapping[str, EvaluatedExpression]
|
57
67
|
) -> EvaluatedExpression:
|
68
|
+
val = _quick_eval(expr.expr)
|
69
|
+
if val is not None:
|
70
|
+
return EvaluatedExpression(value=val)
|
71
|
+
|
58
72
|
model_locals: dict[str, ExpressionValue] = {}
|
59
73
|
model_locals.update(ATOMIC_EXPRESSION_FUNCTIONS)
|
60
74
|
model_locals.update(
|
@@ -65,9 +79,8 @@ def evaluate(
|
|
65
79
|
)
|
66
80
|
# locals override builtin-functions
|
67
81
|
model_locals.update({name: expr.value for name, expr in locals_dict.items()})
|
68
|
-
uninitialized_locals = uninitialized_locals or set()
|
69
82
|
|
70
|
-
_validate_undefined_vars(expr.expr, model_locals
|
83
|
+
_validate_undefined_vars(expr.expr, model_locals)
|
71
84
|
|
72
85
|
sympy_expr = translate_to_sympy(expr.expr)
|
73
86
|
try:
|
@@ -95,11 +108,8 @@ def evaluate(
|
|
95
108
|
|
96
109
|
|
97
110
|
def _validate_undefined_vars(
|
98
|
-
expr: str,
|
99
|
-
model_locals: dict[str, ExpressionValue],
|
100
|
-
uninitialized_locals: Optional[set[str]],
|
111
|
+
expr: str, model_locals: dict[str, ExpressionValue]
|
101
112
|
) -> None:
|
102
|
-
uninitialized_locals = uninitialized_locals or set()
|
103
113
|
id_visitor = _VarsCollector()
|
104
114
|
id_visitor.visit(ast.parse(expr))
|
105
115
|
identifiers = id_visitor.vars
|
@@ -108,7 +118,6 @@ def _validate_undefined_vars(
|
|
108
118
|
- model_locals.keys()
|
109
119
|
- set(SYMPY_SUPPORTED_EXPRESSIONS)
|
110
120
|
- set(symbolic.__all__)
|
111
|
-
- uninitialized_locals
|
112
121
|
)
|
113
122
|
|
114
123
|
if len(undefined_vars) == 1:
|
@@ -134,7 +134,7 @@ class _InterpreterExpandable(QFunc):
|
|
134
134
|
dummy_function = NativeFunctionDefinition(
|
135
135
|
name=current_operation.name,
|
136
136
|
positional_arg_declarations=current_operation.positional_arg_declarations,
|
137
|
-
body=
|
137
|
+
body=[stmt],
|
138
138
|
)
|
139
139
|
declarative_functions = {
|
140
140
|
name: func
|
@@ -24,6 +24,7 @@ from classiq.interface.generator.types.compilation_metadata import CompilationMe
|
|
24
24
|
from classiq.interface.model.handle_binding import (
|
25
25
|
FieldHandleBinding,
|
26
26
|
HandleBinding,
|
27
|
+
HandlesList,
|
27
28
|
SlicedHandleBinding,
|
28
29
|
SubscriptHandleBinding,
|
29
30
|
)
|
@@ -51,7 +52,12 @@ from classiq.model_expansions.function_builder import (
|
|
51
52
|
OperationBuilder,
|
52
53
|
OperationContext,
|
53
54
|
)
|
54
|
-
from classiq.model_expansions.scope import
|
55
|
+
from classiq.model_expansions.scope import (
|
56
|
+
Evaluated,
|
57
|
+
QuantumSymbol,
|
58
|
+
QuantumSymbolList,
|
59
|
+
Scope,
|
60
|
+
)
|
55
61
|
from classiq.model_expansions.scope_initialization import (
|
56
62
|
add_entry_point_params_to_scope,
|
57
63
|
init_builtin_types,
|
@@ -98,10 +104,8 @@ class BaseInterpreter:
|
|
98
104
|
main_closure.positional_arg_declarations, main_closure
|
99
105
|
)
|
100
106
|
context = self._expand_operation(main_closure)
|
101
|
-
self._expanded_functions[main_closure.
|
102
|
-
|
103
|
-
cast(FunctionContext, context), main_closure.positional_arg_declarations
|
104
|
-
)
|
107
|
+
self._expanded_functions[main_closure.name] = self._builder.create_definition(
|
108
|
+
cast(FunctionContext, context), main_closure.positional_arg_declarations
|
105
109
|
)
|
106
110
|
|
107
111
|
def _get_main_closure(self, main_func: FunctionClosure) -> FunctionClosure:
|
@@ -233,6 +237,14 @@ class BaseInterpreter:
|
|
233
237
|
)
|
234
238
|
return Evaluated(value=fields[field_name])
|
235
239
|
|
240
|
+
@evaluate.register
|
241
|
+
def evaluate_handles_list(self, handles_list: HandlesList) -> Evaluated:
|
242
|
+
return Evaluated(
|
243
|
+
value=QuantumSymbolList.from_symbols(
|
244
|
+
[self.evaluate(handle).value for handle in handles_list.handles]
|
245
|
+
)
|
246
|
+
)
|
247
|
+
|
236
248
|
@abstractmethod
|
237
249
|
def emit(self, statement: QuantumStatement) -> None:
|
238
250
|
pass
|
@@ -261,19 +273,19 @@ class BaseInterpreter:
|
|
261
273
|
|
262
274
|
def _expand_operation(self, operation: Closure) -> OperationContext:
|
263
275
|
with self._builder.operation_context(operation) as context:
|
264
|
-
|
265
|
-
(func_def := self._expanded_functions.get(operation.closure_id))
|
266
|
-
is not None
|
267
|
-
):
|
268
|
-
cached_closure = self._top_level_scope[func_def.name].value
|
269
|
-
operation.captured_vars.set(
|
270
|
-
cached_closure.captured_vars, cached_closure, operation
|
271
|
-
)
|
272
|
-
else:
|
273
|
-
self._expand_body(operation)
|
276
|
+
self._expand_body(operation)
|
274
277
|
|
275
278
|
return context
|
276
279
|
|
280
|
+
def _expand_cached_function(
|
281
|
+
self, operation: FunctionClosure, func_def: NativeFunctionDefinition
|
282
|
+
) -> None:
|
283
|
+
with self._builder.operation_context(operation):
|
284
|
+
cached_closure = self._top_level_scope[func_def.name].value
|
285
|
+
operation.captured_vars.set(
|
286
|
+
cached_closure.captured_vars, cached_closure, operation
|
287
|
+
)
|
288
|
+
|
277
289
|
def _expand_body(self, operation: Closure) -> None:
|
278
290
|
for block, block_body in operation.blocks.items():
|
279
291
|
self._expand_block(block_body, block)
|
@@ -6,11 +6,7 @@ from pydantic import ValidationError
|
|
6
6
|
from classiq.interface.exceptions import ClassiqError
|
7
7
|
from classiq.interface.model.allocate import Allocate
|
8
8
|
from classiq.interface.model.bind_operation import BindOperation
|
9
|
-
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
10
9
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
11
|
-
from classiq.interface.model.quantum_function_declaration import (
|
12
|
-
NamedParamsQuantumFunctionDeclaration,
|
13
|
-
)
|
14
10
|
from classiq.interface.source_reference import SourceReference
|
15
11
|
|
16
12
|
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
@@ -23,22 +19,10 @@ from classiq.model_expansions.quantum_operations.quantum_function_call import (
|
|
23
19
|
DeclarativeQuantumFunctionCallEmitter,
|
24
20
|
)
|
25
21
|
from classiq.model_expansions.scope import Scope
|
26
|
-
from classiq.model_expansions.visitors.symbolic_param_inference import (
|
27
|
-
SymbolicParamInference,
|
28
|
-
)
|
29
22
|
from classiq.qmod.model_state_container import QMODULE
|
30
23
|
|
31
24
|
|
32
25
|
class FrontendGenerativeInterpreter(GenerativeInterpreter):
|
33
|
-
def infer_symbolic_parameters(
|
34
|
-
self,
|
35
|
-
functions: list[NativeFunctionDefinition],
|
36
|
-
additional_signatures: (
|
37
|
-
list[NamedParamsQuantumFunctionDeclaration] | None
|
38
|
-
) = None,
|
39
|
-
) -> None:
|
40
|
-
SymbolicParamInference(functions, additional_signatures).infer()
|
41
|
-
|
42
26
|
def emit_allocate(self, allocate: Allocate) -> None:
|
43
27
|
AllocateEmitter(self, allow_symbolic_size=True).emit(allocate)
|
44
28
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from functools import singledispatchmethod
|
2
|
-
from typing import Any
|
2
|
+
from typing import Any, Optional
|
3
3
|
|
4
4
|
import numpy as np
|
5
5
|
from numpy.random import permutation
|
@@ -104,9 +104,9 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
104
104
|
def infer_symbolic_parameters(
|
105
105
|
self,
|
106
106
|
functions: list[NativeFunctionDefinition],
|
107
|
-
additional_signatures:
|
108
|
-
list[NamedParamsQuantumFunctionDeclaration]
|
109
|
-
|
107
|
+
additional_signatures: Optional[
|
108
|
+
list[NamedParamsQuantumFunctionDeclaration]
|
109
|
+
] = None,
|
110
110
|
) -> None:
|
111
111
|
pass
|
112
112
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import TYPE_CHECKING
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
2
2
|
|
3
3
|
import sympy
|
4
4
|
|
@@ -49,7 +49,7 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
49
49
|
self.emit_statement(allocate)
|
50
50
|
return True
|
51
51
|
|
52
|
-
def _get_var_size(self, target: QuantumSymbol, size: Expression
|
52
|
+
def _get_var_size(self, target: QuantumSymbol, size: Optional[Expression]) -> str:
|
53
53
|
if size is None:
|
54
54
|
if not target.quantum_type.is_evaluated:
|
55
55
|
raise ClassiqValueError(
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
1
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
2
4
|
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
3
5
|
from classiq.interface.generator.expressions.expression import Expression
|
@@ -69,7 +71,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
69
71
|
self._assign_to_inferred_var_and_bind(op, result_type, inferred_result_type)
|
70
72
|
return True
|
71
73
|
|
72
|
-
def _infer_result_type(self, op: ArithmeticOperation) -> QuantumNumeric
|
74
|
+
def _infer_result_type(self, op: ArithmeticOperation) -> Optional[QuantumNumeric]:
|
73
75
|
expr = self._evaluate_expression(op.expression)
|
74
76
|
if len(self._get_classical_vars_in_expression(expr)):
|
75
77
|
return None
|
@@ -4,6 +4,7 @@ from typing import (
|
|
4
4
|
TYPE_CHECKING,
|
5
5
|
Any,
|
6
6
|
Generic,
|
7
|
+
Optional,
|
7
8
|
cast,
|
8
9
|
)
|
9
10
|
from uuid import UUID
|
@@ -27,16 +28,19 @@ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_insta
|
|
27
28
|
from classiq.interface.generator.functions.port_declaration import (
|
28
29
|
PortDeclarationDirection,
|
29
30
|
)
|
31
|
+
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
30
32
|
from classiq.interface.model.classical_parameter_declaration import (
|
31
33
|
ClassicalParameterDeclaration,
|
32
34
|
)
|
33
35
|
from classiq.interface.model.handle_binding import HandleBinding
|
36
|
+
from classiq.interface.model.model import MAIN_FUNCTION_NAME
|
34
37
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
35
38
|
from classiq.interface.model.port_declaration import PortDeclaration
|
36
39
|
from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
|
37
40
|
from classiq.interface.model.quantum_function_declaration import (
|
38
41
|
NamedParamsQuantumFunctionDeclaration,
|
39
42
|
PositionalArg,
|
43
|
+
QuantumOperandDeclaration,
|
40
44
|
)
|
41
45
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
42
46
|
from classiq.interface.model.variable_declaration_statement import (
|
@@ -48,7 +52,7 @@ from classiq.model_expansions.capturing.captured_vars import (
|
|
48
52
|
UNINITIALIZED_VAR_MESSAGE,
|
49
53
|
validate_args_are_not_propagated,
|
50
54
|
)
|
51
|
-
from classiq.model_expansions.closure import FunctionClosure
|
55
|
+
from classiq.model_expansions.closure import Closure, FunctionClosure
|
52
56
|
from classiq.model_expansions.evaluators.argument_types import (
|
53
57
|
add_information_from_output_arguments,
|
54
58
|
)
|
@@ -62,7 +66,19 @@ from classiq.model_expansions.quantum_operations.emitter import (
|
|
62
66
|
Emitter,
|
63
67
|
QuantumStatementT,
|
64
68
|
)
|
65
|
-
from classiq.model_expansions.
|
69
|
+
from classiq.model_expansions.quantum_operations.function_calls_cache import (
|
70
|
+
get_func_call_cache_key,
|
71
|
+
)
|
72
|
+
from classiq.model_expansions.scope import (
|
73
|
+
Evaluated,
|
74
|
+
QuantumSymbol,
|
75
|
+
QuantumSymbolList,
|
76
|
+
QuantumVariable,
|
77
|
+
Scope,
|
78
|
+
)
|
79
|
+
from classiq.model_expansions.transformers.type_qualifier_inference import (
|
80
|
+
TypeQualifierInference,
|
81
|
+
)
|
66
82
|
from classiq.model_expansions.transformers.var_splitter import VarSplitter
|
67
83
|
from classiq.model_expansions.utils.text_utils import are, readable_list, s
|
68
84
|
from classiq.qmod.semantics.validation.signature_validation import (
|
@@ -74,11 +90,14 @@ if TYPE_CHECKING:
|
|
74
90
|
|
75
91
|
|
76
92
|
def _validate_cloning(evaluated_args: list[Evaluated]) -> None:
|
77
|
-
handles =
|
78
|
-
|
93
|
+
handles = chain.from_iterable(
|
94
|
+
(
|
95
|
+
[arg.value.handle]
|
96
|
+
if isinstance(arg.value, QuantumSymbol)
|
97
|
+
else arg.value.handles if isinstance(arg.value, QuantumSymbolList) else []
|
98
|
+
)
|
79
99
|
for arg in evaluated_args
|
80
|
-
|
81
|
-
]
|
100
|
+
)
|
82
101
|
for handle, other_handle in combinations(handles, 2):
|
83
102
|
if handle.overlaps(other_handle):
|
84
103
|
if handle == other_handle:
|
@@ -130,7 +149,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
130
149
|
self,
|
131
150
|
function: FunctionClosure,
|
132
151
|
args: list[ArgValue],
|
133
|
-
propagated_debug_info: FunctionDebugInfo
|
152
|
+
propagated_debug_info: Optional[FunctionDebugInfo],
|
134
153
|
) -> QuantumFunctionCall:
|
135
154
|
call = self._create_quantum_function_call(
|
136
155
|
function, args, propagated_debug_info=propagated_debug_info
|
@@ -140,8 +159,8 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
140
159
|
|
141
160
|
@staticmethod
|
142
161
|
def _get_back_ref(
|
143
|
-
propagated_debug_info: FunctionDebugInfo
|
144
|
-
) -> UUID
|
162
|
+
propagated_debug_info: Optional[FunctionDebugInfo],
|
163
|
+
) -> Optional[UUID]:
|
145
164
|
if propagated_debug_info is None:
|
146
165
|
return None
|
147
166
|
if propagated_debug_info.node is None:
|
@@ -152,7 +171,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
152
171
|
self,
|
153
172
|
function: FunctionClosure,
|
154
173
|
args: list[ArgValue],
|
155
|
-
propagated_debug_info: FunctionDebugInfo
|
174
|
+
propagated_debug_info: Optional[FunctionDebugInfo],
|
156
175
|
) -> QuantumFunctionCall:
|
157
176
|
function = function.clone()
|
158
177
|
function = function.set_depth(self._builder.current_function.depth + 1)
|
@@ -164,19 +183,22 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
164
183
|
)
|
165
184
|
new_positional_arg_decls = new_declaration.positional_arg_declarations
|
166
185
|
if not self.should_expand_function(function, evaluated_args):
|
167
|
-
is_atomic = True
|
168
186
|
new_declaration = self._expanded_functions_by_name.get(
|
169
187
|
function.name, new_declaration
|
170
188
|
)
|
171
189
|
else:
|
172
|
-
is_atomic = False
|
173
190
|
new_declaration = self._expand_function(
|
174
191
|
evaluated_args, new_declaration, function
|
175
192
|
)
|
193
|
+
new_positional_arg_decls = new_declaration.positional_arg_declarations
|
194
|
+
evaluated_args = [
|
195
|
+
arg
|
196
|
+
for arg in evaluated_args
|
197
|
+
if isinstance(arg.value, QuantumVariable) or _is_symbolic(arg.value)
|
198
|
+
]
|
176
199
|
|
177
|
-
|
178
|
-
|
179
|
-
)
|
200
|
+
add_information_from_output_arguments(new_positional_arg_decls, evaluated_args)
|
201
|
+
new_positional_args = [arg.emit() for arg in evaluated_args]
|
180
202
|
captured_args = function.captured_vars.filter_vars(function).get_captured_args(
|
181
203
|
self._builder.current_function
|
182
204
|
)
|
@@ -219,18 +241,20 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
219
241
|
function: FunctionClosure,
|
220
242
|
) -> NamedParamsQuantumFunctionDeclaration:
|
221
243
|
self._add_params_to_scope(decl.positional_arg_declarations, args, function)
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
244
|
+
function = function.with_new_declaration(decl)
|
245
|
+
cache_key = get_func_call_cache_key(decl, args)
|
246
|
+
if cache_key in self._expanded_functions:
|
247
|
+
function_def = self._expanded_functions[cache_key]
|
248
|
+
self._expand_cached_function(function, function_def)
|
227
249
|
self._expanded_functions_compilation_metadata[
|
228
250
|
function_def.name
|
229
251
|
].occurrences_number += 1
|
230
252
|
return function_def
|
231
253
|
|
254
|
+
context = self._expand_operation(function)
|
255
|
+
function_context = cast(FunctionContext, context)
|
232
256
|
function_def = self._create_function_definition(function_context, args)
|
233
|
-
self._expanded_functions[
|
257
|
+
self._expanded_functions[cache_key] = function_def
|
234
258
|
self._top_level_scope[function_def.name] = Evaluated(
|
235
259
|
value=function_context.closure.with_new_declaration(function_def)
|
236
260
|
)
|
@@ -260,6 +284,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
260
284
|
)
|
261
285
|
captured_ports = captured_vars.get_captured_parameters()
|
262
286
|
if len(captured_ports) == 0:
|
287
|
+
self._override_type_qualifier(function_context, func_def)
|
263
288
|
return func_def
|
264
289
|
func_def.positional_arg_declarations = list(
|
265
290
|
chain.from_iterable((func_def.positional_arg_declarations, captured_ports))
|
@@ -271,6 +296,8 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
271
296
|
rewrite_mapping |= captured_vars.get_classical_captured_mapping()
|
272
297
|
func_def.body = self.rewrite(func_def.body, rewrite_mapping)
|
273
298
|
|
299
|
+
self._override_type_qualifier(function_context, func_def)
|
300
|
+
|
274
301
|
return func_def
|
275
302
|
|
276
303
|
@staticmethod
|
@@ -281,7 +308,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
281
308
|
) -> None:
|
282
309
|
for parameter, argument in zip(parameters, arguments):
|
283
310
|
param_handle = HandleBinding(name=parameter.name)
|
284
|
-
if isinstance(argument.value,
|
311
|
+
if isinstance(argument.value, QuantumVariable):
|
285
312
|
assert isinstance(parameter, PortDeclaration)
|
286
313
|
closure.scope[parameter.name] = Evaluated(
|
287
314
|
QuantumSymbol(
|
@@ -299,26 +326,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
299
326
|
else:
|
300
327
|
closure.scope[parameter.name] = argument
|
301
328
|
|
302
|
-
def _get_new_positional_args(
|
303
|
-
self,
|
304
|
-
evaluated_args: list[Evaluated],
|
305
|
-
is_atomic: bool,
|
306
|
-
new_positional_arg_decls: Sequence[PositionalArg],
|
307
|
-
) -> list[ArgValue]:
|
308
|
-
evaluated_args = add_information_from_output_arguments(
|
309
|
-
new_positional_arg_decls, evaluated_args
|
310
|
-
)
|
311
|
-
if is_atomic:
|
312
|
-
return [arg.emit() for arg in evaluated_args]
|
313
|
-
|
314
|
-
positional_args = [
|
315
|
-
arg.emit()
|
316
|
-
for arg in evaluated_args
|
317
|
-
if isinstance(arg.value, QuantumSymbol) or _is_symbolic(arg.value)
|
318
|
-
]
|
319
|
-
|
320
|
-
return positional_args
|
321
|
-
|
322
329
|
def _prepare_fully_typed_declaration(
|
323
330
|
self, function: FunctionClosure, evaluated_args: list[Evaluated]
|
324
331
|
) -> NamedParamsQuantumFunctionDeclaration:
|
@@ -371,3 +378,45 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
371
378
|
raise ClassiqExpansionError(UNINITIALIZED_VAR_MESSAGE.format(var_name))
|
372
379
|
if var_state and param.direction == PortDeclarationDirection.Output:
|
373
380
|
raise ClassiqExpansionError(INITIALIZED_VAR_MESSAGE.format(var_name))
|
381
|
+
|
382
|
+
def _override_type_qualifier(
|
383
|
+
self, func_context: FunctionContext, func_def: NativeFunctionDefinition
|
384
|
+
) -> None:
|
385
|
+
"""
|
386
|
+
The type qualifier can be changed according to the operand passed to the
|
387
|
+
function. For example,
|
388
|
+
apply_to_all(X, q) --> q will be QFree after expansion
|
389
|
+
apply_to_all(H, q) --> q will be Quantum after expansion
|
390
|
+
This also holds for the intermediate lambda created during the expansion.
|
391
|
+
|
392
|
+
We don't override the type qualifier if it's explicitly specified (QFree or
|
393
|
+
Const), neither in the function declaration nor in the operand declaration.
|
394
|
+
"""
|
395
|
+
|
396
|
+
if func_context.is_lambda:
|
397
|
+
self._update_type_qualifiers(func_def)
|
398
|
+
return
|
399
|
+
|
400
|
+
orig_name = func_context.name
|
401
|
+
if (
|
402
|
+
orig_name == MAIN_FUNCTION_NAME
|
403
|
+
or orig_name not in func_context.closure.scope
|
404
|
+
):
|
405
|
+
return
|
406
|
+
|
407
|
+
orig_func = func_context.closure.scope[orig_name].value
|
408
|
+
if isinstance(orig_func, Closure) and not any(
|
409
|
+
isinstance(param_decl, QuantumOperandDeclaration)
|
410
|
+
for param_decl in orig_func.positional_arg_declarations
|
411
|
+
):
|
412
|
+
return
|
413
|
+
|
414
|
+
self._update_type_qualifiers(func_def)
|
415
|
+
|
416
|
+
@staticmethod
|
417
|
+
def _update_type_qualifiers(func_def: NativeFunctionDefinition) -> None:
|
418
|
+
# only override the qualifier if it's unspecified (not QFree or Const)
|
419
|
+
for port in func_def.port_declarations:
|
420
|
+
if port.type_qualifier is TypeQualifier.Quantum:
|
421
|
+
port.type_qualifier = TypeQualifier.Inferred
|
422
|
+
TypeQualifierInference().run(func_def.port_declarations, func_def.body)
|
@@ -47,7 +47,7 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
47
47
|
)
|
48
48
|
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
49
49
|
|
50
|
-
from classiq.model_expansions.closure import Closure, GenerativeClosure
|
50
|
+
from classiq.model_expansions.closure import Closure, FunctionClosure, GenerativeClosure
|
51
51
|
from classiq.model_expansions.function_builder import (
|
52
52
|
OperationBuilder,
|
53
53
|
OperationContext,
|
@@ -87,6 +87,11 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
87
87
|
def _expand_operation(self, closure: Closure) -> OperationContext:
|
88
88
|
return self._interpreter._expand_operation(closure)
|
89
89
|
|
90
|
+
def _expand_cached_function(
|
91
|
+
self, closure: FunctionClosure, func_def: NativeFunctionDefinition
|
92
|
+
) -> None:
|
93
|
+
return self._interpreter._expand_cached_function(closure, func_def)
|
94
|
+
|
90
95
|
@property
|
91
96
|
def _builder(self) -> OperationBuilder:
|
92
97
|
return self._interpreter._builder
|
@@ -181,12 +186,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
181
186
|
self._capture_classical_var(var_name, var_type)
|
182
187
|
|
183
188
|
def _update_captured_vars(self, op: QuantumOperation) -> None:
|
184
|
-
|
185
|
-
[(handle, PortDeclarationDirection.Input) for handle in op.inputs]
|
186
|
-
+ [(handle, PortDeclarationDirection.Output) for handle in op.outputs]
|
187
|
-
+ [(handle, PortDeclarationDirection.Inout) for handle in op.inouts]
|
188
|
-
)
|
189
|
-
for handle, direction in handles:
|
189
|
+
for handle, direction in op.handles_with_directions:
|
190
190
|
self._capture_handle(handle, direction)
|
191
191
|
|
192
192
|
def _capture_handle(
|