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
@@ -1,5 +1,5 @@
|
|
1
1
|
from enum import Enum
|
2
|
-
from typing import
|
2
|
+
from typing import Mapping
|
3
3
|
|
4
4
|
from classiq.interface.generator.expressions.expression import Expression
|
5
5
|
from classiq.interface.generator.functions.classical_function_declaration import (
|
@@ -10,21 +10,20 @@ from classiq.interface.generator.functions.classical_type import (
|
|
10
10
|
ClassicalList,
|
11
11
|
Integer,
|
12
12
|
Real,
|
13
|
-
Struct,
|
14
13
|
)
|
15
14
|
from classiq.interface.generator.functions.port_declaration import (
|
16
15
|
PortDeclarationDirection,
|
17
16
|
)
|
17
|
+
from classiq.interface.generator.functions.type_name import Struct
|
18
18
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
19
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
20
|
+
ClassicalParameterDeclaration,
|
21
|
+
)
|
19
22
|
from classiq.interface.model.port_declaration import PortDeclaration
|
20
23
|
from classiq.interface.model.quantum_function_declaration import (
|
21
|
-
|
24
|
+
NamedParamsQuantumFunctionDeclaration,
|
22
25
|
)
|
23
26
|
|
24
|
-
if TYPE_CHECKING:
|
25
|
-
from classiq.qmod.builtins.structs import GaussianModel
|
26
|
-
from classiq.qmod.symbolic_expr import SymbolicExpr
|
27
|
-
|
28
27
|
FUNCTION_PORT_NAME = "func_port"
|
29
28
|
OBJECTIVE_PORT_NAME = "obj_port"
|
30
29
|
|
@@ -40,44 +39,30 @@ FINANCE_FUNCTION_PORT_SIZE_MAPPING: Mapping[FinanceModelType, str] = {
|
|
40
39
|
}
|
41
40
|
|
42
41
|
|
43
|
-
def _get_gaussian_size(finance_model: "GaussianModel") -> "SymbolicExpr":
|
44
|
-
from classiq.qmod.symbolic import floor, log, sum as sym_sum
|
45
|
-
|
46
|
-
return (
|
47
|
-
finance_model.num_qubits
|
48
|
-
+ finance_model.rhos.len
|
49
|
-
+ floor(log(sym_sum(finance_model.loss), 2))
|
50
|
-
+ 1
|
51
|
-
)
|
52
|
-
|
53
|
-
|
54
|
-
FINANCE_FUNCTION_PORT_SIZE_FUNCTION_MAPPING: Mapping[FinanceModelType, Callable] = {
|
55
|
-
FinanceModelType.Gaussian: _get_gaussian_size,
|
56
|
-
FinanceModelType.LogNormal: lambda finance_model: finance_model.num_qubits,
|
57
|
-
}
|
58
|
-
|
59
|
-
|
60
42
|
def _generate_finance_function(
|
61
43
|
finance_model: FinanceModelType,
|
62
|
-
) ->
|
63
|
-
return
|
44
|
+
) -> NamedParamsQuantumFunctionDeclaration:
|
45
|
+
return NamedParamsQuantumFunctionDeclaration(
|
64
46
|
name=f"{finance_model.value}_finance",
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
47
|
+
positional_arg_declarations=[
|
48
|
+
ClassicalParameterDeclaration(
|
49
|
+
name="finance_model",
|
50
|
+
classical_type=Struct(name=f"{finance_model.name}Model"),
|
51
|
+
),
|
52
|
+
ClassicalParameterDeclaration(
|
53
|
+
name="finance_function", classical_type=Struct(name="FinanceFunction")
|
54
|
+
),
|
55
|
+
PortDeclaration(
|
71
56
|
name=FUNCTION_PORT_NAME,
|
72
57
|
direction=PortDeclarationDirection.Inout,
|
73
58
|
size=Expression(expr=FINANCE_FUNCTION_PORT_SIZE_MAPPING[finance_model]),
|
74
59
|
),
|
75
|
-
|
60
|
+
PortDeclaration(
|
76
61
|
name=OBJECTIVE_PORT_NAME,
|
77
62
|
direction=PortDeclarationDirection.Inout,
|
78
63
|
size=Expression(expr="1"),
|
79
64
|
),
|
80
|
-
|
65
|
+
],
|
81
66
|
)
|
82
67
|
|
83
68
|
|
@@ -118,21 +103,29 @@ FINANCE_FUNCTION = StructDeclaration(
|
|
118
103
|
|
119
104
|
LOG_NORMAL_FINANCE_POST_PROCESS = ClassicalFunctionDeclaration(
|
120
105
|
name="log_normal_finance_post_process",
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
106
|
+
positional_parameters=[
|
107
|
+
ClassicalParameterDeclaration(
|
108
|
+
name="finance_model", classical_type=Struct(name="LogNormalModel")
|
109
|
+
),
|
110
|
+
ClassicalParameterDeclaration(
|
111
|
+
name="estimation_method", classical_type=Struct(name="FinanceFunction")
|
112
|
+
),
|
113
|
+
ClassicalParameterDeclaration(name="probability", classical_type=Real()),
|
114
|
+
],
|
126
115
|
return_type=Real(),
|
127
116
|
)
|
128
117
|
|
129
118
|
GAUSSIAN_FINANCE_POST_PROCESS = ClassicalFunctionDeclaration(
|
130
119
|
name="gaussian_finance_post_process",
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
120
|
+
positional_parameters=[
|
121
|
+
ClassicalParameterDeclaration(
|
122
|
+
name="finance_model", classical_type=Struct(name="GaussianModel")
|
123
|
+
),
|
124
|
+
ClassicalParameterDeclaration(
|
125
|
+
name="estimation_method", classical_type=Struct(name="FinanceFunction")
|
126
|
+
),
|
127
|
+
ClassicalParameterDeclaration(name="probability", classical_type=Real()),
|
128
|
+
],
|
136
129
|
return_type=Real(),
|
137
130
|
)
|
138
131
|
|
@@ -3,18 +3,20 @@ import enum
|
|
3
3
|
from classiq.interface.generator.expressions.expression import Expression
|
4
4
|
from classiq.interface.generator.functions.classical_type import (
|
5
5
|
ClassicalList,
|
6
|
-
Enum,
|
7
6
|
Integer,
|
8
7
|
Real,
|
9
|
-
Struct,
|
10
8
|
)
|
11
9
|
from classiq.interface.generator.functions.port_declaration import (
|
12
10
|
PortDeclarationDirection,
|
13
11
|
)
|
12
|
+
from classiq.interface.generator.functions.type_name import Enum, Struct
|
14
13
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
14
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
15
|
+
ClassicalParameterDeclaration,
|
16
|
+
)
|
15
17
|
from classiq.interface.model.port_declaration import PortDeclaration
|
16
18
|
from classiq.interface.model.quantum_function_declaration import (
|
17
|
-
|
19
|
+
NamedParamsQuantumFunctionDeclaration,
|
18
20
|
)
|
19
21
|
|
20
22
|
|
@@ -24,29 +26,33 @@ class FeatureMapType(enum.Enum):
|
|
24
26
|
|
25
27
|
|
26
28
|
QSVM_PAULI_FEATURE_MAP_SIZE = "get_field(feature_map, 'feature_dimension')"
|
27
|
-
QSVM_PAULI_FEATURE_MAP =
|
29
|
+
QSVM_PAULI_FEATURE_MAP = NamedParamsQuantumFunctionDeclaration(
|
28
30
|
name="pauli_feature_map",
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
positional_arg_declarations=[
|
32
|
+
ClassicalParameterDeclaration(
|
33
|
+
name="feature_map", classical_type=Struct(name="QSVMFeatureMapPauli")
|
34
|
+
),
|
35
|
+
PortDeclaration(
|
32
36
|
name="qbv",
|
33
37
|
direction=PortDeclarationDirection.Inout,
|
34
38
|
size=Expression(expr=QSVM_PAULI_FEATURE_MAP_SIZE),
|
35
|
-
)
|
36
|
-
|
39
|
+
),
|
40
|
+
],
|
37
41
|
)
|
38
42
|
|
39
43
|
QSVM_BLOCH_SPHERE_FEATURE_MAP_SIZE = "ceiling(feature_dimension/2)"
|
40
|
-
QSVM_BLOCH_SPHERE_FEATURE_MAP =
|
44
|
+
QSVM_BLOCH_SPHERE_FEATURE_MAP = NamedParamsQuantumFunctionDeclaration(
|
41
45
|
name="bloch_sphere_feature_map",
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
positional_arg_declarations=[
|
47
|
+
ClassicalParameterDeclaration(
|
48
|
+
name="feature_dimension", classical_type=Integer()
|
49
|
+
),
|
50
|
+
PortDeclaration(
|
45
51
|
name="qbv",
|
46
52
|
direction=PortDeclarationDirection.Inout,
|
47
53
|
size=Expression(expr=QSVM_BLOCH_SPHERE_FEATURE_MAP_SIZE),
|
48
|
-
)
|
49
|
-
|
54
|
+
),
|
55
|
+
],
|
50
56
|
)
|
51
57
|
|
52
58
|
QSVM_FEATURE_MAP_PAULI = StructDeclaration(
|
@@ -1,8 +1,9 @@
|
|
1
|
-
from typing import Any, Dict, Optional, Set
|
1
|
+
from typing import Any, Dict, Final, Optional, Set
|
2
2
|
|
3
3
|
import networkx as nx
|
4
4
|
import pydantic
|
5
5
|
|
6
|
+
from classiq.interface.exceptions import ClassiqValueError
|
6
7
|
from classiq.interface.generator.arith import arithmetic_expression_parser
|
7
8
|
from classiq.interface.generator.arith.arithmetic_expression_abc import (
|
8
9
|
ArithmeticExpressionABC,
|
@@ -21,10 +22,9 @@ from classiq.interface.model.quantum_type import (
|
|
21
22
|
register_info_to_quantum_type,
|
22
23
|
)
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
ARITHMETIC_EXPRESSION_RESULT_NAME: str = "expression_result"
|
25
|
+
ARITHMETIC_EXPRESSION_TARGET_NAME: Final[str] = "arithmetic_target"
|
26
|
+
ARITHMETIC_EXPRESSION_RESULT_NAME: Final[str] = "expression_result"
|
27
|
+
ARITHMETIC_EXPRESSION_GARBAGE_NAME: Final[str] = "expression_garbage"
|
28
28
|
|
29
29
|
|
30
30
|
class Arithmetic(ArithmeticExpressionABC):
|
@@ -64,12 +64,14 @@ class Arithmetic(ArithmeticExpressionABC):
|
|
64
64
|
if name in self._inputs
|
65
65
|
}
|
66
66
|
# TODO: avoid calling the result builder again, as it is called in validation
|
67
|
-
|
67
|
+
result_builder = ArithmeticResultBuilder(
|
68
68
|
graph=arithmetic_expression_parser.parse_expression(self.expression),
|
69
69
|
definitions=self.definitions,
|
70
70
|
machine_precision=self.machine_precision,
|
71
|
-
)
|
72
|
-
self._outputs[ARITHMETIC_EXPRESSION_RESULT_NAME] =
|
71
|
+
)
|
72
|
+
self._outputs[ARITHMETIC_EXPRESSION_RESULT_NAME] = result_builder.result
|
73
|
+
if result_builder.garbage:
|
74
|
+
self._outputs[ARITHMETIC_EXPRESSION_GARBAGE_NAME] = result_builder.garbage
|
73
75
|
if self.target:
|
74
76
|
self._inputs[ARITHMETIC_EXPRESSION_TARGET_NAME] = self.target
|
75
77
|
|
@@ -2,11 +2,10 @@ from typing import Callable, Dict, List
|
|
2
2
|
|
3
3
|
from typing_extensions import TypeAlias
|
4
4
|
|
5
|
+
from classiq.interface.exceptions import ClassiqArithmeticError
|
5
6
|
from classiq.interface.generator.arith import argument_utils
|
6
7
|
from classiq.interface.generator.arith.binary_ops import BOOLEAN_OP_WITH_FRACTIONS_ERROR
|
7
8
|
|
8
|
-
from classiq.exceptions import ClassiqArithmeticError
|
9
|
-
|
10
9
|
ArgTypeValidator: TypeAlias = Callable[[List[argument_utils.RegisterOrConst]], None]
|
11
10
|
|
12
11
|
|
@@ -7,6 +7,7 @@ import networkx as nx
|
|
7
7
|
import pydantic
|
8
8
|
from typing_extensions import TypeAlias
|
9
9
|
|
10
|
+
from classiq.interface.exceptions import ClassiqValueError
|
10
11
|
from classiq.interface.generator.arith import number_utils
|
11
12
|
from classiq.interface.generator.arith.arithmetic_expression_parser import (
|
12
13
|
parse_expression,
|
@@ -30,8 +31,6 @@ from classiq.interface.generator.expressions.expression_constants import (
|
|
30
31
|
from classiq.interface.generator.function_params import FunctionParams
|
31
32
|
from classiq.interface.helpers.custom_pydantic_types import PydanticExpressionStr
|
32
33
|
|
33
|
-
from classiq.exceptions import ClassiqValueError
|
34
|
-
|
35
34
|
ValidDefinitions: TypeAlias = Union[
|
36
35
|
pydantic.StrictInt, pydantic.StrictFloat, RegisterArithmeticInfo
|
37
36
|
]
|
@@ -88,7 +87,27 @@ class ArithmeticExpressionABC(abc.ABC, FunctionParams):
|
|
88
87
|
cls._validate_ast_obj(ast_obj)
|
89
88
|
|
90
89
|
graph = parse_expression(expression)
|
91
|
-
|
90
|
+
try:
|
91
|
+
cls._validate_expression_graph(graph, values)
|
92
|
+
except ClassiqValueError as e:
|
93
|
+
# This flow was created specifically for inplace Boolean XOR operations like q1 ^ q2.
|
94
|
+
# We can't plug equality in previous stages due to SymPy restrictions.
|
95
|
+
# Note that we don't validate that the expression itself is Boolean (passing non-Boolean expressions
|
96
|
+
# as inplace is currently not supported, so it's a bug).
|
97
|
+
if not e.raw_message == "Expression does not support target assignment":
|
98
|
+
raise
|
99
|
+
ast_parsed_expression = ast.parse(expression)
|
100
|
+
ast_expr = ast_parsed_expression.body[0]
|
101
|
+
if (
|
102
|
+
not isinstance(ast_expr, ast.Expr)
|
103
|
+
or not isinstance(ast_expr.value, ast.BinOp)
|
104
|
+
or not isinstance(ast_expr.value.op, ast.BitXor)
|
105
|
+
):
|
106
|
+
raise
|
107
|
+
expression = f"({expression}) == 1"
|
108
|
+
graph = parse_expression(expression)
|
109
|
+
cls._validate_expression_graph(graph, values)
|
110
|
+
|
92
111
|
validate_arithmetic_result_type(
|
93
112
|
graph=graph,
|
94
113
|
definitions=definitions,
|
@@ -4,6 +4,7 @@ from typing import Collection, List, Optional, Set, Tuple, Type, Union, cast
|
|
4
4
|
|
5
5
|
import networkx as nx
|
6
6
|
|
7
|
+
from classiq.interface.exceptions import ClassiqArithmeticError
|
7
8
|
from classiq.interface.generator.arith.arithmetic_expression_validator import (
|
8
9
|
DEFAULT_EXPRESSION_TYPE,
|
9
10
|
DEFAULT_SUPPORTED_FUNC_NAMES,
|
@@ -16,11 +17,9 @@ from classiq.interface.generator.arith.ast_node_rewrite import (
|
|
16
17
|
AstNodeRewrite,
|
17
18
|
)
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
_MULTIPLE_RESULTS_ERROR_MESSAGE: str = "Expression cannot contain multiple result"
|
20
|
+
_MULTIPLE_RESULTS_ERROR_MESSAGE: str = "Expression cannot contain multiple results"
|
22
21
|
_UNEXPECTED_ARITHMETIC_ERROR_MESSAGE: str = (
|
23
|
-
"
|
22
|
+
"Quantum expressions that evaluate to a classical value are not supported"
|
24
23
|
)
|
25
24
|
_ALLOWED_MULTI_ARGUMENT_FUNCTIONS = ("min", "max")
|
26
25
|
Node = Union[str, float, int]
|
@@ -5,13 +5,12 @@ from typing import Any, Dict, Optional, Set, Tuple, Type, Union
|
|
5
5
|
|
6
6
|
from typing_extensions import TypeAlias, get_args
|
7
7
|
|
8
|
+
from classiq.interface.exceptions import ClassiqArithmeticError, ClassiqValueError
|
8
9
|
from classiq.interface.generator.arith.ast_node_rewrite import AstNodeRewrite
|
9
10
|
from classiq.interface.generator.expressions.sympy_supported_expressions import (
|
10
11
|
SYMPY_SUPPORTED_EXPRESSIONS,
|
11
12
|
)
|
12
13
|
|
13
|
-
from classiq.exceptions import ClassiqArithmeticError, ClassiqValueError
|
14
|
-
|
15
14
|
DEFAULT_SUPPORTED_FUNC_NAMES: Set[str] = {"CLShift", "CRShift", "min", "max"}
|
16
15
|
|
17
16
|
DEFAULT_EXPRESSION_TYPE = "arithmetic"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from typing import Callable, Dict, FrozenSet, List, Optional
|
2
2
|
|
3
|
+
from classiq.interface.exceptions import ClassiqArithmeticError
|
3
4
|
from classiq.interface.generator.arith.argument_utils import (
|
4
5
|
RegisterOrConst as RegisterOrFloat,
|
5
6
|
)
|
@@ -35,8 +36,6 @@ from classiq.interface.generator.arith.logical_ops import LogicalAnd, LogicalOr
|
|
35
36
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
36
37
|
from classiq.interface.generator.arith.unary_ops import BitwiseInvert, Negation
|
37
38
|
|
38
|
-
from classiq.exceptions import ClassiqArithmeticError
|
39
|
-
|
40
39
|
ParamsGetter = Callable[..., ArithmeticOperationParams] # Argument vary
|
41
40
|
|
42
41
|
_TARGET_ERROR_MESSAGE: str = "Target unavailable for the requested operation"
|
@@ -1,14 +1,13 @@
|
|
1
|
-
from typing import Any, Dict, List, Optional, Set
|
1
|
+
from typing import Any, Dict, List, Optional, Set, Tuple
|
2
2
|
|
3
3
|
import networkx as nx
|
4
4
|
|
5
|
+
from classiq.interface.exceptions import ClassiqArithmeticError
|
5
6
|
from classiq.interface.generator.arith import arithmetic_param_getters, number_utils
|
6
7
|
from classiq.interface.generator.arith.argument_utils import RegisterOrConst
|
7
8
|
from classiq.interface.generator.arith.ast_node_rewrite import OUTPUT_SIZE
|
8
9
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
9
10
|
|
10
|
-
from classiq.exceptions import ClassiqArithmeticError
|
11
|
-
|
12
11
|
ArithmeticDefinitions = Dict[str, RegisterOrConst]
|
13
12
|
|
14
13
|
|
@@ -20,7 +19,7 @@ class ArithmeticResultBuilder:
|
|
20
19
|
definitions: ArithmeticDefinitions,
|
21
20
|
machine_precision: int,
|
22
21
|
) -> None:
|
23
|
-
self.result = self._fill_operation_results(
|
22
|
+
self.result, self.garbage = self._fill_operation_results(
|
24
23
|
graph=graph,
|
25
24
|
result_definitions=definitions,
|
26
25
|
machine_precision=machine_precision,
|
@@ -62,7 +61,7 @@ class ArithmeticResultBuilder:
|
|
62
61
|
graph: nx.DiGraph,
|
63
62
|
result_definitions: ArithmeticDefinitions,
|
64
63
|
machine_precision: int,
|
65
|
-
) -> RegisterArithmeticInfo:
|
64
|
+
) -> Tuple[RegisterArithmeticInfo, Optional[RegisterArithmeticInfo]]:
|
66
65
|
inputs_node_set: Set[str] = {
|
67
66
|
vertex for vertex, deg in graph.in_degree if deg == 0
|
68
67
|
}
|
@@ -80,29 +79,34 @@ class ArithmeticResultBuilder:
|
|
80
79
|
for predecessor_node in graph.predecessors(node)
|
81
80
|
]
|
82
81
|
if graph.out_degree(node) == 0:
|
83
|
-
return cls.
|
82
|
+
return cls._get_node_result_and_garbage(
|
84
83
|
graph, args, node, machine_precision=machine_precision
|
85
84
|
)
|
86
|
-
node_results[node] = cls.
|
85
|
+
node_results[node], _ = cls._get_node_result_and_garbage(
|
87
86
|
graph, args, node, machine_precision=machine_precision
|
88
87
|
)
|
89
88
|
raise ClassiqArithmeticError("Expression has no result")
|
90
89
|
|
91
90
|
@classmethod
|
92
|
-
def
|
91
|
+
def _get_node_result_and_garbage(
|
93
92
|
cls,
|
94
93
|
graph: nx.DiGraph,
|
95
94
|
args: List[RegisterOrConst],
|
96
95
|
node: str,
|
97
96
|
*,
|
98
97
|
machine_precision: int,
|
99
|
-
) -> RegisterArithmeticInfo:
|
100
|
-
|
98
|
+
) -> Tuple[RegisterArithmeticInfo, Optional[RegisterArithmeticInfo]]:
|
99
|
+
node_params = arithmetic_param_getters.get_params(
|
101
100
|
node_id=node,
|
102
101
|
args=args,
|
103
102
|
output_size=graph.nodes[node].get(OUTPUT_SIZE, None),
|
104
103
|
machine_precision=machine_precision,
|
105
|
-
)
|
104
|
+
)
|
105
|
+
|
106
|
+
return (
|
107
|
+
node_params.outputs[node_params.output_name],
|
108
|
+
node_params.outputs.get(node_params.garbage_output_name),
|
109
|
+
)
|
106
110
|
|
107
111
|
@staticmethod
|
108
112
|
def _convert_int_to_float_str(node: Any) -> str:
|
@@ -2,7 +2,7 @@ import ast
|
|
2
2
|
import itertools
|
3
3
|
from typing import Any, Iterator, Optional, Union, cast
|
4
4
|
|
5
|
-
from classiq.exceptions import ClassiqArithmeticError
|
5
|
+
from classiq.interface.exceptions import ClassiqArithmeticError
|
6
6
|
|
7
7
|
SEPARATOR: str = "_"
|
8
8
|
OUTPUT_SIZE: str = "output_size"
|
@@ -16,6 +16,8 @@ from typing import (
|
|
16
16
|
import pydantic
|
17
17
|
from pydantic.generics import GenericModel
|
18
18
|
|
19
|
+
from classiq.interface.enum_utils import StrEnum
|
20
|
+
from classiq.interface.exceptions import ClassiqValueError
|
19
21
|
from classiq.interface.generator.arith import argument_utils, number_utils
|
20
22
|
from classiq.interface.generator.arith.argument_utils import RegisterOrConst
|
21
23
|
from classiq.interface.generator.arith.arithmetic_operations import (
|
@@ -28,9 +30,6 @@ from classiq.interface.generator.arith.register_user_input import RegisterArithm
|
|
28
30
|
from classiq.interface.generator.arith.unary_ops import Negation
|
29
31
|
from classiq.interface.generator.function_params import get_zero_input_name
|
30
32
|
|
31
|
-
from classiq._internals.enum_utils import StrEnum
|
32
|
-
from classiq.exceptions import ClassiqValueError
|
33
|
-
|
34
33
|
LeftDataT = TypeVar("LeftDataT")
|
35
34
|
RightDataT = TypeVar("RightDataT")
|
36
35
|
_NumericArgumentInplaceErrorMessage: str = "Cannot inplace the numeric argument {}"
|
@@ -617,7 +616,7 @@ class Power(BinaryOpParams[RegisterArithmeticInfo, pydantic.PositiveInt]):
|
|
617
616
|
*,
|
618
617
|
arg: RegisterArithmeticInfo,
|
619
618
|
action_right_arg: RegisterOrConst,
|
620
|
-
compute_power: int
|
619
|
+
compute_power: int,
|
621
620
|
) -> pydantic.NonNegativeInt:
|
622
621
|
inner_compute_power_params = Power(
|
623
622
|
left_arg=arg,
|
@@ -800,6 +799,7 @@ class Modulo(EffectiveUnaryOpParams[int]):
|
|
800
799
|
return 2 ** (repr_qubits)
|
801
800
|
|
802
801
|
def _get_result_register(self) -> RegisterArithmeticInfo:
|
803
|
-
|
804
|
-
|
805
|
-
|
802
|
+
size = round(math.log2(self.right_arg))
|
803
|
+
if size <= 0:
|
804
|
+
raise ClassiqValueError("Cannot use a quantum expression with zero size")
|
805
|
+
return RegisterArithmeticInfo(size=size, is_signed=False, fraction_places=0)
|
@@ -3,6 +3,7 @@ from typing import Any, Dict, Iterable
|
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
|
6
|
+
from classiq.interface.exceptions import ClassiqValueError
|
6
7
|
from classiq.interface.generator.arith import argument_utils
|
7
8
|
from classiq.interface.generator.arith.argument_utils import RegisterOrConst
|
8
9
|
from classiq.interface.generator.arith.arithmetic_operations import (
|
@@ -15,8 +16,6 @@ from classiq.interface.generator.arith.binary_ops import (
|
|
15
16
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
16
17
|
from classiq.interface.generator.function_params import get_zero_input_name
|
17
18
|
|
18
|
-
from classiq.exceptions import ClassiqValueError
|
19
|
-
|
20
19
|
Numeric = (float, int)
|
21
20
|
|
22
21
|
|
@@ -57,38 +56,56 @@ class Extremum(ArithmeticOperationParams):
|
|
57
56
|
def _bound_calculator(cls, arg1: float, arg2: float) -> float:
|
58
57
|
pass
|
59
58
|
|
59
|
+
@staticmethod
|
60
|
+
def _less_qubits_arg(
|
61
|
+
arg1: RegisterOrConst, arg2: RegisterOrConst
|
62
|
+
) -> RegisterOrConst:
|
63
|
+
if not isinstance(arg1, RegisterArithmeticInfo):
|
64
|
+
return arg1
|
65
|
+
if not isinstance(arg2, RegisterArithmeticInfo):
|
66
|
+
return arg2
|
67
|
+
return arg1 if arg1.size <= arg2.size else arg2
|
68
|
+
|
60
69
|
@classmethod
|
61
70
|
@abc.abstractmethod
|
62
|
-
def
|
71
|
+
def preferred_arg(
|
63
72
|
cls, arg1: RegisterOrConst, arg2: RegisterOrConst
|
64
73
|
) -> RegisterOrConst:
|
65
74
|
pass
|
66
75
|
|
67
76
|
def _get_result_register(self) -> RegisterArithmeticInfo:
|
68
|
-
|
69
|
-
|
77
|
+
eff_left_arg = argument_utils.limit_fraction_places(
|
78
|
+
self.left_arg, self.machine_precision
|
79
|
+
)
|
80
|
+
eff_right_arg = argument_utils.limit_fraction_places(
|
81
|
+
self.right_arg, self.machine_precision
|
82
|
+
)
|
83
|
+
if argument_utils.arg_bounds_overlap((eff_left_arg, eff_right_arg)):
|
84
|
+
return self._get_general_case_result_register(eff_left_arg, eff_right_arg)
|
70
85
|
return argument_utils.as_arithmetic_info(
|
71
|
-
self.
|
86
|
+
self.preferred_arg(eff_left_arg, eff_right_arg)
|
72
87
|
)
|
73
88
|
|
74
|
-
def _get_general_case_result_register(
|
89
|
+
def _get_general_case_result_register(
|
90
|
+
self, eff_left_arg: RegisterOrConst, eff_right_arg: RegisterOrConst
|
91
|
+
) -> RegisterArithmeticInfo:
|
75
92
|
integer_part_size = max(
|
76
|
-
argument_utils.integer_part_size(
|
77
|
-
argument_utils.integer_part_size(
|
93
|
+
argument_utils.integer_part_size(eff_left_arg),
|
94
|
+
argument_utils.integer_part_size(eff_right_arg),
|
78
95
|
)
|
79
96
|
fraction_places = max(
|
80
|
-
argument_utils.fraction_places(
|
81
|
-
argument_utils.fraction_places(
|
97
|
+
argument_utils.fraction_places(eff_left_arg),
|
98
|
+
argument_utils.fraction_places(eff_right_arg),
|
82
99
|
)
|
83
100
|
required_size = integer_part_size + fraction_places
|
84
101
|
bounds = (
|
85
102
|
self._bound_calculator(
|
86
|
-
argument_utils.lower_bound(
|
87
|
-
argument_utils.lower_bound(
|
103
|
+
argument_utils.lower_bound(eff_left_arg),
|
104
|
+
argument_utils.lower_bound(eff_right_arg),
|
88
105
|
),
|
89
106
|
self._bound_calculator(
|
90
|
-
argument_utils.upper_bound(
|
91
|
-
argument_utils.upper_bound(
|
107
|
+
argument_utils.upper_bound(eff_left_arg),
|
108
|
+
argument_utils.upper_bound(eff_right_arg),
|
92
109
|
),
|
93
110
|
)
|
94
111
|
return RegisterArithmeticInfo(
|
@@ -107,12 +124,15 @@ class Min(Extremum):
|
|
107
124
|
return min(arg1, arg2)
|
108
125
|
|
109
126
|
@classmethod
|
110
|
-
def
|
127
|
+
def preferred_arg(
|
111
128
|
cls, arg1: RegisterOrConst, arg2: RegisterOrConst
|
112
129
|
) -> RegisterOrConst:
|
113
|
-
|
130
|
+
min1, min2 = min(argument_utils.bounds(arg1)), min(argument_utils.bounds(arg2))
|
131
|
+
if min1 < min2:
|
114
132
|
return arg1
|
115
|
-
|
133
|
+
if min2 < min1:
|
134
|
+
return arg2
|
135
|
+
return cls._less_qubits_arg(arg1, arg2)
|
116
136
|
|
117
137
|
|
118
138
|
class Max(Extremum):
|
@@ -123,9 +143,12 @@ class Max(Extremum):
|
|
123
143
|
return max(arg1, arg2)
|
124
144
|
|
125
145
|
@classmethod
|
126
|
-
def
|
146
|
+
def preferred_arg(
|
127
147
|
cls, arg1: RegisterOrConst, arg2: RegisterOrConst
|
128
148
|
) -> RegisterOrConst:
|
129
|
-
|
149
|
+
max1, max2 = max(argument_utils.bounds(arg1)), max(argument_utils.bounds(arg2))
|
150
|
+
if max1 > max2:
|
130
151
|
return arg1
|
131
|
-
|
152
|
+
if max2 > max1:
|
153
|
+
return arg2
|
154
|
+
return cls._less_qubits_arg(arg1, arg2)
|
@@ -2,6 +2,7 @@ from typing import Iterable, List, Optional
|
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
+
from classiq.interface.exceptions import ClassiqValueError
|
5
6
|
from classiq.interface.generator.arith.argument_utils import RegisterOrConst
|
6
7
|
from classiq.interface.generator.arith.arithmetic_operations import (
|
7
8
|
ArithmeticOperationParams,
|
@@ -9,8 +10,6 @@ from classiq.interface.generator.arith.arithmetic_operations import (
|
|
9
10
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
10
11
|
from classiq.interface.generator.function_params import get_zero_input_name
|
11
12
|
|
12
|
-
from classiq.exceptions import ClassiqValueError
|
13
|
-
|
14
13
|
|
15
14
|
def get_arg_name(idx: int) -> str:
|
16
15
|
return f"arg_{idx}"
|
@@ -2,14 +2,13 @@ from typing import Any, Dict, Optional
|
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
+
from classiq.interface.exceptions import ClassiqValueError
|
5
6
|
from classiq.interface.generator.arith import number_utils
|
6
7
|
from classiq.interface.helpers.custom_pydantic_types import PydanticFloatTuple
|
7
8
|
from classiq.interface.helpers.hashable_pydantic_base_model import (
|
8
9
|
HashablePydanticBaseModel,
|
9
10
|
)
|
10
11
|
|
11
|
-
from classiq.exceptions import ClassiqValueError
|
12
|
-
|
13
12
|
|
14
13
|
class RegisterArithmeticInfo(HashablePydanticBaseModel):
|
15
14
|
size: pydantic.PositiveInt
|
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Final, Iterable, Optional
|
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
+
from classiq.interface.exceptions import ClassiqValueError
|
5
6
|
from classiq.interface.generator.arith import argument_utils, number_utils
|
6
7
|
from classiq.interface.generator.arith.arithmetic_operations import (
|
7
8
|
ArithmeticOperationParams,
|
@@ -9,8 +10,6 @@ from classiq.interface.generator.arith.arithmetic_operations import (
|
|
9
10
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
10
11
|
from classiq.interface.generator.function_params import get_zero_input_name
|
11
12
|
|
12
|
-
from classiq.exceptions import ClassiqValueError
|
13
|
-
|
14
13
|
UNARY_ARG_NAME: Final[str] = "arg"
|
15
14
|
|
16
15
|
|