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,9 +1,8 @@
|
|
1
|
-
from typing import Hashable, List, Mapping
|
1
|
+
from typing import Hashable, List, Mapping
|
2
2
|
|
3
|
+
from classiq.interface.exceptions import ClassiqValueError
|
3
4
|
from classiq.interface.helpers.pydantic_model_helpers import Nameable
|
4
5
|
|
5
|
-
from classiq.exceptions import ClassiqValueError
|
6
|
-
|
7
6
|
|
8
7
|
def is_list_unique(lst: List[Hashable]) -> bool:
|
9
8
|
return len(set(lst)) == len(lst)
|
@@ -16,19 +15,3 @@ def validate_nameables_mapping(
|
|
16
15
|
raise ClassiqValueError(
|
17
16
|
f"{declaration_type} declaration names should match the keys of their names."
|
18
17
|
)
|
19
|
-
|
20
|
-
|
21
|
-
def validate_nameables_no_overlap(
|
22
|
-
left_nameables_dict: Optional[Mapping[str, Nameable]],
|
23
|
-
right_nameables_dict: Optional[Mapping[str, Nameable]],
|
24
|
-
left_declaration_type: str,
|
25
|
-
right_declaration_type: str,
|
26
|
-
) -> Optional[str]:
|
27
|
-
if left_nameables_dict is None or right_nameables_dict is None:
|
28
|
-
return None
|
29
|
-
|
30
|
-
matched_names = left_nameables_dict.keys() & right_nameables_dict.keys()
|
31
|
-
if matched_names:
|
32
|
-
return f"{left_declaration_type} declaration names overlap with {right_declaration_type} declaration names: {matched_names}"
|
33
|
-
|
34
|
-
return None
|
@@ -2,15 +2,15 @@ from typing import Dict, List, Optional, Tuple
|
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
+
from classiq.interface.enum_utils import StrEnum
|
5
6
|
from classiq.interface.generator.hardware.hardware_data import SynthesisHardwareData
|
6
7
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
7
8
|
|
8
|
-
from classiq._internals.enum_utils import StrEnum
|
9
|
-
|
10
9
|
|
11
10
|
class OperationLevel(StrEnum):
|
12
|
-
|
13
|
-
|
11
|
+
QMOD_FUNCTION_CALL = "QMOD_CALL"
|
12
|
+
QMOD_STATEMENT = "QMOD_STATEMENT"
|
13
|
+
ENGINE_FUNCTION_CALL = "ENGINE_CALL"
|
14
14
|
BASIS_GATE = "BASIS_GATE"
|
15
15
|
UNKNOWN = "UNKNOWN"
|
16
16
|
|
@@ -41,6 +41,12 @@ class OperationLink(pydantic.BaseModel):
|
|
41
41
|
qubits: Tuple[int, ...]
|
42
42
|
type: str
|
43
43
|
|
44
|
+
class Config:
|
45
|
+
allow_mutation = False
|
46
|
+
|
47
|
+
def __hash__(self) -> int:
|
48
|
+
return hash((type(self), self.label, self.qubits, self.type))
|
49
|
+
|
44
50
|
|
45
51
|
class OperationLinks(pydantic.BaseModel):
|
46
52
|
inputs: List[OperationLink]
|
@@ -0,0 +1 @@
|
|
1
|
+
INTERFACE_VERSION = "2"
|
classiq/interface/jobs.py
CHANGED
@@ -4,11 +4,10 @@ import pydantic
|
|
4
4
|
from pydantic import BaseModel
|
5
5
|
from pydantic.generics import GenericModel
|
6
6
|
|
7
|
+
from classiq.interface.enum_utils import StrEnum
|
8
|
+
from classiq.interface.exceptions import ClassiqAPIError
|
7
9
|
from classiq.interface.helpers.custom_encoders import CUSTOM_ENCODERS
|
8
10
|
|
9
|
-
from classiq._internals.enum_utils import StrEnum
|
10
|
-
from classiq.exceptions import ClassiqAPIError
|
11
|
-
|
12
11
|
JSONObject = Dict[str, Any]
|
13
12
|
T = TypeVar("T", bound=Union[pydantic.BaseModel, JSONObject])
|
14
13
|
AUTH_HEADER = "Classiq-BE-Auth"
|
@@ -1,11 +1,10 @@
|
|
1
|
-
from typing import List, Literal, Mapping
|
1
|
+
from typing import List, Literal, Mapping, Sequence
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
-
from classiq.interface.
|
6
|
-
from classiq.interface.model.
|
7
|
-
|
8
|
-
from classiq.exceptions import ClassiqValueError
|
5
|
+
from classiq.interface.exceptions import ClassiqValueError
|
6
|
+
from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
|
7
|
+
from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
|
9
8
|
|
10
9
|
BIND_INPUT_NAME = "bind_input"
|
11
10
|
BIND_OUTPUT_NAME = "bind_output"
|
@@ -14,8 +13,8 @@ BIND_OUTPUT_NAME = "bind_output"
|
|
14
13
|
class BindOperation(QuantumOperation):
|
15
14
|
kind: Literal["BindOperation"]
|
16
15
|
|
17
|
-
in_handles: List[
|
18
|
-
out_handles: List[
|
16
|
+
in_handles: List[ConcreteHandleBinding]
|
17
|
+
out_handles: List[ConcreteHandleBinding]
|
19
18
|
|
20
19
|
@property
|
21
20
|
def wiring_inputs(self) -> Mapping[str, HandleBinding]:
|
@@ -23,6 +22,16 @@ class BindOperation(QuantumOperation):
|
|
23
22
|
f"{BIND_INPUT_NAME}_{i}": handle for i, handle in enumerate(self.in_handles)
|
24
23
|
}
|
25
24
|
|
25
|
+
@property
|
26
|
+
def readable_inputs(self) -> Sequence[HandleMetadata]:
|
27
|
+
return [
|
28
|
+
HandleMetadata(
|
29
|
+
handle=handle,
|
30
|
+
readable_location="on the left-hand side of a bind statement",
|
31
|
+
)
|
32
|
+
for handle in self.in_handles
|
33
|
+
]
|
34
|
+
|
26
35
|
@property
|
27
36
|
def wiring_outputs(self) -> Mapping[str, HandleBinding]:
|
28
37
|
return {
|
@@ -30,6 +39,16 @@ class BindOperation(QuantumOperation):
|
|
30
39
|
for i, handle in enumerate(self.out_handles)
|
31
40
|
}
|
32
41
|
|
42
|
+
@property
|
43
|
+
def readable_outputs(self) -> Sequence[HandleMetadata]:
|
44
|
+
return [
|
45
|
+
HandleMetadata(
|
46
|
+
handle=handle,
|
47
|
+
readable_location="on the right-hand side of a bind statement",
|
48
|
+
)
|
49
|
+
for handle in self.out_handles
|
50
|
+
]
|
51
|
+
|
33
52
|
@pydantic.validator("in_handles", "out_handles")
|
34
53
|
def validate_handle(cls, handles: List[HandleBinding]) -> List[HandleBinding]:
|
35
54
|
for handle in handles:
|
@@ -2,15 +2,14 @@ from typing import Any, Dict, Literal
|
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
-
from classiq.interface.
|
6
|
-
from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
|
5
|
+
from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
|
7
6
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
7
|
+
from classiq.interface.model.parameter import Parameter
|
8
8
|
|
9
9
|
|
10
|
-
class
|
10
|
+
class AnonClassicalParameterDeclaration(Parameter):
|
11
11
|
kind: Literal["ClassicalParameterDeclaration"]
|
12
12
|
|
13
|
-
name: str
|
14
13
|
classical_type: ConcreteClassicalType
|
15
14
|
|
16
15
|
@pydantic.root_validator(pre=True)
|
@@ -20,4 +19,8 @@ class ClassicalParameterDeclaration(ASTNode):
|
|
20
19
|
)
|
21
20
|
|
22
21
|
def rename(self, new_name: str) -> "ClassicalParameterDeclaration":
|
23
|
-
return self.
|
22
|
+
return ClassicalParameterDeclaration(**{**self.__dict__, "name": new_name})
|
23
|
+
|
24
|
+
|
25
|
+
class ClassicalParameterDeclaration(AnonClassicalParameterDeclaration):
|
26
|
+
name: str
|
@@ -14,11 +14,11 @@ class Control(QuantumExpressionOperation):
|
|
14
14
|
kind: Literal["Control"]
|
15
15
|
body: "StatementBlock"
|
16
16
|
|
17
|
-
|
17
|
+
_ctrl_size: int = pydantic.PrivateAttr(default=0)
|
18
18
|
|
19
19
|
@property
|
20
|
-
def
|
21
|
-
return self.
|
20
|
+
def ctrl_size(self) -> int:
|
21
|
+
return self._ctrl_size
|
22
22
|
|
23
|
-
def
|
24
|
-
self.
|
23
|
+
def set_ctrl_size(self, ctrl_size: int) -> None:
|
24
|
+
self._ctrl_size = ctrl_size
|
@@ -1,13 +1,17 @@
|
|
1
|
-
from
|
1
|
+
from itertools import chain
|
2
|
+
from typing import TYPE_CHECKING, Any, Dict, Sequence, Union
|
2
3
|
|
3
|
-
|
4
|
+
import pydantic
|
5
|
+
from pydantic import Extra, Field
|
4
6
|
|
5
7
|
from classiq.interface.ast_node import ASTNode
|
6
8
|
from classiq.interface.generator.expressions.expression import Expression
|
7
9
|
|
10
|
+
HANDLE_ID_SEPARATOR = "___"
|
11
|
+
|
8
12
|
|
9
13
|
class HandleBinding(ASTNode):
|
10
|
-
name: str
|
14
|
+
name: str = Field(default=None)
|
11
15
|
|
12
16
|
class Config:
|
13
17
|
frozen = True
|
@@ -19,8 +23,49 @@ class HandleBinding(ASTNode):
|
|
19
23
|
def is_bindable(self) -> bool:
|
20
24
|
return True
|
21
25
|
|
26
|
+
@property
|
27
|
+
def identifier(self) -> str:
|
28
|
+
return self.name
|
29
|
+
|
30
|
+
def collapse(self) -> "HandleBinding":
|
31
|
+
return self
|
32
|
+
|
33
|
+
def prefixes(self) -> Sequence["HandleBinding"]:
|
34
|
+
"""
|
35
|
+
Split the handle into prefixes:
|
36
|
+
a.b[0].c --> [a, a.b, a.b[0], a.b[0].c]
|
37
|
+
"""
|
38
|
+
return [self]
|
39
|
+
|
40
|
+
def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
|
41
|
+
return self.name == other_handle.name
|
42
|
+
|
43
|
+
def overlaps(self, other_handle: "HandleBinding") -> bool:
|
44
|
+
self_prefixes = self.collapse().prefixes()
|
45
|
+
other_prefixes = other_handle.collapse().prefixes()
|
46
|
+
return all(
|
47
|
+
self_prefix._tail_overlaps(other_prefix)
|
48
|
+
for self_prefix, other_prefix in zip(self_prefixes, other_prefixes)
|
49
|
+
)
|
50
|
+
|
51
|
+
|
52
|
+
class NestedHandleBinding(HandleBinding):
|
53
|
+
base_handle: "ConcreteHandleBinding"
|
54
|
+
|
55
|
+
@pydantic.root_validator(pre=False)
|
56
|
+
def _set_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
57
|
+
if "base_handle" in values:
|
58
|
+
values["name"] = values["base_handle"].name
|
59
|
+
return values
|
60
|
+
|
61
|
+
def is_bindable(self) -> bool:
|
62
|
+
return False
|
63
|
+
|
64
|
+
def prefixes(self) -> Sequence["HandleBinding"]:
|
65
|
+
return list(chain.from_iterable([self.base_handle.prefixes(), [self]]))
|
66
|
+
|
22
67
|
|
23
|
-
class SubscriptHandleBinding(
|
68
|
+
class SubscriptHandleBinding(NestedHandleBinding):
|
24
69
|
index: Expression
|
25
70
|
|
26
71
|
class Config:
|
@@ -28,13 +73,52 @@ class SubscriptHandleBinding(HandleBinding):
|
|
28
73
|
extra = Extra.forbid
|
29
74
|
|
30
75
|
def __str__(self) -> str:
|
31
|
-
return f"{self.
|
32
|
-
|
33
|
-
|
76
|
+
return f"{self.base_handle}[{self.index}]"
|
77
|
+
|
78
|
+
@property
|
79
|
+
def identifier(self) -> str:
|
80
|
+
return f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}{self.index}"
|
81
|
+
|
82
|
+
def collapse(self) -> HandleBinding:
|
83
|
+
if isinstance(self.base_handle, SlicedHandleBinding):
|
84
|
+
return SubscriptHandleBinding(
|
85
|
+
base_handle=self.base_handle.base_handle,
|
86
|
+
index=self._get_collapsed_index(),
|
87
|
+
).collapse()
|
88
|
+
return SubscriptHandleBinding(
|
89
|
+
base_handle=self.base_handle.collapse(),
|
90
|
+
index=self.index,
|
91
|
+
)
|
92
|
+
|
93
|
+
def _get_collapsed_index(self) -> Expression:
|
94
|
+
if TYPE_CHECKING:
|
95
|
+
assert isinstance(self.base_handle, SlicedHandleBinding)
|
96
|
+
if self.index.is_evaluated() and self.base_handle.start.is_evaluated():
|
97
|
+
return Expression(
|
98
|
+
expr=str(
|
99
|
+
self.base_handle.start.to_int_value() + self.index.to_int_value()
|
100
|
+
)
|
101
|
+
)
|
102
|
+
return Expression(expr=f"({self.base_handle.start})+({self.index})")
|
103
|
+
|
104
|
+
def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
|
105
|
+
if isinstance(other_handle, SubscriptHandleBinding):
|
106
|
+
return self.index == other_handle.index
|
107
|
+
if (
|
108
|
+
isinstance(other_handle, SlicedHandleBinding)
|
109
|
+
and self.index.is_evaluated()
|
110
|
+
and other_handle.start.is_evaluated()
|
111
|
+
and other_handle.end.is_evaluated()
|
112
|
+
):
|
113
|
+
return (
|
114
|
+
other_handle.start.to_int_value()
|
115
|
+
<= self.index.to_int_value()
|
116
|
+
< other_handle.end.to_int_value()
|
117
|
+
)
|
34
118
|
return False
|
35
119
|
|
36
120
|
|
37
|
-
class SlicedHandleBinding(
|
121
|
+
class SlicedHandleBinding(NestedHandleBinding):
|
38
122
|
start: Expression
|
39
123
|
end: Expression
|
40
124
|
|
@@ -43,12 +127,101 @@ class SlicedHandleBinding(HandleBinding):
|
|
43
127
|
extra = Extra.forbid
|
44
128
|
|
45
129
|
def __str__(self) -> str:
|
46
|
-
return f"{self.
|
47
|
-
|
48
|
-
|
130
|
+
return f"{self.base_handle}[{self.start}:{self.end}]"
|
131
|
+
|
132
|
+
@property
|
133
|
+
def identifier(self) -> str:
|
134
|
+
return (
|
135
|
+
f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}{self.start}_{self.end}"
|
136
|
+
)
|
137
|
+
|
138
|
+
def collapse(self) -> HandleBinding:
|
139
|
+
if isinstance(self.base_handle, SlicedHandleBinding):
|
140
|
+
return SubscriptHandleBinding(
|
141
|
+
base_handle=self.base_handle.base_handle,
|
142
|
+
start=self._get_collapsed_start(),
|
143
|
+
end=self._get_collapsed_stop(),
|
144
|
+
).collapse()
|
145
|
+
return SlicedHandleBinding(
|
146
|
+
base_handle=self.base_handle.collapse(),
|
147
|
+
start=self.start,
|
148
|
+
end=self.end,
|
149
|
+
)
|
150
|
+
|
151
|
+
def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
|
152
|
+
if not self.start.is_evaluated() or not self.end.is_evaluated():
|
153
|
+
return False
|
154
|
+
start = self.start.to_int_value()
|
155
|
+
end = self.end.to_int_value()
|
156
|
+
if (
|
157
|
+
isinstance(other_handle, SubscriptHandleBinding)
|
158
|
+
and other_handle.index.is_evaluated()
|
159
|
+
):
|
160
|
+
return start <= other_handle.index.to_int_value() < end
|
161
|
+
if (
|
162
|
+
isinstance(other_handle, SlicedHandleBinding)
|
163
|
+
and other_handle.start.is_evaluated()
|
164
|
+
and other_handle.end.is_evaluated()
|
165
|
+
):
|
166
|
+
other_start = other_handle.start.to_int_value()
|
167
|
+
other_end = other_handle.end.to_int_value()
|
168
|
+
return start <= other_start < end or other_start <= start < other_end
|
49
169
|
return False
|
50
170
|
|
171
|
+
def _get_collapsed_start(self) -> Expression:
|
172
|
+
if TYPE_CHECKING:
|
173
|
+
assert isinstance(self.base_handle, SlicedHandleBinding)
|
174
|
+
if self.start.is_evaluated() and self.base_handle.start.is_evaluated():
|
175
|
+
return Expression(
|
176
|
+
expr=str(
|
177
|
+
self.base_handle.start.to_int_value() + self.start.to_int_value()
|
178
|
+
)
|
179
|
+
)
|
180
|
+
return Expression(expr=f"({self.base_handle.start})+({self.start})")
|
181
|
+
|
182
|
+
def _get_collapsed_stop(self) -> Expression:
|
183
|
+
if TYPE_CHECKING:
|
184
|
+
assert isinstance(self.base_handle, SlicedHandleBinding)
|
185
|
+
if self.end.is_evaluated() and self.base_handle.end.is_evaluated():
|
186
|
+
return Expression(
|
187
|
+
expr=str(self.base_handle.end.to_int_value() - self.end.to_int_value())
|
188
|
+
)
|
189
|
+
return Expression(expr=f"({self.base_handle.end})-({self.end})")
|
190
|
+
|
191
|
+
|
192
|
+
class FieldHandleBinding(NestedHandleBinding):
|
193
|
+
field: str
|
194
|
+
|
195
|
+
class Config:
|
196
|
+
frozen = True
|
197
|
+
extra = Extra.forbid
|
198
|
+
|
199
|
+
def __str__(self) -> str:
|
200
|
+
return f"{self.base_handle}.{self.field}"
|
201
|
+
|
202
|
+
@property
|
203
|
+
def identifier(self) -> str:
|
204
|
+
return f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}{self.field}"
|
205
|
+
|
206
|
+
def collapse(self) -> HandleBinding:
|
207
|
+
return FieldHandleBinding(
|
208
|
+
base_handle=self.base_handle.collapse(),
|
209
|
+
field=self.field,
|
210
|
+
)
|
211
|
+
|
212
|
+
def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
|
213
|
+
return (
|
214
|
+
isinstance(other_handle, FieldHandleBinding)
|
215
|
+
and self.field == other_handle.field
|
216
|
+
)
|
217
|
+
|
51
218
|
|
52
219
|
ConcreteHandleBinding = Union[
|
53
|
-
HandleBinding,
|
220
|
+
HandleBinding,
|
221
|
+
SubscriptHandleBinding,
|
222
|
+
SlicedHandleBinding,
|
223
|
+
FieldHandleBinding,
|
54
224
|
]
|
225
|
+
SubscriptHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
|
226
|
+
SlicedHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
|
227
|
+
FieldHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
|
@@ -1,5 +1,6 @@
|
|
1
|
-
from typing import Literal, Mapping
|
1
|
+
from typing import Literal, Mapping, Sequence
|
2
2
|
|
3
|
+
from classiq.interface.enum_utils import StrEnum
|
3
4
|
from classiq.interface.generator.functions.builtins.core_library import (
|
4
5
|
INTEGER_XOR_FUNCTION,
|
5
6
|
MODULAR_ADD_FUNCTION,
|
@@ -7,11 +8,9 @@ from classiq.interface.generator.functions.builtins.core_library import (
|
|
7
8
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
8
9
|
from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
|
9
10
|
from classiq.interface.model.quantum_function_declaration import (
|
10
|
-
|
11
|
+
NamedParamsQuantumFunctionDeclaration,
|
11
12
|
)
|
12
|
-
from classiq.interface.model.quantum_statement import QuantumOperation
|
13
|
-
|
14
|
-
from classiq._internals.enum_utils import StrEnum
|
13
|
+
from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
|
15
14
|
|
16
15
|
|
17
16
|
class BinaryOperation(StrEnum):
|
@@ -19,7 +18,7 @@ class BinaryOperation(StrEnum):
|
|
19
18
|
Xor = "inplace_xor"
|
20
19
|
|
21
20
|
@property
|
22
|
-
def internal_function_declaration(self) ->
|
21
|
+
def internal_function_declaration(self) -> NamedParamsQuantumFunctionDeclaration:
|
23
22
|
return {
|
24
23
|
BinaryOperation.Addition: MODULAR_ADD_FUNCTION,
|
25
24
|
BinaryOperation.Xor: INTEGER_XOR_FUNCTION,
|
@@ -36,3 +35,15 @@ class InplaceBinaryOperation(QuantumOperation):
|
|
36
35
|
@property
|
37
36
|
def wiring_inouts(self) -> Mapping[str, HandleBinding]:
|
38
37
|
return nameables_to_dict([self.target, self.value])
|
38
|
+
|
39
|
+
@property
|
40
|
+
def readable_inouts(self) -> Sequence[HandleMetadata]:
|
41
|
+
suffix = f" of an in-place {self.operation.name.lower()} statement"
|
42
|
+
return [
|
43
|
+
HandleMetadata(
|
44
|
+
handle=self.target, readable_location=f"as the target{suffix}"
|
45
|
+
),
|
46
|
+
HandleMetadata(
|
47
|
+
handle=self.value, readable_location=f"as the value{suffix}"
|
48
|
+
),
|
49
|
+
]
|
classiq/interface/model/model.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
from collections import Counter
|
2
|
-
from typing import
|
2
|
+
from typing import List, Literal, Mapping, NewType, Set
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
|
6
6
|
from classiq.interface.ast_node import ASTNode
|
7
|
+
from classiq.interface.debug_info.debug_info import DebugInfoCollection
|
8
|
+
from classiq.interface.exceptions import ClassiqValueError
|
7
9
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
8
10
|
from classiq.interface.generator.constant import Constant
|
9
11
|
from classiq.interface.generator.functions.port_declaration import (
|
@@ -13,17 +15,18 @@ from classiq.interface.generator.model.constraints import Constraints
|
|
13
15
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
14
16
|
from classiq.interface.generator.quantum_function_call import SUFFIX_RANDOMIZER
|
15
17
|
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
18
|
+
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
16
19
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
17
20
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
18
21
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
19
|
-
from classiq.interface.model.native_function_definition import
|
22
|
+
from classiq.interface.model.native_function_definition import (
|
23
|
+
NativeFunctionDefinition,
|
24
|
+
)
|
20
25
|
from classiq.interface.model.quantum_function_declaration import (
|
21
|
-
|
26
|
+
NamedParamsQuantumFunctionDeclaration,
|
22
27
|
)
|
23
28
|
from classiq.interface.model.statement_block import StatementBlock
|
24
29
|
|
25
|
-
from classiq.exceptions import ClassiqValueError
|
26
|
-
|
27
30
|
USER_MODEL_MARKER = "user"
|
28
31
|
|
29
32
|
MAIN_FUNCTION_NAME = "main"
|
@@ -73,6 +76,11 @@ class Model(VersionedModel, ASTNode):
|
|
73
76
|
description="user-defined structs",
|
74
77
|
)
|
75
78
|
|
79
|
+
qstructs: List[QStructDeclaration] = pydantic.Field(
|
80
|
+
default_factory=list,
|
81
|
+
description="user-defined quantum structs",
|
82
|
+
)
|
83
|
+
|
76
84
|
classical_execution_code: str = pydantic.Field(
|
77
85
|
description="The classical execution code of the model", default=""
|
78
86
|
)
|
@@ -88,6 +96,10 @@ class Model(VersionedModel, ASTNode):
|
|
88
96
|
)
|
89
97
|
preferences: Preferences = pydantic.Field(default_factory=Preferences)
|
90
98
|
|
99
|
+
debug_info: DebugInfoCollection = pydantic.Field(
|
100
|
+
default_factory=DebugInfoCollection
|
101
|
+
)
|
102
|
+
|
91
103
|
@property
|
92
104
|
def main_func(self) -> NativeFunctionDefinition:
|
93
105
|
return self.function_dict[MAIN_FUNCTION_NAME] # type:ignore[return-value]
|
@@ -109,7 +121,7 @@ class Model(VersionedModel, ASTNode):
|
|
109
121
|
return direction
|
110
122
|
|
111
123
|
@property
|
112
|
-
def function_dict(self) ->
|
124
|
+
def function_dict(self) -> Mapping[str, NamedParamsQuantumFunctionDeclaration]:
|
113
125
|
return nameables_to_dict(self.functions)
|
114
126
|
|
115
127
|
@pydantic.validator("functions", always=True)
|
@@ -149,7 +161,7 @@ class Model(VersionedModel, ASTNode):
|
|
149
161
|
raise ClassiqValueError("The model must contain a `main` function")
|
150
162
|
if any(
|
151
163
|
pd.direction != PortDeclarationDirection.Output
|
152
|
-
for pd in function_dict[MAIN_FUNCTION_NAME].port_declarations
|
164
|
+
for pd in function_dict[MAIN_FUNCTION_NAME].port_declarations
|
153
165
|
):
|
154
166
|
raise ClassiqValueError("Function 'main' cannot declare quantum inputs")
|
155
167
|
|
@@ -169,3 +181,13 @@ class Model(VersionedModel, ASTNode):
|
|
169
181
|
f"{multiply_defined_constants}"
|
170
182
|
)
|
171
183
|
return constants
|
184
|
+
|
185
|
+
def json_no_preferences_and_constraints(self) -> str:
|
186
|
+
return self.json(
|
187
|
+
indent=2,
|
188
|
+
exclude={
|
189
|
+
"constraints",
|
190
|
+
"execution_preferences",
|
191
|
+
"preferences",
|
192
|
+
},
|
193
|
+
)
|
@@ -1,12 +1,16 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
1
3
|
import pydantic
|
2
4
|
|
3
5
|
from classiq.interface.model.quantum_function_declaration import (
|
4
|
-
|
6
|
+
NamedParamsQuantumFunctionDeclaration,
|
5
7
|
)
|
6
|
-
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from classiq.interface.model.statement_block import StatementBlock
|
7
11
|
|
8
12
|
|
9
|
-
class NativeFunctionDefinition(
|
13
|
+
class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
|
10
14
|
"""
|
11
15
|
Facilitates the creation of a user-defined composite function
|
12
16
|
|
@@ -14,6 +18,6 @@ class NativeFunctionDefinition(QuantumFunctionDeclaration):
|
|
14
18
|
objects from other classes.
|
15
19
|
"""
|
16
20
|
|
17
|
-
body: StatementBlock = pydantic.Field(
|
21
|
+
body: "StatementBlock" = pydantic.Field(
|
18
22
|
default_factory=list, description="List of function calls to perform."
|
19
23
|
)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from classiq.interface.ast_node import ASTNode
|
4
|
+
from classiq.interface.exceptions import ClassiqError
|
5
|
+
|
6
|
+
|
7
|
+
class Parameter(ASTNode):
|
8
|
+
name: Optional[str]
|
9
|
+
|
10
|
+
def get_name(self) -> str:
|
11
|
+
if self.name is None:
|
12
|
+
raise ClassiqError("Cannot resolve parameter name")
|
13
|
+
return self.name
|
@@ -1,21 +1,25 @@
|
|
1
|
-
from typing import Any, Dict, Literal, Mapping
|
1
|
+
from typing import Any, Dict, Literal, Mapping, Optional
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
+
from classiq.interface.exceptions import ClassiqValueError
|
6
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
|
+
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
5
8
|
from classiq.interface.generator.functions.port_declaration import (
|
6
9
|
PortDeclarationDirection,
|
7
10
|
)
|
8
11
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
12
|
+
from classiq.interface.model.parameter import Parameter
|
9
13
|
from classiq.interface.model.quantum_variable_declaration import (
|
10
14
|
QuantumVariableDeclaration,
|
11
15
|
)
|
12
16
|
|
13
|
-
from classiq.exceptions import ClassiqValueError
|
14
17
|
|
15
|
-
|
16
|
-
class PortDeclaration(QuantumVariableDeclaration):
|
18
|
+
class AnonPortDeclaration(Parameter):
|
17
19
|
kind: Literal["PortDeclaration"]
|
18
20
|
|
21
|
+
quantum_type: ConcreteQuantumType
|
22
|
+
size: Optional[Expression] = pydantic.Field(default=None)
|
19
23
|
direction: PortDeclarationDirection
|
20
24
|
|
21
25
|
@pydantic.root_validator(pre=True)
|
@@ -32,3 +36,16 @@ class PortDeclaration(QuantumVariableDeclaration):
|
|
32
36
|
raise ClassiqValueError("Port declaration is missing a type")
|
33
37
|
|
34
38
|
return direction
|
39
|
+
|
40
|
+
@pydantic.validator("size")
|
41
|
+
def _propagate_size_to_type(
|
42
|
+
cls, size: Optional[Expression], values: Mapping[str, Any]
|
43
|
+
) -> Optional[Expression]:
|
44
|
+
return QuantumVariableDeclaration._propagate_size_to_type(size, values)
|
45
|
+
|
46
|
+
def rename(self, new_name: str) -> "PortDeclaration":
|
47
|
+
return PortDeclaration(**{**self.__dict__, "name": new_name})
|
48
|
+
|
49
|
+
|
50
|
+
class PortDeclaration(AnonPortDeclaration):
|
51
|
+
name: str
|