classiq 0.68.0__py3-none-any.whl → 0.70.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 +4 -8
- classiq/analyzer/analyzer.py +0 -18
- classiq/analyzer/url_utils.py +9 -4
- classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -11
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/torch_utils.py +1 -1
- classiq/execution/jobs.py +2 -5
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +8 -3
- classiq/interface/chemistry/operator.py +12 -28
- classiq/interface/debug_info/back_ref_util.py +22 -0
- classiq/interface/debug_info/debug_info.py +11 -21
- classiq/interface/executor/optimizer_preferences.py +1 -0
- classiq/interface/executor/quantum_instruction_set.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +21 -6
- classiq/interface/generator/arith/arithmetic_param_getters.py +3 -3
- classiq/interface/generator/circuit_code/circuit_code.py +4 -0
- classiq/interface/generator/circuit_code/types_and_constants.py +1 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +1 -2
- classiq/interface/generator/expressions/expression_types.py +8 -2
- classiq/interface/generator/expressions/proxies/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +75 -0
- classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +26 -0
- classiq/interface/generator/expressions/proxies/classical/classical_scalar_proxy.py +32 -0
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +31 -0
- classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
- classiq/interface/generator/expressions/{qmod_qarray_proxy.py → proxies/quantum/qmod_qarray_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qscalar_proxy.py → proxies/quantum/qmod_qscalar_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qstruct_proxy.py → proxies/quantum/qmod_qstruct_proxy.py} +3 -1
- classiq/interface/generator/functions/classical_type.py +34 -29
- classiq/interface/generator/functions/type_name.py +26 -2
- classiq/interface/generator/generated_circuit_data.py +84 -27
- classiq/interface/generator/model/preferences/preferences.py +1 -0
- classiq/interface/generator/quantum_program.py +0 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/interface/generator/types/enum_declaration.py +12 -1
- classiq/interface/ide/visual_model.py +0 -2
- classiq/interface/model/native_function_definition.py +0 -10
- classiq/interface/model/quantum_statement.py +1 -1
- classiq/interface/model/quantum_type.py +15 -3
- classiq/interface/server/routes.py +0 -6
- classiq/model_expansions/atomic_expression_functions_defs.py +9 -3
- classiq/model_expansions/evaluators/arg_type_match.py +4 -2
- classiq/model_expansions/evaluators/classical_expression.py +2 -2
- classiq/model_expansions/evaluators/control.py +1 -1
- classiq/model_expansions/evaluators/parameter_types.py +58 -16
- classiq/model_expansions/evaluators/quantum_type_utils.py +7 -57
- classiq/model_expansions/expression_evaluator.py +3 -1
- classiq/model_expansions/generative_functions.py +67 -7
- classiq/model_expansions/quantum_operations/arithmetic/__init__.py +0 -0
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +60 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +9 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +0 -13
- classiq/model_expansions/quantum_operations/quantum_function_call.py +0 -22
- classiq/model_expansions/scope.py +7 -6
- classiq/model_expansions/scope_initialization.py +20 -33
- classiq/model_expansions/transformers/model_renamer.py +13 -4
- classiq/model_expansions/visitors/variable_references.py +8 -4
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/amplitude_amplification.py +3 -7
- classiq/open_library/functions/discrete_sine_cosine_transform.py +4 -4
- classiq/open_library/functions/grover.py +2 -2
- classiq/open_library/functions/hea.py +3 -3
- classiq/open_library/functions/lookup_table.py +58 -0
- classiq/open_library/functions/modular_exponentiation.py +10 -20
- classiq/open_library/functions/qft_functions.py +2 -2
- classiq/open_library/functions/qsvt.py +8 -8
- classiq/open_library/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/classical_functions.py +24 -7
- classiq/qmod/builtins/enums.py +1 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/exponentiation.py +24 -0
- classiq/qmod/builtins/operations.py +26 -11
- classiq/qmod/cparam.py +32 -5
- classiq/qmod/declaration_inferrer.py +3 -1
- classiq/qmod/python_classical_type.py +10 -4
- classiq/qmod/qmod_parameter.py +8 -0
- classiq/qmod/qmod_variable.py +11 -14
- classiq/qmod/quantum_callable.py +2 -1
- classiq/qmod/quantum_function.py +3 -2
- classiq/qmod/semantics/annotation/call_annotation.py +0 -28
- classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
- classiq/qmod/semantics/error_manager.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -1
- classiq/qmod/semantics/validation/type_hints.py +29 -0
- classiq/qmod/utilities.py +67 -2
- classiq/synthesis.py +9 -6
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/METADATA +10 -12
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/RECORD +95 -84
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/WHEEL +1 -1
- classiq/interface/execution/jobs.py +0 -31
- /classiq/interface/generator/expressions/{qmod_struct_instance.py → proxies/classical/qmod_struct_instance.py} +0 -0
- /classiq/interface/generator/expressions/{qmod_sized_proxy.py → proxies/quantum/qmod_sized_proxy.py} +0 -0
@@ -48,7 +48,7 @@ from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QScalar, QVa
|
|
48
48
|
from classiq.qmod.quantum_callable import QCallable
|
49
49
|
from classiq.qmod.quantum_expandable import prepare_arg
|
50
50
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
51
|
-
from classiq.qmod.utilities import get_source_ref
|
51
|
+
from classiq.qmod.utilities import Statements, get_source_ref, suppress_return_value
|
52
52
|
|
53
53
|
_MISSING_VALUE: Final[int] = -1
|
54
54
|
|
@@ -63,6 +63,7 @@ def allocate(out: Output[QVar]) -> None:
|
|
63
63
|
pass
|
64
64
|
|
65
65
|
|
66
|
+
@suppress_return_value
|
66
67
|
def allocate(*args: Any, **kwargs: Any) -> None:
|
67
68
|
"""
|
68
69
|
Initialize a quantum variable to a new quantum object in the zero state:
|
@@ -106,6 +107,7 @@ def allocate(*args: Any, **kwargs: Any) -> None:
|
|
106
107
|
)
|
107
108
|
|
108
109
|
|
110
|
+
@suppress_return_value
|
109
111
|
def bind(
|
110
112
|
source: Union[Input[QVar], list[Input[QVar]]],
|
111
113
|
destination: Union[Output[QVar], list[Output[QVar]]],
|
@@ -125,10 +127,11 @@ def bind(
|
|
125
127
|
)
|
126
128
|
|
127
129
|
|
130
|
+
@suppress_return_value
|
128
131
|
def if_(
|
129
132
|
condition: Union[SymbolicExpr, bool],
|
130
|
-
then: Union[QCallable, Callable[[],
|
131
|
-
else_: Union[QCallable, Callable[[],
|
133
|
+
then: Union[QCallable, Callable[[], Statements]],
|
134
|
+
else_: Union[QCallable, Callable[[], Statements], int] = _MISSING_VALUE,
|
132
135
|
) -> None:
|
133
136
|
_validate_operand(then)
|
134
137
|
if else_ != _MISSING_VALUE:
|
@@ -149,10 +152,11 @@ def if_(
|
|
149
152
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(if_stmt)
|
150
153
|
|
151
154
|
|
155
|
+
@suppress_return_value
|
152
156
|
def control(
|
153
157
|
ctrl: Union[SymbolicExpr, QBit, QArray[QBit]],
|
154
|
-
stmt_block: Union[QCallable, Callable[[],
|
155
|
-
else_block: Union[QCallable, Callable[[],
|
158
|
+
stmt_block: Union[QCallable, Callable[[], Statements]],
|
159
|
+
else_block: Union[QCallable, Callable[[], Statements], None] = None,
|
156
160
|
) -> None:
|
157
161
|
_validate_operand(stmt_block)
|
158
162
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
@@ -170,6 +174,7 @@ def control(
|
|
170
174
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(control_stmt)
|
171
175
|
|
172
176
|
|
177
|
+
@suppress_return_value
|
173
178
|
def assign(expression: SymbolicExpr, target_var: QScalar) -> None:
|
174
179
|
"""
|
175
180
|
Initialize a scalar quantum variable using an arithmetic expression.
|
@@ -194,6 +199,7 @@ def assign(expression: SymbolicExpr, target_var: QScalar) -> None:
|
|
194
199
|
)
|
195
200
|
|
196
201
|
|
202
|
+
@suppress_return_value
|
197
203
|
def assign_amplitude(expression: SymbolicExpr, target_var: QScalar) -> None:
|
198
204
|
"""
|
199
205
|
Perform an amplitude-encoding assignment operation on a quantum variable and a
|
@@ -216,6 +222,7 @@ def assign_amplitude(expression: SymbolicExpr, target_var: QScalar) -> None:
|
|
216
222
|
)
|
217
223
|
|
218
224
|
|
225
|
+
@suppress_return_value
|
219
226
|
def inplace_add(expression: SymbolicExpr, target_var: QScalar) -> None:
|
220
227
|
"""
|
221
228
|
Add an arithmetic expression to a quantum variable.
|
@@ -238,6 +245,7 @@ def inplace_add(expression: SymbolicExpr, target_var: QScalar) -> None:
|
|
238
245
|
)
|
239
246
|
|
240
247
|
|
248
|
+
@suppress_return_value
|
241
249
|
def inplace_xor(expression: SymbolicExpr, target_var: QScalar) -> None:
|
242
250
|
"""
|
243
251
|
Bitwise-XOR a quantum variable with an arithmetic expression.
|
@@ -260,9 +268,10 @@ def inplace_xor(expression: SymbolicExpr, target_var: QScalar) -> None:
|
|
260
268
|
)
|
261
269
|
|
262
270
|
|
271
|
+
@suppress_return_value
|
263
272
|
def within_apply(
|
264
|
-
within: Callable[[],
|
265
|
-
apply: Callable[[],
|
273
|
+
within: Callable[[], Statements],
|
274
|
+
apply: Callable[[], Statements],
|
266
275
|
) -> None:
|
267
276
|
_validate_operand(within)
|
268
277
|
_validate_operand(apply)
|
@@ -279,7 +288,10 @@ def within_apply(
|
|
279
288
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(within_apply_stmt)
|
280
289
|
|
281
290
|
|
282
|
-
|
291
|
+
@suppress_return_value
|
292
|
+
def repeat(
|
293
|
+
count: Union[SymbolicExpr, int], iteration: Callable[[int], Statements]
|
294
|
+
) -> None:
|
283
295
|
_validate_operand(iteration)
|
284
296
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
285
297
|
source_ref = get_source_ref(sys._getframe(1))
|
@@ -310,9 +322,10 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
|
|
310
322
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(repeat_stmt)
|
311
323
|
|
312
324
|
|
325
|
+
@suppress_return_value
|
313
326
|
def power(
|
314
327
|
exponent: Union[SymbolicExpr, int],
|
315
|
-
stmt_block: Union[QCallable, Callable[[],
|
328
|
+
stmt_block: Union[QCallable, Callable[[], Statements]],
|
316
329
|
) -> None:
|
317
330
|
_validate_operand(stmt_block)
|
318
331
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
@@ -327,7 +340,8 @@ def power(
|
|
327
340
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(power_stmt)
|
328
341
|
|
329
342
|
|
330
|
-
|
343
|
+
@suppress_return_value
|
344
|
+
def invert(stmt_block: Union[QCallable, Callable[[], Statements]]) -> None:
|
331
345
|
_validate_operand(stmt_block)
|
332
346
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
333
347
|
source_ref = get_source_ref(sys._getframe(1))
|
@@ -339,6 +353,7 @@ def invert(stmt_block: Union[QCallable, Callable[[], None]]) -> None:
|
|
339
353
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(invert_stmt)
|
340
354
|
|
341
355
|
|
356
|
+
@suppress_return_value
|
342
357
|
def phase(expr: SymbolicExpr, theta: float = 1.0) -> None:
|
343
358
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
344
359
|
source_ref = get_source_ref(sys._getframe(1))
|
@@ -402,7 +417,7 @@ def _get_operand_hint(
|
|
402
417
|
|
403
418
|
|
404
419
|
def _operand_to_body(
|
405
|
-
callable_: Union[QCallable, Callable[[],
|
420
|
+
callable_: Union[QCallable, Callable[[], Statements]], param_name: str
|
406
421
|
) -> StatementBlock:
|
407
422
|
op_name = sys._getframe(1).f_code.co_name
|
408
423
|
if (
|
classiq/qmod/cparam.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import sys
|
2
|
+
from abc import ABC, abstractmethod
|
2
3
|
from typing import ( # type: ignore[attr-defined]
|
3
4
|
TYPE_CHECKING,
|
4
5
|
Any,
|
@@ -9,6 +10,8 @@ from typing import ( # type: ignore[attr-defined]
|
|
9
10
|
|
10
11
|
from typing_extensions import ParamSpec
|
11
12
|
|
13
|
+
from classiq.interface.exceptions import ClassiqValueError
|
14
|
+
|
12
15
|
from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
|
13
16
|
|
14
17
|
if TYPE_CHECKING:
|
@@ -21,18 +24,34 @@ else:
|
|
21
24
|
|
22
25
|
class CParam(SymbolicSuperclass):
|
23
26
|
def __init__(self, expr: str) -> None:
|
24
|
-
super().__init__(expr, False)
|
27
|
+
super().__init__(expr, is_quantum=False)
|
28
|
+
|
29
|
+
|
30
|
+
class CParamAbstract(ABC, CParam):
|
31
|
+
|
32
|
+
def __new__(cls, *args: Any, **kwargs: Any) -> "CParamAbstract":
|
33
|
+
raise ClassiqValueError(
|
34
|
+
f"{cls.__name__} is a Qmod type hint for a classical parameter and it cannot be instantiated. "
|
35
|
+
f"Use regular Pythonic values as arguments instead. "
|
36
|
+
f"Example:\n\n"
|
37
|
+
f"def foo(val: {cls.__name__}) -> None: ...\n\n"
|
38
|
+
f"foo({_EXAMPLE_VALUES[cls.__name__]}) # Correct\n"
|
39
|
+
)
|
25
40
|
|
41
|
+
@abstractmethod
|
42
|
+
def __init__(self) -> None:
|
43
|
+
pass
|
26
44
|
|
27
|
-
|
45
|
+
|
46
|
+
class CInt(CParamAbstract):
|
28
47
|
pass
|
29
48
|
|
30
49
|
|
31
|
-
class CReal(
|
50
|
+
class CReal(CParamAbstract):
|
32
51
|
pass
|
33
52
|
|
34
53
|
|
35
|
-
class CBool(
|
54
|
+
class CBool(CParamAbstract):
|
36
55
|
pass
|
37
56
|
|
38
57
|
|
@@ -47,7 +66,7 @@ class ArrayBase(Generic[_P]):
|
|
47
66
|
return _GenericAlias(cls, args)
|
48
67
|
|
49
68
|
|
50
|
-
class CArray(
|
69
|
+
class CArray(CParamAbstract, ArrayBase[_P]):
|
51
70
|
if TYPE_CHECKING:
|
52
71
|
|
53
72
|
@property
|
@@ -62,3 +81,11 @@ Array = CArray
|
|
62
81
|
class CParamScalar(CParam, SymbolicExpr):
|
63
82
|
def __hash__(self) -> int:
|
64
83
|
return hash(str(self))
|
84
|
+
|
85
|
+
|
86
|
+
_EXAMPLE_VALUES: dict[str, Any] = {
|
87
|
+
CInt.__name__: 1,
|
88
|
+
CReal.__name__: 1.0,
|
89
|
+
CBool.__name__: True,
|
90
|
+
CArray.__name__: [1, 2],
|
91
|
+
}
|
@@ -38,6 +38,7 @@ from classiq.qmod.model_state_container import ModelStateContainer
|
|
38
38
|
from classiq.qmod.python_classical_type import PythonClassicalType
|
39
39
|
from classiq.qmod.qmod_variable import QVar
|
40
40
|
from classiq.qmod.quantum_callable import QCallableList
|
41
|
+
from classiq.qmod.semantics.validation.type_hints import validate_annotation
|
41
42
|
from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
|
42
43
|
|
43
44
|
if sys.version_info[0:2] >= (3, 9):
|
@@ -123,7 +124,7 @@ def _extract_operand_decl(
|
|
123
124
|
|
124
125
|
|
125
126
|
def _extract_operand_param(py_type: Any) -> tuple[Optional[str], Any]:
|
126
|
-
if
|
127
|
+
if get_origin(py_type) is not Annotated:
|
127
128
|
return None, py_type
|
128
129
|
args = get_args(py_type)
|
129
130
|
if len(args) == 2:
|
@@ -163,6 +164,7 @@ def _extract_positional_args(
|
|
163
164
|
) -> Sequence[AnonPositionalArg]:
|
164
165
|
result: list[AnonPositionalArg] = []
|
165
166
|
for name, py_type in args:
|
167
|
+
validate_annotation(py_type)
|
166
168
|
if name == "return":
|
167
169
|
continue
|
168
170
|
name = unmangle_keyword(name)
|
@@ -30,16 +30,22 @@ CARRAY_ERROR_MESSAGE = (
|
|
30
30
|
|
31
31
|
class PythonClassicalType:
|
32
32
|
def convert(self, py_type: type) -> Optional[ConcreteClassicalType]:
|
33
|
-
if py_type is int
|
33
|
+
if py_type is int:
|
34
|
+
return Integer().set_generative()
|
35
|
+
elif py_type is CInt:
|
34
36
|
return Integer()
|
35
|
-
elif py_type in (float, complex)
|
37
|
+
elif py_type in (float, complex):
|
38
|
+
return Real().set_generative()
|
39
|
+
elif py_type is CReal:
|
36
40
|
return Real()
|
37
|
-
elif py_type is bool
|
41
|
+
elif py_type is bool:
|
42
|
+
return Bool().set_generative()
|
43
|
+
elif py_type is CBool:
|
38
44
|
return Bool()
|
39
45
|
elif get_origin(py_type) is list:
|
40
46
|
element_type = self.convert(get_args(py_type)[0])
|
41
47
|
if element_type is not None:
|
42
|
-
return ClassicalList(element_type=element_type)
|
48
|
+
return ClassicalList(element_type=element_type).set_generative()
|
43
49
|
elif get_origin(py_type) is CArray:
|
44
50
|
array_args = version_portable_get_args(py_type)
|
45
51
|
if len(array_args) == 1:
|
classiq/qmod/qmod_parameter.py
CHANGED
@@ -22,6 +22,11 @@ from classiq.qmod.cparam import ( # noqa: F401
|
|
22
22
|
CParamScalar,
|
23
23
|
CReal,
|
24
24
|
)
|
25
|
+
from classiq.qmod.generative import (
|
26
|
+
generative_mode_context,
|
27
|
+
interpret_expression,
|
28
|
+
is_generative_mode,
|
29
|
+
)
|
25
30
|
from classiq.qmod.model_state_container import ModelStateContainer
|
26
31
|
from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
|
27
32
|
|
@@ -66,6 +71,9 @@ class CParamList(CParam):
|
|
66
71
|
|
67
72
|
@property
|
68
73
|
def len(self) -> CParamScalar:
|
74
|
+
if is_generative_mode():
|
75
|
+
with generative_mode_context(False):
|
76
|
+
return interpret_expression(str(self.len))
|
69
77
|
return CParamScalar(f"get_field({self}, 'len')")
|
70
78
|
|
71
79
|
|
classiq/qmod/qmod_variable.py
CHANGED
@@ -23,7 +23,7 @@ from typing_extensions import ParamSpec, Self, _AnnotatedAlias
|
|
23
23
|
from classiq.interface.exceptions import ClassiqValueError
|
24
24
|
from classiq.interface.generator.expressions.expression import Expression
|
25
25
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
26
|
-
from classiq.interface.generator.expressions.qmod_qarray_proxy import (
|
26
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy import (
|
27
27
|
ILLEGAL_SLICE_MSG,
|
28
28
|
ILLEGAL_SLICING_STEP_MSG,
|
29
29
|
)
|
@@ -72,12 +72,6 @@ from classiq.qmod.utilities import (
|
|
72
72
|
)
|
73
73
|
|
74
74
|
|
75
|
-
def _is_input_output_typehint(type_hint: Any) -> bool:
|
76
|
-
return isinstance(type_hint, _AnnotatedAlias) and isinstance(
|
77
|
-
type_hint.__metadata__[0], PortDeclarationDirection
|
78
|
-
)
|
79
|
-
|
80
|
-
|
81
75
|
def get_type_hint_expr(type_hint: Any) -> str:
|
82
76
|
if isinstance(type_hint, ForwardRef): # expression in string literal
|
83
77
|
return str(type_hint.__forward_arg__)
|
@@ -143,9 +137,12 @@ class QVar(Symbolic):
|
|
143
137
|
|
144
138
|
@staticmethod
|
145
139
|
def from_type_hint(type_hint: Any) -> Optional[type["QVar"]]:
|
146
|
-
|
147
|
-
|
148
|
-
|
140
|
+
non_annotated_type = (
|
141
|
+
type_hint.__origin__
|
142
|
+
if isinstance(type_hint, _AnnotatedAlias)
|
143
|
+
else type_hint
|
144
|
+
)
|
145
|
+
type_ = get_origin(non_annotated_type) or non_annotated_type
|
149
146
|
if issubclass(type_, QVar):
|
150
147
|
if issubclass(type_, QStruct):
|
151
148
|
with _no_current_expandable():
|
@@ -170,10 +167,10 @@ class QVar(Symbolic):
|
|
170
167
|
|
171
168
|
@classmethod
|
172
169
|
def port_direction(cls, type_hint: Any) -> PortDeclarationDirection:
|
173
|
-
if
|
174
|
-
|
175
|
-
|
176
|
-
|
170
|
+
if isinstance(type_hint, _AnnotatedAlias):
|
171
|
+
for metadata in type_hint.__metadata__:
|
172
|
+
if isinstance(metadata, PortDeclarationDirection):
|
173
|
+
return metadata
|
177
174
|
return PortDeclarationDirection.Inout
|
178
175
|
|
179
176
|
def __str__(self) -> str:
|
classiq/qmod/quantum_callable.py
CHANGED
@@ -21,7 +21,7 @@ from classiq.interface.model.quantum_type import QuantumType
|
|
21
21
|
from classiq.interface.source_reference import SourceReference
|
22
22
|
|
23
23
|
from classiq.qmod.cparam import CInt
|
24
|
-
from classiq.qmod.utilities import get_source_ref
|
24
|
+
from classiq.qmod.utilities import get_source_ref, suppress_return_value
|
25
25
|
|
26
26
|
if TYPE_CHECKING:
|
27
27
|
from classiq.qmod.quantum_expandable import QTerminalCallable
|
@@ -48,6 +48,7 @@ class QCallable(Generic[P], ABC):
|
|
48
48
|
CURRENT_EXPANDABLE: ClassVar[Optional[QExpandableInterface]] = None
|
49
49
|
FRAME_DEPTH = 1
|
50
50
|
|
51
|
+
@suppress_return_value
|
51
52
|
def __call__(self, *args: Any, **kwargs: Any) -> None:
|
52
53
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
53
54
|
source_ref = get_source_ref(sys._getframe(self.FRAME_DEPTH))
|
classiq/qmod/quantum_function.py
CHANGED
@@ -24,10 +24,11 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
24
24
|
)
|
25
25
|
|
26
26
|
from classiq.qmod.classical_function import CFunc
|
27
|
+
from classiq.qmod.cparam import CParamAbstract
|
27
28
|
from classiq.qmod.declaration_inferrer import infer_func_decl
|
28
29
|
from classiq.qmod.generative import set_frontend_interpreter
|
29
30
|
from classiq.qmod.qmod_constant import QConstant
|
30
|
-
from classiq.qmod.qmod_parameter import CArray
|
31
|
+
from classiq.qmod.qmod_parameter import CArray
|
31
32
|
from classiq.qmod.qmod_variable import QVar
|
32
33
|
from classiq.qmod.quantum_callable import QCallable, QCallableList
|
33
34
|
from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
|
@@ -308,7 +309,7 @@ def _validate_no_gen_params(annotations: dict[str, Any]) -> None:
|
|
308
309
|
for name, annotation in annotations.items()
|
309
310
|
if not (
|
310
311
|
name == "return"
|
311
|
-
or (isclass(annotation) and issubclass(annotation,
|
312
|
+
or (isclass(annotation) and issubclass(annotation, CParamAbstract))
|
312
313
|
or (isclass(annotation) and is_dataclass(annotation))
|
313
314
|
or (isclass(annotation) and isinstance(annotation, EnumMeta))
|
314
315
|
or get_origin(annotation) is CArray
|
@@ -3,18 +3,9 @@ from contextlib import contextmanager
|
|
3
3
|
from typing import Any, Optional
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqError
|
6
|
-
from classiq.interface.generator.expressions.expression import Expression
|
7
|
-
from classiq.interface.generator.functions.classical_type import Integer
|
8
|
-
from classiq.interface.generator.functions.port_declaration import (
|
9
|
-
PortDeclarationDirection,
|
10
|
-
)
|
11
|
-
from classiq.interface.model.classical_parameter_declaration import (
|
12
|
-
ClassicalParameterDeclaration,
|
13
|
-
)
|
14
6
|
from classiq.interface.model.model import Model
|
15
7
|
from classiq.interface.model.model_visitor import ModelVisitor
|
16
8
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
17
|
-
from classiq.interface.model.port_declaration import PortDeclaration
|
18
9
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
19
10
|
from classiq.interface.model.quantum_function_declaration import (
|
20
11
|
AnonQuantumOperandDeclaration,
|
@@ -24,36 +15,17 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
24
15
|
from classiq.interface.model.quantum_lambda_function import (
|
25
16
|
QuantumLambdaFunction,
|
26
17
|
)
|
27
|
-
from classiq.interface.model.quantum_type import QuantumBitvector
|
28
18
|
|
29
19
|
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
30
20
|
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
31
21
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
32
22
|
from classiq.qmod.semantics.lambdas import get_renamed_parameters
|
33
23
|
|
34
|
-
ALLOCATE_DECL_FOR_COMPATIBILITY = QuantumFunctionDeclaration(
|
35
|
-
name="allocate",
|
36
|
-
positional_arg_declarations=[
|
37
|
-
ClassicalParameterDeclaration(
|
38
|
-
name="num_qubits",
|
39
|
-
classical_type=Integer(),
|
40
|
-
),
|
41
|
-
PortDeclaration(
|
42
|
-
name="out",
|
43
|
-
quantum_type=QuantumBitvector(length=Expression(expr="num_qubits")),
|
44
|
-
direction=PortDeclarationDirection.Output,
|
45
|
-
),
|
46
|
-
],
|
47
|
-
)
|
48
|
-
|
49
24
|
|
50
25
|
def _annotate_function_call_decl(
|
51
26
|
fc: QuantumFunctionCall,
|
52
27
|
function_dict: Mapping[str, QuantumFunctionDeclaration],
|
53
28
|
) -> None:
|
54
|
-
if fc.function == "allocate": # FIXME: Remove compatibility (CAD-25935)
|
55
|
-
fc.set_func_decl(ALLOCATE_DECL_FOR_COMPATIBILITY)
|
56
|
-
return
|
57
29
|
if fc._func_decl is None:
|
58
30
|
func_decl = function_dict.get(fc.func_name)
|
59
31
|
if func_decl is None:
|
@@ -9,8 +9,18 @@ class QStructAnnotator(ModelVisitor):
|
|
9
9
|
self._visited: set[TypeName] = set()
|
10
10
|
|
11
11
|
def visit_TypeName(self, type_name: TypeName) -> None:
|
12
|
+
self._annotate_quantum_struct(type_name)
|
13
|
+
self._annotate_classical_struct(type_name)
|
14
|
+
|
15
|
+
def _annotate_quantum_struct(self, type_name: TypeName) -> None:
|
16
|
+
if (
|
17
|
+
type_name.has_classical_struct_decl
|
18
|
+
or type_name.has_fields
|
19
|
+
or type_name in self._visited
|
20
|
+
):
|
21
|
+
return
|
12
22
|
decl = QMODULE.qstruct_decls.get(type_name.name)
|
13
|
-
if decl is None
|
23
|
+
if decl is None:
|
14
24
|
return
|
15
25
|
self._visited.add(type_name)
|
16
26
|
new_fields = {
|
@@ -21,3 +31,13 @@ class QStructAnnotator(ModelVisitor):
|
|
21
31
|
# qstructs
|
22
32
|
self.visit(new_fields)
|
23
33
|
type_name.set_fields(new_fields)
|
34
|
+
|
35
|
+
def _annotate_classical_struct(self, type_name: TypeName) -> None:
|
36
|
+
if type_name.has_classical_struct_decl or type_name.has_fields:
|
37
|
+
return
|
38
|
+
decl = QMODULE.type_decls.get(type_name.name)
|
39
|
+
if decl is None:
|
40
|
+
return
|
41
|
+
type_name.set_classical_struct_decl(decl)
|
42
|
+
for field_type in decl.variables.values():
|
43
|
+
self.visit(field_type)
|
@@ -25,7 +25,7 @@ def _validate_main_classical_param_type(
|
|
25
25
|
) -> None:
|
26
26
|
if isinstance(param, ClassicalList):
|
27
27
|
raise ClassiqExpansionError(
|
28
|
-
f"Classical array parameter {param_name!r} of function 'main' must
|
28
|
+
f"Classical array parameter {param_name!r} of function 'main' must "
|
29
29
|
f"specify array length",
|
30
30
|
)
|
31
31
|
if isinstance(param, ClassicalArray):
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from typing_extensions import _AnnotatedAlias
|
4
|
+
|
5
|
+
from classiq.interface.exceptions import ClassiqValueError
|
6
|
+
from classiq.interface.generator.functions.port_declaration import (
|
7
|
+
PortDeclarationDirection,
|
8
|
+
)
|
9
|
+
|
10
|
+
annotation_map: dict[PortDeclarationDirection, str] = {
|
11
|
+
PortDeclarationDirection.Input: PortDeclarationDirection.Input.name,
|
12
|
+
PortDeclarationDirection.Output: PortDeclarationDirection.Output.name,
|
13
|
+
}
|
14
|
+
|
15
|
+
|
16
|
+
def validate_annotation(type_hint: Any) -> None:
|
17
|
+
if not isinstance(type_hint, _AnnotatedAlias):
|
18
|
+
return
|
19
|
+
directions: list[PortDeclarationDirection] = [
|
20
|
+
direction
|
21
|
+
for direction in type_hint.__metadata__
|
22
|
+
if isinstance(direction, PortDeclarationDirection)
|
23
|
+
]
|
24
|
+
if len(directions) <= 1:
|
25
|
+
return
|
26
|
+
raise ClassiqValueError(
|
27
|
+
f"Multiple directions are not allowed in a single type hint: "
|
28
|
+
f"[{', '.join(annotation_map[direction] for direction in reversed(directions))}]\n"
|
29
|
+
)
|
classiq/qmod/utilities.py
CHANGED
@@ -3,16 +3,33 @@ import inspect
|
|
3
3
|
import itertools
|
4
4
|
import keyword
|
5
5
|
import sys
|
6
|
+
from collections import Counter
|
6
7
|
from collections.abc import Iterable
|
7
8
|
from enum import Enum as PythonEnum
|
8
9
|
from types import FrameType
|
9
|
-
from typing import
|
10
|
+
from typing import (
|
11
|
+
TYPE_CHECKING,
|
12
|
+
Any,
|
13
|
+
Callable,
|
14
|
+
ForwardRef,
|
15
|
+
Literal,
|
16
|
+
Optional,
|
17
|
+
Union,
|
18
|
+
get_args,
|
19
|
+
get_origin,
|
20
|
+
overload,
|
21
|
+
)
|
22
|
+
|
23
|
+
from typing_extensions import ParamSpec
|
10
24
|
|
11
|
-
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
25
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
12
26
|
QmodStructInstance,
|
13
27
|
)
|
14
28
|
from classiq.interface.source_reference import SourceReference
|
15
29
|
|
30
|
+
if TYPE_CHECKING:
|
31
|
+
from classiq.qmod.qmod_variable import QVar
|
32
|
+
|
16
33
|
DEFAULT_DECIMAL_PRECISION = 4
|
17
34
|
|
18
35
|
|
@@ -132,3 +149,51 @@ def varname(depth: int) -> Optional[str]:
|
|
132
149
|
if not var_name.isidentifier():
|
133
150
|
return None
|
134
151
|
return var_name
|
152
|
+
|
153
|
+
|
154
|
+
Params = ParamSpec("Params")
|
155
|
+
|
156
|
+
|
157
|
+
def suppress_return_value(func: Callable[Params, None]) -> Callable[Params, None]:
|
158
|
+
# An empty decorator suppresses mypy's func-returns-value error when assigning the
|
159
|
+
# return value of a None-returning function
|
160
|
+
return func
|
161
|
+
|
162
|
+
|
163
|
+
Statements = Union[None, list[Union[None, "QVar"]], tuple[Union[None, "QVar"], ...]]
|
164
|
+
|
165
|
+
|
166
|
+
def _eval_qnum(val: int, size: int, is_signed: bool, fraction_digits: int) -> float:
|
167
|
+
if val < 0 or val >= 2**size:
|
168
|
+
raise ValueError
|
169
|
+
if size == 1 and is_signed and fraction_digits == 1:
|
170
|
+
return -0.5 if val == 1 else 0
|
171
|
+
if is_signed and val & (1 << (size - 1)) > 0:
|
172
|
+
val ^= 1 << (size - 1)
|
173
|
+
val -= 1 << (size - 1)
|
174
|
+
return val * 2**-fraction_digits
|
175
|
+
|
176
|
+
|
177
|
+
def qnum_values(size: int, is_signed: bool, fraction_digits: int) -> list[float]:
|
178
|
+
return [_eval_qnum(i, size, is_signed, fraction_digits) for i in range(2**size)]
|
179
|
+
|
180
|
+
|
181
|
+
def qnum_attributes(max_size: int) -> list[tuple[int, bool, int]]:
|
182
|
+
return [(1, True, 1)] + [
|
183
|
+
(size, is_signed, fraction_digits)
|
184
|
+
for size in range(1, max_size + 1)
|
185
|
+
for is_signed in (False, True)
|
186
|
+
for fraction_digits in range(size - int(is_signed) + 1)
|
187
|
+
]
|
188
|
+
|
189
|
+
|
190
|
+
_VAR_NAME_COUNTER: Counter[str] = Counter()
|
191
|
+
|
192
|
+
|
193
|
+
def get_temp_var_name(var_name: str = "temp") -> str:
|
194
|
+
n = _VAR_NAME_COUNTER[var_name]
|
195
|
+
_VAR_NAME_COUNTER[var_name] += 1
|
196
|
+
return f"{var_name}_{n}"
|
197
|
+
|
198
|
+
|
199
|
+
RealFunction = Callable[Params, float]
|
classiq/synthesis.py
CHANGED
@@ -3,16 +3,15 @@ from typing import Any, NewType, Optional, Union
|
|
3
3
|
import pydantic
|
4
4
|
|
5
5
|
from classiq.interface.analyzer.result import QasmCode
|
6
|
-
from classiq.interface.exceptions import ClassiqValueError
|
6
|
+
from classiq.interface.exceptions import ClassiqError, ClassiqValueError
|
7
7
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
8
8
|
from classiq.interface.generator.model.constraints import Constraints
|
9
9
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
10
|
-
from classiq.interface.model.model import Model, SerializedModel
|
10
|
+
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model, SerializedModel
|
11
11
|
|
12
12
|
from classiq import QuantumProgram
|
13
13
|
from classiq._internals import async_utils
|
14
14
|
from classiq._internals.api_wrapper import ApiWrapper
|
15
|
-
from classiq.qmod.create_model_function import create_model
|
16
15
|
from classiq.qmod.quantum_function import GenerativeQFunc, QFunc
|
17
16
|
|
18
17
|
SerializedQuantumProgram = NewType("SerializedQuantumProgram", str)
|
@@ -90,9 +89,13 @@ def synthesize(
|
|
90
89
|
SerializedQuantumProgram: Quantum program serialized as a string. (See: QuantumProgram)
|
91
90
|
"""
|
92
91
|
if isinstance(model, (QFunc, GenerativeQFunc)):
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
func_name = model._py_callable.__name__
|
93
|
+
if func_name != MAIN_FUNCTION_NAME:
|
94
|
+
raise ClassiqError(
|
95
|
+
f"The entry point function must be named 'main', got {func_name!r}"
|
96
|
+
)
|
97
|
+
model_obj = model.create_model(constraints=constraints, preferences=preferences)
|
98
|
+
serialized_model = model_obj.get_model()
|
96
99
|
else:
|
97
100
|
serialized_model = model
|
98
101
|
result = async_utils.run(synthesize_async(serialized_model))
|