classiq 0.67.0__py3-none-any.whl → 0.68.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 +5 -1
- classiq/_internals/async_utils.py +1 -1
- classiq/_internals/authentication/password_manager.py +1 -1
- classiq/_internals/client.py +1 -1
- classiq/execution/execution_session.py +7 -3
- classiq/executor.py +7 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +1 -1
- classiq/interface/chemistry/operator.py +1 -1
- classiq/interface/debug_info/debug_info.py +15 -0
- classiq/interface/generator/arith/arithmetic.py +96 -1
- classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
- classiq/interface/generator/generated_circuit_data.py +4 -2
- classiq/interface/generator/quantum_program.py +18 -1
- classiq/interface/generator/types/enum_declaration.py +33 -2
- classiq/interface/model/classical_if.py +2 -2
- classiq/interface/model/control.py +2 -2
- classiq/interface/model/invert.py +2 -2
- classiq/interface/model/power.py +2 -2
- classiq/interface/model/quantum_function_call.py +4 -0
- classiq/interface/model/repeat.py +2 -2
- classiq/interface/model/statement_block.py +1 -1
- classiq/interface/model/within_apply_operation.py +2 -2
- classiq/model_expansions/interpreters/generative_interpreter.py +78 -18
- classiq/model_expansions/quantum_operations/allocate.py +3 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -0
- classiq/model_expansions/quantum_operations/bind.py +2 -1
- classiq/model_expansions/quantum_operations/block_evaluator.py +76 -0
- classiq/model_expansions/quantum_operations/classicalif.py +5 -4
- classiq/model_expansions/quantum_operations/composite_emitter.py +27 -0
- classiq/model_expansions/quantum_operations/emitter.py +16 -2
- classiq/model_expansions/quantum_operations/expression_evaluator.py +33 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +28 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -2
- classiq/model_expansions/quantum_operations/repeat.py +2 -1
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -1
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +1 -1
- classiq/open_library/functions/__init__.py +1 -2
- classiq/open_library/functions/amplitude_amplification.py +8 -5
- classiq/open_library/functions/discrete_sine_cosine_transform.py +16 -13
- classiq/open_library/functions/grover.py +6 -10
- classiq/open_library/functions/modular_exponentiation.py +7 -13
- classiq/open_library/functions/state_preparation.py +16 -17
- classiq/open_library/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +10 -2
- classiq/qmod/builtins/functions/chemistry.py +6 -38
- classiq/qmod/quantum_expandable.py +30 -6
- classiq/qmod/semantics/validation/types_validation.py +1 -1
- classiq/qmod/symbolic.py +2 -1
- classiq/qmod/utilities.py +2 -1
- classiq/qmod/write_qmod.py +10 -7
- classiq/synthesis.py +20 -7
- {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/METADATA +1 -1
- {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/RECORD +55 -51
- classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
- {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/WHEEL +0 -0
@@ -21,8 +21,11 @@ from classiq.interface.model.model import Model
|
|
21
21
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
22
22
|
from classiq.interface.model.phase_operation import PhaseOperation
|
23
23
|
from classiq.interface.model.power import Power
|
24
|
-
from classiq.interface.model.quantum_expressions.
|
25
|
-
|
24
|
+
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
25
|
+
AmplitudeLoadingOperation,
|
26
|
+
)
|
27
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
28
|
+
ArithmeticOperation,
|
26
29
|
)
|
27
30
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
28
31
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -55,7 +58,17 @@ from classiq.model_expansions.quantum_operations import (
|
|
55
58
|
VariableDeclarationStatementEmitter,
|
56
59
|
)
|
57
60
|
from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
|
58
|
-
from classiq.model_expansions.quantum_operations.
|
61
|
+
from classiq.model_expansions.quantum_operations.assignment_result_processor import (
|
62
|
+
AssignmentResultProcessor,
|
63
|
+
)
|
64
|
+
from classiq.model_expansions.quantum_operations.block_evaluator import BlockEvaluator
|
65
|
+
from classiq.model_expansions.quantum_operations.composite_emitter import (
|
66
|
+
CompositeEmitter,
|
67
|
+
)
|
68
|
+
from classiq.model_expansions.quantum_operations.expression_evaluator import (
|
69
|
+
ExpressionEvaluator,
|
70
|
+
)
|
71
|
+
from classiq.model_expansions.quantum_operations.handle_evaluator import HandleEvaluator
|
59
72
|
from classiq.model_expansions.scope import Evaluated, Scope
|
60
73
|
from classiq.model_expansions.scope_initialization import (
|
61
74
|
add_constants_to_scope,
|
@@ -134,15 +147,39 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
134
147
|
BindEmitter(self).emit(bind)
|
135
148
|
|
136
149
|
@emit.register
|
137
|
-
def
|
138
|
-
|
139
|
-
self,
|
150
|
+
def emit_amplitude_loading_operation(self, op: AmplitudeLoadingOperation) -> None:
|
151
|
+
CompositeEmitter[AmplitudeLoadingOperation](
|
152
|
+
self,
|
153
|
+
[
|
154
|
+
HandleEvaluator(self, "result_var"),
|
155
|
+
ExpressionEvaluator(self, "expression"),
|
156
|
+
AssignmentResultProcessor(self),
|
157
|
+
],
|
158
|
+
).emit(op)
|
159
|
+
|
160
|
+
@emit.register
|
161
|
+
def _emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
|
162
|
+
self.emit_arithmetic_operation(op)
|
163
|
+
|
164
|
+
def emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
|
165
|
+
CompositeEmitter[ArithmeticOperation](
|
166
|
+
self,
|
167
|
+
[
|
168
|
+
HandleEvaluator(self, "result_var"),
|
169
|
+
ExpressionEvaluator(self, "expression"),
|
170
|
+
AssignmentResultProcessor(self),
|
171
|
+
],
|
140
172
|
).emit(op)
|
141
173
|
|
142
174
|
@emit.register
|
143
175
|
def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
|
144
|
-
|
145
|
-
self,
|
176
|
+
CompositeEmitter[InplaceBinaryOperation](
|
177
|
+
self,
|
178
|
+
[
|
179
|
+
HandleEvaluator(self, "target"),
|
180
|
+
HandleEvaluator(self, "value"),
|
181
|
+
ExpressionEvaluator(self, "value"),
|
182
|
+
],
|
146
183
|
).emit(op)
|
147
184
|
|
148
185
|
@emit.register
|
@@ -157,37 +194,60 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
157
194
|
|
158
195
|
@emit.register
|
159
196
|
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
160
|
-
|
197
|
+
BlockEvaluator(
|
161
198
|
self,
|
162
199
|
WITHIN_APPLY_NAME,
|
163
|
-
|
200
|
+
"within",
|
201
|
+
"apply",
|
202
|
+
"compute",
|
203
|
+
"action",
|
164
204
|
).emit(within_apply)
|
165
205
|
|
166
206
|
@emit.register
|
167
207
|
def emit_invert(self, invert: Invert) -> None:
|
168
|
-
|
208
|
+
BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
|
169
209
|
|
170
210
|
@emit.register
|
171
211
|
def emit_repeat(self, repeat: Repeat) -> None:
|
172
212
|
RepeatEmitter(self).emit(repeat)
|
173
213
|
|
174
214
|
@emit.register
|
215
|
+
def _emit_control(self, control: Control) -> None:
|
216
|
+
self.emit_control(control)
|
217
|
+
|
175
218
|
def emit_control(self, control: Control) -> None:
|
176
|
-
|
219
|
+
CompositeEmitter[Control](
|
177
220
|
self,
|
178
|
-
|
179
|
-
|
221
|
+
[
|
222
|
+
ExpressionEvaluator(self, "expression"),
|
223
|
+
BlockEvaluator(
|
224
|
+
self,
|
225
|
+
CONTROL_OPERATOR_NAME,
|
226
|
+
"body",
|
227
|
+
"else_block",
|
228
|
+
),
|
229
|
+
],
|
180
230
|
).emit(control)
|
181
231
|
|
182
232
|
@emit.register
|
183
233
|
def emit_power(self, power: Power) -> None:
|
184
|
-
|
185
|
-
|
186
|
-
|
234
|
+
CompositeEmitter[Power](
|
235
|
+
self,
|
236
|
+
[
|
237
|
+
ExpressionEvaluator(self, "power"),
|
238
|
+
BlockEvaluator(self, CONTROL_OPERATOR_NAME, "body"),
|
239
|
+
],
|
240
|
+
).emit(power)
|
187
241
|
|
188
242
|
@emit.register
|
189
243
|
def emit_phase(self, phase: PhaseOperation) -> None:
|
190
|
-
|
244
|
+
CompositeEmitter[PhaseOperation](
|
245
|
+
self,
|
246
|
+
[
|
247
|
+
ExpressionEvaluator(self, "expression"),
|
248
|
+
ExpressionEvaluator(self, "theta"),
|
249
|
+
],
|
250
|
+
).emit(phase)
|
191
251
|
|
192
252
|
def _expand_body(self, operation: Closure) -> None:
|
193
253
|
if isinstance(operation, FunctionClosure) and operation.name == "permute":
|
@@ -12,7 +12,7 @@ from classiq.model_expansions.scope import QuantumSymbol
|
|
12
12
|
|
13
13
|
|
14
14
|
class AllocateEmitter(Emitter[Allocate]):
|
15
|
-
def emit(self, allocate: Allocate, /) ->
|
15
|
+
def emit(self, allocate: Allocate, /) -> bool:
|
16
16
|
target: QuantumSymbol = self._interpreter.evaluate(allocate.target).as_type(
|
17
17
|
QuantumSymbol
|
18
18
|
)
|
@@ -32,6 +32,7 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
32
32
|
)
|
33
33
|
self._register_debug_info(allocate)
|
34
34
|
self.emit_statement(allocate)
|
35
|
+
return True
|
35
36
|
|
36
37
|
def _get_var_size(self, target: QuantumSymbol, size: Expression | None) -> int:
|
37
38
|
if size is None:
|
@@ -70,4 +71,5 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
70
71
|
level=OperationLevel.QMOD_STATEMENT,
|
71
72
|
is_allocate_or_free=True,
|
72
73
|
port_to_passed_variable_map={"ARG": str(allocate.target)},
|
74
|
+
node=allocate._as_back_ref(),
|
73
75
|
)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
2
|
+
from classiq.interface.generator.functions.port_declaration import (
|
3
|
+
PortDeclarationDirection,
|
4
|
+
)
|
5
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
6
|
+
ArithmeticOperation,
|
7
|
+
ArithmeticOperationKind,
|
8
|
+
)
|
9
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
10
|
+
QuantumAssignmentOperation,
|
11
|
+
)
|
12
|
+
|
13
|
+
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
14
|
+
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
15
|
+
from classiq.model_expansions.scope import QuantumSymbol
|
16
|
+
from classiq.model_expansions.transformers.ast_renamer import rename_variables
|
17
|
+
|
18
|
+
|
19
|
+
class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
20
|
+
def emit(self, op: QuantumAssignmentOperation, /) -> bool:
|
21
|
+
if (
|
22
|
+
isinstance(op, ArithmeticOperation)
|
23
|
+
and op.operation_kind == ArithmeticOperationKind.Assignment
|
24
|
+
):
|
25
|
+
direction = PortDeclarationDirection.Output
|
26
|
+
self._update_result_type(op)
|
27
|
+
else:
|
28
|
+
direction = PortDeclarationDirection.Inout
|
29
|
+
self._capture_handle(op.result_var, direction)
|
30
|
+
return False
|
31
|
+
|
32
|
+
def _update_result_type(self, op: ArithmeticOperation) -> None:
|
33
|
+
expr = self._evaluate_expression(op.expression)
|
34
|
+
symbols = self._get_symbols_in_expression(expr)
|
35
|
+
expr_str = rename_variables(
|
36
|
+
expr.expr,
|
37
|
+
{str(symbol.handle): symbol.handle.identifier for symbol in symbols}
|
38
|
+
| {symbol.handle.qmod_expr: symbol.handle.identifier for symbol in symbols},
|
39
|
+
)
|
40
|
+
for symbol in symbols:
|
41
|
+
expr_str = expr_str.replace(
|
42
|
+
symbol.handle.qmod_expr, symbol.handle.identifier
|
43
|
+
)
|
44
|
+
result_type = compute_arithmetic_result_type(
|
45
|
+
expr_str,
|
46
|
+
{symbol.handle.identifier: symbol.quantum_type for symbol in symbols},
|
47
|
+
self._machine_precision,
|
48
|
+
)
|
49
|
+
result_symbol = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
|
50
|
+
copy_type_information(
|
51
|
+
result_type, result_symbol.quantum_type, str(op.result_var)
|
52
|
+
)
|
@@ -16,7 +16,7 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
|
16
16
|
|
17
17
|
|
18
18
|
class BindEmitter(Emitter[BindOperation]):
|
19
|
-
def emit(self, bind: BindOperation, /) ->
|
19
|
+
def emit(self, bind: BindOperation, /) -> bool:
|
20
20
|
inputs, outputs = self._get_inputs_outputs(bind)
|
21
21
|
validate_bind_targets(bind, self._current_scope)
|
22
22
|
unsized_outputs = [
|
@@ -56,6 +56,7 @@ class BindEmitter(Emitter[BindOperation]):
|
|
56
56
|
back_ref=bind.uuid,
|
57
57
|
)
|
58
58
|
)
|
59
|
+
return True
|
59
60
|
|
60
61
|
def _get_inputs_outputs(
|
61
62
|
self, bind: BindOperation
|
@@ -0,0 +1,76 @@
|
|
1
|
+
from collections.abc import Sequence
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
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
|
+
if TYPE_CHECKING:
|
11
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
12
|
+
|
13
|
+
|
14
|
+
_BLOCK_RENAMES = {
|
15
|
+
"compute": "within",
|
16
|
+
"action": "apply",
|
17
|
+
}
|
18
|
+
_REVERSE_BLOCK_RENAMES = {rename: name for name, rename in _BLOCK_RENAMES.items()}
|
19
|
+
|
20
|
+
|
21
|
+
class BlockEvaluator(Emitter[QuantumOperation]):
|
22
|
+
def __init__(
|
23
|
+
self, interpreter: "BaseInterpreter", operation_name: str, *block_names: str
|
24
|
+
) -> None:
|
25
|
+
super().__init__(interpreter)
|
26
|
+
self._operation_name = operation_name
|
27
|
+
self._block_names: Sequence[str] = block_names
|
28
|
+
|
29
|
+
def emit(self, op: QuantumOperation, /) -> bool:
|
30
|
+
expanded_blocks: dict[str, list[QuantumStatement]] = {}
|
31
|
+
blocks = [
|
32
|
+
block
|
33
|
+
for block in self._block_names
|
34
|
+
if hasattr(op, block) and getattr(op, block) is not None
|
35
|
+
]
|
36
|
+
|
37
|
+
if len(blocks) > 0:
|
38
|
+
if op.is_generative():
|
39
|
+
expanded_blocks = self.expand_generative_blocks(op)
|
40
|
+
else:
|
41
|
+
expanded_blocks = self.expand_blocks(op, blocks)
|
42
|
+
expanded_blocks.update(expanded_blocks)
|
43
|
+
|
44
|
+
op = op.model_copy(update={**expanded_blocks, "back_ref": op.uuid})
|
45
|
+
self._builder.emit_statement(op)
|
46
|
+
return True
|
47
|
+
|
48
|
+
def expand_blocks(
|
49
|
+
self, op: QuantumOperation, block_names: list[str]
|
50
|
+
) -> dict[str, list[QuantumStatement]]:
|
51
|
+
blocks = {
|
52
|
+
_BLOCK_RENAMES.get(block, block): getattr(op, block)
|
53
|
+
for block in block_names
|
54
|
+
}
|
55
|
+
block_closure = Closure(
|
56
|
+
name=self._operation_name,
|
57
|
+
scope=Scope(parent=self._current_scope),
|
58
|
+
blocks=blocks,
|
59
|
+
)
|
60
|
+
context = self._expand_operation(block_closure)
|
61
|
+
return {
|
62
|
+
block: context.statements(_BLOCK_RENAMES.get(block, block))
|
63
|
+
for block in block_names
|
64
|
+
}
|
65
|
+
|
66
|
+
def expand_generative_blocks(
|
67
|
+
self, op: QuantumOperation
|
68
|
+
) -> dict[str, list[QuantumStatement]]:
|
69
|
+
blocks = [
|
70
|
+
block for block in self._block_names if op.has_generative_block(block)
|
71
|
+
]
|
72
|
+
context = self._expand_generative_context(op, self._operation_name, blocks)
|
73
|
+
return {
|
74
|
+
_REVERSE_BLOCK_RENAMES.get(block, block): context.statements(block)
|
75
|
+
for block in blocks
|
76
|
+
}
|
@@ -18,7 +18,7 @@ def _is_all_identity_calls(body: Sequence[QuantumStatement]) -> bool:
|
|
18
18
|
|
19
19
|
|
20
20
|
class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
21
|
-
def emit(self, classical_if: ClassicalIf, /) ->
|
21
|
+
def emit(self, classical_if: ClassicalIf, /) -> bool:
|
22
22
|
condition = self._interpreter.evaluate(classical_if.condition).as_type(bool)
|
23
23
|
op_name = "then" if condition else "else"
|
24
24
|
is_generative = classical_if.is_generative()
|
@@ -26,7 +26,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
|
26
26
|
body: Sequence[QuantumStatement]
|
27
27
|
if is_generative:
|
28
28
|
if not classical_if.has_generative_block(op_name):
|
29
|
-
return
|
29
|
+
return True
|
30
30
|
context = self._expand_generative_context(classical_if, op_name, op_name)
|
31
31
|
context.blocks["body"] = context.blocks[op_name]
|
32
32
|
context.blocks.pop(op_name)
|
@@ -35,7 +35,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
|
35
35
|
body = classical_if.then if condition else classical_if.else_
|
36
36
|
|
37
37
|
if _is_all_identity_calls(body):
|
38
|
-
return
|
38
|
+
return True
|
39
39
|
|
40
40
|
if is_generative or not self._should_wrap(body):
|
41
41
|
for stmt in body:
|
@@ -43,7 +43,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
|
43
43
|
self._interpreter._builder.emit_statement(stmt)
|
44
44
|
else:
|
45
45
|
self._interpreter.emit_statement(stmt)
|
46
|
-
return
|
46
|
+
return True
|
47
47
|
|
48
48
|
then_else_func = FunctionClosure.create(
|
49
49
|
name=self._counted_name_allocator.allocate("then" if condition else "else"),
|
@@ -54,3 +54,4 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
|
54
54
|
self._emit_quantum_function_call(
|
55
55
|
then_else_func, list(), new_function_debug_info_by_node(classical_if)
|
56
56
|
)
|
57
|
+
return True
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from collections.abc import Sequence
|
2
|
+
from typing import TYPE_CHECKING, Generic
|
3
|
+
|
4
|
+
from classiq.model_expansions.quantum_operations.emitter import (
|
5
|
+
Emitter,
|
6
|
+
QuantumStatementT,
|
7
|
+
)
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
11
|
+
|
12
|
+
|
13
|
+
class CompositeEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT]):
|
14
|
+
def __init__(
|
15
|
+
self,
|
16
|
+
interpreter: "BaseInterpreter",
|
17
|
+
emitters: Sequence[Emitter[QuantumStatementT]],
|
18
|
+
) -> None:
|
19
|
+
super().__init__(interpreter)
|
20
|
+
self._emitters = emitters
|
21
|
+
|
22
|
+
def emit(self, statement: QuantumStatementT, /) -> bool:
|
23
|
+
for emitter in self._emitters:
|
24
|
+
if emitter.emit(statement):
|
25
|
+
return True
|
26
|
+
self._builder.emit_statement(statement)
|
27
|
+
return True
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import ast
|
1
2
|
from abc import ABC, abstractmethod
|
2
3
|
from typing import (
|
3
4
|
TYPE_CHECKING,
|
@@ -39,12 +40,15 @@ from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
|
39
40
|
translate_sympy_quantum_expression,
|
40
41
|
)
|
41
42
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
43
|
+
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
42
44
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
43
45
|
|
44
46
|
if TYPE_CHECKING:
|
45
47
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
46
48
|
|
47
|
-
QuantumStatementT = TypeVar(
|
49
|
+
QuantumStatementT = TypeVar(
|
50
|
+
"QuantumStatementT", bound=QuantumStatement, contravariant=True
|
51
|
+
)
|
48
52
|
|
49
53
|
|
50
54
|
class Emitter(Generic[QuantumStatementT], ABC):
|
@@ -60,7 +64,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
60
64
|
)
|
61
65
|
|
62
66
|
@abstractmethod
|
63
|
-
def emit(self, statement: QuantumStatementT, /) ->
|
67
|
+
def emit(self, statement: QuantumStatementT, /) -> bool:
|
64
68
|
pass
|
65
69
|
|
66
70
|
def _expand_operation(self, closure: Closure) -> OperationContext:
|
@@ -173,3 +177,13 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
173
177
|
defining_function=defining_function,
|
174
178
|
direction=direction,
|
175
179
|
)
|
180
|
+
|
181
|
+
def _get_symbols_in_expression(self, expr: Expression) -> list[QuantumSymbol]:
|
182
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
183
|
+
vrc.visit(ast.parse(expr.expr))
|
184
|
+
handles = dict.fromkeys(
|
185
|
+
handle
|
186
|
+
for handle in vrc.var_handles
|
187
|
+
if isinstance(self._current_scope[handle.name].value, QuantumSymbol)
|
188
|
+
)
|
189
|
+
return [self._interpreter.evaluate(handle).value for handle in handles]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from classiq.interface.generator.expressions.expression import Expression
|
4
|
+
from classiq.interface.generator.functions.port_declaration import (
|
5
|
+
PortDeclarationDirection,
|
6
|
+
)
|
7
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
8
|
+
|
9
|
+
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
13
|
+
|
14
|
+
|
15
|
+
class ExpressionEvaluator(Emitter[QuantumOperation]):
|
16
|
+
def __init__(self, interpreter: "BaseInterpreter", expression_name: str) -> None:
|
17
|
+
super().__init__(interpreter)
|
18
|
+
self._expression_name = expression_name
|
19
|
+
|
20
|
+
def emit(self, op: QuantumOperation, /) -> bool:
|
21
|
+
expression = getattr(op, self._expression_name)
|
22
|
+
if not isinstance(expression, Expression) or expression.is_evaluated():
|
23
|
+
return False
|
24
|
+
evaluated_expression = self._evaluate_expression(
|
25
|
+
expression, preserve_bool_ops=True
|
26
|
+
)
|
27
|
+
for symbol in self._get_symbols_in_expression(evaluated_expression):
|
28
|
+
self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
|
29
|
+
op = op.model_copy(
|
30
|
+
update={self._expression_name: evaluated_expression, "back_ref": op.uuid}
|
31
|
+
)
|
32
|
+
self._interpreter.emit(op)
|
33
|
+
return True
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
4
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
5
|
+
|
6
|
+
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
10
|
+
|
11
|
+
|
12
|
+
class HandleEvaluator(Emitter[QuantumOperation]):
|
13
|
+
def __init__(self, interpreter: "BaseInterpreter", handle_name: str) -> None:
|
14
|
+
super().__init__(interpreter)
|
15
|
+
self._handle_name = handle_name
|
16
|
+
|
17
|
+
def emit(self, op: QuantumOperation, /) -> bool:
|
18
|
+
handle = getattr(op, self._handle_name)
|
19
|
+
if not isinstance(handle, HandleBinding):
|
20
|
+
return False
|
21
|
+
evaluated_handle = self._interpreter.evaluate(handle).value.handle
|
22
|
+
if handle == evaluated_handle:
|
23
|
+
return False
|
24
|
+
op = op.model_copy(
|
25
|
+
update={self._handle_name: evaluated_handle, "back_ref": op.uuid}
|
26
|
+
)
|
27
|
+
self._interpreter.emit(op)
|
28
|
+
return True
|
@@ -28,16 +28,17 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
28
28
|
super().__init__(interpreter)
|
29
29
|
self._model = self._interpreter._model
|
30
30
|
|
31
|
-
def emit(self, call: QuantumFunctionCall, /) ->
|
31
|
+
def emit(self, call: QuantumFunctionCall, /) -> bool:
|
32
32
|
if call.function == "allocate": # FIXME: Remove compatibility (CAD-25935)
|
33
33
|
self._allocate_compatibility(call)
|
34
|
-
return
|
34
|
+
return True
|
35
35
|
function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
|
36
36
|
args = call.positional_args
|
37
37
|
with ErrorManager().call(function.name):
|
38
38
|
self._emit_quantum_function_call(
|
39
39
|
function, args, self._debug_info.get(call.uuid)
|
40
40
|
)
|
41
|
+
return True
|
41
42
|
|
42
43
|
def _allocate_compatibility(self, call: QuantumFunctionCall) -> None:
|
43
44
|
if len(call.positional_args) != 2:
|
@@ -17,7 +17,7 @@ from classiq.qmod.quantum_function import GenerativeQFunc
|
|
17
17
|
|
18
18
|
|
19
19
|
class RepeatEmitter(CallEmitter[Repeat]):
|
20
|
-
def emit(self, repeat: Repeat, /) ->
|
20
|
+
def emit(self, repeat: Repeat, /) -> bool:
|
21
21
|
count = self._interpreter.evaluate(repeat.count).as_type(int)
|
22
22
|
if count < 0:
|
23
23
|
raise ClassiqExpansionError(
|
@@ -26,6 +26,7 @@ class RepeatEmitter(CallEmitter[Repeat]):
|
|
26
26
|
op_name = self._counted_name_allocator.allocate(REPEAT_OPERATOR_NAME)
|
27
27
|
for i in range(count):
|
28
28
|
self._emit_iteration(repeat, i, op_name)
|
29
|
+
return True
|
29
30
|
|
30
31
|
def _emit_iteration(self, repeat: Repeat, i: int, op_name: str) -> None:
|
31
32
|
closure_constructor: type[FunctionClosure]
|
@@ -12,7 +12,7 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
|
12
12
|
|
13
13
|
|
14
14
|
class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
|
15
|
-
def emit(self, variable_declaration: VariableDeclarationStatement, /) ->
|
15
|
+
def emit(self, variable_declaration: VariableDeclarationStatement, /) -> bool:
|
16
16
|
var_decl = variable_declaration.model_copy(
|
17
17
|
update=dict(back_ref=variable_declaration.uuid)
|
18
18
|
)
|
@@ -36,3 +36,4 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
|
|
36
36
|
var_decl.name, self._builder.current_function
|
37
37
|
)
|
38
38
|
self.emit_statement(var_decl)
|
39
|
+
return True
|
@@ -174,6 +174,6 @@ class ExpressionSympyTranslator(ast.NodeTransformer):
|
|
174
174
|
def visit_Attribute(self, node: ast.Attribute) -> ast.Call:
|
175
175
|
return ast.Call(
|
176
176
|
func=ast.Name("get_field"),
|
177
|
-
args=[node.value, ast.Constant(value=node.attr)],
|
177
|
+
args=[self.visit(node.value), ast.Constant(value=node.attr)],
|
178
178
|
keywords=[],
|
179
179
|
)
|
@@ -10,7 +10,7 @@ from .hea import *
|
|
10
10
|
from .linear_pauli_rotation import *
|
11
11
|
from .linear_pauli_rotation import _single_pauli
|
12
12
|
from .modular_exponentiation import *
|
13
|
-
from .modular_exponentiation import _check_msb
|
13
|
+
from .modular_exponentiation import _check_msb
|
14
14
|
from .qaoa_penalty import *
|
15
15
|
from .qft_functions import *
|
16
16
|
from .qpe import *
|
@@ -72,7 +72,6 @@ OPEN_LIBRARY_FUNCTIONS = [
|
|
72
72
|
qst_type2,
|
73
73
|
modular_increment,
|
74
74
|
qft,
|
75
|
-
_ctrl_x,
|
76
75
|
_prepare_uniform_trimmed_state_step,
|
77
76
|
_qct_d_operator,
|
78
77
|
_qct_pi_operator,
|
@@ -4,7 +4,7 @@ from classiq.qmod.builtins.operations import (
|
|
4
4
|
allocate,
|
5
5
|
bind,
|
6
6
|
control,
|
7
|
-
|
7
|
+
power,
|
8
8
|
within_apply,
|
9
9
|
)
|
10
10
|
from classiq.qmod.cparam import CInt, CReal
|
@@ -24,7 +24,7 @@ def amplitude_amplification(
|
|
24
24
|
"""
|
25
25
|
[Qmod Classiq-library function]
|
26
26
|
|
27
|
-
Applies the Amplitude Amplification algorithm
|
27
|
+
Applies the Amplitude Amplification algorithm; Prepares a state using the given `space_transform` function, and applies `reps` repetititions
|
28
28
|
of the grover operator, using the given `oracle` functions which marks the "good" states.
|
29
29
|
|
30
30
|
Args:
|
@@ -34,7 +34,10 @@ def amplitude_amplification(
|
|
34
34
|
packed_vars: The variable that holds the state to be amplified. Assumed to be in the zero state at the beginning of the algorithm.
|
35
35
|
"""
|
36
36
|
space_transform(packed_qvars)
|
37
|
-
|
37
|
+
power(
|
38
|
+
reps,
|
39
|
+
lambda: grover_operator(oracle, space_transform, packed_qvars),
|
40
|
+
)
|
38
41
|
|
39
42
|
|
40
43
|
@qfunc
|
@@ -47,7 +50,7 @@ def exact_amplitude_amplification(
|
|
47
50
|
"""
|
48
51
|
[Qmod Classiq-library function]
|
49
52
|
|
50
|
-
Applies an exact version of the Amplitude Amplification algorithm
|
53
|
+
Applies an exact version of the Amplitude Amplification algorithm, assuming knowledge of the amplitude of the marked state.
|
51
54
|
The function should be applied on the zero state, and it takes care for preparing the initial state before amplification using the `space_transform`.
|
52
55
|
|
53
56
|
Based on the algorithm in [Quantum state preparation without coherent arithmetic](https://arxiv.org/abs/2210.14892).
|
@@ -68,7 +71,7 @@ def exact_amplitude_amplification(
|
|
68
71
|
theta = pi / (4 * k + 2)
|
69
72
|
rot_phase = 2 * acos(sin(theta) / amplitude)
|
70
73
|
|
71
|
-
extended_qvars: QArray = QArray(
|
74
|
+
extended_qvars: QArray = QArray()
|
72
75
|
within_apply(
|
73
76
|
lambda: [ # type:ignore[arg-type]
|
74
77
|
allocate(aux),
|