classiq 0.56.0__py3-none-any.whl → 0.57.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/analyzer/show_interactive_hack.py +16 -4
- classiq/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/executor/execution_request.py +5 -5
- classiq/interface/generator/arith/arithmetic_expression_validator.py +28 -9
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/model_expansions/closure.py +24 -6
- classiq/model_expansions/quantum_operations/call_emitter.py +207 -0
- classiq/model_expansions/quantum_operations/classicalif.py +2 -2
- classiq/model_expansions/quantum_operations/control.py +7 -5
- classiq/model_expansions/quantum_operations/emitter.py +1 -186
- classiq/model_expansions/quantum_operations/expression_operation.py +26 -189
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +2 -2
- classiq/model_expansions/quantum_operations/invert.py +2 -2
- classiq/model_expansions/quantum_operations/phase.py +3 -1
- classiq/model_expansions/quantum_operations/power.py +2 -2
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -9
- classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -2
- classiq/model_expansions/quantum_operations/repeat.py +2 -2
- classiq/model_expansions/transformers/__init__.py +0 -0
- classiq/model_expansions/transformers/var_splitter.py +237 -0
- classiq/qmod/__init__.py +0 -2
- classiq/qmod/builtins/classical_functions.py +1 -0
- classiq/qmod/builtins/functions/state_preparation.py +1 -1
- classiq/qmod/create_model_function.py +25 -20
- classiq/qmod/pretty_print/pretty_printer.py +53 -28
- classiq/qmod/qfunc.py +43 -9
- classiq/qmod/quantum_function.py +30 -24
- classiq/synthesis.py +3 -1
- {classiq-0.56.0.dist-info → classiq-0.57.0.dist-info}/METADATA +1 -1
- {classiq-0.56.0.dist-info → classiq-0.57.0.dist-info}/RECORD +32 -30
- classiq/qmod/synthesize_separately.py +0 -15
- {classiq-0.56.0.dist-info → classiq-0.57.0.dist-info}/WHEEL +0 -0
@@ -10,7 +10,7 @@ from classiq._internals.async_utils import syncify_function
|
|
10
10
|
from classiq.analyzer.url_utils import circuit_page_uri, client_ide_base_url
|
11
11
|
|
12
12
|
|
13
|
-
async def handle_remote_app(circuit: QuantumProgram,
|
13
|
+
async def handle_remote_app(circuit: QuantumProgram, display_url: bool = True) -> None:
|
14
14
|
if circuit.outputs.get(QuantumFormat.QASM) is None:
|
15
15
|
raise ClassiqAnalyzerVisualizationError(
|
16
16
|
"Missing QASM transpilation: visualization is only supported "
|
@@ -23,14 +23,26 @@ async def handle_remote_app(circuit: QuantumProgram, dispaly_url: bool = False)
|
|
23
23
|
circuit_page_uri(circuit_id=circuit_dataid.id, circuit_version=circuit.version),
|
24
24
|
)
|
25
25
|
|
26
|
-
if
|
26
|
+
if display_url:
|
27
27
|
print(f"Opening: {app_url}") # noqa: T201
|
28
28
|
|
29
29
|
webbrowser.open_new_tab(app_url)
|
30
30
|
|
31
31
|
|
32
|
-
async def _show_interactive(self: QuantumProgram,
|
33
|
-
|
32
|
+
async def _show_interactive(self: QuantumProgram, display_url: bool = True) -> None:
|
33
|
+
"""
|
34
|
+
Displays the interactive representation of the quantum program in the Classiq IDE.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
self:
|
38
|
+
The serialized quantum program to be displayed.
|
39
|
+
display_url:
|
40
|
+
Whether to print the url
|
41
|
+
|
42
|
+
Links:
|
43
|
+
[Visualization tool](https://docs.classiq.io/latest/reference-manual/analyzer/quantum-program-visualization-tool/)
|
44
|
+
"""
|
45
|
+
await handle_remote_app(self, display_url)
|
34
46
|
|
35
47
|
|
36
48
|
QuantumProgram.show = syncify_function(_show_interactive) # type: ignore[attr-defined]
|
classiq/executor.py
CHANGED
@@ -46,7 +46,7 @@ def execute(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
|
|
46
46
|
Returns:
|
47
47
|
ExecutionJob: The result of the execution.
|
48
48
|
|
49
|
-
For examples please see [Execution Documentation](https://docs.classiq.io/latest/user-guide/
|
49
|
+
For examples please see [Execution Documentation](https://docs.classiq.io/latest/user-guide/execution/)
|
50
50
|
"""
|
51
51
|
return async_utils.run(execute_async(quantum_program))
|
52
52
|
|
classiq/interface/_version.py
CHANGED
@@ -46,16 +46,16 @@ class QuantumProgramExecutionRequest(ExecutionRequest):
|
|
46
46
|
class ExecutionJobDetails(VersionedModel):
|
47
47
|
id: str
|
48
48
|
|
49
|
-
name: Optional[str]
|
49
|
+
name: Optional[str] = Field(default=None)
|
50
50
|
start_time: datetime
|
51
|
-
end_time: Optional[datetime]
|
51
|
+
end_time: Optional[datetime] = Field(default=None)
|
52
52
|
|
53
|
-
provider: Optional[str]
|
54
|
-
backend_name: Optional[str]
|
53
|
+
provider: Optional[str] = Field(default=None)
|
54
|
+
backend_name: Optional[str] = Field(default=None)
|
55
55
|
|
56
56
|
status: JobStatus
|
57
57
|
|
58
|
-
num_shots: Optional[int]
|
58
|
+
num_shots: Optional[int] = Field(default=None)
|
59
59
|
program_id: Optional[str] = Field(default=None)
|
60
60
|
|
61
61
|
error: Optional[str] = Field(default=None)
|
@@ -16,9 +16,6 @@ DEFAULT_SUPPORTED_FUNC_NAMES: set[str] = {"CLShift", "CRShift", "min", "max"}
|
|
16
16
|
DEFAULT_EXPRESSION_TYPE = "arithmetic"
|
17
17
|
IDENITIFIER_REGEX = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
|
18
18
|
|
19
|
-
_REPEATED_VARIABLES_ERROR_MESSAGE: str = (
|
20
|
-
"Repeated variables in the beginning of an arithmetic expression are not allowed."
|
21
|
-
)
|
22
19
|
ValidKeyValuePairs: TypeAlias = dict[str, set[str]]
|
23
20
|
|
24
21
|
SupportedNodesTypes = Union[
|
@@ -107,13 +104,25 @@ class ExpressionValidator(ast.NodeVisitor):
|
|
107
104
|
raise ClassiqArithmeticError("Must call `validate` before getting ast_obj")
|
108
105
|
return self._ast_obj
|
109
106
|
|
110
|
-
|
111
|
-
|
107
|
+
def _check_repeated_variables(
|
108
|
+
self, variables: tuple[Any, Any], expr: ast.AST, error_suffix: str
|
109
|
+
) -> None:
|
110
|
+
if (
|
111
|
+
isinstance(expr, ast.BinOp)
|
112
|
+
and isinstance(expr.op, ast.Pow)
|
113
|
+
and ast.Pow not in self.supported_nodes
|
114
|
+
):
|
115
|
+
raise ClassiqValueError(
|
116
|
+
"Raising to a power (<var> ** <exp>) and multiplying a variable by "
|
117
|
+
"itself (<var> * <var>) are not supported"
|
118
|
+
)
|
112
119
|
if (
|
113
120
|
all(isinstance(var, ast.Name) for var in variables)
|
114
121
|
and variables[0].id == variables[1].id
|
115
122
|
):
|
116
|
-
raise ClassiqValueError(
|
123
|
+
raise ClassiqValueError(
|
124
|
+
f"Expression {ast.unparse(expr)!r} is not supported ({error_suffix})"
|
125
|
+
)
|
117
126
|
|
118
127
|
@staticmethod
|
119
128
|
def _check_multiple_comparators(node: ast.Compare) -> None:
|
@@ -135,7 +144,11 @@ class ExpressionValidator(ast.NodeVisitor):
|
|
135
144
|
)
|
136
145
|
|
137
146
|
def validate_Compare(self, node: ast.Compare) -> None: # noqa: N802
|
138
|
-
self._check_repeated_variables(
|
147
|
+
self._check_repeated_variables(
|
148
|
+
(node.left, node.comparators[0]),
|
149
|
+
node,
|
150
|
+
"both sides of the comparison are identical",
|
151
|
+
)
|
139
152
|
self._check_multiple_comparators(node)
|
140
153
|
|
141
154
|
def visit_Compare(self, node: ast.Compare) -> None:
|
@@ -143,7 +156,9 @@ class ExpressionValidator(ast.NodeVisitor):
|
|
143
156
|
self.generic_visit(node)
|
144
157
|
|
145
158
|
def validate_BinOp(self, node: ast.BinOp) -> None: # noqa: N802
|
146
|
-
self._check_repeated_variables(
|
159
|
+
self._check_repeated_variables(
|
160
|
+
(node.left, node.right), node, "both sides of the operation are identical"
|
161
|
+
)
|
147
162
|
|
148
163
|
def visit_BinOp(self, node: ast.BinOp) -> None:
|
149
164
|
self.validate_BinOp(node)
|
@@ -151,7 +166,11 @@ class ExpressionValidator(ast.NodeVisitor):
|
|
151
166
|
|
152
167
|
def validate_Call(self, node: ast.Call) -> None: # noqa: N802
|
153
168
|
if len(node.args) >= 2:
|
154
|
-
self._check_repeated_variables(
|
169
|
+
self._check_repeated_variables(
|
170
|
+
(node.args[0], node.args[1]),
|
171
|
+
node,
|
172
|
+
"the first two call arguments are identical",
|
173
|
+
)
|
155
174
|
node_id = AstNodeRewrite().extract_node_id(node)
|
156
175
|
if node_id not in self._supported_functions:
|
157
176
|
raise ClassiqValueError(f"{node_id} not in supported functions")
|
@@ -21,6 +21,7 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
21
21
|
from classiq.interface.model.quantum_function_declaration import (
|
22
22
|
NamedParamsQuantumFunctionDeclaration,
|
23
23
|
PositionalArg,
|
24
|
+
QuantumOperandDeclaration,
|
24
25
|
)
|
25
26
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
26
27
|
from classiq.interface.model.variable_declaration_statement import (
|
@@ -213,26 +214,43 @@ def _generate_arg_id(
|
|
213
214
|
arg_name = arg_declaration.name
|
214
215
|
if isinstance(arg_declaration, ClassicalParameterDeclaration):
|
215
216
|
return {arg_name: evaluated_classical_param_to_str(arg_value)}
|
216
|
-
|
217
|
+
if isinstance(arg_declaration, PortDeclaration):
|
218
|
+
return {arg_name: _evaluated_port_to_str(arg_value)}
|
219
|
+
if isinstance(arg_declaration, QuantumOperandDeclaration):
|
220
|
+
return {arg_name: _evaluated_operand_to_str(arg_value)}
|
217
221
|
|
218
222
|
|
219
|
-
@singledispatch
|
220
223
|
def _evaluated_arg_to_str(arg: Any) -> str:
|
221
224
|
if isinstance(arg, str):
|
222
225
|
return arg
|
223
226
|
return str(uuid.uuid4())
|
224
227
|
|
225
228
|
|
226
|
-
@
|
229
|
+
@singledispatch
|
230
|
+
def _evaluated_port_to_str(arg: Any) -> str:
|
231
|
+
return _evaluated_arg_to_str(arg)
|
232
|
+
|
233
|
+
|
234
|
+
@_evaluated_port_to_str.register
|
227
235
|
def _evaluated_quantum_symbol_to_str(port: QuantumSymbol) -> str:
|
228
236
|
return port.quantum_type.model_dump_json(exclude_none=True, exclude={"name"})
|
229
237
|
|
230
238
|
|
231
|
-
@
|
239
|
+
@_evaluated_port_to_str.register
|
232
240
|
def _evaluated_symbol_to_str(port: Symbol) -> str:
|
233
241
|
return repr(port)
|
234
242
|
|
235
243
|
|
236
|
-
@
|
237
|
-
def _evaluated_operand_to_str(
|
244
|
+
@singledispatch
|
245
|
+
def _evaluated_operand_to_str(arg: Any) -> str:
|
246
|
+
return _evaluated_arg_to_str(arg)
|
247
|
+
|
248
|
+
|
249
|
+
@_evaluated_operand_to_str.register
|
250
|
+
def _evaluated_one_operand_to_str(operand: FunctionClosure) -> str:
|
238
251
|
return operand.closure_id
|
252
|
+
|
253
|
+
|
254
|
+
@_evaluated_operand_to_str.register
|
255
|
+
def _evaluated_list_operands_to_str(operands: list) -> str:
|
256
|
+
return json.dumps([_evaluated_operand_to_str(ope) for ope in operands])
|
@@ -0,0 +1,207 @@
|
|
1
|
+
from collections.abc import Sequence
|
2
|
+
from typing import (
|
3
|
+
Generic,
|
4
|
+
cast,
|
5
|
+
)
|
6
|
+
|
7
|
+
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
8
|
+
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
9
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
10
|
+
ClassicalParameterDeclaration,
|
11
|
+
)
|
12
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
13
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
14
|
+
from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
|
15
|
+
from classiq.interface.model.quantum_function_declaration import (
|
16
|
+
NamedParamsQuantumFunctionDeclaration,
|
17
|
+
PositionalArg,
|
18
|
+
)
|
19
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
20
|
+
from classiq.interface.model.variable_declaration_statement import (
|
21
|
+
VariableDeclarationStatement,
|
22
|
+
)
|
23
|
+
|
24
|
+
from classiq.model_expansions.capturing.propagated_var_stack import (
|
25
|
+
validate_args_are_not_propagated,
|
26
|
+
)
|
27
|
+
from classiq.model_expansions.closure import FunctionClosure
|
28
|
+
from classiq.model_expansions.evaluators.argument_types import (
|
29
|
+
add_information_from_output_arguments,
|
30
|
+
)
|
31
|
+
from classiq.model_expansions.evaluators.parameter_types import (
|
32
|
+
evaluate_parameter_types_from_args,
|
33
|
+
)
|
34
|
+
from classiq.model_expansions.function_builder import (
|
35
|
+
FunctionContext,
|
36
|
+
)
|
37
|
+
from classiq.model_expansions.generative_functions import emit_operands_as_declarative
|
38
|
+
from classiq.model_expansions.quantum_operations.emitter import (
|
39
|
+
Emitter,
|
40
|
+
QuantumStatementT,
|
41
|
+
)
|
42
|
+
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
43
|
+
from classiq.qmod.builtins.functions import allocate, free
|
44
|
+
|
45
|
+
|
46
|
+
class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT]):
|
47
|
+
@staticmethod
|
48
|
+
def _should_wrap(body: Sequence[QuantumStatement]) -> bool:
|
49
|
+
# This protects shadowing of captured variables (i.e, bad user code) by wrapping the body in a function
|
50
|
+
# I'm sure there are better ways to handle it, but this is the simplest way to do it for now
|
51
|
+
return any(isinstance(stmt, VariableDeclarationStatement) for stmt in body)
|
52
|
+
|
53
|
+
def _create_expanded_wrapping_function(
|
54
|
+
self, name: str, body: Sequence[QuantumStatement]
|
55
|
+
) -> QuantumFunctionCall:
|
56
|
+
wrapping_function = FunctionClosure.create(
|
57
|
+
name=name, body=body, scope=Scope(parent=self._current_scope)
|
58
|
+
)
|
59
|
+
return self._create_quantum_function_call(wrapping_function, list())
|
60
|
+
|
61
|
+
def _emit_quantum_function_call(
|
62
|
+
self, function: FunctionClosure, args: list[ArgValue]
|
63
|
+
) -> QuantumFunctionCall:
|
64
|
+
call = self._create_quantum_function_call(function, args)
|
65
|
+
self._builder.emit_statement(call)
|
66
|
+
return call
|
67
|
+
|
68
|
+
def _create_quantum_function_call(
|
69
|
+
self, function: FunctionClosure, args: list[ArgValue]
|
70
|
+
) -> QuantumFunctionCall:
|
71
|
+
evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
|
72
|
+
new_declaration = self._prepare_fully_typed_declaration(
|
73
|
+
function, evaluated_args
|
74
|
+
)
|
75
|
+
new_positional_arg_decls = new_declaration.positional_arg_declarations
|
76
|
+
is_atomic = function.is_atomic
|
77
|
+
new_function_name = function.name
|
78
|
+
if not is_atomic: # perform monomorphization per interpreted parameters set
|
79
|
+
self._add_params_to_scope(
|
80
|
+
new_positional_arg_decls, evaluated_args, function
|
81
|
+
)
|
82
|
+
context = self._expand_operation(
|
83
|
+
function.with_new_declaration(new_declaration)
|
84
|
+
)
|
85
|
+
function_context = cast(FunctionContext, context)
|
86
|
+
closure_id = function_context.closure.closure_id
|
87
|
+
function_def = self._expanded_functions.get(closure_id)
|
88
|
+
if function_def is None:
|
89
|
+
function_def = self._builder.create_definition(function_context)
|
90
|
+
self._expanded_functions[closure_id] = function_def
|
91
|
+
self._top_level_scope[function_def.name] = Evaluated(
|
92
|
+
value=function_context.closure.with_new_declaration(function_def)
|
93
|
+
)
|
94
|
+
new_declaration = function_def
|
95
|
+
new_function_name = function_def.name
|
96
|
+
compilation_metadata = self._functions_compilation_metadata.get(
|
97
|
+
function.name
|
98
|
+
)
|
99
|
+
if compilation_metadata is not None:
|
100
|
+
self._expanded_functions_compilation_metadata[new_function_name] = (
|
101
|
+
compilation_metadata
|
102
|
+
)
|
103
|
+
|
104
|
+
new_positional_args = self._get_new_positional_args(
|
105
|
+
evaluated_args, is_atomic, new_positional_arg_decls
|
106
|
+
)
|
107
|
+
new_call = QuantumFunctionCall(
|
108
|
+
function=new_function_name,
|
109
|
+
positional_args=new_positional_args,
|
110
|
+
)
|
111
|
+
is_allocate_or_free = (
|
112
|
+
new_call.func_name == allocate.func_decl.name
|
113
|
+
or new_call.func_name == free.func_decl.name
|
114
|
+
)
|
115
|
+
parameters = {
|
116
|
+
arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
|
117
|
+
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
118
|
+
if isinstance(arg_decl, ClassicalParameterDeclaration)
|
119
|
+
}
|
120
|
+
|
121
|
+
port_to_passed_variable_map = {
|
122
|
+
arg_decl.name: str(evaluated_arg.value.handle)
|
123
|
+
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
124
|
+
if isinstance(arg_decl, PortDeclaration)
|
125
|
+
}
|
126
|
+
self._interpreter._model.debug_info[new_call.uuid] = FunctionDebugInfo(
|
127
|
+
name=new_call.func_name,
|
128
|
+
level=OperationLevel.QMOD_FUNCTION_CALL,
|
129
|
+
parameters=parameters,
|
130
|
+
is_allocate_or_free=is_allocate_or_free,
|
131
|
+
port_to_passed_variable_map=port_to_passed_variable_map,
|
132
|
+
)
|
133
|
+
new_call.set_func_decl(new_declaration)
|
134
|
+
return new_call
|
135
|
+
|
136
|
+
@staticmethod
|
137
|
+
def _add_params_to_scope(
|
138
|
+
parameters: Sequence[PositionalArg],
|
139
|
+
arguments: Sequence[Evaluated],
|
140
|
+
closure: FunctionClosure,
|
141
|
+
) -> None:
|
142
|
+
for parameter, argument in zip(parameters, arguments):
|
143
|
+
if isinstance(argument.value, QuantumSymbol):
|
144
|
+
assert isinstance(parameter, PortDeclaration)
|
145
|
+
closure.scope[parameter.name] = Evaluated(
|
146
|
+
QuantumSymbol(
|
147
|
+
handle=HandleBinding(name=parameter.name),
|
148
|
+
quantum_type=parameter.quantum_type,
|
149
|
+
),
|
150
|
+
defining_function=closure,
|
151
|
+
)
|
152
|
+
else:
|
153
|
+
closure.scope[parameter.name] = argument
|
154
|
+
|
155
|
+
def _get_new_positional_args(
|
156
|
+
self,
|
157
|
+
evaluated_args: list[Evaluated],
|
158
|
+
is_atomic: bool,
|
159
|
+
new_positional_arg_decls: Sequence[PositionalArg],
|
160
|
+
) -> list[ArgValue]:
|
161
|
+
evaluated_args = add_information_from_output_arguments(
|
162
|
+
new_positional_arg_decls, evaluated_args
|
163
|
+
)
|
164
|
+
if is_atomic:
|
165
|
+
return [
|
166
|
+
emit_operands_as_declarative(self._interpreter, param, arg)
|
167
|
+
for param, arg in zip(new_positional_arg_decls, evaluated_args)
|
168
|
+
]
|
169
|
+
|
170
|
+
positional_args = [
|
171
|
+
arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
|
172
|
+
]
|
173
|
+
|
174
|
+
propagated_variables = self._propagated_var_stack.get_propagated_variables(
|
175
|
+
flatten=True
|
176
|
+
)
|
177
|
+
validate_args_are_not_propagated(positional_args, propagated_variables)
|
178
|
+
positional_args.extend(propagated_variables)
|
179
|
+
|
180
|
+
return positional_args
|
181
|
+
|
182
|
+
def _prepare_fully_typed_declaration(
|
183
|
+
self, function: FunctionClosure, evaluated_args: list[Evaluated]
|
184
|
+
) -> NamedParamsQuantumFunctionDeclaration:
|
185
|
+
"""
|
186
|
+
Given, for example,
|
187
|
+
def my_func(x: int, q: QArray["x"], p: QArray[]) -> None:
|
188
|
+
...
|
189
|
+
def main(...):
|
190
|
+
...
|
191
|
+
allocate(5, s)
|
192
|
+
my_func(3, r, s)
|
193
|
+
The code below will evaluate x to be 3, q to be of size 3 and p to be of size 5.
|
194
|
+
Note that it requires a scope for the parameter declaration space, which is
|
195
|
+
different from the call scope. For example, the former uses r,s and the latter
|
196
|
+
uses p, q.
|
197
|
+
"""
|
198
|
+
with self._scope_guard(Scope(parent=self._current_scope)):
|
199
|
+
# The signature scope is passed as a separate argument to avoid contaminating the statement execution scope
|
200
|
+
return NamedParamsQuantumFunctionDeclaration(
|
201
|
+
name=function.name,
|
202
|
+
positional_arg_declarations=evaluate_parameter_types_from_args(
|
203
|
+
function,
|
204
|
+
function.signature_scope,
|
205
|
+
evaluated_args,
|
206
|
+
),
|
207
|
+
)
|
@@ -5,7 +5,7 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
5
5
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
6
6
|
|
7
7
|
from classiq.model_expansions.closure import FunctionClosure
|
8
|
-
from classiq.model_expansions.quantum_operations.
|
8
|
+
from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
|
9
9
|
from classiq.model_expansions.scope import Scope
|
10
10
|
|
11
11
|
|
@@ -16,7 +16,7 @@ def _is_all_identity_calls(body: Sequence[QuantumStatement]) -> bool:
|
|
16
16
|
)
|
17
17
|
|
18
18
|
|
19
|
-
class ClassicalIfEmitter(
|
19
|
+
class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
20
20
|
def emit(self, classical_if: ClassicalIf, /) -> None:
|
21
21
|
with self._propagated_var_stack.capture_variables(classical_if):
|
22
22
|
self._emit_propagated(classical_if)
|
@@ -26,7 +26,6 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
26
26
|
from classiq.interface.model.quantum_type import (
|
27
27
|
QuantumBit,
|
28
28
|
QuantumBitvector,
|
29
|
-
QuantumType,
|
30
29
|
)
|
31
30
|
from classiq.interface.model.statement_block import ConcreteQuantumStatement
|
32
31
|
from classiq.interface.model.variable_declaration_statement import (
|
@@ -47,6 +46,7 @@ from classiq.model_expansions.quantum_operations.expression_operation import (
|
|
47
46
|
ExpressionOperationEmitter,
|
48
47
|
)
|
49
48
|
from classiq.model_expansions.scope import Scope
|
49
|
+
from classiq.model_expansions.transformers.var_splitter import SymbolParts
|
50
50
|
from classiq.qmod.builtins.functions.standard_gates import X
|
51
51
|
|
52
52
|
|
@@ -54,7 +54,9 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
54
54
|
def emit(self, control: Control, /) -> None:
|
55
55
|
condition = self._evaluate_op_expression(control)
|
56
56
|
|
57
|
-
arrays_with_subscript = self.
|
57
|
+
arrays_with_subscript = self.split_symbols(
|
58
|
+
condition, self._counted_name_allocator.allocate
|
59
|
+
)
|
58
60
|
if len(arrays_with_subscript) > 0:
|
59
61
|
if control.is_generative():
|
60
62
|
with self._propagated_var_stack.capture_variables(control):
|
@@ -308,12 +310,12 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
308
310
|
raise ClassiqExpansionError(_condition_err_msg(condition_val))
|
309
311
|
|
310
312
|
def _get_updated_op_split_symbols(
|
311
|
-
self, op: Control,
|
313
|
+
self, op: Control, symbol_parts: SymbolParts
|
312
314
|
) -> Control:
|
313
|
-
new_body = self.
|
315
|
+
new_body = self.rewrite(op.body, symbol_parts)
|
314
316
|
new_else = None
|
315
317
|
if op.else_block is not None:
|
316
|
-
new_else = self.
|
318
|
+
new_else = self.rewrite(op.else_block, symbol_parts)
|
317
319
|
return op.model_copy(update=dict(body=new_body, else_block=new_else))
|
318
320
|
|
319
321
|
|