classiq 0.46.1__py3-none-any.whl → 0.48.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/_internals/api_wrapper.py +45 -8
- 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 +133 -45
- classiq/execution/jobs.py +120 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +0 -1
- classiq/interface/debug_info/debug_info.py +23 -1
- classiq/interface/execution/primitives.py +17 -0
- classiq/interface/executor/iqae_result.py +3 -3
- classiq/interface/executor/result.py +3 -1
- classiq/interface/generator/arith/arithmetic_operations.py +5 -2
- classiq/interface/generator/arith/binary_ops.py +21 -14
- classiq/interface/generator/arith/extremum_operations.py +9 -1
- classiq/interface/generator/arith/number_utils.py +6 -0
- classiq/interface/generator/arith/register_user_input.py +30 -21
- classiq/interface/generator/arith/unary_ops.py +13 -1
- classiq/interface/generator/expressions/expression.py +8 -0
- classiq/interface/generator/functions/type_name.py +1 -3
- classiq/interface/generator/generated_circuit_data.py +47 -2
- classiq/interface/generator/quantum_program.py +10 -2
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +17 -3
- classiq/interface/ide/visual_model.py +10 -5
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/bind_operation.py +0 -3
- classiq/interface/model/phase_operation.py +11 -0
- classiq/interface/model/port_declaration.py +1 -12
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +34 -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/model/statement_block.py +3 -0
- classiq/interface/server/global_versions.py +4 -4
- classiq/interface/server/routes.py +0 -3
- 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 +17 -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 +68 -7
- classiq/model_expansions/quantum_operations/expression_operation.py +25 -16
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +167 -95
- classiq/model_expansions/quantum_operations/invert.py +12 -6
- classiq/model_expansions/quantum_operations/phase.py +189 -0
- 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 +55 -161
- classiq/qmod/create_model_function.py +1 -1
- classiq/qmod/generative.py +14 -5
- classiq/qmod/native/pretty_printer.py +14 -4
- classiq/qmod/pretty_print/pretty_printer.py +14 -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.46.1.dist-info → classiq-0.48.0.dist-info}/METADATA +9 -4
- {classiq-0.46.1.dist-info → classiq-0.48.0.dist-info}/RECORD +71 -66
- {classiq-0.46.1.dist-info → classiq-0.48.0.dist-info}/WHEEL +0 -0
@@ -1,5 +1,15 @@
|
|
1
1
|
from abc import abstractmethod
|
2
|
-
from typing import
|
2
|
+
from typing import (
|
3
|
+
TYPE_CHECKING,
|
4
|
+
Dict,
|
5
|
+
Generic,
|
6
|
+
List,
|
7
|
+
Optional,
|
8
|
+
Sequence,
|
9
|
+
TypeVar,
|
10
|
+
Union,
|
11
|
+
cast,
|
12
|
+
)
|
3
13
|
|
4
14
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
5
15
|
from classiq.interface.ide.visual_model import OperationLevel
|
@@ -14,7 +24,7 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
14
24
|
NamedParamsQuantumFunctionDeclaration,
|
15
25
|
PositionalArg,
|
16
26
|
)
|
17
|
-
from classiq.interface.model.quantum_statement import QuantumStatement
|
27
|
+
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
18
28
|
from classiq.interface.model.variable_declaration_statement import (
|
19
29
|
VariableDeclarationStatement,
|
20
30
|
)
|
@@ -23,7 +33,7 @@ from classiq.model_expansions.capturing.propagated_var_stack import (
|
|
23
33
|
PropagatedVarStack,
|
24
34
|
validate_args_are_not_propagated,
|
25
35
|
)
|
26
|
-
from classiq.model_expansions.closure import FunctionClosure
|
36
|
+
from classiq.model_expansions.closure import Closure, FunctionClosure, GenerativeClosure
|
27
37
|
from classiq.model_expansions.evaluators.argument_types import (
|
28
38
|
add_information_from_output_arguments,
|
29
39
|
)
|
@@ -33,10 +43,13 @@ from classiq.model_expansions.evaluators.parameter_types import (
|
|
33
43
|
from classiq.model_expansions.function_builder import (
|
34
44
|
FunctionContext,
|
35
45
|
OperationBuilder,
|
46
|
+
OperationContext,
|
36
47
|
)
|
48
|
+
from classiq.model_expansions.generative_functions import emit_operands_as_declarative
|
37
49
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
38
50
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
39
51
|
from classiq.qmod.builtins.functions import allocate, free
|
52
|
+
from classiq.qmod.quantum_function import GenerativeQFunc
|
40
53
|
|
41
54
|
if TYPE_CHECKING:
|
42
55
|
from classiq.model_expansions.interpreter import Interpreter
|
@@ -50,13 +63,24 @@ class Emitter(Generic[QuantumStatementT]):
|
|
50
63
|
self._interpreter = interpreter
|
51
64
|
|
52
65
|
self._scope_guard = self._interpreter._scope_guard
|
53
|
-
self._expand_operation = self._interpreter._expand_operation
|
54
66
|
self._machine_precision = self._interpreter._model.preferences.machine_precision
|
55
67
|
|
68
|
+
self._generative_contexts: Dict[str, OperationContext] = {}
|
69
|
+
|
56
70
|
@abstractmethod
|
57
71
|
def emit(self, statement: QuantumStatementT, /) -> None:
|
58
72
|
pass
|
59
73
|
|
74
|
+
def _expand_operation(self, closure: Closure) -> OperationContext:
|
75
|
+
if closure.name in self._generative_contexts:
|
76
|
+
if isinstance(closure, FunctionClosure):
|
77
|
+
return FunctionContext(
|
78
|
+
closure=closure,
|
79
|
+
blocks=self._generative_contexts[closure.name].blocks,
|
80
|
+
)
|
81
|
+
return self._generative_contexts[closure.name]
|
82
|
+
return self._interpreter._expand_operation(closure)
|
83
|
+
|
60
84
|
@property
|
61
85
|
def _propagated_var_stack(self) -> PropagatedVarStack:
|
62
86
|
return self._interpreter._propagated_var_stack
|
@@ -131,16 +155,22 @@ class Emitter(Generic[QuantumStatementT]):
|
|
131
155
|
or new_call.func_name == free.func_decl.name
|
132
156
|
)
|
133
157
|
parameters = {
|
134
|
-
arg_decl.name: FunctionDebugInfo.param_controller(value=
|
135
|
-
for arg_decl,
|
158
|
+
arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
|
159
|
+
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
136
160
|
if isinstance(arg_decl, ClassicalParameterDeclaration)
|
137
161
|
}
|
138
162
|
|
163
|
+
port_to_passed_variable_map = {
|
164
|
+
arg_decl.name: evaluated_arg.value.handle.name
|
165
|
+
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
166
|
+
if isinstance(arg_decl, PortDeclaration)
|
167
|
+
}
|
139
168
|
self._interpreter._model.debug_info[new_call.uuid] = FunctionDebugInfo(
|
140
169
|
name=new_call.func_name,
|
141
170
|
level=OperationLevel.QMOD_FUNCTION_CALL,
|
142
171
|
parameters=parameters,
|
143
172
|
is_allocate_or_free=is_allocate_or_free,
|
173
|
+
port_to_passed_variable_map=port_to_passed_variable_map,
|
144
174
|
)
|
145
175
|
if is_atomic:
|
146
176
|
new_call.set_func_decl(new_declaration)
|
@@ -175,7 +205,10 @@ class Emitter(Generic[QuantumStatementT]):
|
|
175
205
|
new_positional_arg_decls, evaluated_args
|
176
206
|
)
|
177
207
|
if is_atomic:
|
178
|
-
return [
|
208
|
+
return [
|
209
|
+
emit_operands_as_declarative(self._interpreter, param, arg)
|
210
|
+
for param, arg in zip(new_positional_arg_decls, evaluated_args)
|
211
|
+
]
|
179
212
|
|
180
213
|
positional_args = [
|
181
214
|
arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
|
@@ -213,3 +246,31 @@ class Emitter(Generic[QuantumStatementT]):
|
|
213
246
|
evaluated_args,
|
214
247
|
),
|
215
248
|
)
|
249
|
+
|
250
|
+
def _register_generative_context(
|
251
|
+
self,
|
252
|
+
op: QuantumOperation,
|
253
|
+
context_name: str,
|
254
|
+
block_names: Union[None, str, List[str]] = None,
|
255
|
+
func_decl: Optional[NamedParamsQuantumFunctionDeclaration] = None,
|
256
|
+
) -> OperationContext:
|
257
|
+
if isinstance(block_names, str):
|
258
|
+
block_names = [block_names]
|
259
|
+
block_names = block_names or ["body"]
|
260
|
+
func_decl = func_decl or NamedParamsQuantumFunctionDeclaration(
|
261
|
+
name=context_name
|
262
|
+
)
|
263
|
+
gen_closure = GenerativeClosure(
|
264
|
+
name=func_decl.name,
|
265
|
+
scope=Scope(parent=self._interpreter._current_scope),
|
266
|
+
blocks={},
|
267
|
+
generative_blocks={
|
268
|
+
block_name: GenerativeQFunc(
|
269
|
+
op.get_generative_block(block_name), func_decl
|
270
|
+
)
|
271
|
+
for block_name in block_names
|
272
|
+
},
|
273
|
+
)
|
274
|
+
context = self._interpreter._expand_operation(gen_closure)
|
275
|
+
self._generative_contexts[context_name] = context
|
276
|
+
return context
|
@@ -58,17 +58,20 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
58
58
|
symbols_parts, bind_ops = self._get_bind_ops(symbols_to_split)
|
59
59
|
|
60
60
|
for symbol_parts in symbols_parts:
|
61
|
-
for symbol in symbol_parts:
|
61
|
+
for symbol, symbol_part_var_name in symbol_parts:
|
62
62
|
if symbol.handle.identifier not in self._current_scope:
|
63
63
|
self._interpreter.emit_statement(
|
64
64
|
VariableDeclarationStatement(
|
65
|
-
name=
|
65
|
+
name=symbol_part_var_name,
|
66
66
|
quantum_type=symbol.quantum_type,
|
67
67
|
)
|
68
68
|
)
|
69
69
|
|
70
70
|
new_expression = self._update_op_expression(
|
71
|
-
{
|
71
|
+
{
|
72
|
+
symbol.handle: symbol_part_var_name
|
73
|
+
for symbol, symbol_part_var_name in chain.from_iterable(symbols_parts)
|
74
|
+
},
|
72
75
|
expression,
|
73
76
|
)
|
74
77
|
new_op = op.copy(update=dict(expression=new_expression))
|
@@ -83,7 +86,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
83
86
|
|
84
87
|
def _update_op_expression(
|
85
88
|
self,
|
86
|
-
symbol_parts: Dict[HandleBinding,
|
89
|
+
symbol_parts: Dict[HandleBinding, str],
|
87
90
|
expression: Expression,
|
88
91
|
) -> Expression:
|
89
92
|
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
@@ -94,7 +97,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
94
97
|
collapsed_handle = handle.collapse()
|
95
98
|
if collapsed_handle in symbol_parts:
|
96
99
|
new_expr_str = new_expr_str.replace(
|
97
|
-
str(handle), symbol_parts[collapsed_handle]
|
100
|
+
str(handle), symbol_parts[collapsed_handle]
|
98
101
|
)
|
99
102
|
self._check_all_handles_were_replaced(new_expr_str)
|
100
103
|
|
@@ -115,32 +118,38 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
115
118
|
):
|
116
119
|
raise ClassiqInternalExpansionError(f"Did not replace handle {handle}")
|
117
120
|
|
118
|
-
@staticmethod
|
119
121
|
def _get_bind_ops(
|
122
|
+
self,
|
120
123
|
symbols_to_split: List[QuantumSymbol],
|
121
|
-
) -> Tuple[List[List[QuantumSymbol]], List[BindOperation]]:
|
124
|
+
) -> Tuple[List[List[Tuple[QuantumSymbol, str]]], List[BindOperation]]:
|
122
125
|
bind_ops = []
|
123
126
|
symbols_parts = []
|
124
127
|
for symbol in symbols_to_split:
|
125
|
-
symbol_parts =
|
128
|
+
symbol_parts = self._get_symbol_parts(symbol)
|
126
129
|
symbols_parts.append(symbol_parts)
|
127
130
|
bind_ops.append(
|
128
131
|
BindOperation(
|
129
132
|
in_handles=[symbol.handle],
|
130
133
|
out_handles=[
|
131
|
-
HandleBinding(name=
|
132
|
-
for
|
134
|
+
HandleBinding(name=symbol_part_var_name)
|
135
|
+
for _, symbol_part_var_name in symbol_parts
|
133
136
|
],
|
134
137
|
)
|
135
138
|
)
|
136
139
|
return symbols_parts, bind_ops
|
137
140
|
|
138
|
-
|
139
|
-
|
141
|
+
def _get_symbol_parts(
|
142
|
+
self, symbol: QuantumSymbol
|
143
|
+
) -> List[Tuple[QuantumSymbol, str]]:
|
140
144
|
quantum_type = symbol.quantum_type
|
141
145
|
|
142
146
|
if isinstance(quantum_type, (QuantumBit, QuantumNumeric)):
|
143
|
-
return [
|
147
|
+
return [
|
148
|
+
(
|
149
|
+
symbol,
|
150
|
+
self._counted_name_allocator.allocate(symbol.handle.identifier),
|
151
|
+
)
|
152
|
+
]
|
144
153
|
|
145
154
|
if isinstance(quantum_type, QuantumBitvector):
|
146
155
|
if not quantum_type.has_length:
|
@@ -150,7 +159,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
150
159
|
)
|
151
160
|
return list(
|
152
161
|
chain.from_iterable(
|
153
|
-
|
162
|
+
self._get_symbol_parts(symbol[idx])
|
154
163
|
for idx in range(quantum_type.length_value)
|
155
164
|
)
|
156
165
|
)
|
@@ -160,7 +169,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
160
169
|
|
161
170
|
return list(
|
162
171
|
chain.from_iterable(
|
163
|
-
|
172
|
+
self._get_symbol_parts(field_symbol)
|
164
173
|
for field_symbol in symbol.fields.values()
|
165
174
|
)
|
166
175
|
)
|
@@ -204,7 +213,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
204
213
|
op_with_evaluated_types = op.copy(update={"expression": expression})
|
205
214
|
vrc = VarRefCollector()
|
206
215
|
vrc.visit(ast.parse(op_with_evaluated_types.expression.expr))
|
207
|
-
handles =
|
216
|
+
handles = vrc.var_handles
|
208
217
|
op_with_evaluated_types.set_var_handles(handles)
|
209
218
|
op_with_evaluated_types.initialize_var_types(
|
210
219
|
{
|
@@ -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,60 @@ 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
|
+
],
|
156
|
+
action=[
|
157
|
+
*value_pad_init_ops,
|
158
|
+
WithinApply(
|
159
|
+
compute=[
|
160
|
+
*value_post_bind_ops,
|
161
|
+
],
|
162
|
+
action=[op_call],
|
163
|
+
),
|
164
|
+
],
|
165
|
+
),
|
163
166
|
]
|
164
167
|
|
165
168
|
|
@@ -176,75 +179,144 @@ def _internal_inplace_binary_operation_function_call(
|
|
176
179
|
return internal_function_call
|
177
180
|
|
178
181
|
|
179
|
-
def
|
182
|
+
def _trim_superfluous_fraction_digits(
|
180
183
|
kind: str, var: QuantumSymbol, frac_digits_diff: int
|
181
|
-
) -> Tuple[
|
184
|
+
) -> Tuple[QuantumSymbol, List[VariableDeclarationStatement], List[BindOperation]]:
|
185
|
+
if frac_digits_diff <= 0:
|
186
|
+
return var, [], []
|
187
|
+
|
182
188
|
quantum_type = var.quantum_type
|
183
189
|
if TYPE_CHECKING:
|
184
190
|
assert isinstance(quantum_type, QuantumNumeric)
|
185
191
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
- quantum_type.fraction_digits_value
|
192
|
-
- int(quantum_type.sign_value)
|
192
|
+
trimmed_fraction_digits_var = QuantumSymbol(
|
193
|
+
handle=HandleBinding(name=f"trimmed_{kind}_fraction_digits"),
|
194
|
+
quantum_type=QuantumBitvector(
|
195
|
+
length=Expression(expr=str(frac_digits_diff)),
|
196
|
+
),
|
193
197
|
)
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
198
|
+
overlap_var = QuantumSymbol(
|
199
|
+
handle=HandleBinding(name=f"{kind}_overlap"),
|
200
|
+
quantum_type=QuantumNumeric(
|
201
|
+
size=Expression(expr=str(quantum_type.size_in_bits - frac_digits_diff)),
|
202
|
+
is_signed=quantum_type.is_signed,
|
203
|
+
fraction_digits=Expression(expr="0"),
|
204
|
+
),
|
205
|
+
)
|
206
|
+
bind_targets = trimmed_fraction_digits_var, overlap_var
|
200
207
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
quantum_type=QuantumBitvector(
|
206
|
-
length=Expression(expr=str(frac_digits_diff)),
|
207
|
-
),
|
208
|
-
)
|
208
|
+
split_var_declarations = [
|
209
|
+
VariableDeclarationStatement(
|
210
|
+
name=var.handle.name,
|
211
|
+
quantum_type=var.quantum_type,
|
209
212
|
)
|
213
|
+
for var in bind_targets
|
214
|
+
]
|
215
|
+
bind_op = BindOperation(
|
216
|
+
in_handles=[var.handle],
|
217
|
+
out_handles=[var.handle for var in bind_targets],
|
218
|
+
)
|
210
219
|
|
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)
|
220
|
+
return overlap_var, split_var_declarations, [bind_op]
|
222
221
|
|
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
222
|
|
231
|
-
|
223
|
+
def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> Tuple[
|
224
|
+
QuantumSymbol,
|
225
|
+
List[VariableDeclarationStatement],
|
226
|
+
List[QuantumStatement],
|
227
|
+
List[QuantumFunctionCall],
|
228
|
+
List[BindOperation],
|
229
|
+
]:
|
230
|
+
quantum_type = var.quantum_type
|
231
|
+
if TYPE_CHECKING:
|
232
|
+
assert isinstance(quantum_type, QuantumNumeric)
|
232
233
|
|
234
|
+
if not quantum_type.sign_value or size_diff >= 0:
|
235
|
+
return var, [], [], [], []
|
233
236
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
if len(bind_targets) == 0:
|
238
|
-
return [], []
|
237
|
+
significand_var, sign_var, sign_split_bind = _split_sign(kind, var)
|
238
|
+
padding_var, padding_allocation = _allocate_padding(kind, size_diff)
|
239
|
+
padding_init_ops = _init_padding(sign_var, padding_var, size_diff)
|
239
240
|
|
240
|
-
|
241
|
-
|
242
|
-
|
241
|
+
padded_var = QuantumSymbol(
|
242
|
+
handle=HandleBinding(name=f"padded_{kind}"),
|
243
|
+
quantum_type=QuantumNumeric(
|
244
|
+
size=Expression(expr=str(quantum_type.size_in_bits - size_diff)),
|
245
|
+
is_signed=Expression(expr="False"),
|
246
|
+
fraction_digits=Expression(expr="0"),
|
247
|
+
),
|
243
248
|
)
|
244
|
-
|
249
|
+
padding_rebind = BindOperation(
|
250
|
+
in_handles=[significand_var.handle, sign_var.handle, padding_var.handle],
|
251
|
+
out_handles=[padded_var.handle],
|
252
|
+
)
|
253
|
+
|
254
|
+
var_decls = [
|
245
255
|
VariableDeclarationStatement(
|
246
256
|
name=var.handle.name,
|
247
257
|
quantum_type=var.quantum_type,
|
248
258
|
)
|
249
|
-
for var in
|
250
|
-
]
|
259
|
+
for var in (significand_var, sign_var, padding_var, padded_var)
|
260
|
+
]
|
261
|
+
|
262
|
+
return (
|
263
|
+
padded_var,
|
264
|
+
var_decls,
|
265
|
+
[sign_split_bind, padding_allocation],
|
266
|
+
padding_init_ops,
|
267
|
+
[padding_rebind],
|
268
|
+
)
|
269
|
+
|
270
|
+
|
271
|
+
def _init_padding(
|
272
|
+
sign_var: QuantumSymbol, padding_var: QuantumSymbol, size_diff: int
|
273
|
+
) -> List[QuantumFunctionCall]:
|
274
|
+
padding_init_ops = [
|
275
|
+
QuantumFunctionCall(
|
276
|
+
function=CX.func_decl.name,
|
277
|
+
positional_args=[sign_var.handle, padding_var[idx].handle],
|
278
|
+
)
|
279
|
+
for idx in range(-size_diff)
|
280
|
+
]
|
281
|
+
for cx_call in padding_init_ops:
|
282
|
+
cx_call.set_func_decl(CX.func_decl)
|
283
|
+
return padding_init_ops
|
284
|
+
|
285
|
+
|
286
|
+
def _allocate_padding(
|
287
|
+
kind: str, size_diff: int
|
288
|
+
) -> Tuple[QuantumSymbol, QuantumFunctionCall]:
|
289
|
+
padding_var = QuantumSymbol(
|
290
|
+
handle=HandleBinding(name=f"{kind}_sign_padding"),
|
291
|
+
quantum_type=QuantumBitvector(
|
292
|
+
length=Expression(expr=str(-size_diff)),
|
293
|
+
),
|
294
|
+
)
|
295
|
+
padding_allocation = QuantumFunctionCall(
|
296
|
+
function=allocate.func_decl.name,
|
297
|
+
positional_args=[Expression(expr=str(-size_diff)), padding_var.handle],
|
298
|
+
)
|
299
|
+
padding_allocation.set_func_decl(allocate.func_decl)
|
300
|
+
return padding_var, padding_allocation
|
301
|
+
|
302
|
+
|
303
|
+
def _split_sign(
|
304
|
+
kind: str, var: QuantumSymbol
|
305
|
+
) -> Tuple[QuantumSymbol, QuantumSymbol, BindOperation]:
|
306
|
+
significand_var = QuantumSymbol(
|
307
|
+
handle=HandleBinding(name=f"{kind}_significand"),
|
308
|
+
quantum_type=QuantumNumeric(
|
309
|
+
size=Expression(expr=str(var.quantum_type.size_in_bits - 1)),
|
310
|
+
is_signed=Expression(expr="False"),
|
311
|
+
fraction_digits=Expression(expr="0"),
|
312
|
+
),
|
313
|
+
)
|
314
|
+
sign_var = QuantumSymbol(
|
315
|
+
handle=HandleBinding(name=f"{kind}_sign_bit"),
|
316
|
+
quantum_type=QuantumBit(),
|
317
|
+
)
|
318
|
+
sign_split_bind = BindOperation(
|
319
|
+
in_handles=[var.handle],
|
320
|
+
out_handles=[significand_var.handle, sign_var.handle],
|
321
|
+
)
|
322
|
+
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
|
)
|