classiq 0.51.1__py3-none-any.whl → 0.53.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/_internals/api_wrapper.py +47 -15
- classiq/_internals/authentication/auth0.py +20 -4
- classiq/_internals/authentication/password_manager.py +16 -4
- classiq/_internals/client.py +3 -3
- classiq/_internals/host_checker.py +5 -3
- classiq/_internals/jobs.py +3 -3
- classiq/analyzer/analyzer_utilities.py +1 -1
- classiq/applications/chemistry/ground_state_problem.py +1 -1
- classiq/applications/combinatorial_helpers/pyomo_utils.py +3 -1
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/qlayer.py +25 -6
- classiq/execution/__init__.py +5 -0
- classiq/execution/execution_session.py +43 -2
- classiq/execution/iqcc.py +63 -0
- classiq/execution/jobs.py +2 -2
- classiq/execution/qaoa.py +84 -0
- classiq/executor.py +3 -3
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +19 -9
- classiq/interface/analyzer/cytoscape_graph.py +10 -3
- classiq/interface/analyzer/result.py +6 -5
- classiq/interface/applications/qsvm.py +13 -12
- classiq/interface/backend/backend_preferences.py +78 -105
- classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
- classiq/interface/backend/pydantic_backend.py +24 -12
- classiq/interface/backend/quantum_backend_providers.py +2 -0
- classiq/interface/chemistry/fermionic_operator.py +7 -7
- classiq/interface/chemistry/ground_state_problem.py +23 -18
- classiq/interface/chemistry/molecule.py +10 -5
- classiq/interface/chemistry/operator.py +71 -44
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
- classiq/interface/debug_info/debug_info.py +3 -4
- classiq/interface/exceptions.py +3 -1
- classiq/interface/execution/iqcc.py +19 -0
- classiq/interface/execution/jobs.py +10 -10
- classiq/interface/executor/aws_execution_cost.py +37 -20
- classiq/interface/executor/execution_preferences.py +1 -2
- classiq/interface/executor/execution_request.py +2 -2
- classiq/interface/executor/execution_result.py +4 -2
- classiq/interface/executor/iqae_result.py +1 -1
- classiq/interface/executor/optimizer_preferences.py +14 -10
- classiq/interface/executor/quantum_code.py +21 -16
- classiq/interface/executor/register_initialization.py +10 -10
- classiq/interface/executor/result.py +31 -17
- classiq/interface/executor/vqe_result.py +1 -1
- classiq/interface/finance/function_input.py +27 -18
- classiq/interface/finance/log_normal_model_input.py +2 -2
- classiq/interface/finance/model_input.py +3 -2
- classiq/interface/generator/amplitude_loading.py +8 -6
- classiq/interface/generator/arith/argument_utils.py +24 -0
- classiq/interface/generator/arith/arithmetic.py +5 -3
- classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
- classiq/interface/generator/arith/arithmetic_operations.py +6 -3
- classiq/interface/generator/arith/binary_ops.py +88 -63
- classiq/interface/generator/arith/extremum_operations.py +22 -13
- classiq/interface/generator/arith/logical_ops.py +6 -4
- classiq/interface/generator/arith/number_utils.py +3 -3
- classiq/interface/generator/arith/register_user_input.py +32 -17
- classiq/interface/generator/arith/unary_ops.py +5 -4
- classiq/interface/generator/chemistry_function_params.py +2 -1
- classiq/interface/generator/circuit_code/circuit_code.py +2 -1
- classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
- classiq/interface/generator/complex_type.py +14 -18
- classiq/interface/generator/control_state.py +32 -26
- classiq/interface/generator/expressions/expression.py +6 -5
- classiq/interface/generator/function_params.py +22 -39
- classiq/interface/generator/functions/classical_function_declaration.py +1 -1
- classiq/interface/generator/functions/classical_type.py +32 -23
- classiq/interface/generator/functions/concrete_types.py +8 -7
- classiq/interface/generator/functions/function_declaration.py +4 -5
- classiq/interface/generator/functions/type_name.py +5 -4
- classiq/interface/generator/generated_circuit_data.py +9 -6
- classiq/interface/generator/grover_diffuser.py +26 -18
- classiq/interface/generator/grover_operator.py +32 -22
- classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
- classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
- classiq/interface/generator/hardware/hardware_data.py +27 -26
- classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
- classiq/interface/generator/hartree_fock.py +2 -1
- classiq/interface/generator/identity.py +7 -2
- classiq/interface/generator/linear_pauli_rotations.py +27 -14
- classiq/interface/generator/mcu.py +15 -12
- classiq/interface/generator/mcx.py +18 -10
- classiq/interface/generator/model/constraints.py +4 -2
- classiq/interface/generator/model/model.py +2 -1
- classiq/interface/generator/model/preferences/preferences.py +30 -32
- classiq/interface/generator/oracles/custom_oracle.py +13 -10
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
- classiq/interface/generator/qpe.py +38 -26
- classiq/interface/generator/qsvm.py +4 -4
- classiq/interface/generator/quantum_function_call.py +57 -44
- classiq/interface/generator/quantum_program.py +8 -6
- classiq/interface/generator/range_types.py +10 -11
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
- classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
- classiq/interface/generator/standard_gates/u_gate.py +7 -10
- classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
- classiq/interface/generator/state_preparation/distributions.py +12 -12
- classiq/interface/generator/state_preparation/state_preparation.py +22 -16
- classiq/interface/generator/types/enum_declaration.py +2 -1
- classiq/interface/generator/ucc.py +2 -1
- classiq/interface/generator/unitary_gate.py +2 -1
- classiq/interface/generator/user_defined_function_params.py +3 -0
- classiq/interface/generator/visitor.py +1 -1
- classiq/interface/hardware.py +18 -3
- classiq/interface/helpers/custom_pydantic_types.py +38 -47
- classiq/interface/helpers/dotdict.py +18 -0
- classiq/interface/helpers/pydantic_model_helpers.py +3 -2
- classiq/interface/helpers/versioned_model.py +1 -4
- classiq/interface/ide/ide_data.py +5 -5
- classiq/interface/ide/visual_model.py +18 -5
- classiq/interface/interface_version.py +1 -1
- classiq/interface/jobs.py +12 -22
- classiq/interface/model/bind_operation.py +2 -1
- classiq/interface/model/classical_parameter_declaration.py +10 -4
- classiq/interface/model/handle_binding.py +20 -24
- classiq/interface/model/inplace_binary_operation.py +16 -9
- classiq/interface/model/model.py +21 -11
- classiq/interface/model/native_function_definition.py +10 -0
- classiq/interface/model/port_declaration.py +10 -7
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
- classiq/interface/model/quantum_function_declaration.py +22 -11
- classiq/interface/model/quantum_statement.py +6 -7
- classiq/interface/model/quantum_type.py +22 -19
- classiq/interface/model/statement_block.py +9 -9
- classiq/interface/server/global_versions.py +4 -5
- classiq/interface/server/routes.py +8 -0
- classiq/model_expansions/evaluators/parameter_types.py +3 -3
- classiq/model_expansions/expression_renamer.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +11 -12
- classiq/model_expansions/quantum_operations/emitter.py +22 -0
- classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +42 -12
- classiq/model_expansions/quantum_operations/invert.py +1 -1
- classiq/model_expansions/quantum_operations/phase.py +4 -5
- classiq/model_expansions/quantum_operations/power.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
- classiq/model_expansions/quantum_operations/within_apply.py +1 -1
- classiq/qmod/__init__.py +2 -0
- classiq/qmod/builtins/__init__.py +1 -3
- classiq/qmod/builtins/functions/__init__.py +9 -0
- classiq/qmod/builtins/functions/arithmetic.py +10 -0
- classiq/qmod/builtins/functions/standard_gates.py +14 -14
- classiq/qmod/builtins/functions/variational.py +37 -0
- classiq/qmod/create_model_function.py +16 -6
- classiq/qmod/qmod_parameter.py +3 -1
- classiq/qmod/quantum_expandable.py +43 -10
- classiq/qmod/quantum_function.py +24 -2
- classiq/qmod/semantics/static_semantics_visitor.py +3 -1
- classiq/qmod/synthesize_separately.py +16 -0
- classiq/qmod/type_attribute_remover.py +1 -1
- classiq/qmod/write_qmod.py +2 -4
- classiq/synthesis.py +11 -13
- {classiq-0.51.1.dist-info → classiq-0.53.0.dist-info}/METADATA +3 -2
- {classiq-0.51.1.dist-info → classiq-0.53.0.dist-info}/RECORD +158 -152
- {classiq-0.51.1.dist-info → classiq-0.53.0.dist-info}/WHEEL +0 -0
@@ -1,11 +1,12 @@
|
|
1
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
1
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union
|
2
2
|
|
3
3
|
import pydantic
|
4
|
-
from
|
4
|
+
from pydantic import Field
|
5
|
+
from pydantic_core.core_schema import ValidationInfo
|
6
|
+
from typing_extensions import Annotated, Self, TypeAlias
|
5
7
|
|
6
8
|
from classiq.interface.backend.backend_preferences import (
|
7
9
|
BackendPreferences,
|
8
|
-
validate_backend_service_provider,
|
9
10
|
)
|
10
11
|
from classiq.interface.backend.quantum_backend_providers import (
|
11
12
|
AllBackendsNameByVendor,
|
@@ -27,14 +28,14 @@ from classiq.interface.helpers.custom_pydantic_types import PydanticMachinePreci
|
|
27
28
|
if TYPE_CHECKING:
|
28
29
|
VisualizationLevel: TypeAlias = Optional[int]
|
29
30
|
else:
|
30
|
-
VisualizationLevel: TypeAlias = Optional[
|
31
|
+
VisualizationLevel: TypeAlias = Optional[Annotated[int, Field(ge=-1)]]
|
31
32
|
|
32
33
|
if TYPE_CHECKING:
|
33
34
|
PydanticBackendName = str
|
34
35
|
else:
|
35
|
-
PydanticBackendName =
|
36
|
-
strict=True, min_length=1,
|
37
|
-
|
36
|
+
PydanticBackendName = Annotated[
|
37
|
+
str, Field(strict=True, min_length=1, pattern="^([.A-Za-z0-9_-]*)$")
|
38
|
+
]
|
38
39
|
|
39
40
|
|
40
41
|
class QuantumFormat(StrEnum):
|
@@ -57,9 +58,9 @@ _SERVICE_PROVIDER_TO_FORMAT: Dict[Provider, QuantumFormat] = {
|
|
57
58
|
if TYPE_CHECKING:
|
58
59
|
PydanticConstrainedQuantumFormatList = List[QuantumFormat]
|
59
60
|
else:
|
60
|
-
PydanticConstrainedQuantumFormatList =
|
61
|
-
QuantumFormat,
|
62
|
-
|
61
|
+
PydanticConstrainedQuantumFormatList = Annotated[
|
62
|
+
List[QuantumFormat], Field(min_length=1, max_length=len(QuantumFormat))
|
63
|
+
]
|
63
64
|
|
64
65
|
|
65
66
|
class TranspilationOption(StrEnum):
|
@@ -75,7 +76,7 @@ class TranspilationOption(StrEnum):
|
|
75
76
|
return self != TranspilationOption.NONE
|
76
77
|
|
77
78
|
|
78
|
-
class Preferences(pydantic.BaseModel, extra=
|
79
|
+
class Preferences(pydantic.BaseModel, extra="forbid"):
|
79
80
|
"""
|
80
81
|
Preferences for synthesizing a quantum circuit.
|
81
82
|
|
@@ -194,21 +195,14 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
|
|
194
195
|
description="The random seed used for the generation",
|
195
196
|
)
|
196
197
|
|
197
|
-
@pydantic.
|
198
|
-
|
199
|
-
cls, backend_service_provider: Any
|
200
|
-
) -> Optional[Provider]:
|
201
|
-
if backend_service_provider is None:
|
202
|
-
return None
|
203
|
-
return validate_backend_service_provider(backend_service_provider)
|
204
|
-
|
205
|
-
@pydantic.validator("optimization_timeout_seconds")
|
198
|
+
@pydantic.field_validator("optimization_timeout_seconds", mode="before")
|
199
|
+
@classmethod
|
206
200
|
def optimization_timeout_less_than_generation_timeout(
|
207
201
|
cls,
|
208
202
|
optimization_timeout_seconds: Optional[pydantic.PositiveInt],
|
209
|
-
|
203
|
+
info: ValidationInfo,
|
210
204
|
) -> Optional[pydantic.PositiveInt]:
|
211
|
-
generation_timeout_seconds =
|
205
|
+
generation_timeout_seconds = info.data.get("timeout_seconds")
|
212
206
|
if generation_timeout_seconds is None or optimization_timeout_seconds is None:
|
213
207
|
return optimization_timeout_seconds
|
214
208
|
if optimization_timeout_seconds >= generation_timeout_seconds:
|
@@ -219,16 +213,20 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
|
|
219
213
|
)
|
220
214
|
return optimization_timeout_seconds
|
221
215
|
|
222
|
-
@pydantic.
|
216
|
+
@pydantic.field_validator("output_format", mode="before")
|
217
|
+
@classmethod
|
223
218
|
def make_output_format_list(cls, output_format: Any) -> List:
|
224
|
-
if not
|
219
|
+
if not isinstance(output_format, Sequence) or isinstance(output_format, str):
|
225
220
|
output_format = [output_format]
|
226
221
|
|
227
222
|
return output_format
|
228
223
|
|
229
|
-
@pydantic.
|
224
|
+
@pydantic.field_validator("output_format", mode="before")
|
225
|
+
@classmethod
|
230
226
|
def validate_output_format(
|
231
|
-
cls,
|
227
|
+
cls,
|
228
|
+
output_format: PydanticConstrainedQuantumFormatList,
|
229
|
+
info: ValidationInfo,
|
232
230
|
) -> PydanticConstrainedQuantumFormatList:
|
233
231
|
if len(output_format) != len(set(output_format)):
|
234
232
|
raise ClassiqValueError(
|
@@ -236,7 +234,7 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
|
|
236
234
|
"has at least one format that appears twice or more"
|
237
235
|
)
|
238
236
|
|
239
|
-
service_provider =
|
237
|
+
service_provider = info.data.get("backend_service_provider")
|
240
238
|
if service_provider is None:
|
241
239
|
return output_format
|
242
240
|
|
@@ -246,13 +244,13 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
|
|
246
244
|
|
247
245
|
return output_format
|
248
246
|
|
249
|
-
@pydantic.
|
250
|
-
def validate_backend(
|
251
|
-
backend_name =
|
252
|
-
backend_service_provider =
|
247
|
+
@pydantic.model_validator(mode="after")
|
248
|
+
def validate_backend(self) -> Self:
|
249
|
+
backend_name = self.backend_name
|
250
|
+
backend_service_provider = self.backend_service_provider
|
253
251
|
if (backend_name is None) != (backend_service_provider is None):
|
254
252
|
raise ClassiqValueError(BACKEND_VALIDATION_ERROR_MESSAGE)
|
255
|
-
return
|
253
|
+
return self
|
256
254
|
|
257
255
|
@property
|
258
256
|
def backend_preferences(self) -> Optional[BackendPreferences]:
|
@@ -22,18 +22,21 @@ class CustomOracle(OracleABC[QubitState]):
|
|
22
22
|
default_factory=CustomFunction,
|
23
23
|
)
|
24
24
|
|
25
|
-
@pydantic.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
@pydantic.model_validator(mode="before")
|
26
|
+
@classmethod
|
27
|
+
def _parse_oracle(cls, values: Any) -> Dict[str, Any]:
|
28
|
+
if isinstance(values, dict):
|
29
|
+
parse_function_params_values(
|
30
|
+
values=values,
|
31
|
+
params_key="custom_oracle_params",
|
32
|
+
discriminator_key="custom_oracle",
|
33
|
+
param_classes={CustomFunction},
|
34
|
+
default_parser_class=CustomFunction,
|
35
|
+
)
|
34
36
|
return values
|
35
37
|
|
36
|
-
@pydantic.
|
38
|
+
@pydantic.field_validator("custom_oracle_params")
|
39
|
+
@classmethod
|
37
40
|
def _validate_names_match_oracle(
|
38
41
|
cls, custom_oracle_params: CustomFunction
|
39
42
|
) -> CustomFunction:
|
@@ -2,6 +2,8 @@ import math
|
|
2
2
|
from typing import Any, Dict, Generic, List, Sequence, Tuple, TypeVar
|
3
3
|
|
4
4
|
import pydantic
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
6
|
+
from pydantic_core.core_schema import ValidationInfo
|
5
7
|
|
6
8
|
from classiq.interface.exceptions import ClassiqError
|
7
9
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
@@ -18,8 +20,8 @@ Breakpoint = TypeVar("Breakpoint")
|
|
18
20
|
|
19
21
|
|
20
22
|
class AffineMap(HashablePydanticBaseModel):
|
21
|
-
slope: float =
|
22
|
-
offset: float =
|
23
|
+
slope: float = Field(default=1.0)
|
24
|
+
offset: float = Field(default=0.0)
|
23
25
|
|
24
26
|
def evaluate(self, x: float) -> float:
|
25
27
|
return self.offset + self.slope * x
|
@@ -27,16 +29,15 @@ class AffineMap(HashablePydanticBaseModel):
|
|
27
29
|
def image_bounds(self, domain_bounds: Tuple[float, float]) -> Tuple[float, float]:
|
28
30
|
return self.evaluate(domain_bounds[0]), self.evaluate(domain_bounds[1])
|
29
31
|
|
30
|
-
|
31
|
-
frozen = True
|
32
|
+
model_config = ConfigDict(frozen=True)
|
32
33
|
|
33
34
|
|
34
35
|
class PiecewiseLinearAmplitudeLoadingABC(
|
35
|
-
FunctionParams,
|
36
|
+
FunctionParams, BaseModel, Generic[Breakpoint]
|
36
37
|
):
|
37
|
-
num_qubits:
|
38
|
-
breakpoints: Sequence[
|
39
|
-
affine_maps: Sequence[AffineMap] =
|
38
|
+
num_qubits: int = Field()
|
39
|
+
breakpoints: Sequence[int] = Field()
|
40
|
+
affine_maps: Sequence[AffineMap] = Field()
|
40
41
|
|
41
42
|
def _create_ios(self) -> None:
|
42
43
|
self._inputs = {
|
@@ -58,19 +59,35 @@ class PiecewiseLinearAmplitudeLoadingABC(
|
|
58
59
|
top = max(max(piece) for piece in piece_bounds)
|
59
60
|
return bottom, top
|
60
61
|
|
61
|
-
@
|
62
|
+
@field_validator("breakpoints", mode="before")
|
63
|
+
@classmethod
|
62
64
|
def _validate_breakpoints(cls, breakpoints: Sequence[int]) -> Sequence[int]:
|
65
|
+
return cls.validate_breakpoints(breakpoints)
|
66
|
+
|
67
|
+
@classmethod
|
68
|
+
def validate_breakpoints(cls, breakpoints: Sequence[int]) -> Sequence[int]:
|
63
69
|
assert len(breakpoints) == len(
|
64
70
|
set(breakpoints)
|
65
71
|
), "Repeated breakpoints encountered"
|
66
72
|
assert list(breakpoints) == sorted(breakpoints), "Breakpoints not sorted"
|
67
|
-
return breakpoints
|
73
|
+
return list(map(int, breakpoints))
|
68
74
|
|
69
|
-
@pydantic.
|
70
|
-
|
75
|
+
@pydantic.model_validator(mode="before")
|
76
|
+
@classmethod
|
77
|
+
def _validate_lengths(cls, values: Any) -> Dict[str, Any]:
|
71
78
|
breakpoints = values.get("breakpoints", list())
|
72
79
|
affine_maps = values.get("affine_maps", list())
|
73
80
|
num_qubits = values.get("num_qubits", int)
|
81
|
+
if isinstance(values, dict):
|
82
|
+
breakpoints = values.get("breakpoints", list())
|
83
|
+
affine_maps = values.get("affine_maps", list())
|
84
|
+
num_qubits = values.get("num_qubits", int)
|
85
|
+
elif isinstance(values, PiecewiseLinearAmplitudeLoadingABC):
|
86
|
+
breakpoints = values.breakpoints
|
87
|
+
affine_maps = values.affine_maps
|
88
|
+
num_qubits = values.num_qubits
|
89
|
+
values = values.__dict__
|
90
|
+
|
74
91
|
assert len(breakpoints) - 1 == len(
|
75
92
|
affine_maps
|
76
93
|
), "Size mismatch between the number of slopes and breakpoints. The number of breakpoints should be the number of slopes + 1"
|
@@ -80,28 +97,27 @@ class PiecewiseLinearAmplitudeLoadingABC(
|
|
80
97
|
return values
|
81
98
|
|
82
99
|
|
83
|
-
class PiecewiseLinearRotationAmplitudeLoading(
|
84
|
-
PiecewiseLinearAmplitudeLoadingABC[pydantic.NonNegativeInt]
|
85
|
-
):
|
100
|
+
class PiecewiseLinearRotationAmplitudeLoading(PiecewiseLinearAmplitudeLoadingABC[int]):
|
86
101
|
pass
|
87
102
|
|
88
|
-
@
|
89
|
-
|
90
|
-
|
103
|
+
@field_validator("breakpoints")
|
104
|
+
@classmethod
|
105
|
+
def _validate_breakpoints_field(
|
106
|
+
cls, breakpoints: Sequence[int], info: ValidationInfo
|
91
107
|
) -> Sequence[int]:
|
92
|
-
num_qubits =
|
108
|
+
num_qubits = info.data.get("num_qubits")
|
93
109
|
assert isinstance(num_qubits, int), "Must have an integer number of qubits"
|
94
110
|
assert min(breakpoints) == 0, "First breakpoint must be 0"
|
95
111
|
assert (
|
96
112
|
max(breakpoints) == 2**num_qubits - 1
|
97
113
|
), f"Last breakpoint must be {2**num_qubits - 1}"
|
98
|
-
return PiecewiseLinearAmplitudeLoadingABC.
|
114
|
+
return PiecewiseLinearAmplitudeLoadingABC.validate_breakpoints(
|
99
115
|
breakpoints=breakpoints
|
100
116
|
)
|
101
117
|
|
102
118
|
|
103
119
|
class PiecewiseLinearAmplitudeLoading(PiecewiseLinearAmplitudeLoadingABC[float]):
|
104
|
-
rescaling_factor: float =
|
120
|
+
rescaling_factor: float = Field(default=0.25 * math.pi)
|
105
121
|
|
106
122
|
def rescaled(self) -> PiecewiseLinearRotationAmplitudeLoading:
|
107
123
|
c, d = self._get_image_bounds()
|
@@ -1,6 +1,9 @@
|
|
1
1
|
from typing import Any, Dict, Optional, Tuple
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
from pydantic import ConfigDict
|
5
|
+
from pydantic_core.core_schema import ValidationInfo
|
6
|
+
from typing_extensions import Self
|
4
7
|
|
5
8
|
from classiq.interface.exceptions import ClassiqMismatchIOsError, ClassiqValueError
|
6
9
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
@@ -36,9 +39,7 @@ class ExponentiationScaling(pydantic.BaseModel):
|
|
36
39
|
default=2.0,
|
37
40
|
description="The scaling factor of the exponentiation max_depth; defaults to 2.",
|
38
41
|
)
|
39
|
-
|
40
|
-
class Config:
|
41
|
-
frozen = True
|
42
|
+
model_config = ConfigDict(frozen=True)
|
42
43
|
|
43
44
|
|
44
45
|
class ExponentiationSpecification(pydantic.BaseModel):
|
@@ -55,17 +56,13 @@ class ExponentiationSpecification(pydantic.BaseModel):
|
|
55
56
|
default=None,
|
56
57
|
description="The max_depth of each exponentiation function; overrides scaling.",
|
57
58
|
)
|
59
|
+
model_config = ConfigDict(frozen=True)
|
58
60
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
@pydantic.root_validator
|
63
|
-
def _validate_exponentiation_specification(
|
64
|
-
cls, values: Dict[str, Any]
|
65
|
-
) -> Dict[str, Any]:
|
66
|
-
if values.get("scaling") is None and values.get("max_depths") is None:
|
61
|
+
@pydantic.model_validator(mode="after")
|
62
|
+
def _validate_exponentiation_specification(self) -> Self:
|
63
|
+
if self.scaling is None and self.max_depths is None:
|
67
64
|
raise ClassiqValueError("At least one specification must be provided.")
|
68
|
-
return
|
65
|
+
return self
|
69
66
|
|
70
67
|
|
71
68
|
class PhaseEstimation(FunctionParams):
|
@@ -104,28 +101,42 @@ class PhaseEstimation(FunctionParams):
|
|
104
101
|
self._outputs[self._output_name] = RegisterArithmeticInfo(size=self.size)
|
105
102
|
self._create_zero_input_registers({DEFAULT_ZERO_NAME: self.size})
|
106
103
|
|
107
|
-
@pydantic.
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
104
|
+
@pydantic.model_validator(mode="before")
|
105
|
+
@classmethod
|
106
|
+
def _validate_composite_name(cls, values: Any) -> Dict[str, Any]:
|
107
|
+
if not isinstance(values, dict):
|
108
|
+
return values
|
109
|
+
unitary_params = values.get("unitary_params")
|
110
|
+
unitary = values.get("unitary")
|
111
|
+
|
112
|
+
if isinstance(unitary_params, CustomFunction) and not unitary:
|
112
113
|
raise ClassiqValueError(
|
113
114
|
"`PhaseEstimation` of a user define function (`CustomFunction`) must receive the function name from the `unitary` field"
|
114
115
|
)
|
115
116
|
return values
|
116
117
|
|
117
|
-
@pydantic.
|
118
|
-
|
118
|
+
@pydantic.model_validator(mode="before")
|
119
|
+
@classmethod
|
120
|
+
def _parse_function_params(
|
121
|
+
cls, values: Any, info: ValidationInfo
|
122
|
+
) -> Dict[str, Any]:
|
123
|
+
vals = info.data.copy() if info.data else {}
|
124
|
+
if isinstance(values, dict):
|
125
|
+
vals = values
|
126
|
+
elif isinstance(values, PhaseEstimation):
|
127
|
+
vals = values.model_dump()
|
128
|
+
|
119
129
|
parse_function_params_values(
|
120
|
-
values=
|
130
|
+
values=vals,
|
121
131
|
params_key="unitary_params",
|
122
132
|
discriminator_key="unitary",
|
123
133
|
param_classes=function_param_library_without_self_reference.param_list,
|
124
134
|
default_parser_class=CustomFunction,
|
125
135
|
)
|
126
|
-
return
|
136
|
+
return vals
|
127
137
|
|
128
|
-
@pydantic.
|
138
|
+
@pydantic.field_validator("unitary_params")
|
139
|
+
@classmethod
|
129
140
|
def _validate_unitary_params(cls, unitary_params: FunctionParams) -> FunctionParams:
|
130
141
|
if not unitary_params.is_powerable():
|
131
142
|
if isinstance(unitary_params, CustomFunction):
|
@@ -135,22 +146,23 @@ class PhaseEstimation(FunctionParams):
|
|
135
146
|
)
|
136
147
|
return unitary_params
|
137
148
|
|
138
|
-
@pydantic.
|
149
|
+
@pydantic.field_validator("exponentiation_specification")
|
150
|
+
@classmethod
|
139
151
|
def _validate_exponentiation_specification(
|
140
152
|
cls,
|
141
153
|
exponentiation_specification: Optional[ExponentiationSpecification],
|
142
|
-
|
154
|
+
validation_info: ValidationInfo,
|
143
155
|
) -> Optional[ExponentiationSpecification]:
|
144
156
|
if exponentiation_specification is None:
|
145
157
|
return exponentiation_specification
|
146
|
-
unitary_params =
|
158
|
+
unitary_params = validation_info.data.get("unitary_params")
|
147
159
|
if not isinstance(unitary_params, Exponentiation):
|
148
160
|
raise ClassiqValueError(
|
149
161
|
"exponentiation_specification is only valid for Exponentiation unitary_params."
|
150
162
|
)
|
151
163
|
if exponentiation_specification.max_depths is not None and len(
|
152
164
|
exponentiation_specification.max_depths
|
153
|
-
) !=
|
165
|
+
) != validation_info.data.get("size"):
|
154
166
|
raise ClassiqValueError(
|
155
167
|
"Length of max_depths must match the provided size."
|
156
168
|
)
|
@@ -2,6 +2,7 @@ from typing import List, Literal, Optional, Union
|
|
2
2
|
|
3
3
|
import numpy as np
|
4
4
|
import pydantic
|
5
|
+
from pydantic import ConfigDict
|
5
6
|
|
6
7
|
from classiq.interface.enum_utils import StrEnum
|
7
8
|
from classiq.interface.exceptions import ClassiqQSVMError, ClassiqValueError
|
@@ -28,9 +29,7 @@ class QSVMFeatureMapEntanglement(StrEnum):
|
|
28
29
|
|
29
30
|
class QSVMFeatureMapDimensional(HashablePydanticBaseModel):
|
30
31
|
feature_dimension: Optional[int] = None
|
31
|
-
|
32
|
-
class Config:
|
33
|
-
frozen = True
|
32
|
+
model_config = ConfigDict(frozen=True)
|
34
33
|
|
35
34
|
|
36
35
|
class QSVMFeatureMapPauli(QSVMFeatureMapDimensional):
|
@@ -42,7 +41,8 @@ class QSVMFeatureMapPauli(QSVMFeatureMapDimensional):
|
|
42
41
|
parameter_prefix: str = "x"
|
43
42
|
name: str = "PauliFeatureMap"
|
44
43
|
|
45
|
-
@pydantic.
|
44
|
+
@pydantic.field_validator("paulis", mode="before")
|
45
|
+
@classmethod
|
46
46
|
def set_paulis(cls, paulis: List[str]) -> List[str]:
|
47
47
|
# iterate every letter in every string in the list of paulis
|
48
48
|
for s in paulis:
|
@@ -21,7 +21,8 @@ from typing import (
|
|
21
21
|
from uuid import UUID, uuid4
|
22
22
|
|
23
23
|
import pydantic
|
24
|
-
from pydantic import BaseModel,
|
24
|
+
from pydantic import BaseModel, ConfigDict
|
25
|
+
from pydantic_core.core_schema import ValidationInfo
|
25
26
|
|
26
27
|
from classiq.interface.exceptions import ClassiqControlError, ClassiqValueError
|
27
28
|
from classiq.interface.generator import function_param_list, function_params as f_params
|
@@ -146,10 +147,11 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
146
147
|
)
|
147
148
|
name: PydanticNonEmptyString = pydantic.Field(
|
148
149
|
default=None,
|
150
|
+
validate_default=True,
|
149
151
|
description="The name of the function instance. "
|
150
152
|
"If not set, determined automatically.",
|
151
153
|
)
|
152
|
-
|
154
|
+
source_id: Optional[UUID] = pydantic.Field(default=None)
|
153
155
|
arithmetic_id: Optional[str] = pydantic.Field(default=None)
|
154
156
|
inverse_op_id: Optional[UUID] = pydantic.Field(default=None)
|
155
157
|
|
@@ -214,8 +216,9 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
214
216
|
return self.function_params.inputs_full(self.strict_zero_ios)
|
215
217
|
return self.function_params.outputs
|
216
218
|
|
217
|
-
@pydantic.
|
218
|
-
|
219
|
+
@pydantic.field_validator("name", mode="before")
|
220
|
+
@classmethod
|
221
|
+
def _create_name(cls, name: Optional[str], info: ValidationInfo) -> str:
|
219
222
|
"""
|
220
223
|
generates a name to a user defined-functions as follows:
|
221
224
|
<function_name>_<SUFFIX_MARKER>_<random_suffix>
|
@@ -226,9 +229,9 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
226
229
|
raise ClassiqValueError(BAD_CALL_NAME_ERROR_MSG)
|
227
230
|
return name
|
228
231
|
|
229
|
-
function =
|
232
|
+
function = info.data.get("function")
|
230
233
|
|
231
|
-
params =
|
234
|
+
params = info.data.get("function_params")
|
232
235
|
if (
|
233
236
|
isinstance(params, CustomFunction)
|
234
237
|
and function == CustomFunction.discriminator()
|
@@ -241,25 +244,30 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
241
244
|
return name if name else suffix
|
242
245
|
return f"{function.split(f'_{EXPANDED_KEYWORD}')[0]}_{suffix}"
|
243
246
|
|
244
|
-
@pydantic.
|
245
|
-
|
246
|
-
|
247
|
-
|
247
|
+
@pydantic.model_validator(mode="before")
|
248
|
+
@classmethod
|
249
|
+
def validate_composite_name(cls, values: Any) -> Dict[str, Any]:
|
250
|
+
if (
|
251
|
+
isinstance(values, dict)
|
252
|
+
and isinstance(values.get("unitary_params"), CustomFunction)
|
253
|
+
and not values.get("unitary")
|
248
254
|
):
|
249
255
|
raise ClassiqValueError(
|
250
256
|
"`PhaseEstimation` of a user define function (`CustomFunction`) must receive the function name from the `unitary` field"
|
251
257
|
)
|
252
258
|
return values
|
253
259
|
|
254
|
-
@pydantic.
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
260
|
+
@pydantic.model_validator(mode="before")
|
261
|
+
@classmethod
|
262
|
+
def _parse_function_params(cls, values: Any) -> Dict[str, Any]:
|
263
|
+
if isinstance(values, dict):
|
264
|
+
f_params.parse_function_params_values(
|
265
|
+
values=values,
|
266
|
+
params_key="function_params",
|
267
|
+
discriminator_key="function",
|
268
|
+
param_classes=function_param_list.function_param_library.param_list,
|
269
|
+
default_parser_class=CustomFunction,
|
270
|
+
)
|
263
271
|
return values
|
264
272
|
|
265
273
|
# TODO: note that this checks QuantumFunctionCall input register names
|
@@ -295,22 +303,25 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
295
303
|
if error_msg:
|
296
304
|
raise ClassiqValueError("\n".join(error_msg))
|
297
305
|
|
298
|
-
@pydantic.
|
306
|
+
@pydantic.field_validator("strict_zero_ios")
|
307
|
+
@classmethod
|
299
308
|
def _validate_arithmetic_cannot_strict_zero_ios(
|
300
|
-
cls, strict_zero_ios: bool,
|
309
|
+
cls, strict_zero_ios: bool, info: ValidationInfo
|
301
310
|
) -> bool:
|
302
311
|
assert not (
|
303
|
-
|
312
|
+
info.data.get("function") == Arithmetic.discriminator()
|
313
|
+
and not strict_zero_ios
|
304
314
|
), "when using the Arithmetic function, assign to the expression result register via the target parameter instead of the strict_zero_ios flag"
|
305
315
|
return strict_zero_ios
|
306
316
|
|
307
|
-
@pydantic.
|
317
|
+
@pydantic.field_validator("control_states")
|
318
|
+
@classmethod
|
308
319
|
def _validate_control_states(
|
309
|
-
cls, control_states: List[ControlState],
|
320
|
+
cls, control_states: List[ControlState], info: ValidationInfo
|
310
321
|
) -> List[ControlState]:
|
311
322
|
control_names = [ctrl_state.name for ctrl_state in control_states]
|
312
|
-
function_params =
|
313
|
-
strict_zero_ios =
|
323
|
+
function_params = info.data.get("function_params")
|
324
|
+
strict_zero_ios = info.data.get("strict_zero_ios")
|
314
325
|
if not (
|
315
326
|
isinstance(function_params, FunctionParams)
|
316
327
|
and isinstance(strict_zero_ios, bool)
|
@@ -382,12 +393,13 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
382
393
|
|
383
394
|
return not any((empty_slices, out_of_range, overlapping_slices))
|
384
395
|
|
385
|
-
@pydantic.
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
396
|
+
@pydantic.field_validator("inputs", mode="before")
|
397
|
+
@classmethod
|
398
|
+
def _validate_inputs(cls, inputs: IOType, info: ValidationInfo) -> WireDict:
|
399
|
+
params: Optional[FunctionParams] = info.data.get("function_params")
|
400
|
+
is_inverse: bool = info.data.get("is_inverse", False)
|
401
|
+
strict_zero_ios: bool = info.data.get("strict_zero_ios", True)
|
402
|
+
control_states: List[ControlState] = info.data.get("control_states", list())
|
391
403
|
if params is None:
|
392
404
|
return dict()
|
393
405
|
if isinstance(params, CustomFunction):
|
@@ -452,12 +464,13 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
452
464
|
if error_msg:
|
453
465
|
raise ClassiqValueError("\n".join(error_msg))
|
454
466
|
|
455
|
-
@pydantic.
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
467
|
+
@pydantic.field_validator("outputs", mode="before")
|
468
|
+
@classmethod
|
469
|
+
def _validate_outputs(cls, outputs: IOType, info: ValidationInfo) -> IOType:
|
470
|
+
params = info.data.get("function_params")
|
471
|
+
is_inverse: bool = info.data.get("is_inverse", False)
|
472
|
+
strict_zero_ios: bool = info.data.get("strict_zero_ios", True)
|
473
|
+
control_states = info.data.get("control_states", list())
|
461
474
|
if params is None:
|
462
475
|
return outputs
|
463
476
|
if isinstance(params, CustomFunction):
|
@@ -492,15 +505,16 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
492
505
|
|
493
506
|
return outputs
|
494
507
|
|
495
|
-
@pydantic.
|
508
|
+
@pydantic.field_validator("power")
|
509
|
+
@classmethod
|
496
510
|
def _validate_power(
|
497
|
-
cls, power: pydantic.NonNegativeInt,
|
511
|
+
cls, power: pydantic.NonNegativeInt, info: ValidationInfo
|
498
512
|
) -> pydantic.NonNegativeInt:
|
499
|
-
function_params =
|
513
|
+
function_params = info.data.get("function_params")
|
500
514
|
if function_params is None:
|
501
515
|
return power
|
502
516
|
if power != 1 and not function_params.is_powerable(
|
503
|
-
|
517
|
+
info.data.get("strict_zero_ios")
|
504
518
|
):
|
505
519
|
raise ClassiqValueError("Cannot power this operator")
|
506
520
|
return power
|
@@ -633,8 +647,7 @@ class SynthesisQuantumFunctionCall(BaseModel):
|
|
633
647
|
call_kwargs["control_states"] = self.control_states + [control_state]
|
634
648
|
return SynthesisQuantumFunctionCall(**call_kwargs)
|
635
649
|
|
636
|
-
|
637
|
-
extra = Extra.forbid
|
650
|
+
model_config = ConfigDict(extra="forbid")
|
638
651
|
|
639
652
|
|
640
653
|
def _generate_single_io_err(
|