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/quantum_callable.py
CHANGED
@@ -12,13 +12,13 @@ from typing import ( # type: ignore[attr-defined]
|
|
12
12
|
|
13
13
|
from typing_extensions import ParamSpec
|
14
14
|
|
15
|
-
from classiq.interface.ast_node import SourceReference
|
16
15
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
17
16
|
from classiq.interface.model.quantum_function_declaration import (
|
18
|
-
|
17
|
+
AnonQuantumFunctionDeclaration,
|
19
18
|
)
|
20
19
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
21
20
|
from classiq.interface.model.quantum_type import QuantumType
|
21
|
+
from classiq.interface.source_reference import SourceReference
|
22
22
|
|
23
23
|
from classiq.qmod.qmod_parameter import CInt
|
24
24
|
from classiq.qmod.utilities import get_source_ref
|
@@ -58,7 +58,7 @@ class QCallable(Generic[P], ABC):
|
|
58
58
|
|
59
59
|
@property
|
60
60
|
@abstractmethod
|
61
|
-
def func_decl(self) ->
|
61
|
+
def func_decl(self) -> AnonQuantumFunctionDeclaration:
|
62
62
|
raise NotImplementedError
|
63
63
|
|
64
64
|
# Support comma-separated generic args in older Python versions
|
@@ -20,24 +20,23 @@ from typing import (
|
|
20
20
|
from sympy import Basic
|
21
21
|
from typing_extensions import Self
|
22
22
|
|
23
|
-
from classiq.interface.
|
23
|
+
from classiq.interface.exceptions import ClassiqValueError
|
24
24
|
from classiq.interface.generator.expressions.expression import Expression
|
25
|
-
from classiq.interface.generator.functions.
|
26
|
-
PythonClassicalTypes,
|
27
|
-
)
|
25
|
+
from classiq.interface.generator.functions.concrete_types import PythonClassicalTypes
|
28
26
|
from classiq.interface.model.classical_parameter_declaration import (
|
29
|
-
|
27
|
+
AnonClassicalParameterDeclaration,
|
30
28
|
)
|
31
|
-
from classiq.interface.model.port_declaration import
|
29
|
+
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
32
30
|
from classiq.interface.model.quantum_function_call import (
|
33
31
|
ArgValue,
|
34
32
|
OperandIdentifier,
|
35
33
|
QuantumFunctionCall,
|
36
34
|
)
|
37
35
|
from classiq.interface.model.quantum_function_declaration import (
|
38
|
-
|
36
|
+
AnonPositionalArg,
|
37
|
+
AnonQuantumFunctionDeclaration,
|
38
|
+
AnonQuantumOperandDeclaration,
|
39
39
|
QuantumFunctionDeclaration,
|
40
|
-
QuantumOperandDeclaration,
|
41
40
|
)
|
42
41
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
43
42
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
@@ -45,14 +44,25 @@ from classiq.interface.model.quantum_type import QuantumType
|
|
45
44
|
from classiq.interface.model.variable_declaration_statement import (
|
46
45
|
VariableDeclarationStatement,
|
47
46
|
)
|
47
|
+
from classiq.interface.source_reference import SourceReference
|
48
48
|
|
49
|
-
from classiq.exceptions import ClassiqValueError
|
50
49
|
from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
|
51
50
|
from classiq.qmod.qmod_constant import QConstant
|
52
|
-
from classiq.qmod.qmod_parameter import
|
53
|
-
|
51
|
+
from classiq.qmod.qmod_parameter import (
|
52
|
+
CInt,
|
53
|
+
CParam,
|
54
|
+
CParamScalar,
|
55
|
+
create_param,
|
56
|
+
get_qmod_type,
|
57
|
+
)
|
58
|
+
from classiq.qmod.qmod_variable import (
|
59
|
+
QVar,
|
60
|
+
create_qvar_for_port_decl,
|
61
|
+
set_symbolic_qvar_properties,
|
62
|
+
)
|
54
63
|
from classiq.qmod.quantum_callable import QCallable, QExpandableInterface
|
55
64
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
65
|
+
from classiq.qmod.type_attribute_remover import decl_without_type_attributes
|
56
66
|
from classiq.qmod.utilities import mangle_keyword, qmod_val_to_expr_str
|
57
67
|
|
58
68
|
ArgType = Union[CParam, QVar, QCallable]
|
@@ -89,11 +99,11 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
89
99
|
|
90
100
|
def expand(self) -> None:
|
91
101
|
if self not in QExpandable.STACK:
|
92
|
-
with self:
|
102
|
+
with self, set_symbolic_qvar_properties(True):
|
93
103
|
self._py_callable(*self._get_positional_args())
|
94
104
|
|
95
|
-
def infer_rename_params(self) ->
|
96
|
-
return
|
105
|
+
def infer_rename_params(self) -> Optional[List[str]]:
|
106
|
+
return None
|
97
107
|
|
98
108
|
def add_local_handle(
|
99
109
|
self,
|
@@ -112,60 +122,94 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
112
122
|
|
113
123
|
def _get_positional_args(self) -> List[ArgType]:
|
114
124
|
result: List[ArgType] = []
|
115
|
-
for arg in self.func_decl.
|
116
|
-
|
117
|
-
actual_name =
|
118
|
-
|
125
|
+
for idx, arg in enumerate(self.func_decl.positional_arg_declarations):
|
126
|
+
rename_params = self.infer_rename_params()
|
127
|
+
actual_name = (
|
128
|
+
rename_params[idx] if rename_params is not None else arg.get_name()
|
129
|
+
)
|
130
|
+
if isinstance(arg, AnonClassicalParameterDeclaration):
|
119
131
|
result.append(
|
120
132
|
create_param(actual_name, arg.classical_type, self._qmodule)
|
121
133
|
)
|
122
|
-
elif isinstance(arg,
|
134
|
+
elif isinstance(arg, AnonPortDeclaration):
|
123
135
|
result.append(create_qvar_for_port_decl(arg, actual_name))
|
124
136
|
else:
|
125
|
-
assert isinstance(arg,
|
126
|
-
result.append(QTerminalCallable(arg))
|
137
|
+
assert isinstance(arg, AnonQuantumOperandDeclaration)
|
138
|
+
result.append(QTerminalCallable(arg, idx))
|
127
139
|
return result
|
128
140
|
|
129
141
|
def create_quantum_function_call(
|
130
142
|
self, source_ref_: SourceReference, *args: Any, **kwargs: Any
|
131
143
|
) -> QuantumFunctionCall:
|
144
|
+
func_decl = self.func_decl
|
145
|
+
if not isinstance(func_decl, QuantumFunctionDeclaration):
|
146
|
+
raise NotImplementedError
|
132
147
|
return _create_quantum_function_call(
|
133
|
-
|
148
|
+
func_decl, None, source_ref_, *args, **kwargs
|
134
149
|
)
|
135
150
|
|
136
151
|
|
137
152
|
class QLambdaFunction(QExpandable):
|
138
|
-
def __init__(
|
153
|
+
def __init__(
|
154
|
+
self, decl: AnonQuantumFunctionDeclaration, py_callable: Callable
|
155
|
+
) -> None:
|
139
156
|
py_callable.__annotations__.pop("return", None)
|
140
157
|
super().__init__(py_callable)
|
141
158
|
self._decl = decl
|
142
159
|
|
143
160
|
@property
|
144
|
-
def func_decl(self) ->
|
161
|
+
def func_decl(self) -> AnonQuantumFunctionDeclaration:
|
145
162
|
return self._decl
|
146
163
|
|
147
|
-
def infer_rename_params(self) ->
|
148
|
-
|
149
|
-
decl_params = self.func_decl.get_positional_arg_decls()
|
150
|
-
return {
|
151
|
-
decl_param.name: py_param
|
152
|
-
for decl_param, py_param in zip(decl_params, py_params.args)
|
153
|
-
if decl_param.name != py_param
|
154
|
-
}
|
164
|
+
def infer_rename_params(self) -> List[str]:
|
165
|
+
return inspect.getfullargspec(self._py_callable).args
|
155
166
|
|
156
167
|
|
157
168
|
class QTerminalCallable(QCallable):
|
169
|
+
@overload
|
158
170
|
def __init__(
|
159
171
|
self,
|
160
172
|
decl: QuantumFunctionDeclaration,
|
173
|
+
param_idx: Optional[int] = None,
|
161
174
|
index_: Optional[Union[int, CParamScalar]] = None,
|
162
175
|
) -> None:
|
163
|
-
|
176
|
+
pass
|
177
|
+
|
178
|
+
@overload
|
179
|
+
def __init__(
|
180
|
+
self,
|
181
|
+
decl: AnonQuantumFunctionDeclaration,
|
182
|
+
param_idx: int,
|
183
|
+
index_: Optional[Union[int, CParamScalar]] = None,
|
184
|
+
) -> None:
|
185
|
+
pass
|
186
|
+
|
187
|
+
def __init__(
|
188
|
+
self,
|
189
|
+
decl: AnonQuantumFunctionDeclaration,
|
190
|
+
param_idx: Optional[int] = None,
|
191
|
+
index_: Optional[Union[int, CParamScalar]] = None,
|
192
|
+
) -> None:
|
193
|
+
self._decl = self._override_decl_name(decl, param_idx)
|
164
194
|
self._index = index_
|
165
195
|
|
196
|
+
@staticmethod
|
197
|
+
def _override_decl_name(
|
198
|
+
decl: AnonQuantumFunctionDeclaration, param_idx: Optional[int]
|
199
|
+
) -> QuantumFunctionDeclaration:
|
200
|
+
if (
|
201
|
+
not isinstance(QCallable.CURRENT_EXPANDABLE, QLambdaFunction)
|
202
|
+
or param_idx is None
|
203
|
+
):
|
204
|
+
return decl.rename(decl.get_name())
|
205
|
+
rename_params = QCallable.CURRENT_EXPANDABLE.infer_rename_params()
|
206
|
+
return decl.rename(new_name=rename_params[param_idx])
|
207
|
+
|
166
208
|
@property
|
167
209
|
def is_list(self) -> bool:
|
168
|
-
return
|
210
|
+
return (
|
211
|
+
isinstance(self._decl, AnonQuantumOperandDeclaration) and self._decl.is_list
|
212
|
+
)
|
169
213
|
|
170
214
|
def __getitem__(self, key: Union[slice, int, CInt]) -> "QTerminalCallable":
|
171
215
|
if not self.is_list:
|
@@ -174,7 +218,7 @@ class QTerminalCallable(QCallable):
|
|
174
218
|
raise NotImplementedError("Operand lists don't support slicing")
|
175
219
|
if isinstance(key, CParam) and not isinstance(key, CParamScalar):
|
176
220
|
raise ClassiqValueError("Non-classical parameter for slicing")
|
177
|
-
return QTerminalCallable(self._decl, key)
|
221
|
+
return QTerminalCallable(self._decl, index_=key)
|
178
222
|
|
179
223
|
def __len__(self) -> int:
|
180
224
|
raise ClassiqValueError(
|
@@ -212,43 +256,54 @@ class QTerminalCallable(QCallable):
|
|
212
256
|
|
213
257
|
@overload
|
214
258
|
def prepare_arg(
|
215
|
-
arg_decl:
|
259
|
+
arg_decl: AnonPositionalArg,
|
260
|
+
val: Union[QCallable, Callable[..., None]],
|
261
|
+
func_name: Optional[str],
|
262
|
+
param_name: str,
|
216
263
|
) -> QuantumLambdaFunction: ...
|
217
264
|
|
218
265
|
|
219
266
|
@overload
|
220
|
-
def prepare_arg(
|
267
|
+
def prepare_arg(
|
268
|
+
arg_decl: AnonPositionalArg, val: Any, func_name: Optional[str], param_name: str
|
269
|
+
) -> ArgValue: ...
|
221
270
|
|
222
271
|
|
223
|
-
def prepare_arg(
|
272
|
+
def prepare_arg(
|
273
|
+
arg_decl: AnonPositionalArg, val: Any, func_name: Optional[str], param_name: str
|
274
|
+
) -> ArgValue:
|
224
275
|
if isinstance(val, QConstant):
|
225
276
|
val.add_to_model()
|
226
277
|
return Expression(expr=str(val.name))
|
227
|
-
if isinstance(arg_decl,
|
278
|
+
if isinstance(arg_decl, AnonClassicalParameterDeclaration):
|
228
279
|
_validate_classical_arg(val, arg_decl, func_name)
|
229
280
|
return Expression(expr=qmod_val_to_expr_str(val))
|
230
|
-
elif isinstance(arg_decl,
|
281
|
+
elif isinstance(arg_decl, AnonPortDeclaration):
|
231
282
|
if not isinstance(val, QVar):
|
283
|
+
func_name_message = (
|
284
|
+
"" if func_name is None else f" of function {func_name!r}"
|
285
|
+
)
|
232
286
|
raise ClassiqValueError(
|
233
|
-
f"Argument {str(val)!r} to parameter {
|
234
|
-
f"
|
287
|
+
f"Argument {str(val)!r} to parameter {param_name!r}{func_name_message} "
|
288
|
+
f"has incompatible type; expected quantum variable"
|
235
289
|
)
|
236
290
|
return val.get_handle_binding()
|
237
291
|
else:
|
238
292
|
if isinstance(val, list):
|
239
293
|
if not all(isinstance(v, QCallable) or callable(v) for v in val):
|
240
294
|
raise ClassiqValueError(
|
241
|
-
f"Quantum operand {
|
295
|
+
f"Quantum operand {param_name!r} cannot be initialized with a "
|
242
296
|
f"list of non-callables"
|
243
297
|
)
|
244
298
|
val = cast(List[Union[QCallable, Callable[[Any], None]]], val)
|
245
|
-
return [prepare_arg(arg_decl, v, func_name) for v in val]
|
299
|
+
return [prepare_arg(arg_decl, v, func_name, param_name) for v in val]
|
246
300
|
|
247
301
|
if not isinstance(val, QCallable):
|
248
|
-
|
302
|
+
new_arg_decl = decl_without_type_attributes(arg_decl)
|
303
|
+
val = QLambdaFunction(new_arg_decl, val)
|
249
304
|
val.expand()
|
250
305
|
return QuantumLambdaFunction(
|
251
|
-
|
306
|
+
pos_rename_params=val.infer_rename_params(),
|
252
307
|
body=val.body,
|
253
308
|
)
|
254
309
|
|
@@ -258,7 +313,7 @@ def prepare_arg(arg_decl: PositionalArg, val: Any, func_name: str) -> ArgValue:
|
|
258
313
|
|
259
314
|
|
260
315
|
def _validate_classical_arg(
|
261
|
-
arg: Any, arg_decl:
|
316
|
+
arg: Any, arg_decl: AnonClassicalParameterDeclaration, func_name: Optional[str]
|
262
317
|
) -> None:
|
263
318
|
if (
|
264
319
|
not isinstance(
|
@@ -268,15 +323,16 @@ def _validate_classical_arg(
|
|
268
323
|
or isinstance(arg, SymbolicExpr)
|
269
324
|
and arg.is_quantum
|
270
325
|
):
|
326
|
+
func_name_message = "" if func_name is None else f" of function {func_name!r}"
|
271
327
|
raise ClassiqValueError(
|
272
|
-
f"Argument {str(arg)!r} to parameter {arg_decl.name!r}
|
273
|
-
f"
|
274
|
-
f"{arg_decl.classical_type.
|
328
|
+
f"Argument {str(arg)!r} to parameter {arg_decl.name!r}{func_name_message} "
|
329
|
+
f"has incompatible type; expected "
|
330
|
+
f"{get_qmod_type(arg_decl.classical_type).__name__}"
|
275
331
|
)
|
276
332
|
|
277
333
|
|
278
334
|
def _get_operand_hint_args(
|
279
|
-
func:
|
335
|
+
func: AnonQuantumFunctionDeclaration, param: AnonPositionalArg, param_value: str
|
280
336
|
) -> str:
|
281
337
|
return ", ".join(
|
282
338
|
[
|
@@ -285,39 +341,43 @@ def _get_operand_hint_args(
|
|
285
341
|
if decl.name == param.name
|
286
342
|
else f"{decl.name}=..."
|
287
343
|
)
|
288
|
-
for decl in func.
|
344
|
+
for decl in func.positional_arg_declarations
|
289
345
|
]
|
290
346
|
)
|
291
347
|
|
292
348
|
|
293
|
-
def _get_operand_hint(
|
349
|
+
def _get_operand_hint(
|
350
|
+
func: AnonQuantumFunctionDeclaration, param: AnonPositionalArg
|
351
|
+
) -> str:
|
294
352
|
return (
|
295
|
-
f"\nHint: To
|
296
|
-
f"
|
297
|
-
f"
|
298
|
-
f"
|
299
|
-
f"or a quantum function "
|
300
|
-
f"`{func.name}({_get_operand_hint_args(func, param, 'my_func')})`"
|
353
|
+
f"\nHint: To call a function under {func.name!r} use a lambda function as in "
|
354
|
+
f"'{func.name}({_get_operand_hint_args(func, param, 'lambda: f(q)')})' "
|
355
|
+
f"or pass the quantum function directly as in "
|
356
|
+
f"'{func.name}({_get_operand_hint_args(func, param, 'f')})'."
|
301
357
|
)
|
302
358
|
|
303
359
|
|
304
360
|
def _prepare_args(
|
305
|
-
decl:
|
361
|
+
decl: AnonQuantumFunctionDeclaration, arg_list: List[Any], kwargs: Dict[str, Any]
|
306
362
|
) -> List[ArgValue]:
|
307
363
|
result = []
|
308
|
-
for arg_decl in decl.
|
364
|
+
for idx, arg_decl in enumerate(decl.positional_arg_declarations):
|
365
|
+
arg = None
|
309
366
|
if arg_list:
|
310
367
|
arg = arg_list.pop(0)
|
311
|
-
|
368
|
+
elif arg_decl.name is not None:
|
312
369
|
arg = kwargs.pop(mangle_keyword(arg_decl.name), None)
|
313
370
|
if arg is None:
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
371
|
+
if arg_decl.name is not None:
|
372
|
+
param_name = repr(arg_decl.name)
|
373
|
+
else:
|
374
|
+
param_name = f"#{idx + 1}"
|
375
|
+
error_message = f"Missing required argument for parameter {param_name}"
|
376
|
+
if isinstance(arg_decl, AnonQuantumOperandDeclaration):
|
318
377
|
error_message += _get_operand_hint(decl, arg_decl)
|
319
378
|
raise ClassiqValueError(error_message)
|
320
|
-
|
379
|
+
param_name = arg_decl.name if arg_decl.name is not None else f"#{idx + 1}"
|
380
|
+
result.append(prepare_arg(arg_decl, arg, decl.name, param_name))
|
321
381
|
|
322
382
|
return result
|
323
383
|
|
@@ -329,7 +389,7 @@ def _create_quantum_function_call(
|
|
329
389
|
*args: Any,
|
330
390
|
**kwargs: Any,
|
331
391
|
) -> QuantumFunctionCall:
|
332
|
-
arg_decls = decl_.
|
392
|
+
arg_decls = decl_.positional_arg_declarations
|
333
393
|
arg_list = list(args)
|
334
394
|
prepared_args = _prepare_args(decl_, arg_list, kwargs)
|
335
395
|
|
classiq/qmod/quantum_function.py
CHANGED
@@ -5,27 +5,30 @@ from enum import EnumMeta
|
|
5
5
|
from inspect import isclass
|
6
6
|
from typing import Any, Callable, Dict, List, Optional, Tuple, get_origin
|
7
7
|
|
8
|
+
from classiq.interface.exceptions import ClassiqError
|
8
9
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
9
10
|
from classiq.interface.generator.model.constraints import Constraints
|
10
11
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
11
12
|
from classiq.interface.model.model import Model, SerializedModel
|
12
13
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
13
14
|
from classiq.interface.model.quantum_function_declaration import (
|
15
|
+
NamedParamsQuantumFunctionDeclaration,
|
14
16
|
QuantumFunctionDeclaration,
|
15
17
|
)
|
16
18
|
|
17
|
-
from classiq.exceptions import ClassiqError
|
18
19
|
from classiq.qmod.classical_function import CFunc
|
19
20
|
from classiq.qmod.declaration_inferrer import infer_func_decl
|
21
|
+
from classiq.qmod.model_state_container import QMODULE
|
20
22
|
from classiq.qmod.qmod_constant import QConstant
|
21
23
|
from classiq.qmod.qmod_parameter import CArray, CParam
|
22
24
|
from classiq.qmod.qmod_variable import QVar
|
23
25
|
from classiq.qmod.quantum_callable import QCallable, QCallableList
|
24
26
|
from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
|
25
27
|
from classiq.qmod.utilities import mangle_keyword, unmangle_keyword
|
28
|
+
from classiq.qmod.write_qmod import write_qmod
|
26
29
|
|
27
30
|
|
28
|
-
def _lookup_qfunc(name: str) -> Optional[
|
31
|
+
def _lookup_qfunc(name: str) -> Optional[NamedParamsQuantumFunctionDeclaration]:
|
29
32
|
# FIXME: to be generalized to existing user-defined functions
|
30
33
|
return QuantumFunctionDeclaration.BUILTIN_FUNCTION_DECLARATIONS.get(name)
|
31
34
|
|
@@ -36,15 +39,21 @@ def create_model(
|
|
36
39
|
execution_preferences: Optional[ExecutionPreferences] = None,
|
37
40
|
preferences: Optional[Preferences] = None,
|
38
41
|
classical_execution_function: Optional[CFunc] = None,
|
42
|
+
out_file: Optional[str] = None,
|
39
43
|
) -> SerializedModel:
|
40
44
|
if entry_point.func_decl.name != "main":
|
41
45
|
raise ClassiqError(
|
42
46
|
f"The entry point function must be named 'main', got '{entry_point.func_decl.name}'"
|
43
47
|
)
|
44
|
-
|
48
|
+
result = entry_point.create_model(
|
45
49
|
constraints, execution_preferences, preferences, classical_execution_function
|
46
50
|
).get_model()
|
47
51
|
|
52
|
+
if out_file is not None:
|
53
|
+
write_qmod(result, out_file)
|
54
|
+
|
55
|
+
return result
|
56
|
+
|
48
57
|
|
49
58
|
class QFunc(QExpandable):
|
50
59
|
FRAME_DEPTH = 2
|
@@ -55,7 +64,7 @@ class QFunc(QExpandable):
|
|
55
64
|
functools.update_wrapper(self, py_callable)
|
56
65
|
|
57
66
|
@property
|
58
|
-
def func_decl(self) ->
|
67
|
+
def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
59
68
|
return self._qmodule.native_defs.get(
|
60
69
|
self._py_callable.__name__,
|
61
70
|
infer_func_decl(self._py_callable, qmodule=self._qmodule),
|
@@ -74,6 +83,7 @@ class QFunc(QExpandable):
|
|
74
83
|
) -> Model:
|
75
84
|
self._qmodule.enum_decls = dict()
|
76
85
|
self._qmodule.type_decls = dict()
|
86
|
+
self._qmodule.qstruct_decls = dict()
|
77
87
|
self._qmodule.native_defs = dict()
|
78
88
|
self._qmodule.constants = dict()
|
79
89
|
QConstant.set_current_model(self._qmodule)
|
@@ -93,6 +103,7 @@ class QFunc(QExpandable):
|
|
93
103
|
functions=list(self._qmodule.native_defs.values()),
|
94
104
|
enums=list(self._qmodule.enum_decls.values()),
|
95
105
|
types=list(self._qmodule.type_decls.values()),
|
106
|
+
qstructs=list(self._qmodule.qstruct_decls.values()),
|
96
107
|
**{key: value for key, value in model_extra_settings if value},
|
97
108
|
)
|
98
109
|
|
@@ -138,7 +149,7 @@ class ExternalQFunc(QTerminalCallable):
|
|
138
149
|
|
139
150
|
py_callable.__annotations__.pop("return", None)
|
140
151
|
if py_callable.__annotations__.keys() != {
|
141
|
-
mangle_keyword(arg.name) for arg in decl.
|
152
|
+
mangle_keyword(arg.name) for arg in decl.positional_arg_declarations
|
142
153
|
}:
|
143
154
|
raise ClassiqError(
|
144
155
|
f"Parameter type hints for {py_callable.__name__!r} do not match imported declaration"
|
@@ -147,6 +158,14 @@ class ExternalQFunc(QTerminalCallable):
|
|
147
158
|
functools.update_wrapper(self, py_callable)
|
148
159
|
|
149
160
|
|
161
|
+
class GenerativeQFunc(QTerminalCallable):
|
162
|
+
func_decl: NamedParamsQuantumFunctionDeclaration
|
163
|
+
|
164
|
+
def __init__(self, py_callable: Callable) -> None:
|
165
|
+
super().__init__(infer_func_decl(py_callable, QMODULE))
|
166
|
+
self.py_callable = py_callable
|
167
|
+
|
168
|
+
|
150
169
|
ILLEGAL_PARAM_ERROR = "Unsupported type hint '{annotation}' for argument '{name}'."
|
151
170
|
|
152
171
|
|
@@ -1,17 +1,15 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Mapping
|
2
2
|
|
3
|
+
from classiq.interface.exceptions import ClassiqError
|
3
4
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
4
5
|
from classiq.interface.model.quantum_function_declaration import (
|
6
|
+
AnonQuantumOperandDeclaration,
|
5
7
|
QuantumFunctionDeclaration,
|
6
8
|
)
|
7
9
|
from classiq.interface.model.quantum_lambda_function import (
|
8
|
-
QuantumCallable,
|
9
10
|
QuantumLambdaFunction,
|
10
|
-
QuantumOperand,
|
11
11
|
)
|
12
12
|
|
13
|
-
from classiq.exceptions import ClassiqError
|
14
|
-
|
15
13
|
|
16
14
|
def annotate_function_call_decl(
|
17
15
|
fc: QuantumFunctionCall,
|
@@ -25,14 +23,14 @@ def annotate_function_call_decl(
|
|
25
23
|
)
|
26
24
|
fc.set_func_decl(func_decl)
|
27
25
|
|
28
|
-
for
|
29
|
-
|
30
|
-
|
26
|
+
for arg, param in zip(fc.positional_args, fc.func_decl.positional_arg_declarations):
|
27
|
+
if not isinstance(param, AnonQuantumOperandDeclaration):
|
28
|
+
continue
|
29
|
+
args: list
|
30
|
+
if isinstance(arg, list):
|
31
|
+
args = arg
|
32
|
+
else:
|
33
|
+
args = [arg]
|
34
|
+
for qlambda in args:
|
31
35
|
if isinstance(qlambda, QuantumLambdaFunction):
|
32
|
-
qlambda.set_op_decl(
|
33
|
-
|
34
|
-
|
35
|
-
def _get_lambda_defs(operand: QuantumOperand) -> List[QuantumCallable]:
|
36
|
-
if isinstance(operand, list):
|
37
|
-
return operand
|
38
|
-
return [operand]
|
36
|
+
qlambda.set_op_decl(param)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
from contextlib import contextmanager
|
2
|
-
from typing import Iterator, List, Type
|
2
|
+
from typing import Iterator, List, Optional, Type
|
3
3
|
|
4
4
|
from classiq.interface.ast_node import ASTNode
|
5
|
+
from classiq.interface.source_reference import SourceReferencedError
|
5
6
|
|
6
7
|
|
7
8
|
class ErrorManager:
|
@@ -14,19 +15,28 @@ class ErrorManager:
|
|
14
15
|
if hasattr(self, "_instantiated"):
|
15
16
|
return
|
16
17
|
self._instantiated = True
|
17
|
-
self._errors: List[
|
18
|
+
self._errors: List[SourceReferencedError] = []
|
18
19
|
self._current_nodes_stack: List[ASTNode] = []
|
20
|
+
self._call_stack: List[str] = []
|
21
|
+
|
22
|
+
@property
|
23
|
+
def annotated_errors(self) -> List[str]:
|
24
|
+
return [str(error) for error in self._errors]
|
19
25
|
|
20
26
|
def add_error(self, error: str) -> None:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
27
|
+
self._errors.append(
|
28
|
+
SourceReferencedError(
|
29
|
+
error=error,
|
30
|
+
source_ref=(
|
31
|
+
self._current_nodes_stack[-1].source_ref
|
32
|
+
if self._current_nodes_stack
|
33
|
+
else None
|
34
|
+
),
|
35
|
+
function=self.current_function,
|
36
|
+
)
|
26
37
|
)
|
27
|
-
self._errors.append(source_referenced_error)
|
28
38
|
|
29
|
-
def get_errors(self) -> List[
|
39
|
+
def get_errors(self) -> List[SourceReferencedError]:
|
30
40
|
return self._errors
|
31
41
|
|
32
42
|
def clear(self) -> None:
|
@@ -38,12 +48,28 @@ class ErrorManager:
|
|
38
48
|
|
39
49
|
def report_errors(self, error_type: Type[Exception]) -> None:
|
40
50
|
if self.has_errors():
|
41
|
-
errors = self.
|
51
|
+
errors = self.annotated_errors
|
42
52
|
self.clear()
|
43
53
|
raise error_type("\n\t" + "\n\t".join(errors))
|
44
54
|
|
55
|
+
@property
|
56
|
+
def current_function(self) -> Optional[str]:
|
57
|
+
return self._call_stack[-1] if self._call_stack else None
|
58
|
+
|
45
59
|
@contextmanager
|
46
60
|
def node_context(self, node: ASTNode) -> Iterator[None]:
|
47
61
|
self._current_nodes_stack.append(node)
|
48
62
|
yield
|
49
63
|
self._current_nodes_stack.pop()
|
64
|
+
|
65
|
+
@contextmanager
|
66
|
+
def call(self, func_name: str) -> Iterator[None]:
|
67
|
+
self._call_stack.append(func_name)
|
68
|
+
yield
|
69
|
+
self._call_stack.pop()
|
70
|
+
|
71
|
+
|
72
|
+
def append_error(node: ASTNode, message: str) -> None:
|
73
|
+
instance = ErrorManager()
|
74
|
+
with instance.node_context(node):
|
75
|
+
instance.add_error(message)
|