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
@@ -0,0 +1,84 @@
|
|
1
|
+
import math
|
2
|
+
from typing import Callable, Optional, Tuple, Type
|
3
|
+
|
4
|
+
import numpy as np
|
5
|
+
import scipy
|
6
|
+
|
7
|
+
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
8
|
+
from classiq.interface.executor.result import ExecutionDetails
|
9
|
+
from classiq.interface.model.model import SerializedModel
|
10
|
+
|
11
|
+
from classiq.execution import ExecutionSession
|
12
|
+
from classiq.qmod.builtins.functions import (
|
13
|
+
RX,
|
14
|
+
allocate,
|
15
|
+
apply_to_all,
|
16
|
+
hadamard_transform,
|
17
|
+
)
|
18
|
+
from classiq.qmod.builtins.operations import phase, repeat
|
19
|
+
from classiq.qmod.cparam import CReal
|
20
|
+
from classiq.qmod.create_model_function import create_model
|
21
|
+
from classiq.qmod.qfunc import qfunc
|
22
|
+
from classiq.qmod.qmod_parameter import CArray
|
23
|
+
from classiq.qmod.qmod_variable import Output, QVar
|
24
|
+
from classiq.synthesis import SerializedQuantumProgram, synthesize
|
25
|
+
|
26
|
+
|
27
|
+
def execute_qaoa(
|
28
|
+
problem_vars: Type[QVar],
|
29
|
+
cost_func: Callable,
|
30
|
+
num_layers: int,
|
31
|
+
maxiter: int,
|
32
|
+
execution_preferences: Optional[ExecutionPreferences] = None,
|
33
|
+
) -> Tuple[SerializedModel, SerializedQuantumProgram, ExecutionDetails]:
|
34
|
+
"""
|
35
|
+
Implements a simple QAOA algorithm, including the creation and synthesis of the QAOA
|
36
|
+
ansatz and the classical optimization loop.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
problem_vars: the quantum type (scalar, array, or struct) of the problem variable(s)
|
40
|
+
cost_func: the arithmetic expression that evaluates the cost given an instance of the problem_vars type
|
41
|
+
num_layers: the number of layers of the QAOA ansatz
|
42
|
+
maxiter: the maximum number of iterations for the classical optimization loop
|
43
|
+
execution_preferences: the execution settings for running the QAOA ansatz
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
a tuple containing the model of the QAOA ansatz, the corresponding synthesized quantum program,
|
47
|
+
and the result of the execution with the optimized parameters
|
48
|
+
"""
|
49
|
+
|
50
|
+
@qfunc
|
51
|
+
def main(
|
52
|
+
params: CArray[CReal, num_layers * 2], # type:ignore[valid-type]
|
53
|
+
v: Output[problem_vars], # type:ignore[valid-type]
|
54
|
+
) -> None:
|
55
|
+
allocate(v.size, v) # type:ignore[attr-defined]
|
56
|
+
hadamard_transform(v)
|
57
|
+
repeat(
|
58
|
+
num_layers,
|
59
|
+
lambda i: [ # type:ignore[arg-type]
|
60
|
+
phase(-cost_func(v), params[i]), # type:ignore[func-returns-value]
|
61
|
+
apply_to_all(lambda q: RX(params[num_layers + i], q), v),
|
62
|
+
],
|
63
|
+
)
|
64
|
+
|
65
|
+
model = create_model(main)
|
66
|
+
qprog = synthesize(model)
|
67
|
+
|
68
|
+
es = ExecutionSession(qprog, execution_preferences)
|
69
|
+
initial_params = (
|
70
|
+
np.concatenate((np.linspace(0, 1, num_layers), np.linspace(1, 0, num_layers)))
|
71
|
+
* math.pi
|
72
|
+
)
|
73
|
+
final_params = scipy.optimize.minimize(
|
74
|
+
lambda params: es.estimate_cost(
|
75
|
+
lambda state: cost_func(state["v"]),
|
76
|
+
{"params": params.tolist()},
|
77
|
+
),
|
78
|
+
x0=initial_params,
|
79
|
+
method="COBYLA",
|
80
|
+
options={"maxiter": maxiter},
|
81
|
+
).x.tolist()
|
82
|
+
result = es.sample({"params": final_params})
|
83
|
+
|
84
|
+
return model, qprog, result
|
classiq/executor.py
CHANGED
@@ -27,7 +27,7 @@ BackendPreferencesAndResult: TypeAlias = Tuple[
|
|
27
27
|
def _parse_serialized_qprog(
|
28
28
|
quantum_program: SerializedQuantumProgram,
|
29
29
|
) -> QuantumProgram:
|
30
|
-
return QuantumProgram.
|
30
|
+
return QuantumProgram.model_validate_json(quantum_program)
|
31
31
|
|
32
32
|
|
33
33
|
async def execute_async(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
|
@@ -46,7 +46,7 @@ def execute(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
|
|
46
46
|
Returns:
|
47
47
|
ExecutionJob: The result of the execution.
|
48
48
|
|
49
|
-
For examples please see [Execution Documentation](https://docs.classiq.io/latest/
|
49
|
+
For examples please see [Execution Documentation](https://docs.classiq.io/latest/user-guide/executor/)
|
50
50
|
"""
|
51
51
|
return async_utils.run(execute_async(quantum_program))
|
52
52
|
|
@@ -57,7 +57,7 @@ def set_quantum_program_execution_preferences(
|
|
57
57
|
) -> SerializedQuantumProgram:
|
58
58
|
circuit = _parse_serialized_qprog(quantum_program)
|
59
59
|
circuit.model.execution_preferences = preferences
|
60
|
-
return SerializedQuantumProgram(circuit.
|
60
|
+
return SerializedQuantumProgram(circuit.model_dump_json())
|
61
61
|
|
62
62
|
|
63
63
|
__all__ = [
|
classiq/interface/_version.py
CHANGED
@@ -2,7 +2,7 @@ from typing import Dict, List, Optional
|
|
2
2
|
|
3
3
|
import numpy
|
4
4
|
import pydantic
|
5
|
-
from pydantic import
|
5
|
+
from pydantic import ConfigDict, Field, StringConstraints
|
6
6
|
from typing_extensions import Annotated
|
7
7
|
|
8
8
|
from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
|
@@ -36,7 +36,8 @@ class HardwareListParams(pydantic.BaseModel):
|
|
36
36
|
providers: List[Provider]
|
37
37
|
from_ide: bool = Field(default=False)
|
38
38
|
|
39
|
-
@pydantic.
|
39
|
+
@pydantic.field_validator("providers")
|
40
|
+
@classmethod
|
40
41
|
def set_default_providers(
|
41
42
|
cls, providers: Optional[List[AnalyzerProviderVendor]]
|
42
43
|
) -> List[AnalyzerProviderVendor]:
|
@@ -55,8 +56,12 @@ class AnalysisOptionalDevicesParams(HardwareListParams):
|
|
55
56
|
|
56
57
|
|
57
58
|
class GateNamsMapping(pydantic.BaseModel):
|
58
|
-
qasm_name: Annotated[
|
59
|
-
|
59
|
+
qasm_name: Annotated[
|
60
|
+
str, Annotated[str, StringConstraints(max_length=MAX_NAME_LENGTH)]
|
61
|
+
]
|
62
|
+
display_name: Annotated[
|
63
|
+
str, Annotated[str, StringConstraints(max_length=MAX_NAME_LENGTH)]
|
64
|
+
]
|
60
65
|
|
61
66
|
|
62
67
|
class LatexParams(AnalysisParams):
|
@@ -66,7 +71,7 @@ class LatexParams(AnalysisParams):
|
|
66
71
|
|
67
72
|
|
68
73
|
class AnalysisHardwareTranspilationParams(pydantic.BaseModel):
|
69
|
-
hardware_data: Optional[SynthesisHardwareData]
|
74
|
+
hardware_data: Optional[SynthesisHardwareData] = None
|
70
75
|
random_seed: int
|
71
76
|
transpilation_option: TranspilationOption
|
72
77
|
|
@@ -91,13 +96,18 @@ class CircuitAnalysisHardwareParams(AnalysisParams):
|
|
91
96
|
|
92
97
|
class AnalysisRBParams(pydantic.BaseModel):
|
93
98
|
hardware: str
|
94
|
-
counts: List[
|
95
|
-
|
99
|
+
counts: List[
|
100
|
+
Dict[
|
101
|
+
str, Annotated[int, Annotated[int, Field(strict=True, gt=0, le=MAX_COUNTS)]]
|
102
|
+
]
|
103
|
+
]
|
104
|
+
num_clifford: List[
|
105
|
+
Annotated[int, Annotated[int, Field(strict=True, gt=0, le=MAX_NUM_CLIFFORD)]]
|
106
|
+
]
|
96
107
|
|
97
108
|
|
98
109
|
class ChemistryGenerationParams(pydantic.BaseModel):
|
99
|
-
|
100
|
-
title = "Chemistry"
|
110
|
+
model_config = ConfigDict(title="Chemistry")
|
101
111
|
|
102
112
|
molecule: MoleculeProblem = pydantic.Field(
|
103
113
|
title="Molecule",
|
@@ -17,16 +17,23 @@ class CytoScapePosition(pydantic.BaseModel):
|
|
17
17
|
|
18
18
|
class CytoScapeEdgeData(pydantic.BaseModel):
|
19
19
|
source: str = pydantic.Field(
|
20
|
-
default
|
20
|
+
default=" ", description="the Id of the Node that is the Source of the edge"
|
21
21
|
)
|
22
22
|
target: str = pydantic.Field(
|
23
|
-
default
|
23
|
+
default=" ", description="the Id of the Node that is the Target the edge"
|
24
24
|
)
|
25
25
|
|
26
|
+
@pydantic.model_validator(mode="before")
|
27
|
+
@classmethod
|
28
|
+
def _validate_values(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
29
|
+
values["source"] = str(values["source"]) or " "
|
30
|
+
values["target"] = str(values["target"]) or " "
|
31
|
+
return values
|
32
|
+
|
26
33
|
|
27
34
|
class CytoScapeEdge(pydantic.BaseModel):
|
28
35
|
data: CytoScapeEdgeData = pydantic.Field(
|
29
|
-
|
36
|
+
description="Edge's Data, mainly the source and target of the Edge"
|
30
37
|
)
|
31
38
|
|
32
39
|
|
@@ -3,7 +3,7 @@ from uuid import UUID
|
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
from pydantic import Field
|
6
|
-
from typing_extensions import Annotated
|
6
|
+
from typing_extensions import Annotated, Self
|
7
7
|
|
8
8
|
from classiq.interface.analyzer.analysis_params import MAX_FILE_LENGTH
|
9
9
|
from classiq.interface.enum_utils import StrEnum
|
@@ -74,12 +74,13 @@ class HardwareComparisonInformation(pydantic.BaseModel):
|
|
74
74
|
default=..., description="Number of total gates."
|
75
75
|
)
|
76
76
|
|
77
|
-
@pydantic.
|
78
|
-
def validate_equal_length(
|
77
|
+
@pydantic.model_validator(mode="after")
|
78
|
+
def validate_equal_length(self) -> Self:
|
79
|
+
values = self.model_dump()
|
79
80
|
lengths = list(map(len, values.values()))
|
80
81
|
if len(set(lengths)) != 1:
|
81
82
|
raise ClassiqValueError("All lists should have the same length")
|
82
|
-
return
|
83
|
+
return self
|
83
84
|
|
84
85
|
|
85
86
|
# TODO: copy the types for `devices` & `providers` from `HardwareComparisonInformation`
|
@@ -112,7 +113,7 @@ HardwareComparisonGraphType = Annotated[
|
|
112
113
|
]
|
113
114
|
|
114
115
|
_HARDWARE_COMPARISON_TABLE_COLUMNS_NAMES: Dict[str, str] = {
|
115
|
-
s.upper(): s.capitalize() for s in SingleHardwareInformation.
|
116
|
+
s.upper(): s.capitalize() for s in SingleHardwareInformation.model_fields
|
116
117
|
}
|
117
118
|
|
118
119
|
|
@@ -1,20 +1,18 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
2
|
from typing import (
|
3
|
-
TYPE_CHECKING,
|
4
3
|
Any,
|
5
4
|
Iterable as IterableType,
|
6
5
|
List,
|
7
6
|
Optional,
|
8
7
|
Tuple,
|
8
|
+
Type,
|
9
9
|
Union,
|
10
10
|
)
|
11
11
|
|
12
12
|
import numpy as np
|
13
13
|
import pydantic
|
14
14
|
from numpy.typing import ArrayLike
|
15
|
-
|
16
|
-
if TYPE_CHECKING:
|
17
|
-
from pydantic.typing import AnyClassMethod
|
15
|
+
from pydantic import ConfigDict, field_validator
|
18
16
|
|
19
17
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
20
18
|
|
@@ -33,8 +31,12 @@ def listify(obj: Union[IterableType, ArrayLike]) -> list:
|
|
33
31
|
return list(obj) # type: ignore[arg-type]
|
34
32
|
|
35
33
|
|
36
|
-
def validate_array_to_list(name: str) ->
|
37
|
-
|
34
|
+
def validate_array_to_list(name: str) -> Any:
|
35
|
+
@field_validator(name, mode="before")
|
36
|
+
def _listify(cls: Type[pydantic.BaseModel], value: Any) -> Any:
|
37
|
+
return listify(value)
|
38
|
+
|
39
|
+
return _listify
|
38
40
|
|
39
41
|
|
40
42
|
Shape = Tuple[int, ...]
|
@@ -89,16 +91,15 @@ class QSVMData(VersionedModel):
|
|
89
91
|
data: DataList
|
90
92
|
labels: Optional[LabelsInt] = None
|
91
93
|
internal_state: Optional[QSVMInternalState] = None
|
94
|
+
model_config = ConfigDict(extra="forbid")
|
92
95
|
|
93
|
-
|
94
|
-
|
95
|
-
extra = "forbid"
|
96
|
-
|
97
|
-
@pydantic.validator("data", pre=True)
|
96
|
+
@pydantic.field_validator("data", mode="before")
|
97
|
+
@classmethod
|
98
98
|
def set_data(cls, data: Union[IterableType, ArrayLike]) -> list:
|
99
99
|
return listify(data)
|
100
100
|
|
101
|
-
@pydantic.
|
101
|
+
@pydantic.field_validator("labels", mode="before")
|
102
|
+
@classmethod
|
102
103
|
def set_labels(
|
103
104
|
cls, labels: Optional[Union[IterableType, ArrayLike]]
|
104
105
|
) -> Optional[list]:
|
@@ -3,7 +3,8 @@ from __future__ import annotations
|
|
3
3
|
from typing import Any, Dict, Iterable, List, Optional, Union
|
4
4
|
|
5
5
|
import pydantic
|
6
|
-
from pydantic import BaseModel
|
6
|
+
from pydantic import BaseModel
|
7
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
7
8
|
|
8
9
|
from classiq.interface.backend import pydantic_backend
|
9
10
|
from classiq.interface.backend.quantum_backend_providers import (
|
@@ -21,7 +22,6 @@ from classiq.interface.backend.quantum_backend_providers import (
|
|
21
22
|
)
|
22
23
|
from classiq.interface.exceptions import ClassiqValueError
|
23
24
|
from classiq.interface.hardware import Provider
|
24
|
-
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
25
25
|
|
26
26
|
|
27
27
|
class BackendPreferences(BaseModel):
|
@@ -36,10 +36,7 @@ class BackendPreferences(BaseModel):
|
|
36
36
|
backend_name (str): Name of the requested backend or target.
|
37
37
|
"""
|
38
38
|
|
39
|
-
|
40
|
-
# in the subclass, it shouldn't be dumped with exclude_unset. This causes this field not to appear.
|
41
|
-
# For example: don't use obj.dict(exclude_unset=True).
|
42
|
-
backend_service_provider: str = pydantic.Field(
|
39
|
+
backend_service_provider: ProviderVendor = pydantic.Field(
|
43
40
|
..., description="Provider company or cloud for the requested backend."
|
44
41
|
)
|
45
42
|
backend_name: str = pydantic.Field(
|
@@ -50,12 +47,6 @@ class BackendPreferences(BaseModel):
|
|
50
47
|
def hw_provider(self) -> Provider:
|
51
48
|
return Provider(self.backend_service_provider)
|
52
49
|
|
53
|
-
@pydantic.validator("backend_service_provider", pre=True)
|
54
|
-
def validate_backend_service_provider(
|
55
|
-
cls, backend_service_provider: Any
|
56
|
-
) -> Provider:
|
57
|
-
return validate_backend_service_provider(backend_service_provider)
|
58
|
-
|
59
50
|
@classmethod
|
60
51
|
def batch_preferences(
|
61
52
|
cls, *, backend_names: Iterable[str], **kwargs: Any
|
@@ -110,7 +101,9 @@ class AliceBobBackendPreferences(BackendPreferences):
|
|
110
101
|
For more details, refer to the [Alice&Bob Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/alice-and-bob-backends/).
|
111
102
|
"""
|
112
103
|
|
113
|
-
backend_service_provider: ProviderTypeVendor.ALICE_BOB
|
104
|
+
backend_service_provider: ProviderTypeVendor.ALICE_BOB = pydantic.Field(
|
105
|
+
default=ProviderVendor.ALICE_AND_BOB
|
106
|
+
)
|
114
107
|
distance: Optional[int] = pydantic.Field(
|
115
108
|
default=None, description="Repetition code distance"
|
116
109
|
)
|
@@ -127,12 +120,6 @@ class AliceBobBackendPreferences(BackendPreferences):
|
|
127
120
|
..., description="AliceBob API key"
|
128
121
|
)
|
129
122
|
|
130
|
-
@pydantic.root_validator(pre=True)
|
131
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
132
|
-
return values_with_discriminator(
|
133
|
-
values, "backend_service_provider", ProviderVendor.ALICE_AND_BOB
|
134
|
-
)
|
135
|
-
|
136
123
|
@property
|
137
124
|
def parameters(self) -> Dict[str, Any]:
|
138
125
|
parameters = {
|
@@ -154,13 +141,9 @@ class ClassiqBackendPreferences(BackendPreferences):
|
|
154
141
|
For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/classiq-backends/).
|
155
142
|
"""
|
156
143
|
|
157
|
-
backend_service_provider: ProviderTypeVendor.CLASSIQ
|
158
|
-
|
159
|
-
|
160
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
161
|
-
return values_with_discriminator(
|
162
|
-
values, "backend_service_provider", ProviderVendor.CLASSIQ
|
163
|
-
)
|
144
|
+
backend_service_provider: ProviderTypeVendor.CLASSIQ = pydantic.Field(
|
145
|
+
default=ProviderVendor.CLASSIQ
|
146
|
+
)
|
164
147
|
|
165
148
|
def is_nvidia_backend(self) -> bool:
|
166
149
|
return self.backend_name in list(ClassiqNvidiaBackendNames)
|
@@ -197,7 +180,9 @@ class AwsBackendPreferences(BackendPreferences):
|
|
197
180
|
[AwsBackendPreferences examples](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/amazon-backends/?h=awsbackend#usage)
|
198
181
|
"""
|
199
182
|
|
200
|
-
backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET
|
183
|
+
backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET = pydantic.Field(
|
184
|
+
default=ProviderVendor.AMAZON_BRAKET
|
185
|
+
)
|
201
186
|
aws_role_arn: pydantic_backend.PydanticAwsRoleArn = pydantic.Field(
|
202
187
|
description="ARN of the role to be assumed for execution on your Braket account."
|
203
188
|
)
|
@@ -206,21 +191,14 @@ class AwsBackendPreferences(BackendPreferences):
|
|
206
191
|
description="S3 Folder Path Within The S3 Bucket"
|
207
192
|
)
|
208
193
|
|
209
|
-
@
|
210
|
-
|
211
|
-
|
212
|
-
) -> str:
|
194
|
+
@pydantic.field_validator("s3_bucket_name", mode="before")
|
195
|
+
@classmethod
|
196
|
+
def _validate_s3_bucket_name(cls, s3_bucket_name: str) -> str:
|
213
197
|
s3_bucket_name = s3_bucket_name.strip()
|
214
198
|
if not s3_bucket_name.startswith("amazon-braket-"):
|
215
199
|
raise ClassiqValueError('S3 bucket name should start with "amazon-braket-"')
|
216
200
|
return s3_bucket_name
|
217
201
|
|
218
|
-
@pydantic.root_validator(pre=True)
|
219
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
220
|
-
return values_with_discriminator(
|
221
|
-
values, "backend_service_provider", ProviderVendor.AMAZON_BRAKET
|
222
|
-
)
|
223
|
-
|
224
202
|
|
225
203
|
class IBMBackendProvider(BaseModel):
|
226
204
|
"""
|
@@ -255,7 +233,9 @@ class IBMBackendPreferences(BackendPreferences):
|
|
255
233
|
See examples in the [IBM Quantum Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/ibm-backends/?h=).
|
256
234
|
"""
|
257
235
|
|
258
|
-
backend_service_provider: ProviderTypeVendor.IBM_QUANTUM
|
236
|
+
backend_service_provider: ProviderTypeVendor.IBM_QUANTUM = pydantic.Field(
|
237
|
+
default=ProviderVendor.IBM_QUANTUM
|
238
|
+
)
|
259
239
|
access_token: Optional[str] = pydantic.Field(
|
260
240
|
default=None,
|
261
241
|
description="IBM Quantum access token to be used"
|
@@ -270,14 +250,8 @@ class IBMBackendPreferences(BackendPreferences):
|
|
270
250
|
description="QCTRL API key to access QCTRL optimization abilities",
|
271
251
|
)
|
272
252
|
|
273
|
-
@pydantic.root_validator(pre=True)
|
274
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
275
|
-
return values_with_discriminator(
|
276
|
-
values, "backend_service_provider", ProviderVendor.IBM_QUANTUM
|
277
|
-
)
|
278
253
|
|
279
|
-
|
280
|
-
class AzureCredential(pydantic.BaseSettings):
|
254
|
+
class AzureCredential(BaseSettings):
|
281
255
|
"""
|
282
256
|
Represents the credentials and configuration required to authenticate with Azure services.
|
283
257
|
|
@@ -296,11 +270,20 @@ class AzureCredential(pydantic.BaseSettings):
|
|
296
270
|
description="Azure Resource ID (including Azure subscription ID, resource "
|
297
271
|
"group and workspace), for personal resource",
|
298
272
|
)
|
273
|
+
model_config = SettingsConfigDict(
|
274
|
+
title="Azure Service Principal Credential",
|
275
|
+
env_prefix="AZURE_",
|
276
|
+
case_sensitive=False,
|
277
|
+
extra="allow",
|
278
|
+
)
|
299
279
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
280
|
+
def __init__(self, **data: Any) -> None:
|
281
|
+
initial_data = {
|
282
|
+
field: data[field] for field in data if field in self.model_fields
|
283
|
+
}
|
284
|
+
super().__init__(**data)
|
285
|
+
for field, value in initial_data.items():
|
286
|
+
setattr(self, field, value)
|
304
287
|
|
305
288
|
|
306
289
|
class AzureBackendPreferences(BackendPreferences):
|
@@ -317,7 +300,9 @@ class AzureBackendPreferences(BackendPreferences):
|
|
317
300
|
|
318
301
|
"""
|
319
302
|
|
320
|
-
backend_service_provider: ProviderTypeVendor.AZURE_QUANTUM
|
303
|
+
backend_service_provider: ProviderTypeVendor.AZURE_QUANTUM = pydantic.Field(
|
304
|
+
default=ProviderVendor.AZURE_QUANTUM
|
305
|
+
)
|
321
306
|
|
322
307
|
location: str = pydantic.Field(
|
323
308
|
default="East US", description="Azure personal resource region"
|
@@ -343,12 +328,6 @@ class AzureBackendPreferences(BackendPreferences):
|
|
343
328
|
"""
|
344
329
|
return self.credentials is None
|
345
330
|
|
346
|
-
@pydantic.root_validator(pre=True)
|
347
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
348
|
-
return values_with_discriminator(
|
349
|
-
values, "backend_service_provider", ProviderVendor.AZURE_QUANTUM
|
350
|
-
)
|
351
|
-
|
352
331
|
|
353
332
|
class IonqBackendPreferences(BackendPreferences):
|
354
333
|
"""
|
@@ -365,7 +344,9 @@ class IonqBackendPreferences(BackendPreferences):
|
|
365
344
|
See examples in the [IonQ Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/ionq-backends/?h=).
|
366
345
|
"""
|
367
346
|
|
368
|
-
backend_service_provider: ProviderTypeVendor.IONQ
|
347
|
+
backend_service_provider: ProviderTypeVendor.IONQ = pydantic.Field(
|
348
|
+
default=ProviderVendor.IONQ
|
349
|
+
)
|
369
350
|
api_key: pydantic_backend.PydanticIonQApiKeyType = pydantic.Field(
|
370
351
|
..., description="IonQ API key"
|
371
352
|
)
|
@@ -374,12 +355,6 @@ class IonqBackendPreferences(BackendPreferences):
|
|
374
355
|
description="Error mitigation configuration.",
|
375
356
|
)
|
376
357
|
|
377
|
-
@pydantic.root_validator(pre=True)
|
378
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
379
|
-
return values_with_discriminator(
|
380
|
-
values, "backend_service_provider", ProviderVendor.IONQ
|
381
|
-
)
|
382
|
-
|
383
358
|
|
384
359
|
class GCPBackendPreferences(BackendPreferences):
|
385
360
|
"""
|
@@ -394,13 +369,9 @@ class GCPBackendPreferences(BackendPreferences):
|
|
394
369
|
See examples in the [Google Cloud Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/google-backends/?h=).
|
395
370
|
"""
|
396
371
|
|
397
|
-
backend_service_provider: ProviderTypeVendor.GOOGLE
|
398
|
-
|
399
|
-
|
400
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
401
|
-
return values_with_discriminator(
|
402
|
-
values, "backend_service_provider", ProviderVendor.GOOGLE
|
403
|
-
)
|
372
|
+
backend_service_provider: ProviderTypeVendor.GOOGLE = pydantic.Field(
|
373
|
+
default=ProviderVendor.GOOGLE
|
374
|
+
)
|
404
375
|
|
405
376
|
def is_nvidia_backend(self) -> bool:
|
406
377
|
return True
|
@@ -417,16 +388,12 @@ class OQCBackendPreferences(BackendPreferences):
|
|
417
388
|
password (str): OQC password
|
418
389
|
"""
|
419
390
|
|
420
|
-
backend_service_provider: ProviderTypeVendor.OQC
|
391
|
+
backend_service_provider: ProviderTypeVendor.OQC = pydantic.Field(
|
392
|
+
default=ProviderVendor.OQC
|
393
|
+
)
|
421
394
|
username: str = pydantic.Field(description="OQC username")
|
422
395
|
password: str = pydantic.Field(description="OQC password")
|
423
396
|
|
424
|
-
@pydantic.root_validator(pre=True)
|
425
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
426
|
-
return values_with_discriminator(
|
427
|
-
values, "backend_service_provider", ProviderVendor.OQC
|
428
|
-
)
|
429
|
-
|
430
397
|
|
431
398
|
class IntelBackendPreferences(BackendPreferences):
|
432
399
|
"""
|
@@ -438,13 +405,9 @@ class IntelBackendPreferences(BackendPreferences):
|
|
438
405
|
For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/classiq-backends/).
|
439
406
|
"""
|
440
407
|
|
441
|
-
backend_service_provider: ProviderTypeVendor.INTEL
|
442
|
-
|
443
|
-
|
444
|
-
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
445
|
-
return values_with_discriminator(
|
446
|
-
values, "backend_service_provider", ProviderVendor.INTEL
|
447
|
-
)
|
408
|
+
backend_service_provider: ProviderTypeVendor.INTEL = pydantic.Field(
|
409
|
+
default=ProviderVendor.INTEL
|
410
|
+
)
|
448
411
|
|
449
412
|
|
450
413
|
class AQTBackendPreferences(BackendPreferences):
|
@@ -458,17 +421,38 @@ class AQTBackendPreferences(BackendPreferences):
|
|
458
421
|
workspace: The AQT workspace where the simulator/hardware is located.
|
459
422
|
"""
|
460
423
|
|
461
|
-
|
462
|
-
|
424
|
+
backend_service_provider: ProviderTypeVendor.AQT = pydantic.Field(
|
425
|
+
default=ProviderVendor.AQT
|
426
|
+
)
|
463
427
|
api_key: str = pydantic.Field(description="AQT API key")
|
464
428
|
workspace: str = pydantic.Field(description="AQT workspace")
|
465
429
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
430
|
+
|
431
|
+
class IQCCBackendPreferences(BackendPreferences):
|
432
|
+
"""
|
433
|
+
NOTE: This is a work in progress and is subject to change.
|
434
|
+
|
435
|
+
Represents the backend preferences specific to IQCC (Israeli Quantum Computing
|
436
|
+
Center).
|
437
|
+
|
438
|
+
Attributes:
|
439
|
+
auth_token: The authorization token generated by calling `generate_iqcc_token`.
|
440
|
+
target_id: The target ID of the login node.
|
441
|
+
target_scope_id: The scope ID of the specified target.
|
442
|
+
ssh_user_name: The user name to use when connecting to the SSH server on the login node.
|
443
|
+
ssh_key: The private key to use when connecting to the SSH server on the login node.
|
444
|
+
slurm_account: The account to use when initiating SLURM jobs.
|
445
|
+
"""
|
446
|
+
|
447
|
+
backend_service_provider: ProviderTypeVendor.IQCC = pydantic.Field(
|
448
|
+
default=ProviderVendor.IQCC
|
449
|
+
)
|
450
|
+
auth_token: str
|
451
|
+
target_id: str
|
452
|
+
target_scope_id: str
|
453
|
+
ssh_user_name: str
|
454
|
+
ssh_key: str
|
455
|
+
slurm_account: str
|
472
456
|
|
473
457
|
|
474
458
|
def is_exact_simulator(backend_preferences: BackendPreferences) -> bool:
|
@@ -502,6 +486,7 @@ BackendPreferencesTypes = Union[
|
|
502
486
|
OQCBackendPreferences,
|
503
487
|
IntelBackendPreferences,
|
504
488
|
AQTBackendPreferences,
|
489
|
+
IQCCBackendPreferences,
|
505
490
|
]
|
506
491
|
|
507
492
|
__all__ = [
|
@@ -525,17 +510,5 @@ __all__ = [
|
|
525
510
|
"OQCBackendNames",
|
526
511
|
"IntelBackendPreferences",
|
527
512
|
"AQTBackendPreferences",
|
513
|
+
"IQCCBackendPreferences",
|
528
514
|
]
|
529
|
-
|
530
|
-
|
531
|
-
def validate_backend_service_provider(backend_service_provider: Any) -> Provider:
|
532
|
-
if isinstance(backend_service_provider, Provider):
|
533
|
-
return backend_service_provider
|
534
|
-
if isinstance(backend_service_provider, str):
|
535
|
-
for member in Provider:
|
536
|
-
if member.lower() == backend_service_provider.lower():
|
537
|
-
return Provider(member)
|
538
|
-
raise ClassiqValueError(
|
539
|
-
f"""Vendor {backend_service_provider} is not supported.
|
540
|
-
The supported providers are {', '.join(Provider)}."""
|
541
|
-
)
|