classiq 0.38.0__py3-none-any.whl → 0.40.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/__init__.py +22 -22
- classiq/_internals/api_wrapper.py +13 -1
- classiq/_internals/client.py +12 -2
- classiq/analyzer/analyzer.py +3 -1
- classiq/applications/__init__.py +1 -8
- classiq/applications/chemistry/__init__.py +6 -0
- classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +1 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/arithmetic_expression.py +1 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/combinatorial_problem_utils.py +25 -6
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_mapping.py +1 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_utils.py +1 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/memory.py +2 -4
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/optimization_model.py +13 -16
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/pyomo_utils.py +4 -2
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/encoding.py +3 -10
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/fixed_variables.py +4 -6
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/ising_converter.py +3 -5
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty_support.py +3 -7
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/slack_variables.py +4 -6
- classiq/applications/combinatorial_optimization/__init__.py +11 -3
- classiq/{applications_model_constructors → applications/combinatorial_optimization}/combinatorial_optimization_model_constructor.py +9 -10
- classiq/applications/finance/__init__.py +3 -2
- classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +24 -14
- classiq/applications/grover/__init__.py +11 -0
- classiq/applications/libraries/qmci_library.py +35 -0
- classiq/applications/qsvm/__init__.py +5 -1
- classiq/execution/all_hardware_devices.py +13 -0
- classiq/executor.py +2 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/result.py +1 -5
- classiq/interface/applications/qsvm.py +4 -2
- classiq/interface/ast_node.py +23 -0
- classiq/interface/backend/backend_preferences.py +5 -5
- classiq/interface/backend/quantum_backend_providers.py +7 -7
- classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
- classiq/interface/executor/execution_preferences.py +4 -9
- classiq/interface/executor/execution_request.py +2 -37
- classiq/interface/executor/vqe_result.py +1 -1
- classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
- classiq/interface/generator/application_apis/finance_declarations.py +1 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +2 -0
- classiq/interface/generator/builtin_api_builder.py +0 -5
- classiq/interface/generator/constant.py +2 -3
- classiq/interface/generator/expressions/expression.py +2 -4
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +82 -0
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +22 -1
- classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
- classiq/interface/generator/functions/__init__.py +2 -2
- classiq/interface/generator/functions/builtins/__init__.py +15 -0
- classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
- classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +8 -6
- classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +10 -4
- classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
- classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +893 -319
- classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
- classiq/interface/generator/functions/classical_type.py +31 -21
- classiq/interface/generator/functions/function_declaration.py +2 -2
- classiq/interface/generator/hartree_fock.py +10 -2
- classiq/interface/generator/model/classical_main_validator.py +1 -1
- classiq/interface/generator/model/model.py +1 -1
- classiq/interface/generator/model/preferences/preferences.py +4 -2
- classiq/interface/generator/quantum_function_call.py +1 -1
- classiq/interface/generator/types/struct_declaration.py +2 -4
- classiq/interface/model/call_synthesis_data.py +3 -3
- classiq/interface/model/classical_if.py +13 -0
- classiq/interface/model/classical_parameter_declaration.py +2 -3
- classiq/interface/model/{quantum_if_operation.py → control.py} +39 -21
- classiq/interface/model/handle_binding.py +3 -2
- classiq/interface/model/invert.py +10 -0
- classiq/interface/model/model.py +2 -1
- classiq/interface/model/power.py +12 -0
- classiq/interface/model/quantum_function_call.py +9 -4
- classiq/interface/model/quantum_lambda_function.py +3 -9
- classiq/interface/model/quantum_statement.py +3 -2
- classiq/interface/model/quantum_type.py +8 -9
- classiq/interface/model/quantum_variable_declaration.py +2 -2
- classiq/interface/model/repeat.py +13 -0
- classiq/interface/model/resolvers/function_call_resolver.py +21 -0
- classiq/interface/model/statement_block.py +18 -4
- classiq/interface/model/validations/handles_validator.py +8 -12
- classiq/interface/model/within_apply_operation.py +4 -4
- classiq/interface/server/routes.py +0 -4
- classiq/qmod/__init__.py +6 -2
- classiq/qmod/builtins/classical_functions.py +34 -39
- classiq/qmod/builtins/functions.py +287 -300
- classiq/qmod/builtins/operations.py +217 -16
- classiq/qmod/builtins/structs.py +50 -48
- classiq/qmod/declaration_inferrer.py +30 -18
- classiq/qmod/native/expression_to_qmod.py +5 -4
- classiq/qmod/native/pretty_printer.py +48 -26
- classiq/qmod/qmod_constant.py +29 -5
- classiq/qmod/qmod_parameter.py +56 -34
- classiq/qmod/qmod_struct.py +2 -2
- classiq/qmod/qmod_variable.py +87 -43
- classiq/qmod/quantum_callable.py +8 -4
- classiq/qmod/quantum_expandable.py +25 -20
- classiq/qmod/quantum_function.py +29 -2
- classiq/qmod/symbolic.py +79 -69
- classiq/qmod/symbolic_expr.py +1 -1
- classiq/qmod/symbolic_type.py +1 -4
- classiq/qmod/utilities.py +29 -0
- {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/METADATA +1 -1
- {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/RECORD +122 -141
- classiq/applications/benchmarking/__init__.py +0 -9
- classiq/applications/benchmarking/mirror_benchmarking.py +0 -70
- classiq/applications/numpy_utils.py +0 -37
- classiq/applications_model_constructors/__init__.py +0 -25
- classiq/applications_model_constructors/combinatorial_helpers/multiple_comp_basis_sp.py +0 -34
- classiq/applications_model_constructors/libraries/qmci_library.py +0 -107
- classiq/builtin_functions/__init__.py +0 -43
- classiq/builtin_functions/amplitude_loading.py +0 -3
- classiq/builtin_functions/binary_ops.py +0 -1
- classiq/builtin_functions/exponentiation.py +0 -5
- classiq/builtin_functions/qpe.py +0 -4
- classiq/builtin_functions/qsvm.py +0 -7
- classiq/builtin_functions/range_types.py +0 -5
- classiq/builtin_functions/standard_gates.py +0 -1
- classiq/builtin_functions/state_preparation.py +0 -6
- classiq/builtin_functions/suzuki_trotter.py +0 -3
- classiq/interface/executor/error_mitigation.py +0 -6
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py +0 -0
- classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -95
- classiq/model/__init__.py +0 -14
- classiq/model/composite_function_generator.py +0 -33
- classiq/model/function_handler.py +0 -462
- classiq/model/logic_flow.py +0 -149
- classiq/model/logic_flow_change_handler.py +0 -71
- classiq/model/model.py +0 -229
- classiq/quantum_functions/__init__.py +0 -17
- classiq/quantum_functions/annotation_parser.py +0 -205
- classiq/quantum_functions/decorators.py +0 -22
- classiq/quantum_functions/function_library.py +0 -181
- classiq/quantum_functions/function_parser.py +0 -74
- classiq/quantum_functions/quantum_function.py +0 -236
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/allowed_constraints.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/isolation.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/pauli_utils.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/py.typed +0 -0
- /classiq/{applications_model_constructors/combinatorial_helpers/transformations → applications/combinatorial_helpers/solvers}/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/sympy_utils.py +0 -0
- /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers/transformations}/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/sign_seperation.py +0 -0
- /classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +0 -0
- /classiq/{interface/generator/functions/core_lib_declarations → applications/libraries}/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
- /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
- /classiq/{quantum_register.py → interface/model/quantum_register.py} +0 -0
- {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/WHEEL +0 -0
@@ -11,18 +11,22 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
11
11
|
)
|
12
12
|
from classiq.interface.generator.visitor import NodeType, Visitor
|
13
13
|
from classiq.interface.model.bind_operation import BindOperation
|
14
|
+
from classiq.interface.model.classical_if import ClassicalIf
|
14
15
|
from classiq.interface.model.classical_parameter_declaration import (
|
15
16
|
ClassicalParameterDeclaration,
|
16
17
|
)
|
18
|
+
from classiq.interface.model.control import Control
|
17
19
|
from classiq.interface.model.handle_binding import (
|
18
20
|
HandleBinding,
|
19
21
|
SlicedHandleBinding,
|
20
22
|
SubscriptHandleBinding,
|
21
23
|
)
|
22
24
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
25
|
+
from classiq.interface.model.invert import Invert
|
23
26
|
from classiq.interface.model.model import Model
|
24
27
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
25
28
|
from classiq.interface.model.port_declaration import PortDeclaration
|
29
|
+
from classiq.interface.model.power import Power
|
26
30
|
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
27
31
|
AmplitudeLoadingOperation,
|
28
32
|
)
|
@@ -37,7 +41,6 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
37
41
|
QuantumFunctionDeclaration,
|
38
42
|
QuantumOperandDeclaration,
|
39
43
|
)
|
40
|
-
from classiq.interface.model.quantum_if_operation import QuantumIfOperation
|
41
44
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
42
45
|
from classiq.interface.model.quantum_type import (
|
43
46
|
QuantumBit,
|
@@ -47,11 +50,12 @@ from classiq.interface.model.quantum_type import (
|
|
47
50
|
from classiq.interface.model.quantum_variable_declaration import (
|
48
51
|
QuantumVariableDeclaration,
|
49
52
|
)
|
53
|
+
from classiq.interface.model.repeat import Repeat
|
50
54
|
from classiq.interface.model.statement_block import StatementBlock
|
51
55
|
from classiq.interface.model.variable_declaration_statement import (
|
52
56
|
VariableDeclarationStatement,
|
53
57
|
)
|
54
|
-
from classiq.interface.model.within_apply_operation import
|
58
|
+
from classiq.interface.model.within_apply_operation import WithinApply
|
55
59
|
|
56
60
|
from classiq import Bool, ClassicalList, Integer, Pauli, Real, Struct, StructDeclaration
|
57
61
|
from classiq.qmod.native.expression_to_qmod import transform_expression
|
@@ -208,33 +212,51 @@ class DSLPrettyPrinter(Visitor):
|
|
208
212
|
)
|
209
213
|
return f"{self._indent}{func_call.func_name}{f'[{self.visit(func_call.function.index)}]' if isinstance(func_call.function, OperandIdentifier) else ''}{gen_time_arg_list}({quantum_args});\n"
|
210
214
|
|
211
|
-
def
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
215
|
+
def visit_Control(self, op: Control) -> str:
|
216
|
+
control = f"{self._indent}control ({self.visit(op.expression)}) {{\n"
|
217
|
+
control += self._visit_body(op.body)
|
218
|
+
control += f"{self._indent}}}\n"
|
219
|
+
return control
|
220
|
+
|
221
|
+
def visit_ClassicalIf(self, op: ClassicalIf) -> str:
|
222
|
+
classical_if = f"{self._indent}if ({self.visit(op.condition)}) {{\n"
|
223
|
+
if not op.then:
|
224
|
+
raise AssertionError('Expected non empty "then" block')
|
225
|
+
classical_if += self._visit_body(op.then)
|
226
|
+
|
227
|
+
if op.else_:
|
228
|
+
classical_if += f"{self._indent}}} else {{\n"
|
229
|
+
classical_if += self._visit_body(op.else_)
|
230
|
+
|
231
|
+
classical_if += f"{self._indent}}}\n"
|
232
|
+
return classical_if
|
233
|
+
|
234
|
+
def visit_WithinApply(self, op: WithinApply) -> str:
|
231
235
|
within_apply_code = f"{self._indent}within {{\n"
|
232
|
-
within_apply_code += self._visit_body(compute
|
236
|
+
within_apply_code += self._visit_body(op.compute)
|
233
237
|
within_apply_code += f"{self._indent}}} apply {{\n"
|
234
|
-
within_apply_code += self._visit_body(action
|
238
|
+
within_apply_code += self._visit_body(op.action)
|
235
239
|
within_apply_code += f"{self._indent}}}\n"
|
236
240
|
return within_apply_code
|
237
241
|
|
242
|
+
def visit_Repeat(self, repeat: Repeat) -> str:
|
243
|
+
repeat_code = f"{self._indent}repeat ({self.visit(repeat.iter_var)}: {self.visit(repeat.count)}) {{\n"
|
244
|
+
repeat_code += self._visit_body(repeat.body)
|
245
|
+
repeat_code += f"{self._indent}}}\n"
|
246
|
+
return repeat_code
|
247
|
+
|
248
|
+
def visit_Power(self, power: Power) -> str:
|
249
|
+
power_code = f"{self._indent}power ({self.visit(power.power)}) {{\n"
|
250
|
+
power_code += self._visit_body(power.body)
|
251
|
+
power_code += f"{self._indent}}}\n"
|
252
|
+
return power_code
|
253
|
+
|
254
|
+
def visit_Invert(self, invert: Invert) -> str:
|
255
|
+
invert_code = f"{self._indent}invert {{\n"
|
256
|
+
invert_code += self._visit_body(invert.body)
|
257
|
+
invert_code += f"{self._indent}}}\n"
|
258
|
+
return invert_code
|
259
|
+
|
238
260
|
def _visit_body(self, body: StatementBlock) -> str:
|
239
261
|
code = ""
|
240
262
|
self._level += 1
|
@@ -280,10 +302,10 @@ class DSLPrettyPrinter(Visitor):
|
|
280
302
|
return var_ref.name
|
281
303
|
|
282
304
|
def visit_SlicedHandleBinding(self, var_ref: SlicedHandleBinding) -> str:
|
283
|
-
return
|
305
|
+
return f"{var_ref.name}[{self.visit(var_ref.start)}:{self.visit(var_ref.end)}]"
|
284
306
|
|
285
307
|
def visit_SubscriptHandleBinding(self, var_ref: SubscriptHandleBinding) -> str:
|
286
|
-
return
|
308
|
+
return f"{var_ref.name}[{self.visit(var_ref.index)}]"
|
287
309
|
|
288
310
|
def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
|
289
311
|
op = "^=" if arith_op.inplace_result else "="
|
classiq/qmod/qmod_constant.py
CHANGED
@@ -3,12 +3,16 @@ from typing import Any, Optional
|
|
3
3
|
|
4
4
|
from classiq.interface.generator.constant import Constant
|
5
5
|
from classiq.interface.generator.expressions.expression import Expression
|
6
|
-
from classiq.interface.generator.functions.classical_type import
|
6
|
+
from classiq.interface.generator.functions.classical_type import (
|
7
|
+
ClassicalArray,
|
8
|
+
ClassicalList,
|
9
|
+
CStructBase,
|
10
|
+
)
|
7
11
|
|
8
12
|
from classiq.exceptions import ClassiqError
|
9
13
|
from classiq.qmod.declaration_inferrer import python_type_to_qmod
|
10
14
|
from classiq.qmod.model_state_container import ModelStateContainer
|
11
|
-
from classiq.qmod.qmod_parameter import
|
15
|
+
from classiq.qmod.qmod_parameter import CParam, CParamList, CParamStruct
|
12
16
|
|
13
17
|
|
14
18
|
class QConstant:
|
@@ -57,20 +61,40 @@ class QConstant:
|
|
57
61
|
value=Expression(expr=expr),
|
58
62
|
)
|
59
63
|
|
60
|
-
def __getattr__(self, name: str) ->
|
64
|
+
def __getattr__(self, name: str) -> CParam:
|
61
65
|
self.add_to_model()
|
62
66
|
|
63
67
|
py_type = type(self._value)
|
64
68
|
if (
|
65
69
|
QConstant.CURRENT_QMODULE is None
|
66
70
|
or not inspect.isclass(py_type)
|
67
|
-
or not issubclass(py_type,
|
71
|
+
or not issubclass(py_type, CStructBase)
|
68
72
|
):
|
69
73
|
return self.__getattribute__(name)
|
70
74
|
|
71
|
-
return
|
75
|
+
return CParamStruct.get_field(
|
72
76
|
QConstant.CURRENT_QMODULE, self.name, py_type.__name__, name
|
73
77
|
)
|
74
78
|
|
79
|
+
def __getitem__(self, item: Any) -> CParam:
|
80
|
+
self.add_to_model()
|
81
|
+
|
82
|
+
assert QConstant.CURRENT_QMODULE is not None
|
83
|
+
|
84
|
+
qmod_type = python_type_to_qmod(
|
85
|
+
self._py_type, qmodule=QConstant.CURRENT_QMODULE
|
86
|
+
)
|
87
|
+
if qmod_type is None:
|
88
|
+
raise ClassiqError("Invalid QMOD type")
|
89
|
+
|
90
|
+
if not isinstance(qmod_type, (ClassicalList, ClassicalArray)):
|
91
|
+
raise ClassiqError("Invalid subscript to non-list constant")
|
92
|
+
|
93
|
+
return CParamList(
|
94
|
+
self.name,
|
95
|
+
qmod_type,
|
96
|
+
QConstant.CURRENT_QMODULE,
|
97
|
+
)[item]
|
98
|
+
|
75
99
|
def __str__(self) -> str:
|
76
100
|
return self.name
|
classiq/qmod/qmod_parameter.py
CHANGED
@@ -26,21 +26,54 @@ _T = TypeVar("_T")
|
|
26
26
|
|
27
27
|
|
28
28
|
if TYPE_CHECKING:
|
29
|
+
SymbolicSuperclass = SymbolicExpr
|
30
|
+
else:
|
31
|
+
SymbolicSuperclass = Symbolic
|
29
32
|
|
30
|
-
class QParam(SymbolicExpr, Generic[_T]):
|
31
|
-
pass
|
32
33
|
|
33
|
-
|
34
|
+
class CParam(SymbolicSuperclass):
|
35
|
+
pass
|
36
|
+
|
37
|
+
|
38
|
+
class QParam(CParam, Generic[_T]):
|
39
|
+
pass
|
40
|
+
|
41
|
+
|
42
|
+
class CInt(CParam):
|
43
|
+
pass
|
44
|
+
|
45
|
+
|
46
|
+
class CReal(CParam):
|
47
|
+
pass
|
48
|
+
|
49
|
+
|
50
|
+
class CBool(CParam):
|
51
|
+
pass
|
52
|
+
|
53
|
+
|
54
|
+
_P = ParamSpec("_P")
|
55
|
+
|
56
|
+
|
57
|
+
class ArrayBase(Generic[_P]):
|
58
|
+
# Support comma-separated generic args in older Python versions
|
59
|
+
if sys.version_info[0:2] < (3, 10):
|
60
|
+
|
61
|
+
def __class_getitem__(cls, args) -> _GenericAlias:
|
62
|
+
return _GenericAlias(cls, args)
|
63
|
+
|
64
|
+
|
65
|
+
class CArray(CParam, ArrayBase[_P]):
|
66
|
+
if TYPE_CHECKING:
|
34
67
|
|
35
|
-
|
36
|
-
|
68
|
+
@property
|
69
|
+
def len(self) -> int: ...
|
37
70
|
|
38
71
|
|
39
|
-
class
|
72
|
+
class CParamScalar(CParam, SymbolicExpr):
|
40
73
|
pass
|
41
74
|
|
42
75
|
|
43
|
-
class
|
76
|
+
class CParamList(CParam):
|
44
77
|
def __init__(
|
45
78
|
self,
|
46
79
|
expr: str,
|
@@ -51,7 +84,7 @@ class QParamList(QParam):
|
|
51
84
|
self._qmodule = qmodule
|
52
85
|
self._list_type = list_type
|
53
86
|
|
54
|
-
def __getitem__(self, key: Any) ->
|
87
|
+
def __getitem__(self, key: Any) -> CParam:
|
55
88
|
return create_param(
|
56
89
|
f"({self})[{key}]",
|
57
90
|
self._list_type.element_type,
|
@@ -60,14 +93,15 @@ class QParamList(QParam):
|
|
60
93
|
|
61
94
|
def __len__(self) -> int:
|
62
95
|
raise ClassiqValueError(
|
63
|
-
"len(<expr>) is not supported for QMod lists - use <expr>.len
|
96
|
+
"len(<expr>) is not supported for QMod lists - use <expr>.len instead"
|
64
97
|
)
|
65
98
|
|
66
|
-
|
67
|
-
|
99
|
+
@property
|
100
|
+
def len(self) -> CParamScalar:
|
101
|
+
return CParamScalar(f"get_field({self}, 'len')")
|
68
102
|
|
69
103
|
|
70
|
-
class
|
104
|
+
class CParamStruct(CParam):
|
71
105
|
def __init__(
|
72
106
|
self, expr: str, struct_type: Struct, *, qmodule: ModelStateContainer
|
73
107
|
) -> None:
|
@@ -75,8 +109,8 @@ class QParamStruct(QParam):
|
|
75
109
|
self._qmodule = qmodule
|
76
110
|
self._struct_type = struct_type
|
77
111
|
|
78
|
-
def __getattr__(self, field_name: str) ->
|
79
|
-
return
|
112
|
+
def __getattr__(self, field_name: str) -> CParam:
|
113
|
+
return CParamStruct.get_field(
|
80
114
|
self._qmodule, str(self), self._struct_type.name, field_name
|
81
115
|
)
|
82
116
|
|
@@ -86,7 +120,7 @@ class QParamStruct(QParam):
|
|
86
120
|
variable_name: str,
|
87
121
|
struct_name: str,
|
88
122
|
field_name: str,
|
89
|
-
) ->
|
123
|
+
) -> CParam:
|
90
124
|
struct_decl = StructDeclaration.BUILTIN_STRUCT_DECLARATIONS.get(
|
91
125
|
struct_name, qmodule.type_decls.get(struct_name)
|
92
126
|
)
|
@@ -104,27 +138,15 @@ class QParamStruct(QParam):
|
|
104
138
|
)
|
105
139
|
|
106
140
|
|
107
|
-
_P = ParamSpec("_P")
|
108
|
-
|
109
|
-
|
110
|
-
class ArrayBase(Generic[_P]):
|
111
|
-
# Support comma-separated generic args in older Python versions
|
112
|
-
if sys.version_info[0:2] < (3, 10):
|
113
|
-
|
114
|
-
def __class_getitem__(cls, args) -> _GenericAlias:
|
115
|
-
return _GenericAlias(cls, args)
|
116
|
-
|
117
|
-
|
118
|
-
class Array(ArrayBase[_P]):
|
119
|
-
pass
|
120
|
-
|
121
|
-
|
122
141
|
def create_param(
|
123
142
|
expr_str: str, ctype: ClassicalType, qmodule: ModelStateContainer
|
124
|
-
) ->
|
143
|
+
) -> CParam:
|
125
144
|
if isinstance(ctype, (ClassicalList, ClassicalArray)):
|
126
|
-
return
|
145
|
+
return CParamList(expr_str, ctype, qmodule=qmodule)
|
127
146
|
elif isinstance(ctype, Struct):
|
128
|
-
return
|
147
|
+
return CParamStruct(expr_str, ctype, qmodule=qmodule)
|
129
148
|
else:
|
130
|
-
return
|
149
|
+
return CParamScalar(expr_str)
|
150
|
+
|
151
|
+
|
152
|
+
Array = CArray
|
classiq/qmod/qmod_struct.py
CHANGED
@@ -3,7 +3,7 @@ from typing import Any, Type
|
|
3
3
|
|
4
4
|
from typing_extensions import dataclass_transform
|
5
5
|
|
6
|
-
from classiq.interface.generator.functions.classical_type import
|
6
|
+
from classiq.interface.generator.functions.classical_type import CStructBase
|
7
7
|
|
8
8
|
|
9
9
|
def _qmod_val_to_expr_str(val: Any) -> str:
|
@@ -30,7 +30,7 @@ def struct(user_class: Type) -> Type:
|
|
30
30
|
|
31
31
|
user_dataclass = type(
|
32
32
|
user_class.__name__,
|
33
|
-
(
|
33
|
+
(CStructBase, dataclasses.dataclass(user_class)),
|
34
34
|
dict(),
|
35
35
|
)
|
36
36
|
user_dataclass.__repr__ = _new_repr # type:ignore[assignment]
|
classiq/qmod/qmod_variable.py
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
import abc
|
2
2
|
import sys
|
3
3
|
from contextlib import contextmanager
|
4
|
-
from typing import
|
5
|
-
from typing import (
|
4
|
+
from typing import ( # type: ignore[attr-defined]
|
6
5
|
TYPE_CHECKING,
|
7
6
|
Any,
|
8
7
|
ForwardRef,
|
@@ -14,6 +13,7 @@ from typing import (
|
|
14
13
|
Type,
|
15
14
|
TypeVar,
|
16
15
|
Union,
|
16
|
+
_GenericAlias,
|
17
17
|
get_args,
|
18
18
|
get_origin,
|
19
19
|
overload,
|
@@ -21,11 +21,16 @@ from typing import (
|
|
21
21
|
|
22
22
|
from typing_extensions import Annotated, ParamSpec, Self, _AnnotatedAlias
|
23
23
|
|
24
|
+
from classiq.interface.ast_node import SourceReference
|
24
25
|
from classiq.interface.generator.expressions.expression import Expression
|
25
26
|
from classiq.interface.generator.functions.port_declaration import (
|
26
27
|
PortDeclarationDirection,
|
27
28
|
)
|
28
|
-
from classiq.interface.model.handle_binding import
|
29
|
+
from classiq.interface.model.handle_binding import (
|
30
|
+
HandleBinding,
|
31
|
+
SlicedHandleBinding,
|
32
|
+
SubscriptHandleBinding,
|
33
|
+
)
|
29
34
|
from classiq.interface.model.port_declaration import PortDeclaration
|
30
35
|
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
31
36
|
AmplitudeLoadingOperation,
|
@@ -41,15 +46,16 @@ from classiq.interface.model.quantum_type import (
|
|
41
46
|
)
|
42
47
|
|
43
48
|
from classiq.exceptions import ClassiqValueError
|
44
|
-
from classiq.qmod.qmod_parameter import ArrayBase,
|
49
|
+
from classiq.qmod.qmod_parameter import ArrayBase, CBool, CInt, CParam, CParamScalar
|
45
50
|
from classiq.qmod.quantum_callable import QCallable
|
46
51
|
from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
|
47
52
|
from classiq.qmod.symbolic_type import SymbolicTypes
|
48
|
-
from classiq.qmod.utilities import version_portable_get_args
|
53
|
+
from classiq.qmod.utilities import get_source_ref, version_portable_get_args
|
49
54
|
|
50
55
|
ILLEGAL_SLICING_STEP_MSG = "Slicing with a step of a quantum variable is not supported"
|
51
56
|
SLICE_OUT_OF_BOUNDS_MSG = "Slice end index out of bounds"
|
52
57
|
UNSUPPORTED_ELEMENT_TYPE = "Only QBit is supported as element type for QArray"
|
58
|
+
QARRAY_ELEMENT_NOT_SUBSCRIPTABLE = "Subscripting an element in QArray is illegal"
|
53
59
|
|
54
60
|
|
55
61
|
def _is_input_output_typehint(type_hint: Any) -> bool:
|
@@ -77,8 +83,9 @@ def _no_current_expandable() -> Iterator[None]:
|
|
77
83
|
QCallable.CURRENT_EXPANDABLE = current_expandable
|
78
84
|
|
79
85
|
|
80
|
-
class QVar:
|
86
|
+
class QVar(Symbolic):
|
81
87
|
def __init__(self, name: str) -> None:
|
88
|
+
super().__init__(name)
|
82
89
|
self._name = name
|
83
90
|
if QCallable.CURRENT_EXPANDABLE is not None:
|
84
91
|
QCallable.CURRENT_EXPANDABLE.add_local_handle(
|
@@ -115,6 +122,9 @@ class QVar:
|
|
115
122
|
assert type_hint == cls or get_origin(type_hint) == cls
|
116
123
|
return PortDeclarationDirection.Inout
|
117
124
|
|
125
|
+
def __str__(self) -> str:
|
126
|
+
return str(self.get_handle_binding())
|
127
|
+
|
118
128
|
|
119
129
|
_Q = TypeVar("_Q", bound=QVar)
|
120
130
|
Output = Annotated[_Q, PortDeclarationDirection.Output]
|
@@ -126,7 +136,9 @@ class QScalar(QVar, SymbolicExpr):
|
|
126
136
|
QVar.__init__(self, name)
|
127
137
|
SymbolicExpr.__init__(self, name)
|
128
138
|
|
129
|
-
def _insert_arith_operation(
|
139
|
+
def _insert_arith_operation(
|
140
|
+
self, expr: SymbolicTypes, inplace: bool, source_ref: SourceReference
|
141
|
+
) -> None:
|
130
142
|
# Fixme: Arithmetic operations are not yet supported on slices (see CAD-12670)
|
131
143
|
if TYPE_CHECKING:
|
132
144
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
@@ -135,16 +147,20 @@ class QScalar(QVar, SymbolicExpr):
|
|
135
147
|
expression=Expression(expr=str(expr)),
|
136
148
|
result_var=self.get_handle_binding(),
|
137
149
|
inplace_result=inplace,
|
150
|
+
source_ref=source_ref,
|
138
151
|
)
|
139
152
|
)
|
140
153
|
|
141
|
-
def _insert_amplitude_loading(
|
154
|
+
def _insert_amplitude_loading(
|
155
|
+
self, expr: SymbolicTypes, source_ref: SourceReference
|
156
|
+
) -> None:
|
142
157
|
if TYPE_CHECKING:
|
143
158
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
144
159
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
145
160
|
AmplitudeLoadingOperation(
|
146
161
|
expression=Expression(expr=str(expr)),
|
147
162
|
result_var=self.get_handle_binding(),
|
163
|
+
source_ref=source_ref,
|
148
164
|
)
|
149
165
|
)
|
150
166
|
|
@@ -157,7 +173,7 @@ class QScalar(QVar, SymbolicExpr):
|
|
157
173
|
f"Invalid argument {other!r} for out-of-place arithmetic operation"
|
158
174
|
)
|
159
175
|
|
160
|
-
self._insert_arith_operation(other, False)
|
176
|
+
self._insert_arith_operation(other, False, get_source_ref(sys._getframe(1)))
|
161
177
|
return self
|
162
178
|
|
163
179
|
def __ixor__(self, other: Any) -> Self:
|
@@ -166,7 +182,7 @@ class QScalar(QVar, SymbolicExpr):
|
|
166
182
|
f"Invalid argument {other!r} for in-place arithmetic operation"
|
167
183
|
)
|
168
184
|
|
169
|
-
self._insert_arith_operation(other, True)
|
185
|
+
self._insert_arith_operation(other, True, get_source_ref(sys._getframe(1)))
|
170
186
|
return self
|
171
187
|
|
172
188
|
def __imul__(self, other: Any) -> Self:
|
@@ -175,7 +191,7 @@ class QScalar(QVar, SymbolicExpr):
|
|
175
191
|
f"Invalid argument {other!r} for out of ampltiude encoding operation"
|
176
192
|
)
|
177
193
|
|
178
|
-
self._insert_amplitude_loading(other)
|
194
|
+
self._insert_amplitude_loading(other, get_source_ref(sys._getframe(1)))
|
179
195
|
return self
|
180
196
|
|
181
197
|
|
@@ -202,18 +218,18 @@ class QNum(Generic[_P], QScalar):
|
|
202
218
|
def __init__(
|
203
219
|
self,
|
204
220
|
name: str,
|
205
|
-
size: Union[int,
|
206
|
-
is_signed: Union[bool,
|
207
|
-
fraction_digits: Union[int,
|
221
|
+
size: Union[int, CInt],
|
222
|
+
is_signed: Union[bool, CBool],
|
223
|
+
fraction_digits: Union[int, CInt],
|
208
224
|
):
|
209
225
|
pass
|
210
226
|
|
211
227
|
def __init__(
|
212
228
|
self,
|
213
229
|
name: str,
|
214
|
-
size: Union[int,
|
215
|
-
is_signed: Union[bool,
|
216
|
-
fraction_digits: Union[int,
|
230
|
+
size: Union[int, CInt, None] = None,
|
231
|
+
is_signed: Union[bool, CBool, None] = None,
|
232
|
+
fraction_digits: Union[int, CInt, None] = None,
|
217
233
|
):
|
218
234
|
if (
|
219
235
|
size is None
|
@@ -239,8 +255,8 @@ class QNum(Generic[_P], QScalar):
|
|
239
255
|
type_args = type_args[0]
|
240
256
|
if len(type_args) != 3:
|
241
257
|
raise ClassiqValueError(
|
242
|
-
"QNum receives three type arguments: QNum[size: int |
|
243
|
-
"is_signed: bool |
|
258
|
+
"QNum receives three type arguments: QNum[size: int | CInt, "
|
259
|
+
"is_signed: bool | CBool, fraction_digits: int | CInt]"
|
244
260
|
)
|
245
261
|
return cls.QMOD_TYPE(
|
246
262
|
size=Expression(expr=get_type_hint_expr(type_args[0])),
|
@@ -256,16 +272,16 @@ class QNum(Generic[_P], QScalar):
|
|
256
272
|
)
|
257
273
|
|
258
274
|
@property
|
259
|
-
def size(self) ->
|
260
|
-
return
|
275
|
+
def size(self) -> CParamScalar:
|
276
|
+
return CParamScalar(f"get_field({self._name}, 'size')")
|
261
277
|
|
262
278
|
@property
|
263
|
-
def fraction_digits(self) ->
|
264
|
-
return
|
279
|
+
def fraction_digits(self) -> CParamScalar:
|
280
|
+
return CParamScalar(f"get_field({self._name}, 'fraction_digits')")
|
265
281
|
|
266
282
|
@property
|
267
|
-
def is_signed(self) ->
|
268
|
-
return
|
283
|
+
def is_signed(self) -> CParamScalar:
|
284
|
+
return CParamScalar(f"get_field({self._name}, 'is_signed')")
|
269
285
|
|
270
286
|
# Support comma-separated generic args in older Python versions
|
271
287
|
if sys.version_info[0:2] < (3, 10):
|
@@ -279,35 +295,53 @@ class QArray(ArrayBase[_P], QVar):
|
|
279
295
|
self,
|
280
296
|
name: str,
|
281
297
|
element_type: _GenericAlias = QBit,
|
282
|
-
length: Optional[Union[int,
|
298
|
+
length: Optional[Union[int, CInt]] = None,
|
299
|
+
# TODO [CAD-18620]: improve type hints
|
283
300
|
slice_: Optional[Tuple[int, int]] = None,
|
301
|
+
index_: Optional[Union[int, CInt]] = None,
|
284
302
|
) -> None:
|
285
303
|
if element_type is not QBit:
|
286
304
|
raise ClassiqValueError(UNSUPPORTED_ELEMENT_TYPE)
|
287
305
|
self._element_type = element_type
|
288
306
|
self._length = length
|
289
307
|
self._slice = slice_
|
308
|
+
self._index = index_
|
290
309
|
super().__init__(name)
|
291
310
|
|
292
311
|
def get_handle_binding(self) -> HandleBinding:
|
293
|
-
if self.
|
294
|
-
return
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
312
|
+
if self._index is not None:
|
313
|
+
return SubscriptHandleBinding(
|
314
|
+
name=self._name,
|
315
|
+
index=Expression(expr=str(self._index)),
|
316
|
+
)
|
317
|
+
|
318
|
+
if self._slice is not None:
|
319
|
+
return SlicedHandleBinding(
|
320
|
+
name=self._name,
|
321
|
+
start=Expression(expr=str(self._slice[0])),
|
322
|
+
end=Expression(expr=str(self._slice[1])),
|
323
|
+
)
|
324
|
+
|
325
|
+
return HandleBinding(name=self._name)
|
326
|
+
|
327
|
+
def __getitem__(self, key: Union[slice, int, CInt]) -> "QArray":
|
328
|
+
if self._index is not None:
|
329
|
+
raise ClassiqValueError(QARRAY_ELEMENT_NOT_SUBSCRIPTABLE)
|
330
|
+
|
331
|
+
# TODO [CAD-18620]: improve type hints
|
332
|
+
new_index: Optional[Any] = None
|
300
333
|
|
301
|
-
def __getitem__(self, key: Union[slice, int, QParam]) -> "QArray":
|
302
|
-
offset = self._slice[0] if self._slice is not None else 0
|
303
334
|
if isinstance(key, slice):
|
304
335
|
if key.step is not None:
|
305
336
|
raise ClassiqValueError(ILLEGAL_SLICING_STEP_MSG)
|
306
|
-
new_slice = (
|
337
|
+
new_slice = self._get_new_slice(key.start, key.stop)
|
338
|
+
|
307
339
|
else:
|
308
|
-
if isinstance(key,
|
340
|
+
if isinstance(key, CParam) and not isinstance(key, CParamScalar):
|
309
341
|
raise ClassiqValueError("Non-classical parameter for slicing")
|
310
|
-
new_slice = (
|
342
|
+
new_slice = self._get_new_slice(key, key + 1)
|
343
|
+
new_index = new_slice[0]
|
344
|
+
|
311
345
|
if (
|
312
346
|
self._slice is not None
|
313
347
|
and not isinstance(new_slice[1], Symbolic)
|
@@ -322,23 +356,33 @@ class QArray(ArrayBase[_P], QVar):
|
|
322
356
|
raise ClassiqValueError(SLICE_OUT_OF_BOUNDS_MSG)
|
323
357
|
# prevent addition to local handles, since this is used for slicing existing local handles
|
324
358
|
with _no_current_expandable():
|
325
|
-
return QArray(
|
359
|
+
return QArray(
|
360
|
+
self._name, length=self._length, slice_=new_slice, index_=new_index
|
361
|
+
)
|
362
|
+
|
363
|
+
# TODO [CAD-18620]: improve type hints
|
364
|
+
def _get_new_slice(self, start: Any, end: Any) -> Tuple[Any, Any]:
|
365
|
+
if self._slice is not None:
|
366
|
+
return (self._slice[0] + start, self._slice[0] + end)
|
367
|
+
return (start, end)
|
326
368
|
|
327
369
|
def __len__(self) -> int:
|
328
370
|
raise ClassiqValueError(
|
329
|
-
"len(<var>) is not supported for quantum variables - use <var>.len
|
371
|
+
"len(<var>) is not supported for quantum variables - use <var>.len instead"
|
330
372
|
)
|
331
373
|
|
332
374
|
if TYPE_CHECKING:
|
333
375
|
|
376
|
+
@property
|
334
377
|
def len(self) -> int: ...
|
335
378
|
|
336
379
|
else:
|
337
380
|
|
338
|
-
|
381
|
+
@property
|
382
|
+
def len(self) -> CParamScalar:
|
339
383
|
if self._length is not None:
|
340
|
-
return
|
341
|
-
return
|
384
|
+
return CParamScalar(f"{self._length}")
|
385
|
+
return CParamScalar(f"get_field({self._name}, 'len')")
|
342
386
|
|
343
387
|
@classmethod
|
344
388
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|