classiq 0.90.0__py3-none-any.whl → 0.91.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.
- classiq/evaluators/expression_evaluator.py +24 -124
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +10 -3
- classiq/evaluators/qmod_node_evaluators/utils.py +0 -8
- classiq/interface/_version.py +1 -1
- classiq/interface/executor/result.py +22 -3
- classiq/interface/generator/expressions/expression_types.py +2 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +3 -8
- classiq/interface/generator/functions/classical_type.py +2 -5
- classiq/interface/generator/functions/type_name.py +0 -12
- classiq/interface/model/quantum_type.py +0 -39
- classiq/model_expansions/capturing/captured_vars.py +3 -0
- classiq/model_expansions/function_builder.py +18 -2
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +0 -10
- classiq/model_expansions/interpreters/generative_interpreter.py +63 -18
- classiq/model_expansions/quantum_operations/emitter.py +13 -3
- classiq/model_expansions/quantum_operations/expression_evaluator.py +49 -5
- classiq/model_expansions/scope.py +5 -14
- classiq/model_expansions/utils/handles_collector.py +7 -0
- classiq/qmod/builtins/operations.py +7 -3
- classiq/qmod/qmod_variable.py +3 -4
- classiq/qmod/semantics/error_manager.py +34 -15
- classiq/qmod/symbolic.py +15 -4
- classiq/qmod/utilities.py +4 -1
- classiq/synthesis.py +1 -2
- {classiq-0.90.0.dist-info → classiq-0.91.1.dist-info}/METADATA +1 -1
- {classiq-0.90.0.dist-info → classiq-0.91.1.dist-info}/RECORD +27 -41
- classiq/interface/generator/expressions/handle_identifier.py +0 -6
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -41
- classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/quantum/qmod_qarray_proxy.py +0 -80
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +0 -77
- classiq/interface/generator/expressions/proxies/quantum/qmod_qstruct_proxy.py +0 -38
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +0 -39
- classiq/interface/generator/expressions/type_proxy.py +0 -10
- classiq/model_expansions/atomic_expression_functions_defs.py +0 -395
- classiq/model_expansions/model_tables.py +0 -18
- classiq/model_expansions/sympy_conversion/__init__.py +0 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +0 -181
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +0 -136
- classiq/model_expansions/utils/sympy_utils.py +0 -24
- {classiq-0.90.0.dist-info → classiq-0.91.1.dist-info}/WHEEL +0 -0
|
@@ -11,6 +11,7 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
|
|
|
11
11
|
CLASSICAL_IF_OPERATOR_NAME,
|
|
12
12
|
CONTROL_OPERATOR_NAME,
|
|
13
13
|
INVERT_OPERATOR_NAME,
|
|
14
|
+
POWER_OPERATOR_NAME,
|
|
14
15
|
REPEAT_OPERATOR_NAME,
|
|
15
16
|
WITHIN_APPLY_NAME,
|
|
16
17
|
)
|
|
@@ -108,6 +109,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
108
109
|
self.infer_symbolic_parameters(
|
|
109
110
|
model.functions, [gen_func.func_decl for gen_func in generative_functions]
|
|
110
111
|
)
|
|
112
|
+
self._symbolic_parameters_switch = self.allow_symbolic_parameters()
|
|
111
113
|
|
|
112
114
|
def infer_symbolic_parameters(
|
|
113
115
|
self,
|
|
@@ -118,6 +120,9 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
118
120
|
) -> None:
|
|
119
121
|
pass
|
|
120
122
|
|
|
123
|
+
def allow_symbolic_parameters(self) -> bool:
|
|
124
|
+
return True
|
|
125
|
+
|
|
121
126
|
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
|
122
127
|
func_decl = NamedParamsQuantumFunctionDeclaration(
|
|
123
128
|
name=self._counted_name_allocator.allocate(
|
|
@@ -164,18 +169,28 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
164
169
|
QuantumFunctionCallEmitter(self).emit(call)
|
|
165
170
|
|
|
166
171
|
@emit.register
|
|
167
|
-
def _emit_allocate(self, allocate: Allocate) -> None:
|
|
168
|
-
return self.emit_allocate(allocate)
|
|
169
|
-
|
|
170
172
|
def emit_allocate(self, allocate: Allocate) -> None:
|
|
171
|
-
|
|
173
|
+
CompositeEmitter[Allocate](
|
|
174
|
+
self,
|
|
175
|
+
[
|
|
176
|
+
ExpressionEvaluator(
|
|
177
|
+
self,
|
|
178
|
+
"size",
|
|
179
|
+
readable_expression_name="allocation size",
|
|
180
|
+
allow_link_time_vars=self._symbolic_parameters_switch,
|
|
181
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
182
|
+
),
|
|
183
|
+
AllocateEmitter(
|
|
184
|
+
self, allow_symbolic_attrs=self._symbolic_parameters_switch
|
|
185
|
+
),
|
|
186
|
+
],
|
|
187
|
+
).emit(allocate)
|
|
172
188
|
|
|
173
189
|
@emit.register
|
|
174
|
-
def _emit_bind(self, bind: BindOperation) -> None:
|
|
175
|
-
self.emit_bind(bind)
|
|
176
|
-
|
|
177
190
|
def emit_bind(self, bind: BindOperation) -> None:
|
|
178
|
-
BindEmitter(self).emit(
|
|
191
|
+
BindEmitter(self, allow_symbolic_size=self._symbolic_parameters_switch).emit(
|
|
192
|
+
bind
|
|
193
|
+
)
|
|
179
194
|
|
|
180
195
|
@emit.register
|
|
181
196
|
def emit_amplitude_loading_operation(self, op: AmplitudeLoadingOperation) -> None:
|
|
@@ -184,7 +199,12 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
184
199
|
[
|
|
185
200
|
HandleEvaluator(self, "result_var"),
|
|
186
201
|
ExpressionEvaluator(
|
|
187
|
-
self,
|
|
202
|
+
self,
|
|
203
|
+
"expression",
|
|
204
|
+
readable_expression_name="amplitude-encoding expression",
|
|
205
|
+
simplify=True,
|
|
206
|
+
treat_qnum_as_float=True,
|
|
207
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
188
208
|
),
|
|
189
209
|
AssignmentResultProcessor(self),
|
|
190
210
|
],
|
|
@@ -223,14 +243,16 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
223
243
|
VariableDeclarationStatementEmitter(self).emit(variable_declaration)
|
|
224
244
|
|
|
225
245
|
@emit.register
|
|
226
|
-
def _emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
|
227
|
-
self.emit_classical_if(classical_if)
|
|
228
|
-
|
|
229
246
|
def emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
|
230
247
|
CompositeEmitter[ClassicalIf](
|
|
231
248
|
self,
|
|
232
249
|
[
|
|
233
|
-
ExpressionEvaluator(
|
|
250
|
+
ExpressionEvaluator(
|
|
251
|
+
self,
|
|
252
|
+
"condition",
|
|
253
|
+
readable_expression_name="classical-if condition",
|
|
254
|
+
allow_link_time_vars=self._symbolic_parameters_switch,
|
|
255
|
+
),
|
|
234
256
|
IfElimination(self),
|
|
235
257
|
BlockEvaluator(
|
|
236
258
|
self,
|
|
@@ -278,7 +300,14 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
278
300
|
CompositeEmitter[Control](
|
|
279
301
|
self,
|
|
280
302
|
[
|
|
281
|
-
ExpressionEvaluator(
|
|
303
|
+
ExpressionEvaluator(
|
|
304
|
+
self,
|
|
305
|
+
"expression",
|
|
306
|
+
simplify=True,
|
|
307
|
+
readable_expression_name="control expression",
|
|
308
|
+
allow_link_time_vars=self._symbolic_parameters_switch,
|
|
309
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
310
|
+
),
|
|
282
311
|
BlockEvaluator(
|
|
283
312
|
self,
|
|
284
313
|
CONTROL_OPERATOR_NAME,
|
|
@@ -293,8 +322,13 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
293
322
|
CompositeEmitter[Power](
|
|
294
323
|
self,
|
|
295
324
|
[
|
|
296
|
-
ExpressionEvaluator(
|
|
297
|
-
|
|
325
|
+
ExpressionEvaluator(
|
|
326
|
+
self,
|
|
327
|
+
"power",
|
|
328
|
+
readable_expression_name="power exponent",
|
|
329
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
330
|
+
),
|
|
331
|
+
BlockEvaluator(self, POWER_OPERATOR_NAME, "body"),
|
|
298
332
|
],
|
|
299
333
|
).emit(power)
|
|
300
334
|
|
|
@@ -303,8 +337,19 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
303
337
|
CompositeEmitter[PhaseOperation](
|
|
304
338
|
self,
|
|
305
339
|
[
|
|
306
|
-
ExpressionEvaluator(
|
|
307
|
-
|
|
340
|
+
ExpressionEvaluator(
|
|
341
|
+
self,
|
|
342
|
+
"expression",
|
|
343
|
+
readable_expression_name="phase expression",
|
|
344
|
+
simplify=True,
|
|
345
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
346
|
+
),
|
|
347
|
+
ExpressionEvaluator(
|
|
348
|
+
self,
|
|
349
|
+
"theta",
|
|
350
|
+
readable_expression_name="phase theta expression",
|
|
351
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
352
|
+
),
|
|
308
353
|
],
|
|
309
354
|
).emit(phase)
|
|
310
355
|
|
|
@@ -45,7 +45,7 @@ from classiq.model_expansions.function_builder import (
|
|
|
45
45
|
OperationBuilder,
|
|
46
46
|
OperationContext,
|
|
47
47
|
)
|
|
48
|
-
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
|
48
|
+
from classiq.model_expansions.scope import ClassicalSymbol, QuantumSymbol, Scope
|
|
49
49
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
|
50
50
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
|
51
51
|
|
|
@@ -240,10 +240,20 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
|
240
240
|
dict.fromkeys(var.name for var in expr_val.get_classical_vars().values())
|
|
241
241
|
)
|
|
242
242
|
return [
|
|
243
|
-
(
|
|
243
|
+
(
|
|
244
|
+
var,
|
|
245
|
+
(
|
|
246
|
+
get_proxy_type(proxy)
|
|
247
|
+
if isinstance(proxy, ClassicalProxy)
|
|
248
|
+
else proxy.classical_type
|
|
249
|
+
),
|
|
250
|
+
)
|
|
244
251
|
for var in classical_vars
|
|
245
252
|
if var in self._current_scope
|
|
246
|
-
and isinstance(
|
|
253
|
+
and isinstance(
|
|
254
|
+
proxy := self._current_scope[var].value,
|
|
255
|
+
(ClassicalProxy, ClassicalSymbol),
|
|
256
|
+
)
|
|
247
257
|
]
|
|
248
258
|
|
|
249
259
|
def _get_quantum_type_attributes_in_expression(
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
|
2
2
|
|
|
3
|
+
from classiq.interface.exceptions import (
|
|
4
|
+
ClassiqExpansionError,
|
|
5
|
+
ClassiqInternalExpansionError,
|
|
6
|
+
)
|
|
3
7
|
from classiq.interface.generator.expressions.expression import Expression
|
|
4
8
|
from classiq.interface.generator.functions.port_declaration import (
|
|
5
9
|
PortDeclarationDirection,
|
|
6
10
|
)
|
|
11
|
+
from classiq.interface.helpers.text_utils import readable_list, s
|
|
7
12
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
|
8
13
|
|
|
9
14
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
|
15
|
+
from classiq.model_expansions.scope import ClassicalSymbol
|
|
10
16
|
|
|
11
17
|
if TYPE_CHECKING:
|
|
12
18
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
|
@@ -18,13 +24,23 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
|
|
|
18
24
|
interpreter: "BaseInterpreter",
|
|
19
25
|
expression_name: str,
|
|
20
26
|
*,
|
|
27
|
+
readable_expression_name: Optional[str] = None,
|
|
21
28
|
simplify: bool = False,
|
|
22
29
|
treat_qnum_as_float: bool = False,
|
|
30
|
+
allow_link_time_vars: bool = True,
|
|
31
|
+
allow_runtime_vars: bool = True,
|
|
23
32
|
) -> None:
|
|
24
33
|
super().__init__(interpreter)
|
|
25
34
|
self._expression_name = expression_name
|
|
26
35
|
self._simplify = simplify
|
|
27
36
|
self._treat_qnum_as_float = treat_qnum_as_float
|
|
37
|
+
self._allow_link_time_vars = allow_link_time_vars
|
|
38
|
+
self._allow_runtime_vars = allow_runtime_vars
|
|
39
|
+
if (
|
|
40
|
+
not allow_link_time_vars or not allow_runtime_vars
|
|
41
|
+
) and readable_expression_name is None:
|
|
42
|
+
raise ClassiqInternalExpansionError
|
|
43
|
+
self._readable_expression_name = readable_expression_name
|
|
28
44
|
|
|
29
45
|
def emit(self, op: QuantumOperation, /) -> bool:
|
|
30
46
|
expression = getattr(op, self._expression_name)
|
|
@@ -37,13 +53,41 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
|
|
|
37
53
|
)
|
|
38
54
|
for symbol in self._get_symbols_in_expression(evaluated_expression):
|
|
39
55
|
self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
|
|
40
|
-
|
|
41
|
-
evaluated_expression
|
|
42
|
-
):
|
|
43
|
-
self._capture_classical_var(var_name, var_type)
|
|
56
|
+
self._process_classical_parameters(evaluated_expression)
|
|
44
57
|
op = op.model_copy(
|
|
45
58
|
update={self._expression_name: evaluated_expression, "back_ref": op.uuid}
|
|
46
59
|
)
|
|
47
60
|
self._interpreter.add_to_debug_info(op)
|
|
48
61
|
self._interpreter.emit(op)
|
|
49
62
|
return True
|
|
63
|
+
|
|
64
|
+
def _process_classical_parameters(self, evaluated_expression: Expression) -> None:
|
|
65
|
+
link_time_vars: list[str] = []
|
|
66
|
+
runtime_vars: list[str] = []
|
|
67
|
+
for var_name, var_type in self._get_classical_vars_in_expression(
|
|
68
|
+
evaluated_expression
|
|
69
|
+
):
|
|
70
|
+
if isinstance(self._current_scope[var_name].value, ClassicalSymbol):
|
|
71
|
+
runtime_vars.append(var_name)
|
|
72
|
+
else:
|
|
73
|
+
link_time_vars.append(var_name)
|
|
74
|
+
self._capture_classical_var(var_name, var_type)
|
|
75
|
+
if not self._allow_link_time_vars and len(link_time_vars) > 0:
|
|
76
|
+
link_time_message = f"link-time variable{s(link_time_vars)} {readable_list(link_time_vars, quote=True)}"
|
|
77
|
+
else:
|
|
78
|
+
link_time_message = None
|
|
79
|
+
if not self._allow_runtime_vars and len(runtime_vars) > 0:
|
|
80
|
+
runtime_message = f"runtime variable{s(runtime_vars)} {readable_list(runtime_vars, quote=True)}"
|
|
81
|
+
else:
|
|
82
|
+
runtime_message = None
|
|
83
|
+
if link_time_message is None:
|
|
84
|
+
error_message = runtime_message
|
|
85
|
+
elif runtime_message is None:
|
|
86
|
+
error_message = link_time_message
|
|
87
|
+
else:
|
|
88
|
+
error_message = f"{link_time_message} and {runtime_message}"
|
|
89
|
+
if error_message is not None:
|
|
90
|
+
raise ClassiqExpansionError(
|
|
91
|
+
f"The {self._readable_expression_name} cannot receive "
|
|
92
|
+
f"{error_message}"
|
|
93
|
+
)
|
|
@@ -3,7 +3,7 @@ from collections import UserDict
|
|
|
3
3
|
from collections.abc import Iterator
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from functools import singledispatch
|
|
6
|
-
from typing import TYPE_CHECKING, Any,
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
|
|
7
7
|
|
|
8
8
|
import sympy
|
|
9
9
|
|
|
@@ -20,7 +20,6 @@ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_insta
|
|
|
20
20
|
)
|
|
21
21
|
from classiq.interface.generator.functions.classical_type import ClassicalType
|
|
22
22
|
from classiq.interface.generator.functions.type_name import TypeName
|
|
23
|
-
from classiq.interface.helpers.text_utils import readable_list, s
|
|
24
23
|
from classiq.interface.model.handle_binding import (
|
|
25
24
|
FieldHandleBinding,
|
|
26
25
|
GeneralHandle,
|
|
@@ -235,29 +234,21 @@ def _evaluated_to_str_struct_literal(value: QmodStructInstance) -> str:
|
|
|
235
234
|
return f"struct_literal({value.struct_declaration.name}, {', '.join(f'{k}={evaluated_to_str(v)}' for k, v in value.fields.items())})"
|
|
236
235
|
|
|
237
236
|
|
|
238
|
-
def _raise_type_error(val: Any, t: type, location_hint: Optional[str]) -> NoReturn:
|
|
239
|
-
if isinstance(val, QmodAnnotatedExpression) and len(val.get_classical_vars()) > 0:
|
|
240
|
-
symbolic_vars = sorted(map(str, val.get_classical_vars().values()))
|
|
241
|
-
suffix = f" {location_hint}" if location_hint is not None else ""
|
|
242
|
-
raise ClassiqExpansionError(
|
|
243
|
-
f"Cannot use execution parameter{s(symbolic_vars)} {readable_list(symbolic_vars, quote=True)} in a compile-time context{suffix}"
|
|
244
|
-
)
|
|
245
|
-
raise ClassiqExpansionError(f"Invalid access to expression {val!r} as {t}")
|
|
246
|
-
|
|
247
|
-
|
|
248
237
|
@dataclass(frozen=True)
|
|
249
238
|
class Evaluated: # FIXME: Merge with EvaluatedExpression if possible
|
|
250
239
|
value: Any
|
|
251
240
|
defining_function: Optional["FunctionClosure"] = None
|
|
252
241
|
|
|
253
|
-
def as_type(self, t: type[T]
|
|
242
|
+
def as_type(self, t: type[T]) -> T:
|
|
254
243
|
value = self.value
|
|
255
244
|
if isinstance(value, sympy.Basic):
|
|
256
245
|
value = get_sympy_val(value)
|
|
257
246
|
if t is int and isinstance(value, float):
|
|
258
247
|
value = int(value)
|
|
259
248
|
if not isinstance(value, t):
|
|
260
|
-
|
|
249
|
+
raise ClassiqExpansionError(
|
|
250
|
+
f"Invalid access to expression {self.value!r} as {t}"
|
|
251
|
+
)
|
|
261
252
|
|
|
262
253
|
return value
|
|
263
254
|
|
|
@@ -7,6 +7,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
|
7
7
|
QuantumExpressionOperation,
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
10
11
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
|
11
12
|
|
|
12
13
|
|
|
@@ -18,6 +19,12 @@ class _HandlesCollector(Visitor):
|
|
|
18
19
|
self.handles.append(handle)
|
|
19
20
|
|
|
20
21
|
def visit_Expression(self, expression: Expression) -> None:
|
|
22
|
+
if expression.is_evaluated():
|
|
23
|
+
expr_val = expression.value.value
|
|
24
|
+
if isinstance(expr_val, QmodAnnotatedExpression):
|
|
25
|
+
self.handles.extend(expr_val.get_classical_vars().values())
|
|
26
|
+
self.handles.extend(expr_val.get_quantum_vars().values())
|
|
27
|
+
return
|
|
21
28
|
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
|
22
29
|
vrc.visit(ast.parse(expression.expr))
|
|
23
30
|
self.handles.extend(vrc.var_handles)
|
|
@@ -518,19 +518,23 @@ def invert(stmt_block: Union[QCallable, Callable[[], Statements]]) -> None:
|
|
|
518
518
|
|
|
519
519
|
|
|
520
520
|
@overload
|
|
521
|
-
def phase(
|
|
521
|
+
def phase(
|
|
522
|
+
phase_expr: Union[SymbolicExpr, float], theta: Union[SymbolicExpr, float] = 1.0
|
|
523
|
+
) -> None:
|
|
522
524
|
pass
|
|
523
525
|
|
|
524
526
|
|
|
525
527
|
@overload
|
|
526
|
-
def phase(
|
|
528
|
+
def phase(
|
|
529
|
+
*, expr: Union[SymbolicExpr, float], theta: Union[SymbolicExpr, float] = 1.0
|
|
530
|
+
) -> None:
|
|
527
531
|
pass
|
|
528
532
|
|
|
529
533
|
|
|
530
534
|
@suppress_return_value
|
|
531
535
|
def phase(
|
|
532
536
|
phase_expr: Union[SymbolicExpr, float, None] = None,
|
|
533
|
-
theta: float = 1.0,
|
|
537
|
+
theta: Union[SymbolicExpr, float] = 1.0,
|
|
534
538
|
expr: Any = None,
|
|
535
539
|
) -> None:
|
|
536
540
|
"""
|
classiq/qmod/qmod_variable.py
CHANGED
|
@@ -31,10 +31,6 @@ from classiq.interface.exceptions import (
|
|
|
31
31
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
|
32
32
|
from classiq.interface.generator.expressions.expression import Expression
|
|
33
33
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
|
34
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy import (
|
|
35
|
-
ILLEGAL_SLICE_MSG,
|
|
36
|
-
ILLEGAL_SLICING_STEP_MSG,
|
|
37
|
-
)
|
|
38
34
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
|
39
35
|
from classiq.interface.generator.functions.port_declaration import (
|
|
40
36
|
PortDeclarationDirection,
|
|
@@ -83,6 +79,9 @@ from classiq.qmod.utilities import (
|
|
|
83
79
|
version_portable_get_args,
|
|
84
80
|
)
|
|
85
81
|
|
|
82
|
+
ILLEGAL_SLICING_STEP_MSG = "Slicing with a step of a quantum variable is not supported"
|
|
83
|
+
ILLEGAL_SLICE_MSG = "Quantum array slice must be of the form [<int-value>:<int-value>]."
|
|
84
|
+
|
|
86
85
|
|
|
87
86
|
@contextmanager
|
|
88
87
|
def _no_current_expandable() -> Iterator[None]:
|
|
@@ -18,6 +18,7 @@ class ErrorManager:
|
|
|
18
18
|
return
|
|
19
19
|
self._instantiated = True
|
|
20
20
|
self._errors: list[SourceReferencedError] = []
|
|
21
|
+
self._warnings: list[SourceReferencedError] = []
|
|
21
22
|
self._current_nodes_stack: list[ASTNode] = []
|
|
22
23
|
self._call_stack: list[str] = []
|
|
23
24
|
self._ignore_errors: bool = False
|
|
@@ -41,38 +42,56 @@ class ErrorManager:
|
|
|
41
42
|
def annotated_errors(self) -> list[str]:
|
|
42
43
|
return [str(error) for error in self._errors]
|
|
43
44
|
|
|
45
|
+
@property
|
|
46
|
+
def annotated_warnings(self) -> list[str]:
|
|
47
|
+
return [str(error) for error in self._warnings]
|
|
48
|
+
|
|
44
49
|
def add_error(
|
|
45
50
|
self,
|
|
46
51
|
error: str,
|
|
47
52
|
*,
|
|
48
53
|
source_ref: Optional[SourceReference] = None,
|
|
49
54
|
function: Optional[str] = None,
|
|
55
|
+
warning: bool = False,
|
|
50
56
|
) -> None:
|
|
51
|
-
if
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
57
|
+
if self._ignore_errors:
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
source_ref_error = SourceReferencedError(
|
|
61
|
+
error=error.replace(CLASSIQ_SLACK_COMMUNITY_LINK, ""),
|
|
62
|
+
source_ref=(
|
|
63
|
+
source_ref if source_ref is not None else self._current_source_ref
|
|
64
|
+
),
|
|
65
|
+
function=(function if function is not None else self.current_function),
|
|
66
|
+
)
|
|
67
|
+
if warning:
|
|
68
|
+
self._warnings.append(source_ref_error)
|
|
69
|
+
else:
|
|
70
|
+
self._errors.append(source_ref_error)
|
|
65
71
|
|
|
66
72
|
def get_errors(self) -> list[SourceReferencedError]:
|
|
67
73
|
return self._errors
|
|
68
74
|
|
|
75
|
+
def get_warnings(self) -> list[SourceReferencedError]:
|
|
76
|
+
return self._warnings
|
|
77
|
+
|
|
69
78
|
def clear(self) -> None:
|
|
79
|
+
self.clear_errors()
|
|
80
|
+
self.clear_warnings()
|
|
81
|
+
|
|
82
|
+
def clear_errors(self) -> None:
|
|
70
83
|
self._current_nodes_stack = []
|
|
71
84
|
self._errors = []
|
|
72
85
|
|
|
86
|
+
def clear_warnings(self) -> None:
|
|
87
|
+
self._warnings = []
|
|
88
|
+
|
|
73
89
|
def has_errors(self) -> bool:
|
|
74
90
|
return len(self._errors) > 0
|
|
75
91
|
|
|
92
|
+
def has_warnings(self) -> bool:
|
|
93
|
+
return len(self._warnings) > 0
|
|
94
|
+
|
|
76
95
|
def report_errors(
|
|
77
96
|
self, error_type: type[Exception], mask: Optional[list[int]] = None
|
|
78
97
|
) -> None:
|
|
@@ -82,7 +101,7 @@ class ErrorManager:
|
|
|
82
101
|
if mask is None
|
|
83
102
|
else [self.annotated_errors[idx] for idx in mask]
|
|
84
103
|
)
|
|
85
|
-
self.
|
|
104
|
+
self.clear_errors()
|
|
86
105
|
raise error_type("\n\t" + "\n\t".join(errors))
|
|
87
106
|
|
|
88
107
|
@property
|
classiq/qmod/symbolic.py
CHANGED
|
@@ -11,9 +11,6 @@ from typing import (
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
|
|
13
13
|
from classiq.interface.exceptions import ClassiqValueError
|
|
14
|
-
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
15
|
-
subscript_to_str,
|
|
16
|
-
)
|
|
17
14
|
|
|
18
15
|
from classiq.qmod import model_state_container
|
|
19
16
|
from classiq.qmod.declaration_inferrer import python_type_to_qmod
|
|
@@ -309,12 +306,26 @@ def sum(arr: SymbolicTypes) -> CParamScalar:
|
|
|
309
306
|
return symbolic_function(arr)
|
|
310
307
|
|
|
311
308
|
|
|
309
|
+
def _subscript_to_str(index: Any) -> str:
|
|
310
|
+
if not isinstance(index, slice):
|
|
311
|
+
return str(index)
|
|
312
|
+
expr = ""
|
|
313
|
+
if index.start is not None:
|
|
314
|
+
expr += str(index.start)
|
|
315
|
+
expr += ":"
|
|
316
|
+
if index.stop is not None:
|
|
317
|
+
expr += str(index.stop)
|
|
318
|
+
if index.step is not None:
|
|
319
|
+
expr += f":{index.step}"
|
|
320
|
+
return expr
|
|
321
|
+
|
|
322
|
+
|
|
312
323
|
def subscript(
|
|
313
324
|
array: Union[list, CArray[CReal], np.ndarray],
|
|
314
325
|
index: Any,
|
|
315
326
|
) -> CParamScalar:
|
|
316
327
|
return CParamScalar(
|
|
317
|
-
expr=f"{qmod_val_to_expr_str(_unwrap_numpy(array))}[{
|
|
328
|
+
expr=f"{qmod_val_to_expr_str(_unwrap_numpy(array))}[{_subscript_to_str(index)}]"
|
|
318
329
|
)
|
|
319
330
|
|
|
320
331
|
|
classiq/qmod/utilities.py
CHANGED
|
@@ -29,6 +29,7 @@ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_insta
|
|
|
29
29
|
from classiq.interface.source_reference import SourceReference
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
32
|
+
from classiq.qmod.cparam import CParam
|
|
32
33
|
from classiq.qmod.qmod_variable import QVar
|
|
33
34
|
|
|
34
35
|
|
|
@@ -162,7 +163,9 @@ def suppress_return_value(func: Callable[Params, None]) -> Callable[Params, None
|
|
|
162
163
|
return func
|
|
163
164
|
|
|
164
165
|
|
|
165
|
-
Statements = Union[
|
|
166
|
+
Statements = Union[
|
|
167
|
+
None, list[Union[None, "QVar", "CParam"]], tuple[Union[None, "QVar", "CParam"], ...]
|
|
168
|
+
]
|
|
166
169
|
|
|
167
170
|
|
|
168
171
|
def _eval_qnum(val: int, size: int, is_signed: bool, fraction_digits: int) -> float:
|
classiq/synthesis.py
CHANGED
|
@@ -57,8 +57,7 @@ async def synthesize_async(
|
|
|
57
57
|
) -> QuantumProgram:
|
|
58
58
|
model = Model.model_validate_json(serialized_model)
|
|
59
59
|
quantum_program = await ApiWrapper.call_generation_task(model)
|
|
60
|
-
|
|
61
|
-
quantum_program.raise_warnings()
|
|
60
|
+
quantum_program.raise_warnings()
|
|
62
61
|
return quantum_program
|
|
63
62
|
|
|
64
63
|
|