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
|
+
import datetime
|
1
2
|
from datetime import date
|
2
|
-
from typing import Any, Dict, List, Optional
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
3
4
|
|
4
5
|
import pydantic
|
5
|
-
from pydantic import
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field
|
7
|
+
from pydantic_core.core_schema import ValidationInfo
|
6
8
|
|
7
9
|
from classiq.interface.enum_utils import StrEnum
|
8
|
-
from classiq.interface.exceptions import ClassiqValueError
|
9
10
|
|
10
11
|
|
11
12
|
class Granularity(StrEnum):
|
@@ -19,30 +20,44 @@ class CostScope(StrEnum):
|
|
19
20
|
organization = "organization"
|
20
21
|
|
21
22
|
|
22
|
-
class ExecutionCostForTimePeriod(
|
23
|
-
start: date =
|
24
|
-
description="The beginning of the time period for tasks usage and cost ("
|
25
|
-
"inclusive).",
|
23
|
+
class ExecutionCostForTimePeriod(BaseModel):
|
24
|
+
start: date = Field(
|
25
|
+
description="The beginning of the time period for tasks usage and cost (inclusive)."
|
26
26
|
)
|
27
|
-
end: date =
|
28
|
-
description="The end of the time period for tasks usage and cost (exclusive)."
|
27
|
+
end: date = Field(
|
28
|
+
description="The end of the time period for tasks usage and cost (exclusive)."
|
29
29
|
)
|
30
|
-
granularity: Granularity =
|
30
|
+
granularity: Granularity = Field(
|
31
31
|
description="Either MONTHLY or DAILY, or HOURLY.", default=Granularity.daily
|
32
32
|
)
|
33
|
-
cost_scope: CostScope =
|
33
|
+
cost_scope: CostScope = Field(
|
34
34
|
description="Either user or organization", default=CostScope.user
|
35
35
|
)
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
@pydantic.field_validator("start", mode="before")
|
38
|
+
@classmethod
|
39
|
+
def validate_start_date(cls, start_date: Union[datetime.datetime, date]) -> date:
|
40
|
+
if isinstance(start_date, datetime.datetime):
|
41
|
+
return start_date.date()
|
42
|
+
return start_date
|
43
|
+
|
44
|
+
@pydantic.field_validator("end", mode="before")
|
45
|
+
@classmethod
|
46
|
+
def validate_date_and_date_order(
|
47
|
+
cls, v: Union[date, datetime.datetime], info: ValidationInfo
|
48
|
+
) -> date:
|
49
|
+
if isinstance(v, datetime.datetime):
|
50
|
+
v = v.date()
|
51
|
+
if "start" in info.data and v <= info.data["start"]:
|
52
|
+
raise ValueError('"end" date should be after "start" date')
|
44
53
|
return v
|
45
54
|
|
55
|
+
def dict(self, **kwargs: Any) -> Dict[str, Any]:
|
56
|
+
data = super().model_dump(**kwargs)
|
57
|
+
data["start"] = self.start.strftime("%Y-%m-%d")
|
58
|
+
data["end"] = self.end.strftime("%Y-%m-%d")
|
59
|
+
return data
|
60
|
+
|
46
61
|
|
47
62
|
"""The following models describe the aws response model and based on this schema:
|
48
63
|
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ce.html#CostExplorer.Client.get_cost_and_usage"""
|
@@ -65,8 +80,10 @@ class Total(pydantic.BaseModel):
|
|
65
80
|
class ExecutedTaskForPeriodItem(pydantic.BaseModel):
|
66
81
|
TimePeriod: TimePeriod
|
67
82
|
Total: Total
|
68
|
-
Groups: Optional[List]
|
69
|
-
Estimated: Optional[bool]
|
83
|
+
Groups: Optional[List] = None
|
84
|
+
Estimated: Optional[bool] = None
|
85
|
+
|
86
|
+
model_config = ConfigDict(extra="forbid")
|
70
87
|
|
71
88
|
|
72
89
|
class ExecutionCostForTimePeriodResponse(pydantic.BaseModel):
|
@@ -57,9 +57,9 @@ class ExecutionJobDetails(VersionedModel):
|
|
57
57
|
status: JobStatus
|
58
58
|
|
59
59
|
num_shots: Optional[int]
|
60
|
-
program_id: Optional[str]
|
60
|
+
program_id: Optional[str] = Field(default=None)
|
61
61
|
|
62
|
-
error: Optional[str]
|
62
|
+
error: Optional[str] = Field(default=None)
|
63
63
|
|
64
64
|
|
65
65
|
class ExecutionJobsQueryResults(VersionedModel):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Any, List, Literal, Union
|
2
2
|
|
3
|
-
from pydantic import BaseModel, Field
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field
|
4
4
|
from typing_extensions import Annotated, TypeAlias
|
5
5
|
|
6
6
|
from classiq.interface.enum_utils import StrEnum
|
@@ -85,7 +85,7 @@ class TaggedIQAEResult(BaseModel):
|
|
85
85
|
class TaggedUnstructured(BaseModel):
|
86
86
|
value_type: Literal[SavedResultValueType.Unstructured]
|
87
87
|
name: str
|
88
|
-
value: Any
|
88
|
+
value: Any = None
|
89
89
|
|
90
90
|
|
91
91
|
SavedResult = Annotated[
|
@@ -109,3 +109,5 @@ ResultsCollection: TypeAlias = List[SavedResult]
|
|
109
109
|
|
110
110
|
class ExecuteGeneratedCircuitResults(VersionedModel):
|
111
111
|
results: ResultsCollection
|
112
|
+
|
113
|
+
model_config = ConfigDict(extra="forbid")
|
@@ -14,6 +14,6 @@ class IQAEIterationData(BaseModel):
|
|
14
14
|
|
15
15
|
class IQAEResult(VersionedModel, QmodPyObject):
|
16
16
|
estimation: float
|
17
|
-
confidence_interval: List[float] = Field(
|
17
|
+
confidence_interval: List[float] = Field(min_length=2, max_length=2)
|
18
18
|
iterations_data: List[IQAEIterationData]
|
19
19
|
warnings: List[str]
|
@@ -1,7 +1,8 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import List, Optional
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
from pydantic import BaseModel
|
5
|
+
from pydantic_core.core_schema import ValidationInfo
|
5
6
|
|
6
7
|
from classiq.interface.enum_utils import StrEnum
|
7
8
|
from classiq.interface.exceptions import ClassiqValueError
|
@@ -53,11 +54,12 @@ class OptimizerPreferences(BaseModel):
|
|
53
54
|
description="If True, the optimizer will not compute the variance of the ansatz.",
|
54
55
|
)
|
55
56
|
|
56
|
-
@pydantic.
|
57
|
+
@pydantic.field_validator("tolerance", mode="before")
|
58
|
+
@classmethod
|
57
59
|
def check_tolerance(
|
58
|
-
cls, tolerance: Optional[pydantic.PositiveFloat],
|
60
|
+
cls, tolerance: Optional[pydantic.PositiveFloat], info: ValidationInfo
|
59
61
|
) -> Optional[pydantic.PositiveFloat]:
|
60
|
-
optimizer_type =
|
62
|
+
optimizer_type = info.data.get("type")
|
61
63
|
if tolerance is not None and optimizer_type == OptimizerType.SPSA:
|
62
64
|
raise ClassiqValueError("No tolerance param for SPSA optimizer")
|
63
65
|
|
@@ -66,11 +68,12 @@ class OptimizerPreferences(BaseModel):
|
|
66
68
|
|
67
69
|
return tolerance
|
68
70
|
|
69
|
-
@pydantic.
|
71
|
+
@pydantic.field_validator("step_size", mode="before")
|
72
|
+
@classmethod
|
70
73
|
def check_step_size(
|
71
|
-
cls, step_size: Optional[pydantic.PositiveFloat],
|
74
|
+
cls, step_size: Optional[pydantic.PositiveFloat], info: ValidationInfo
|
72
75
|
) -> Optional[pydantic.PositiveFloat]:
|
73
|
-
optimizer_type =
|
76
|
+
optimizer_type = info.data.get("name")
|
74
77
|
if step_size is not None and optimizer_type not in (
|
75
78
|
OptimizerType.L_BFGS_B,
|
76
79
|
OptimizerType.ADAM,
|
@@ -109,11 +112,12 @@ class CombinatorialOptimizer(OptimizerPreferences):
|
|
109
112
|
description="Whether to check if all the solutions satisfy the constraints",
|
110
113
|
)
|
111
114
|
|
112
|
-
@pydantic.
|
115
|
+
@pydantic.field_validator("alpha_cvar", mode="before")
|
116
|
+
@classmethod
|
113
117
|
def check_alpha_cvar(
|
114
|
-
cls, alpha_cvar: Optional[PydanticAlphaParamCVAR],
|
118
|
+
cls, alpha_cvar: Optional[PydanticAlphaParamCVAR], info: ValidationInfo
|
115
119
|
) -> Optional[PydanticAlphaParamCVAR]:
|
116
|
-
cost_type =
|
120
|
+
cost_type = info.data.get("cost_type")
|
117
121
|
if alpha_cvar is not None and cost_type != CostType.CVAR:
|
118
122
|
raise ClassiqValueError("Use CVAR params only for CostType.CVAR.")
|
119
123
|
|
@@ -4,7 +4,8 @@ from pathlib import Path
|
|
4
4
|
from typing import Any, Dict, Optional, Tuple, Union
|
5
5
|
|
6
6
|
import pydantic
|
7
|
-
from pydantic import BaseModel
|
7
|
+
from pydantic import BaseModel, ConfigDict
|
8
|
+
from pydantic_core.core_schema import ValidationInfo
|
8
9
|
|
9
10
|
from classiq.interface.backend.ionq.ionq_quantum_program import IonqQuantumCircuit
|
10
11
|
from classiq.interface.backend.pydantic_backend import PydanticArgumentNameType
|
@@ -31,17 +32,18 @@ class QuantumBaseCode(BaseModel):
|
|
31
32
|
..., description="The textual representation of the program"
|
32
33
|
)
|
33
34
|
|
34
|
-
@pydantic.
|
35
|
+
@pydantic.field_validator("code")
|
36
|
+
@classmethod
|
35
37
|
def load_quantum_program(
|
36
|
-
cls, code: Union[CodeType, IonqQuantumCircuit], values:
|
38
|
+
cls, code: Union[CodeType, IonqQuantumCircuit], values: ValidationInfo
|
37
39
|
) -> CodeType:
|
38
|
-
syntax = values.get("syntax")
|
40
|
+
syntax = values.data.get("syntax")
|
39
41
|
if isinstance(code, IonqQuantumCircuit):
|
40
42
|
if syntax != QuantumInstructionSet.IONQ:
|
41
43
|
raise ClassiqValueError(
|
42
44
|
f"Invalid code type {type(code)} for syntax: {syntax}"
|
43
45
|
)
|
44
|
-
return code.
|
46
|
+
return code.model_dump_json()
|
45
47
|
|
46
48
|
return code
|
47
49
|
|
@@ -56,41 +58,44 @@ class QuantumCode(QuantumBaseCode):
|
|
56
58
|
description="The map of outputs to their qubits in the circuit.",
|
57
59
|
)
|
58
60
|
registers_initialization: Optional[RegistersInitialization] = pydantic.Field(
|
59
|
-
|
61
|
+
default=None,
|
60
62
|
description="Initial conditions for the different registers in the circuit.",
|
61
63
|
)
|
62
64
|
synthesis_execution_data: Optional[ExecutionData] = pydantic.Field(default=None)
|
63
65
|
synthesis_execution_arguments: Arguments = pydantic.Field(default_factory=dict)
|
66
|
+
model_config = ConfigDict(validate_assignment=True)
|
64
67
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
@pydantic.validator("arguments")
|
68
|
+
@pydantic.field_validator("arguments", mode="before")
|
69
|
+
@classmethod
|
69
70
|
def validate_arguments(
|
70
|
-
cls, arguments: MultipleArguments,
|
71
|
+
cls, arguments: MultipleArguments, info: ValidationInfo
|
71
72
|
) -> MultipleArguments:
|
72
|
-
if arguments and
|
73
|
+
if arguments and info.data.get("syntax") not in (
|
73
74
|
QuantumInstructionSet.QSHARP,
|
74
75
|
QuantumInstructionSet.QASM,
|
75
76
|
):
|
76
77
|
raise ClassiqValueError("Only QASM or Q# programs support arguments")
|
77
78
|
|
78
|
-
if
|
79
|
+
if (
|
80
|
+
info.data.get("syntax") == QuantumInstructionSet.QSHARP
|
81
|
+
and len(arguments) > 1
|
82
|
+
):
|
79
83
|
raise ClassiqValueError(
|
80
84
|
f"Q# programs supports only one group of arguments. {len(arguments)} given"
|
81
85
|
)
|
82
86
|
|
83
87
|
return arguments
|
84
88
|
|
85
|
-
@pydantic.
|
89
|
+
@pydantic.field_validator("synthesis_execution_data")
|
90
|
+
@classmethod
|
86
91
|
def validate_synthesis_execution_data(
|
87
92
|
cls,
|
88
93
|
synthesis_execution_data: Optional[ExecutionData],
|
89
|
-
values:
|
94
|
+
values: ValidationInfo,
|
90
95
|
) -> Optional[ExecutionData]:
|
91
96
|
if (
|
92
97
|
synthesis_execution_data is not None
|
93
|
-
and values.get("syntax") is not QuantumInstructionSet.QASM
|
98
|
+
and values.data.get("syntax") is not QuantumInstructionSet.QASM
|
94
99
|
):
|
95
100
|
raise ClassiqValueError("Only QASM supports the requested configuration")
|
96
101
|
|
@@ -1,6 +1,7 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import List
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
from typing_extensions import Self
|
4
5
|
|
5
6
|
from classiq.interface.exceptions import ClassiqStateInitializationError
|
6
7
|
from classiq.interface.generator.arith import number_utils
|
@@ -15,19 +16,18 @@ class RegisterInitialization(pydantic.BaseModel):
|
|
15
16
|
qubits: List[int]
|
16
17
|
initial_condition: pydantic.NonNegativeInt
|
17
18
|
|
18
|
-
@pydantic.
|
19
|
+
@pydantic.field_validator("initial_condition", mode="before")
|
20
|
+
@classmethod
|
19
21
|
def _validate_initial_condition(cls, value: int) -> int:
|
20
22
|
if not isinstance(value, int) or value < 0:
|
21
23
|
raise ClassiqStateInitializationError(_NON_INTEGER_INITIALIZATION_ERROR_MSG)
|
22
24
|
return value
|
23
25
|
|
24
|
-
@pydantic.
|
25
|
-
def _validate_register_initialization(
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
initial_condition: int = values.get("initial_condition", 0)
|
30
|
-
name: str = values.get("name", "")
|
26
|
+
@pydantic.model_validator(mode="after")
|
27
|
+
def _validate_register_initialization(self) -> Self:
|
28
|
+
qubits: List[int] = self.qubits or []
|
29
|
+
initial_condition: int = self.initial_condition or 0
|
30
|
+
name: str = self.name or ""
|
31
31
|
|
32
32
|
initial_condition_length = number_utils.size(initial_condition)
|
33
33
|
register_length = len(qubits)
|
@@ -35,4 +35,4 @@ class RegisterInitialization(pydantic.BaseModel):
|
|
35
35
|
raise ClassiqStateInitializationError(
|
36
36
|
f"Register {name} has {register_length} qubits, which is not enough to represent the number {initial_condition}."
|
37
37
|
)
|
38
|
-
return
|
38
|
+
return self
|
@@ -16,7 +16,7 @@ from typing import (
|
|
16
16
|
|
17
17
|
import pydantic
|
18
18
|
from pydantic import BaseModel
|
19
|
-
from typing_extensions import TypeAlias
|
19
|
+
from typing_extensions import Self, TypeAlias
|
20
20
|
|
21
21
|
from classiq.interface.exceptions import ClassiqError
|
22
22
|
from classiq.interface.executor.quantum_code import OutputQubitsMap, Qubits
|
@@ -24,6 +24,7 @@ from classiq.interface.generator.arith import number_utils
|
|
24
24
|
from classiq.interface.generator.complex_type import Complex
|
25
25
|
from classiq.interface.generator.functions.classical_type import QmodPyObject
|
26
26
|
from classiq.interface.helpers.custom_pydantic_types import PydanticNonNegIntTuple
|
27
|
+
from classiq.interface.helpers.dotdict import get_recursive_dotdict
|
27
28
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
28
29
|
|
29
30
|
_ILLEGAL_QUBIT_ERROR_MSG: str = "Illegal qubit index requested"
|
@@ -37,16 +38,26 @@ MeasuredShots: TypeAlias = pydantic.NonNegativeInt
|
|
37
38
|
ParsedState: TypeAlias = Mapping[Name, RegisterValue]
|
38
39
|
ParsedStates: TypeAlias = Mapping[State, ParsedState]
|
39
40
|
Counts: TypeAlias = Dict[State, MeasuredShots]
|
40
|
-
StateVector: TypeAlias = Optional[Dict[str,
|
41
|
+
StateVector: TypeAlias = Optional[Dict[str, Complex]]
|
42
|
+
|
43
|
+
if TYPE_CHECKING:
|
44
|
+
DotAccessParsedState = Mapping[Name, Any]
|
45
|
+
else:
|
46
|
+
DotAccessParsedState = ParsedState
|
41
47
|
|
42
48
|
|
43
49
|
class SampledState(BaseModel):
|
44
|
-
state:
|
50
|
+
state: DotAccessParsedState
|
45
51
|
shots: MeasuredShots
|
46
52
|
|
47
53
|
def __repr__(self) -> str:
|
48
54
|
return f"{self.state}: {self.shots}"
|
49
55
|
|
56
|
+
@pydantic.field_validator("state", mode="after")
|
57
|
+
@classmethod
|
58
|
+
def _convert_state_to_dotdict(cls, state: ParsedState) -> DotAccessParsedState:
|
59
|
+
return {name: get_recursive_dotdict(value) for name, value in state.items()}
|
60
|
+
|
50
61
|
|
51
62
|
ParsedCounts: TypeAlias = List[SampledState]
|
52
63
|
|
@@ -60,7 +71,7 @@ class SimulatedState(BaseModel):
|
|
60
71
|
return self.state[item]
|
61
72
|
|
62
73
|
|
63
|
-
SimulatedState.
|
74
|
+
SimulatedState.model_rebuild()
|
64
75
|
ParsedStateVector: TypeAlias = List[SimulatedState]
|
65
76
|
|
66
77
|
|
@@ -170,7 +181,7 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
170
181
|
default=None,
|
171
182
|
description="The state vector when executed on a simulator, with LSB right qubit order",
|
172
183
|
)
|
173
|
-
parsed_state_vector_states: ParsedStates = pydantic.Field(
|
184
|
+
parsed_state_vector_states: Optional[ParsedStates] = pydantic.Field(
|
174
185
|
default=None,
|
175
186
|
description="A mapping between the raw states of the state vector (bitstrings) to their parsed states (registers' values)",
|
176
187
|
)
|
@@ -182,22 +193,23 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
182
193
|
default=None, description="The total number of shots the circuit was executed"
|
183
194
|
)
|
184
195
|
|
185
|
-
@pydantic.
|
196
|
+
@pydantic.field_validator("counts", mode="after")
|
197
|
+
@classmethod
|
186
198
|
def _clean_spaces_from_counts_keys(cls, v: Counts) -> Counts:
|
187
199
|
if not v or " " not in list(v.keys())[0]:
|
188
200
|
return v
|
189
201
|
return {state.replace(" ", ""): v[state] for state in v}
|
190
202
|
|
191
|
-
@pydantic.
|
192
|
-
def _validate_num_shots(
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
return
|
203
|
+
@pydantic.model_validator(mode="after")
|
204
|
+
def _validate_num_shots(self) -> Self:
|
205
|
+
if isinstance(self, ExecutionDetails):
|
206
|
+
if self.num_shots is not None:
|
207
|
+
return self
|
208
|
+
counts = self.counts
|
209
|
+
if not counts:
|
210
|
+
return self
|
211
|
+
self.num_shots = sum(shots for _, shots in counts.items())
|
212
|
+
return self
|
201
213
|
|
202
214
|
@property
|
203
215
|
def parsed_counts(self) -> ParsedCounts:
|
@@ -205,6 +217,8 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
205
217
|
|
206
218
|
@property
|
207
219
|
def parsed_state_vector(self) -> Optional[ParsedStateVector]:
|
220
|
+
if TYPE_CHECKING:
|
221
|
+
assert self.parsed_state_vector_states is not None
|
208
222
|
return prepare_parsed_state_vector(
|
209
223
|
self.state_vector, self.parsed_state_vector_states
|
210
224
|
)
|
@@ -297,7 +311,7 @@ class MultipleExecutionDetails(VersionedModel):
|
|
297
311
|
return self.details[index]
|
298
312
|
|
299
313
|
|
300
|
-
class EstimationMetadata(BaseModel, extra=
|
314
|
+
class EstimationMetadata(BaseModel, extra="allow"):
|
301
315
|
shots: Optional[pydantic.NonNegativeInt] = None
|
302
316
|
remapped_qubits: bool = False
|
303
317
|
input_qubit_map: Optional[List[PydanticNonNegIntTuple]] = None
|
@@ -1,6 +1,8 @@
|
|
1
1
|
from typing import Any, Dict, Optional, Union
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
from pydantic import ConfigDict
|
5
|
+
from pydantic_core.core_schema import ValidationInfo
|
4
6
|
|
5
7
|
from classiq.interface.exceptions import ClassiqValueError
|
6
8
|
from classiq.interface.generator.expressions.enums.finance_functions import (
|
@@ -20,9 +22,7 @@ class FunctionCondition(pydantic.BaseModel):
|
|
20
22
|
default=False,
|
21
23
|
description="When true, function is set when input is larger to threshold and otherwise 0. Default is False.",
|
22
24
|
)
|
23
|
-
|
24
|
-
class Config:
|
25
|
-
frozen = True
|
25
|
+
model_config = ConfigDict(frozen=True)
|
26
26
|
|
27
27
|
|
28
28
|
class FinanceFunctionInput(pydantic.BaseModel):
|
@@ -50,24 +50,33 @@ class FinanceFunctionInput(pydantic.BaseModel):
|
|
50
50
|
description="The required probability on the tail of the distribution (1 - percentile)",
|
51
51
|
)
|
52
52
|
|
53
|
-
@pydantic.
|
54
|
-
|
55
|
-
|
56
|
-
if
|
57
|
-
|
58
|
-
|
53
|
+
@pydantic.model_validator(mode="before")
|
54
|
+
@classmethod
|
55
|
+
def _convert_f_if_str(cls, values: Any, info: ValidationInfo) -> Dict[str, Any]:
|
56
|
+
if isinstance(values, dict):
|
57
|
+
f = values.get("f")
|
58
|
+
elif isinstance(values, FinanceFunctionInput):
|
59
|
+
f = values.f
|
60
|
+
values = values.model_dump()
|
61
|
+
else:
|
62
|
+
f = info.data.get("f")
|
63
|
+
if isinstance(f, str) and f in get_finance_function_dict():
|
64
|
+
values["f"] = get_finance_function_dict()[f]
|
65
|
+
return values
|
59
66
|
|
60
|
-
@pydantic.
|
67
|
+
@pydantic.field_validator("use_chebyshev_polynomial_approximation", mode="before")
|
68
|
+
@classmethod
|
61
69
|
def _validate_polynomial_flag(
|
62
|
-
cls, use_chebyshev_flag: bool,
|
70
|
+
cls, use_chebyshev_flag: bool, info: ValidationInfo
|
63
71
|
) -> bool:
|
64
|
-
if use_chebyshev_flag ^ (
|
72
|
+
if use_chebyshev_flag ^ (info.data.get("polynomial_degree") is None):
|
65
73
|
return use_chebyshev_flag
|
66
74
|
raise ClassiqValueError(
|
67
75
|
"Degree must be positive and use_chebyshev_polynomial_approximation set to True"
|
68
76
|
)
|
69
77
|
|
70
|
-
@pydantic.
|
78
|
+
@pydantic.field_validator("f", mode="before")
|
79
|
+
@classmethod
|
71
80
|
def _validate_finance_function(
|
72
81
|
cls, f: Union[int, str, "FinanceFunctionType"]
|
73
82
|
) -> FinanceFunctionType:
|
@@ -77,17 +86,17 @@ class FinanceFunctionInput(pydantic.BaseModel):
|
|
77
86
|
return FinanceFunctionType(f)
|
78
87
|
return get_finance_function_dict()[f]
|
79
88
|
|
80
|
-
@pydantic.
|
89
|
+
@pydantic.field_validator("tail_probability", mode="before")
|
90
|
+
@classmethod
|
81
91
|
def _validate_tail_probability_assignment_for_shortfall(
|
82
92
|
cls,
|
83
93
|
tail_probability: Optional[PydanticNonZeroProbabilityFloat],
|
84
|
-
|
94
|
+
info: ValidationInfo,
|
85
95
|
) -> Optional[PydanticNonZeroProbabilityFloat]:
|
86
|
-
if
|
96
|
+
if info.data.get("f") == FinanceFunctionType.SHORTFALL and not tail_probability:
|
87
97
|
raise ClassiqValueError(
|
88
98
|
"Tail probability must be set for expected shortfall"
|
89
99
|
)
|
90
100
|
return tail_probability
|
91
101
|
|
92
|
-
|
93
|
-
frozen = True
|
102
|
+
model_config = ConfigDict(frozen=True)
|
@@ -2,6 +2,7 @@ from typing import Literal, Tuple
|
|
2
2
|
|
3
3
|
import numpy as np
|
4
4
|
import pydantic
|
5
|
+
from pydantic import ConfigDict
|
5
6
|
|
6
7
|
from classiq.interface.finance.model_input import FinanceModelInput
|
7
8
|
|
@@ -36,5 +37,4 @@ class LogNormalModelInput(FinanceModelInput):
|
|
36
37
|
def num_output_qubits(self) -> int:
|
37
38
|
return self.num_qubits
|
38
39
|
|
39
|
-
|
40
|
-
frozen = True
|
40
|
+
model_config = ConfigDict(frozen=True)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import abc
|
2
2
|
from typing import Tuple
|
3
3
|
|
4
|
+
from pydantic import ConfigDict
|
5
|
+
|
4
6
|
from classiq.interface.helpers.hashable_pydantic_base_model import (
|
5
7
|
HashablePydanticBaseModel,
|
6
8
|
)
|
@@ -13,8 +15,7 @@ class FinanceModelInput(HashablePydanticBaseModel):
|
|
13
15
|
def num_output_qubits(self) -> int:
|
14
16
|
return 0
|
15
17
|
|
16
|
-
|
17
|
-
frozen = True
|
18
|
+
model_config = ConfigDict(frozen=True)
|
18
19
|
|
19
20
|
@property
|
20
21
|
@abc.abstractmethod
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import re
|
2
|
-
from typing import
|
2
|
+
from typing import get_args
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
import sympy
|
6
|
+
from typing_extensions import Self
|
6
7
|
|
7
8
|
from classiq.interface.enum_utils import StrEnum
|
8
9
|
from classiq.interface.exceptions import ClassiqValueError
|
@@ -50,7 +51,8 @@ class AmplitudeLoading(FunctionParams):
|
|
50
51
|
description="Implementation options.",
|
51
52
|
)
|
52
53
|
|
53
|
-
@pydantic.
|
54
|
+
@pydantic.field_validator("expression", mode="before")
|
55
|
+
@classmethod
|
54
56
|
def validate_coefficient(cls, expression: str) -> str:
|
55
57
|
if isinstance(expression, str):
|
56
58
|
# We validate the given value is legal and does not contain code that will be executed in our BE.
|
@@ -65,9 +67,9 @@ class AmplitudeLoading(FunctionParams):
|
|
65
67
|
return str(expression)
|
66
68
|
return expression
|
67
69
|
|
68
|
-
@pydantic.
|
69
|
-
def check_all_variable_are_defined(
|
70
|
-
expression =
|
70
|
+
@pydantic.model_validator(mode="after")
|
71
|
+
def check_all_variable_are_defined(self) -> Self:
|
72
|
+
expression = self.expression or ""
|
71
73
|
literals = set(re.findall(SUPPORTED_VAR_NAMES_REG, expression))
|
72
74
|
|
73
75
|
not_allowed = literals.intersection(FORBIDDEN_LITERALS) - BOOLEAN_LITERALS
|
@@ -79,7 +81,7 @@ class AmplitudeLoading(FunctionParams):
|
|
79
81
|
|
80
82
|
if len(variables) != 1:
|
81
83
|
raise ClassiqValueError(f"{variables} must contain exactly single variable")
|
82
|
-
return
|
84
|
+
return self
|
83
85
|
|
84
86
|
def _create_ios(self) -> None:
|
85
87
|
self._inputs = {
|
@@ -1,6 +1,9 @@
|
|
1
1
|
from typing import Tuple, Union
|
2
2
|
|
3
3
|
from classiq.interface.generator.arith import number_utils
|
4
|
+
from classiq.interface.generator.arith.number_utils import (
|
5
|
+
get_int_representation_and_fraction_places,
|
6
|
+
)
|
4
7
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
5
8
|
|
6
9
|
RegisterOrConst = Union[RegisterArithmeticInfo, float]
|
@@ -73,3 +76,24 @@ def as_arithmetic_info(
|
|
73
76
|
fraction_places=number_utils.fraction_places(arg),
|
74
77
|
bounds=(arg, arg) if with_bounds else None,
|
75
78
|
)
|
79
|
+
|
80
|
+
|
81
|
+
def unsigned_integer_interpretation(
|
82
|
+
value: float, register: RegisterArithmeticInfo
|
83
|
+
) -> int:
|
84
|
+
int_val, fraction_digits = get_int_representation_and_fraction_places(value)
|
85
|
+
|
86
|
+
# align fraction digits
|
87
|
+
fraction_digits_diff = register.fraction_places - fraction_digits
|
88
|
+
if fraction_digits_diff < 0:
|
89
|
+
int_val >>= -fraction_digits_diff
|
90
|
+
else:
|
91
|
+
int_val <<= fraction_digits_diff
|
92
|
+
|
93
|
+
# extend sign bit
|
94
|
+
if int(value) < 0:
|
95
|
+
bin_val = number_utils.binary_string(int_val)
|
96
|
+
bin_val += "1" * (register.size - len(bin_val))
|
97
|
+
int_val = number_utils.binary_to_int(bin_val[::-1])
|
98
|
+
|
99
|
+
return int_val
|