classiq 0.47.0__py3-none-any.whl → 0.48.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +2 -7
- classiq/applications/grover/grover_model_constructor.py +2 -1
- classiq/execution/execution_session.py +40 -9
- classiq/execution/jobs.py +18 -6
- classiq/interface/_version.py +1 -1
- classiq/interface/execution/primitives.py +9 -1
- classiq/interface/executor/iqae_result.py +3 -3
- classiq/interface/executor/result.py +3 -1
- classiq/interface/generator/expressions/expression.py +8 -0
- classiq/interface/generator/functions/type_name.py +1 -3
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +17 -3
- classiq/interface/ide/visual_model.py +3 -4
- classiq/interface/model/bind_operation.py +0 -3
- classiq/interface/model/port_declaration.py +1 -12
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +38 -6
- classiq/interface/model/quantum_lambda_function.py +4 -1
- classiq/interface/model/quantum_statement.py +16 -1
- classiq/interface/model/quantum_variable_declaration.py +0 -22
- classiq/interface/server/global_versions.py +4 -4
- classiq/model_expansions/capturing/propagated_var_stack.py +5 -2
- classiq/model_expansions/closure.py +7 -2
- classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
- classiq/model_expansions/generative_functions.py +146 -28
- classiq/model_expansions/interpreter.py +11 -5
- classiq/model_expansions/quantum_operations/classicalif.py +27 -10
- classiq/model_expansions/quantum_operations/control.py +22 -15
- classiq/model_expansions/quantum_operations/emitter.py +60 -5
- classiq/model_expansions/quantum_operations/expression_operation.py +25 -16
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +163 -95
- classiq/model_expansions/quantum_operations/invert.py +12 -6
- classiq/model_expansions/quantum_operations/phase.py +15 -3
- classiq/model_expansions/quantum_operations/power.py +9 -8
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +20 -5
- classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
- classiq/model_expansions/quantum_operations/repeat.py +32 -13
- classiq/model_expansions/quantum_operations/within_apply.py +19 -6
- classiq/model_expansions/scope.py +16 -5
- classiq/model_expansions/scope_initialization.py +11 -1
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +23 -1
- classiq/model_expansions/visitors/variable_references.py +11 -7
- classiq/qmod/builtins/__init__.py +10 -0
- classiq/qmod/builtins/constants.py +10 -0
- classiq/qmod/builtins/functions/state_preparation.py +4 -1
- classiq/qmod/builtins/operations.py +43 -163
- classiq/qmod/create_model_function.py +1 -1
- classiq/qmod/generative.py +14 -5
- classiq/qmod/native/pretty_printer.py +9 -5
- classiq/qmod/pretty_print/pretty_printer.py +8 -4
- classiq/qmod/qmod_constant.py +28 -18
- classiq/qmod/qmod_variable.py +43 -23
- classiq/qmod/quantum_expandable.py +14 -1
- classiq/qmod/semantics/static_semantics_visitor.py +10 -0
- classiq/qmod/semantics/validation/constants_validation.py +16 -0
- {classiq-0.47.0.dist-info → classiq-0.48.1.dist-info}/METADATA +3 -1
- {classiq-0.47.0.dist-info → classiq-0.48.1.dist-info}/RECORD +56 -54
- {classiq-0.47.0.dist-info → classiq-0.48.1.dist-info}/WHEEL +0 -0
@@ -1,6 +1,5 @@
|
|
1
|
-
from typing import TYPE_CHECKING, List,
|
1
|
+
from typing import TYPE_CHECKING, List, Tuple
|
2
2
|
|
3
|
-
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
4
3
|
from classiq.interface.generator.expressions.expression import Expression
|
5
4
|
from classiq.interface.generator.functions.port_declaration import (
|
6
5
|
PortDeclarationDirection,
|
@@ -25,6 +24,7 @@ from classiq.interface.model.quantum_type import (
|
|
25
24
|
from classiq.interface.model.variable_declaration_statement import (
|
26
25
|
VariableDeclarationStatement,
|
27
26
|
)
|
27
|
+
from classiq.interface.model.within_apply_operation import WithinApply
|
28
28
|
|
29
29
|
from classiq.model_expansions.closure import FunctionClosure
|
30
30
|
from classiq.model_expansions.evaluators.parameter_types import (
|
@@ -35,7 +35,7 @@ from classiq.model_expansions.evaluators.quantum_type_utils import (
|
|
35
35
|
)
|
36
36
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
37
37
|
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
38
|
-
from classiq.qmod.builtins.functions import integer_xor, modular_add
|
38
|
+
from classiq.qmod.builtins.functions import CX, allocate, integer_xor, modular_add
|
39
39
|
|
40
40
|
|
41
41
|
def _binary_function_declaration(
|
@@ -59,16 +59,13 @@ class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
|
|
59
59
|
assert isinstance(value_var.quantum_type, QuantumNumeric)
|
60
60
|
assert isinstance(target_var.quantum_type, QuantumNumeric)
|
61
61
|
|
62
|
-
sign_diff = int(value_var.quantum_type.sign_value) - int(
|
63
|
-
target_var.quantum_type.sign_value
|
64
|
-
)
|
65
62
|
frac_digits_diff = (
|
66
63
|
value_var.quantum_type.fraction_digits_value
|
67
64
|
- target_var.quantum_type.fraction_digits_value
|
68
65
|
)
|
69
66
|
if (
|
70
|
-
|
71
|
-
or -
|
67
|
+
frac_digits_diff == value_var.quantum_type.size_in_bits
|
68
|
+
or -frac_digits_diff == target_var.quantum_type.size_in_bits
|
72
69
|
):
|
73
70
|
with self._propagated_var_stack.capture_variables(op):
|
74
71
|
return
|
@@ -97,7 +94,6 @@ class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
|
|
97
94
|
body=_build_inplace_binary_operation(
|
98
95
|
value_var=value_var,
|
99
96
|
target_var=target_var,
|
100
|
-
frac_digits_diff=frac_digits_diff,
|
101
97
|
internal_function_declaration=_binary_function_declaration(
|
102
98
|
op.operation
|
103
99
|
),
|
@@ -113,53 +109,56 @@ class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
|
|
113
109
|
def _build_inplace_binary_operation(
|
114
110
|
value_var: QuantumSymbol,
|
115
111
|
target_var: QuantumSymbol,
|
116
|
-
frac_digits_diff: int,
|
117
112
|
internal_function_declaration: NamedParamsQuantumFunctionDeclaration,
|
118
113
|
) -> List[QuantumStatement]:
|
119
114
|
if TYPE_CHECKING:
|
120
115
|
assert isinstance(value_var.quantum_type, QuantumNumeric)
|
121
116
|
assert isinstance(target_var.quantum_type, QuantumNumeric)
|
122
117
|
|
123
|
-
|
124
|
-
|
118
|
+
frac_digits_diff = (
|
119
|
+
value_var.quantum_type.fraction_digits_value
|
120
|
+
- target_var.quantum_type.fraction_digits_value
|
125
121
|
)
|
126
|
-
|
127
|
-
|
122
|
+
size_diff = (
|
123
|
+
value_var.quantum_type.size_in_bits - target_var.quantum_type.size_in_bits
|
128
124
|
)
|
129
125
|
|
130
|
-
|
131
|
-
|
126
|
+
target_overlap_var, target_var_decls, target_bind_ops = (
|
127
|
+
_trim_superfluous_fraction_digits("target", target_var, -frac_digits_diff)
|
132
128
|
)
|
133
|
-
|
134
|
-
|
129
|
+
value_overlap_var, value_trim_var_decls, value_bind_ops = (
|
130
|
+
_trim_superfluous_fraction_digits("value", value_var, frac_digits_diff)
|
135
131
|
)
|
132
|
+
(
|
133
|
+
value_padded_var,
|
134
|
+
value_pad_var_decls,
|
135
|
+
value_pad_pre_bind_ops,
|
136
|
+
value_pad_init_ops,
|
137
|
+
value_post_bind_ops,
|
138
|
+
) = _pad_with_sign_bit("value", value_overlap_var, size_diff)
|
136
139
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
value_overlap_var.handle,
|
143
|
-
target_overlap_var.handle,
|
144
|
-
)
|
145
|
-
)
|
146
|
-
if value_sign_var is not None and target_sign_var is not None:
|
147
|
-
binary_ops.append(
|
148
|
-
_internal_inplace_binary_operation_function_call(
|
149
|
-
internal_function_declaration,
|
150
|
-
value_sign_var.handle,
|
151
|
-
target_sign_var.handle,
|
152
|
-
)
|
153
|
-
)
|
154
|
-
if len(binary_ops) == 0:
|
155
|
-
raise ClassiqInternalExpansionError("Bug in unrolling inplace operation")
|
140
|
+
op_call = _internal_inplace_binary_operation_function_call(
|
141
|
+
internal_function_declaration,
|
142
|
+
value_padded_var.handle,
|
143
|
+
target_overlap_var.handle,
|
144
|
+
)
|
156
145
|
|
157
146
|
return [
|
158
|
-
*
|
159
|
-
*
|
160
|
-
*
|
161
|
-
|
162
|
-
|
147
|
+
*target_var_decls,
|
148
|
+
*value_trim_var_decls,
|
149
|
+
*value_pad_var_decls,
|
150
|
+
WithinApply(
|
151
|
+
compute=[
|
152
|
+
*target_bind_ops,
|
153
|
+
*value_bind_ops,
|
154
|
+
*value_pad_pre_bind_ops,
|
155
|
+
*value_pad_init_ops,
|
156
|
+
*value_post_bind_ops,
|
157
|
+
],
|
158
|
+
action=[
|
159
|
+
op_call,
|
160
|
+
],
|
161
|
+
),
|
163
162
|
]
|
164
163
|
|
165
164
|
|
@@ -176,75 +175,144 @@ def _internal_inplace_binary_operation_function_call(
|
|
176
175
|
return internal_function_call
|
177
176
|
|
178
177
|
|
179
|
-
def
|
178
|
+
def _trim_superfluous_fraction_digits(
|
180
179
|
kind: str, var: QuantumSymbol, frac_digits_diff: int
|
181
|
-
) -> Tuple[
|
180
|
+
) -> Tuple[QuantumSymbol, List[VariableDeclarationStatement], List[BindOperation]]:
|
181
|
+
if frac_digits_diff <= 0:
|
182
|
+
return var, [], []
|
183
|
+
|
182
184
|
quantum_type = var.quantum_type
|
183
185
|
if TYPE_CHECKING:
|
184
186
|
assert isinstance(quantum_type, QuantumNumeric)
|
185
187
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
- quantum_type.fraction_digits_value
|
192
|
-
- int(quantum_type.sign_value)
|
188
|
+
trimmed_fraction_digits_var = QuantumSymbol(
|
189
|
+
handle=HandleBinding(name=f"trimmed_{kind}_fraction_digits"),
|
190
|
+
quantum_type=QuantumBitvector(
|
191
|
+
length=Expression(expr=str(frac_digits_diff)),
|
192
|
+
),
|
193
193
|
)
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
194
|
+
overlap_var = QuantumSymbol(
|
195
|
+
handle=HandleBinding(name=f"{kind}_overlap"),
|
196
|
+
quantum_type=QuantumNumeric(
|
197
|
+
size=Expression(expr=str(quantum_type.size_in_bits - frac_digits_diff)),
|
198
|
+
is_signed=quantum_type.is_signed,
|
199
|
+
fraction_digits=Expression(expr="0"),
|
200
|
+
),
|
201
|
+
)
|
202
|
+
bind_targets = trimmed_fraction_digits_var, overlap_var
|
200
203
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
quantum_type=QuantumBitvector(
|
206
|
-
length=Expression(expr=str(frac_digits_diff)),
|
207
|
-
),
|
208
|
-
)
|
204
|
+
split_var_declarations = [
|
205
|
+
VariableDeclarationStatement(
|
206
|
+
name=var.handle.name,
|
207
|
+
quantum_type=var.quantum_type,
|
209
208
|
)
|
209
|
+
for var in bind_targets
|
210
|
+
]
|
211
|
+
bind_op = BindOperation(
|
212
|
+
in_handles=[var.handle],
|
213
|
+
out_handles=[var.handle for var in bind_targets],
|
214
|
+
)
|
210
215
|
|
211
|
-
overlap_var
|
212
|
-
if significand_overlap + fraction_overlap > 0:
|
213
|
-
overlap_var = QuantumSymbol(
|
214
|
-
handle=HandleBinding(name=f"{kind}_overlap"),
|
215
|
-
quantum_type=QuantumNumeric(
|
216
|
-
size=Expression(expr=str(significand_overlap + fraction_overlap)),
|
217
|
-
is_signed=Expression(expr="False"),
|
218
|
-
fraction_digits=Expression(expr=str(fraction_overlap)),
|
219
|
-
),
|
220
|
-
)
|
221
|
-
bind_targets.append(overlap_var)
|
216
|
+
return overlap_var, split_var_declarations, [bind_op]
|
222
217
|
|
223
|
-
sign_var = None
|
224
|
-
if quantum_type.sign_value:
|
225
|
-
sign_var = QuantumSymbol(
|
226
|
-
handle=HandleBinding(name=f"trimmed_{kind}_sign"),
|
227
|
-
quantum_type=QuantumBit(),
|
228
|
-
)
|
229
|
-
bind_targets.append(sign_var)
|
230
218
|
|
231
|
-
|
219
|
+
def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> Tuple[
|
220
|
+
QuantumSymbol,
|
221
|
+
List[VariableDeclarationStatement],
|
222
|
+
List[QuantumStatement],
|
223
|
+
List[QuantumFunctionCall],
|
224
|
+
List[BindOperation],
|
225
|
+
]:
|
226
|
+
quantum_type = var.quantum_type
|
227
|
+
if TYPE_CHECKING:
|
228
|
+
assert isinstance(quantum_type, QuantumNumeric)
|
232
229
|
|
230
|
+
if not quantum_type.sign_value or size_diff >= 0:
|
231
|
+
return var, [], [], [], []
|
233
232
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
if len(bind_targets) == 0:
|
238
|
-
return [], []
|
233
|
+
significand_var, sign_var, sign_split_bind = _split_sign(kind, var)
|
234
|
+
padding_var, padding_allocation = _allocate_padding(kind, size_diff)
|
235
|
+
padding_init_ops = _init_padding(sign_var, padding_var, size_diff)
|
239
236
|
|
240
|
-
|
241
|
-
|
242
|
-
|
237
|
+
padded_var = QuantumSymbol(
|
238
|
+
handle=HandleBinding(name=f"padded_{kind}"),
|
239
|
+
quantum_type=QuantumNumeric(
|
240
|
+
size=Expression(expr=str(quantum_type.size_in_bits - size_diff)),
|
241
|
+
is_signed=Expression(expr="False"),
|
242
|
+
fraction_digits=Expression(expr="0"),
|
243
|
+
),
|
243
244
|
)
|
244
|
-
|
245
|
+
padding_rebind = BindOperation(
|
246
|
+
in_handles=[significand_var.handle, sign_var.handle, padding_var.handle],
|
247
|
+
out_handles=[padded_var.handle],
|
248
|
+
)
|
249
|
+
|
250
|
+
var_decls = [
|
245
251
|
VariableDeclarationStatement(
|
246
252
|
name=var.handle.name,
|
247
253
|
quantum_type=var.quantum_type,
|
248
254
|
)
|
249
|
-
for var in
|
250
|
-
]
|
255
|
+
for var in (significand_var, sign_var, padding_var, padded_var)
|
256
|
+
]
|
257
|
+
|
258
|
+
return (
|
259
|
+
padded_var,
|
260
|
+
var_decls,
|
261
|
+
[sign_split_bind, padding_allocation],
|
262
|
+
padding_init_ops,
|
263
|
+
[padding_rebind],
|
264
|
+
)
|
265
|
+
|
266
|
+
|
267
|
+
def _init_padding(
|
268
|
+
sign_var: QuantumSymbol, padding_var: QuantumSymbol, size_diff: int
|
269
|
+
) -> List[QuantumFunctionCall]:
|
270
|
+
padding_init_ops = [
|
271
|
+
QuantumFunctionCall(
|
272
|
+
function=CX.func_decl.name,
|
273
|
+
positional_args=[sign_var.handle, padding_var[idx].handle],
|
274
|
+
)
|
275
|
+
for idx in range(-size_diff)
|
276
|
+
]
|
277
|
+
for cx_call in padding_init_ops:
|
278
|
+
cx_call.set_func_decl(CX.func_decl)
|
279
|
+
return padding_init_ops
|
280
|
+
|
281
|
+
|
282
|
+
def _allocate_padding(
|
283
|
+
kind: str, size_diff: int
|
284
|
+
) -> Tuple[QuantumSymbol, QuantumFunctionCall]:
|
285
|
+
padding_var = QuantumSymbol(
|
286
|
+
handle=HandleBinding(name=f"{kind}_sign_padding"),
|
287
|
+
quantum_type=QuantumBitvector(
|
288
|
+
length=Expression(expr=str(-size_diff)),
|
289
|
+
),
|
290
|
+
)
|
291
|
+
padding_allocation = QuantumFunctionCall(
|
292
|
+
function=allocate.func_decl.name,
|
293
|
+
positional_args=[Expression(expr=str(-size_diff)), padding_var.handle],
|
294
|
+
)
|
295
|
+
padding_allocation.set_func_decl(allocate.func_decl)
|
296
|
+
return padding_var, padding_allocation
|
297
|
+
|
298
|
+
|
299
|
+
def _split_sign(
|
300
|
+
kind: str, var: QuantumSymbol
|
301
|
+
) -> Tuple[QuantumSymbol, QuantumSymbol, BindOperation]:
|
302
|
+
significand_var = QuantumSymbol(
|
303
|
+
handle=HandleBinding(name=f"{kind}_significand"),
|
304
|
+
quantum_type=QuantumNumeric(
|
305
|
+
size=Expression(expr=str(var.quantum_type.size_in_bits - 1)),
|
306
|
+
is_signed=Expression(expr="False"),
|
307
|
+
fraction_digits=Expression(expr="0"),
|
308
|
+
),
|
309
|
+
)
|
310
|
+
sign_var = QuantumSymbol(
|
311
|
+
handle=HandleBinding(name=f"{kind}_sign_bit"),
|
312
|
+
quantum_type=QuantumBit(),
|
313
|
+
)
|
314
|
+
sign_split_bind = BindOperation(
|
315
|
+
in_handles=[var.handle],
|
316
|
+
out_handles=[significand_var.handle, sign_var.handle],
|
317
|
+
)
|
318
|
+
return significand_var, sign_var, sign_split_bind
|
@@ -10,6 +10,14 @@ from classiq.model_expansions.scope import Scope
|
|
10
10
|
|
11
11
|
class InvertEmitter(Emitter[Invert]):
|
12
12
|
def emit(self, invert: Invert, /) -> None:
|
13
|
+
with self._propagated_var_stack.capture_variables(invert):
|
14
|
+
self._emit_propagated(invert)
|
15
|
+
|
16
|
+
def _emit_propagated(self, invert: Invert, /) -> None:
|
17
|
+
if invert.is_generative():
|
18
|
+
context = self._register_generative_context(invert, INVERT_OPERATOR_NAME)
|
19
|
+
invert = invert.copy(update={"body": context.statements("body")})
|
20
|
+
|
13
21
|
if self._should_wrap(invert.body):
|
14
22
|
self._emit_wrapped(invert)
|
15
23
|
return
|
@@ -22,17 +30,15 @@ class InvertEmitter(Emitter[Invert]):
|
|
22
30
|
blocks={"body": invert.body},
|
23
31
|
scope=Scope(parent=self._current_scope),
|
24
32
|
)
|
25
|
-
|
26
|
-
context = self._expand_operation(invert_operation)
|
33
|
+
context = self._expand_operation(invert_operation)
|
27
34
|
self._builder.emit_statement(
|
28
35
|
Invert(body=context.statements("body"), source_ref=invert.source_ref)
|
29
36
|
)
|
30
37
|
|
31
38
|
def _emit_wrapped(self, invert: Invert) -> None:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
)
|
39
|
+
wrapping_function = self._create_expanded_wrapping_function(
|
40
|
+
INVERT_OPERATOR_NAME, invert.body
|
41
|
+
)
|
36
42
|
self._builder.emit_statement(
|
37
43
|
Invert(body=[wrapping_function], source_ref=invert.source_ref)
|
38
44
|
)
|
@@ -21,7 +21,6 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
21
21
|
|
22
22
|
from classiq.applications.combinatorial_helpers.transformations.ising_converter import (
|
23
23
|
_find_sub_list_items,
|
24
|
-
_get_coeff_from_expr,
|
25
24
|
_get_vars,
|
26
25
|
_refine_ising_expr,
|
27
26
|
_to_ising_symbolic_objective_function,
|
@@ -34,6 +33,12 @@ from classiq.qmod.semantics.error_manager import ErrorManager
|
|
34
33
|
|
35
34
|
|
36
35
|
class PhaseEmitter(ExpressionOperationEmitter[PhaseOperation]):
|
36
|
+
def _negate_expression(self, expression: Expression, /) -> Expression:
|
37
|
+
return self._evaluate_expression(
|
38
|
+
# TODO: change to model_copy for pydantic V2
|
39
|
+
expression.copy(update=dict(expr=f"-({expression.expr})"))
|
40
|
+
)
|
41
|
+
|
37
42
|
def emit(self, phase_op: PhaseOperation, /) -> None:
|
38
43
|
phase_expression = self._evaluate_op_expression(phase_op)
|
39
44
|
phase_op = phase_op.copy(update=dict(expression=phase_expression))
|
@@ -41,7 +46,10 @@ class PhaseEmitter(ExpressionOperationEmitter[PhaseOperation]):
|
|
41
46
|
if len(arrays_with_subscript) > 0:
|
42
47
|
self._emit_with_split(phase_op, phase_op.expression, arrays_with_subscript)
|
43
48
|
return
|
44
|
-
|
49
|
+
# TODO: change to model_copy for pydantic V2
|
50
|
+
phase_op = phase_op.copy(
|
51
|
+
update=dict(expression=self._negate_expression(phase_op.expression))
|
52
|
+
)
|
45
53
|
phase_op = self._evaluate_types_in_expression(phase_op, phase_op.expression)
|
46
54
|
if len(phase_op.var_handles) == 0:
|
47
55
|
ErrorManager().add_error(
|
@@ -135,6 +143,7 @@ def _convert_ising_sympy_to_pauli_terms(
|
|
135
143
|
ising_expr: sympy.Expr, ordered_sympy_vars: List[sympy.Symbol]
|
136
144
|
) -> str:
|
137
145
|
pauli_terms: List[str] = []
|
146
|
+
coefficients = ising_expr.as_coefficients_dict(*ordered_sympy_vars)
|
138
147
|
for expr_term in ising_expr.args:
|
139
148
|
expr_vars = _get_vars(expr_term)
|
140
149
|
z_vec = _find_sub_list_items(ordered_sympy_vars, expr_vars)
|
@@ -144,7 +153,10 @@ def _convert_ising_sympy_to_pauli_terms(
|
|
144
153
|
pauli_elements[len(z_vec) - index - 1] = (
|
145
154
|
"Z" # reminder: Pauli reverses the order!
|
146
155
|
)
|
147
|
-
|
156
|
+
term_var = sympy.Mul(
|
157
|
+
*(var for i, var in enumerate(ordered_sympy_vars) if z_vec[i])
|
158
|
+
)
|
159
|
+
coeff = float(coefficients[term_var])
|
148
160
|
paulis = [f"Pauli.{pauli}" for pauli in pauli_elements]
|
149
161
|
pauli_terms.append(
|
150
162
|
# fmt: off
|
@@ -2,7 +2,6 @@ from typing import Union
|
|
2
2
|
|
3
3
|
import sympy
|
4
4
|
|
5
|
-
from classiq.interface.exceptions import ClassiqExpansionError
|
6
5
|
from classiq.interface.generator.expressions.evaluated_expression import (
|
7
6
|
EvaluatedExpression,
|
8
7
|
)
|
@@ -22,6 +21,14 @@ class PowerEmitter(Emitter[Power]):
|
|
22
21
|
_power_expr: Expression
|
23
22
|
|
24
23
|
def emit(self, power: Power, /) -> None:
|
24
|
+
with self._propagated_var_stack.capture_variables(power):
|
25
|
+
self._emit_propagated(power)
|
26
|
+
|
27
|
+
def _emit_propagated(self, power: Power) -> None:
|
28
|
+
if power.is_generative():
|
29
|
+
context = self._register_generative_context(power, POWER_OPERATOR_NAME)
|
30
|
+
power = power.copy(update={"body": context.statements("body")})
|
31
|
+
|
25
32
|
self._power = power
|
26
33
|
self._power_value = self._get_power_value()
|
27
34
|
self._power_expr = Expression(
|
@@ -41,8 +48,7 @@ class PowerEmitter(Emitter[Power]):
|
|
41
48
|
blocks=dict(body=self._power.body),
|
42
49
|
scope=Scope(parent=self._current_scope),
|
43
50
|
)
|
44
|
-
|
45
|
-
context = self._expand_operation(power_operation)
|
51
|
+
context = self._expand_operation(power_operation)
|
46
52
|
self._builder.emit_statement(
|
47
53
|
Power(
|
48
54
|
body=context.statements("body"),
|
@@ -66,9 +72,4 @@ class PowerEmitter(Emitter[Power]):
|
|
66
72
|
|
67
73
|
def _get_power_value(self) -> Union[int, sympy.Basic]:
|
68
74
|
power_value = self._interpreter.evaluate(self._power.power).value
|
69
|
-
if not (isinstance(power_value, int) or power_value.is_symbol):
|
70
|
-
raise ClassiqExpansionError(
|
71
|
-
f"`power`'s argument should be an integer or identifier. Complex "
|
72
|
-
f"expressions are not supported. Got {str(power_value)!r}"
|
73
|
-
)
|
74
75
|
return power_value
|
@@ -11,6 +11,7 @@ from classiq.interface.model.inplace_binary_operation import (
|
|
11
11
|
)
|
12
12
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
13
13
|
ArithmeticOperation,
|
14
|
+
ArithmeticOperationKind,
|
14
15
|
)
|
15
16
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
16
17
|
QuantumAssignmentOperation,
|
@@ -62,7 +63,7 @@ class QuantumAssignmentOperationEmitter(
|
|
62
63
|
self, op: ArithmeticOperation, expression: Expression
|
63
64
|
) -> None:
|
64
65
|
op, expression, is_bool_opt = self._optimize_boolean_expression(op, expression)
|
65
|
-
if op.
|
66
|
+
if op.is_inplace:
|
66
67
|
self._emit_inplace_arithmetic_op(op, expression, is_bool_opt)
|
67
68
|
else:
|
68
69
|
self._emit_general_assignment_operation(op)
|
@@ -70,7 +71,9 @@ class QuantumAssignmentOperationEmitter(
|
|
70
71
|
def _emit_inplace_arithmetic_op(
|
71
72
|
self, op: ArithmeticOperation, expression: Expression, is_bool_opt: bool
|
72
73
|
) -> None:
|
73
|
-
if op.
|
74
|
+
if op.operation_kind != ArithmeticOperationKind.InplaceXor or (
|
75
|
+
op.result_type.size_in_bits > 1 or not _is_res_boolean(op)
|
76
|
+
):
|
74
77
|
_validate_naive_inplace_handles(op)
|
75
78
|
self._build_naive_inplace(op, expression)
|
76
79
|
return
|
@@ -100,7 +103,15 @@ class QuantumAssignmentOperationEmitter(
|
|
100
103
|
def _optimize_boolean_expression(
|
101
104
|
self, op: ArithmeticOperation, expression: Expression
|
102
105
|
) -> Tuple[ArithmeticOperation, Expression, bool]:
|
103
|
-
if
|
106
|
+
if (
|
107
|
+
self._interpreter._is_frontend
|
108
|
+
or op.operation_kind
|
109
|
+
not in (
|
110
|
+
ArithmeticOperationKind.Assignment,
|
111
|
+
ArithmeticOperationKind.InplaceXor,
|
112
|
+
)
|
113
|
+
or not _all_vars_boolean(op)
|
114
|
+
):
|
104
115
|
return op, expression, False
|
105
116
|
optimizer = BooleanExpressionOptimizer()
|
106
117
|
optimized_expression = Expression(
|
@@ -130,10 +141,14 @@ class QuantumAssignmentOperationEmitter(
|
|
130
141
|
arith_expression = ArithmeticOperation(
|
131
142
|
result_var=HandleBinding(name=aux_var),
|
132
143
|
expression=new_expression,
|
133
|
-
|
144
|
+
operation_kind=ArithmeticOperationKind.Assignment,
|
134
145
|
)
|
146
|
+
if qe.operation_kind == ArithmeticOperationKind.InplaceXor:
|
147
|
+
op = BinaryOperation.Xor
|
148
|
+
else:
|
149
|
+
op = BinaryOperation.Addition
|
135
150
|
inplace_store = InplaceBinaryOperation(
|
136
|
-
operation=
|
151
|
+
operation=op,
|
137
152
|
target=qe.result_var,
|
138
153
|
value=HandleBinding(name=aux_var),
|
139
154
|
)
|
@@ -11,5 +11,5 @@ class QuantumFunctionCallEmitter(Emitter[QuantumFunctionCall]):
|
|
11
11
|
args = call.positional_args
|
12
12
|
with ErrorManager().call(
|
13
13
|
function.name
|
14
|
-
), self._propagated_var_stack.capture_variables(call):
|
14
|
+
), function.scope.freeze(), self._propagated_var_stack.capture_variables(call):
|
15
15
|
self._emit_quantum_function_call(function, args)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import Type
|
2
|
+
|
1
3
|
from classiq.interface.generator.expressions.expression import Expression
|
2
4
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
3
5
|
REPEAT_OPERATOR_NAME,
|
@@ -8,9 +10,10 @@ from classiq.interface.model.classical_parameter_declaration import (
|
|
8
10
|
)
|
9
11
|
from classiq.interface.model.repeat import Repeat
|
10
12
|
|
11
|
-
from classiq.model_expansions.closure import FunctionClosure
|
13
|
+
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
12
14
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
13
15
|
from classiq.model_expansions.scope import Scope
|
16
|
+
from classiq.qmod.quantum_function import GenerativeQFunc
|
14
17
|
|
15
18
|
|
16
19
|
class RepeatEmitter(Emitter[Repeat]):
|
@@ -18,16 +21,32 @@ class RepeatEmitter(Emitter[Repeat]):
|
|
18
21
|
count = self._interpreter.evaluate(repeat.count).as_type(int)
|
19
22
|
for i in range(count):
|
20
23
|
with self._propagated_var_stack.capture_variables(repeat):
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
self._emit_propagated(repeat, i)
|
25
|
+
|
26
|
+
def _emit_propagated(self, repeat: Repeat, i: int) -> None:
|
27
|
+
closure_constructor: Type[FunctionClosure]
|
28
|
+
extra_args: dict
|
29
|
+
if repeat.is_generative():
|
30
|
+
closure_constructor = GenerativeFunctionClosure
|
31
|
+
extra_args = {
|
32
|
+
"generative_blocks": {
|
33
|
+
"body": GenerativeQFunc(
|
34
|
+
repeat.get_generative_block("body"),
|
35
|
+
),
|
36
|
+
}
|
37
|
+
}
|
38
|
+
else:
|
39
|
+
closure_constructor = FunctionClosure
|
40
|
+
extra_args = {}
|
41
|
+
iteration_function = closure_constructor.create(
|
42
|
+
name=REPEAT_OPERATOR_NAME,
|
43
|
+
positional_arg_declarations=[
|
44
|
+
ClassicalParameterDeclaration(
|
45
|
+
name=repeat.iter_var, classical_type=Integer()
|
33
46
|
)
|
47
|
+
],
|
48
|
+
body=repeat.body,
|
49
|
+
scope=Scope(parent=self._current_scope),
|
50
|
+
**extra_args,
|
51
|
+
)
|
52
|
+
self._emit_quantum_function_call(iteration_function, [Expression(expr=str(i))])
|
@@ -11,6 +11,21 @@ from classiq.model_expansions.scope import Scope
|
|
11
11
|
|
12
12
|
class WithinApplyEmitter(Emitter[WithinApply]):
|
13
13
|
def emit(self, within_apply: WithinApply, /) -> None:
|
14
|
+
with self._propagated_var_stack.capture_variables(within_apply):
|
15
|
+
self._emit_propagated(within_apply)
|
16
|
+
|
17
|
+
def _emit_propagated(self, within_apply: WithinApply) -> None:
|
18
|
+
if within_apply.is_generative():
|
19
|
+
within_apply_context = self._register_generative_context(
|
20
|
+
within_apply, WITHIN_APPLY_NAME, ["within", "apply"]
|
21
|
+
)
|
22
|
+
within_apply = within_apply.copy(
|
23
|
+
update={
|
24
|
+
"compute": within_apply_context.statements("within"),
|
25
|
+
"action": within_apply_context.statements("apply"),
|
26
|
+
}
|
27
|
+
)
|
28
|
+
|
14
29
|
if self._should_wrap(within_apply.compute):
|
15
30
|
self._emit_wrapped(within_apply)
|
16
31
|
return
|
@@ -23,8 +38,7 @@ class WithinApplyEmitter(Emitter[WithinApply]):
|
|
23
38
|
blocks=dict(within=within_apply.compute, apply=within_apply.action),
|
24
39
|
scope=Scope(parent=self._current_scope),
|
25
40
|
)
|
26
|
-
|
27
|
-
context = self._expand_operation(within_apply_operation)
|
41
|
+
context = self._expand_operation(within_apply_operation)
|
28
42
|
self._builder.emit_statement(
|
29
43
|
WithinApply(
|
30
44
|
compute=context.statements("within"),
|
@@ -34,10 +48,9 @@ class WithinApplyEmitter(Emitter[WithinApply]):
|
|
34
48
|
)
|
35
49
|
|
36
50
|
def _emit_wrapped(self, within_apply: WithinApply) -> None:
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
)
|
51
|
+
wrapped_compute = self._create_expanded_wrapping_function(
|
52
|
+
COMPUTE_OPERATOR_NAME, within_apply.compute
|
53
|
+
)
|
41
54
|
wrapped_within_apply = WithinApply(
|
42
55
|
compute=[wrapped_compute],
|
43
56
|
action=within_apply.action,
|