classiq 0.63.0__py3-none-any.whl → 0.64.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/url_utils.py +2 -3
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/result.py +1 -2
- classiq/interface/executor/result.py +6 -3
- classiq/interface/helpers/datastructures.py +26 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/handle_binding.py +11 -3
- classiq/interface/server/routes.py +4 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +6 -6
- classiq/model_expansions/capturing/captured_vars.py +27 -10
- classiq/model_expansions/evaluators/arg_type_match.py +4 -7
- classiq/model_expansions/evaluators/quantum_type_utils.py +15 -8
- classiq/model_expansions/expression_evaluator.py +8 -2
- classiq/model_expansions/generative_functions.py +3 -3
- classiq/model_expansions/interpreters/__init__.py +0 -0
- classiq/model_expansions/{interpreter.py → interpreters/base_interpreter.py} +26 -137
- classiq/model_expansions/interpreters/generative_interpreter.py +108 -0
- classiq/model_expansions/model_tables.py +1 -92
- classiq/model_expansions/quantum_operations/__init__.py +0 -10
- classiq/model_expansions/quantum_operations/call_emitter.py +3 -3
- classiq/model_expansions/quantum_operations/emitter.py +2 -2
- classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -2
- classiq/model_expansions/quantum_operations/shallow_emitter.py +2 -2
- classiq/model_expansions/scope_initialization.py +8 -0
- classiq/qmod/declaration_inferrer.py +0 -3
- classiq/qmod/generative.py +4 -4
- classiq/qmod/qfunc.py +4 -2
- classiq/qmod/qmod_variable.py +17 -10
- classiq/qmod/quantum_function.py +6 -4
- classiq/qmod/utilities.py +7 -1
- {classiq-0.63.0.dist-info → classiq-0.64.0.dist-info}/METADATA +1 -1
- {classiq-0.63.0.dist-info → classiq-0.64.0.dist-info}/RECORD +33 -39
- classiq/interface/helpers/dotdict.py +0 -18
- classiq/model_expansions/quantum_operations/control.py +0 -290
- classiq/model_expansions/quantum_operations/expression_operation.py +0 -103
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +0 -535
- classiq/model_expansions/quantum_operations/invert.py +0 -36
- classiq/model_expansions/quantum_operations/phase.py +0 -187
- classiq/model_expansions/quantum_operations/power.py +0 -71
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +0 -230
- classiq/model_expansions/quantum_operations/within_apply.py +0 -25
- {classiq-0.63.0.dist-info → classiq-0.64.0.dist-info}/WHEEL +0 -0
@@ -1,187 +0,0 @@
|
|
1
|
-
from typing import TYPE_CHECKING
|
2
|
-
|
3
|
-
import sympy
|
4
|
-
from sympy import sympify
|
5
|
-
|
6
|
-
from classiq.interface.exceptions import ClassiqExpansionError
|
7
|
-
from classiq.interface.generator.expressions.expression import Expression
|
8
|
-
from classiq.interface.model.bind_operation import BindOperation
|
9
|
-
from classiq.interface.model.handle_binding import HANDLE_ID_SEPARATOR, HandleBinding
|
10
|
-
from classiq.interface.model.phase_operation import PhaseOperation
|
11
|
-
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
12
|
-
from classiq.interface.model.quantum_type import (
|
13
|
-
QuantumBitvector,
|
14
|
-
QuantumNumeric,
|
15
|
-
QuantumScalar,
|
16
|
-
)
|
17
|
-
from classiq.interface.model.variable_declaration_statement import (
|
18
|
-
VariableDeclarationStatement,
|
19
|
-
)
|
20
|
-
from classiq.interface.model.within_apply_operation import WithinApply
|
21
|
-
|
22
|
-
from classiq.applications.combinatorial_helpers.transformations.ising_converter import (
|
23
|
-
_find_sub_list_items,
|
24
|
-
_get_vars,
|
25
|
-
_refine_ising_expr,
|
26
|
-
_to_ising_symbolic_objective_function,
|
27
|
-
)
|
28
|
-
from classiq.model_expansions.quantum_operations.expression_operation import (
|
29
|
-
ExpressionOperationEmitter,
|
30
|
-
)
|
31
|
-
from classiq.qmod.builtins.functions.exponentiation import suzuki_trotter
|
32
|
-
from classiq.qmod.semantics.error_manager import ErrorManager
|
33
|
-
|
34
|
-
|
35
|
-
class PhaseEmitter(ExpressionOperationEmitter[PhaseOperation]):
|
36
|
-
def _negate_expression(self, expression: Expression, /) -> Expression:
|
37
|
-
return self._evaluate_expression(
|
38
|
-
expression.model_copy(update=dict(expr=f"-({expression.expr})"))
|
39
|
-
)
|
40
|
-
|
41
|
-
def emit(self, phase_op: PhaseOperation, /) -> None:
|
42
|
-
arrays_with_subscript = self.split_symbols(
|
43
|
-
phase_op.expression, self._counted_name_allocator.allocate
|
44
|
-
)
|
45
|
-
if len(arrays_with_subscript) > 0:
|
46
|
-
self._emit_with_split(phase_op, phase_op.expression, arrays_with_subscript)
|
47
|
-
return
|
48
|
-
|
49
|
-
phase_op = phase_op.model_copy(
|
50
|
-
update=dict(expression=self._negate_expression(phase_op.expression))
|
51
|
-
)
|
52
|
-
phase_op = self._evaluate_types_in_expression(phase_op)
|
53
|
-
if len(phase_op.var_handles) == 0:
|
54
|
-
ErrorManager().add_error(
|
55
|
-
"Cannot perform phase operation on an expression with no quantum variables."
|
56
|
-
)
|
57
|
-
return
|
58
|
-
|
59
|
-
aux_name = self._counted_name_allocator.allocate("phase_aux")
|
60
|
-
if len(phase_op.var_handles) > 1:
|
61
|
-
split_join = True
|
62
|
-
evolution_variable = HandleBinding(name=aux_name)
|
63
|
-
else:
|
64
|
-
split_join = False
|
65
|
-
evolution_variable = phase_op.var_handles[0]
|
66
|
-
expression_evolution_function = QuantumFunctionCall(
|
67
|
-
function=suzuki_trotter.func_decl.name,
|
68
|
-
positional_args=[
|
69
|
-
_convert_cost_expression_to_hamiltonian(
|
70
|
-
phase_op.expression.expr,
|
71
|
-
{
|
72
|
-
var.name: self._current_scope[var.name].value.quantum_type
|
73
|
-
for var in phase_op.var_handles
|
74
|
-
},
|
75
|
-
),
|
76
|
-
phase_op.theta,
|
77
|
-
Expression(expr="1"),
|
78
|
-
Expression(expr="1"),
|
79
|
-
evolution_variable,
|
80
|
-
],
|
81
|
-
source_ref=phase_op.source_ref,
|
82
|
-
)
|
83
|
-
expression_evolution_function.set_func_decl(suzuki_trotter.func_decl)
|
84
|
-
|
85
|
-
if split_join:
|
86
|
-
self._interpreter.emit_statement(
|
87
|
-
VariableDeclarationStatement(
|
88
|
-
name=aux_name, quantum_type=QuantumBitvector()
|
89
|
-
)
|
90
|
-
)
|
91
|
-
self._interpreter.emit_statement(
|
92
|
-
WithinApply(
|
93
|
-
compute=[
|
94
|
-
BindOperation(
|
95
|
-
in_handles=phase_op.var_handles,
|
96
|
-
out_handles=[HandleBinding(name=aux_name)],
|
97
|
-
)
|
98
|
-
],
|
99
|
-
action=[expression_evolution_function],
|
100
|
-
source_ref=phase_op.source_ref,
|
101
|
-
)
|
102
|
-
)
|
103
|
-
else:
|
104
|
-
self._interpreter.emit_statement(
|
105
|
-
expression_evolution_function,
|
106
|
-
)
|
107
|
-
|
108
|
-
|
109
|
-
def _get_single_bit_vars_expression(
|
110
|
-
expr: sympy.Expr, vars_info: dict[str, QuantumScalar]
|
111
|
-
) -> tuple[sympy.Expr, list[sympy.Symbol]]:
|
112
|
-
bit_vars = []
|
113
|
-
for var_name, var_info in vars_info.items():
|
114
|
-
size = var_info.size_in_bits
|
115
|
-
var = sympy.Symbol(var_name)
|
116
|
-
if size == 1:
|
117
|
-
bits = [var]
|
118
|
-
is_signed = False
|
119
|
-
fraction_places = 0
|
120
|
-
else:
|
121
|
-
if TYPE_CHECKING:
|
122
|
-
assert isinstance(var_info, QuantumNumeric)
|
123
|
-
bits = [
|
124
|
-
sympy.Symbol(f"{var_name}{HANDLE_ID_SEPARATOR}{i}__split__")
|
125
|
-
for i in range(size)
|
126
|
-
]
|
127
|
-
is_signed = var_info.sign_value
|
128
|
-
fraction_places = var_info.fraction_digits_value
|
129
|
-
bit_vars.extend(bits)
|
130
|
-
split_var = 0
|
131
|
-
for i, bit in enumerate(bits):
|
132
|
-
if is_signed and i == size - 1: # sign bit (MSB)
|
133
|
-
split_var -= bit * 2 ** (size - 1 - fraction_places)
|
134
|
-
else:
|
135
|
-
split_var += bit * 2 ** (i - fraction_places)
|
136
|
-
expr = expr.subs(var, split_var)
|
137
|
-
return expr, bit_vars
|
138
|
-
|
139
|
-
|
140
|
-
def _convert_ising_sympy_to_pauli_terms(
|
141
|
-
ising_expr: sympy.Expr, ordered_sympy_vars: list[sympy.Symbol]
|
142
|
-
) -> str:
|
143
|
-
pauli_terms: list[str] = []
|
144
|
-
coefficients = ising_expr.as_coefficients_dict(*ordered_sympy_vars)
|
145
|
-
for expr_term in ising_expr.args:
|
146
|
-
expr_vars = _get_vars(expr_term)
|
147
|
-
z_vec = _find_sub_list_items(ordered_sympy_vars, expr_vars)
|
148
|
-
pauli_elements = ["I"] * len(z_vec)
|
149
|
-
for index, is_z_op in enumerate(z_vec):
|
150
|
-
if is_z_op:
|
151
|
-
pauli_elements[len(z_vec) - index - 1] = (
|
152
|
-
"Z" # reminder: Pauli reverses the order!
|
153
|
-
)
|
154
|
-
term_var = sympy.Mul(
|
155
|
-
*(var for i, var in enumerate(ordered_sympy_vars) if z_vec[i])
|
156
|
-
)
|
157
|
-
coeff = float(coefficients[term_var])
|
158
|
-
paulis = [f"Pauli.{pauli}" for pauli in pauli_elements]
|
159
|
-
pauli_terms.append(
|
160
|
-
# fmt: off
|
161
|
-
"struct_literal("
|
162
|
-
"PauliTerm,"
|
163
|
-
f"pauli=[{', '.join(paulis)}],"
|
164
|
-
f"coefficient={Expression(expr=str(coeff))},"
|
165
|
-
")"
|
166
|
-
# fmt: on,
|
167
|
-
)
|
168
|
-
return f"[{', '.join(pauli_terms)}]"
|
169
|
-
|
170
|
-
|
171
|
-
def _convert_cost_expression_to_hamiltonian(
|
172
|
-
expr: str,
|
173
|
-
vars: dict[str, QuantumScalar],
|
174
|
-
) -> Expression:
|
175
|
-
sympy_expr = sympify(expr)
|
176
|
-
single_bit_vars_expression, single_bit_vars = _get_single_bit_vars_expression(
|
177
|
-
sympy_expr, vars
|
178
|
-
)
|
179
|
-
if not single_bit_vars_expression.is_polynomial():
|
180
|
-
raise ClassiqExpansionError(f"phased expression {expr!r} is not polynomial")
|
181
|
-
|
182
|
-
ising_expr = _to_ising_symbolic_objective_function(single_bit_vars_expression)
|
183
|
-
ising_expr = _refine_ising_expr(ising_expr)
|
184
|
-
|
185
|
-
return Expression(
|
186
|
-
expr=_convert_ising_sympy_to_pauli_terms(ising_expr, single_bit_vars)
|
187
|
-
)
|
@@ -1,71 +0,0 @@
|
|
1
|
-
from typing import Union
|
2
|
-
|
3
|
-
import sympy
|
4
|
-
|
5
|
-
from classiq.interface.exceptions import ClassiqExpansionError
|
6
|
-
from classiq.interface.generator.expressions.evaluated_expression import (
|
7
|
-
EvaluatedExpression,
|
8
|
-
)
|
9
|
-
from classiq.interface.generator.expressions.expression import Expression
|
10
|
-
from classiq.interface.generator.functions.builtins.internal_operators import (
|
11
|
-
POWER_OPERATOR_NAME,
|
12
|
-
)
|
13
|
-
from classiq.interface.model.power import Power
|
14
|
-
|
15
|
-
from classiq.model_expansions.closure import Closure
|
16
|
-
from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
|
17
|
-
from classiq.model_expansions.scope import Scope
|
18
|
-
|
19
|
-
|
20
|
-
class PowerEmitter(CallEmitter[Power]):
|
21
|
-
_power_value: Union[int, sympy.Basic]
|
22
|
-
_power_expr: Expression
|
23
|
-
|
24
|
-
def emit(self, power: Power, /) -> None:
|
25
|
-
self._power = power
|
26
|
-
self._power_value = self._get_power_value()
|
27
|
-
self._power_expr = Expression(
|
28
|
-
expr=str(self._power_value), source_ref=power.power.source_ref
|
29
|
-
)
|
30
|
-
self._power_expr._evaluated_expr = EvaluatedExpression(value=self._power_value)
|
31
|
-
|
32
|
-
if len(power.body) > 1 and isinstance(self._power_value, sympy.Basic):
|
33
|
-
self._emit_wrapped()
|
34
|
-
return
|
35
|
-
|
36
|
-
self._emit_as_operation(power)
|
37
|
-
|
38
|
-
def _emit_as_operation(self, power: Power) -> None:
|
39
|
-
power_operation = Closure(
|
40
|
-
name=POWER_OPERATOR_NAME,
|
41
|
-
blocks=dict(body=self._power.body),
|
42
|
-
scope=Scope(parent=self._current_scope),
|
43
|
-
)
|
44
|
-
context = self._expand_operation(power_operation)
|
45
|
-
self.emit_statement(
|
46
|
-
Power(
|
47
|
-
body=context.statements("body"),
|
48
|
-
power=self._power_expr,
|
49
|
-
source_ref=power.source_ref,
|
50
|
-
)
|
51
|
-
)
|
52
|
-
|
53
|
-
def _emit_wrapped(self) -> None:
|
54
|
-
wrapping_function = self._create_expanded_wrapping_function(
|
55
|
-
POWER_OPERATOR_NAME, self._power.body
|
56
|
-
)
|
57
|
-
self.emit_statement(
|
58
|
-
Power(
|
59
|
-
body=[wrapping_function],
|
60
|
-
power=self._power_expr,
|
61
|
-
source_ref=self._power.source_ref,
|
62
|
-
)
|
63
|
-
)
|
64
|
-
|
65
|
-
def _get_power_value(self) -> Union[int, sympy.Basic]:
|
66
|
-
power_value = self._interpreter.evaluate(self._power.power).value
|
67
|
-
if isinstance(power_value, int) and power_value < 0:
|
68
|
-
raise ClassiqExpansionError(
|
69
|
-
f"power exponent must be non-negative, got {power_value}"
|
70
|
-
)
|
71
|
-
return power_value
|
@@ -1,230 +0,0 @@
|
|
1
|
-
import ast
|
2
|
-
import re
|
3
|
-
|
4
|
-
from classiq.interface.exceptions import (
|
5
|
-
ClassiqExpansionError,
|
6
|
-
ClassiqInternalExpansionError,
|
7
|
-
)
|
8
|
-
from classiq.interface.generator.arith.arithmetic import is_zero
|
9
|
-
from classiq.interface.generator.arith.arithmetic_expression_validator import (
|
10
|
-
is_constant,
|
11
|
-
)
|
12
|
-
from classiq.interface.generator.compiler_keywords import INPLACE_ARITH_AUX_VAR_PREFIX
|
13
|
-
from classiq.interface.generator.expressions.expression import Expression
|
14
|
-
from classiq.interface.model.handle_binding import HandleBinding
|
15
|
-
from classiq.interface.model.inplace_binary_operation import (
|
16
|
-
BinaryOperation,
|
17
|
-
InplaceBinaryOperation,
|
18
|
-
)
|
19
|
-
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
20
|
-
ArithmeticOperation,
|
21
|
-
ArithmeticOperationKind,
|
22
|
-
)
|
23
|
-
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
24
|
-
QuantumAssignmentOperation,
|
25
|
-
)
|
26
|
-
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
27
|
-
from classiq.interface.model.quantum_type import QuantumNumeric
|
28
|
-
from classiq.interface.model.variable_declaration_statement import (
|
29
|
-
VariableDeclarationStatement,
|
30
|
-
)
|
31
|
-
from classiq.interface.model.within_apply_operation import WithinApply
|
32
|
-
|
33
|
-
from classiq.model_expansions.capturing.mangling_utils import demangle_handle
|
34
|
-
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
35
|
-
from classiq.model_expansions.quantum_operations.expression_operation import (
|
36
|
-
ExpressionOperationEmitter,
|
37
|
-
)
|
38
|
-
from classiq.model_expansions.scope import QuantumSymbol
|
39
|
-
from classiq.model_expansions.transformers.var_splitter import SymbolParts
|
40
|
-
from classiq.model_expansions.visitors.boolean_expression_transformers import (
|
41
|
-
BooleanExpressionFuncLibAdapter,
|
42
|
-
BooleanExpressionOptimizer,
|
43
|
-
)
|
44
|
-
from classiq.qmod import builtins
|
45
|
-
from classiq.qmod.builtins.functions import X, allocate
|
46
|
-
|
47
|
-
HANDLE_ERROR_MESSAGE = (
|
48
|
-
"Quantum variable '{handle_str}' cannot appear on both sides of the assignment"
|
49
|
-
)
|
50
|
-
|
51
|
-
|
52
|
-
def _is_variable(expr: str) -> bool:
|
53
|
-
return re.fullmatch("[a-zA-Z_][a-zA-Z0-9_]*", expr) is not None
|
54
|
-
|
55
|
-
|
56
|
-
class QuantumAssignmentOperationEmitter(
|
57
|
-
ExpressionOperationEmitter[QuantumAssignmentOperation]
|
58
|
-
):
|
59
|
-
def emit(self, op: QuantumAssignmentOperation, /) -> None:
|
60
|
-
if self._skip_assignment(op, op.expression.expr):
|
61
|
-
return
|
62
|
-
arrays_with_subscript = self.split_symbols(
|
63
|
-
op.expression, self._counted_name_allocator.allocate
|
64
|
-
)
|
65
|
-
if len(arrays_with_subscript) > 0:
|
66
|
-
self._emit_with_split(op, op.expression, arrays_with_subscript)
|
67
|
-
return
|
68
|
-
|
69
|
-
self._emit_op(op)
|
70
|
-
|
71
|
-
def _emit_op(self, op: QuantumAssignmentOperation) -> None:
|
72
|
-
op = self._evaluate_types_in_expression(op)
|
73
|
-
if isinstance(op, ArithmeticOperation):
|
74
|
-
self._emit_arithmetic_op(op)
|
75
|
-
return
|
76
|
-
self._emit_general_assignment_operation(op)
|
77
|
-
|
78
|
-
def _emit_arithmetic_op(self, op: ArithmeticOperation) -> None:
|
79
|
-
op, expression, is_bool_opt = self._optimize_boolean_expression(op)
|
80
|
-
if op.is_inplace:
|
81
|
-
self._emit_inplace_arithmetic_op(op, expression, is_bool_opt)
|
82
|
-
else:
|
83
|
-
self._emit_general_assignment_operation(op)
|
84
|
-
|
85
|
-
def _emit_inplace_arithmetic_op(
|
86
|
-
self, op: ArithmeticOperation, expression: Expression, is_bool_opt: bool
|
87
|
-
) -> None:
|
88
|
-
target = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
|
89
|
-
if (
|
90
|
-
op.operation_kind != ArithmeticOperationKind.InplaceXor
|
91
|
-
or op.result_type.size_in_bits > 1
|
92
|
-
or not self._is_res_boolean(op)
|
93
|
-
or target.quantum_type.size_in_bits > 1
|
94
|
-
or is_constant(expression.expr)
|
95
|
-
):
|
96
|
-
_validate_naive_inplace_handles(op)
|
97
|
-
self._build_naive_inplace(op, expression)
|
98
|
-
return
|
99
|
-
|
100
|
-
op, expression, to_invert = self._adapt_boolean_inplace(
|
101
|
-
op, expression, is_bool_opt
|
102
|
-
)
|
103
|
-
self._emit_general_assignment_operation(op)
|
104
|
-
if not to_invert:
|
105
|
-
return
|
106
|
-
|
107
|
-
call = QuantumFunctionCall(
|
108
|
-
function=builtins.functions.X.__name__, # type:ignore[attr-defined]
|
109
|
-
positional_args=[op.result_var],
|
110
|
-
source_ref=op.source_ref,
|
111
|
-
)
|
112
|
-
call.set_func_decl(X.func_decl)
|
113
|
-
self._interpreter.emit_statement(call)
|
114
|
-
|
115
|
-
def _emit_general_assignment_operation(
|
116
|
-
self, op: QuantumAssignmentOperation
|
117
|
-
) -> None:
|
118
|
-
result = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
|
119
|
-
copy_type_information(op.result_type, result.quantum_type, str(result.handle))
|
120
|
-
self.emit_statement(op)
|
121
|
-
|
122
|
-
def _optimize_boolean_expression(
|
123
|
-
self, op: ArithmeticOperation
|
124
|
-
) -> tuple[ArithmeticOperation, Expression, bool]:
|
125
|
-
if (
|
126
|
-
op.operation_kind
|
127
|
-
not in (
|
128
|
-
ArithmeticOperationKind.Assignment,
|
129
|
-
ArithmeticOperationKind.InplaceXor,
|
130
|
-
)
|
131
|
-
or not self._all_vars_boolean(op)
|
132
|
-
or not self._is_res_boolean(op)
|
133
|
-
):
|
134
|
-
return op, op.expression, False
|
135
|
-
optimizer = BooleanExpressionOptimizer()
|
136
|
-
optimized_expression = Expression(
|
137
|
-
expr=ast.unparse(optimizer.visit(ast.parse(op.expression.expr)))
|
138
|
-
)
|
139
|
-
optimized_expression = self._evaluate_expression(optimized_expression)
|
140
|
-
optimized_op = op.model_copy(update=dict(expression=optimized_expression))
|
141
|
-
return optimized_op, optimized_expression, optimizer.is_convertible
|
142
|
-
|
143
|
-
def _adapt_boolean_inplace(
|
144
|
-
self, op: ArithmeticOperation, expression: Expression, is_bool_opt: bool
|
145
|
-
) -> tuple[ArithmeticOperation, Expression, bool]:
|
146
|
-
adapter = BooleanExpressionFuncLibAdapter(is_bool_opt)
|
147
|
-
adapted_expression = self._evaluate_expression(
|
148
|
-
Expression(expr=ast.unparse(adapter.visit(ast.parse(expression.expr))))
|
149
|
-
)
|
150
|
-
adapted_op = op.model_copy(update=dict(expression=adapted_expression))
|
151
|
-
return adapted_op, adapted_expression, adapter.to_invert
|
152
|
-
|
153
|
-
def _build_naive_inplace(
|
154
|
-
self, qe: ArithmeticOperation, new_expression: Expression
|
155
|
-
) -> None:
|
156
|
-
if qe.operation_kind == ArithmeticOperationKind.InplaceXor:
|
157
|
-
op = BinaryOperation.Xor
|
158
|
-
elif qe.operation_kind == ArithmeticOperationKind.InplaceAdd:
|
159
|
-
op = BinaryOperation.Addition
|
160
|
-
else:
|
161
|
-
raise ClassiqInternalExpansionError(
|
162
|
-
f"Unrecognized operation kind {qe.operation_kind!r}"
|
163
|
-
)
|
164
|
-
|
165
|
-
if is_constant(new_expression.expr):
|
166
|
-
self._interpreter.emit_statement(
|
167
|
-
InplaceBinaryOperation(
|
168
|
-
operation=op,
|
169
|
-
target=qe.result_var,
|
170
|
-
value=new_expression,
|
171
|
-
)
|
172
|
-
)
|
173
|
-
return
|
174
|
-
|
175
|
-
if _is_variable(new_expression.expr):
|
176
|
-
value_var = self._interpreter.evaluate(new_expression.expr).value
|
177
|
-
if isinstance(value_var, QuantumSymbol):
|
178
|
-
self._interpreter.emit_statement(
|
179
|
-
InplaceBinaryOperation(
|
180
|
-
operation=op,
|
181
|
-
target=qe.result_var,
|
182
|
-
value=value_var.handle,
|
183
|
-
)
|
184
|
-
)
|
185
|
-
return
|
186
|
-
|
187
|
-
aux_var = self._counted_name_allocator.allocate(INPLACE_ARITH_AUX_VAR_PREFIX)
|
188
|
-
self._interpreter.emit_statement(
|
189
|
-
VariableDeclarationStatement(name=aux_var, quantum_type=QuantumNumeric())
|
190
|
-
)
|
191
|
-
arith_expression = ArithmeticOperation(
|
192
|
-
result_var=HandleBinding(name=aux_var),
|
193
|
-
expression=new_expression,
|
194
|
-
operation_kind=ArithmeticOperationKind.Assignment,
|
195
|
-
)
|
196
|
-
inplace_store = InplaceBinaryOperation(
|
197
|
-
operation=op,
|
198
|
-
target=qe.result_var,
|
199
|
-
value=HandleBinding(name=aux_var),
|
200
|
-
)
|
201
|
-
self._interpreter.emit_statement(
|
202
|
-
WithinApply(compute=[arith_expression], action=[inplace_store])
|
203
|
-
)
|
204
|
-
|
205
|
-
def _skip_assignment(self, op: QuantumAssignmentOperation, expr: str) -> bool:
|
206
|
-
if not isinstance(op, ArithmeticOperation) or not is_zero(expr):
|
207
|
-
return False
|
208
|
-
if op.operation_kind != ArithmeticOperationKind.Assignment:
|
209
|
-
return True
|
210
|
-
allocate_call = QuantumFunctionCall(
|
211
|
-
function=allocate.func_decl.name,
|
212
|
-
positional_args=[Expression(expr="1"), op.result_var],
|
213
|
-
)
|
214
|
-
allocate_call.set_func_decl(allocate.func_decl)
|
215
|
-
self._interpreter.emit_statement(allocate_call)
|
216
|
-
return True
|
217
|
-
|
218
|
-
def _get_updated_op_split_symbols(
|
219
|
-
self, op: QuantumAssignmentOperation, symbol_parts: SymbolParts
|
220
|
-
) -> QuantumAssignmentOperation:
|
221
|
-
return op.model_copy(
|
222
|
-
update=dict(result_var=self.rewrite(op.result_var, symbol_parts))
|
223
|
-
)
|
224
|
-
|
225
|
-
|
226
|
-
def _validate_naive_inplace_handles(qe: ArithmeticOperation) -> None:
|
227
|
-
if qe.result_var in qe.var_handles:
|
228
|
-
raise ClassiqExpansionError(
|
229
|
-
HANDLE_ERROR_MESSAGE.format(handle_str=str(demangle_handle(qe.result_var)))
|
230
|
-
)
|
@@ -1,25 +0,0 @@
|
|
1
|
-
from classiq.interface.generator.functions.builtins.internal_operators import (
|
2
|
-
WITHIN_APPLY_NAME,
|
3
|
-
)
|
4
|
-
from classiq.interface.model.within_apply_operation import WithinApply
|
5
|
-
|
6
|
-
from classiq.model_expansions.closure import Closure
|
7
|
-
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
8
|
-
from classiq.model_expansions.scope import Scope
|
9
|
-
|
10
|
-
|
11
|
-
class WithinApplyEmitter(Emitter[WithinApply]):
|
12
|
-
def emit(self, within_apply: WithinApply, /) -> None:
|
13
|
-
within_apply_operation = Closure(
|
14
|
-
name=WITHIN_APPLY_NAME,
|
15
|
-
blocks=dict(within=within_apply.compute, apply=within_apply.action),
|
16
|
-
scope=Scope(parent=self._current_scope),
|
17
|
-
)
|
18
|
-
context = self._expand_operation(within_apply_operation)
|
19
|
-
self.emit_statement(
|
20
|
-
WithinApply(
|
21
|
-
compute=context.statements("within"),
|
22
|
-
action=context.statements("apply"),
|
23
|
-
source_ref=within_apply.source_ref,
|
24
|
-
)
|
25
|
-
)
|
File without changes
|