classiq 0.37.1__py3-none-any.whl → 0.39.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 +23 -24
- classiq/_analyzer_extras/_ipywidgets_async_extension.py +1 -1
- classiq/_analyzer_extras/interactive_hardware.py +3 -3
- classiq/_internals/api_wrapper.py +37 -17
- classiq/_internals/async_utils.py +1 -74
- classiq/_internals/authentication/device.py +9 -4
- classiq/_internals/authentication/password_manager.py +25 -10
- classiq/_internals/authentication/token_manager.py +2 -2
- classiq/_internals/client.py +24 -6
- classiq/_internals/jobs.py +10 -7
- classiq/analyzer/analyzer.py +29 -29
- classiq/analyzer/analyzer_utilities.py +5 -5
- classiq/analyzer/rb.py +4 -5
- classiq/analyzer/show_interactive_hack.py +6 -6
- classiq/applications/__init__.py +1 -8
- classiq/applications/chemistry/__init__.py +6 -0
- classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +9 -16
- classiq/applications/combinatorial_helpers/allowed_constraints.py +20 -0
- classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
- classiq/applications/combinatorial_helpers/arithmetic/isolation.py +42 -0
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +150 -0
- classiq/applications/combinatorial_helpers/encoding_mapping.py +107 -0
- classiq/applications/combinatorial_helpers/encoding_utils.py +122 -0
- classiq/applications/combinatorial_helpers/memory.py +77 -0
- classiq/applications/combinatorial_helpers/optimization_model.py +162 -0
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +75 -0
- classiq/applications/combinatorial_helpers/py.typed +0 -0
- classiq/applications/combinatorial_helpers/pyomo_utils.py +245 -0
- classiq/applications/combinatorial_helpers/solvers/__init__.py +0 -0
- classiq/applications/combinatorial_helpers/sympy_utils.py +22 -0
- classiq/applications/combinatorial_helpers/transformations/__init__.py +0 -0
- classiq/applications/combinatorial_helpers/transformations/encoding.py +187 -0
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +142 -0
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +122 -0
- classiq/applications/combinatorial_helpers/transformations/penalty.py +32 -0
- classiq/applications/combinatorial_helpers/transformations/penalty_support.py +37 -0
- classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +75 -0
- classiq/applications/combinatorial_helpers/transformations/slack_variables.py +88 -0
- classiq/applications/combinatorial_optimization/__init__.py +13 -2
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +134 -0
- classiq/applications/finance/__init__.py +3 -2
- classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +27 -30
- classiq/applications/grover/__init__.py +11 -0
- classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +20 -91
- classiq/applications/libraries/__init__.py +0 -0
- classiq/applications/libraries/qmci_library.py +35 -0
- classiq/applications/qnn/circuit_utils.py +2 -2
- classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
- classiq/applications/qnn/types.py +2 -2
- classiq/applications/qsvm/__init__.py +5 -1
- classiq/applications/qsvm/qsvm.py +4 -7
- classiq/applications/qsvm/qsvm_data_generation.py +2 -5
- classiq/exceptions.py +43 -1
- classiq/execution/all_hardware_devices.py +13 -0
- classiq/executor.py +12 -10
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +6 -3
- classiq/interface/analyzer/result.py +12 -8
- classiq/interface/applications/qsvm.py +17 -3
- classiq/interface/ast_node.py +23 -0
- classiq/interface/backend/backend_preferences.py +4 -2
- classiq/interface/backend/pydantic_backend.py +3 -1
- classiq/interface/backend/quantum_backend_providers.py +1 -0
- classiq/interface/chemistry/fermionic_operator.py +15 -13
- classiq/interface/chemistry/ground_state_problem.py +18 -3
- classiq/interface/chemistry/molecule.py +8 -6
- classiq/interface/chemistry/operator.py +20 -14
- classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
- classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
- classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
- classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
- classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
- classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
- classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
- classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
- classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
- classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
- classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
- classiq/interface/executor/aws_execution_cost.py +4 -3
- classiq/interface/executor/estimation.py +2 -2
- classiq/interface/executor/execution_preferences.py +5 -34
- classiq/interface/executor/execution_request.py +15 -48
- classiq/interface/executor/optimizer_preferences.py +22 -13
- classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
- classiq/interface/executor/quantum_instruction_set.py +2 -1
- classiq/interface/executor/register_initialization.py +1 -3
- classiq/interface/executor/result.py +41 -10
- classiq/interface/executor/vqe_result.py +2 -2
- classiq/interface/finance/function_input.py +17 -4
- classiq/interface/finance/gaussian_model_input.py +3 -1
- classiq/interface/finance/log_normal_model_input.py +3 -1
- classiq/interface/finance/model_input.py +2 -0
- classiq/interface/generator/amplitude_loading.py +6 -3
- classiq/interface/generator/application_apis/__init__.py +1 -0
- classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
- classiq/interface/generator/arith/argument_utils.py +14 -4
- classiq/interface/generator/arith/arithmetic.py +3 -1
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
- classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
- classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
- classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
- classiq/interface/generator/arith/arithmetic_operations.py +5 -10
- classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
- classiq/interface/generator/arith/binary_ops.py +202 -54
- classiq/interface/generator/arith/extremum_operations.py +5 -3
- classiq/interface/generator/arith/logical_ops.py +4 -2
- classiq/interface/generator/arith/machine_precision.py +3 -0
- classiq/interface/generator/arith/number_utils.py +34 -44
- classiq/interface/generator/arith/register_user_input.py +21 -1
- classiq/interface/generator/arith/unary_ops.py +16 -25
- classiq/interface/generator/builtin_api_builder.py +0 -5
- classiq/interface/generator/chemistry_function_params.py +4 -4
- classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
- classiq/interface/generator/compiler_keywords.py +4 -0
- classiq/interface/generator/complex_type.py +3 -10
- classiq/interface/generator/constant.py +2 -3
- classiq/interface/generator/control_state.py +5 -3
- classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
- classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
- classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
- classiq/interface/generator/expressions/evaluated_expression.py +18 -4
- classiq/interface/generator/expressions/expression.py +3 -5
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
- classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
- classiq/interface/generator/finance.py +1 -1
- classiq/interface/generator/function_params.py +7 -6
- classiq/interface/generator/functions/__init__.py +2 -2
- classiq/interface/generator/functions/builtins/__init__.py +15 -0
- classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
- classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
- classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
- classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +612 -219
- classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
- classiq/interface/generator/functions/classical_type.py +2 -4
- classiq/interface/generator/functions/foreign_function_definition.py +12 -4
- classiq/interface/generator/functions/function_declaration.py +2 -2
- classiq/interface/generator/functions/function_implementation.py +8 -4
- classiq/interface/generator/functions/native_function_definition.py +4 -2
- classiq/interface/generator/functions/register.py +4 -2
- classiq/interface/generator/functions/register_mapping_data.py +14 -10
- classiq/interface/generator/generated_circuit_data.py +2 -2
- classiq/interface/generator/grover_operator.py +5 -3
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
- classiq/interface/generator/hardware/hardware_data.py +6 -4
- classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
- classiq/interface/generator/hartree_fock.py +13 -3
- classiq/interface/generator/linear_pauli_rotations.py +3 -1
- classiq/interface/generator/mcu.py +5 -3
- classiq/interface/generator/mcx.py +7 -5
- classiq/interface/generator/model/classical_main_validator.py +1 -1
- classiq/interface/generator/model/constraints.py +2 -1
- classiq/interface/generator/model/model.py +12 -20
- classiq/interface/generator/model/preferences/preferences.py +4 -3
- classiq/interface/generator/oracles/custom_oracle.py +4 -2
- classiq/interface/generator/oracles/oracle_abc.py +2 -2
- classiq/interface/generator/qpe.py +6 -4
- classiq/interface/generator/qsvm.py +5 -8
- classiq/interface/generator/quantum_function_call.py +21 -16
- classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
- classiq/interface/generator/range_types.py +3 -1
- classiq/interface/generator/slice_parsing_utils.py +8 -3
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
- classiq/interface/generator/state_preparation/metrics.py +2 -1
- classiq/interface/generator/state_preparation/state_preparation.py +7 -5
- classiq/interface/generator/state_propagator.py +16 -5
- classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
- classiq/interface/generator/types/struct_declaration.py +10 -7
- classiq/interface/generator/ucc.py +6 -4
- classiq/interface/generator/unitary_gate.py +7 -3
- classiq/interface/generator/validations/flow_graph.py +6 -4
- classiq/interface/generator/validations/validator_functions.py +6 -4
- classiq/interface/hardware.py +2 -2
- classiq/interface/helpers/custom_encoders.py +3 -0
- classiq/interface/helpers/pydantic_model_helpers.py +0 -6
- classiq/interface/helpers/validation_helpers.py +1 -1
- classiq/interface/helpers/versioned_model.py +4 -1
- classiq/interface/ide/show.py +2 -2
- classiq/interface/jobs.py +72 -3
- classiq/interface/model/bind_operation.py +18 -11
- classiq/interface/model/call_synthesis_data.py +68 -0
- classiq/interface/model/classical_if.py +13 -0
- classiq/interface/model/classical_parameter_declaration.py +2 -3
- classiq/interface/model/control.py +16 -0
- classiq/interface/model/handle_binding.py +3 -2
- classiq/interface/model/inplace_binary_operation.py +2 -2
- classiq/interface/model/invert.py +10 -0
- classiq/interface/model/model.py +29 -22
- classiq/interface/model/native_function_definition.py +3 -5
- classiq/interface/model/power.py +12 -0
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
- classiq/interface/model/quantum_expressions/control_state.py +2 -2
- classiq/interface/model/quantum_function_call.py +33 -142
- classiq/interface/model/quantum_function_declaration.py +8 -0
- classiq/interface/model/quantum_if_operation.py +4 -5
- classiq/interface/model/quantum_lambda_function.py +58 -0
- classiq/{quantum_register.py → interface/model/quantum_register.py} +17 -9
- classiq/interface/model/quantum_statement.py +3 -2
- classiq/interface/model/quantum_type.py +58 -59
- classiq/interface/model/quantum_variable_declaration.py +3 -3
- classiq/interface/model/repeat.py +13 -0
- classiq/interface/model/resolvers/function_call_resolver.py +26 -0
- classiq/interface/model/statement_block.py +49 -0
- classiq/interface/model/validations/handles_validator.py +16 -18
- classiq/interface/model/within_apply_operation.py +11 -0
- classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
- classiq/interface/server/routes.py +5 -4
- classiq/qmod/__init__.py +13 -6
- classiq/qmod/builtins/classical_execution_primitives.py +27 -36
- classiq/qmod/builtins/classical_functions.py +22 -12
- classiq/qmod/builtins/functions.py +272 -328
- classiq/qmod/builtins/operations.py +171 -35
- classiq/qmod/builtins/structs.py +15 -15
- classiq/qmod/cfunc.py +42 -0
- classiq/qmod/classical_function.py +6 -14
- classiq/qmod/declaration_inferrer.py +12 -21
- classiq/qmod/expression_query.py +23 -0
- classiq/qmod/model_state_container.py +2 -0
- classiq/qmod/native/__init__.py +0 -0
- classiq/qmod/native/expression_to_qmod.py +189 -0
- classiq/qmod/native/pretty_printer.py +340 -0
- classiq/qmod/qfunc.py +27 -0
- classiq/qmod/qmod_constant.py +100 -0
- classiq/qmod/qmod_parameter.py +36 -13
- classiq/qmod/qmod_struct.py +3 -3
- classiq/qmod/qmod_variable.py +148 -31
- classiq/qmod/quantum_callable.py +1 -0
- classiq/qmod/quantum_expandable.py +18 -19
- classiq/qmod/quantum_function.py +41 -8
- classiq/qmod/symbolic.py +48 -5
- classiq/qmod/symbolic_expr.py +9 -0
- classiq/qmod/utilities.py +13 -0
- classiq/qmod/write_qmod.py +39 -0
- {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/METADATA +2 -1
- {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/RECORD +244 -225
- {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/WHEEL +1 -1
- classiq/applications/benchmarking/__init__.py +0 -9
- classiq/applications/benchmarking/mirror_benchmarking.py +0 -67
- classiq/applications/numpy_utils.py +0 -37
- classiq/applications_model_constructors/__init__.py +0 -17
- classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +0 -178
- classiq/applications_model_constructors/libraries/qmci_library.py +0 -109
- classiq/builtin_functions/__init__.py +0 -43
- classiq/builtin_functions/amplitude_loading.py +0 -3
- classiq/builtin_functions/binary_ops.py +0 -1
- classiq/builtin_functions/exponentiation.py +0 -5
- classiq/builtin_functions/qpe.py +0 -4
- classiq/builtin_functions/qsvm.py +0 -7
- classiq/builtin_functions/range_types.py +0 -5
- classiq/builtin_functions/standard_gates.py +0 -1
- classiq/builtin_functions/state_preparation.py +0 -6
- classiq/builtin_functions/suzuki_trotter.py +0 -3
- classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
- classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -169
- classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
- classiq/interface/generator/types/combinatorial_problem.py +0 -26
- classiq/interface/model/numeric_reinterpretation.py +0 -25
- classiq/interface/model/operator_synthesis_data.py +0 -48
- classiq/model/__init__.py +0 -14
- classiq/model/composite_function_generator.py +0 -33
- classiq/model/function_handler.py +0 -466
- classiq/model/function_handler.pyi +0 -152
- classiq/model/logic_flow.py +0 -149
- classiq/model/logic_flow_change_handler.py +0 -71
- classiq/model/model.py +0 -246
- classiq/quantum_functions/__init__.py +0 -17
- classiq/quantum_functions/annotation_parser.py +0 -207
- classiq/quantum_functions/decorators.py +0 -22
- classiq/quantum_functions/function_library.py +0 -181
- classiq/quantum_functions/function_parser.py +0 -74
- classiq/quantum_functions/quantum_function.py +0 -236
- /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers}/__init__.py +0 -0
- /classiq/{interface/generator/functions/core_lib_declarations → applications/combinatorial_helpers/arithmetic}/__init__.py +0 -0
- /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → applications/combinatorial_helpers/pauli_helpers/__init__.py} +0 -0
- /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
- /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
- /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +0 -0
- /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +0 -0
@@ -2,24 +2,27 @@ from typing import Any, ClassVar, Dict, Mapping
|
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
+
from classiq.interface.ast_node import HashableASTNode
|
5
6
|
from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
|
6
|
-
from classiq.interface.helpers.hashable_pydantic_base_model import (
|
7
|
-
HashablePydanticBaseModel,
|
8
|
-
)
|
9
7
|
|
10
8
|
from classiq.exceptions import ClassiqValueError
|
11
9
|
|
12
10
|
|
13
|
-
class StructDeclaration(
|
11
|
+
class StructDeclaration(HashableASTNode):
|
14
12
|
name: str
|
15
13
|
|
16
14
|
variables: Dict[str, ConcreteClassicalType] = pydantic.Field(
|
17
15
|
default_factory=dict,
|
18
|
-
description="Dictionary of variable names and their classical
|
16
|
+
description="Dictionary of variable names and their classical types",
|
19
17
|
)
|
20
18
|
|
21
19
|
BUILTIN_STRUCT_DECLARATIONS: ClassVar[Dict[str, "StructDeclaration"]] = {}
|
22
20
|
|
23
21
|
def validate_fields(self, fields: Mapping[str, Any]) -> None:
|
24
|
-
|
25
|
-
|
22
|
+
expected_field_names = list(self.variables.keys())
|
23
|
+
received_field_names = list(fields.keys())
|
24
|
+
if set(expected_field_names) != set(received_field_names):
|
25
|
+
raise ClassiqValueError(
|
26
|
+
f"Invalid fields for {self.name} instance. Expected fields "
|
27
|
+
f"{expected_field_names}, got {received_field_names}"
|
28
|
+
)
|
@@ -10,6 +10,8 @@ from classiq.interface.generator.excitations import (
|
|
10
10
|
EXCITATIONS_TYPE_EXACT,
|
11
11
|
)
|
12
12
|
|
13
|
+
from classiq.exceptions import ClassiqValueError
|
14
|
+
|
13
15
|
_EXCITATIONS_DICT = {"s": 1, "d": 2, "t": 3, "q": 4}
|
14
16
|
|
15
17
|
DEFAULT_EXCITATIONS = [1, 2]
|
@@ -44,7 +46,7 @@ class UCC(ChemistryFunctionParams):
|
|
44
46
|
def _validate_excitations(cls, excitations: EXCITATIONS_TYPE) -> EXCITATIONS_TYPE:
|
45
47
|
if isinstance(excitations, int):
|
46
48
|
if excitations not in _EXCITATIONS_DICT.values():
|
47
|
-
raise
|
49
|
+
raise ClassiqValueError(
|
48
50
|
f"possible values of excitations are {list(_EXCITATIONS_DICT.values())}"
|
49
51
|
)
|
50
52
|
excitations = [excitations]
|
@@ -53,19 +55,19 @@ class UCC(ChemistryFunctionParams):
|
|
53
55
|
excitations = list(excitations) # type: ignore[assignment]
|
54
56
|
if all(isinstance(idx, int) for idx in excitations):
|
55
57
|
if any(idx not in _EXCITATIONS_DICT.values() for idx in excitations):
|
56
|
-
raise
|
58
|
+
raise ClassiqValueError(
|
57
59
|
f"possible values of excitations are {list(_EXCITATIONS_DICT.values())}"
|
58
60
|
)
|
59
61
|
|
60
62
|
elif all(isinstance(idx, str) for idx in excitations):
|
61
63
|
if any(idx not in _EXCITATIONS_DICT.keys() for idx in excitations):
|
62
|
-
raise
|
64
|
+
raise ClassiqValueError(
|
63
65
|
f"possible values of excitations are {list(_EXCITATIONS_DICT.keys())}"
|
64
66
|
)
|
65
67
|
excitations = sorted(_EXCITATIONS_DICT[idx] for idx in excitations) # type: ignore[index]
|
66
68
|
|
67
69
|
else:
|
68
|
-
raise
|
70
|
+
raise ClassiqValueError(
|
69
71
|
"excitations must be of the same type (all str or all int)"
|
70
72
|
)
|
71
73
|
return excitations
|
@@ -6,6 +6,8 @@ import pydantic
|
|
6
6
|
from classiq.interface.generator import complex_type, function_params
|
7
7
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
8
8
|
|
9
|
+
from classiq.exceptions import ClassiqValueError
|
10
|
+
|
9
11
|
DataNumber = Union[complex_type.Complex, float, int]
|
10
12
|
DataArray = List[List[DataNumber]]
|
11
13
|
|
@@ -28,11 +30,13 @@ class UnitaryGate(function_params.FunctionParams):
|
|
28
30
|
def validate_data(cls, data: DataArray) -> DataArray:
|
29
31
|
data_np = np.array(data, dtype=object)
|
30
32
|
if data_np.ndim != 2:
|
31
|
-
raise
|
33
|
+
raise ClassiqValueError("Data must me two dimensional")
|
32
34
|
if data_np.shape[0] != data_np.shape[1]:
|
33
|
-
raise
|
35
|
+
raise ClassiqValueError("Matrix must be square")
|
34
36
|
if not np.mod(np.log2(data_np.shape[0]), 1) == 0:
|
35
|
-
raise
|
37
|
+
raise ClassiqValueError(
|
38
|
+
"Matrix dimensions must be an integer exponent of 2"
|
39
|
+
)
|
36
40
|
return data
|
37
41
|
|
38
42
|
@property
|
@@ -11,6 +11,8 @@ from classiq.interface.generator.quantum_function_call import (
|
|
11
11
|
)
|
12
12
|
from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyString
|
13
13
|
|
14
|
+
from classiq.exceptions import ClassiqValueError
|
15
|
+
|
14
16
|
IO_MULTI_USE_ERROR_MSG = "Input and output names can only be used once"
|
15
17
|
UNCONNECTED_WIRES_ERROR_MSG = "Wires connected only on one end"
|
16
18
|
UNCONNECTED_FLOW_IO_ERROR_MSG = "Flow IOs not connected to inner calls"
|
@@ -40,7 +42,7 @@ def _parse_call_inputs(
|
|
40
42
|
wire = wires[wire_name]
|
41
43
|
|
42
44
|
if wire.end:
|
43
|
-
raise
|
45
|
+
raise ClassiqValueError(
|
44
46
|
IO_MULTI_USE_ERROR_MSG
|
45
47
|
+ f". The name {wire_name} is used multiple times."
|
46
48
|
)
|
@@ -62,7 +64,7 @@ def _parse_call_outputs(
|
|
62
64
|
wire = wires[wire_name]
|
63
65
|
|
64
66
|
if wire.start:
|
65
|
-
raise
|
67
|
+
raise ClassiqValueError(
|
66
68
|
IO_MULTI_USE_ERROR_MSG
|
67
69
|
+ f". The name {wire_name} is used multiple times."
|
68
70
|
)
|
@@ -148,7 +150,7 @@ def validate_legal_wiring(
|
|
148
150
|
if unconnected_wires:
|
149
151
|
error_messages.append(f"{UNCONNECTED_WIRES_ERROR_MSG}: {unconnected_wires}")
|
150
152
|
|
151
|
-
raise
|
153
|
+
raise ClassiqValueError(_join_errors(error_messages))
|
152
154
|
|
153
155
|
|
154
156
|
def _join_errors(error_messages: List[str]) -> str:
|
@@ -180,7 +182,7 @@ def validate_acyclic_logic_flow(
|
|
180
182
|
|
181
183
|
if not nx.algorithms.is_directed_acyclic_graph(graph):
|
182
184
|
cycles = list(nx.algorithms.simple_cycles(graph))
|
183
|
-
raise
|
185
|
+
raise ClassiqValueError(CYCLE_ERROR_MSG + ". Cycles are: " + str(cycles))
|
184
186
|
|
185
187
|
return graph
|
186
188
|
|
@@ -4,6 +4,8 @@ import numpy as np
|
|
4
4
|
|
5
5
|
from classiq.interface.helpers.custom_pydantic_types import PydanticProbabilityFloat
|
6
6
|
|
7
|
+
from classiq.exceptions import ClassiqValueError
|
8
|
+
|
7
9
|
NOT_SUM_TO_ONE_ERROR = "Probabilities do not sum to 1"
|
8
10
|
|
9
11
|
SUM_TO_ONE_SENSITIVITY = 8
|
@@ -26,9 +28,9 @@ def is_probabilities_sum_to_one(pro: Iterable[PydanticProbabilityFloat]) -> bool
|
|
26
28
|
|
27
29
|
def validate_amplitudes(amp: Amplitude) -> Amplitude:
|
28
30
|
if not is_amplitudes_sum_to_one(amp):
|
29
|
-
raise
|
31
|
+
raise ClassiqValueError("Amplitudes do not sum to 1")
|
30
32
|
if not _is_power_of_two(amp):
|
31
|
-
raise
|
33
|
+
raise ClassiqValueError("Amplitudes length must be power of 2")
|
32
34
|
return amp
|
33
35
|
|
34
36
|
|
@@ -36,7 +38,7 @@ def validate_probabilities(
|
|
36
38
|
cls: type, pmf: Sequence[PydanticProbabilityFloat]
|
37
39
|
) -> Sequence[PydanticProbabilityFloat]:
|
38
40
|
if not is_probabilities_sum_to_one(pmf):
|
39
|
-
raise
|
41
|
+
raise ClassiqValueError(NOT_SUM_TO_ONE_ERROR)
|
40
42
|
if not _is_power_of_two(pmf):
|
41
|
-
raise
|
43
|
+
raise ClassiqValueError("Probabilities length must be power of 2")
|
42
44
|
return pmf
|
classiq/interface/hardware.py
CHANGED
@@ -17,8 +17,8 @@ class Provider(StrEnum):
|
|
17
17
|
OQC = "OQC"
|
18
18
|
|
19
19
|
@property
|
20
|
-
def id(self):
|
21
|
-
return self.value.replace(" ", "-").lower()
|
20
|
+
def id(self) -> "ProviderIDEnum":
|
21
|
+
return self.value.replace(" ", "-").lower() # type: ignore[return-value]
|
22
22
|
|
23
23
|
|
24
24
|
ProviderIDEnum = StrEnum("ProviderIDEnum", {p.id: p.id for p in Provider}) # type: ignore[misc]
|
@@ -1,11 +1,5 @@
|
|
1
1
|
from typing import Any, Dict, Protocol, Sequence, TypeVar
|
2
2
|
|
3
|
-
import pydantic
|
4
|
-
|
5
|
-
|
6
|
-
def get_discriminator_field(default: str, **kwargs: Any) -> Any:
|
7
|
-
return pydantic.Field(default_factory=lambda: default, **kwargs)
|
8
|
-
|
9
3
|
|
10
4
|
def values_with_discriminator(
|
11
5
|
values: Dict[str, Any], discriminator: str, discriminator_value: Any
|
@@ -12,7 +12,7 @@ def is_list_unique(lst: List[Hashable]) -> bool:
|
|
12
12
|
def validate_nameables_mapping(
|
13
13
|
nameables_dict: Mapping[str, Nameable], declaration_type: str
|
14
14
|
) -> None:
|
15
|
-
if not all(
|
15
|
+
if not all(name == nameable.name for (name, nameable) in nameables_dict.items()):
|
16
16
|
raise ClassiqValueError(
|
17
17
|
f"{declaration_type} declaration names should match the keys of their names."
|
18
18
|
)
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import pydantic
|
2
2
|
|
3
3
|
from classiq.interface._version import VERSION
|
4
|
+
from classiq.interface.helpers.custom_encoders import CUSTOM_ENCODERS
|
4
5
|
|
5
6
|
|
6
|
-
class VersionedModel(
|
7
|
+
class VersionedModel(
|
8
|
+
pydantic.BaseModel, extra=pydantic.Extra.forbid, json_encoders=CUSTOM_ENCODERS
|
9
|
+
):
|
7
10
|
version: str = pydantic.Field(default=VERSION)
|
classiq/interface/ide/show.py
CHANGED
@@ -4,7 +4,7 @@ import pydantic
|
|
4
4
|
|
5
5
|
from classiq.interface.analyzer.result import QasmCode
|
6
6
|
|
7
|
-
from classiq import
|
7
|
+
from classiq import QuantumProgram
|
8
8
|
from classiq._internals.api_wrapper import ApiWrapper
|
9
9
|
from classiq._internals.async_utils import syncify_function
|
10
10
|
from classiq.exceptions import ClassiqValueError
|
@@ -28,7 +28,7 @@ CANT_PARSE_QUANTUM_PROGRAM_MSG = (
|
|
28
28
|
|
29
29
|
def show(quantum_program: SerializedQuantumProgram) -> None:
|
30
30
|
try:
|
31
|
-
circuit =
|
31
|
+
circuit = QuantumProgram.parse_raw(quantum_program)
|
32
32
|
except pydantic.error_wrappers.ValidationError as exc:
|
33
33
|
raise ClassiqValueError(CANT_PARSE_QUANTUM_PROGRAM_MSG) from exc
|
34
34
|
circuit.show() # type: ignore[attr-defined]
|
classiq/interface/jobs.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
from typing import Any, Dict, Generic, TypeVar, Union
|
1
|
+
from typing import Any, Dict, Generic, Literal, TypeVar, Union
|
2
2
|
|
3
3
|
import pydantic
|
4
|
-
from pydantic import BaseModel
|
4
|
+
from pydantic import BaseModel, Field
|
5
5
|
from pydantic.generics import GenericModel
|
6
6
|
|
7
|
+
from classiq.interface.helpers.custom_encoders import CUSTOM_ENCODERS
|
8
|
+
|
7
9
|
from classiq._internals.enum_utils import StrEnum
|
8
10
|
|
9
11
|
JSONObject = Dict[str, Any]
|
@@ -29,6 +31,73 @@ class JobStatus(StrEnum):
|
|
29
31
|
return self in (self.COMPLETED, self.FAILED, self.CANCELLED)
|
30
32
|
|
31
33
|
|
32
|
-
|
34
|
+
"""
|
35
|
+
A job can be in either of 3 states: ongoing, completed successfully or completed
|
36
|
+
unsuccessfully. Each job status belongs to one of the 3 states
|
37
|
+
The class JobDescriptionBase represents a job description, regardless of its state
|
38
|
+
JobDescriptionSuccess represents a job that was completed successfully. It contains the
|
39
|
+
job result in the description field. The type of the result depends on the route, and
|
40
|
+
so it's defined as a generic class
|
41
|
+
JobDescriptionFailure represents a job that was completed unsuccessfully. It contains
|
42
|
+
the failure details (i.e., error message) in the description field
|
43
|
+
JobDescriptionNonFinal represents a job that has not terminated yet. It does not contain
|
44
|
+
any additional information
|
45
|
+
JobDescriptionUnion is used to define a discriminator field between the 3 states. Since
|
46
|
+
JobDescriptionSuccess is generic, so is the union. This means it cannot be defined
|
47
|
+
as an annotated type alias (that is, we cannot define
|
48
|
+
JobDescriptionUnion = Annotated[Union[...], Field(discriminator="kind")])
|
49
|
+
"""
|
50
|
+
|
51
|
+
SuccessStatus = Literal[JobStatus.COMPLETED]
|
52
|
+
FailureStatus = Union[
|
53
|
+
Literal[JobStatus.FAILED],
|
54
|
+
Literal[JobStatus.CANCELLED],
|
55
|
+
]
|
56
|
+
NonFinalStatus = Union[
|
57
|
+
Literal[JobStatus.QUEUED],
|
58
|
+
Literal[JobStatus.RUNNING],
|
59
|
+
Literal[JobStatus.READY],
|
60
|
+
Literal[JobStatus.CANCELLING],
|
61
|
+
Literal[JobStatus.UNKNOWN],
|
62
|
+
]
|
63
|
+
|
64
|
+
|
65
|
+
class FailureDetails(BaseModel):
|
66
|
+
details: str
|
67
|
+
|
68
|
+
|
69
|
+
class JobDescriptionBase(GenericModel, Generic[T], json_encoders=CUSTOM_ENCODERS):
|
70
|
+
kind: str
|
33
71
|
status: JobStatus
|
72
|
+
description: Union[T, FailureDetails, Dict]
|
73
|
+
|
74
|
+
|
75
|
+
class JobDescriptionSuccess(JobDescriptionBase[T], Generic[T]):
|
76
|
+
kind: Literal["success"] = pydantic.Field(default="success")
|
77
|
+
status: SuccessStatus = Field(default=JobStatus.COMPLETED)
|
34
78
|
description: T
|
79
|
+
|
80
|
+
|
81
|
+
class JobDescriptionFailure(JobDescriptionBase[Any]):
|
82
|
+
kind: Literal["failure"] = pydantic.Field(default="failure")
|
83
|
+
status: FailureStatus
|
84
|
+
description: FailureDetails
|
85
|
+
|
86
|
+
|
87
|
+
class JobDescriptionNonFinal(JobDescriptionBase[Any]):
|
88
|
+
kind: Literal["non_final"] = pydantic.Field(default="non_final")
|
89
|
+
status: NonFinalStatus
|
90
|
+
description: Dict = Field(default_factory=dict)
|
91
|
+
|
92
|
+
@pydantic.validator("description")
|
93
|
+
def validate_empty_description(cls, description: Dict) -> Dict:
|
94
|
+
if description:
|
95
|
+
raise ValueError("Non-final job description must be empty")
|
96
|
+
|
97
|
+
return description
|
98
|
+
|
99
|
+
|
100
|
+
class JobDescriptionUnion(GenericModel, Generic[T], json_encoders=CUSTOM_ENCODERS):
|
101
|
+
__root__: Union[
|
102
|
+
JobDescriptionSuccess[T], JobDescriptionFailure, JobDescriptionNonFinal
|
103
|
+
] = Field(discriminator="kind")
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Mapping
|
1
|
+
from typing import List, Mapping
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
@@ -12,19 +12,26 @@ BIND_OUTPUT_NAME = "bind_output"
|
|
12
12
|
|
13
13
|
|
14
14
|
class BindOperation(QuantumOperation):
|
15
|
-
|
16
|
-
|
15
|
+
in_handles: List[HandleBinding]
|
16
|
+
out_handles: List[HandleBinding]
|
17
17
|
|
18
18
|
@property
|
19
19
|
def wiring_inputs(self) -> Mapping[str, HandleBinding]:
|
20
|
-
return {
|
20
|
+
return {
|
21
|
+
f"{BIND_INPUT_NAME}_{i}": handle for i, handle in enumerate(self.in_handles)
|
22
|
+
}
|
21
23
|
|
22
24
|
@property
|
23
25
|
def wiring_outputs(self) -> Mapping[str, HandleBinding]:
|
24
|
-
return {
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
return {
|
27
|
+
f"{BIND_OUTPUT_NAME}_{i}": handle
|
28
|
+
for i, handle in enumerate(self.out_handles)
|
29
|
+
}
|
30
|
+
|
31
|
+
@pydantic.validator("in_handles", "out_handles")
|
32
|
+
def validate_handle(cls, handles: List[HandleBinding]) -> List[HandleBinding]:
|
33
|
+
for handle in handles:
|
34
|
+
if not handle.is_bindable():
|
35
|
+
raise ClassiqValueError(f"Cannot bind '{handle}'")
|
36
|
+
|
37
|
+
return handles
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import dataclasses
|
2
|
+
from typing import Any, Iterator, List, Mapping
|
3
|
+
|
4
|
+
from sympy import sympify
|
5
|
+
|
6
|
+
from classiq.interface.generator.control_state import ControlState
|
7
|
+
from classiq.interface.generator.synthesis_execution_parameter import PydanticPowerType
|
8
|
+
|
9
|
+
from classiq.exceptions import ClassiqValueError
|
10
|
+
|
11
|
+
ILLEGAL_NESTED_POWER_ERROR = "Nested power calls with a parametric power and an integer power are unsupported: {a}, {b}"
|
12
|
+
|
13
|
+
|
14
|
+
def _merge_power(a: PydanticPowerType, b: PydanticPowerType) -> PydanticPowerType:
|
15
|
+
symbolic_res = sympify(a) * sympify(b)
|
16
|
+
if symbolic_res.is_Integer:
|
17
|
+
return int(symbolic_res)
|
18
|
+
elif symbolic_res.is_symbol:
|
19
|
+
return str(symbolic_res)
|
20
|
+
else:
|
21
|
+
raise ClassiqValueError(ILLEGAL_NESTED_POWER_ERROR.format(a=a, b=b))
|
22
|
+
|
23
|
+
|
24
|
+
@dataclasses.dataclass
|
25
|
+
class CallSynthesisData(Mapping):
|
26
|
+
power: PydanticPowerType = 1
|
27
|
+
is_inverse: bool = False
|
28
|
+
control_states: List[ControlState] = dataclasses.field(default_factory=list)
|
29
|
+
should_control: bool = True
|
30
|
+
|
31
|
+
def merge(self, other: "CallSynthesisData") -> "CallSynthesisData":
|
32
|
+
return CallSynthesisData(
|
33
|
+
power=_merge_power(self.power, other.power),
|
34
|
+
is_inverse=self.is_inverse != other.is_inverse,
|
35
|
+
control_states=self.control_states + other.control_states,
|
36
|
+
should_control=self.should_control and other.should_control,
|
37
|
+
)
|
38
|
+
|
39
|
+
def set_control(self, ctrl_name: str, ctrl_size: int) -> None:
|
40
|
+
self.control_states = [
|
41
|
+
ControlState(
|
42
|
+
name=ctrl_name,
|
43
|
+
num_ctrl_qubits=ctrl_size,
|
44
|
+
)
|
45
|
+
]
|
46
|
+
|
47
|
+
def update_control_state(self, ctrl_size: int, ctrl_state: str) -> None:
|
48
|
+
prev_ctrl_state = self.control_states.pop()
|
49
|
+
self.control_states.append(
|
50
|
+
ControlState(
|
51
|
+
name=prev_ctrl_state.name,
|
52
|
+
num_ctrl_qubits=ctrl_size,
|
53
|
+
ctrl_state=ctrl_state,
|
54
|
+
)
|
55
|
+
)
|
56
|
+
|
57
|
+
@property
|
58
|
+
def has_control(self) -> bool:
|
59
|
+
return bool(self.control_states)
|
60
|
+
|
61
|
+
def __getitem__(self, key: str) -> Any:
|
62
|
+
return dataclasses.asdict(self)[key]
|
63
|
+
|
64
|
+
def __iter__(self) -> Iterator[str]:
|
65
|
+
return iter(dataclasses.asdict(self))
|
66
|
+
|
67
|
+
def __len__(self) -> int:
|
68
|
+
return len(dataclasses.asdict(self))
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from classiq.interface.generator.expressions.expression import Expression
|
4
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
5
|
+
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from classiq.interface.model.statement_block import StatementBlock
|
8
|
+
|
9
|
+
|
10
|
+
class ClassicalIf(QuantumOperation):
|
11
|
+
condition: Expression
|
12
|
+
then: "StatementBlock"
|
13
|
+
else_: "StatementBlock"
|
@@ -1,8 +1,7 @@
|
|
1
|
-
import
|
2
|
-
|
1
|
+
from classiq.interface.ast_node import ASTNode
|
3
2
|
from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
|
4
3
|
|
5
4
|
|
6
|
-
class ClassicalParameterDeclaration(
|
5
|
+
class ClassicalParameterDeclaration(ASTNode):
|
7
6
|
name: str
|
8
7
|
classical_type: ConcreteClassicalType
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Union
|
2
|
+
|
3
|
+
from classiq.interface.model.handle_binding import (
|
4
|
+
HandleBinding,
|
5
|
+
SlicedHandleBinding,
|
6
|
+
SubscriptHandleBinding,
|
7
|
+
)
|
8
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from classiq.interface.model.statement_block import StatementBlock
|
12
|
+
|
13
|
+
|
14
|
+
class Control(QuantumOperation):
|
15
|
+
control: Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
|
16
|
+
body: "StatementBlock"
|
@@ -1,9 +1,10 @@
|
|
1
|
-
from pydantic import
|
1
|
+
from pydantic import Extra
|
2
2
|
|
3
|
+
from classiq.interface.ast_node import ASTNode
|
3
4
|
from classiq.interface.generator.expressions.expression import Expression
|
4
5
|
|
5
6
|
|
6
|
-
class HandleBinding(
|
7
|
+
class HandleBinding(ASTNode):
|
7
8
|
name: str
|
8
9
|
|
9
10
|
class Config:
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from classiq.interface.model.statement_block import StatementBlock
|
7
|
+
|
8
|
+
|
9
|
+
class Invert(QuantumOperation):
|
10
|
+
body: "StatementBlock"
|
classiq/interface/model/model.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
from
|
1
|
+
from collections import Counter
|
2
|
+
from typing import Any, Dict, List, Literal, NewType, Optional, Set
|
2
3
|
|
3
4
|
import pydantic
|
4
5
|
|
6
|
+
from classiq.interface.ast_node import ASTNode
|
5
7
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
6
8
|
from classiq.interface.generator.constant import Constant
|
7
9
|
from classiq.interface.generator.functions.port_declaration import (
|
@@ -10,23 +12,17 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
10
12
|
from classiq.interface.generator.model.constraints import Constraints
|
11
13
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
12
14
|
from classiq.interface.generator.quantum_function_call import SUFFIX_RANDOMIZER
|
13
|
-
from classiq.interface.generator.types.combinatorial_problem import (
|
14
|
-
CombinatorialOptimizationStructDeclaration,
|
15
|
-
)
|
16
15
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
17
|
-
from classiq.interface.helpers.pydantic_model_helpers import
|
18
|
-
get_discriminator_field,
|
19
|
-
nameables_to_dict,
|
20
|
-
)
|
16
|
+
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
21
17
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
22
18
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
23
|
-
from classiq.interface.model.quantum_function_call import ConcreteQuantumStatement
|
24
19
|
from classiq.interface.model.quantum_function_declaration import (
|
25
20
|
QuantumFunctionDeclaration,
|
26
21
|
)
|
27
22
|
from classiq.interface.model.resolvers.function_call_resolver import (
|
28
23
|
resolve_function_calls,
|
29
24
|
)
|
25
|
+
from classiq.interface.model.statement_block import StatementBlock
|
30
26
|
|
31
27
|
from classiq.exceptions import ClassiqValueError
|
32
28
|
|
@@ -39,10 +35,6 @@ DEFAULT_PORT_SIZE = 1
|
|
39
35
|
|
40
36
|
SerializedModel = NewType("SerializedModel", str)
|
41
37
|
|
42
|
-
ConcreteStructDeclaration = Union[
|
43
|
-
CombinatorialOptimizationStructDeclaration, StructDeclaration
|
44
|
-
]
|
45
|
-
|
46
38
|
TYPE_NAME_CONFLICT_BUILTIN = (
|
47
39
|
"Type '{name}' conflicts with a builtin type with the same name"
|
48
40
|
)
|
@@ -60,12 +52,12 @@ class VersionedSerializedModel(VersionedModel):
|
|
60
52
|
model: SerializedModel
|
61
53
|
|
62
54
|
|
63
|
-
class Model(VersionedModel):
|
55
|
+
class Model(VersionedModel, ASTNode):
|
64
56
|
"""
|
65
57
|
All the relevant data for generating quantum circuit in one place.
|
66
58
|
"""
|
67
59
|
|
68
|
-
kind: Literal["user"] =
|
60
|
+
kind: Literal["user"] = pydantic.Field(default=USER_MODEL_MARKER)
|
69
61
|
|
70
62
|
# Must be validated before logic_flow
|
71
63
|
functions: List[NativeFunctionDefinition] = pydantic.Field(
|
@@ -73,7 +65,7 @@ class Model(VersionedModel):
|
|
73
65
|
description="The user-defined custom type library.",
|
74
66
|
)
|
75
67
|
|
76
|
-
types: List[
|
68
|
+
types: List[StructDeclaration] = pydantic.Field(
|
77
69
|
default_factory=list,
|
78
70
|
description="The user-defined custom function library.",
|
79
71
|
)
|
@@ -98,7 +90,7 @@ class Model(VersionedModel):
|
|
98
90
|
return self.function_dict[MAIN_FUNCTION_NAME] # type:ignore[return-value]
|
99
91
|
|
100
92
|
@property
|
101
|
-
def body(self) ->
|
93
|
+
def body(self) -> StatementBlock:
|
102
94
|
return self.main_func.body
|
103
95
|
|
104
96
|
@pydantic.validator("preferences", always=True)
|
@@ -142,15 +134,15 @@ class Model(VersionedModel):
|
|
142
134
|
return values
|
143
135
|
|
144
136
|
@pydantic.validator("types")
|
145
|
-
def types_validator(
|
146
|
-
cls, types: List[ConcreteStructDeclaration]
|
147
|
-
) -> List[ConcreteStructDeclaration]:
|
137
|
+
def types_validator(cls, types: List[StructDeclaration]) -> List[StructDeclaration]:
|
148
138
|
user_defined_types: Set[str] = set()
|
149
139
|
for ctype in types:
|
150
140
|
if ctype.name in StructDeclaration.BUILTIN_STRUCT_DECLARATIONS:
|
151
|
-
raise
|
141
|
+
raise ClassiqValueError(
|
142
|
+
TYPE_NAME_CONFLICT_BUILTIN.format(name=ctype.name)
|
143
|
+
)
|
152
144
|
if ctype.name in user_defined_types:
|
153
|
-
raise
|
145
|
+
raise ClassiqValueError(TYPE_NAME_CONFLICT_USER.format(name=ctype.name))
|
154
146
|
user_defined_types.add(ctype.name)
|
155
147
|
|
156
148
|
return types
|
@@ -174,3 +166,18 @@ class Model(VersionedModel):
|
|
174
166
|
raise ClassiqValueError("Function 'main' cannot declare quantum inputs")
|
175
167
|
|
176
168
|
return functions
|
169
|
+
|
170
|
+
@pydantic.validator("constants")
|
171
|
+
def _validate_constants(cls, constants: List[Constant]) -> List[Constant]:
|
172
|
+
constant_definition_counts = Counter(
|
173
|
+
[constant.name for constant in constants]
|
174
|
+
).items()
|
175
|
+
multiply_defined_constants = {
|
176
|
+
constant for constant, count in constant_definition_counts if count > 1
|
177
|
+
}
|
178
|
+
if len(multiply_defined_constants) > 0:
|
179
|
+
raise ClassiqValueError(
|
180
|
+
f"The following constants were defined more than once: "
|
181
|
+
f"{multiply_defined_constants}"
|
182
|
+
)
|
183
|
+
return constants
|