classiq 0.60.0__py3-none-any.whl → 0.61.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 +28 -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_optimization/__init__.py +7 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +197 -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/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +12 -12
- 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/expressions/expression_constants.py +3 -0
- classiq/interface/generator/generated_circuit_data.py +58 -20
- classiq/interface/generator/model/__init__.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/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 +24 -8
- classiq/model_expansions/capturing/mangling_utils.py +23 -15
- classiq/model_expansions/evaluators/arg_type_match.py +7 -7
- classiq/model_expansions/expression_evaluator.py +5 -2
- classiq/model_expansions/function_builder.py +21 -4
- classiq/model_expansions/generative_functions.py +12 -90
- classiq/model_expansions/interpreter.py +58 -11
- classiq/model_expansions/quantum_operations/call_emitter.py +19 -10
- 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 +27 -14
- 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 +3 -1
- classiq/model_expansions/quantum_operations/shallow_emitter.py +155 -0
- classiq/model_expansions/quantum_operations/within_apply.py +0 -14
- classiq/model_expansions/scope.py +10 -4
- 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 +3 -3
- 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/qmod_variable.py +2 -5
- classiq/qmod/quantum_expandable.py +18 -4
- classiq/qmod/quantum_function.py +19 -6
- 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.0.dist-info → classiq-0.61.0.dist-info}/METADATA +1 -1
- {classiq-0.60.0.dist-info → classiq-0.61.0.dist-info}/RECORD +97 -94
- classiq/execution/qaoa.py +0 -86
- {classiq-0.60.0.dist-info → classiq-0.61.0.dist-info}/WHEEL +0 -0
@@ -1,4 +1,5 @@
|
|
1
1
|
import ast
|
2
|
+
import re
|
2
3
|
from collections.abc import Mapping
|
3
4
|
from enum import EnumMeta
|
4
5
|
from typing import Any, Optional
|
@@ -12,7 +13,7 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
12
13
|
)
|
13
14
|
from classiq.interface.generator.expressions.expression import Expression
|
14
15
|
from classiq.interface.generator.expressions.expression_constants import (
|
15
|
-
|
16
|
+
CPARAM_EXECUTION_SUFFIX_PATTERN,
|
16
17
|
)
|
17
18
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
18
19
|
from classiq.interface.generator.expressions.sympy_supported_expressions import (
|
@@ -99,7 +100,9 @@ def _validate_undefined_vars(
|
|
99
100
|
|
100
101
|
# Ignore expanded execution parameters
|
101
102
|
undefined_vars = {
|
102
|
-
var
|
103
|
+
var
|
104
|
+
for var in undefined_vars
|
105
|
+
if not re.search(CPARAM_EXECUTION_SUFFIX_PATTERN, var)
|
103
106
|
}
|
104
107
|
|
105
108
|
if len(undefined_vars) == 1:
|
@@ -20,6 +20,9 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
20
20
|
PositionalArg,
|
21
21
|
)
|
22
22
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
23
|
+
from classiq.interface.model.variable_declaration_statement import (
|
24
|
+
VariableDeclarationStatement,
|
25
|
+
)
|
23
26
|
from classiq.interface.source_reference import SourceReference
|
24
27
|
|
25
28
|
from classiq.model_expansions.capturing.captured_vars import (
|
@@ -37,6 +40,14 @@ class Block:
|
|
37
40
|
statements: list[QuantumStatement] = field(default_factory=list)
|
38
41
|
captured_vars: CapturedVars = field(default_factory=CapturedVars)
|
39
42
|
|
43
|
+
@property
|
44
|
+
def variable_declarations(self) -> list[VariableDeclarationStatement]:
|
45
|
+
return [
|
46
|
+
stmt
|
47
|
+
for stmt in self.statements
|
48
|
+
if isinstance(stmt, VariableDeclarationStatement)
|
49
|
+
]
|
50
|
+
|
40
51
|
|
41
52
|
@dataclass
|
42
53
|
class OperationContext(Generic[ClosureType]):
|
@@ -123,9 +134,13 @@ class OperationBuilder:
|
|
123
134
|
not isinstance(self.current_operation, FunctionClosure)
|
124
135
|
and self.current_operation.name != WITHIN_APPLY_NAME
|
125
136
|
):
|
126
|
-
validate_captured_directions(
|
137
|
+
validate_captured_directions(
|
138
|
+
captured_vars.filter_vars(
|
139
|
+
self.current_function, self.current_block.variable_declarations
|
140
|
+
)
|
141
|
+
)
|
127
142
|
self.current_operation.captured_vars.update(
|
128
|
-
captured_vars.
|
143
|
+
captured_vars.filter_vars(self.current_function)
|
129
144
|
)
|
130
145
|
self._blocks.pop()
|
131
146
|
|
@@ -149,7 +164,7 @@ class OperationBuilder:
|
|
149
164
|
return
|
150
165
|
within_captured_vars = self._operations[-1].blocks["within"].captured_vars
|
151
166
|
self.current_operation.captured_vars.update(
|
152
|
-
within_captured_vars.
|
167
|
+
within_captured_vars.filter_vars(self.current_function).negate()
|
153
168
|
)
|
154
169
|
|
155
170
|
def _propagate_captured_vars(self) -> None:
|
@@ -160,7 +175,9 @@ class OperationBuilder:
|
|
160
175
|
if len(self._operations) < 2:
|
161
176
|
return
|
162
177
|
parent_block = self._operations[-2].blocks[self._blocks[-1]]
|
163
|
-
parent_block.captured_vars.update(
|
178
|
+
parent_block.captured_vars.update(
|
179
|
+
captured_vars.filter_vars(self.parent_function)
|
180
|
+
)
|
164
181
|
|
165
182
|
@contextmanager
|
166
183
|
def source_ref_context(
|
@@ -1,31 +1,23 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
from typing import TYPE_CHECKING, Any
|
3
3
|
|
4
|
-
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
5
4
|
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
6
5
|
QmodStructInstance,
|
7
6
|
)
|
8
7
|
from classiq.interface.generator.functions.type_name import Struct
|
9
|
-
from classiq.interface.generator.visitor import Visitor
|
10
8
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
11
9
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
12
10
|
from classiq.interface.model.port_declaration import PortDeclaration
|
13
|
-
from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
|
14
11
|
from classiq.interface.model.quantum_function_declaration import (
|
15
12
|
PositionalArg,
|
16
13
|
QuantumFunctionDeclaration,
|
17
14
|
QuantumOperandDeclaration,
|
18
15
|
)
|
19
|
-
from classiq.interface.model.quantum_lambda_function import (
|
20
|
-
QuantumCallable,
|
21
|
-
QuantumLambdaFunction,
|
22
|
-
)
|
23
16
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
24
17
|
|
25
18
|
from classiq.model_expansions.closure import (
|
26
19
|
FunctionClosure,
|
27
20
|
GenerativeClosure,
|
28
|
-
GenerativeFunctionClosure,
|
29
21
|
)
|
30
22
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
31
23
|
from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
|
@@ -35,7 +27,6 @@ from classiq.qmod.qmod_variable import QNum, _create_qvar_for_qtype
|
|
35
27
|
from classiq.qmod.quantum_callable import QCallable
|
36
28
|
from classiq.qmod.quantum_expandable import (
|
37
29
|
QExpandable,
|
38
|
-
QLambdaFunction,
|
39
30
|
QTerminalCallable,
|
40
31
|
)
|
41
32
|
from classiq.qmod.quantum_function import QFunc
|
@@ -71,12 +62,18 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated)
|
|
71
62
|
)
|
72
63
|
if isinstance(param, QuantumOperandDeclaration):
|
73
64
|
if param.is_list:
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
65
|
+
func_list: list[FunctionClosure] = evaluated.as_type(list)
|
66
|
+
return LenList(
|
67
|
+
[
|
68
|
+
QTerminalCallable(
|
69
|
+
QuantumOperandDeclaration(
|
70
|
+
name=param.name,
|
71
|
+
positional_arg_declarations=param.positional_arg_declarations,
|
72
|
+
),
|
73
|
+
index_=idx,
|
74
|
+
)
|
75
|
+
for idx in range(len(func_list))
|
76
|
+
]
|
80
77
|
)
|
81
78
|
else:
|
82
79
|
func = evaluated.as_type(FunctionClosure)
|
@@ -143,78 +140,3 @@ def emit_generative_statements(
|
|
143
140
|
True
|
144
141
|
):
|
145
142
|
generative_function._py_callable(*python_qmod_args)
|
146
|
-
|
147
|
-
|
148
|
-
def emit_operands_as_declarative(
|
149
|
-
interpreter: "Interpreter", param: PositionalArg, arg: Evaluated
|
150
|
-
) -> ArgValue:
|
151
|
-
if not isinstance(param, QuantumOperandDeclaration):
|
152
|
-
return arg.emit()
|
153
|
-
value = arg.value
|
154
|
-
if isinstance(value, list):
|
155
|
-
return [
|
156
|
-
_expand_operand_as_declarative(interpreter, param, item) for item in value
|
157
|
-
]
|
158
|
-
if isinstance(value, GenerativeFunctionClosure):
|
159
|
-
return _expand_operand_as_declarative(interpreter, param, value)
|
160
|
-
if isinstance(value, FunctionClosure):
|
161
|
-
if value.is_lambda:
|
162
|
-
raise ClassiqInternalExpansionError
|
163
|
-
_register_declarative_function(interpreter, value.name)
|
164
|
-
return value.name
|
165
|
-
raise ClassiqInternalExpansionError
|
166
|
-
|
167
|
-
|
168
|
-
def _expand_operand_as_declarative(
|
169
|
-
interpreter: "Interpreter",
|
170
|
-
param: QuantumOperandDeclaration,
|
171
|
-
arg: GenerativeFunctionClosure,
|
172
|
-
) -> QuantumCallable:
|
173
|
-
if not arg.is_lambda:
|
174
|
-
_register_declarative_function(interpreter, arg.name)
|
175
|
-
return arg.name
|
176
|
-
val = QLambdaFunction(param, arg.generative_blocks["body"]._py_callable)
|
177
|
-
with generative_mode_context(False):
|
178
|
-
val.expand()
|
179
|
-
_DecFuncVisitor(interpreter).visit(val.body)
|
180
|
-
qlambda = QuantumLambdaFunction(
|
181
|
-
pos_rename_params=val.infer_rename_params(),
|
182
|
-
body=val.body,
|
183
|
-
)
|
184
|
-
qlambda.set_op_decl(param)
|
185
|
-
return qlambda
|
186
|
-
|
187
|
-
|
188
|
-
def _register_declarative_function(interpreter: "Interpreter", func_name: str) -> None:
|
189
|
-
if func_name in nameables_to_dict(list(interpreter._expanded_functions.values())):
|
190
|
-
return
|
191
|
-
|
192
|
-
for user_gen_func in interpreter._generative_functions:
|
193
|
-
if user_gen_func.func_decl.name == func_name:
|
194
|
-
break
|
195
|
-
else:
|
196
|
-
return
|
197
|
-
|
198
|
-
with generative_mode_context(False):
|
199
|
-
dec_func = QFunc(user_gen_func._py_callable)
|
200
|
-
dec_func.expand()
|
201
|
-
dec_func_def = QMODULE.native_defs[func_name]
|
202
|
-
interpreter._expanded_functions[func_name] = dec_func_def
|
203
|
-
_DecFuncVisitor(interpreter).visit(dec_func_def)
|
204
|
-
|
205
|
-
|
206
|
-
class _DecFuncVisitor(Visitor):
|
207
|
-
def __init__(self, interpreter: "Interpreter"):
|
208
|
-
self._interpreter = interpreter
|
209
|
-
|
210
|
-
def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
|
211
|
-
_register_declarative_function(self._interpreter, call.func_name)
|
212
|
-
for arg in call.positional_args:
|
213
|
-
if isinstance(arg, str):
|
214
|
-
arg = [arg]
|
215
|
-
if isinstance(arg, list):
|
216
|
-
for possible_func_name in arg:
|
217
|
-
if isinstance(possible_func_name, str):
|
218
|
-
_register_declarative_function(
|
219
|
-
self._interpreter, possible_func_name
|
220
|
-
)
|
@@ -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,
|
@@ -108,7 +116,9 @@ class Interpreter:
|
|
108
116
|
self._builder = OperationBuilder(self._top_level_scope)
|
109
117
|
self._expanded_functions: dict[str, NativeFunctionDefinition] = {}
|
110
118
|
|
111
|
-
self._main_renamer: ExpressionRenamer =
|
119
|
+
self._main_renamer: Optional[ExpressionRenamer] = (
|
120
|
+
get_main_renamer(self._model.functions) if self._is_frontend else None
|
121
|
+
)
|
112
122
|
|
113
123
|
if generative_functions is None:
|
114
124
|
generative_functions = []
|
@@ -280,11 +290,21 @@ class Interpreter:
|
|
280
290
|
|
281
291
|
@emit.register
|
282
292
|
def emit_quantum_assignment_operation(self, op: QuantumAssignmentOperation) -> None:
|
283
|
-
|
293
|
+
if self._is_frontend:
|
294
|
+
ShallowEmitter(
|
295
|
+
self, "assignment_operation", components=["expression", "result_var"]
|
296
|
+
).emit(op)
|
297
|
+
else:
|
298
|
+
QuantumAssignmentOperationEmitter(self).emit(op)
|
284
299
|
|
285
300
|
@emit.register
|
286
|
-
def emit_inplace_binary_operation(self,
|
287
|
-
|
301
|
+
def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
|
302
|
+
if self._is_frontend:
|
303
|
+
ShallowEmitter(
|
304
|
+
self, "inplace_binary_operation", components=["target", "value"]
|
305
|
+
).emit(op)
|
306
|
+
else:
|
307
|
+
InplaceBinaryOperationEmitter(self).emit(op)
|
288
308
|
|
289
309
|
@emit.register
|
290
310
|
def emit_variable_declaration(
|
@@ -298,11 +318,21 @@ class Interpreter:
|
|
298
318
|
|
299
319
|
@emit.register
|
300
320
|
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
301
|
-
|
321
|
+
if self._is_frontend:
|
322
|
+
ShallowEmitter(
|
323
|
+
self,
|
324
|
+
WITHIN_APPLY_NAME,
|
325
|
+
components=["within", "apply", "compute", "action"],
|
326
|
+
).emit(within_apply)
|
327
|
+
else:
|
328
|
+
WithinApplyEmitter(self).emit(within_apply)
|
302
329
|
|
303
330
|
@emit.register
|
304
331
|
def emit_invert(self, invert: Invert) -> None:
|
305
|
-
|
332
|
+
if self._is_frontend:
|
333
|
+
ShallowEmitter(self, INVERT_OPERATOR_NAME, components=["body"]).emit(invert)
|
334
|
+
else:
|
335
|
+
InvertEmitter(self).emit(invert)
|
306
336
|
|
307
337
|
@emit.register
|
308
338
|
def emit_repeat(self, repeat: Repeat) -> None:
|
@@ -310,15 +340,32 @@ class Interpreter:
|
|
310
340
|
|
311
341
|
@emit.register
|
312
342
|
def emit_control(self, control: Control) -> None:
|
313
|
-
|
343
|
+
if self._is_frontend:
|
344
|
+
ShallowEmitter(
|
345
|
+
self,
|
346
|
+
CONTROL_OPERATOR_NAME,
|
347
|
+
components=["expression", "body", "else_block"],
|
348
|
+
).emit(control)
|
349
|
+
else:
|
350
|
+
ControlEmitter(self).emit(control)
|
314
351
|
|
315
352
|
@emit.register
|
316
353
|
def emit_power(self, power: Power) -> None:
|
317
|
-
|
354
|
+
if self._is_frontend:
|
355
|
+
ShallowEmitter(
|
356
|
+
self, CONTROL_OPERATOR_NAME, components=["power", "body"]
|
357
|
+
).emit(power)
|
358
|
+
else:
|
359
|
+
PowerEmitter(self).emit(power)
|
318
360
|
|
319
361
|
@emit.register
|
320
362
|
def emit_phase(self, phase: PhaseOperation) -> None:
|
321
|
-
|
363
|
+
if self._is_frontend:
|
364
|
+
ShallowEmitter(self, "phase", components=["expression", "theta"]).emit(
|
365
|
+
phase
|
366
|
+
)
|
367
|
+
else:
|
368
|
+
PhaseEmitter(self).emit(phase)
|
322
369
|
|
323
370
|
def _expand_block(self, block: Sequence[QuantumStatement], block_name: str) -> None:
|
324
371
|
with self._builder.block_context(block_name):
|
@@ -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,
|
@@ -73,14 +73,22 @@ 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:
|
85
93
|
function = function.set_depth(self._builder.current_function.depth + 1)
|
86
94
|
function = function.copy_scope()
|
@@ -144,10 +152,14 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
144
152
|
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
145
153
|
if isinstance(arg_decl, PortDeclaration)
|
146
154
|
}
|
147
|
-
self.
|
155
|
+
self._debug_info[new_call.uuid] = FunctionDebugInfo(
|
148
156
|
name=new_call.func_name,
|
149
157
|
level=OperationLevel.QMOD_FUNCTION_CALL,
|
150
|
-
parameters=
|
158
|
+
parameters=(
|
159
|
+
parameters
|
160
|
+
if propagated_debug_info is None
|
161
|
+
else propagated_debug_info.parameters
|
162
|
+
),
|
151
163
|
is_allocate_or_free=is_allocate_or_free,
|
152
164
|
port_to_passed_variable_map=port_to_passed_variable_map,
|
153
165
|
)
|
@@ -203,10 +215,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
203
215
|
new_positional_arg_decls, evaluated_args
|
204
216
|
)
|
205
217
|
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
|
-
]
|
218
|
+
return [arg.emit() for arg in evaluated_args]
|
210
219
|
|
211
220
|
positional_args = [
|
212
221
|
arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
|
@@ -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:
|
@@ -55,20 +57,12 @@ class Emitter(Generic[QuantumStatementT]):
|
|
55
57
|
self._functions_compilation_metadata = (
|
56
58
|
self._interpreter._model.functions_compilation_metadata
|
57
59
|
)
|
58
|
-
self._generative_contexts: dict[str, OperationContext] = {}
|
59
60
|
|
60
61
|
@abstractmethod
|
61
62
|
def emit(self, statement: QuantumStatementT, /) -> None:
|
62
63
|
pass
|
63
64
|
|
64
65
|
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
66
|
return self._interpreter._expand_operation(closure)
|
73
67
|
|
74
68
|
@property
|
@@ -91,7 +85,11 @@ class Emitter(Generic[QuantumStatementT]):
|
|
91
85
|
def _counted_name_allocator(self) -> CountedNameAllocator:
|
92
86
|
return self._interpreter._counted_name_allocator
|
93
87
|
|
94
|
-
|
88
|
+
@property
|
89
|
+
def _debug_info(self) -> DebugInfoCollection:
|
90
|
+
return self._interpreter._model.debug_info
|
91
|
+
|
92
|
+
def _expand_generative_context(
|
95
93
|
self,
|
96
94
|
op: QuantumOperation,
|
97
95
|
context_name: str,
|
@@ -116,15 +114,19 @@ class Emitter(Generic[QuantumStatementT]):
|
|
116
114
|
},
|
117
115
|
)
|
118
116
|
context = self._interpreter._expand_operation(gen_closure)
|
119
|
-
self._generative_contexts[context_name] = context
|
120
117
|
op.clear_generative_blocks()
|
121
118
|
return context
|
122
119
|
|
123
|
-
def _evaluate_expression(
|
120
|
+
def _evaluate_expression(
|
121
|
+
self, expression: Expression, preserve_bool_ops: bool = False
|
122
|
+
) -> Expression:
|
124
123
|
evaluated_expression = self._interpreter.evaluate(expression)
|
125
124
|
if isinstance(evaluated_expression.value, sympy.Basic):
|
126
125
|
new_expression = Expression(
|
127
|
-
expr=translate_sympy_quantum_expression(
|
126
|
+
expr=translate_sympy_quantum_expression(
|
127
|
+
evaluated_expression.value,
|
128
|
+
preserve_bool_ops=preserve_bool_ops,
|
129
|
+
)
|
128
130
|
)
|
129
131
|
else:
|
130
132
|
new_expression = Expression(expr=str(evaluated_expression.value))
|
@@ -162,3 +164,14 @@ class Emitter(Generic[QuantumStatementT]):
|
|
162
164
|
defining_function=defining_function,
|
163
165
|
direction=direction,
|
164
166
|
)
|
167
|
+
|
168
|
+
def capture_handles_in_expression(self, expr: Expression) -> None:
|
169
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
170
|
+
vrc.visit(ast.parse(expr.expr))
|
171
|
+
handles = dict.fromkeys(
|
172
|
+
handle
|
173
|
+
for handle in vrc.var_handles
|
174
|
+
if isinstance(self._current_scope[handle.name].value, QuantumSymbol)
|
175
|
+
)
|
176
|
+
for handle in handles:
|
177
|
+
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
|