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,535 +0,0 @@
|
|
1
|
-
from typing import TYPE_CHECKING, Optional, Union
|
2
|
-
|
3
|
-
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
4
|
-
from classiq.interface.generator.expressions.expression import Expression
|
5
|
-
from classiq.interface.generator.functions.port_declaration import (
|
6
|
-
PortDeclarationDirection,
|
7
|
-
)
|
8
|
-
from classiq.interface.model.bind_operation import BindOperation
|
9
|
-
from classiq.interface.model.control import Control
|
10
|
-
from classiq.interface.model.handle_binding import HandleBinding, SubscriptHandleBinding
|
11
|
-
from classiq.interface.model.inplace_binary_operation import (
|
12
|
-
BinaryOperation,
|
13
|
-
InplaceBinaryOperation,
|
14
|
-
)
|
15
|
-
from classiq.interface.model.port_declaration import PortDeclaration
|
16
|
-
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
17
|
-
from classiq.interface.model.quantum_function_declaration import (
|
18
|
-
NamedParamsQuantumFunctionDeclaration,
|
19
|
-
)
|
20
|
-
from classiq.interface.model.quantum_statement import QuantumStatement
|
21
|
-
from classiq.interface.model.quantum_type import QuantumBitvector, QuantumNumeric
|
22
|
-
from classiq.interface.model.repeat import Repeat
|
23
|
-
from classiq.interface.model.variable_declaration_statement import (
|
24
|
-
VariableDeclarationStatement,
|
25
|
-
)
|
26
|
-
from classiq.interface.model.within_apply_operation import WithinApply
|
27
|
-
|
28
|
-
from classiq.model_expansions.closure import FunctionClosure
|
29
|
-
from classiq.model_expansions.evaluators.parameter_types import (
|
30
|
-
evaluate_types_in_quantum_symbols,
|
31
|
-
)
|
32
|
-
from classiq.model_expansions.evaluators.quantum_type_utils import (
|
33
|
-
validate_inplace_binary_op_vars,
|
34
|
-
)
|
35
|
-
from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
|
36
|
-
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
37
|
-
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
38
|
-
from classiq.qmod.builtins.functions import (
|
39
|
-
CX,
|
40
|
-
X,
|
41
|
-
allocate,
|
42
|
-
integer_xor,
|
43
|
-
modular_add,
|
44
|
-
modular_add_constant,
|
45
|
-
real_xor_constant,
|
46
|
-
)
|
47
|
-
|
48
|
-
|
49
|
-
def _binary_function_declaration(
|
50
|
-
op: BinaryOperation, constant: bool
|
51
|
-
) -> NamedParamsQuantumFunctionDeclaration:
|
52
|
-
return {
|
53
|
-
False: {
|
54
|
-
BinaryOperation.Addition: modular_add.func_decl,
|
55
|
-
BinaryOperation.Xor: integer_xor.func_decl,
|
56
|
-
},
|
57
|
-
True: {
|
58
|
-
BinaryOperation.Addition: modular_add_constant.func_decl,
|
59
|
-
BinaryOperation.Xor: real_xor_constant.func_decl,
|
60
|
-
},
|
61
|
-
}[constant][op]
|
62
|
-
|
63
|
-
|
64
|
-
class InplaceBinaryOperationEmitter(CallEmitter[InplaceBinaryOperation]):
|
65
|
-
def emit(self, op: InplaceBinaryOperation, /) -> None:
|
66
|
-
if isinstance(op.value, Expression):
|
67
|
-
self._emit_constant_operation(op)
|
68
|
-
return
|
69
|
-
|
70
|
-
value_var = self._interpreter.evaluate(op.value).as_type(QuantumSymbol)
|
71
|
-
target_var = self._interpreter.evaluate(op.target).as_type(QuantumSymbol)
|
72
|
-
value_var, target_var = evaluate_types_in_quantum_symbols(
|
73
|
-
[value_var, target_var], self._current_scope
|
74
|
-
)
|
75
|
-
validate_inplace_binary_op_vars(value_var, target_var, op.operation.value)
|
76
|
-
if TYPE_CHECKING:
|
77
|
-
assert isinstance(value_var.quantum_type, QuantumNumeric)
|
78
|
-
assert isinstance(target_var.quantum_type, QuantumNumeric)
|
79
|
-
|
80
|
-
frac_digits_diff = (
|
81
|
-
value_var.quantum_type.fraction_digits_value
|
82
|
-
- target_var.quantum_type.fraction_digits_value
|
83
|
-
)
|
84
|
-
if (
|
85
|
-
frac_digits_diff == value_var.quantum_type.size_in_bits
|
86
|
-
or -frac_digits_diff == target_var.quantum_type.size_in_bits
|
87
|
-
):
|
88
|
-
return
|
89
|
-
|
90
|
-
value_var = QuantumSymbol(
|
91
|
-
handle=HandleBinding(name="value"), quantum_type=value_var.quantum_type
|
92
|
-
)
|
93
|
-
target_var = QuantumSymbol(
|
94
|
-
handle=HandleBinding(name="target"),
|
95
|
-
quantum_type=target_var.quantum_type,
|
96
|
-
)
|
97
|
-
internal_func_decl = _binary_function_declaration(op.operation, constant=False)
|
98
|
-
if op.operation == BinaryOperation.Xor:
|
99
|
-
body = _build_inplace_xor_operation(
|
100
|
-
value_var=value_var,
|
101
|
-
target_var=target_var,
|
102
|
-
name_allocator=self._interpreter._counted_name_allocator,
|
103
|
-
)
|
104
|
-
else:
|
105
|
-
body = _build_inplace_binary_operation(
|
106
|
-
value_var=value_var,
|
107
|
-
target_var=target_var,
|
108
|
-
internal_function_declaration=internal_func_decl,
|
109
|
-
)
|
110
|
-
inplace_binary_op_function = FunctionClosure.create(
|
111
|
-
name=op.operation.value,
|
112
|
-
positional_arg_declarations=[
|
113
|
-
PortDeclaration(
|
114
|
-
name=value_var.handle.name,
|
115
|
-
quantum_type=value_var.quantum_type,
|
116
|
-
direction=PortDeclarationDirection.Inout,
|
117
|
-
),
|
118
|
-
PortDeclaration(
|
119
|
-
name=target_var.handle.name,
|
120
|
-
quantum_type=target_var.quantum_type,
|
121
|
-
direction=PortDeclarationDirection.Inout,
|
122
|
-
),
|
123
|
-
],
|
124
|
-
body=body,
|
125
|
-
scope=Scope(parent=self._current_scope),
|
126
|
-
)
|
127
|
-
self._emit_quantum_function_call(
|
128
|
-
inplace_binary_op_function, [op.value, op.target]
|
129
|
-
)
|
130
|
-
|
131
|
-
def _emit_constant_operation(self, op: InplaceBinaryOperation) -> None:
|
132
|
-
if TYPE_CHECKING:
|
133
|
-
assert isinstance(op.value, Expression)
|
134
|
-
self._interpreter.emit(
|
135
|
-
_internal_inplace_binary_operation_function_call(
|
136
|
-
_binary_function_declaration(op.operation, constant=True),
|
137
|
-
op.value,
|
138
|
-
op.target,
|
139
|
-
)
|
140
|
-
)
|
141
|
-
|
142
|
-
|
143
|
-
def _build_inplace_binary_operation(
|
144
|
-
value_var: QuantumSymbol,
|
145
|
-
target_var: QuantumSymbol,
|
146
|
-
internal_function_declaration: NamedParamsQuantumFunctionDeclaration,
|
147
|
-
) -> list[QuantumStatement]:
|
148
|
-
if TYPE_CHECKING:
|
149
|
-
assert isinstance(value_var.quantum_type, QuantumNumeric)
|
150
|
-
assert isinstance(target_var.quantum_type, QuantumNumeric)
|
151
|
-
|
152
|
-
frac_digits_diff = (
|
153
|
-
value_var.quantum_type.fraction_digits_value
|
154
|
-
- target_var.quantum_type.fraction_digits_value
|
155
|
-
)
|
156
|
-
|
157
|
-
target_overlap_var, target_var_decls, target_bind_ops = (
|
158
|
-
_trim_superfluous_fraction_digits("target", target_var, -frac_digits_diff)
|
159
|
-
)
|
160
|
-
value_overlap_var, value_trim_var_decls, value_bind_ops = (
|
161
|
-
_trim_superfluous_fraction_digits("value", value_var, frac_digits_diff)
|
162
|
-
)
|
163
|
-
size_diff = (
|
164
|
-
value_overlap_var.quantum_type.size_in_bits
|
165
|
-
- target_overlap_var.quantum_type.size_in_bits
|
166
|
-
)
|
167
|
-
(
|
168
|
-
value_padded_var,
|
169
|
-
value_pad_var_decls,
|
170
|
-
value_pad_pre_bind_ops,
|
171
|
-
value_pad_init_ops,
|
172
|
-
value_post_bind_ops,
|
173
|
-
) = _pad_with_sign_bit("value", value_overlap_var, size_diff)
|
174
|
-
|
175
|
-
op_call = _internal_inplace_binary_operation_function_call(
|
176
|
-
internal_function_declaration,
|
177
|
-
value_padded_var.handle,
|
178
|
-
target_overlap_var.handle,
|
179
|
-
)
|
180
|
-
|
181
|
-
return [
|
182
|
-
*target_var_decls,
|
183
|
-
*value_trim_var_decls,
|
184
|
-
*value_pad_var_decls,
|
185
|
-
WithinApply(
|
186
|
-
compute=[
|
187
|
-
*target_bind_ops,
|
188
|
-
*value_bind_ops,
|
189
|
-
*value_pad_pre_bind_ops,
|
190
|
-
*value_pad_init_ops,
|
191
|
-
*value_post_bind_ops,
|
192
|
-
],
|
193
|
-
action=[
|
194
|
-
op_call,
|
195
|
-
],
|
196
|
-
),
|
197
|
-
]
|
198
|
-
|
199
|
-
|
200
|
-
def _build_inplace_xor_operation(
|
201
|
-
value_var: QuantumSymbol,
|
202
|
-
target_var: QuantumSymbol,
|
203
|
-
name_allocator: CountedNameAllocator,
|
204
|
-
) -> list[QuantumStatement]:
|
205
|
-
if TYPE_CHECKING:
|
206
|
-
assert isinstance(value_var.quantum_type, QuantumNumeric)
|
207
|
-
assert isinstance(target_var.quantum_type, QuantumNumeric)
|
208
|
-
|
209
|
-
frac_digits_diff = (
|
210
|
-
value_var.quantum_type.fraction_digits_value
|
211
|
-
- target_var.quantum_type.fraction_digits_value
|
212
|
-
)
|
213
|
-
|
214
|
-
target_overlap_var, target_var_decls, target_bind_ops = (
|
215
|
-
_trim_superfluous_fraction_digits("target", target_var, -frac_digits_diff)
|
216
|
-
)
|
217
|
-
value_overlap_var, value_trim_var_decls, value_bind_ops = (
|
218
|
-
_trim_superfluous_fraction_digits("value", value_var, frac_digits_diff)
|
219
|
-
)
|
220
|
-
target_left_var, value_left_var, sign_var_decls, sign_bind_ops, sign_xor = (
|
221
|
-
_split_and_xor_sign(target_overlap_var, value_overlap_var, name_allocator)
|
222
|
-
)
|
223
|
-
|
224
|
-
action: list[QuantumStatement] = []
|
225
|
-
if target_left_var is not None and value_left_var is not None:
|
226
|
-
action.append(
|
227
|
-
_internal_inplace_binary_operation_function_call(
|
228
|
-
integer_xor.func_decl,
|
229
|
-
value_left_var.handle,
|
230
|
-
target_left_var.handle,
|
231
|
-
)
|
232
|
-
)
|
233
|
-
action.extend(sign_xor)
|
234
|
-
|
235
|
-
return [
|
236
|
-
*target_var_decls,
|
237
|
-
*value_trim_var_decls,
|
238
|
-
*sign_var_decls,
|
239
|
-
WithinApply(
|
240
|
-
compute=[
|
241
|
-
*target_bind_ops,
|
242
|
-
*value_bind_ops,
|
243
|
-
*sign_bind_ops,
|
244
|
-
],
|
245
|
-
action=action,
|
246
|
-
),
|
247
|
-
]
|
248
|
-
|
249
|
-
|
250
|
-
def _internal_inplace_binary_operation_function_call(
|
251
|
-
internal_function_declaration: NamedParamsQuantumFunctionDeclaration,
|
252
|
-
value: Union[HandleBinding, Expression],
|
253
|
-
target_var: HandleBinding,
|
254
|
-
) -> QuantumFunctionCall:
|
255
|
-
internal_function_call = QuantumFunctionCall(
|
256
|
-
function=internal_function_declaration.name,
|
257
|
-
positional_args=[value, target_var],
|
258
|
-
)
|
259
|
-
internal_function_call.set_func_decl(internal_function_declaration)
|
260
|
-
return internal_function_call
|
261
|
-
|
262
|
-
|
263
|
-
def _trim_superfluous_fraction_digits(
|
264
|
-
kind: str, var: QuantumSymbol, frac_digits_diff: int
|
265
|
-
) -> tuple[QuantumSymbol, list[VariableDeclarationStatement], list[BindOperation]]:
|
266
|
-
if frac_digits_diff <= 0:
|
267
|
-
return var, [], []
|
268
|
-
|
269
|
-
quantum_type = var.quantum_type
|
270
|
-
if TYPE_CHECKING:
|
271
|
-
assert isinstance(quantum_type, QuantumNumeric)
|
272
|
-
|
273
|
-
trimmed_fraction_digits_var = QuantumSymbol(
|
274
|
-
handle=HandleBinding(name=f"trimmed_{kind}_fraction_digits"),
|
275
|
-
quantum_type=QuantumBitvector(
|
276
|
-
length=Expression(expr=str(frac_digits_diff)),
|
277
|
-
),
|
278
|
-
)
|
279
|
-
overlap_var = QuantumSymbol(
|
280
|
-
handle=HandleBinding(name=f"{kind}_overlap"),
|
281
|
-
quantum_type=QuantumNumeric(
|
282
|
-
size=Expression(expr=str(quantum_type.size_in_bits - frac_digits_diff)),
|
283
|
-
is_signed=quantum_type.is_signed,
|
284
|
-
fraction_digits=Expression(expr="0"),
|
285
|
-
),
|
286
|
-
)
|
287
|
-
bind_targets = trimmed_fraction_digits_var, overlap_var
|
288
|
-
|
289
|
-
split_var_declarations = [
|
290
|
-
VariableDeclarationStatement(
|
291
|
-
name=var.handle.name,
|
292
|
-
quantum_type=var.quantum_type,
|
293
|
-
)
|
294
|
-
for var in bind_targets
|
295
|
-
]
|
296
|
-
bind_op = BindOperation(
|
297
|
-
in_handles=[var.handle],
|
298
|
-
out_handles=[var.handle for var in bind_targets],
|
299
|
-
)
|
300
|
-
|
301
|
-
return overlap_var, split_var_declarations, [bind_op]
|
302
|
-
|
303
|
-
|
304
|
-
def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> tuple[
|
305
|
-
QuantumSymbol,
|
306
|
-
list[VariableDeclarationStatement],
|
307
|
-
list[QuantumStatement],
|
308
|
-
list[QuantumFunctionCall],
|
309
|
-
list[BindOperation],
|
310
|
-
]:
|
311
|
-
quantum_type = var.quantum_type
|
312
|
-
if TYPE_CHECKING:
|
313
|
-
assert isinstance(quantum_type, QuantumNumeric)
|
314
|
-
|
315
|
-
if not quantum_type.sign_value or size_diff >= 0:
|
316
|
-
return var, [], [], [], []
|
317
|
-
|
318
|
-
padding_var, padding_allocation = _allocate_padding(kind, size_diff)
|
319
|
-
padded_var = QuantumSymbol(
|
320
|
-
handle=HandleBinding(name=f"padded_{kind}"),
|
321
|
-
quantum_type=QuantumNumeric(
|
322
|
-
size=Expression(expr=str(quantum_type.size_in_bits - size_diff)),
|
323
|
-
is_signed=Expression(expr="False"),
|
324
|
-
fraction_digits=Expression(expr="0"),
|
325
|
-
),
|
326
|
-
)
|
327
|
-
var_decls = [
|
328
|
-
VariableDeclarationStatement(
|
329
|
-
name=var.handle.name,
|
330
|
-
quantum_type=var.quantum_type,
|
331
|
-
)
|
332
|
-
for var in (padding_var, padded_var)
|
333
|
-
]
|
334
|
-
|
335
|
-
if quantum_type.size_in_bits == 1: # qnum<1, SIGNED, ?>
|
336
|
-
padding_init_ops = _init_padding(var, padding_var, size_diff)
|
337
|
-
padding_rebind = BindOperation(
|
338
|
-
in_handles=[var.handle, padding_var.handle],
|
339
|
-
out_handles=[padded_var.handle],
|
340
|
-
)
|
341
|
-
return (
|
342
|
-
padded_var,
|
343
|
-
var_decls,
|
344
|
-
[padding_allocation],
|
345
|
-
padding_init_ops,
|
346
|
-
[padding_rebind],
|
347
|
-
)
|
348
|
-
|
349
|
-
significand_var, sign_var, sign_split_bind = _split_var(kind, var, 1)
|
350
|
-
padding_init_ops = _init_padding(sign_var, padding_var, size_diff)
|
351
|
-
|
352
|
-
padding_rebind = BindOperation(
|
353
|
-
in_handles=[significand_var.handle, sign_var.handle, padding_var.handle],
|
354
|
-
out_handles=[padded_var.handle],
|
355
|
-
)
|
356
|
-
|
357
|
-
var_decls += [
|
358
|
-
VariableDeclarationStatement(
|
359
|
-
name=var.handle.name,
|
360
|
-
quantum_type=var.quantum_type,
|
361
|
-
)
|
362
|
-
for var in (significand_var, sign_var)
|
363
|
-
]
|
364
|
-
|
365
|
-
return (
|
366
|
-
padded_var,
|
367
|
-
var_decls,
|
368
|
-
[sign_split_bind, padding_allocation],
|
369
|
-
padding_init_ops,
|
370
|
-
[padding_rebind],
|
371
|
-
)
|
372
|
-
|
373
|
-
|
374
|
-
def _init_padding(
|
375
|
-
sign_var: QuantumSymbol, padding_var: QuantumSymbol, size_diff: int
|
376
|
-
) -> list[QuantumFunctionCall]:
|
377
|
-
padding_init_ops = [
|
378
|
-
QuantumFunctionCall(
|
379
|
-
function=CX.func_decl.name,
|
380
|
-
positional_args=[sign_var.handle, padding_var[idx].handle],
|
381
|
-
)
|
382
|
-
for idx in range(-size_diff)
|
383
|
-
]
|
384
|
-
for cx_call in padding_init_ops:
|
385
|
-
cx_call.set_func_decl(CX.func_decl)
|
386
|
-
return padding_init_ops
|
387
|
-
|
388
|
-
|
389
|
-
def _allocate_padding(
|
390
|
-
kind: str, size_diff: int
|
391
|
-
) -> tuple[QuantumSymbol, QuantumFunctionCall]:
|
392
|
-
padding_var = QuantumSymbol(
|
393
|
-
handle=HandleBinding(name=f"{kind}_sign_padding"),
|
394
|
-
quantum_type=QuantumBitvector(
|
395
|
-
length=Expression(expr=str(-size_diff)),
|
396
|
-
),
|
397
|
-
)
|
398
|
-
padding_allocation = QuantumFunctionCall(
|
399
|
-
function=allocate.func_decl.name,
|
400
|
-
positional_args=[Expression(expr=str(-size_diff)), padding_var.handle],
|
401
|
-
)
|
402
|
-
padding_allocation.set_func_decl(allocate.func_decl)
|
403
|
-
return padding_var, padding_allocation
|
404
|
-
|
405
|
-
|
406
|
-
def _split_var(
|
407
|
-
kind: str, var: QuantumSymbol, right_size: int
|
408
|
-
) -> tuple[QuantumSymbol, QuantumSymbol, BindOperation]:
|
409
|
-
left_var = QuantumSymbol(
|
410
|
-
handle=HandleBinding(name=f"{kind}_left"),
|
411
|
-
quantum_type=QuantumNumeric(
|
412
|
-
size=Expression(expr=str(var.quantum_type.size_in_bits - right_size)),
|
413
|
-
is_signed=Expression(expr="False"),
|
414
|
-
fraction_digits=Expression(expr="0"),
|
415
|
-
),
|
416
|
-
)
|
417
|
-
right_var = QuantumSymbol(
|
418
|
-
handle=HandleBinding(name=f"{kind}_right"),
|
419
|
-
quantum_type=QuantumNumeric(
|
420
|
-
size=Expression(expr=str(right_size)),
|
421
|
-
is_signed=Expression(expr="False"),
|
422
|
-
fraction_digits=Expression(expr="0"),
|
423
|
-
),
|
424
|
-
)
|
425
|
-
split_bind = BindOperation(
|
426
|
-
in_handles=[var.handle],
|
427
|
-
out_handles=[left_var.handle, right_var.handle],
|
428
|
-
)
|
429
|
-
return left_var, right_var, split_bind
|
430
|
-
|
431
|
-
|
432
|
-
def _split_and_xor_sign(
|
433
|
-
target_var: QuantumSymbol,
|
434
|
-
value_var: QuantumSymbol,
|
435
|
-
name_allocator: CountedNameAllocator,
|
436
|
-
) -> tuple[
|
437
|
-
Optional[QuantumSymbol],
|
438
|
-
Optional[QuantumSymbol],
|
439
|
-
list[VariableDeclarationStatement],
|
440
|
-
list[BindOperation],
|
441
|
-
list[Control],
|
442
|
-
]:
|
443
|
-
if TYPE_CHECKING:
|
444
|
-
assert isinstance(value_var.quantum_type, QuantumNumeric)
|
445
|
-
assert isinstance(target_var.quantum_type, QuantumNumeric)
|
446
|
-
size_diff = (
|
447
|
-
value_var.quantum_type.size_in_bits - target_var.quantum_type.size_in_bits
|
448
|
-
)
|
449
|
-
if not value_var.quantum_type.sign_value or size_diff >= 0:
|
450
|
-
return target_var, value_var, [], [], []
|
451
|
-
|
452
|
-
if value_var.quantum_type.size_in_bits == 1:
|
453
|
-
return None, None, [], [], [_xor_sign(target_var, value_var, name_allocator)]
|
454
|
-
|
455
|
-
value_rest_var, value_sign_var, value_split_bind = _split_var("value", value_var, 1)
|
456
|
-
target_left_var, target_right_var, target_split_bind = _split_var(
|
457
|
-
"target", target_var, -size_diff + 1
|
458
|
-
)
|
459
|
-
var_decls = [
|
460
|
-
VariableDeclarationStatement(
|
461
|
-
name=var.handle.name,
|
462
|
-
quantum_type=var.quantum_type,
|
463
|
-
)
|
464
|
-
for var in (value_rest_var, value_sign_var, target_left_var, target_right_var)
|
465
|
-
]
|
466
|
-
bind_ops = [value_split_bind, target_split_bind]
|
467
|
-
sign_xor = _xor_sign(target_right_var, value_sign_var, name_allocator)
|
468
|
-
return target_left_var, value_rest_var, var_decls, bind_ops, [sign_xor]
|
469
|
-
|
470
|
-
|
471
|
-
def _xor_sign(
|
472
|
-
target_var: QuantumSymbol,
|
473
|
-
value_var: QuantumSymbol,
|
474
|
-
name_allocator: CountedNameAllocator,
|
475
|
-
) -> Control:
|
476
|
-
quantum_type = value_var.quantum_type
|
477
|
-
if TYPE_CHECKING:
|
478
|
-
assert isinstance(quantum_type, QuantumNumeric)
|
479
|
-
if quantum_type.size_in_bits != 1 or quantum_type.fraction_digits_value not in (
|
480
|
-
0,
|
481
|
-
1,
|
482
|
-
):
|
483
|
-
raise ClassiqInternalExpansionError
|
484
|
-
|
485
|
-
aux_var = name_allocator.allocate("inplace_xor_aux")
|
486
|
-
iteration_var = name_allocator.allocate("i")
|
487
|
-
inner_x_call = QuantumFunctionCall(
|
488
|
-
function=X.func_decl.name,
|
489
|
-
positional_args=[
|
490
|
-
SubscriptHandleBinding(
|
491
|
-
base_handle=HandleBinding(name=aux_var),
|
492
|
-
index=Expression(expr=iteration_var),
|
493
|
-
)
|
494
|
-
],
|
495
|
-
)
|
496
|
-
inner_x_call.set_func_decl(X.func_decl)
|
497
|
-
inner_xor = WithinApply(
|
498
|
-
compute=[
|
499
|
-
BindOperation(
|
500
|
-
in_handles=[target_var.handle],
|
501
|
-
out_handles=[HandleBinding(name=aux_var)],
|
502
|
-
),
|
503
|
-
],
|
504
|
-
action=[
|
505
|
-
Repeat(
|
506
|
-
iter_var=iteration_var,
|
507
|
-
count=Expression(expr=f"{target_var.quantum_type.size_in_bits}"),
|
508
|
-
body=[inner_x_call],
|
509
|
-
)
|
510
|
-
],
|
511
|
-
)
|
512
|
-
|
513
|
-
if quantum_type.sign_value:
|
514
|
-
if quantum_type.fraction_digits_value == 1:
|
515
|
-
ctrl_value = -0.5
|
516
|
-
else:
|
517
|
-
ctrl_value = -1
|
518
|
-
else:
|
519
|
-
if quantum_type.fraction_digits_value == 1:
|
520
|
-
ctrl_value = 0.5
|
521
|
-
else:
|
522
|
-
ctrl_value = 1
|
523
|
-
|
524
|
-
return Control(
|
525
|
-
expression=Expression(expr=f"{value_var.handle} == {ctrl_value}"),
|
526
|
-
body=[
|
527
|
-
VariableDeclarationStatement(
|
528
|
-
name=aux_var,
|
529
|
-
quantum_type=QuantumBitvector(
|
530
|
-
length=Expression(expr=f"{target_var.quantum_type.size_in_bits}")
|
531
|
-
),
|
532
|
-
),
|
533
|
-
inner_xor,
|
534
|
-
],
|
535
|
-
)
|
@@ -1,36 +0,0 @@
|
|
1
|
-
from classiq.interface.generator.functions.builtins.internal_operators import (
|
2
|
-
INVERT_OPERATOR_NAME,
|
3
|
-
)
|
4
|
-
from classiq.interface.model.invert import Invert
|
5
|
-
|
6
|
-
from classiq.model_expansions.closure import Closure
|
7
|
-
from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
|
8
|
-
from classiq.model_expansions.scope import Scope
|
9
|
-
|
10
|
-
|
11
|
-
class InvertEmitter(CallEmitter[Invert]):
|
12
|
-
def emit(self, invert: Invert, /) -> None:
|
13
|
-
if self._should_wrap(invert.body):
|
14
|
-
self._emit_wrapped(invert)
|
15
|
-
return
|
16
|
-
|
17
|
-
self._emit_as_operation(invert)
|
18
|
-
|
19
|
-
def _emit_as_operation(self, invert: Invert) -> None:
|
20
|
-
invert_operation = Closure(
|
21
|
-
name=INVERT_OPERATOR_NAME,
|
22
|
-
blocks={"body": invert.body},
|
23
|
-
scope=Scope(parent=self._current_scope),
|
24
|
-
)
|
25
|
-
context = self._expand_operation(invert_operation)
|
26
|
-
self.emit_statement(
|
27
|
-
Invert(body=context.statements("body"), source_ref=invert.source_ref)
|
28
|
-
)
|
29
|
-
|
30
|
-
def _emit_wrapped(self, invert: Invert) -> None:
|
31
|
-
wrapping_function = self._create_expanded_wrapping_function(
|
32
|
-
INVERT_OPERATOR_NAME, invert.body
|
33
|
-
)
|
34
|
-
self.emit_statement(
|
35
|
-
Invert(body=[wrapping_function], source_ref=invert.source_ref)
|
36
|
-
)
|