classiq 0.46.1__py3-none-any.whl → 0.48.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/_internals/api_wrapper.py +45 -8
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +2 -7
- classiq/applications/grover/grover_model_constructor.py +2 -1
- classiq/execution/execution_session.py +133 -45
- classiq/execution/jobs.py +120 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +0 -1
- classiq/interface/debug_info/debug_info.py +23 -1
- classiq/interface/execution/primitives.py +17 -0
- classiq/interface/executor/iqae_result.py +3 -3
- classiq/interface/executor/result.py +3 -1
- classiq/interface/generator/arith/arithmetic_operations.py +5 -2
- classiq/interface/generator/arith/binary_ops.py +21 -14
- classiq/interface/generator/arith/extremum_operations.py +9 -1
- classiq/interface/generator/arith/number_utils.py +6 -0
- classiq/interface/generator/arith/register_user_input.py +30 -21
- classiq/interface/generator/arith/unary_ops.py +13 -1
- classiq/interface/generator/expressions/expression.py +8 -0
- classiq/interface/generator/functions/type_name.py +1 -3
- classiq/interface/generator/generated_circuit_data.py +47 -2
- classiq/interface/generator/quantum_program.py +10 -2
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +17 -3
- classiq/interface/ide/visual_model.py +10 -5
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/bind_operation.py +0 -3
- classiq/interface/model/phase_operation.py +11 -0
- classiq/interface/model/port_declaration.py +1 -12
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +34 -6
- classiq/interface/model/quantum_lambda_function.py +4 -1
- classiq/interface/model/quantum_statement.py +16 -1
- classiq/interface/model/quantum_variable_declaration.py +0 -22
- classiq/interface/model/statement_block.py +3 -0
- classiq/interface/server/global_versions.py +4 -4
- classiq/interface/server/routes.py +0 -3
- classiq/model_expansions/capturing/propagated_var_stack.py +5 -2
- classiq/model_expansions/closure.py +7 -2
- classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
- classiq/model_expansions/generative_functions.py +146 -28
- classiq/model_expansions/interpreter.py +17 -5
- classiq/model_expansions/quantum_operations/classicalif.py +27 -10
- classiq/model_expansions/quantum_operations/control.py +22 -15
- classiq/model_expansions/quantum_operations/emitter.py +68 -7
- classiq/model_expansions/quantum_operations/expression_operation.py +25 -16
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +167 -95
- classiq/model_expansions/quantum_operations/invert.py +12 -6
- classiq/model_expansions/quantum_operations/phase.py +189 -0
- classiq/model_expansions/quantum_operations/power.py +9 -8
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +20 -5
- classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
- classiq/model_expansions/quantum_operations/repeat.py +32 -13
- classiq/model_expansions/quantum_operations/within_apply.py +19 -6
- classiq/model_expansions/scope.py +16 -5
- classiq/model_expansions/scope_initialization.py +11 -1
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +23 -1
- classiq/model_expansions/visitors/variable_references.py +11 -7
- classiq/qmod/builtins/__init__.py +10 -0
- classiq/qmod/builtins/constants.py +10 -0
- classiq/qmod/builtins/functions/state_preparation.py +4 -1
- classiq/qmod/builtins/operations.py +55 -161
- classiq/qmod/create_model_function.py +1 -1
- classiq/qmod/generative.py +14 -5
- classiq/qmod/native/pretty_printer.py +14 -4
- classiq/qmod/pretty_print/pretty_printer.py +14 -4
- classiq/qmod/qmod_constant.py +28 -18
- classiq/qmod/qmod_variable.py +43 -23
- classiq/qmod/quantum_expandable.py +14 -1
- classiq/qmod/semantics/static_semantics_visitor.py +10 -0
- classiq/qmod/semantics/validation/constants_validation.py +16 -0
- {classiq-0.46.1.dist-info → classiq-0.48.0.dist-info}/METADATA +9 -4
- {classiq-0.46.1.dist-info → classiq-0.48.0.dist-info}/RECORD +71 -66
- {classiq-0.46.1.dist-info → classiq-0.48.0.dist-info}/WHEEL +0 -0
@@ -1,17 +1,13 @@
|
|
1
1
|
import inspect
|
2
2
|
import sys
|
3
|
-
import warnings
|
4
3
|
from types import FrameType
|
5
4
|
from typing import (
|
6
|
-
TYPE_CHECKING,
|
7
5
|
Any,
|
8
6
|
Callable,
|
9
7
|
Final,
|
10
8
|
List,
|
11
9
|
Mapping,
|
12
|
-
Optional,
|
13
10
|
Union,
|
14
|
-
overload,
|
15
11
|
)
|
16
12
|
|
17
13
|
from classiq.interface.exceptions import ClassiqValueError
|
@@ -31,6 +27,7 @@ from classiq.interface.model.inplace_binary_operation import (
|
|
31
27
|
InplaceBinaryOperation,
|
32
28
|
)
|
33
29
|
from classiq.interface.model.invert import Invert
|
30
|
+
from classiq.interface.model.phase_operation import PhaseOperation
|
34
31
|
from classiq.interface.model.power import Power
|
35
32
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
36
33
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -79,57 +76,33 @@ def if_(
|
|
79
76
|
_validate_operand(else_)
|
80
77
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
81
78
|
source_ref = get_source_ref(sys._getframe(1))
|
82
|
-
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
83
|
-
ClassicalIf(
|
84
|
-
condition=Expression(expr=str(condition)),
|
85
|
-
then=_operand_to_body(then, "then"),
|
86
|
-
else_=_operand_to_body(else_, "else") if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
|
87
|
-
source_ref=source_ref,
|
88
|
-
)
|
89
|
-
)
|
90
|
-
|
91
|
-
|
92
|
-
@overload # FIXME: Remove overloading (CAD-21932)
|
93
|
-
def control(
|
94
|
-
ctrl: Union[QBit, QArray[QBit]], stmt_block: Union[QCallable, Callable[[], None]]
|
95
|
-
) -> None:
|
96
|
-
pass
|
97
|
-
|
98
79
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
)
|
103
|
-
|
80
|
+
if_stmt = ClassicalIf(
|
81
|
+
condition=Expression(expr=str(condition)),
|
82
|
+
then=_operand_to_body(then, "then"),
|
83
|
+
else_=_operand_to_body(else_, "else") if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
|
84
|
+
source_ref=source_ref,
|
85
|
+
)
|
86
|
+
if_stmt.set_generative_block("then", then)
|
87
|
+
if callable(else_):
|
88
|
+
if_stmt.set_generative_block("else", else_)
|
89
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(if_stmt)
|
104
90
|
|
105
91
|
|
106
92
|
def control(
|
107
93
|
ctrl: Union[SymbolicExpr, QBit, QArray[QBit]],
|
108
|
-
stmt_block:
|
109
|
-
operand: Optional[Union[QCallable, Callable[[], None]]] = None,
|
94
|
+
stmt_block: Union[QCallable, Callable[[], None]],
|
110
95
|
) -> None:
|
111
|
-
if operand is not None:
|
112
|
-
warnings.warn(
|
113
|
-
"Parameter 'operand' of function 'control' has been renamed to "
|
114
|
-
"'stmt_block'. Parameter 'operand' will be deprecated in a future "
|
115
|
-
"release.\nHint: Change `control(ctrl=..., operand=...)` to "
|
116
|
-
"`control(ctrl=..., stmt_block=...)` or `control(..., ...)`.",
|
117
|
-
category=DeprecationWarning,
|
118
|
-
stacklevel=2,
|
119
|
-
)
|
120
|
-
stmt_block = operand
|
121
|
-
if TYPE_CHECKING:
|
122
|
-
assert stmt_block is not None
|
123
96
|
_validate_operand(stmt_block)
|
124
97
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
125
98
|
source_ref = get_source_ref(sys._getframe(1))
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
source_ref=source_ref,
|
131
|
-
)
|
99
|
+
control_stmt = Control(
|
100
|
+
expression=Expression(expr=str(ctrl)),
|
101
|
+
body=_operand_to_body(stmt_block, "stmt_block"),
|
102
|
+
source_ref=source_ref,
|
132
103
|
)
|
104
|
+
control_stmt.set_generative_block("body", stmt_block)
|
105
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(control_stmt)
|
133
106
|
|
134
107
|
|
135
108
|
def inplace_add(
|
@@ -164,56 +137,22 @@ def inplace_xor(
|
|
164
137
|
)
|
165
138
|
|
166
139
|
|
167
|
-
@overload # FIXME: Remove overloading (CAD-21932)
|
168
140
|
def within_apply(
|
169
141
|
within: Callable[[], None],
|
170
142
|
apply: Callable[[], None],
|
171
143
|
) -> None:
|
172
|
-
pass
|
173
|
-
|
174
|
-
|
175
|
-
@overload
|
176
|
-
def within_apply(
|
177
|
-
within: Callable[[], List[None]],
|
178
|
-
apply: Callable[[], List[None]],
|
179
|
-
) -> None:
|
180
|
-
pass
|
181
|
-
|
182
|
-
|
183
|
-
def within_apply( # type:ignore[misc]
|
184
|
-
within: Optional[Callable[[], None]] = None,
|
185
|
-
apply: Optional[Callable[[], None]] = None,
|
186
|
-
compute: Optional[Callable[[], None]] = None,
|
187
|
-
action: Optional[Callable[[], None]] = None,
|
188
|
-
) -> None:
|
189
|
-
if compute is not None or action is not None:
|
190
|
-
warnings.warn(
|
191
|
-
"Parameters 'compute' and 'action' of function 'within_apply' have "
|
192
|
-
"been renamed to 'within' and 'apply' respectively. Parameters 'compute' "
|
193
|
-
"and 'action' will be deprecated in a future release.\nHint: Change "
|
194
|
-
"`within_apply(compute=..., action=...)` to "
|
195
|
-
"`within_apply(within=..., apply=...)` or `within_apply(..., ...)`.",
|
196
|
-
category=DeprecationWarning,
|
197
|
-
stacklevel=2,
|
198
|
-
)
|
199
|
-
if compute is not None:
|
200
|
-
within = compute
|
201
|
-
if action is not None:
|
202
|
-
apply = action
|
203
|
-
if TYPE_CHECKING:
|
204
|
-
assert within is not None
|
205
|
-
assert apply is not None
|
206
144
|
_validate_operand(within)
|
207
145
|
_validate_operand(apply)
|
208
146
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
209
147
|
source_ref = get_source_ref(sys._getframe(1))
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
source_ref=source_ref,
|
215
|
-
)
|
148
|
+
within_apply_stmt = WithinApply(
|
149
|
+
compute=_operand_to_body(within, "within"),
|
150
|
+
action=_operand_to_body(apply, "apply"),
|
151
|
+
source_ref=source_ref,
|
216
152
|
)
|
153
|
+
within_apply_stmt.set_generative_block("within", within)
|
154
|
+
within_apply_stmt.set_generative_block("apply", apply)
|
155
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(within_apply_stmt)
|
217
156
|
|
218
157
|
|
219
158
|
def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) -> None:
|
@@ -236,98 +175,52 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
|
|
236
175
|
"Argument 'iteration' to 'repeat' should be a callable that takes one integer argument."
|
237
176
|
)
|
238
177
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
source_ref=source_ref,
|
245
|
-
)
|
178
|
+
repeat_stmt = Repeat(
|
179
|
+
iter_var=inspect.getfullargspec(iteration).args[0],
|
180
|
+
count=Expression(expr=str(count)),
|
181
|
+
body=iteration_operand.body,
|
182
|
+
source_ref=source_ref,
|
246
183
|
)
|
184
|
+
repeat_stmt.set_generative_block("body", iteration)
|
185
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(repeat_stmt)
|
247
186
|
|
248
187
|
|
249
|
-
@overload # FIXME: Remove overloading (CAD-21932)
|
250
|
-
def power(
|
251
|
-
exponent: SymbolicExpr,
|
252
|
-
stmt_block: Union[QCallable, Callable[[], None]],
|
253
|
-
) -> None:
|
254
|
-
pass
|
255
|
-
|
256
|
-
|
257
|
-
@overload
|
258
188
|
def power(
|
259
|
-
exponent: int,
|
189
|
+
exponent: Union[SymbolicExpr, int],
|
260
190
|
stmt_block: Union[QCallable, Callable[[], None]],
|
261
191
|
) -> None:
|
262
|
-
pass
|
263
|
-
|
264
|
-
|
265
|
-
def power(
|
266
|
-
exponent: Optional[Union[SymbolicExpr, int]] = None,
|
267
|
-
stmt_block: Optional[Union[QCallable, Callable[[], None]]] = None,
|
268
|
-
power: Optional[Union[SymbolicExpr, int]] = None,
|
269
|
-
operand: Optional[Union[QCallable, Callable[[], None]]] = None,
|
270
|
-
) -> None:
|
271
|
-
if power is not None or operand is not None:
|
272
|
-
warnings.warn(
|
273
|
-
"Parameters 'exponent' and 'operand' of function 'power' have been "
|
274
|
-
"renamed to 'exponent' and 'stmt_block' respectively. Parameters "
|
275
|
-
"'exponent' and 'operand' will be deprecated in a future release.\nHint: "
|
276
|
-
"Change `power(power=..., operand=...)` to "
|
277
|
-
"`power(exponent=..., stmt_block=...)` or `power(..., ...)`.",
|
278
|
-
category=DeprecationWarning,
|
279
|
-
stacklevel=2,
|
280
|
-
)
|
281
|
-
if power is not None:
|
282
|
-
exponent = power
|
283
|
-
if operand is not None:
|
284
|
-
stmt_block = operand
|
285
|
-
if TYPE_CHECKING:
|
286
|
-
assert exponent is not None
|
287
|
-
assert stmt_block is not None
|
288
192
|
_validate_operand(stmt_block)
|
289
193
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
290
194
|
source_ref = get_source_ref(sys._getframe(1))
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
source_ref=source_ref,
|
296
|
-
)
|
195
|
+
power_stmt = Power(
|
196
|
+
power=Expression(expr=str(exponent)),
|
197
|
+
body=_operand_to_body(stmt_block, "stmt_block"),
|
198
|
+
source_ref=source_ref,
|
297
199
|
)
|
200
|
+
power_stmt.set_generative_block("body", stmt_block)
|
201
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(power_stmt)
|
298
202
|
|
299
203
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
204
|
+
def invert(stmt_block: Union[QCallable, Callable[[], None]]) -> None:
|
205
|
+
_validate_operand(stmt_block)
|
206
|
+
assert QCallable.CURRENT_EXPANDABLE is not None
|
207
|
+
source_ref = get_source_ref(sys._getframe(1))
|
208
|
+
invert_stmt = Invert(
|
209
|
+
body=_operand_to_body(stmt_block, "stmt_block"), source_ref=source_ref
|
210
|
+
)
|
211
|
+
invert_stmt.set_generative_block("body", stmt_block)
|
212
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(invert_stmt)
|
308
213
|
|
309
214
|
|
310
|
-
def
|
311
|
-
stmt_block: Optional[Union[QCallable, Callable[[], None]]] = None,
|
312
|
-
operand: Optional[Union[QCallable, Callable[[], None]]] = None,
|
313
|
-
) -> None:
|
314
|
-
if operand is not None:
|
315
|
-
warnings.warn(
|
316
|
-
"Parameter 'operand' of function 'invert' has been renamed to "
|
317
|
-
"'stmt_block'. Parameter 'operand' will be deprecated in a future "
|
318
|
-
"release.\nHint: Change `invert(operand=...)` to `invert(stmt_block=...)` "
|
319
|
-
"or `invert(...)`.",
|
320
|
-
category=DeprecationWarning,
|
321
|
-
stacklevel=2,
|
322
|
-
)
|
323
|
-
stmt_block = operand
|
324
|
-
if TYPE_CHECKING:
|
325
|
-
assert stmt_block is not None
|
326
|
-
_validate_operand(stmt_block)
|
215
|
+
def phase(expr: SymbolicExpr, theta: float = 1.0) -> None:
|
327
216
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
328
217
|
source_ref = get_source_ref(sys._getframe(1))
|
329
218
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
330
|
-
|
219
|
+
PhaseOperation(
|
220
|
+
expression=Expression(expr=str(expr)),
|
221
|
+
theta=Expression(expr=str(theta)),
|
222
|
+
source_ref=source_ref,
|
223
|
+
)
|
331
224
|
)
|
332
225
|
|
333
226
|
|
@@ -414,6 +307,7 @@ __all__ = [
|
|
414
307
|
"power",
|
415
308
|
"within_apply",
|
416
309
|
"repeat",
|
310
|
+
"phase",
|
417
311
|
]
|
418
312
|
|
419
313
|
|
@@ -174,7 +174,7 @@ def _interpret_generative_model(
|
|
174
174
|
gen_model,
|
175
175
|
{gen_func.func_decl.name: gen_func.func_decl for gen_func in gen_functions},
|
176
176
|
)
|
177
|
-
interpreter = Interpreter(gen_model, gen_functions)
|
177
|
+
interpreter = Interpreter(gen_model, gen_functions, is_frontend=True)
|
178
178
|
set_frontend_interpreter(interpreter)
|
179
179
|
functions_dict = nameables_to_dict(interpreter.expand().functions)
|
180
180
|
|
classiq/qmod/generative.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
from contextlib import contextmanager
|
2
|
-
from typing import TYPE_CHECKING, Iterator, Optional
|
2
|
+
from typing import TYPE_CHECKING, Any, Iterator, Optional
|
3
3
|
|
4
4
|
from classiq.interface.exceptions import ClassiqError
|
5
|
+
from classiq.interface.generator.expressions.expression import Expression
|
5
6
|
|
6
7
|
if TYPE_CHECKING:
|
7
8
|
from classiq.model_expansions.interpreter import Interpreter
|
@@ -20,8 +21,10 @@ def generative_mode_context(generative: bool) -> Iterator[None]:
|
|
20
21
|
global _GENERATIVE_MODE
|
21
22
|
previous = _GENERATIVE_MODE
|
22
23
|
_GENERATIVE_MODE = generative
|
23
|
-
|
24
|
-
|
24
|
+
try:
|
25
|
+
yield
|
26
|
+
finally:
|
27
|
+
_GENERATIVE_MODE = previous
|
25
28
|
|
26
29
|
|
27
30
|
@contextmanager
|
@@ -29,8 +32,10 @@ def enable_generative_expansion(enabled: bool) -> Iterator[None]:
|
|
29
32
|
global _GENERATIVE_ENABLED_SWITCH
|
30
33
|
previous = _GENERATIVE_ENABLED_SWITCH
|
31
34
|
_GENERATIVE_ENABLED_SWITCH = enabled
|
32
|
-
|
33
|
-
|
35
|
+
try:
|
36
|
+
yield
|
37
|
+
finally:
|
38
|
+
_GENERATIVE_ENABLED_SWITCH = previous
|
34
39
|
|
35
40
|
|
36
41
|
def is_generative_expansion_enabled() -> bool:
|
@@ -46,3 +51,7 @@ def get_frontend_interpreter() -> "Interpreter":
|
|
46
51
|
if _FRONTEND_INTERPRETER is None:
|
47
52
|
raise ClassiqError("Interpreter was not set")
|
48
53
|
return _FRONTEND_INTERPRETER
|
54
|
+
|
55
|
+
|
56
|
+
def interpret_expression(expr: str) -> Any:
|
57
|
+
return get_frontend_interpreter().evaluate(Expression(expr=expr)).value
|
@@ -37,6 +37,7 @@ from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperat
|
|
37
37
|
from classiq.interface.model.invert import Invert
|
38
38
|
from classiq.interface.model.model import Model
|
39
39
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
40
|
+
from classiq.interface.model.phase_operation import PhaseOperation
|
40
41
|
from classiq.interface.model.port_declaration import (
|
41
42
|
AnonPortDeclaration,
|
42
43
|
)
|
@@ -46,6 +47,7 @@ from classiq.interface.model.quantum_expressions.amplitude_loading_operation imp
|
|
46
47
|
)
|
47
48
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
48
49
|
ArithmeticOperation,
|
50
|
+
ArithmeticOperationKind,
|
49
51
|
)
|
50
52
|
from classiq.interface.model.quantum_function_call import (
|
51
53
|
OperandIdentifier,
|
@@ -185,13 +187,11 @@ class DSLPrettyPrinter(Visitor):
|
|
185
187
|
def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
|
186
188
|
params = ""
|
187
189
|
if qtype.size is not None:
|
188
|
-
assert qtype.is_signed is not None
|
189
|
-
assert qtype.fraction_digits is not None
|
190
|
-
|
191
190
|
params = "<{}>".format(
|
192
191
|
", ".join(
|
193
192
|
self.visit(param)
|
194
193
|
for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
|
194
|
+
if param is not None
|
195
195
|
)
|
196
196
|
)
|
197
197
|
|
@@ -255,6 +255,11 @@ class DSLPrettyPrinter(Visitor):
|
|
255
255
|
control += f"{self._indent}}}\n"
|
256
256
|
return control
|
257
257
|
|
258
|
+
def visit_PhaseOperation(self, op: PhaseOperation) -> str:
|
259
|
+
theta = f", {self.visit(op.theta)}" if op.theta else ""
|
260
|
+
phase = f"{self._indent}phase ({self.visit(op.expression)}{theta});\n"
|
261
|
+
return phase
|
262
|
+
|
258
263
|
def visit_ClassicalIf(self, op: ClassicalIf) -> str:
|
259
264
|
classical_if = f"{self._indent}if ({self.visit(op.condition)}) {{\n"
|
260
265
|
if not op.then:
|
@@ -340,7 +345,12 @@ class DSLPrettyPrinter(Visitor):
|
|
340
345
|
return f"{self.visit(var_ref.base_handle)}.{self.visit(var_ref.field)}"
|
341
346
|
|
342
347
|
def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
|
343
|
-
|
348
|
+
if arith_op.get_operation_kind() == ArithmeticOperationKind.Assignment:
|
349
|
+
op = "="
|
350
|
+
elif arith_op.get_operation_kind() == ArithmeticOperationKind.InplaceXor:
|
351
|
+
op = "^="
|
352
|
+
else:
|
353
|
+
op = "+="
|
344
354
|
return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)};\n"
|
345
355
|
|
346
356
|
def visit_AmplitudeLoadingOperation(
|
@@ -39,6 +39,7 @@ from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperat
|
|
39
39
|
from classiq.interface.model.invert import Invert
|
40
40
|
from classiq.interface.model.model import Model
|
41
41
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
42
|
+
from classiq.interface.model.phase_operation import PhaseOperation
|
42
43
|
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
43
44
|
from classiq.interface.model.power import Power
|
44
45
|
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
@@ -46,6 +47,7 @@ from classiq.interface.model.quantum_expressions.amplitude_loading_operation imp
|
|
46
47
|
)
|
47
48
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
48
49
|
ArithmeticOperation,
|
50
|
+
ArithmeticOperationKind,
|
49
51
|
)
|
50
52
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
51
53
|
QuantumAssignmentOperation,
|
@@ -114,12 +116,10 @@ class VariableDeclarationAssignment(Visitor):
|
|
114
116
|
|
115
117
|
params = []
|
116
118
|
if qtype.size is not None:
|
117
|
-
assert qtype.is_signed is not None
|
118
|
-
assert qtype.fraction_digits is not None
|
119
|
-
|
120
119
|
params = [
|
121
120
|
self.pretty_printer.visit(param)
|
122
121
|
for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
|
122
|
+
if param is not None
|
123
123
|
]
|
124
124
|
|
125
125
|
return "QNum", params
|
@@ -392,6 +392,11 @@ class PythonPrettyPrinter(Visitor):
|
|
392
392
|
self._imports["control"] = 1
|
393
393
|
return f"{self._indent}control({self.visit(op.expression)}, {self._visit_body(op.body)})\n"
|
394
394
|
|
395
|
+
def visit_PhaseOperation(self, op: PhaseOperation) -> str:
|
396
|
+
self._imports["phase"] = 1
|
397
|
+
theta = f", {self.visit(op.theta)}" if op.theta is not None else ""
|
398
|
+
return f"{self._indent}phase({self.visit(op.expression)},{theta})\n"
|
399
|
+
|
395
400
|
def visit_ClassicalIf(self, op: ClassicalIf) -> str:
|
396
401
|
self._imports["if_"] = 1
|
397
402
|
return f"{self._indent}if_(condition={self.visit(op.condition)}, then={self._visit_body(op.then)}, else_={self._visit_body(op.else_)})\n"
|
@@ -464,7 +469,12 @@ class PythonPrettyPrinter(Visitor):
|
|
464
469
|
return f"{self.visit(var_ref.base_handle)}.{self.visit(var_ref.field)}"
|
465
470
|
|
466
471
|
def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
|
467
|
-
|
472
|
+
if arith_op.get_operation_kind() == ArithmeticOperationKind.Assignment:
|
473
|
+
op = "|="
|
474
|
+
elif arith_op.get_operation_kind() == ArithmeticOperationKind.InplaceXor:
|
475
|
+
op = "^="
|
476
|
+
else:
|
477
|
+
op = "+="
|
468
478
|
return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)}\n"
|
469
479
|
|
470
480
|
def visit_AmplitudeLoadingOperation(
|
classiq/qmod/qmod_constant.py
CHANGED
@@ -16,11 +16,16 @@ from classiq.qmod.qmod_parameter import CParam, CParamList, CParamStruct
|
|
16
16
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
17
17
|
from classiq.qmod.utilities import qmod_val_to_expr_str
|
18
18
|
|
19
|
+
QMODULE_ERROR_MESSAGE = (
|
20
|
+
"Error trying to add a constant to a model without a current QModule."
|
21
|
+
)
|
22
|
+
|
19
23
|
|
20
24
|
class QConstant(SymbolicExpr):
|
21
25
|
CURRENT_QMODULE: Optional[ModelStateContainer] = None
|
22
26
|
|
23
27
|
def __init__(self, name: str, py_type: type, value: Any) -> None:
|
28
|
+
super().__init__(name, False)
|
24
29
|
self.name = name
|
25
30
|
self._py_type = py_type
|
26
31
|
self._value = value
|
@@ -30,10 +35,12 @@ class QConstant(SymbolicExpr):
|
|
30
35
|
QConstant.CURRENT_QMODULE = qmodule
|
31
36
|
|
32
37
|
def add_to_model(self) -> None:
|
38
|
+
from classiq.qmod.builtins.constants import __all__ as builtin_constants
|
39
|
+
|
40
|
+
if self.name in builtin_constants:
|
41
|
+
return
|
33
42
|
if QConstant.CURRENT_QMODULE is None:
|
34
|
-
raise ClassiqError(
|
35
|
-
"Error trying to add a constant to a model without a current QModule."
|
36
|
-
)
|
43
|
+
raise ClassiqError(QMODULE_ERROR_MESSAGE)
|
37
44
|
|
38
45
|
expr = qmod_val_to_expr_str(self._value)
|
39
46
|
if (
|
@@ -42,26 +49,32 @@ class QConstant(SymbolicExpr):
|
|
42
49
|
):
|
43
50
|
raise ClassiqError(f"Constant {self.name} is already defined in the model")
|
44
51
|
|
52
|
+
QConstant.CURRENT_QMODULE.constants[self.name] = self._get_constant_node()
|
53
|
+
|
54
|
+
def _get_constant_node(self) -> Constant:
|
45
55
|
if isinstance(self._value, QConstant):
|
46
|
-
QConstant.CURRENT_QMODULE
|
56
|
+
if QConstant.CURRENT_QMODULE is None:
|
57
|
+
raise ClassiqError(QMODULE_ERROR_MESSAGE)
|
58
|
+
return Constant(
|
47
59
|
name=self.name,
|
48
60
|
const_type=QConstant.CURRENT_QMODULE.constants[
|
49
61
|
self._value.name
|
50
62
|
].const_type,
|
51
63
|
value=Expression(expr=self._value.name),
|
52
64
|
)
|
53
|
-
else:
|
54
|
-
qmod_type = python_type_to_qmod(
|
55
|
-
self._py_type, qmodule=QConstant.CURRENT_QMODULE
|
56
|
-
)
|
57
|
-
if qmod_type is None:
|
58
|
-
raise ClassiqError("Invalid QMOD type")
|
59
65
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
)
|
66
|
+
qmod_type = python_type_to_qmod(
|
67
|
+
self._py_type, qmodule=QConstant.CURRENT_QMODULE
|
68
|
+
)
|
69
|
+
if qmod_type is None:
|
70
|
+
raise ClassiqError("Invalid QMOD type")
|
71
|
+
|
72
|
+
expr = qmod_val_to_expr_str(self._value)
|
73
|
+
return Constant(
|
74
|
+
name=self.name,
|
75
|
+
const_type=qmod_type,
|
76
|
+
value=Expression(expr=expr),
|
77
|
+
)
|
65
78
|
|
66
79
|
def __getattr__(self, name: str) -> CParam:
|
67
80
|
self.add_to_model()
|
@@ -100,6 +113,3 @@ class QConstant(SymbolicExpr):
|
|
100
113
|
qmod_type,
|
101
114
|
QConstant.CURRENT_QMODULE,
|
102
115
|
)[item]
|
103
|
-
|
104
|
-
def __str__(self) -> str:
|
105
|
-
return self.name
|