classiq 0.43.3__py3-none-any.whl → 0.45.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 +8 -3
- classiq/_internals/api_wrapper.py +2 -2
- classiq/_internals/authentication/auth0.py +1 -1
- classiq/_internals/authentication/device.py +5 -1
- classiq/_internals/authentication/token_manager.py +5 -4
- classiq/_internals/client.py +5 -8
- classiq/_internals/config.py +1 -2
- classiq/_internals/host_checker.py +34 -13
- classiq/_internals/jobs.py +3 -3
- classiq/analyzer/analyzer.py +1 -1
- classiq/analyzer/analyzer_utilities.py +1 -1
- classiq/analyzer/rb.py +1 -1
- classiq/applications/chemistry/chemistry_model_constructor.py +13 -7
- classiq/applications/combinatorial_helpers/allowed_constraints.py +4 -1
- classiq/applications/combinatorial_helpers/arithmetic/isolation.py +1 -1
- classiq/applications/combinatorial_helpers/encoding_mapping.py +1 -1
- classiq/applications/combinatorial_helpers/encoding_utils.py +2 -1
- classiq/applications/combinatorial_helpers/optimization_model.py +1 -1
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +1 -1
- classiq/applications/combinatorial_helpers/pyomo_utils.py +1 -2
- classiq/applications/combinatorial_helpers/transformations/encoding.py +1 -1
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +5 -4
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +1 -1
- classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
- classiq/applications/finance/finance_model_constructor.py +4 -3
- classiq/applications/grover/grover_model_constructor.py +7 -5
- classiq/applications/hamiltonian/__init__.py +0 -0
- classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
- classiq/applications/qnn/circuit_utils.py +1 -1
- classiq/applications/qnn/datasets/dataset_base_classes.py +2 -1
- classiq/applications/qnn/datasets/dataset_not.py +2 -1
- classiq/applications/qnn/qlayer.py +3 -2
- classiq/applications/qnn/torch_utils.py +2 -1
- classiq/applications/qsvm/qsvm_model_constructor.py +1 -1
- classiq/execution/execution_session.py +1 -1
- classiq/execution/jobs.py +5 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/cytoscape_graph.py +1 -2
- classiq/interface/analyzer/result.py +2 -3
- classiq/interface/ast_node.py +1 -18
- classiq/interface/backend/backend_preferences.py +11 -18
- classiq/interface/backend/ionq/ionq_quantum_program.py +1 -1
- classiq/interface/backend/pydantic_backend.py +0 -5
- classiq/interface/backend/quantum_backend_providers.py +4 -3
- classiq/interface/chemistry/fermionic_operator.py +1 -2
- classiq/interface/chemistry/ground_state_problem.py +2 -3
- classiq/interface/chemistry/molecule.py +1 -2
- classiq/interface/chemistry/operator.py +8 -10
- classiq/interface/combinatorial_optimization/encoding_types.py +1 -1
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +1 -1
- classiq/interface/combinatorial_optimization/solver_types.py +1 -1
- classiq/interface/debug_info/__init__.py +0 -0
- classiq/interface/debug_info/debug_info.py +32 -0
- classiq/{exceptions.py → interface/exceptions.py} +4 -0
- classiq/interface/executor/aws_execution_cost.py +2 -2
- classiq/interface/executor/execution_preferences.py +2 -47
- classiq/interface/executor/execution_result.py +1 -2
- classiq/interface/executor/optimizer_preferences.py +2 -3
- classiq/interface/executor/quantum_code.py +1 -2
- classiq/interface/executor/quantum_instruction_set.py +2 -2
- classiq/interface/executor/register_initialization.py +1 -2
- classiq/interface/executor/result.py +29 -14
- classiq/interface/finance/function_input.py +6 -11
- classiq/interface/generator/amplitude_loading.py +2 -3
- classiq/interface/generator/ansatz_library.py +1 -1
- classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
- classiq/interface/generator/application_apis/chemistry_declarations.py +78 -60
- classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +19 -10
- classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
- classiq/interface/generator/application_apis/finance_declarations.py +37 -44
- classiq/interface/generator/application_apis/qsvm_declarations.py +21 -15
- classiq/interface/generator/arith/arithmetic.py +10 -8
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +1 -2
- classiq/interface/generator/arith/arithmetic_expression_abc.py +22 -3
- classiq/interface/generator/arith/arithmetic_expression_parser.py +3 -4
- classiq/interface/generator/arith/arithmetic_expression_validator.py +1 -2
- classiq/interface/generator/arith/arithmetic_param_getters.py +1 -2
- classiq/interface/generator/arith/arithmetic_result_builder.py +15 -11
- classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
- classiq/interface/generator/arith/binary_ops.py +7 -7
- classiq/interface/generator/arith/endianness.py +1 -1
- classiq/interface/generator/arith/extremum_operations.py +44 -21
- classiq/interface/generator/arith/logical_ops.py +1 -2
- classiq/interface/generator/arith/register_user_input.py +1 -2
- classiq/interface/generator/arith/unary_ops.py +1 -2
- classiq/interface/generator/arith/uncomputation_methods.py +1 -1
- classiq/interface/generator/chemistry_function_params.py +1 -2
- classiq/interface/generator/circuit_code/circuit_code.py +1 -2
- classiq/interface/generator/circuit_code/types_and_constants.py +1 -2
- classiq/interface/generator/commuting_pauli_exponentiation.py +1 -2
- classiq/interface/generator/constant.py +1 -1
- classiq/interface/generator/control_state.py +1 -2
- classiq/interface/generator/custom_ansatz.py +1 -2
- classiq/interface/generator/expressions/atomic_expression_functions.py +1 -0
- classiq/interface/generator/expressions/enums/finance_functions.py +4 -5
- classiq/interface/generator/expressions/evaluated_expression.py +1 -2
- classiq/interface/generator/expressions/expression.py +1 -2
- classiq/interface/generator/expressions/expression_constants.py +3 -1
- classiq/interface/generator/expressions/non_symbolic_expr.py +1 -1
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +53 -70
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +2 -7
- classiq/interface/generator/expressions/qmod_qstruct_proxy.py +35 -0
- classiq/interface/generator/expressions/qmod_sized_proxy.py +1 -1
- classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
- classiq/interface/generator/function_params.py +2 -3
- classiq/interface/generator/functions/builtins/core_library/__init__.py +4 -2
- classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +41 -41
- classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +52 -42
- classiq/interface/generator/functions/builtins/open_lib_functions.py +1095 -3347
- classiq/interface/generator/functions/builtins/quantum_operators.py +9 -22
- classiq/interface/generator/functions/classical_function_declaration.py +14 -6
- classiq/interface/generator/functions/classical_type.py +7 -114
- classiq/interface/generator/functions/concrete_types.py +55 -0
- classiq/interface/generator/functions/function_declaration.py +10 -10
- classiq/interface/generator/functions/port_declaration.py +1 -2
- classiq/interface/generator/functions/type_name.py +80 -0
- classiq/interface/generator/generated_circuit_data.py +3 -3
- classiq/interface/generator/grover_diffuser.py +1 -2
- classiq/interface/generator/grover_operator.py +1 -2
- classiq/interface/generator/hamiltonian_evolution/exponentiation.py +1 -2
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +1 -2
- classiq/interface/generator/hardware/hardware_data.py +1 -2
- classiq/interface/generator/hardware_efficient_ansatz.py +2 -3
- classiq/interface/generator/hartree_fock.py +1 -2
- classiq/interface/generator/linear_pauli_rotations.py +1 -2
- classiq/interface/generator/mcmt_method.py +1 -1
- classiq/interface/generator/mcu.py +1 -2
- classiq/interface/generator/mcx.py +1 -2
- classiq/interface/generator/model/constraints.py +2 -3
- classiq/interface/generator/model/model.py +12 -2
- classiq/interface/generator/model/preferences/preferences.py +7 -3
- classiq/interface/generator/model/quantum_register.py +1 -2
- classiq/interface/generator/oracles/arithmetic_oracle.py +1 -2
- classiq/interface/generator/oracles/custom_oracle.py +1 -2
- classiq/interface/generator/oracles/oracle_abc.py +1 -2
- classiq/interface/generator/partitioned_register.py +1 -2
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +1 -2
- classiq/interface/generator/preferences/optimization.py +1 -2
- classiq/interface/generator/qpe.py +1 -2
- classiq/interface/generator/qsvm.py +2 -3
- classiq/interface/generator/quantum_function_call.py +4 -2
- classiq/interface/generator/quantum_program.py +6 -7
- classiq/interface/generator/range_types.py +1 -1
- classiq/interface/generator/register_role.py +8 -2
- classiq/interface/generator/slice_parsing_utils.py +1 -2
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +1 -2
- classiq/interface/generator/state_preparation/metrics.py +2 -3
- classiq/interface/generator/state_preparation/state_preparation.py +1 -2
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +1 -3
- classiq/interface/generator/transpiler_basis_gates.py +1 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +38 -45
- classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +1 -2
- classiq/interface/generator/types/enum_declaration.py +1 -2
- classiq/interface/generator/types/qstruct_declaration.py +17 -0
- classiq/interface/generator/types/struct_declaration.py +2 -3
- classiq/interface/generator/ucc.py +1 -2
- classiq/interface/generator/unitary_gate.py +1 -2
- classiq/interface/generator/validations/flow_graph.py +1 -2
- classiq/interface/generator/validations/validator_functions.py +1 -2
- classiq/interface/hardware.py +1 -1
- classiq/interface/helpers/validation_helpers.py +2 -19
- classiq/interface/ide/visual_model.py +10 -4
- classiq/interface/interface_version.py +1 -0
- classiq/interface/jobs.py +2 -3
- classiq/interface/model/bind_operation.py +26 -7
- classiq/interface/model/classical_parameter_declaration.py +8 -5
- classiq/interface/model/control.py +5 -5
- classiq/interface/model/handle_binding.py +185 -12
- classiq/interface/model/inplace_binary_operation.py +17 -6
- classiq/interface/model/model.py +29 -7
- classiq/interface/model/native_function_definition.py +8 -4
- classiq/interface/model/parameter.py +13 -0
- classiq/interface/model/port_declaration.py +21 -4
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +22 -8
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +30 -6
- classiq/interface/model/quantum_expressions/quantum_expression.py +4 -9
- classiq/interface/model/quantum_function_call.py +136 -194
- classiq/interface/model/quantum_function_declaration.py +147 -165
- classiq/interface/model/quantum_lambda_function.py +23 -6
- classiq/interface/model/quantum_statement.py +34 -8
- classiq/interface/model/quantum_type.py +41 -11
- classiq/interface/model/quantum_variable_declaration.py +1 -1
- classiq/interface/model/statement_block.py +2 -0
- classiq/interface/model/validation_handle.py +8 -2
- classiq/interface/server/global_versions.py +4 -4
- classiq/interface/server/routes.py +2 -0
- classiq/interface/source_reference.py +59 -0
- classiq/qmod/__init__.py +2 -3
- classiq/qmod/builtins/classical_execution_primitives.py +1 -1
- classiq/qmod/builtins/functions.py +39 -11
- classiq/qmod/builtins/operations.py +172 -41
- classiq/qmod/classical_function.py +1 -1
- classiq/qmod/declaration_inferrer.py +102 -57
- classiq/qmod/expression_query.py +1 -1
- classiq/qmod/model_state_container.py +2 -0
- classiq/qmod/native/pretty_printer.py +71 -53
- classiq/qmod/pretty_print/pretty_printer.py +98 -52
- classiq/qmod/qfunc.py +11 -5
- classiq/qmod/qmod_constant.py +1 -1
- classiq/qmod/qmod_parameter.py +27 -4
- classiq/qmod/qmod_variable.py +405 -174
- classiq/qmod/quantum_callable.py +3 -3
- classiq/qmod/quantum_expandable.py +128 -68
- classiq/qmod/quantum_function.py +24 -5
- classiq/qmod/semantics/annotation.py +13 -15
- classiq/qmod/semantics/error_manager.py +36 -10
- classiq/qmod/semantics/static_semantics_visitor.py +164 -76
- classiq/qmod/semantics/validation/func_call_validation.py +43 -97
- classiq/qmod/semantics/validation/handle_validation.py +85 -0
- classiq/qmod/semantics/validation/types_validation.py +108 -1
- classiq/qmod/symbolic.py +2 -1
- classiq/qmod/type_attribute_remover.py +32 -0
- classiq/qmod/utilities.py +26 -5
- classiq/{interface/ide/show.py → show.py} +1 -1
- {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/METADATA +3 -3
- {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/RECORD +219 -207
- classiq/qmod/qmod_struct.py +0 -13
- /classiq/{_internals → interface}/enum_utils.py +0 -0
- {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/WHEEL +0 -0
classiq/qmod/qmod_variable.py
CHANGED
@@ -8,30 +8,41 @@ from typing import ( # type: ignore[attr-defined]
|
|
8
8
|
Generic,
|
9
9
|
Iterator,
|
10
10
|
Literal,
|
11
|
+
Mapping,
|
11
12
|
Optional,
|
12
13
|
Tuple,
|
13
14
|
Type,
|
14
15
|
TypeVar,
|
15
16
|
Union,
|
16
17
|
_GenericAlias,
|
18
|
+
cast,
|
17
19
|
get_args,
|
18
20
|
get_origin,
|
19
|
-
overload,
|
20
21
|
)
|
21
22
|
|
22
23
|
from typing_extensions import Annotated, ParamSpec, Self, _AnnotatedAlias
|
23
24
|
|
24
|
-
from classiq.interface.
|
25
|
+
from classiq.interface.exceptions import ClassiqValueError
|
25
26
|
from classiq.interface.generator.expressions.expression import Expression
|
27
|
+
from classiq.interface.generator.expressions.qmod_qarray_proxy import (
|
28
|
+
ILLEGAL_SLICE_BOUNDS_MSG,
|
29
|
+
ILLEGAL_SLICE_MSG,
|
30
|
+
ILLEGAL_SLICING_STEP_MSG,
|
31
|
+
SLICE_OUT_OF_BOUNDS_MSG,
|
32
|
+
SUBSCRIPT_OUT_OF_BOUNDS_MSG,
|
33
|
+
)
|
26
34
|
from classiq.interface.generator.functions.port_declaration import (
|
27
35
|
PortDeclarationDirection,
|
28
36
|
)
|
37
|
+
from classiq.interface.generator.functions.type_name import TypeName
|
38
|
+
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
29
39
|
from classiq.interface.model.handle_binding import (
|
40
|
+
FieldHandleBinding,
|
30
41
|
HandleBinding,
|
31
42
|
SlicedHandleBinding,
|
32
43
|
SubscriptHandleBinding,
|
33
44
|
)
|
34
|
-
from classiq.interface.model.port_declaration import
|
45
|
+
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
35
46
|
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
36
47
|
AmplitudeLoadingOperation,
|
37
48
|
)
|
@@ -44,18 +55,25 @@ from classiq.interface.model.quantum_type import (
|
|
44
55
|
QuantumNumeric,
|
45
56
|
QuantumType,
|
46
57
|
)
|
58
|
+
from classiq.interface.source_reference import SourceReference
|
47
59
|
|
48
|
-
from classiq.
|
49
|
-
from classiq.qmod.qmod_parameter import ArrayBase, CBool, CInt,
|
60
|
+
from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
|
61
|
+
from classiq.qmod.qmod_parameter import ArrayBase, CBool, CInt, CParamScalar
|
50
62
|
from classiq.qmod.quantum_callable import QCallable
|
51
63
|
from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
|
52
64
|
from classiq.qmod.symbolic_type import SymbolicTypes
|
53
65
|
from classiq.qmod.utilities import get_source_ref, version_portable_get_args
|
54
66
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
67
|
+
QVAR_PROPERTIES_ARE_SYMBOLIC = True
|
68
|
+
|
69
|
+
|
70
|
+
@contextmanager
|
71
|
+
def set_symbolic_qvar_properties(symbolic: bool) -> Iterator[None]:
|
72
|
+
global QVAR_PROPERTIES_ARE_SYMBOLIC
|
73
|
+
previous_symbolic = QVAR_PROPERTIES_ARE_SYMBOLIC
|
74
|
+
QVAR_PROPERTIES_ARE_SYMBOLIC = symbolic
|
75
|
+
yield
|
76
|
+
QVAR_PROPERTIES_ARE_SYMBOLIC = previous_symbolic
|
59
77
|
|
60
78
|
|
61
79
|
def _is_input_output_typehint(type_hint: Any) -> bool:
|
@@ -84,18 +102,30 @@ def _no_current_expandable() -> Iterator[None]:
|
|
84
102
|
|
85
103
|
|
86
104
|
class QVar(Symbolic):
|
87
|
-
def __init__(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
105
|
+
def __init__(
|
106
|
+
self,
|
107
|
+
origin: Union[str, HandleBinding],
|
108
|
+
*,
|
109
|
+
expr_str: Optional[str] = None,
|
110
|
+
depth: int = 2,
|
111
|
+
) -> None:
|
112
|
+
super().__init__(str(origin), True)
|
113
|
+
source_ref = (
|
114
|
+
get_source_ref(sys._getframe(depth))
|
115
|
+
if isinstance(origin, str)
|
116
|
+
else origin.source_ref
|
117
|
+
)
|
118
|
+
self._base_handle: HandleBinding = (
|
119
|
+
HandleBinding(name=origin) if isinstance(origin, str) else origin
|
120
|
+
)
|
121
|
+
if isinstance(origin, str) and QCallable.CURRENT_EXPANDABLE is not None:
|
92
122
|
QCallable.CURRENT_EXPANDABLE.add_local_handle(
|
93
|
-
|
123
|
+
origin, self.get_qmod_type(), source_ref
|
94
124
|
)
|
125
|
+
self._expr_str = expr_str if expr_str is not None else str(origin)
|
95
126
|
|
96
|
-
@abc.abstractmethod
|
97
127
|
def get_handle_binding(self) -> HandleBinding:
|
98
|
-
|
128
|
+
return self._base_handle
|
99
129
|
|
100
130
|
@abc.abstractmethod
|
101
131
|
def get_qmod_type(self) -> QuantumType:
|
@@ -107,6 +137,9 @@ class QVar(Symbolic):
|
|
107
137
|
return QVar.from_type_hint(type_hint.__args__[0])
|
108
138
|
type_ = get_origin(type_hint) or type_hint
|
109
139
|
if issubclass(type_, QVar):
|
140
|
+
if issubclass(type_, QStruct):
|
141
|
+
with _no_current_expandable():
|
142
|
+
type_("DUMMY")._add_qmod_qstruct(qmodule=QMODULE)
|
110
143
|
return type_
|
111
144
|
return None
|
112
145
|
|
@@ -115,6 +148,16 @@ class QVar(Symbolic):
|
|
115
148
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
116
149
|
raise NotImplementedError()
|
117
150
|
|
151
|
+
@classmethod
|
152
|
+
@abc.abstractmethod
|
153
|
+
def to_qvar(
|
154
|
+
cls,
|
155
|
+
origin: Union[str, HandleBinding],
|
156
|
+
type_hint: Any,
|
157
|
+
expr_str: Optional[str],
|
158
|
+
) -> Self:
|
159
|
+
raise NotImplementedError()
|
160
|
+
|
118
161
|
@classmethod
|
119
162
|
def port_direction(cls, type_hint: Any) -> PortDeclarationDirection:
|
120
163
|
if _is_input_output_typehint(type_hint):
|
@@ -124,7 +167,17 @@ class QVar(Symbolic):
|
|
124
167
|
return PortDeclarationDirection.Inout
|
125
168
|
|
126
169
|
def __str__(self) -> str:
|
127
|
-
return
|
170
|
+
return self._expr_str
|
171
|
+
|
172
|
+
@property
|
173
|
+
def size(self) -> Union[CParamScalar, int]:
|
174
|
+
if not QVAR_PROPERTIES_ARE_SYMBOLIC:
|
175
|
+
return self._evaluate_size()
|
176
|
+
return CParamScalar(f"get_field({self}, 'size')")
|
177
|
+
|
178
|
+
@abc.abstractmethod
|
179
|
+
def _evaluate_size(self) -> int:
|
180
|
+
raise NotImplementedError
|
128
181
|
|
129
182
|
|
130
183
|
_Q = TypeVar("_Q", bound=QVar)
|
@@ -133,9 +186,15 @@ Input = Annotated[_Q, PortDeclarationDirection.Input]
|
|
133
186
|
|
134
187
|
|
135
188
|
class QScalar(QVar, SymbolicExpr):
|
136
|
-
def __init__(
|
137
|
-
|
138
|
-
|
189
|
+
def __init__(
|
190
|
+
self,
|
191
|
+
origin: Union[str, HandleBinding],
|
192
|
+
*,
|
193
|
+
_expr_str: Optional[str] = None,
|
194
|
+
depth: int = 2,
|
195
|
+
) -> None:
|
196
|
+
QVar.__init__(self, origin, expr_str=_expr_str, depth=depth)
|
197
|
+
SymbolicExpr.__init__(self, str(origin), True)
|
139
198
|
|
140
199
|
def _insert_arith_operation(
|
141
200
|
self, expr: SymbolicTypes, inplace: bool, source_ref: SourceReference
|
@@ -165,9 +224,6 @@ class QScalar(QVar, SymbolicExpr):
|
|
165
224
|
)
|
166
225
|
)
|
167
226
|
|
168
|
-
def get_handle_binding(self) -> HandleBinding:
|
169
|
-
return HandleBinding(name=self._name)
|
170
|
-
|
171
227
|
def __ior__(self, other: Any) -> Self:
|
172
228
|
if not isinstance(other, get_args(SymbolicTypes)):
|
173
229
|
raise TypeError(
|
@@ -201,36 +257,33 @@ class QBit(QScalar):
|
|
201
257
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
202
258
|
return QuantumBit()
|
203
259
|
|
260
|
+
@classmethod
|
261
|
+
def to_qvar(
|
262
|
+
cls,
|
263
|
+
origin: Union[str, HandleBinding],
|
264
|
+
type_hint: Any,
|
265
|
+
expr_str: Optional[str],
|
266
|
+
) -> "QBit":
|
267
|
+
return QBit(origin, _expr_str=expr_str)
|
268
|
+
|
204
269
|
def get_qmod_type(self) -> QuantumType:
|
205
270
|
return QuantumBit()
|
206
271
|
|
272
|
+
def _evaluate_size(self) -> int:
|
273
|
+
return 1
|
274
|
+
|
207
275
|
|
208
276
|
_P = ParamSpec("_P")
|
209
277
|
|
210
278
|
|
211
279
|
class QNum(Generic[_P], QScalar):
|
212
|
-
QMOD_TYPE = QuantumNumeric
|
213
|
-
|
214
|
-
@overload
|
215
|
-
def __init__(self, name: str):
|
216
|
-
pass
|
217
|
-
|
218
|
-
@overload
|
219
280
|
def __init__(
|
220
281
|
self,
|
221
|
-
name: str,
|
222
|
-
size: Union[int, CInt],
|
223
|
-
is_signed: Union[bool, CBool],
|
224
|
-
fraction_digits: Union[int, CInt],
|
225
|
-
|
226
|
-
pass
|
227
|
-
|
228
|
-
def __init__(
|
229
|
-
self,
|
230
|
-
name: str,
|
231
|
-
size: Union[int, CInt, None] = None,
|
232
|
-
is_signed: Union[bool, CBool, None] = None,
|
233
|
-
fraction_digits: Union[int, CInt, None] = None,
|
282
|
+
name: Union[str, HandleBinding],
|
283
|
+
size: Union[int, CInt, Expression, None] = None,
|
284
|
+
is_signed: Union[bool, CBool, Expression, None] = None,
|
285
|
+
fraction_digits: Union[int, CInt, Expression, None] = None,
|
286
|
+
_expr_str: Optional[str] = None,
|
234
287
|
):
|
235
288
|
if (
|
236
289
|
size is None
|
@@ -241,48 +294,90 @@ class QNum(Generic[_P], QScalar):
|
|
241
294
|
raise ClassiqValueError(
|
242
295
|
"Assign none or all of size, is_signed, and fraction_digits"
|
243
296
|
)
|
244
|
-
self._size =
|
245
|
-
|
297
|
+
self._size = (
|
298
|
+
size
|
299
|
+
if size is None or isinstance(size, Expression)
|
300
|
+
else Expression(expr=str(size))
|
301
|
+
)
|
302
|
+
self._is_signed = (
|
303
|
+
is_signed
|
304
|
+
if is_signed is None or isinstance(is_signed, Expression)
|
305
|
+
else Expression(expr=str(is_signed))
|
306
|
+
)
|
246
307
|
self._fraction_digits = (
|
247
|
-
|
308
|
+
fraction_digits
|
309
|
+
if fraction_digits is None or isinstance(fraction_digits, Expression)
|
310
|
+
else Expression(expr=str(fraction_digits))
|
248
311
|
)
|
249
|
-
super().__init__(name, 3)
|
312
|
+
super().__init__(name, _expr_str=_expr_str, depth=3)
|
250
313
|
|
251
314
|
@classmethod
|
252
|
-
def
|
253
|
-
type_args =
|
315
|
+
def _get_attributes(cls, type_hint: Any) -> Tuple[Any, Any, Any]:
|
316
|
+
type_args = version_portable_get_args(type_hint)
|
254
317
|
if len(type_args) == 0:
|
255
|
-
return
|
256
|
-
type_args = type_args[0]
|
318
|
+
return None, None, None
|
257
319
|
if len(type_args) != 3:
|
258
320
|
raise ClassiqValueError(
|
259
321
|
"QNum receives three type arguments: QNum[size: int | CInt, "
|
260
322
|
"is_signed: bool | CBool, fraction_digits: int | CInt]"
|
261
323
|
)
|
262
|
-
return
|
263
|
-
|
264
|
-
|
265
|
-
|
324
|
+
return type_args[0], type_args[1], type_args[2]
|
325
|
+
|
326
|
+
@classmethod
|
327
|
+
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
328
|
+
size, is_signed, fraction_digits = cls._get_attributes(type_hint)
|
329
|
+
return QuantumNumeric(
|
330
|
+
size=(
|
331
|
+
Expression(expr=get_type_hint_expr(size)) if size is not None else None
|
332
|
+
),
|
333
|
+
is_signed=(
|
334
|
+
Expression(expr=get_type_hint_expr(is_signed))
|
335
|
+
if is_signed is not None
|
336
|
+
else None
|
337
|
+
),
|
338
|
+
fraction_digits=(
|
339
|
+
Expression(expr=get_type_hint_expr(fraction_digits))
|
340
|
+
if fraction_digits is not None
|
341
|
+
else None
|
342
|
+
),
|
266
343
|
)
|
267
344
|
|
345
|
+
@classmethod
|
346
|
+
def to_qvar(
|
347
|
+
cls,
|
348
|
+
origin: Union[str, HandleBinding],
|
349
|
+
type_hint: Any,
|
350
|
+
expr_str: Optional[str],
|
351
|
+
) -> "QNum":
|
352
|
+
return QNum(origin, *cls._get_attributes(type_hint), _expr_str=expr_str)
|
353
|
+
|
268
354
|
def get_qmod_type(self) -> QuantumType:
|
269
|
-
return
|
355
|
+
return QuantumNumeric(
|
270
356
|
size=self._size,
|
271
357
|
is_signed=self._is_signed,
|
272
358
|
fraction_digits=self._fraction_digits,
|
273
359
|
)
|
274
360
|
|
275
|
-
|
276
|
-
|
277
|
-
|
361
|
+
def _evaluate_size(self) -> int:
|
362
|
+
if TYPE_CHECKING:
|
363
|
+
assert self._size is not None
|
364
|
+
return self._size.to_int_value()
|
278
365
|
|
279
366
|
@property
|
280
|
-
def fraction_digits(self) -> CParamScalar:
|
281
|
-
|
367
|
+
def fraction_digits(self) -> Union[CParamScalar, int]:
|
368
|
+
if not QVAR_PROPERTIES_ARE_SYMBOLIC:
|
369
|
+
if TYPE_CHECKING:
|
370
|
+
assert self._fraction_digits is not None
|
371
|
+
return self._fraction_digits.to_int_value()
|
372
|
+
return CParamScalar(f"get_field({self}, 'fraction_digits')")
|
282
373
|
|
283
374
|
@property
|
284
|
-
def is_signed(self) -> CParamScalar:
|
285
|
-
|
375
|
+
def is_signed(self) -> Union[CParamScalar, bool]:
|
376
|
+
if not QVAR_PROPERTIES_ARE_SYMBOLIC:
|
377
|
+
if TYPE_CHECKING:
|
378
|
+
assert self._is_signed is not None
|
379
|
+
return self._is_signed.to_bool_value()
|
380
|
+
return CParamScalar(f"get_field({self}, 'is_signed')")
|
286
381
|
|
287
382
|
# Support comma-separated generic args in older Python versions
|
288
383
|
if sys.version_info[0:2] < (3, 10):
|
@@ -292,84 +387,83 @@ class QNum(Generic[_P], QScalar):
|
|
292
387
|
|
293
388
|
|
294
389
|
class QArray(ArrayBase[_P], QVar):
|
390
|
+
# TODO [CAD-18620]: improve type hints
|
295
391
|
def __init__(
|
296
392
|
self,
|
297
|
-
name: str,
|
298
|
-
element_type: _GenericAlias = QBit,
|
299
|
-
length: Optional[Union[int,
|
300
|
-
|
301
|
-
slice_: Optional[Tuple[int, int]] = None,
|
302
|
-
index_: Optional[Union[int, CInt]] = None,
|
393
|
+
name: Union[str, HandleBinding],
|
394
|
+
element_type: Union[_GenericAlias, QuantumType] = QBit,
|
395
|
+
length: Optional[Union[int, SymbolicExpr, Expression]] = None,
|
396
|
+
_expr_str: Optional[str] = None,
|
303
397
|
) -> None:
|
304
|
-
if not issubclass(get_origin(element_type) or element_type, (QBit, QNum)):
|
305
|
-
raise ClassiqValueError(UNSUPPORTED_ELEMENT_TYPE)
|
306
398
|
self._element_type = element_type
|
307
|
-
self._length =
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
if self._index is not None:
|
314
|
-
return SubscriptHandleBinding(
|
315
|
-
name=self._name,
|
316
|
-
index=Expression(expr=str(self._index)),
|
317
|
-
)
|
318
|
-
|
319
|
-
if self._slice is not None:
|
320
|
-
return SlicedHandleBinding(
|
321
|
-
name=self._name,
|
322
|
-
start=Expression(expr=str(self._slice[0])),
|
323
|
-
end=Expression(expr=str(self._slice[1])),
|
324
|
-
)
|
325
|
-
|
326
|
-
return HandleBinding(name=self._name)
|
327
|
-
|
328
|
-
def __getitem__(self, key: Union[slice, int, CInt]) -> Any:
|
329
|
-
if self._index is not None:
|
330
|
-
raise ClassiqValueError(QARRAY_ELEMENT_NOT_SUBSCRIPTABLE)
|
331
|
-
|
332
|
-
# TODO [CAD-18620]: improve type hints
|
333
|
-
new_index: Optional[Any] = None
|
399
|
+
self._length = (
|
400
|
+
length
|
401
|
+
if length is None or isinstance(length, Expression)
|
402
|
+
else Expression(expr=str(length))
|
403
|
+
)
|
404
|
+
super().__init__(name, expr_str=_expr_str)
|
334
405
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
406
|
+
def __getitem__(self, key: Union[slice, int, SymbolicExpr]) -> Any:
|
407
|
+
return (
|
408
|
+
self._get_slice(key) if isinstance(key, slice) else self._get_subscript(key)
|
409
|
+
)
|
339
410
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
411
|
+
def _get_subscript(self, index: Union[slice, int, SymbolicExpr]) -> Any:
|
412
|
+
if isinstance(index, SymbolicExpr) and index.is_quantum:
|
413
|
+
raise ClassiqValueError("Non-classical parameter for slicing")
|
414
|
+
if (
|
415
|
+
isinstance(index, int)
|
416
|
+
and self._length is not None
|
417
|
+
and self._length.is_evaluated()
|
418
|
+
):
|
419
|
+
length = self._length.to_int_value()
|
420
|
+
if index < 0 or index >= length:
|
421
|
+
raise ClassiqValueError(SUBSCRIPT_OUT_OF_BOUNDS_MSG)
|
422
|
+
|
423
|
+
return _create_qvar_for_qtype(
|
424
|
+
self.get_qmod_type().element_type,
|
425
|
+
SubscriptHandleBinding(
|
426
|
+
base_handle=self._base_handle,
|
427
|
+
index=Expression(expr=str(index)),
|
428
|
+
),
|
429
|
+
expr_str=f"{self}[{index}]",
|
430
|
+
)
|
345
431
|
|
432
|
+
def _get_slice(self, slice_: slice) -> Any:
|
433
|
+
if slice_.step is not None:
|
434
|
+
raise ClassiqValueError(ILLEGAL_SLICING_STEP_MSG)
|
435
|
+
if not isinstance(slice_.start, (int, SymbolicExpr)) or not isinstance(
|
436
|
+
slice_.stop, (int, SymbolicExpr)
|
437
|
+
):
|
438
|
+
raise ClassiqValueError(ILLEGAL_SLICE_MSG)
|
346
439
|
if (
|
347
|
-
|
348
|
-
and
|
349
|
-
and
|
350
|
-
and new_slice[1] > self._slice[1]
|
351
|
-
) or (
|
352
|
-
self._length is not None
|
353
|
-
and not isinstance(new_slice[1], Symbolic)
|
354
|
-
and not isinstance(self._length, Symbolic)
|
355
|
-
and new_slice[1] > self._length
|
440
|
+
isinstance(slice_.start, int)
|
441
|
+
and isinstance(slice_.stop, int)
|
442
|
+
and slice_.start >= slice_.stop
|
356
443
|
):
|
357
|
-
raise ClassiqValueError(
|
358
|
-
|
359
|
-
with _no_current_expandable():
|
360
|
-
if new_index is None:
|
361
|
-
array_class = QArray
|
362
|
-
else:
|
363
|
-
array_class = QArraySubscript
|
364
|
-
return array_class(
|
365
|
-
self._name, length=self._length, slice_=new_slice, index_=new_index
|
444
|
+
raise ClassiqValueError(
|
445
|
+
ILLEGAL_SLICE_BOUNDS_MSG.format(slice_.start, slice_.stop)
|
366
446
|
)
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
447
|
+
if self._length is not None and self._length.is_evaluated():
|
448
|
+
length = self._length.to_int_value()
|
449
|
+
if (
|
450
|
+
isinstance(slice_.start, int)
|
451
|
+
and slice_.start < 0
|
452
|
+
or isinstance(slice_.stop, int)
|
453
|
+
and slice_.stop > length
|
454
|
+
):
|
455
|
+
raise ClassiqValueError(SLICE_OUT_OF_BOUNDS_MSG)
|
456
|
+
|
457
|
+
return QArray(
|
458
|
+
name=SlicedHandleBinding(
|
459
|
+
base_handle=self._base_handle,
|
460
|
+
start=Expression(expr=str(slice_.start)),
|
461
|
+
end=Expression(expr=str(slice_.stop)),
|
462
|
+
),
|
463
|
+
element_type=self._element_type,
|
464
|
+
length=slice_.stop - slice_.start,
|
465
|
+
_expr_str=f"{self}[{slice_.start}:{slice_.stop}]",
|
466
|
+
)
|
373
467
|
|
374
468
|
def __len__(self) -> int:
|
375
469
|
raise ClassiqValueError(
|
@@ -384,69 +478,206 @@ class QArray(ArrayBase[_P], QVar):
|
|
384
478
|
else:
|
385
479
|
|
386
480
|
@property
|
387
|
-
def len(self) -> CParamScalar:
|
481
|
+
def len(self) -> Union[CParamScalar, int]:
|
482
|
+
if not QVAR_PROPERTIES_ARE_SYMBOLIC:
|
483
|
+
return self._length.to_int_value()
|
388
484
|
if self._length is not None:
|
389
485
|
return CParamScalar(f"{self._length}")
|
390
|
-
return CParamScalar(f"get_field({self
|
486
|
+
return CParamScalar(f"get_field({self}, 'len')")
|
487
|
+
|
488
|
+
def _evaluate_size(self) -> int:
|
489
|
+
if TYPE_CHECKING:
|
490
|
+
assert self._length is not None
|
491
|
+
return self._element_type.size_in_bits * self._length.to_int_value()
|
391
492
|
|
392
493
|
@classmethod
|
393
|
-
def
|
494
|
+
def _get_attributes(cls, type_hint: Any) -> Tuple[Type[QVar], Any]:
|
394
495
|
type_args = version_portable_get_args(type_hint)
|
395
|
-
if len(type_args) ==
|
396
|
-
|
496
|
+
if len(type_args) == 0:
|
497
|
+
return QBit, None
|
498
|
+
if len(type_args) == 1:
|
499
|
+
if isinstance(type_args[0], (str, int)):
|
500
|
+
return QBit, type_args[0]
|
501
|
+
return type_args[0], None
|
502
|
+
if len(type_args) != 2:
|
503
|
+
raise ClassiqValueError(
|
504
|
+
"QArray receives two type arguments: QArray[element_type: QVar, "
|
505
|
+
"length: int | CInt]"
|
506
|
+
)
|
507
|
+
return cast(Tuple[Type[QVar], Any], type_args)
|
397
508
|
|
398
|
-
|
509
|
+
@classmethod
|
510
|
+
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
511
|
+
api_element_type, length = cls._get_attributes(type_hint)
|
399
512
|
api_element_class = get_origin(api_element_type) or api_element_type
|
400
513
|
element_type = api_element_class.to_qmod_quantum_type(api_element_type)
|
401
514
|
|
402
515
|
length_expr: Optional[Expression] = None
|
403
|
-
if
|
404
|
-
length_expr = Expression(expr=get_type_hint_expr(
|
516
|
+
if length is not None:
|
517
|
+
length_expr = Expression(expr=get_type_hint_expr(length))
|
405
518
|
|
406
519
|
return QuantumBitvector(element_type=element_type, length=length_expr)
|
407
520
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
521
|
+
@classmethod
|
522
|
+
def to_qvar(
|
523
|
+
cls,
|
524
|
+
origin: Union[str, HandleBinding],
|
525
|
+
type_hint: Any,
|
526
|
+
expr_str: Optional[str],
|
527
|
+
) -> "QArray":
|
528
|
+
return QArray(origin, *cls._get_attributes(type_hint), _expr_str=expr_str)
|
529
|
+
|
530
|
+
def get_qmod_type(self) -> QuantumBitvector:
|
531
|
+
if isinstance(self._element_type, QuantumType):
|
532
|
+
element_type = self._element_type
|
533
|
+
else:
|
534
|
+
element_class = get_origin(self._element_type) or self._element_type
|
535
|
+
element_type = element_class.to_qmod_quantum_type(self._element_type)
|
413
536
|
return QuantumBitvector(
|
414
|
-
element_type=
|
415
|
-
length=
|
537
|
+
element_type=element_type,
|
538
|
+
length=self._length,
|
416
539
|
)
|
417
540
|
|
418
541
|
|
419
|
-
class
|
420
|
-
|
421
|
-
|
422
|
-
return CParamScalar(f"get_field({self.get_handle_binding()}, 'size')")
|
542
|
+
class QStruct(QVar):
|
543
|
+
_struct_name: str
|
544
|
+
_fields: Mapping[str, QVar]
|
423
545
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
546
|
+
def __init__(
|
547
|
+
self,
|
548
|
+
name: Union[str, HandleBinding],
|
549
|
+
_struct_name: Optional[str] = None,
|
550
|
+
_fields: Optional[Mapping[str, QVar]] = None,
|
551
|
+
_expr_str: Optional[str] = None,
|
552
|
+
) -> None:
|
553
|
+
if _struct_name is None or _fields is None:
|
554
|
+
with _no_current_expandable():
|
555
|
+
temp_var = QStruct.to_qvar(name, type(self), _expr_str)
|
556
|
+
_struct_name = temp_var._struct_name
|
557
|
+
_fields = temp_var._fields
|
558
|
+
self._struct_name = _struct_name
|
559
|
+
self._fields = _fields
|
560
|
+
for field_name, var in _fields.items():
|
561
|
+
setattr(self, field_name, var)
|
562
|
+
super().__init__(name)
|
563
|
+
self._add_qmod_qstruct(qmodule=QMODULE)
|
564
|
+
|
565
|
+
def get_qmod_type(self) -> QuantumType:
|
566
|
+
return TypeName(name=self._struct_name)
|
567
|
+
|
568
|
+
@classmethod
|
569
|
+
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
570
|
+
with _no_current_expandable():
|
571
|
+
type_hint("DUMMY")
|
572
|
+
return TypeName(name=type_hint.__name__)
|
573
|
+
|
574
|
+
@classmethod
|
575
|
+
def to_qvar(
|
576
|
+
cls,
|
577
|
+
origin: Union[str, HandleBinding],
|
578
|
+
type_hint: Any,
|
579
|
+
expr_str: Optional[str],
|
580
|
+
) -> "QStruct":
|
581
|
+
field_types = {
|
582
|
+
field_name: (QVar.from_type_hint(field_type), field_type)
|
583
|
+
for field_name, field_type in type_hint.__annotations__.items()
|
584
|
+
}
|
585
|
+
illegal_fields = [
|
586
|
+
(field_name, field_type)
|
587
|
+
for field_name, (field_class, field_type) in field_types.items()
|
588
|
+
if field_class is None
|
589
|
+
]
|
590
|
+
if len(illegal_fields) > 0:
|
591
|
+
raise ClassiqValueError(
|
592
|
+
f"Field {illegal_fields[0][0]!r} of quantum struct "
|
593
|
+
f"{type_hint.__name__} has a non-quantum type "
|
594
|
+
f"{illegal_fields[0][1].__name__}."
|
595
|
+
)
|
596
|
+
base_handle = HandleBinding(name=origin) if isinstance(origin, str) else origin
|
597
|
+
with _no_current_expandable():
|
598
|
+
field_vars = {
|
599
|
+
field_name: cast(Type[QVar], field_class).to_qvar(
|
600
|
+
FieldHandleBinding(base_handle=base_handle, field=field_name),
|
601
|
+
field_type,
|
602
|
+
f"get_field({expr_str if expr_str is not None else str(origin)}, '{field_name}')",
|
603
|
+
)
|
604
|
+
for field_name, (field_class, field_type) in field_types.items()
|
605
|
+
}
|
606
|
+
return QStruct(
|
607
|
+
name=origin,
|
608
|
+
_struct_name=type_hint.__name__,
|
609
|
+
_fields=field_vars,
|
610
|
+
_expr_str=expr_str,
|
428
611
|
)
|
429
612
|
|
430
|
-
|
431
|
-
|
432
|
-
|
613
|
+
def _add_qmod_qstruct(self, *, qmodule: ModelStateContainer) -> None:
|
614
|
+
if self._struct_name in qmodule.qstruct_decls:
|
615
|
+
return
|
616
|
+
|
617
|
+
qmodule.qstruct_decls[self._struct_name] = QStructDeclaration(
|
618
|
+
name=self._struct_name,
|
619
|
+
fields={name: qvar.get_qmod_type() for name, qvar in self._fields.items()},
|
620
|
+
)
|
621
|
+
|
622
|
+
def _evaluate_size(self) -> int:
|
623
|
+
return sum(var._evaluate_size() for var in self._fields.values())
|
624
|
+
|
433
625
|
|
626
|
+
def create_qvar_for_port_decl(port: AnonPortDeclaration, name: str) -> QVar:
|
627
|
+
return _create_qvar_for_qtype(port.quantum_type, HandleBinding(name=name))
|
434
628
|
|
435
|
-
|
629
|
+
|
630
|
+
def _create_qvar_for_qtype(
|
631
|
+
qtype: QuantumType, origin: HandleBinding, expr_str: Optional[str] = None
|
632
|
+
) -> QVar:
|
436
633
|
# prevent addition to local handles, since this is used for ports
|
437
634
|
with _no_current_expandable():
|
438
|
-
if
|
439
|
-
return QBit(
|
440
|
-
elif isinstance(
|
441
|
-
return QNum(
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
635
|
+
if isinstance(qtype, QuantumBit):
|
636
|
+
return QBit(origin, _expr_str=expr_str)
|
637
|
+
elif isinstance(qtype, QuantumNumeric):
|
638
|
+
return QNum(
|
639
|
+
origin,
|
640
|
+
qtype.size,
|
641
|
+
qtype.is_signed,
|
642
|
+
qtype.fraction_digits,
|
643
|
+
_expr_str=expr_str,
|
644
|
+
)
|
645
|
+
elif isinstance(qtype, TypeName):
|
646
|
+
struct_decl = QMODULE.qstruct_decls[qtype.name]
|
647
|
+
return QStruct(
|
648
|
+
origin,
|
649
|
+
struct_decl.name,
|
650
|
+
{
|
651
|
+
field_name: _create_qvar_for_qtype(
|
652
|
+
field_type,
|
653
|
+
FieldHandleBinding(base_handle=origin, field=field_name),
|
654
|
+
f"get_field({expr_str if expr_str is not None else str(origin)}, '{field_name}')",
|
655
|
+
)
|
656
|
+
for field_name, field_type in struct_decl.fields.items()
|
657
|
+
},
|
658
|
+
_expr_str=expr_str,
|
659
|
+
)
|
660
|
+
if TYPE_CHECKING:
|
661
|
+
assert isinstance(qtype, QuantumBitvector)
|
662
|
+
return QArray(origin, qtype.element_type, qtype.length, _expr_str=expr_str)
|
663
|
+
|
664
|
+
|
665
|
+
def get_qvar(qtype: QuantumType, origin: HandleBinding) -> "QVar":
|
666
|
+
if isinstance(qtype, QuantumBit):
|
667
|
+
return QBit(origin)
|
668
|
+
elif isinstance(qtype, QuantumBitvector):
|
669
|
+
return QArray(origin, qtype.element_type, qtype.length)
|
670
|
+
elif isinstance(qtype, QuantumNumeric):
|
671
|
+
return QNum(origin, qtype.size, qtype.is_signed, qtype.fraction_digits)
|
672
|
+
elif isinstance(qtype, TypeName):
|
673
|
+
return QStruct(
|
674
|
+
origin,
|
675
|
+
qtype.name,
|
676
|
+
{
|
677
|
+
field_name: get_qvar(
|
678
|
+
field_type, FieldHandleBinding(base_handle=origin, field=field_name)
|
679
|
+
)
|
680
|
+
for field_name, field_type in qtype.fields.items()
|
681
|
+
},
|
682
|
+
)
|
683
|
+
raise NotImplementedError
|