classiq 0.45.1__py3-none-any.whl → 0.46.1__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.
Files changed (146) hide show
  1. classiq/__init__.py +0 -1
  2. classiq/_internals/__init__.py +20 -0
  3. classiq/_internals/authentication/authentication.py +11 -0
  4. classiq/analyzer/analyzer.py +12 -10
  5. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
  6. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +1 -1
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  8. classiq/applications/libraries/qmci_library.py +4 -9
  9. classiq/execution/execution_session.py +68 -7
  10. classiq/executor.py +14 -2
  11. classiq/interface/_version.py +1 -1
  12. classiq/interface/backend/backend_preferences.py +189 -0
  13. classiq/interface/backend/quantum_backend_providers.py +38 -0
  14. classiq/interface/debug_info/debug_info.py +22 -2
  15. classiq/interface/exceptions.py +16 -1
  16. classiq/interface/executor/execution_preferences.py +18 -0
  17. classiq/interface/generator/application_apis/chemistry_declarations.py +1 -177
  18. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +0 -12
  19. classiq/interface/generator/application_apis/finance_declarations.py +8 -43
  20. classiq/interface/generator/application_apis/qsvm_declarations.py +0 -78
  21. classiq/interface/generator/builtin_api_builder.py +0 -3
  22. classiq/interface/generator/functions/__init__.py +0 -2
  23. classiq/interface/generator/functions/builtins/__init__.py +0 -15
  24. classiq/interface/generator/generated_circuit_data.py +2 -0
  25. classiq/interface/generator/hardware/hardware_data.py +37 -0
  26. classiq/interface/generator/model/constraints.py +18 -1
  27. classiq/interface/generator/model/preferences/preferences.py +53 -1
  28. classiq/interface/generator/model/quantum_register.py +1 -1
  29. classiq/interface/generator/quantum_program.py +10 -2
  30. classiq/interface/generator/transpiler_basis_gates.py +4 -0
  31. classiq/interface/generator/types/builtin_enum_declarations.py +136 -21
  32. classiq/interface/generator/types/enum_declaration.py +1 -3
  33. classiq/interface/generator/types/struct_declaration.py +1 -3
  34. classiq/interface/hardware.py +5 -0
  35. classiq/interface/ide/visual_model.py +1 -1
  36. classiq/interface/model/classical_parameter_declaration.py +6 -0
  37. classiq/interface/model/inplace_binary_operation.py +0 -14
  38. classiq/interface/model/model.py +1 -18
  39. classiq/interface/model/port_declaration.py +4 -2
  40. classiq/interface/model/quantum_function_declaration.py +19 -6
  41. classiq/interface/model/quantum_lambda_function.py +11 -1
  42. classiq/interface/model/quantum_variable_declaration.py +1 -1
  43. classiq/model_expansions/__init__.py +0 -0
  44. classiq/model_expansions/atomic_expression_functions_defs.py +250 -0
  45. classiq/model_expansions/capturing/__init__.py +0 -0
  46. classiq/model_expansions/capturing/captured_var_manager.py +50 -0
  47. classiq/model_expansions/capturing/mangling_utils.py +17 -0
  48. classiq/model_expansions/capturing/propagated_var_stack.py +180 -0
  49. classiq/model_expansions/closure.py +160 -0
  50. classiq/model_expansions/debug_flag.py +3 -0
  51. classiq/model_expansions/evaluators/__init__.py +0 -0
  52. classiq/model_expansions/evaluators/arg_type_match.py +160 -0
  53. classiq/model_expansions/evaluators/argument_types.py +42 -0
  54. classiq/model_expansions/evaluators/classical_expression.py +36 -0
  55. classiq/model_expansions/evaluators/control.py +144 -0
  56. classiq/model_expansions/evaluators/parameter_types.py +227 -0
  57. classiq/model_expansions/evaluators/quantum_type_utils.py +235 -0
  58. classiq/model_expansions/evaluators/type_type_match.py +90 -0
  59. classiq/model_expansions/expression_evaluator.py +125 -0
  60. classiq/model_expansions/expression_renamer.py +76 -0
  61. classiq/model_expansions/function_builder.py +192 -0
  62. classiq/model_expansions/generative_functions.py +101 -0
  63. classiq/model_expansions/interpreter.py +365 -0
  64. classiq/model_expansions/model_tables.py +105 -0
  65. classiq/model_expansions/quantum_operations/__init__.py +19 -0
  66. classiq/model_expansions/quantum_operations/bind.py +64 -0
  67. classiq/model_expansions/quantum_operations/classicalif.py +39 -0
  68. classiq/model_expansions/quantum_operations/control.py +235 -0
  69. classiq/model_expansions/quantum_operations/emitter.py +215 -0
  70. classiq/model_expansions/quantum_operations/expression_operation.py +218 -0
  71. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +250 -0
  72. classiq/model_expansions/quantum_operations/invert.py +38 -0
  73. classiq/model_expansions/quantum_operations/power.py +74 -0
  74. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +174 -0
  75. classiq/model_expansions/quantum_operations/quantum_function_call.py +15 -0
  76. classiq/model_expansions/quantum_operations/repeat.py +33 -0
  77. classiq/model_expansions/quantum_operations/variable_decleration.py +28 -0
  78. classiq/model_expansions/quantum_operations/within_apply.py +46 -0
  79. classiq/model_expansions/scope.py +226 -0
  80. classiq/model_expansions/scope_initialization.py +136 -0
  81. classiq/model_expansions/sympy_conversion/__init__.py +0 -0
  82. classiq/model_expansions/sympy_conversion/arithmetics.py +49 -0
  83. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +150 -0
  84. classiq/model_expansions/sympy_conversion/sympy_to_python.py +113 -0
  85. classiq/model_expansions/utils/__init__.py +0 -0
  86. classiq/model_expansions/utils/counted_name_allocator.py +11 -0
  87. classiq/model_expansions/visitors/__init__.py +0 -0
  88. classiq/model_expansions/visitors/boolean_expression_transformers.py +214 -0
  89. classiq/model_expansions/visitors/variable_references.py +115 -0
  90. classiq/qmod/__init__.py +1 -3
  91. classiq/qmod/builtins/enums.py +33 -2
  92. classiq/qmod/builtins/functions/__init__.py +251 -0
  93. classiq/qmod/builtins/functions/amplitude_estimation.py +27 -0
  94. classiq/qmod/builtins/functions/arithmetic.py +68 -0
  95. classiq/qmod/builtins/functions/benchmarking.py +8 -0
  96. classiq/qmod/builtins/functions/chemistry.py +91 -0
  97. classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +105 -0
  98. classiq/qmod/builtins/functions/exponentiation.py +111 -0
  99. classiq/qmod/builtins/functions/finance.py +34 -0
  100. classiq/qmod/builtins/functions/grover.py +178 -0
  101. classiq/qmod/builtins/functions/hea.py +59 -0
  102. classiq/qmod/builtins/functions/linear_pauli_rotation.py +65 -0
  103. classiq/qmod/builtins/functions/modular_exponentiation.py +137 -0
  104. classiq/qmod/builtins/functions/operators.py +22 -0
  105. classiq/qmod/builtins/functions/qaoa_penalty.py +116 -0
  106. classiq/qmod/builtins/functions/qft.py +23 -0
  107. classiq/qmod/builtins/functions/qpe.py +39 -0
  108. classiq/qmod/builtins/functions/qsvm.py +24 -0
  109. classiq/qmod/builtins/functions/qsvt.py +136 -0
  110. classiq/qmod/builtins/functions/standard_gates.py +739 -0
  111. classiq/qmod/builtins/functions/state_preparation.py +357 -0
  112. classiq/qmod/builtins/functions/swap_test.py +25 -0
  113. classiq/qmod/builtins/structs.py +50 -28
  114. classiq/qmod/cparam.py +64 -0
  115. classiq/qmod/create_model_function.py +190 -0
  116. classiq/qmod/declaration_inferrer.py +52 -81
  117. classiq/qmod/expression_query.py +16 -0
  118. classiq/qmod/generative.py +48 -0
  119. classiq/qmod/model_state_container.py +1 -2
  120. classiq/qmod/native/pretty_printer.py +7 -11
  121. classiq/qmod/pretty_print/pretty_printer.py +7 -11
  122. classiq/qmod/python_classical_type.py +67 -0
  123. classiq/qmod/qfunc.py +19 -4
  124. classiq/qmod/qmod_parameter.py +15 -64
  125. classiq/qmod/qmod_variable.py +27 -45
  126. classiq/qmod/quantum_callable.py +1 -1
  127. classiq/qmod/quantum_expandable.py +10 -4
  128. classiq/qmod/quantum_function.py +22 -40
  129. classiq/qmod/semantics/error_manager.py +22 -10
  130. classiq/qmod/semantics/static_semantics_visitor.py +10 -12
  131. classiq/qmod/semantics/validation/types_validation.py +6 -7
  132. classiq/qmod/utilities.py +2 -2
  133. classiq/qmod/write_qmod.py +14 -0
  134. classiq/show.py +10 -0
  135. classiq/synthesis.py +46 -2
  136. {classiq-0.45.1.dist-info → classiq-0.46.1.dist-info}/METADATA +1 -1
  137. {classiq-0.45.1.dist-info → classiq-0.46.1.dist-info}/RECORD +138 -74
  138. classiq/interface/generator/functions/builtins/core_library/__init__.py +0 -16
  139. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +0 -710
  140. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +0 -105
  141. classiq/interface/generator/functions/builtins/open_lib_functions.py +0 -2489
  142. classiq/interface/generator/functions/builtins/quantum_operators.py +0 -24
  143. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
  144. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +0 -21
  145. classiq/qmod/builtins/functions.py +0 -1029
  146. {classiq-0.45.1.dist-info → classiq-0.46.1.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
+ )