classiq 0.67.0__py3-none-any.whl → 0.69.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 +9 -9
- classiq/_internals/async_utils.py +1 -1
- classiq/_internals/authentication/password_manager.py +1 -1
- classiq/_internals/client.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -11
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/torch_utils.py +1 -1
- classiq/execution/execution_session.py +7 -3
- classiq/execution/jobs.py +2 -5
- classiq/executor.py +7 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +2 -3
- classiq/interface/chemistry/operator.py +12 -8
- classiq/interface/debug_info/back_ref_util.py +22 -0
- classiq/interface/debug_info/debug_info.py +26 -21
- classiq/interface/executor/optimizer_preferences.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +96 -1
- classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
- classiq/interface/generator/arith/arithmetic_param_getters.py +3 -3
- classiq/interface/generator/functions/classical_type.py +12 -1
- classiq/interface/generator/generated_circuit_data.py +64 -23
- classiq/interface/generator/quantum_program.py +18 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/interface/generator/types/enum_declaration.py +45 -3
- classiq/interface/ide/visual_model.py +0 -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/quantum_statement.py +1 -1
- 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/interface/server/routes.py +0 -6
- classiq/model_expansions/generative_functions.py +4 -3
- 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/call_emitter.py +0 -13
- 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/scope_initialization.py +5 -19
- 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 +11 -12
- classiq/open_library/functions/discrete_sine_cosine_transform.py +17 -14
- classiq/open_library/functions/grover.py +7 -11
- classiq/open_library/functions/hea.py +3 -3
- classiq/open_library/functions/modular_exponentiation.py +17 -33
- classiq/open_library/functions/qft_functions.py +2 -2
- classiq/open_library/functions/qsvt.py +8 -8
- 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 +12 -4
- classiq/qmod/builtins/classical_functions.py +24 -7
- classiq/qmod/builtins/enums.py +1 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/chemistry.py +6 -38
- classiq/qmod/builtins/functions/exponentiation.py +24 -0
- classiq/qmod/builtins/operations.py +26 -11
- classiq/qmod/cparam.py +32 -5
- classiq/qmod/python_classical_type.py +10 -4
- classiq/qmod/quantum_callable.py +2 -1
- classiq/qmod/quantum_expandable.py +30 -6
- classiq/qmod/quantum_function.py +3 -2
- classiq/qmod/semantics/error_manager.py +1 -1
- classiq/qmod/semantics/validation/types_validation.py +1 -1
- classiq/qmod/symbolic.py +2 -1
- classiq/qmod/utilities.py +31 -2
- classiq/qmod/write_qmod.py +10 -7
- classiq/synthesis.py +25 -9
- {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/METADATA +1 -1
- {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/RECORD +85 -81
- classiq/interface/execution/jobs.py +0 -31
- classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
- {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/WHEEL +0 -0
@@ -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
|
+
}
|
@@ -13,9 +13,6 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
13
13
|
PortDeclarationDirection,
|
14
14
|
)
|
15
15
|
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
16
|
-
from classiq.interface.model.classical_parameter_declaration import (
|
17
|
-
ClassicalParameterDeclaration,
|
18
|
-
)
|
19
16
|
from classiq.interface.model.handle_binding import HandleBinding
|
20
17
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
21
18
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -162,11 +159,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
162
159
|
back_ref=self._get_back_ref(propagated_debug_info),
|
163
160
|
)
|
164
161
|
is_allocate_or_free = new_call.func_name == free.func_decl.name
|
165
|
-
parameters = {
|
166
|
-
arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
|
167
|
-
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
168
|
-
if isinstance(arg_decl, ClassicalParameterDeclaration)
|
169
|
-
}
|
170
162
|
|
171
163
|
port_to_passed_variable_map = {
|
172
164
|
arg_decl.name: str(evaluated_arg.value.handle)
|
@@ -176,11 +168,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
176
168
|
self._debug_info[new_call.uuid] = FunctionDebugInfo(
|
177
169
|
name=new_call.func_name,
|
178
170
|
level=OperationLevel.QMOD_FUNCTION_CALL,
|
179
|
-
parameters=(
|
180
|
-
parameters
|
181
|
-
if propagated_debug_info is None or propagated_debug_info.name == ""
|
182
|
-
else propagated_debug_info.parameters
|
183
|
-
),
|
184
171
|
is_allocate_or_free=is_allocate_or_free,
|
185
172
|
port_to_passed_variable_map=port_to_passed_variable_map,
|
186
173
|
node=new_call._as_back_ref(),
|
@@ -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
|
@@ -3,10 +3,6 @@ from typing import Any
|
|
3
3
|
|
4
4
|
from classiq.interface.exceptions import ClassiqError
|
5
5
|
from classiq.interface.generator.constant import Constant
|
6
|
-
from classiq.interface.generator.expressions.expression_constants import (
|
7
|
-
CPARAM_EXECUTION_SUFFIX,
|
8
|
-
RESERVED_EXPRESSIONS,
|
9
|
-
)
|
10
6
|
from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
|
11
7
|
from classiq.interface.model.handle_binding import HandleBinding
|
12
8
|
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
@@ -129,12 +125,6 @@ def init_builtin_types() -> None:
|
|
129
125
|
QMODULE.type_decls |= BUILTIN_STRUCT_DECLARATIONS
|
130
126
|
|
131
127
|
|
132
|
-
def _rename_exec_param(param_name: str) -> str:
|
133
|
-
if param_name in RESERVED_EXPRESSIONS:
|
134
|
-
return param_name
|
135
|
-
return param_name + CPARAM_EXECUTION_SUFFIX
|
136
|
-
|
137
|
-
|
138
128
|
def _add_exec_param_parts_to_scope(param_val: Any, scope: Scope) -> None:
|
139
129
|
if not isinstance(param_val, list):
|
140
130
|
scope[str(param_val)] = Evaluated(value=param_val)
|
@@ -145,21 +135,17 @@ def _add_exec_param_parts_to_scope(param_val: Any, scope: Scope) -> None:
|
|
145
135
|
|
146
136
|
def init_exec_params(model: Model, scope: Scope) -> dict[str, ConcreteClassicalType]:
|
147
137
|
if model.execution_parameters is not None:
|
148
|
-
exec_params =
|
149
|
-
param_name: (param_name, param_type)
|
150
|
-
for param_name, param_type in model.execution_parameters.items()
|
151
|
-
}
|
138
|
+
exec_params = model.execution_parameters
|
152
139
|
else:
|
153
140
|
exec_params = {
|
154
|
-
param.name:
|
141
|
+
param.name: param.classical_type
|
155
142
|
for param in model.function_dict.get(
|
156
143
|
"_dec_main", model.main_func
|
157
144
|
).param_decls
|
158
145
|
}
|
159
|
-
for param_name,
|
160
|
-
param_val = param_type.as_symbolic(
|
146
|
+
for param_name, param_type in exec_params.items():
|
147
|
+
param_val = param_type.as_symbolic(param_name)
|
161
148
|
scope[param_name] = Evaluated(value=param_val)
|
162
|
-
scope[param_rename] = Evaluated(value=param_val)
|
163
149
|
if isinstance(param_val, list):
|
164
150
|
_add_exec_param_parts_to_scope(param_val, scope)
|
165
|
-
return
|
151
|
+
return exec_params
|
@@ -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,13 +71,11 @@ 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
|
-
lambda: [
|
76
|
+
lambda: [
|
74
77
|
allocate(aux),
|
75
|
-
bind(
|
76
|
-
[aux, packed_qvars], extended_qvars
|
77
|
-
), # type:ignore[func-returns-value]
|
78
|
+
bind([aux, packed_qvars], extended_qvars),
|
78
79
|
],
|
79
80
|
lambda: amplitude_amplification(
|
80
81
|
k,
|
@@ -82,9 +83,7 @@ def exact_amplitude_amplification(
|
|
82
83
|
qvars_[0] == 0, lambda: oracle(qvars_[1 : qvars_.size])
|
83
84
|
),
|
84
85
|
lambda qvars_: [
|
85
|
-
space_transform(
|
86
|
-
qvars_[1 : qvars_.size]
|
87
|
-
),
|
86
|
+
space_transform(qvars_[1 : qvars_.size]),
|
88
87
|
RY(rot_phase, qvars_[0]),
|
89
88
|
],
|
90
89
|
extended_qvars,
|
@@ -1,13 +1,11 @@
|
|
1
1
|
from classiq.open_library.functions.qft_functions import qft
|
2
|
-
from classiq.open_library.functions.utility_functions import
|
3
|
-
apply_to_all,
|
4
|
-
modular_increment,
|
5
|
-
)
|
2
|
+
from classiq.open_library.functions.utility_functions import apply_to_all
|
6
3
|
from classiq.qmod.builtins.functions.standard_gates import PHASE, H, S, X, Z
|
7
4
|
from classiq.qmod.builtins.operations import (
|
8
5
|
allocate,
|
9
6
|
bind,
|
10
7
|
control,
|
8
|
+
inplace_add,
|
11
9
|
invert,
|
12
10
|
repeat,
|
13
11
|
within_apply,
|
@@ -30,8 +28,13 @@ def _qct_d_operator(x: QNum, q: QBit) -> None:
|
|
30
28
|
|
31
29
|
@qfunc
|
32
30
|
def _qct_pi_operator(x: QArray[QBit], q: QBit) -> None:
|
33
|
-
control(
|
34
|
-
|
31
|
+
control(
|
32
|
+
q == 1,
|
33
|
+
lambda: [
|
34
|
+
apply_to_all(X, x),
|
35
|
+
inplace_add(1, x), # type:ignore[arg-type]
|
36
|
+
],
|
37
|
+
)
|
35
38
|
|
36
39
|
|
37
40
|
def _t_operator(x: QArray) -> None:
|
@@ -63,11 +66,11 @@ def _d1_operator(x: QArray[QBit], q: QBit) -> None:
|
|
63
66
|
|
64
67
|
|
65
68
|
def _pi2_operator(x: QArray[QBit], q: QBit) -> None:
|
66
|
-
control(q == 1, lambda:
|
69
|
+
control(q == 1, lambda: inplace_add(1, x)) # type:ignore[arg-type]
|
67
70
|
|
68
71
|
|
69
72
|
def _j_operator(q: QBit) -> None:
|
70
|
-
within_apply(lambda: Z(q), lambda: (S(q), H(q), S(q)))
|
73
|
+
within_apply(lambda: Z(q), lambda: (S(q), H(q), S(q)))
|
71
74
|
|
72
75
|
|
73
76
|
def _b_t_operator(q: QBit) -> None:
|
@@ -76,7 +79,7 @@ def _b_t_operator(q: QBit) -> None:
|
|
76
79
|
|
77
80
|
|
78
81
|
def _d0dt_operator(x: QArray, q: QBit) -> None:
|
79
|
-
x_num: QNum = QNum(
|
82
|
+
x_num: QNum = QNum(size=x.len)
|
80
83
|
bind(x, x_num)
|
81
84
|
_b_t_operator(q)
|
82
85
|
control(x_num == 0, lambda: _j_operator(q))
|
@@ -140,7 +143,7 @@ def qct_qst_type2(x: QArray[QBit], q: QBit) -> None:
|
|
140
143
|
x: The LSB part of the qubit array to apply the transform to.
|
141
144
|
q: The MSB of the qubit array to apply the transform to.
|
142
145
|
"""
|
143
|
-
extended_state: QArray = QArray(
|
146
|
+
extended_state: QArray = QArray()
|
144
147
|
_vn_operator(x, q)
|
145
148
|
bind([x, q], extended_state)
|
146
149
|
qft(extended_state)
|
@@ -159,8 +162,8 @@ def qct_type2(x: QArray[QBit]) -> None:
|
|
159
162
|
Args:
|
160
163
|
x: The qubit array to apply the transform to.
|
161
164
|
"""
|
162
|
-
q = QBit(
|
163
|
-
within_apply(lambda: allocate(
|
165
|
+
q = QBit()
|
166
|
+
within_apply(lambda: allocate(q), lambda: qct_qst_type2(x, q))
|
164
167
|
|
165
168
|
|
166
169
|
@qfunc
|
@@ -174,8 +177,8 @@ def qst_type2(x: QArray[QBit]) -> None:
|
|
174
177
|
Args:
|
175
178
|
x: The qubit array to apply the transform to.
|
176
179
|
"""
|
177
|
-
q = QBit(
|
180
|
+
q = QBit()
|
178
181
|
within_apply(
|
179
|
-
lambda: (allocate(
|
182
|
+
lambda: (allocate(q), X(q)),
|
180
183
|
lambda: qct_qst_type2(x, q),
|
181
184
|
)
|
@@ -40,9 +40,9 @@ def phase_oracle(
|
|
40
40
|
predicate: A predicate function that takes a QArray of QBits and sets a single QBit |1> if the predicate is true, and |0> otherwise.
|
41
41
|
target: The target QArray of QBits to apply the phase oracle to.
|
42
42
|
"""
|
43
|
-
aux = QBit(
|
43
|
+
aux = QBit()
|
44
44
|
within_apply(
|
45
|
-
within=lambda: (allocate(
|
45
|
+
within=lambda: (allocate(aux), X(aux), H(aux)),
|
46
46
|
apply=lambda: predicate(target, aux),
|
47
47
|
)
|
48
48
|
|
@@ -64,11 +64,11 @@ def reflect_about_zero(packed_vars: QArray[QBit]) -> None:
|
|
64
64
|
Args:
|
65
65
|
packed_vars: The quantum state to reflect.
|
66
66
|
"""
|
67
|
-
msbs: QNum = QNum(
|
68
|
-
lsb = QBit(
|
67
|
+
msbs: QNum = QNum(size=packed_vars.len - 1)
|
68
|
+
lsb = QBit()
|
69
69
|
bind(packed_vars, [msbs, lsb])
|
70
70
|
within_apply(
|
71
|
-
lambda: (X(lsb), H(lsb)),
|
71
|
+
lambda: (X(lsb), H(lsb)),
|
72
72
|
lambda: control(msbs == 0, lambda: X(lsb)),
|
73
73
|
)
|
74
74
|
bind([msbs, lsb], packed_vars)
|
@@ -126,7 +126,7 @@ def grover_operator(
|
|
126
126
|
packed_vars: The state to which to apply the grover operator.
|
127
127
|
"""
|
128
128
|
oracle(packed_vars)
|
129
|
-
grover_diffuser(
|
129
|
+
grover_diffuser(space_transform, packed_vars)
|
130
130
|
U(0, 0, 0, pi, packed_vars[0])
|
131
131
|
|
132
132
|
|
@@ -149,9 +149,5 @@ def grover_search(
|
|
149
149
|
hadamard_transform(packed_vars)
|
150
150
|
power(
|
151
151
|
reps,
|
152
|
-
lambda: grover_operator(
|
153
|
-
lambda qba: oracle(qba),
|
154
|
-
lambda qba: hadamard_transform(qba),
|
155
|
-
packed_vars,
|
156
|
-
),
|
152
|
+
lambda: grover_operator(oracle, hadamard_transform, packed_vars),
|
157
153
|
)
|
@@ -58,8 +58,8 @@ def full_hea(
|
|
58
58
|
"""
|
59
59
|
repeat(
|
60
60
|
reps,
|
61
|
-
lambda r: [
|
62
|
-
repeat(
|
61
|
+
lambda r: [
|
62
|
+
repeat(
|
63
63
|
operands_1qubit.len,
|
64
64
|
lambda i1: repeat(
|
65
65
|
num_qubits,
|
@@ -77,7 +77,7 @@ def full_hea(
|
|
77
77
|
),
|
78
78
|
),
|
79
79
|
),
|
80
|
-
repeat(
|
80
|
+
repeat(
|
81
81
|
operands_2qubit.len,
|
82
82
|
lambda i2: repeat(
|
83
83
|
connectivity_map.len,
|