classiq 0.60.1__py3-none-any.whl → 0.62.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/__init__.py +2 -0
- classiq/_internals/client.py +6 -1
- classiq/applications/__init__.py +1 -1
- classiq/applications/chemistry/__init__.py +7 -7
- classiq/applications/chemistry/chemistry_model_constructor.py +17 -6
- classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +60 -9
- classiq/applications/combinatorial_optimization/__init__.py +7 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +230 -0
- classiq/applications/finance/finance_model_constructor.py +6 -6
- classiq/applications/grover/grover_model_constructor.py +3 -0
- classiq/applications/libraries/qmci_library.py +1 -10
- classiq/applications/qnn/__init__.py +1 -1
- classiq/applications/qnn/datasets/__init__.py +8 -8
- classiq/applications/qsvm/qsvm.py +1 -1
- classiq/execution/__init__.py +0 -2
- classiq/execution/execution_session.py +6 -0
- classiq/execution/jobs.py +9 -1
- classiq/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +33 -15
- classiq/interface/backend/quantum_backend_providers.py +3 -1
- classiq/interface/executor/execution_preferences.py +1 -1
- classiq/interface/generator/application_apis/chemistry_declarations.py +1 -1
- classiq/interface/generator/application_apis/finance_declarations.py +2 -2
- classiq/interface/generator/arith/arithmetic.py +16 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +4 -3
- classiq/interface/generator/copy.py +47 -0
- classiq/interface/generator/expressions/expression_constants.py +3 -0
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/generated_circuit_data.py +58 -20
- classiq/interface/generator/model/__init__.py +1 -1
- classiq/interface/generator/model/preferences/preferences.py +1 -1
- classiq/interface/generator/model/quantum_register.py +3 -3
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +20 -32
- classiq/interface/generator/types/compilation_metadata.py +2 -1
- classiq/interface/ide/visual_model.py +1 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/model.py +2 -3
- classiq/interface/model/quantum_function_call.py +4 -7
- classiq/interface/model/quantum_function_declaration.py +7 -0
- classiq/interface/model/quantum_lambda_function.py +10 -1
- classiq/interface/model/quantum_type.py +3 -1
- classiq/model_expansions/atomic_expression_functions_defs.py +3 -1
- classiq/model_expansions/capturing/captured_vars.py +36 -17
- classiq/model_expansions/capturing/mangling_utils.py +23 -15
- classiq/model_expansions/closure.py +6 -9
- classiq/model_expansions/evaluators/arg_type_match.py +7 -7
- classiq/model_expansions/expression_evaluator.py +5 -2
- classiq/model_expansions/function_builder.py +26 -4
- classiq/model_expansions/generative_functions.py +13 -91
- classiq/model_expansions/interpreter.py +75 -46
- classiq/model_expansions/quantum_operations/call_emitter.py +42 -29
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +5 -31
- classiq/model_expansions/quantum_operations/emitter.py +29 -17
- classiq/model_expansions/quantum_operations/expression_operation.py +3 -5
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +57 -15
- classiq/model_expansions/quantum_operations/invert.py +1 -6
- classiq/model_expansions/quantum_operations/phase.py +2 -5
- classiq/model_expansions/quantum_operations/power.py +0 -4
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +19 -30
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -2
- classiq/model_expansions/quantum_operations/shallow_emitter.py +161 -0
- classiq/model_expansions/quantum_operations/within_apply.py +0 -14
- classiq/model_expansions/scope.py +12 -16
- classiq/model_expansions/scope_initialization.py +0 -11
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +7 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +12 -2
- classiq/model_expansions/transformers/ast_renamer.py +26 -0
- classiq/model_expansions/transformers/var_splitter.py +11 -12
- classiq/model_expansions/visitors/variable_references.py +20 -12
- classiq/qmod/builtins/classical_execution_primitives.py +6 -6
- classiq/qmod/builtins/classical_functions.py +10 -10
- classiq/qmod/builtins/functions/__init__.py +89 -103
- classiq/qmod/builtins/functions/amplitude_estimation.py +1 -1
- classiq/qmod/builtins/functions/arithmetic.py +1 -1
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +6 -6
- classiq/qmod/builtins/functions/grover.py +5 -5
- classiq/qmod/builtins/functions/hea.py +1 -1
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +2 -2
- classiq/qmod/builtins/functions/modular_exponentiation.py +8 -8
- classiq/qmod/builtins/functions/operators.py +1 -1
- classiq/qmod/builtins/functions/qaoa_penalty.py +5 -5
- classiq/qmod/builtins/functions/qft_functions.py +2 -2
- classiq/qmod/builtins/functions/qpe.py +9 -12
- classiq/qmod/builtins/functions/qsvt.py +177 -15
- classiq/qmod/builtins/functions/state_preparation.py +9 -9
- classiq/qmod/builtins/functions/swap_test.py +1 -1
- classiq/qmod/builtins/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/functions/variational.py +2 -2
- classiq/qmod/builtins/operations.py +22 -83
- classiq/qmod/builtins/structs.py +9 -9
- classiq/qmod/native/pretty_printer.py +17 -19
- classiq/qmod/pretty_print/pretty_printer.py +9 -6
- classiq/qmod/python_classical_type.py +1 -5
- classiq/qmod/qmod_variable.py +2 -5
- classiq/qmod/quantum_expandable.py +20 -5
- classiq/qmod/quantum_function.py +23 -10
- classiq/qmod/semantics/static_semantics_visitor.py +34 -16
- classiq/qmod/semantics/validation/func_call_validation.py +9 -5
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
- classiq/qmod/symbolic.py +47 -47
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/METADATA +2 -1
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/RECORD +107 -103
- classiq/execution/qaoa.py +0 -86
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
import
|
2
|
-
from collections.abc import
|
3
|
-
from contextlib import
|
1
|
+
from collections import defaultdict
|
2
|
+
from collections.abc import Sequence
|
3
|
+
from contextlib import nullcontext
|
4
4
|
from functools import singledispatchmethod
|
5
5
|
from typing import Any, Optional, cast
|
6
6
|
|
@@ -15,6 +15,11 @@ from classiq.interface.exceptions import (
|
|
15
15
|
)
|
16
16
|
from classiq.interface.generator.constant import Constant
|
17
17
|
from classiq.interface.generator.expressions.expression import Expression
|
18
|
+
from classiq.interface.generator.functions.builtins.internal_operators import (
|
19
|
+
CONTROL_OPERATOR_NAME,
|
20
|
+
INVERT_OPERATOR_NAME,
|
21
|
+
WITHIN_APPLY_NAME,
|
22
|
+
)
|
18
23
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
19
24
|
from classiq.interface.model.bind_operation import BindOperation
|
20
25
|
from classiq.interface.model.classical_if import ClassicalIf
|
@@ -35,14 +40,16 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
35
40
|
QuantumAssignmentOperation,
|
36
41
|
)
|
37
42
|
from classiq.interface.model.quantum_function_call import (
|
38
|
-
OperandIdentifier,
|
39
43
|
QuantumFunctionCall,
|
40
44
|
)
|
41
45
|
from classiq.interface.model.quantum_function_declaration import (
|
42
46
|
NamedParamsQuantumFunctionDeclaration,
|
43
47
|
QuantumFunctionDeclaration,
|
44
48
|
)
|
45
|
-
from classiq.interface.model.quantum_lambda_function import
|
49
|
+
from classiq.interface.model.quantum_lambda_function import (
|
50
|
+
OperandIdentifier,
|
51
|
+
QuantumLambdaFunction,
|
52
|
+
)
|
46
53
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
47
54
|
from classiq.interface.model.repeat import Repeat
|
48
55
|
from classiq.interface.model.variable_declaration_statement import (
|
@@ -81,6 +88,7 @@ from classiq.model_expansions.quantum_operations import (
|
|
81
88
|
WithinApplyEmitter,
|
82
89
|
)
|
83
90
|
from classiq.model_expansions.quantum_operations.phase import PhaseEmitter
|
91
|
+
from classiq.model_expansions.quantum_operations.shallow_emitter import ShallowEmitter
|
84
92
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
85
93
|
from classiq.model_expansions.scope_initialization import (
|
86
94
|
add_constants_to_scope,
|
@@ -103,43 +111,30 @@ class Interpreter:
|
|
103
111
|
) -> None:
|
104
112
|
self._is_frontend = is_frontend
|
105
113
|
self._model = model
|
106
|
-
self.
|
107
|
-
self._top_level_scope = self._current_scope
|
114
|
+
self._top_level_scope = Scope()
|
108
115
|
self._builder = OperationBuilder(self._top_level_scope)
|
109
116
|
self._expanded_functions: dict[str, NativeFunctionDefinition] = {}
|
110
117
|
|
111
|
-
self._main_renamer: ExpressionRenamer =
|
118
|
+
self._main_renamer: Optional[ExpressionRenamer] = (
|
119
|
+
get_main_renamer(self._model.functions) if self._is_frontend else None
|
120
|
+
)
|
112
121
|
|
113
122
|
if generative_functions is None:
|
114
123
|
generative_functions = []
|
115
124
|
self._generative_functions = generative_functions
|
116
|
-
init_top_level_scope(model, generative_functions, self.
|
125
|
+
init_top_level_scope(model, generative_functions, self._top_level_scope)
|
117
126
|
self._expanded_functions_compilation_metadata: dict[
|
118
127
|
str, CompilationMetadata
|
119
|
-
] =
|
128
|
+
] = defaultdict(CompilationMetadata)
|
120
129
|
self._counted_name_allocator = CountedNameAllocator()
|
121
130
|
self._error_manager: ErrorManager = ErrorManager()
|
122
131
|
|
123
|
-
@contextmanager
|
124
|
-
def _scope_guard(self, scope: Scope) -> Iterator[None]:
|
125
|
-
"""This manager restores both `scope` and `self._current_scope` to their previous values."""
|
126
|
-
scope_data = copy.copy(scope.data)
|
127
|
-
prev_context_scope_data = copy.copy(self._current_scope.data)
|
128
|
-
|
129
|
-
prev_context_scope = self._current_scope
|
130
|
-
self._current_scope = scope
|
131
|
-
yield
|
132
|
-
prev_context_scope.data = prev_context_scope_data
|
133
|
-
self._current_scope = prev_context_scope
|
134
|
-
|
135
|
-
scope.data = scope_data
|
136
|
-
|
137
132
|
def _expand_main_func(self) -> None:
|
138
133
|
main_closure = FunctionClosure.create(
|
139
134
|
name=self._model.main_func.name,
|
140
135
|
positional_arg_declarations=self._model.main_func.positional_arg_declarations,
|
141
136
|
body=self._model.main_func.body,
|
142
|
-
scope=Scope(parent=self.
|
137
|
+
scope=Scope(parent=self._top_level_scope),
|
143
138
|
expr_renamer=self._main_renamer,
|
144
139
|
_depth=0,
|
145
140
|
)
|
@@ -188,11 +183,11 @@ class Interpreter:
|
|
188
183
|
|
189
184
|
@evaluate.register
|
190
185
|
def evaluate_classical_expression(self, expression: Expression) -> Evaluated:
|
191
|
-
return evaluate_classical_expression(expression, self.
|
186
|
+
return evaluate_classical_expression(expression, self._builder.current_scope)
|
192
187
|
|
193
188
|
@evaluate.register
|
194
189
|
def evaluate_identifier(self, identifier: str) -> Evaluated:
|
195
|
-
return self.
|
190
|
+
return self._builder.current_scope[identifier]
|
196
191
|
|
197
192
|
@evaluate.register
|
198
193
|
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
@@ -223,7 +218,7 @@ class Interpreter:
|
|
223
218
|
name=func_decl.name,
|
224
219
|
positional_arg_declarations=func_decl.positional_arg_declarations,
|
225
220
|
body=function.body,
|
226
|
-
scope=Scope(parent=self.
|
221
|
+
scope=Scope(parent=self._builder.current_scope),
|
227
222
|
is_lambda=True,
|
228
223
|
**extra_args,
|
229
224
|
),
|
@@ -280,11 +275,21 @@ class Interpreter:
|
|
280
275
|
|
281
276
|
@emit.register
|
282
277
|
def emit_quantum_assignment_operation(self, op: QuantumAssignmentOperation) -> None:
|
283
|
-
|
278
|
+
if self._is_frontend:
|
279
|
+
ShallowEmitter(
|
280
|
+
self, "assignment_operation", components=["expression", "result_var"]
|
281
|
+
).emit(op)
|
282
|
+
else:
|
283
|
+
QuantumAssignmentOperationEmitter(self).emit(op)
|
284
284
|
|
285
285
|
@emit.register
|
286
|
-
def emit_inplace_binary_operation(self,
|
287
|
-
|
286
|
+
def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
|
287
|
+
if self._is_frontend:
|
288
|
+
ShallowEmitter(
|
289
|
+
self, "inplace_binary_operation", components=["target", "value"]
|
290
|
+
).emit(op)
|
291
|
+
else:
|
292
|
+
InplaceBinaryOperationEmitter(self).emit(op)
|
288
293
|
|
289
294
|
@emit.register
|
290
295
|
def emit_variable_declaration(
|
@@ -298,11 +303,21 @@ class Interpreter:
|
|
298
303
|
|
299
304
|
@emit.register
|
300
305
|
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
301
|
-
|
306
|
+
if self._is_frontend:
|
307
|
+
ShallowEmitter(
|
308
|
+
self,
|
309
|
+
WITHIN_APPLY_NAME,
|
310
|
+
components=["within", "apply", "compute", "action"],
|
311
|
+
).emit(within_apply)
|
312
|
+
else:
|
313
|
+
WithinApplyEmitter(self).emit(within_apply)
|
302
314
|
|
303
315
|
@emit.register
|
304
316
|
def emit_invert(self, invert: Invert) -> None:
|
305
|
-
|
317
|
+
if self._is_frontend:
|
318
|
+
ShallowEmitter(self, INVERT_OPERATOR_NAME, components=["body"]).emit(invert)
|
319
|
+
else:
|
320
|
+
InvertEmitter(self).emit(invert)
|
306
321
|
|
307
322
|
@emit.register
|
308
323
|
def emit_repeat(self, repeat: Repeat) -> None:
|
@@ -310,15 +325,32 @@ class Interpreter:
|
|
310
325
|
|
311
326
|
@emit.register
|
312
327
|
def emit_control(self, control: Control) -> None:
|
313
|
-
|
328
|
+
if self._is_frontend:
|
329
|
+
ShallowEmitter(
|
330
|
+
self,
|
331
|
+
CONTROL_OPERATOR_NAME,
|
332
|
+
components=["expression", "body", "else_block"],
|
333
|
+
).emit(control)
|
334
|
+
else:
|
335
|
+
ControlEmitter(self).emit(control)
|
314
336
|
|
315
337
|
@emit.register
|
316
338
|
def emit_power(self, power: Power) -> None:
|
317
|
-
|
339
|
+
if self._is_frontend:
|
340
|
+
ShallowEmitter(
|
341
|
+
self, CONTROL_OPERATOR_NAME, components=["power", "body"]
|
342
|
+
).emit(power)
|
343
|
+
else:
|
344
|
+
PowerEmitter(self).emit(power)
|
318
345
|
|
319
346
|
@emit.register
|
320
347
|
def emit_phase(self, phase: PhaseOperation) -> None:
|
321
|
-
|
348
|
+
if self._is_frontend:
|
349
|
+
ShallowEmitter(self, "phase", components=["expression", "theta"]).emit(
|
350
|
+
phase
|
351
|
+
)
|
352
|
+
else:
|
353
|
+
PhaseEmitter(self).emit(phase)
|
322
354
|
|
323
355
|
def _expand_block(self, block: Sequence[QuantumStatement], block_name: str) -> None:
|
324
356
|
with self._builder.block_context(block_name):
|
@@ -343,19 +375,16 @@ class Interpreter:
|
|
343
375
|
pass
|
344
376
|
elif isinstance(operation, FunctionClosure) and operation.name == "permute":
|
345
377
|
# special expansion since permute is generative
|
346
|
-
|
347
|
-
self._expand_permute()
|
378
|
+
self._expand_permute()
|
348
379
|
elif isinstance(operation, GenerativeClosure):
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
emit_generative_statements(self, operation, args)
|
380
|
+
args = [
|
381
|
+
self.evaluate(param.name)
|
382
|
+
for param in operation.positional_arg_declarations
|
383
|
+
]
|
384
|
+
emit_generative_statements(self, operation, args)
|
355
385
|
else:
|
356
386
|
for block, block_body in operation.blocks.items():
|
357
|
-
|
358
|
-
self._expand_block(block_body, block)
|
387
|
+
self._expand_block(block_body, block)
|
359
388
|
|
360
389
|
return context
|
361
390
|
|
@@ -3,6 +3,7 @@ from itertools import chain
|
|
3
3
|
from typing import (
|
4
4
|
TYPE_CHECKING,
|
5
5
|
Generic,
|
6
|
+
Optional,
|
6
7
|
cast,
|
7
8
|
)
|
8
9
|
|
@@ -37,7 +38,6 @@ from classiq.model_expansions.evaluators.parameter_types import (
|
|
37
38
|
from classiq.model_expansions.function_builder import (
|
38
39
|
FunctionContext,
|
39
40
|
)
|
40
|
-
from classiq.model_expansions.generative_functions import emit_operands_as_declarative
|
41
41
|
from classiq.model_expansions.quantum_operations.emitter import (
|
42
42
|
Emitter,
|
43
43
|
QuantumStatementT,
|
@@ -53,7 +53,7 @@ if TYPE_CHECKING:
|
|
53
53
|
class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSplitter):
|
54
54
|
def __init__(self, interpreter: "Interpreter") -> None:
|
55
55
|
Emitter.__init__(self, interpreter)
|
56
|
-
VarSplitter.__init__(self, interpreter.
|
56
|
+
VarSplitter.__init__(self, interpreter._builder.current_scope)
|
57
57
|
|
58
58
|
@staticmethod
|
59
59
|
def _should_wrap(body: Sequence[QuantumStatement]) -> bool:
|
@@ -73,17 +73,25 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
73
73
|
return self._create_quantum_function_call(wrapping_function, list())
|
74
74
|
|
75
75
|
def _emit_quantum_function_call(
|
76
|
-
self,
|
76
|
+
self,
|
77
|
+
function: FunctionClosure,
|
78
|
+
args: list[ArgValue],
|
79
|
+
propagated_debug_info: Optional[FunctionDebugInfo] = None,
|
77
80
|
) -> QuantumFunctionCall:
|
78
|
-
call = self._create_quantum_function_call(
|
81
|
+
call = self._create_quantum_function_call(
|
82
|
+
function, args, propagated_debug_info=propagated_debug_info
|
83
|
+
)
|
79
84
|
self.emit_statement(call)
|
80
85
|
return call
|
81
86
|
|
82
87
|
def _create_quantum_function_call(
|
83
|
-
self,
|
88
|
+
self,
|
89
|
+
function: FunctionClosure,
|
90
|
+
args: list[ArgValue],
|
91
|
+
propagated_debug_info: Optional[FunctionDebugInfo] = None,
|
84
92
|
) -> QuantumFunctionCall:
|
93
|
+
function = function.clone()
|
85
94
|
function = function.set_depth(self._builder.current_function.depth + 1)
|
86
|
-
function = function.copy_scope()
|
87
95
|
evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
|
88
96
|
new_declaration = self._prepare_fully_typed_declaration(
|
89
97
|
function, evaluated_args
|
@@ -107,15 +115,20 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
107
115
|
self._top_level_scope[function_def.name] = Evaluated(
|
108
116
|
value=function_context.closure.with_new_declaration(function_def)
|
109
117
|
)
|
118
|
+
compilation_metadata = self._functions_compilation_metadata.get(
|
119
|
+
function.name
|
120
|
+
)
|
121
|
+
if compilation_metadata is not None:
|
122
|
+
self._expanded_functions_compilation_metadata[function_def.name] = (
|
123
|
+
compilation_metadata
|
124
|
+
)
|
125
|
+
else:
|
126
|
+
self._expanded_functions_compilation_metadata[
|
127
|
+
function_def.name
|
128
|
+
].occurrences_number += 1
|
129
|
+
|
110
130
|
new_declaration = function_def
|
111
131
|
new_function_name = function_def.name
|
112
|
-
compilation_metadata = self._functions_compilation_metadata.get(
|
113
|
-
function.name
|
114
|
-
)
|
115
|
-
if compilation_metadata is not None:
|
116
|
-
self._expanded_functions_compilation_metadata[new_function_name] = (
|
117
|
-
compilation_metadata
|
118
|
-
)
|
119
132
|
|
120
133
|
new_positional_args = self._get_new_positional_args(
|
121
134
|
evaluated_args, is_atomic, new_positional_arg_decls
|
@@ -144,10 +157,14 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
144
157
|
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
145
158
|
if isinstance(arg_decl, PortDeclaration)
|
146
159
|
}
|
147
|
-
self.
|
160
|
+
self._debug_info[new_call.uuid] = FunctionDebugInfo(
|
148
161
|
name=new_call.func_name,
|
149
162
|
level=OperationLevel.QMOD_FUNCTION_CALL,
|
150
|
-
parameters=
|
163
|
+
parameters=(
|
164
|
+
parameters
|
165
|
+
if propagated_debug_info is None
|
166
|
+
else propagated_debug_info.parameters
|
167
|
+
),
|
151
168
|
is_allocate_or_free=is_allocate_or_free,
|
152
169
|
port_to_passed_variable_map=port_to_passed_variable_map,
|
153
170
|
)
|
@@ -203,10 +220,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
203
220
|
new_positional_arg_decls, evaluated_args
|
204
221
|
)
|
205
222
|
if is_atomic:
|
206
|
-
return [
|
207
|
-
emit_operands_as_declarative(self._interpreter, param, arg)
|
208
|
-
for param, arg in zip(new_positional_arg_decls, evaluated_args)
|
209
|
-
]
|
223
|
+
return [arg.emit() for arg in evaluated_args]
|
210
224
|
|
211
225
|
positional_args = [
|
212
226
|
arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
|
@@ -230,13 +244,12 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
230
244
|
different from the call scope. For example, the former uses r,s and the latter
|
231
245
|
uses p, q.
|
232
246
|
"""
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
)
|
247
|
+
# The signature scope is passed as a separate argument to avoid contaminating the statement execution scope
|
248
|
+
return NamedParamsQuantumFunctionDeclaration(
|
249
|
+
name=function.name,
|
250
|
+
positional_arg_declarations=evaluate_parameter_types_from_args(
|
251
|
+
function,
|
252
|
+
function.signature_scope,
|
253
|
+
evaluated_args,
|
254
|
+
),
|
255
|
+
)
|
@@ -26,7 +26,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
|
26
26
|
if is_generative:
|
27
27
|
if not classical_if.has_generative_block(op_name):
|
28
28
|
return
|
29
|
-
context = self.
|
29
|
+
context = self._expand_generative_context(classical_if, op_name, op_name)
|
30
30
|
context.blocks["body"] = context.blocks[op_name]
|
31
31
|
context.blocks.pop(op_name)
|
32
32
|
body = context.statements("body")
|
@@ -55,19 +55,16 @@ from classiq.qmod.builtins.functions.standard_gates import X
|
|
55
55
|
|
56
56
|
class ControlEmitter(ExpressionOperationEmitter[Control]):
|
57
57
|
def emit(self, control: Control, /) -> None:
|
58
|
-
condition =
|
59
|
-
|
58
|
+
condition = control.expression
|
60
59
|
arrays_with_subscript = self.split_symbols(
|
61
60
|
condition, self._counted_name_allocator.allocate
|
62
61
|
)
|
63
62
|
if len(arrays_with_subscript) > 0:
|
64
|
-
if control.is_generative():
|
65
|
-
control = self._expand_generative_control(control)
|
66
63
|
self._emit_with_split(control, condition, arrays_with_subscript)
|
67
64
|
return
|
68
65
|
|
69
|
-
control = self._evaluate_types_in_expression(control
|
70
|
-
condition_val =
|
66
|
+
control = self._evaluate_types_in_expression(control)
|
67
|
+
condition_val = control.expression.value.value
|
71
68
|
if isinstance(condition_val, QmodSizedProxy):
|
72
69
|
if control.else_block is None:
|
73
70
|
self._validate_canonical_condition(condition_val)
|
@@ -96,25 +93,9 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
96
93
|
)
|
97
94
|
return Expression(expr=f"{lhs} == 1")
|
98
95
|
|
99
|
-
def _expand_generative_control(self, control: Control) -> Control:
|
100
|
-
block_names = ["body"]
|
101
|
-
if control.has_generative_block("else_block"):
|
102
|
-
block_names += ["else_block"]
|
103
|
-
context = self._register_generative_context(
|
104
|
-
control, CONTROL_OPERATOR_NAME, block_names
|
105
|
-
)
|
106
|
-
new_blocks = {"body": context.statements("body")}
|
107
|
-
if "else_block" in block_names:
|
108
|
-
new_blocks["else_block"] = context.statements("else_block")
|
109
|
-
return control.model_copy(update=new_blocks)
|
110
|
-
|
111
96
|
def _emit_canonical_control(self, control: Control) -> None:
|
112
97
|
# canonical means control(q, body) where q is a single quantum variable
|
113
|
-
|
114
|
-
if is_generative:
|
115
|
-
control = self._expand_generative_control(control)
|
116
|
-
|
117
|
-
if not is_generative and self._should_wrap_control(control):
|
98
|
+
if self._should_wrap_control(control):
|
118
99
|
self._emit_wrapped(control)
|
119
100
|
return
|
120
101
|
self._emit_as_operation(control)
|
@@ -211,12 +192,6 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
211
192
|
compute=[else_compute_call],
|
212
193
|
action=[control_else_inner],
|
213
194
|
)
|
214
|
-
if control_else_inner.is_generative():
|
215
|
-
control_then.remove_generative_block("else_block")
|
216
|
-
control_else_inner.set_generative_block(
|
217
|
-
"body", control_else_inner.get_generative_block("else_block")
|
218
|
-
)
|
219
|
-
control_else_inner.remove_generative_block("else_block")
|
220
195
|
return [control_then, control_else]
|
221
196
|
|
222
197
|
def _control_with_x_gates(
|
@@ -296,8 +271,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
296
271
|
condition_value = control.expression.value.value
|
297
272
|
if not (
|
298
273
|
isinstance(condition_value, Boolean)
|
299
|
-
or self._all_vars_boolean(control)
|
300
|
-
and self._is_res_boolean(control)
|
274
|
+
or (self._all_vars_boolean(control) and self._is_res_boolean(control))
|
301
275
|
):
|
302
276
|
raise ClassiqExpansionError(_condition_err_msg(condition_value))
|
303
277
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import ast
|
1
2
|
from abc import abstractmethod
|
2
3
|
from typing import (
|
3
4
|
TYPE_CHECKING,
|
@@ -9,6 +10,7 @@ from typing import (
|
|
9
10
|
|
10
11
|
import sympy
|
11
12
|
|
13
|
+
from classiq.interface.debug_info.debug_info import DebugInfoCollection
|
12
14
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
13
15
|
from classiq.interface.generator.expressions.evaluated_expression import (
|
14
16
|
EvaluatedExpression,
|
@@ -24,9 +26,8 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
24
26
|
)
|
25
27
|
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
26
28
|
|
27
|
-
from classiq.model_expansions.closure import Closure,
|
29
|
+
from classiq.model_expansions.closure import Closure, GenerativeClosure
|
28
30
|
from classiq.model_expansions.function_builder import (
|
29
|
-
FunctionContext,
|
30
31
|
OperationBuilder,
|
31
32
|
OperationContext,
|
32
33
|
)
|
@@ -35,6 +36,7 @@ from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
|
35
36
|
translate_sympy_quantum_expression,
|
36
37
|
)
|
37
38
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
39
|
+
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
38
40
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
39
41
|
|
40
42
|
if TYPE_CHECKING:
|
@@ -47,7 +49,6 @@ class Emitter(Generic[QuantumStatementT]):
|
|
47
49
|
def __init__(self, interpreter: "Interpreter") -> None:
|
48
50
|
self._interpreter = interpreter
|
49
51
|
|
50
|
-
self._scope_guard = self._interpreter._scope_guard
|
51
52
|
self._machine_precision = self._interpreter._model.preferences.machine_precision
|
52
53
|
self._expanded_functions_compilation_metadata = (
|
53
54
|
self._interpreter._expanded_functions_compilation_metadata
|
@@ -55,20 +56,12 @@ class Emitter(Generic[QuantumStatementT]):
|
|
55
56
|
self._functions_compilation_metadata = (
|
56
57
|
self._interpreter._model.functions_compilation_metadata
|
57
58
|
)
|
58
|
-
self._generative_contexts: dict[str, OperationContext] = {}
|
59
59
|
|
60
60
|
@abstractmethod
|
61
61
|
def emit(self, statement: QuantumStatementT, /) -> None:
|
62
62
|
pass
|
63
63
|
|
64
64
|
def _expand_operation(self, closure: Closure) -> OperationContext:
|
65
|
-
if closure.name in self._generative_contexts:
|
66
|
-
if isinstance(closure, FunctionClosure):
|
67
|
-
return FunctionContext(
|
68
|
-
closure=closure,
|
69
|
-
blocks=self._generative_contexts[closure.name].blocks,
|
70
|
-
)
|
71
|
-
return self._generative_contexts[closure.name]
|
72
65
|
return self._interpreter._expand_operation(closure)
|
73
66
|
|
74
67
|
@property
|
@@ -77,7 +70,7 @@ class Emitter(Generic[QuantumStatementT]):
|
|
77
70
|
|
78
71
|
@property
|
79
72
|
def _current_scope(self) -> Scope:
|
80
|
-
return self.
|
73
|
+
return self._builder.current_scope
|
81
74
|
|
82
75
|
@property
|
83
76
|
def _top_level_scope(self) -> Scope:
|
@@ -91,7 +84,11 @@ class Emitter(Generic[QuantumStatementT]):
|
|
91
84
|
def _counted_name_allocator(self) -> CountedNameAllocator:
|
92
85
|
return self._interpreter._counted_name_allocator
|
93
86
|
|
94
|
-
|
87
|
+
@property
|
88
|
+
def _debug_info(self) -> DebugInfoCollection:
|
89
|
+
return self._interpreter._model.debug_info
|
90
|
+
|
91
|
+
def _expand_generative_context(
|
95
92
|
self,
|
96
93
|
op: QuantumOperation,
|
97
94
|
context_name: str,
|
@@ -106,7 +103,7 @@ class Emitter(Generic[QuantumStatementT]):
|
|
106
103
|
)
|
107
104
|
gen_closure = GenerativeClosure(
|
108
105
|
name=func_decl.name,
|
109
|
-
scope=Scope(parent=self._interpreter.
|
106
|
+
scope=Scope(parent=self._interpreter._builder.current_scope),
|
110
107
|
blocks={},
|
111
108
|
generative_blocks={
|
112
109
|
block_name: GenerativeQFunc(
|
@@ -116,15 +113,19 @@ class Emitter(Generic[QuantumStatementT]):
|
|
116
113
|
},
|
117
114
|
)
|
118
115
|
context = self._interpreter._expand_operation(gen_closure)
|
119
|
-
self._generative_contexts[context_name] = context
|
120
116
|
op.clear_generative_blocks()
|
121
117
|
return context
|
122
118
|
|
123
|
-
def _evaluate_expression(
|
119
|
+
def _evaluate_expression(
|
120
|
+
self, expression: Expression, preserve_bool_ops: bool = False
|
121
|
+
) -> Expression:
|
124
122
|
evaluated_expression = self._interpreter.evaluate(expression)
|
125
123
|
if isinstance(evaluated_expression.value, sympy.Basic):
|
126
124
|
new_expression = Expression(
|
127
|
-
expr=translate_sympy_quantum_expression(
|
125
|
+
expr=translate_sympy_quantum_expression(
|
126
|
+
evaluated_expression.value,
|
127
|
+
preserve_bool_ops=preserve_bool_ops,
|
128
|
+
)
|
128
129
|
)
|
129
130
|
else:
|
130
131
|
new_expression = Expression(expr=str(evaluated_expression.value))
|
@@ -162,3 +163,14 @@ class Emitter(Generic[QuantumStatementT]):
|
|
162
163
|
defining_function=defining_function,
|
163
164
|
direction=direction,
|
164
165
|
)
|
166
|
+
|
167
|
+
def capture_handles_in_expression(self, expr: Expression) -> None:
|
168
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
169
|
+
vrc.visit(ast.parse(expr.expr))
|
170
|
+
handles = dict.fromkeys(
|
171
|
+
handle
|
172
|
+
for handle in vrc.var_handles
|
173
|
+
if isinstance(self._current_scope[handle.name].value, QuantumSymbol)
|
174
|
+
)
|
175
|
+
for handle in handles:
|
176
|
+
self._capture_handle(handle, PortDeclarationDirection.Inout)
|
@@ -60,13 +60,11 @@ class ExpressionOperationEmitter(
|
|
60
60
|
) -> ExpressionOperationT:
|
61
61
|
return op
|
62
62
|
|
63
|
-
def _evaluate_op_expression(self, op: ExpressionOperationT) -> Expression:
|
64
|
-
return self._evaluate_expression(op.expression)
|
65
|
-
|
66
63
|
def _evaluate_types_in_expression(
|
67
|
-
self, op: ExpressionOperationT
|
64
|
+
self, op: ExpressionOperationT
|
68
65
|
) -> ExpressionOperationT:
|
69
|
-
|
66
|
+
new_expression = self._evaluate_expression(op.expression)
|
67
|
+
op_with_evaluated_types = op.model_copy(update={"expression": new_expression})
|
70
68
|
vrc = VarRefCollector()
|
71
69
|
vrc.visit(ast.parse(op_with_evaluated_types.expression.expr))
|
72
70
|
handles = vrc.var_handles
|