classiq 0.45.1__py3-none-any.whl → 0.46.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/__init__.py +0 -1
- classiq/_internals/__init__.py +20 -0
- classiq/_internals/authentication/authentication.py +11 -0
- classiq/analyzer/analyzer.py +12 -10
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
- classiq/applications/libraries/qmci_library.py +4 -9
- classiq/execution/execution_session.py +68 -7
- classiq/executor.py +14 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +189 -0
- classiq/interface/backend/quantum_backend_providers.py +38 -0
- classiq/interface/debug_info/debug_info.py +22 -2
- classiq/interface/exceptions.py +16 -1
- classiq/interface/executor/execution_preferences.py +18 -0
- classiq/interface/generator/application_apis/chemistry_declarations.py +1 -177
- classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +0 -12
- classiq/interface/generator/application_apis/finance_declarations.py +8 -43
- classiq/interface/generator/application_apis/qsvm_declarations.py +0 -78
- classiq/interface/generator/builtin_api_builder.py +0 -3
- classiq/interface/generator/functions/__init__.py +0 -2
- classiq/interface/generator/functions/builtins/__init__.py +0 -15
- classiq/interface/generator/generated_circuit_data.py +2 -0
- classiq/interface/generator/hardware/hardware_data.py +37 -0
- classiq/interface/generator/model/constraints.py +18 -1
- classiq/interface/generator/model/preferences/preferences.py +53 -1
- classiq/interface/generator/model/quantum_register.py +1 -1
- classiq/interface/generator/quantum_program.py +10 -2
- classiq/interface/generator/transpiler_basis_gates.py +4 -0
- classiq/interface/generator/types/builtin_enum_declarations.py +136 -21
- classiq/interface/generator/types/enum_declaration.py +1 -3
- classiq/interface/generator/types/struct_declaration.py +1 -3
- classiq/interface/hardware.py +5 -0
- classiq/interface/ide/visual_model.py +1 -1
- classiq/interface/model/classical_parameter_declaration.py +6 -0
- classiq/interface/model/inplace_binary_operation.py +0 -14
- classiq/interface/model/model.py +1 -18
- classiq/interface/model/port_declaration.py +4 -2
- classiq/interface/model/quantum_function_declaration.py +19 -6
- classiq/interface/model/quantum_lambda_function.py +11 -1
- classiq/interface/model/quantum_variable_declaration.py +1 -1
- classiq/model_expansions/__init__.py +0 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +250 -0
- classiq/model_expansions/capturing/__init__.py +0 -0
- classiq/model_expansions/capturing/captured_var_manager.py +50 -0
- classiq/model_expansions/capturing/mangling_utils.py +17 -0
- classiq/model_expansions/capturing/propagated_var_stack.py +180 -0
- classiq/model_expansions/closure.py +160 -0
- classiq/model_expansions/debug_flag.py +3 -0
- classiq/model_expansions/evaluators/__init__.py +0 -0
- classiq/model_expansions/evaluators/arg_type_match.py +160 -0
- classiq/model_expansions/evaluators/argument_types.py +42 -0
- classiq/model_expansions/evaluators/classical_expression.py +36 -0
- classiq/model_expansions/evaluators/control.py +144 -0
- classiq/model_expansions/evaluators/parameter_types.py +227 -0
- classiq/model_expansions/evaluators/quantum_type_utils.py +235 -0
- classiq/model_expansions/evaluators/type_type_match.py +90 -0
- classiq/model_expansions/expression_evaluator.py +125 -0
- classiq/model_expansions/expression_renamer.py +76 -0
- classiq/model_expansions/function_builder.py +192 -0
- classiq/model_expansions/generative_functions.py +101 -0
- classiq/model_expansions/interpreter.py +365 -0
- classiq/model_expansions/model_tables.py +105 -0
- classiq/model_expansions/quantum_operations/__init__.py +19 -0
- classiq/model_expansions/quantum_operations/bind.py +64 -0
- classiq/model_expansions/quantum_operations/classicalif.py +39 -0
- classiq/model_expansions/quantum_operations/control.py +235 -0
- classiq/model_expansions/quantum_operations/emitter.py +215 -0
- classiq/model_expansions/quantum_operations/expression_operation.py +218 -0
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +250 -0
- classiq/model_expansions/quantum_operations/invert.py +38 -0
- classiq/model_expansions/quantum_operations/power.py +74 -0
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +174 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +15 -0
- classiq/model_expansions/quantum_operations/repeat.py +33 -0
- classiq/model_expansions/quantum_operations/variable_decleration.py +28 -0
- classiq/model_expansions/quantum_operations/within_apply.py +46 -0
- classiq/model_expansions/scope.py +226 -0
- classiq/model_expansions/scope_initialization.py +136 -0
- classiq/model_expansions/sympy_conversion/__init__.py +0 -0
- classiq/model_expansions/sympy_conversion/arithmetics.py +49 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +150 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +113 -0
- classiq/model_expansions/utils/__init__.py +0 -0
- classiq/model_expansions/utils/counted_name_allocator.py +11 -0
- classiq/model_expansions/visitors/__init__.py +0 -0
- classiq/model_expansions/visitors/boolean_expression_transformers.py +214 -0
- classiq/model_expansions/visitors/variable_references.py +115 -0
- classiq/qmod/__init__.py +1 -3
- classiq/qmod/builtins/enums.py +33 -2
- classiq/qmod/builtins/functions/__init__.py +251 -0
- classiq/qmod/builtins/functions/amplitude_estimation.py +26 -0
- classiq/qmod/builtins/functions/arithmetic.py +68 -0
- classiq/qmod/builtins/functions/benchmarking.py +8 -0
- classiq/qmod/builtins/functions/chemistry.py +91 -0
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +105 -0
- classiq/qmod/builtins/functions/exponentiation.py +110 -0
- classiq/qmod/builtins/functions/finance.py +34 -0
- classiq/qmod/builtins/functions/grover.py +179 -0
- classiq/qmod/builtins/functions/hea.py +59 -0
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +65 -0
- classiq/qmod/builtins/functions/modular_exponentiation.py +137 -0
- classiq/qmod/builtins/functions/operators.py +22 -0
- classiq/qmod/builtins/functions/qaoa_penalty.py +116 -0
- classiq/qmod/builtins/functions/qft.py +23 -0
- classiq/qmod/builtins/functions/qpe.py +39 -0
- classiq/qmod/builtins/functions/qsvm.py +24 -0
- classiq/qmod/builtins/functions/qsvt.py +136 -0
- classiq/qmod/builtins/functions/standard_gates.py +739 -0
- classiq/qmod/builtins/functions/state_preparation.py +356 -0
- classiq/qmod/builtins/functions/swap_test.py +25 -0
- classiq/qmod/builtins/structs.py +50 -28
- classiq/qmod/cparam.py +64 -0
- classiq/qmod/create_model_function.py +190 -0
- classiq/qmod/declaration_inferrer.py +52 -81
- classiq/qmod/expression_query.py +16 -0
- classiq/qmod/generative.py +48 -0
- classiq/qmod/model_state_container.py +1 -2
- classiq/qmod/native/pretty_printer.py +7 -11
- classiq/qmod/pretty_print/pretty_printer.py +7 -11
- classiq/qmod/python_classical_type.py +67 -0
- classiq/qmod/qfunc.py +19 -4
- classiq/qmod/qmod_parameter.py +15 -64
- classiq/qmod/qmod_variable.py +27 -45
- classiq/qmod/quantum_callable.py +1 -1
- classiq/qmod/quantum_expandable.py +10 -4
- classiq/qmod/quantum_function.py +22 -40
- classiq/qmod/semantics/error_manager.py +22 -10
- classiq/qmod/semantics/static_semantics_visitor.py +10 -12
- classiq/qmod/semantics/validation/types_validation.py +6 -7
- classiq/qmod/utilities.py +2 -2
- classiq/qmod/write_qmod.py +14 -0
- classiq/show.py +10 -0
- classiq/synthesis.py +46 -2
- {classiq-0.45.1.dist-info → classiq-0.46.0.dist-info}/METADATA +1 -1
- {classiq-0.45.1.dist-info → classiq-0.46.0.dist-info}/RECORD +138 -74
- classiq/interface/generator/functions/builtins/core_library/__init__.py +0 -16
- classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +0 -710
- classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +0 -105
- classiq/interface/generator/functions/builtins/open_lib_functions.py +0 -2489
- classiq/interface/generator/functions/builtins/quantum_operators.py +0 -24
- classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
- classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +0 -21
- classiq/qmod/builtins/functions.py +0 -1029
- {classiq-0.45.1.dist-info → classiq-0.46.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
from contextlib import contextmanager
|
2
|
+
from dataclasses import dataclass, field
|
3
|
+
from typing import Dict, Generic, Iterable, Iterator, List, Optional, Sequence, TypeVar
|
4
|
+
|
5
|
+
from classiq.interface.exceptions import (
|
6
|
+
ClassiqExpansionError,
|
7
|
+
ClassiqInternalExpansionError,
|
8
|
+
)
|
9
|
+
from classiq.interface.generator.compiler_keywords import (
|
10
|
+
EXPANDED_KEYWORD,
|
11
|
+
LAMBDA_KEYWORD,
|
12
|
+
)
|
13
|
+
from classiq.interface.generator.functions.builtins.internal_operators import (
|
14
|
+
WITHIN_APPLY_NAME,
|
15
|
+
)
|
16
|
+
from classiq.interface.generator.functions.port_declaration import (
|
17
|
+
PortDeclarationDirection,
|
18
|
+
)
|
19
|
+
from classiq.interface.model.model import MAIN_FUNCTION_NAME
|
20
|
+
from classiq.interface.model.native_function_definition import (
|
21
|
+
NativeFunctionDefinition,
|
22
|
+
)
|
23
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
24
|
+
from classiq.interface.model.quantum_function_declaration import (
|
25
|
+
PositionalArg,
|
26
|
+
)
|
27
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
28
|
+
|
29
|
+
from classiq.model_expansions.capturing.captured_var_manager import update_captured_vars
|
30
|
+
from classiq.model_expansions.capturing.mangling_utils import demangle_name
|
31
|
+
from classiq.model_expansions.closure import Closure, FunctionClosure
|
32
|
+
|
33
|
+
ClosureType = TypeVar("ClosureType", bound=Closure)
|
34
|
+
|
35
|
+
|
36
|
+
@dataclass
|
37
|
+
class Block:
|
38
|
+
statements: List[QuantumStatement] = field(default_factory=list)
|
39
|
+
captured_vars: List[PortDeclaration] = field(default_factory=list)
|
40
|
+
|
41
|
+
|
42
|
+
@dataclass
|
43
|
+
class OperationContext(Generic[ClosureType]):
|
44
|
+
closure: ClosureType
|
45
|
+
blocks: Dict[str, Block] = field(default_factory=dict)
|
46
|
+
|
47
|
+
@property
|
48
|
+
def name(self) -> str:
|
49
|
+
return self.closure.name
|
50
|
+
|
51
|
+
@property
|
52
|
+
def positional_arg_declarations(self) -> Sequence[PositionalArg]:
|
53
|
+
return self.closure.positional_arg_declarations
|
54
|
+
|
55
|
+
def statements(self, block_name: str) -> List[QuantumStatement]:
|
56
|
+
return self.blocks[block_name].statements
|
57
|
+
|
58
|
+
|
59
|
+
@dataclass
|
60
|
+
class FunctionContext(OperationContext[FunctionClosure]):
|
61
|
+
@classmethod
|
62
|
+
def create(cls, original_function: FunctionClosure) -> "FunctionContext":
|
63
|
+
return cls(original_function, {"body": Block()})
|
64
|
+
|
65
|
+
@property
|
66
|
+
def body(self) -> List[QuantumStatement]:
|
67
|
+
return self.statements("body")
|
68
|
+
|
69
|
+
@property
|
70
|
+
def captured_vars(self) -> List[PortDeclaration]:
|
71
|
+
return self.blocks["body"].captured_vars
|
72
|
+
|
73
|
+
@property
|
74
|
+
def is_lambda(self) -> bool:
|
75
|
+
return self.closure.is_lambda
|
76
|
+
|
77
|
+
|
78
|
+
class OperationBuilder:
|
79
|
+
def __init__(self) -> None:
|
80
|
+
self._operations: List[OperationContext] = []
|
81
|
+
self._blocks: List[str] = []
|
82
|
+
self._counter = 0
|
83
|
+
|
84
|
+
@property
|
85
|
+
def current_operation(self) -> Closure:
|
86
|
+
return self._operations[-1].closure
|
87
|
+
|
88
|
+
@property
|
89
|
+
def current_function(self) -> FunctionClosure:
|
90
|
+
for operation in reversed(self._operations):
|
91
|
+
if isinstance(operation.closure, FunctionClosure):
|
92
|
+
return operation.closure
|
93
|
+
raise ClassiqInternalExpansionError("No function found")
|
94
|
+
|
95
|
+
@property
|
96
|
+
def _current_statements(self) -> List[QuantumStatement]:
|
97
|
+
return self._operations[-1].blocks[self._blocks[-1]].statements
|
98
|
+
|
99
|
+
def emit_statement(self, statement: QuantumStatement) -> None:
|
100
|
+
self._current_statements.append(statement)
|
101
|
+
|
102
|
+
@property
|
103
|
+
def current_statement(self) -> QuantumStatement:
|
104
|
+
return self._current_statements[-1]
|
105
|
+
|
106
|
+
def add_captured_vars(self, captured_vars: Iterable[PortDeclaration]) -> None:
|
107
|
+
self._operations[-1].blocks[self._blocks[-1]].captured_vars.extend(
|
108
|
+
captured_vars
|
109
|
+
)
|
110
|
+
|
111
|
+
@contextmanager
|
112
|
+
def block_context(self, block_name: str) -> Iterator[None]:
|
113
|
+
self._blocks.append(block_name)
|
114
|
+
self._operations[-1].blocks[block_name] = Block()
|
115
|
+
yield
|
116
|
+
self._blocks.pop()
|
117
|
+
|
118
|
+
@contextmanager
|
119
|
+
def operation_context(
|
120
|
+
self, original_operation: Closure
|
121
|
+
) -> Iterator[OperationContext]:
|
122
|
+
context: OperationContext
|
123
|
+
if isinstance(original_operation, FunctionClosure):
|
124
|
+
context = FunctionContext.create(original_operation)
|
125
|
+
else:
|
126
|
+
context = OperationContext(closure=original_operation)
|
127
|
+
self._operations.append(context)
|
128
|
+
yield context
|
129
|
+
self._update_captured_vars()
|
130
|
+
self._operations.pop()
|
131
|
+
|
132
|
+
def _update_captured_vars(self) -> None:
|
133
|
+
for block in self._operations[-1].blocks.values():
|
134
|
+
block.captured_vars = update_captured_vars(block.captured_vars)
|
135
|
+
if not self._is_within_apply_context():
|
136
|
+
validate_captured_vars(block.captured_vars)
|
137
|
+
|
138
|
+
def is_compute_context(self) -> bool:
|
139
|
+
return self._is_within_apply_context("within")
|
140
|
+
|
141
|
+
def _is_within_apply_context(self, block_name: Optional[str] = None) -> bool:
|
142
|
+
return self._is_op_within_apply_context(block_name, -1) or (
|
143
|
+
len(self._operations) > 1
|
144
|
+
and isinstance(self._operations[-1], FunctionContext)
|
145
|
+
and self._is_op_within_apply_context(block_name, -2)
|
146
|
+
)
|
147
|
+
|
148
|
+
def _is_op_within_apply_context(
|
149
|
+
self, block_name: Optional[str], index: int
|
150
|
+
) -> bool:
|
151
|
+
return self._operations[index].name == WITHIN_APPLY_NAME and (
|
152
|
+
block_name is None or self._blocks[index] == block_name
|
153
|
+
)
|
154
|
+
|
155
|
+
def create_definition(
|
156
|
+
self, function_context: FunctionContext
|
157
|
+
) -> NativeFunctionDefinition:
|
158
|
+
name = function_context.name
|
159
|
+
if name != MAIN_FUNCTION_NAME:
|
160
|
+
name = f"{name}_{LAMBDA_KEYWORD + '_0_0_' if function_context.is_lambda else ''}{EXPANDED_KEYWORD}_{self._counter}"
|
161
|
+
self._counter += 1
|
162
|
+
|
163
|
+
new_parameters: List[PortDeclaration] = [
|
164
|
+
param
|
165
|
+
for param in function_context.positional_arg_declarations
|
166
|
+
if isinstance(param, PortDeclaration)
|
167
|
+
] + function_context.captured_vars
|
168
|
+
|
169
|
+
return NativeFunctionDefinition(
|
170
|
+
name=name,
|
171
|
+
body=function_context.body,
|
172
|
+
positional_arg_declarations=new_parameters,
|
173
|
+
)
|
174
|
+
|
175
|
+
|
176
|
+
def validate_captured_vars(captured_vars: List[PortDeclaration]) -> None:
|
177
|
+
if input_captured := [
|
178
|
+
demangle_name(var.name)
|
179
|
+
for var in captured_vars
|
180
|
+
if var.direction is PortDeclarationDirection.Input
|
181
|
+
]:
|
182
|
+
raise ClassiqExpansionError(
|
183
|
+
f"Captured quantum variables {input_captured!r} cannot be used as inputs"
|
184
|
+
)
|
185
|
+
if output_captured := [
|
186
|
+
demangle_name(var.name)
|
187
|
+
for var in captured_vars
|
188
|
+
if var.direction is PortDeclarationDirection.Output
|
189
|
+
]:
|
190
|
+
raise ClassiqExpansionError(
|
191
|
+
f"Captured quantum variables {output_captured!r} cannot be used as outputs"
|
192
|
+
)
|
@@ -0,0 +1,101 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Any, List
|
2
|
+
|
3
|
+
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
4
|
+
QmodStructInstance,
|
5
|
+
)
|
6
|
+
from classiq.interface.generator.functions.type_name import Struct
|
7
|
+
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
8
|
+
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
9
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
10
|
+
from classiq.interface.model.quantum_function_declaration import (
|
11
|
+
PositionalArg,
|
12
|
+
QuantumFunctionDeclaration,
|
13
|
+
QuantumOperandDeclaration,
|
14
|
+
)
|
15
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
16
|
+
|
17
|
+
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
18
|
+
from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
19
|
+
from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
|
20
|
+
from classiq.qmod.model_state_container import QMODULE
|
21
|
+
from classiq.qmod.qmod_parameter import CParamStruct
|
22
|
+
from classiq.qmod.qmod_variable import get_qvar
|
23
|
+
from classiq.qmod.quantum_callable import QCallable
|
24
|
+
from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
|
25
|
+
from classiq.qmod.quantum_function import QFunc
|
26
|
+
from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
|
27
|
+
|
28
|
+
if TYPE_CHECKING:
|
29
|
+
from classiq.model_expansions.interpreter import Interpreter
|
30
|
+
|
31
|
+
|
32
|
+
def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated) -> Any:
|
33
|
+
if isinstance(param, PortDeclaration):
|
34
|
+
quantum_symbol = evaluated.as_type(QuantumSymbol)
|
35
|
+
return get_qvar(quantum_symbol.quantum_type, quantum_symbol.handle)
|
36
|
+
if isinstance(param, QuantumOperandDeclaration):
|
37
|
+
if param.is_list:
|
38
|
+
func_list: List[FunctionClosure] = evaluated.as_type(list)
|
39
|
+
return [
|
40
|
+
QTerminalCallable(
|
41
|
+
QuantumFunctionDeclaration(
|
42
|
+
name=param.name,
|
43
|
+
positional_arg_declarations=param.positional_arg_declarations,
|
44
|
+
),
|
45
|
+
index_=idx,
|
46
|
+
)
|
47
|
+
for idx, func in enumerate(func_list)
|
48
|
+
]
|
49
|
+
else:
|
50
|
+
func = evaluated.as_type(FunctionClosure)
|
51
|
+
return QTerminalCallable(
|
52
|
+
QuantumFunctionDeclaration(
|
53
|
+
name=param.name if func.is_lambda else func.name,
|
54
|
+
positional_arg_declarations=func.positional_arg_declarations,
|
55
|
+
),
|
56
|
+
)
|
57
|
+
classical_value = evaluated.value
|
58
|
+
if isinstance(classical_value, QmodStructInstance):
|
59
|
+
return CParamStruct(
|
60
|
+
expr=param.name,
|
61
|
+
struct_type=Struct(name=classical_value.struct_declaration.name),
|
62
|
+
qmodule=QMODULE,
|
63
|
+
)
|
64
|
+
return classical_value
|
65
|
+
|
66
|
+
|
67
|
+
class _InterpreterExpandable(QFunc):
|
68
|
+
def __init__(self, interpreter: "Interpreter"):
|
69
|
+
super().__init__(lambda: None)
|
70
|
+
self._interpreter = interpreter
|
71
|
+
|
72
|
+
def append_statement_to_body(self, stmt: QuantumStatement) -> None:
|
73
|
+
current_function = self._interpreter._builder.current_function
|
74
|
+
dummy_function = NativeFunctionDefinition(
|
75
|
+
name=current_function.name,
|
76
|
+
positional_arg_declarations=current_function.positional_arg_declarations,
|
77
|
+
body=self._interpreter._builder._current_statements + [stmt],
|
78
|
+
)
|
79
|
+
resolve_function_calls(
|
80
|
+
dummy_function,
|
81
|
+
nameables_to_dict(self._interpreter._get_function_declarations()),
|
82
|
+
)
|
83
|
+
stmt = dummy_function.body[-1]
|
84
|
+
self._interpreter.emit_statement(stmt)
|
85
|
+
|
86
|
+
|
87
|
+
def emit_generative_statements(
|
88
|
+
interpreter: "Interpreter",
|
89
|
+
operation: GenerativeFunctionClosure,
|
90
|
+
args: List[Evaluated],
|
91
|
+
) -> None:
|
92
|
+
python_qmod_args = [
|
93
|
+
translate_ast_arg_to_python_qmod(param, arg)
|
94
|
+
for param, arg in zip(operation.positional_arg_declarations, args)
|
95
|
+
]
|
96
|
+
interpreter_expandable = _InterpreterExpandable(interpreter)
|
97
|
+
QExpandable.STACK.append(interpreter_expandable)
|
98
|
+
QCallable.CURRENT_EXPANDABLE = interpreter_expandable
|
99
|
+
set_frontend_interpreter(interpreter)
|
100
|
+
with interpreter._builder.block_context("body"), generative_mode_context(True):
|
101
|
+
operation.generative_function._py_callable(*python_qmod_args)
|
@@ -0,0 +1,365 @@
|
|
1
|
+
import copy
|
2
|
+
from contextlib import contextmanager, nullcontext
|
3
|
+
from functools import singledispatchmethod
|
4
|
+
from typing import Any, Iterator, List, Optional, Sequence, Tuple, Type, cast
|
5
|
+
|
6
|
+
import numpy as np
|
7
|
+
from numpy.random import permutation
|
8
|
+
|
9
|
+
from classiq.interface.exceptions import (
|
10
|
+
ClassiqExpansionError,
|
11
|
+
ClassiqInternalExpansionError,
|
12
|
+
)
|
13
|
+
from classiq.interface.generator.expressions.expression import Expression
|
14
|
+
from classiq.interface.model.bind_operation import BindOperation
|
15
|
+
from classiq.interface.model.classical_if import ClassicalIf
|
16
|
+
from classiq.interface.model.control import Control
|
17
|
+
from classiq.interface.model.handle_binding import (
|
18
|
+
FieldHandleBinding,
|
19
|
+
HandleBinding,
|
20
|
+
SlicedHandleBinding,
|
21
|
+
SubscriptHandleBinding,
|
22
|
+
)
|
23
|
+
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
24
|
+
from classiq.interface.model.invert import Invert
|
25
|
+
from classiq.interface.model.model import Model
|
26
|
+
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
27
|
+
from classiq.interface.model.power import Power
|
28
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
29
|
+
QuantumAssignmentOperation,
|
30
|
+
)
|
31
|
+
from classiq.interface.model.quantum_function_call import (
|
32
|
+
OperandIdentifier,
|
33
|
+
QuantumFunctionCall,
|
34
|
+
)
|
35
|
+
from classiq.interface.model.quantum_function_declaration import (
|
36
|
+
NamedParamsQuantumFunctionDeclaration,
|
37
|
+
QuantumFunctionDeclaration,
|
38
|
+
)
|
39
|
+
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
40
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
41
|
+
from classiq.interface.model.repeat import Repeat
|
42
|
+
from classiq.interface.model.variable_declaration_statement import (
|
43
|
+
VariableDeclarationStatement,
|
44
|
+
)
|
45
|
+
from classiq.interface.model.within_apply_operation import WithinApply
|
46
|
+
|
47
|
+
from classiq.model_expansions.capturing.propagated_var_stack import PropagatedVarStack
|
48
|
+
from classiq.model_expansions.closure import (
|
49
|
+
Closure,
|
50
|
+
FunctionClosure,
|
51
|
+
GenerativeFunctionClosure,
|
52
|
+
)
|
53
|
+
from classiq.model_expansions.debug_flag import debug_mode
|
54
|
+
from classiq.model_expansions.evaluators.classical_expression import (
|
55
|
+
evaluate_classical_expression,
|
56
|
+
)
|
57
|
+
from classiq.model_expansions.expression_renamer import ExpressionRenamer
|
58
|
+
from classiq.model_expansions.function_builder import (
|
59
|
+
FunctionContext,
|
60
|
+
OperationBuilder,
|
61
|
+
OperationContext,
|
62
|
+
)
|
63
|
+
from classiq.model_expansions.generative_functions import emit_generative_statements
|
64
|
+
from classiq.model_expansions.quantum_operations import (
|
65
|
+
BindEmitter,
|
66
|
+
ClassicalIfEmitter,
|
67
|
+
ControlEmitter,
|
68
|
+
InplaceBinaryOperationEmitter,
|
69
|
+
InvertEmitter,
|
70
|
+
PowerEmitter,
|
71
|
+
QuantumAssignmentOperationEmitter,
|
72
|
+
QuantumFunctionCallEmitter,
|
73
|
+
RepeatEmitter,
|
74
|
+
VariableDeclarationStatementEmitter,
|
75
|
+
WithinApplyEmitter,
|
76
|
+
)
|
77
|
+
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
78
|
+
from classiq.model_expansions.scope_initialization import (
|
79
|
+
add_entry_point_params_to_scope,
|
80
|
+
get_main_renamer,
|
81
|
+
init_top_level_scope,
|
82
|
+
)
|
83
|
+
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
84
|
+
from classiq.qmod.builtins.functions import permute
|
85
|
+
from classiq.qmod.generative import is_generative_mode
|
86
|
+
from classiq.qmod.quantum_function import GenerativeQFunc
|
87
|
+
from classiq.qmod.semantics.error_manager import ErrorManager
|
88
|
+
|
89
|
+
STATEMENT_TYPES_FOR_SOURCE_REFERENCE_PROPAGATION: Tuple[Type[QuantumStatement], ...] = (
|
90
|
+
QuantumFunctionCall,
|
91
|
+
VariableDeclarationStatement,
|
92
|
+
QuantumAssignmentOperation,
|
93
|
+
)
|
94
|
+
|
95
|
+
|
96
|
+
class Interpreter:
|
97
|
+
def __init__(
|
98
|
+
self, model: Model, generative_functions: Optional[List[GenerativeQFunc]] = None
|
99
|
+
) -> None:
|
100
|
+
self._model = model
|
101
|
+
self._current_scope = Scope()
|
102
|
+
self._builder = OperationBuilder()
|
103
|
+
self._expanded_functions: List[NativeFunctionDefinition] = []
|
104
|
+
self._propagated_var_stack = PropagatedVarStack(
|
105
|
+
self._current_scope, self._builder
|
106
|
+
)
|
107
|
+
|
108
|
+
self._main_renamer: ExpressionRenamer = get_main_renamer(self._model.functions)
|
109
|
+
|
110
|
+
if generative_functions is None:
|
111
|
+
generative_functions = []
|
112
|
+
self._generative_functions = generative_functions
|
113
|
+
init_top_level_scope(model, generative_functions, self._current_scope)
|
114
|
+
|
115
|
+
self._counted_name_allocator = CountedNameAllocator()
|
116
|
+
self._error_manager: ErrorManager = ErrorManager()
|
117
|
+
|
118
|
+
@contextmanager
|
119
|
+
def _scope_guard(self, scope: Scope) -> Iterator[None]:
|
120
|
+
"""This manager restores both `scope` and `self._current_scope` to their previous values."""
|
121
|
+
scope_data = copy.copy(scope.data)
|
122
|
+
prev_context_scope_data = copy.copy(self._current_scope.data)
|
123
|
+
|
124
|
+
prev_context_scope = self._current_scope
|
125
|
+
self._current_scope = scope
|
126
|
+
self._propagated_var_stack.set_scope(scope)
|
127
|
+
yield
|
128
|
+
prev_context_scope.data = prev_context_scope_data
|
129
|
+
self._current_scope = prev_context_scope
|
130
|
+
self._propagated_var_stack.set_scope(prev_context_scope)
|
131
|
+
|
132
|
+
scope.data = scope_data
|
133
|
+
|
134
|
+
def _expand_main_func(self) -> None:
|
135
|
+
main_closure = FunctionClosure.create(
|
136
|
+
name=self._model.main_func.name,
|
137
|
+
positional_arg_declarations=self._model.main_func.positional_arg_declarations,
|
138
|
+
body=self._model.main_func.body,
|
139
|
+
scope=Scope(parent=self._current_scope),
|
140
|
+
expr_renamer=self._main_renamer,
|
141
|
+
)
|
142
|
+
|
143
|
+
add_entry_point_params_to_scope(
|
144
|
+
main_closure.positional_arg_declarations, main_closure
|
145
|
+
)
|
146
|
+
context = self._expand_operation(main_closure)
|
147
|
+
self._expanded_functions.append(
|
148
|
+
self._builder.create_definition(cast(FunctionContext, context))
|
149
|
+
)
|
150
|
+
|
151
|
+
def expand(self) -> Model:
|
152
|
+
try:
|
153
|
+
with self._error_manager.call("main"):
|
154
|
+
self._expand_main_func()
|
155
|
+
except Exception as e:
|
156
|
+
if isinstance(e, ClassiqInternalExpansionError) or debug_mode.get():
|
157
|
+
raise e
|
158
|
+
prefix = ""
|
159
|
+
if not isinstance(e, ClassiqExpansionError):
|
160
|
+
prefix = f"{type(e).__name__}: "
|
161
|
+
self._error_manager.add_error(f"{prefix}{e}")
|
162
|
+
finally:
|
163
|
+
self._error_manager.report_errors(ClassiqExpansionError)
|
164
|
+
|
165
|
+
return Model(
|
166
|
+
constraints=self._model.constraints,
|
167
|
+
preferences=self._model.preferences,
|
168
|
+
classical_execution_code=self._model.classical_execution_code,
|
169
|
+
execution_preferences=self._model.execution_preferences,
|
170
|
+
functions=self._expanded_functions,
|
171
|
+
constants=self._model.constants,
|
172
|
+
enums=self._model.enums,
|
173
|
+
types=self._model.types,
|
174
|
+
qstructs=self._model.qstructs,
|
175
|
+
debug_info=self._model.debug_info,
|
176
|
+
)
|
177
|
+
|
178
|
+
@singledispatchmethod
|
179
|
+
def evaluate(self, expression: Any) -> Evaluated:
|
180
|
+
raise NotImplementedError(f"Cannot evaluate {expression!r}")
|
181
|
+
|
182
|
+
@evaluate.register
|
183
|
+
def evaluate_classical_expression(self, expression: Expression) -> Evaluated:
|
184
|
+
return evaluate_classical_expression(expression, self._current_scope)
|
185
|
+
|
186
|
+
@evaluate.register
|
187
|
+
def evaluate_identifier(self, identifier: str) -> Evaluated:
|
188
|
+
return self._current_scope[identifier]
|
189
|
+
|
190
|
+
@evaluate.register
|
191
|
+
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
192
|
+
renamed_params = [
|
193
|
+
param.rename(function.get_rename_params()[idx])
|
194
|
+
for idx, param in enumerate(function.func_decl.positional_arg_declarations)
|
195
|
+
]
|
196
|
+
func_decl = NamedParamsQuantumFunctionDeclaration(
|
197
|
+
name=function.func_decl.name or "<lambda>",
|
198
|
+
positional_arg_declarations=renamed_params,
|
199
|
+
)
|
200
|
+
|
201
|
+
closure_class: Type[FunctionClosure]
|
202
|
+
extra_args: dict[str, Any]
|
203
|
+
if is_generative_mode():
|
204
|
+
closure_class = GenerativeFunctionClosure
|
205
|
+
extra_args = {
|
206
|
+
"generative_function": GenerativeQFunc(function.py_callable, func_decl)
|
207
|
+
}
|
208
|
+
else:
|
209
|
+
closure_class = FunctionClosure
|
210
|
+
extra_args = {}
|
211
|
+
|
212
|
+
return Evaluated(
|
213
|
+
value=closure_class.create(
|
214
|
+
name=func_decl.name,
|
215
|
+
positional_arg_declarations=func_decl.positional_arg_declarations,
|
216
|
+
body=function.body,
|
217
|
+
scope=Scope(parent=self._current_scope),
|
218
|
+
is_lambda=True,
|
219
|
+
**extra_args,
|
220
|
+
),
|
221
|
+
defining_function=self._builder.current_function,
|
222
|
+
)
|
223
|
+
|
224
|
+
@evaluate.register
|
225
|
+
def evaluate_handle_binding(self, handle_binding: HandleBinding) -> Evaluated:
|
226
|
+
return self.evaluate(handle_binding.name)
|
227
|
+
|
228
|
+
@evaluate.register
|
229
|
+
def evaluate_sliced_handle_binding(
|
230
|
+
self, sliced_handle_binding: SlicedHandleBinding
|
231
|
+
) -> Evaluated:
|
232
|
+
quantum_variable = self.evaluate(sliced_handle_binding.base_handle).as_type(
|
233
|
+
QuantumSymbol
|
234
|
+
)
|
235
|
+
start = self.evaluate(sliced_handle_binding.start).as_type(int)
|
236
|
+
end = self.evaluate(sliced_handle_binding.end).as_type(int)
|
237
|
+
return Evaluated(value=quantum_variable[start:end])
|
238
|
+
|
239
|
+
@evaluate.register
|
240
|
+
def evaluate_list(self, value: list) -> Evaluated:
|
241
|
+
return Evaluated(value=[self.evaluate(arg).value for arg in value])
|
242
|
+
|
243
|
+
@evaluate.register
|
244
|
+
def evaluate_subscript_handle(self, subscript: SubscriptHandleBinding) -> Evaluated:
|
245
|
+
base_value = self.evaluate(subscript.base_handle)
|
246
|
+
index_value = self.evaluate(subscript.index).as_type(int)
|
247
|
+
return Evaluated(value=base_value.value[index_value])
|
248
|
+
|
249
|
+
@evaluate.register
|
250
|
+
def evaluate_subscript_operand(self, subscript: OperandIdentifier) -> Evaluated:
|
251
|
+
base_value = self.evaluate(subscript.name)
|
252
|
+
index_value = self.evaluate(subscript.index).as_type(int)
|
253
|
+
return Evaluated(value=base_value.value[index_value])
|
254
|
+
|
255
|
+
@evaluate.register
|
256
|
+
def evaluate_field_access(self, field_access: FieldHandleBinding) -> Evaluated:
|
257
|
+
base_value = self.evaluate(field_access.base_handle)
|
258
|
+
return Evaluated(value=base_value.value.fields[field_access.field])
|
259
|
+
|
260
|
+
@singledispatchmethod
|
261
|
+
def emit(self, statement: QuantumStatement) -> None:
|
262
|
+
raise NotImplementedError(f"Cannot emit {statement!r}")
|
263
|
+
|
264
|
+
@emit.register
|
265
|
+
def emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
266
|
+
QuantumFunctionCallEmitter(self).emit(call)
|
267
|
+
|
268
|
+
@emit.register
|
269
|
+
def emit_bind(self, bind: BindOperation) -> None:
|
270
|
+
BindEmitter(self).emit(bind)
|
271
|
+
|
272
|
+
@emit.register
|
273
|
+
def emit_quantum_assignment_operation(self, op: QuantumAssignmentOperation) -> None:
|
274
|
+
QuantumAssignmentOperationEmitter(self).emit(op)
|
275
|
+
|
276
|
+
@emit.register
|
277
|
+
def emit_inplace_binary_operation(self, operation: InplaceBinaryOperation) -> None:
|
278
|
+
InplaceBinaryOperationEmitter(self).emit(operation)
|
279
|
+
|
280
|
+
@emit.register
|
281
|
+
def emit_variable_declaration(
|
282
|
+
self, variable_declaration: VariableDeclarationStatement
|
283
|
+
) -> None:
|
284
|
+
VariableDeclarationStatementEmitter(self).emit(variable_declaration)
|
285
|
+
|
286
|
+
@emit.register
|
287
|
+
def emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
288
|
+
ClassicalIfEmitter(self).emit(classical_if)
|
289
|
+
|
290
|
+
@emit.register
|
291
|
+
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
292
|
+
WithinApplyEmitter(self).emit(within_apply)
|
293
|
+
|
294
|
+
@emit.register
|
295
|
+
def emit_invert(self, invert: Invert) -> None:
|
296
|
+
InvertEmitter(self).emit(invert)
|
297
|
+
|
298
|
+
@emit.register
|
299
|
+
def emit_repeat(self, repeat: Repeat) -> None:
|
300
|
+
RepeatEmitter(self).emit(repeat)
|
301
|
+
|
302
|
+
@emit.register
|
303
|
+
def emit_control(self, control: Control) -> None:
|
304
|
+
ControlEmitter(self).emit(control)
|
305
|
+
|
306
|
+
@emit.register
|
307
|
+
def emit_power(self, power: Power) -> None:
|
308
|
+
PowerEmitter(self).emit(power)
|
309
|
+
|
310
|
+
def _expand_block(self, block: Sequence[QuantumStatement], block_name: str) -> None:
|
311
|
+
with self._builder.block_context(block_name):
|
312
|
+
for statement in block:
|
313
|
+
self.emit_statement(statement)
|
314
|
+
|
315
|
+
def emit_statement(self, statement: QuantumStatement) -> None:
|
316
|
+
with (
|
317
|
+
self._error_manager.node_context(statement)
|
318
|
+
if statement.source_ref is not None
|
319
|
+
else nullcontext()
|
320
|
+
):
|
321
|
+
self.emit(statement)
|
322
|
+
if isinstance(
|
323
|
+
statement,
|
324
|
+
STATEMENT_TYPES_FOR_SOURCE_REFERENCE_PROPAGATION,
|
325
|
+
):
|
326
|
+
self._builder.current_statement.source_ref = statement.source_ref
|
327
|
+
|
328
|
+
def _expand_operation(self, operation: Closure) -> OperationContext:
|
329
|
+
with self._builder.operation_context(operation) as context:
|
330
|
+
if isinstance(operation, FunctionClosure) and operation.name == "permute":
|
331
|
+
# special expansion since permute is generative
|
332
|
+
with self._scope_guard(operation.scope):
|
333
|
+
self._expand_permute()
|
334
|
+
elif isinstance(operation, GenerativeFunctionClosure):
|
335
|
+
with self._scope_guard(operation.scope):
|
336
|
+
args = [
|
337
|
+
self.evaluate(param.name)
|
338
|
+
for param in operation.positional_arg_declarations
|
339
|
+
]
|
340
|
+
emit_generative_statements(self, operation, args)
|
341
|
+
else:
|
342
|
+
for block, block_body in operation.blocks.items():
|
343
|
+
with self._scope_guard(operation.scope):
|
344
|
+
self._expand_block(block_body, block)
|
345
|
+
|
346
|
+
return context
|
347
|
+
|
348
|
+
def _expand_permute(self) -> None:
|
349
|
+
functions = self.evaluate("functions").as_type(list)
|
350
|
+
functions_permutation = permutation(np.array(range(len(functions))))
|
351
|
+
for function_index in functions_permutation:
|
352
|
+
permute_call = QuantumFunctionCall(
|
353
|
+
function=OperandIdentifier(
|
354
|
+
name="functions", index=Expression(expr=f"{function_index}")
|
355
|
+
)
|
356
|
+
)
|
357
|
+
permute_call.set_func_decl(permute.func_decl)
|
358
|
+
self.emit(permute_call)
|
359
|
+
|
360
|
+
def _get_function_declarations(self) -> Sequence[QuantumFunctionDeclaration]:
|
361
|
+
return (
|
362
|
+
self._model.functions
|
363
|
+
+ [gen_func.func_decl for gen_func in self._generative_functions]
|
364
|
+
+ self._expanded_functions # type:ignore[operator]
|
365
|
+
)
|