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
@@ -2,8 +2,8 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from typing import TYPE_CHECKING, List, Optional
|
4
4
|
|
5
|
-
import
|
6
|
-
from
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field
|
6
|
+
from typing_extensions import Annotated
|
7
7
|
|
8
8
|
# This file is based on autogenerated code from: https://static.ionq.co/schemas/circuit-v0.json using
|
9
9
|
# https://pydantic-docs.helpmanual.io/datamodel_code_generator/
|
@@ -12,10 +12,13 @@ from pydantic import BaseModel
|
|
12
12
|
if TYPE_CHECKING:
|
13
13
|
PydanticGateName = str
|
14
14
|
else:
|
15
|
-
PydanticGateName =
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
PydanticGateName = Annotated[
|
16
|
+
str,
|
17
|
+
Field(
|
18
|
+
pattern=r"^\w+$",
|
19
|
+
min_length=1,
|
20
|
+
),
|
21
|
+
]
|
19
22
|
|
20
23
|
|
21
24
|
class Gate(BaseModel):
|
@@ -24,23 +27,13 @@ class Gate(BaseModel):
|
|
24
27
|
control: Optional[int] = None
|
25
28
|
targets: Optional[List[int]] = None
|
26
29
|
controls: Optional[List[int]] = None
|
27
|
-
|
28
|
-
# Ionq changes format sometimes.
|
29
|
-
# One example is that `IonqQauntumCircuit` got a field name "gateset" with the value "qis"
|
30
|
-
# Another is that `Gate` got a field named "rotation"
|
31
|
-
class Config:
|
32
|
-
extra = pydantic.Extra.allow
|
30
|
+
model_config = ConfigDict(extra="allow")
|
33
31
|
|
34
32
|
|
35
33
|
class IonqQuantumCircuit(BaseModel):
|
36
34
|
qubits: int
|
37
35
|
circuit: List[Gate]
|
38
|
-
|
39
|
-
# Ionq changes format sometimes.
|
40
|
-
# One example is that `IonqQuantumCircuit` got a field name "gateset" with the value "qis"
|
41
|
-
# Another is that `Gate` got a field named "rotation"
|
42
|
-
class Config:
|
43
|
-
extra = pydantic.Extra.allow
|
36
|
+
model_config = ConfigDict(extra="allow")
|
44
37
|
|
45
38
|
@classmethod
|
46
39
|
def from_string(cls, code: str) -> IonqQuantumCircuit:
|
@@ -48,4 +41,4 @@ class IonqQuantumCircuit(BaseModel):
|
|
48
41
|
commentless_code = "\n".join(
|
49
42
|
line for line in code_lines if not line.startswith("//")
|
50
43
|
)
|
51
|
-
return cls.
|
44
|
+
return cls.model_validate_json(commentless_code)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import TYPE_CHECKING
|
2
2
|
|
3
|
-
import
|
3
|
+
from pydantic import Field, StrictStr, constr
|
4
|
+
from typing_extensions import Annotated
|
4
5
|
|
5
6
|
AZURE_QUANTUM_RESOURCE_ID_REGEX = r"^/subscriptions/([a-fA-F0-9-]*)/resourceGroups/([^\s/]*)/providers/Microsoft\.Quantum/Workspaces/([^\s/]*)$"
|
6
7
|
|
@@ -25,20 +26,31 @@ if TYPE_CHECKING:
|
|
25
26
|
else:
|
26
27
|
# TODO Simplify regular expressions in this file
|
27
28
|
|
28
|
-
PydanticAwsRoleArn =
|
29
|
-
|
30
|
-
|
29
|
+
PydanticAwsRoleArn = Annotated[
|
30
|
+
StrictStr,
|
31
|
+
constr(
|
32
|
+
strip_whitespace=True,
|
33
|
+
),
|
34
|
+
]
|
31
35
|
|
32
|
-
PydanticS3BucketKey =
|
36
|
+
PydanticS3BucketKey = Annotated[
|
37
|
+
StrictStr, constr(strip_whitespace=True, min_length=1)
|
38
|
+
]
|
33
39
|
|
34
|
-
PydanticAzureResourceIDType =
|
40
|
+
PydanticAzureResourceIDType = Annotated[
|
41
|
+
str, Field(pattern=AZURE_QUANTUM_RESOURCE_ID_REGEX)
|
42
|
+
]
|
35
43
|
|
36
|
-
PydanticIonQApiKeyType =
|
37
|
-
|
38
|
-
|
44
|
+
PydanticIonQApiKeyType = Annotated[
|
45
|
+
str, Field(pattern=f"[A-Za-z0-9]{{{_IONQ_API_KEY_LENGTH}}}")
|
46
|
+
]
|
39
47
|
|
40
|
-
PydanticAliceBobApiKeyType =
|
48
|
+
PydanticAliceBobApiKeyType = Annotated[
|
49
|
+
StrictStr, constr(min_length=1, strip_whitespace=True)
|
50
|
+
]
|
41
51
|
|
42
|
-
PydanticArgumentNameType =
|
52
|
+
PydanticArgumentNameType = Annotated[str, Field(pattern="[_a-zA-Z][_a-zA-Z0-9]*")]
|
43
53
|
|
44
|
-
PydanticExecutionParameter =
|
54
|
+
PydanticExecutionParameter = Annotated[
|
55
|
+
str, Field(pattern=EXECUTION_PARAMETER_PATTERN)
|
56
|
+
]
|
@@ -20,6 +20,7 @@ class ProviderVendor(StrEnum):
|
|
20
20
|
OQC = "OQC"
|
21
21
|
INTEL = "Intel"
|
22
22
|
AQT = "AQT"
|
23
|
+
IQCC = "IQCC"
|
23
24
|
|
24
25
|
|
25
26
|
class ProviderTypeVendor:
|
@@ -33,6 +34,7 @@ class ProviderTypeVendor:
|
|
33
34
|
OQC = Literal[ProviderVendor.OQC]
|
34
35
|
INTEL = Literal[ProviderVendor.INTEL]
|
35
36
|
AQT = Literal[ProviderVendor.AQT]
|
37
|
+
IQCC = Literal[ProviderVendor.IQCC]
|
36
38
|
|
37
39
|
|
38
40
|
class ClassiqSimulatorBackendNames(StrEnum):
|
@@ -5,6 +5,7 @@ from typing import Set, Tuple, Union
|
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
import pydantic
|
8
|
+
from pydantic import ConfigDict
|
8
9
|
|
9
10
|
from classiq.interface.exceptions import ClassiqValueError
|
10
11
|
from classiq.interface.helpers.hashable_pydantic_base_model import (
|
@@ -75,7 +76,8 @@ class FermionicOperator(HashablePydanticBaseModel):
|
|
75
76
|
|
76
77
|
return (op_symbol, op_index)
|
77
78
|
|
78
|
-
@pydantic.
|
79
|
+
@pydantic.field_validator("op_list")
|
80
|
+
@classmethod
|
79
81
|
def _validate_op_list(cls, op_list: list) -> list:
|
80
82
|
return list(map(cls._validate_single_op, op_list))
|
81
83
|
|
@@ -99,8 +101,7 @@ class FermionicOperator(HashablePydanticBaseModel):
|
|
99
101
|
"FermionicOperator can be summed together only with type FermionicOperator or SummedFermionicOperator"
|
100
102
|
)
|
101
103
|
|
102
|
-
|
103
|
-
frozen = True
|
104
|
+
model_config = ConfigDict(frozen=True)
|
104
105
|
|
105
106
|
@staticmethod
|
106
107
|
def _to_ladder_op(char: str) -> str:
|
@@ -135,9 +136,7 @@ class SummedFermionicOperator(HashablePydanticBaseModel):
|
|
135
136
|
op_list: list = pydantic.Field(
|
136
137
|
description="A list of tuples each containing a FermionicOperator and a coefficient.",
|
137
138
|
)
|
138
|
-
|
139
|
-
class Config:
|
140
|
-
frozen = True
|
139
|
+
model_config = ConfigDict(frozen=True)
|
141
140
|
|
142
141
|
@staticmethod
|
143
142
|
def _validate_single_op(op: tuple) -> FermionicOperatorTuple:
|
@@ -166,7 +165,8 @@ class SummedFermionicOperator(HashablePydanticBaseModel):
|
|
166
165
|
|
167
166
|
return op # type: ignore[return-value] # mypy thinks that it is `Tuple[Any, ...]`, though the asserts here tell otherwise..
|
168
167
|
|
169
|
-
@pydantic.
|
168
|
+
@pydantic.field_validator("op_list")
|
169
|
+
@classmethod
|
170
170
|
def _validate_op_list(cls, op_list: list) -> list:
|
171
171
|
return list(map(cls._validate_single_op, op_list))
|
172
172
|
|
@@ -1,7 +1,8 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import List, Literal, Optional, Tuple, Union, cast
|
2
2
|
|
3
3
|
import pydantic
|
4
|
-
from pydantic import Field
|
4
|
+
from pydantic import ConfigDict, Field
|
5
|
+
from pydantic_core.core_schema import ValidationInfo
|
5
6
|
from typing_extensions import Annotated
|
6
7
|
|
7
8
|
from classiq.interface.chemistry.fermionic_operator import SummedFermionicOperator
|
@@ -52,18 +53,19 @@ class GroundStateProblem(HashablePydanticBaseModel):
|
|
52
53
|
)
|
53
54
|
num_qubits: Optional[int] = pydantic.Field(default=None)
|
54
55
|
|
55
|
-
@pydantic.
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
@pydantic.field_validator("z2_symmetries")
|
57
|
+
@classmethod
|
58
|
+
def _validate_z2_symmetries(cls, z2_symmetries: bool, info: ValidationInfo) -> bool:
|
59
|
+
if (
|
60
|
+
z2_symmetries
|
61
|
+
and info.data.get("mapping") == FermionMapping.FAST_BRAVYI_KITAEV
|
62
|
+
):
|
60
63
|
raise ClassiqValueError(
|
61
64
|
"z2 symmetries reduction can not be used for fast_bravyi_kitaev mapping"
|
62
65
|
)
|
63
66
|
return z2_symmetries
|
64
67
|
|
65
|
-
|
66
|
-
frozen = True
|
68
|
+
model_config = ConfigDict(frozen=True)
|
67
69
|
|
68
70
|
|
69
71
|
class MoleculeProblem(GroundStateProblem):
|
@@ -87,20 +89,23 @@ class HamiltonianProblem(GroundStateProblem):
|
|
87
89
|
description="Tuple containing the numbers of alpha particles and beta particles"
|
88
90
|
)
|
89
91
|
|
90
|
-
@pydantic.
|
91
|
-
|
92
|
-
|
92
|
+
@pydantic.field_validator("num_particles", mode="before")
|
93
|
+
@classmethod
|
94
|
+
def _validate_num_particles(
|
95
|
+
cls,
|
96
|
+
num_particles: Union[
|
97
|
+
List[Union[int, float]], Tuple[Union[int, float], Union[int, float]]
|
98
|
+
],
|
99
|
+
) -> List[int]:
|
100
|
+
assert isinstance(num_particles, (list, tuple))
|
93
101
|
assert len(num_particles) == 2
|
94
102
|
|
95
|
-
|
96
|
-
# floats to ints
|
97
|
-
assert isinstance(num_particles[0], int)
|
98
|
-
assert num_particles[0] >= 1
|
103
|
+
num_particles = [int(x) for x in num_particles]
|
99
104
|
|
100
|
-
assert
|
105
|
+
assert num_particles[0] >= 1
|
101
106
|
assert num_particles[1] >= 1
|
102
107
|
|
103
|
-
return num_particles
|
108
|
+
return cast(List[int], num_particles)
|
104
109
|
|
105
110
|
|
106
111
|
CHEMISTRY_PROBLEMS = (MoleculeProblem, HamiltonianProblem)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import List, Literal, Union
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
from pydantic import ConfigDict
|
4
5
|
|
5
6
|
from classiq.interface.chemistry.elements import ELEMENTS
|
6
7
|
from classiq.interface.exceptions import ClassiqValueError
|
@@ -20,7 +21,7 @@ class Atom(HashablePydanticBaseModel):
|
|
20
21
|
class Molecule(HashablePydanticBaseModel):
|
21
22
|
atoms: List[Atom] = pydantic.Field(
|
22
23
|
description="A list of atoms each containing the atoms symbol and its (x,y,z) location",
|
23
|
-
|
24
|
+
min_length=1,
|
24
25
|
)
|
25
26
|
spin: pydantic.NonNegativeInt = pydantic.Field(
|
26
27
|
default=1, description="spin of the molecule"
|
@@ -33,12 +34,17 @@ class Molecule(HashablePydanticBaseModel):
|
|
33
34
|
def atoms_type(self) -> List[AtomType]:
|
34
35
|
return [(atom.symbol, [atom.x, atom.y, atom.z]) for atom in self.atoms]
|
35
36
|
|
36
|
-
@
|
37
|
-
def
|
37
|
+
@classmethod
|
38
|
+
def _validate_atom(cls, atom: Union[AtomType, Atom]) -> Atom:
|
38
39
|
if isinstance(atom, (list, tuple)):
|
39
40
|
return cls._validate_old_atoms_type(atom)
|
40
41
|
return atom
|
41
42
|
|
43
|
+
@pydantic.field_validator("atoms", mode="before")
|
44
|
+
@classmethod
|
45
|
+
def _validate_atoms(cls, atoms: List[Union[AtomType, Atom]]) -> List[Atom]:
|
46
|
+
return [cls._validate_atom(atom) for atom in atoms]
|
47
|
+
|
42
48
|
@staticmethod
|
43
49
|
def _validate_old_atoms_type(atom: AtomType) -> Atom:
|
44
50
|
if len(atom) != 2:
|
@@ -62,5 +68,4 @@ class Molecule(HashablePydanticBaseModel):
|
|
62
68
|
|
63
69
|
return Atom(symbol=symbol, x=coordinate[0], y=coordinate[1], z=coordinate[2])
|
64
70
|
|
65
|
-
|
66
|
-
frozen = True
|
71
|
+
model_config = ConfigDict(frozen=True)
|
@@ -5,7 +5,6 @@ from typing import (
|
|
5
5
|
Dict,
|
6
6
|
List,
|
7
7
|
Optional,
|
8
|
-
Tuple,
|
9
8
|
Union,
|
10
9
|
cast,
|
11
10
|
)
|
@@ -14,6 +13,7 @@ import numpy as np
|
|
14
13
|
import pydantic
|
15
14
|
import sympy
|
16
15
|
from more_itertools import all_equal
|
16
|
+
from pydantic import ConfigDict
|
17
17
|
|
18
18
|
from classiq.interface.exceptions import ClassiqValueError
|
19
19
|
from classiq.interface.generator.function_params import validate_expression_str
|
@@ -42,8 +42,8 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
42
42
|
pauli_list: PydanticPauliList = pydantic.Field(
|
43
43
|
description="A list of tuples each containing a pauli string comprised of I,X,Y,Z characters and a complex coefficient; for example [('IZ', 0.1), ('XY', 0.2)].",
|
44
44
|
)
|
45
|
-
is_hermitian: bool = pydantic.Field(default=False)
|
46
45
|
has_complex_coefficients: bool = pydantic.Field(default=True)
|
46
|
+
is_hermitian: bool = pydantic.Field(default=False)
|
47
47
|
|
48
48
|
def show(self) -> str:
|
49
49
|
if self.is_hermitian:
|
@@ -55,16 +55,19 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
55
55
|
f"+({summand[1]:+.3f}) * {summand[0]}" for summand in self.pauli_list
|
56
56
|
)
|
57
57
|
|
58
|
-
@pydantic.
|
58
|
+
@pydantic.field_validator("pauli_list", mode="before")
|
59
|
+
@classmethod
|
59
60
|
def _validate_pauli_monomials(
|
60
|
-
cls,
|
61
|
-
) ->
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
61
|
+
cls, pauli_list: PydanticPauliList
|
62
|
+
) -> PydanticPauliList:
|
63
|
+
validated_pauli_list = []
|
64
|
+
for monomial in pauli_list:
|
65
|
+
# Validate the length
|
66
|
+
_PauliMonomialLengthValidator(monomial=monomial) # type: ignore[call-arg]
|
67
|
+
coeff = cls._validate_monomial_coefficient(monomial[1])
|
68
|
+
parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff)
|
69
|
+
validated_pauli_list.append((parsed_monomial.string, parsed_monomial.coeff))
|
70
|
+
return validated_pauli_list
|
68
71
|
|
69
72
|
@staticmethod
|
70
73
|
def _validate_monomial_coefficient(
|
@@ -76,16 +79,38 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
76
79
|
coeff = str(coeff)
|
77
80
|
return coeff
|
78
81
|
|
79
|
-
@pydantic.
|
82
|
+
@pydantic.field_validator("pauli_list", mode="after")
|
83
|
+
@classmethod
|
80
84
|
def _validate_pauli_list(cls, pauli_list: PydanticPauliList) -> PydanticPauliList:
|
81
85
|
if not all_equal(len(summand[0]) for summand in pauli_list):
|
82
86
|
raise ClassiqValueError("Pauli strings have incompatible lengths.")
|
83
87
|
return pauli_list
|
84
88
|
|
85
|
-
@
|
89
|
+
@staticmethod
|
90
|
+
def check_if_hermitian(pauli_list: PydanticPauliList) -> bool:
|
91
|
+
if all(isinstance(summand[1], (float, int, complex)) for summand in pauli_list):
|
92
|
+
if all(np.isclose(summand[1].imag, 0) for summand in pauli_list): # type: ignore[union-attr]
|
93
|
+
return True
|
94
|
+
|
95
|
+
for pauli_string, coeff in pauli_list:
|
96
|
+
reverse_string = pauli_string[::-1]
|
97
|
+
reverse_found = False
|
98
|
+
for other_string, other_coeff in pauli_list:
|
99
|
+
if other_string == reverse_string and np.isclose(
|
100
|
+
coeff, other_coeff.conjugate() # type: ignore[union-attr]
|
101
|
+
):
|
102
|
+
reverse_found = True
|
103
|
+
break
|
104
|
+
if not reverse_found:
|
105
|
+
return False
|
106
|
+
return True
|
107
|
+
return False
|
108
|
+
|
109
|
+
@pydantic.model_validator(mode="before")
|
110
|
+
@classmethod
|
86
111
|
def _validate_hermitianity(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
87
112
|
pauli_list = values.get("pauli_list", [])
|
88
|
-
if
|
113
|
+
if PauliOperator.check_if_hermitian(pauli_list):
|
89
114
|
values["is_hermitian"] = all(
|
90
115
|
np.isclose(complex(summand[1]).real, summand[1])
|
91
116
|
for summand in pauli_list
|
@@ -93,7 +118,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
93
118
|
if values.get("is_hermitian", False):
|
94
119
|
values["has_complex_coefficients"] = False
|
95
120
|
values["pauli_list"] = [
|
96
|
-
(summand[0], complex(summand[1].real)
|
121
|
+
(summand[0], complex(summand[1]).real) for summand in pauli_list
|
97
122
|
]
|
98
123
|
else:
|
99
124
|
values["has_complex_coefficients"] = not all(
|
@@ -161,7 +186,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
161
186
|
(self._extend_pauli_string(pauli_string, num_extra_qubits), coeff)
|
162
187
|
for (pauli_string, coeff) in self.pauli_list
|
163
188
|
]
|
164
|
-
return self.
|
189
|
+
return self.model_copy(update={"pauli_list": new_pauli_list}, deep=True)
|
165
190
|
|
166
191
|
@staticmethod
|
167
192
|
def _reorder_pauli_string(
|
@@ -211,7 +236,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
211
236
|
(cls._reorder_pauli_string(pauli_string, order, new_num_qubits), coeff)
|
212
237
|
for pauli_string, coeff in operator.pauli_list
|
213
238
|
]
|
214
|
-
return cls(pauli_list=new_pauli_list)
|
239
|
+
return cls(pauli_list=new_pauli_list, is_hermitian=operator.is_hermitian)
|
215
240
|
|
216
241
|
@classmethod
|
217
242
|
def from_unzipped_lists(
|
@@ -234,8 +259,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
234
259
|
]
|
235
260
|
)
|
236
261
|
|
237
|
-
|
238
|
-
frozen = True
|
262
|
+
model_config = ConfigDict(frozen=True)
|
239
263
|
|
240
264
|
|
241
265
|
class PauliOperatorV1(HashablePydanticBaseModel):
|
@@ -259,16 +283,19 @@ class PauliOperatorV1(HashablePydanticBaseModel):
|
|
259
283
|
f"+({summand[1]:+.3f}) * {summand[0]}" for summand in self.pauli_list
|
260
284
|
)
|
261
285
|
|
262
|
-
@pydantic.
|
286
|
+
@pydantic.field_validator("pauli_list", mode="before")
|
287
|
+
@classmethod
|
263
288
|
def _validate_pauli_monomials(
|
264
|
-
cls,
|
265
|
-
) ->
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
289
|
+
cls, pauli_list: PydanticPauliList
|
290
|
+
) -> PydanticPauliList:
|
291
|
+
validated_pauli_list = []
|
292
|
+
for monomial in pauli_list:
|
293
|
+
# Validate the length
|
294
|
+
_PauliMonomialLengthValidator(monomial=monomial) # type: ignore[call-arg]
|
295
|
+
coeff = cls._validate_monomial_coefficient(monomial[1])
|
296
|
+
parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff)
|
297
|
+
validated_pauli_list.append((parsed_monomial.string, parsed_monomial.coeff))
|
298
|
+
return validated_pauli_list
|
272
299
|
|
273
300
|
@staticmethod
|
274
301
|
def _validate_monomial_coefficient(
|
@@ -280,32 +307,34 @@ class PauliOperatorV1(HashablePydanticBaseModel):
|
|
280
307
|
coeff = str(coeff)
|
281
308
|
return coeff
|
282
309
|
|
283
|
-
@pydantic.
|
310
|
+
@pydantic.field_validator("pauli_list", mode="after")
|
311
|
+
@classmethod
|
284
312
|
def _validate_pauli_list(cls, pauli_list: PydanticPauliList) -> PydanticPauliList:
|
285
313
|
if not all_equal(len(summand[0]) for summand in pauli_list):
|
286
314
|
raise ClassiqValueError("Pauli strings have incompatible lengths.")
|
287
315
|
return pauli_list
|
288
316
|
|
289
|
-
@pydantic.
|
290
|
-
|
291
|
-
|
317
|
+
@pydantic.model_validator(mode="before")
|
318
|
+
@classmethod
|
319
|
+
def _validate_hermitianity(cls, v: Dict[str, Any]) -> Dict[str, Any]:
|
320
|
+
pauli_list = cast(PydanticPauliList, v.get("pauli_list"))
|
292
321
|
if all(isinstance(summand[1], complex) for summand in pauli_list):
|
293
|
-
|
322
|
+
v["is_hermitian"] = all(
|
294
323
|
np.isclose(complex(summand[1]).real, summand[1])
|
295
324
|
for summand in pauli_list
|
296
325
|
)
|
297
|
-
if
|
298
|
-
|
299
|
-
|
300
|
-
(summand[0], complex(summand[1].real)
|
326
|
+
if v["is_hermitian"]:
|
327
|
+
v["has_complex_coefficients"] = False
|
328
|
+
v["pauli_list"] = [
|
329
|
+
(summand[0], complex(summand[1]).real) for summand in pauli_list
|
301
330
|
]
|
302
331
|
else:
|
303
|
-
|
332
|
+
v["has_complex_coefficients"] = not all(
|
304
333
|
np.isclose(complex(summand[1]).real, summand[1])
|
305
334
|
for summand in pauli_list
|
306
335
|
if isinstance(summand[1], complex)
|
307
336
|
)
|
308
|
-
return
|
337
|
+
return v
|
309
338
|
|
310
339
|
def __mul__(self, coefficient: complex) -> "PauliOperatorV1":
|
311
340
|
multiplied_ising = [
|
@@ -361,7 +390,7 @@ class PauliOperatorV1(HashablePydanticBaseModel):
|
|
361
390
|
(self._extend_pauli_string(pauli_string, num_extra_qubits), coeff)
|
362
391
|
for (pauli_string, coeff) in self.pauli_list
|
363
392
|
]
|
364
|
-
return self.
|
393
|
+
return self.model_copy(update={"pauli_list": new_pauli_list}, deep=True)
|
365
394
|
|
366
395
|
@staticmethod
|
367
396
|
def _reorder_pauli_string(
|
@@ -434,8 +463,7 @@ class PauliOperatorV1(HashablePydanticBaseModel):
|
|
434
463
|
]
|
435
464
|
)
|
436
465
|
|
437
|
-
|
438
|
-
frozen = True
|
466
|
+
model_config = ConfigDict(frozen=True)
|
439
467
|
|
440
468
|
|
441
469
|
# This class validates the length of a monomial.
|
@@ -444,8 +472,7 @@ class _PauliMonomialLengthValidator:
|
|
444
472
|
monomial: PydanticPauliMonomial
|
445
473
|
|
446
474
|
|
447
|
-
|
448
|
-
class _PauliMonomialParser:
|
475
|
+
class _PauliMonomialParser(pydantic.BaseModel):
|
449
476
|
string: PydanticPauliMonomialStr
|
450
477
|
coeff: PydanticParameterComplexType
|
451
478
|
|
@@ -53,7 +53,8 @@ class MhtQaoaInput(BaseModel):
|
|
53
53
|
def is_valid_cost(self, cost: float) -> bool:
|
54
54
|
return True
|
55
55
|
|
56
|
-
@pydantic.
|
56
|
+
@pydantic.field_validator("plot_list")
|
57
|
+
@classmethod
|
57
58
|
def round_plot_list_times_and_validate(
|
58
59
|
cls, plot_list: List[PlotData]
|
59
60
|
) -> List[PlotData]:
|
@@ -15,8 +15,7 @@ ParameterValue = Union[float, int, str, None]
|
|
15
15
|
class FunctionDebugInfo(BaseModel):
|
16
16
|
name: str
|
17
17
|
# Parameters describe classical parameters passed to function
|
18
|
-
|
19
|
-
parameters: Dict[str, str] = Field(type=Dict[str, ParameterValue])
|
18
|
+
parameters: Dict[str, str]
|
20
19
|
level: OperationLevel
|
21
20
|
is_allocate_or_free: bool = Field(default=False)
|
22
21
|
is_inverse: bool = Field(default=False)
|
@@ -54,8 +53,8 @@ class DebugInfoCollection(BaseModel):
|
|
54
53
|
# Pydantic only started supporting UUID as keys in Pydantic V2
|
55
54
|
# See https://github.com/pydantic/pydantic/issues/2096#issuecomment-814860206
|
56
55
|
# For now, we use strings as keys in the raw data and use UUID in the wrapper logic
|
57
|
-
data: Dict[str, FunctionDebugInfo] = Field(
|
58
|
-
blackbox_data: Dict[str, FunctionDebugInfoInterface] = Field(
|
56
|
+
data: Dict[str, FunctionDebugInfo] = Field(default={})
|
57
|
+
blackbox_data: Dict[str, FunctionDebugInfoInterface] = Field(default={})
|
59
58
|
|
60
59
|
def __setitem__(self, key: UUID, value: FunctionDebugInfo) -> None:
|
61
60
|
self.data[str(key)] = value
|
classiq/interface/exceptions.py
CHANGED
@@ -51,7 +51,9 @@ class ClassiqAnalyzerVisualizationError(ClassiqError):
|
|
51
51
|
|
52
52
|
|
53
53
|
class ClassiqAPIError(ClassiqError):
|
54
|
-
|
54
|
+
def __init__(self, message: str, status_code: Optional[int] = None) -> None:
|
55
|
+
self.status_code = status_code
|
56
|
+
super().__init__(message)
|
55
57
|
|
56
58
|
|
57
59
|
class ClassiqVersionError(ClassiqError):
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from classiq.interface.helpers.versioned_model import VersionedModel
|
2
|
+
|
3
|
+
|
4
|
+
class IQCCInitAuthData(VersionedModel):
|
5
|
+
auth_scope_id: str
|
6
|
+
auth_method_id: str
|
7
|
+
|
8
|
+
|
9
|
+
class IQCCInitAuthResponse(VersionedModel):
|
10
|
+
auth_url: str
|
11
|
+
token_id: str
|
12
|
+
|
13
|
+
|
14
|
+
class IQCCProbeAuthData(IQCCInitAuthData):
|
15
|
+
token_id: str
|
16
|
+
|
17
|
+
|
18
|
+
class IQCCProbeAuthResponse(VersionedModel):
|
19
|
+
auth_token: str
|
@@ -1,28 +1,28 @@
|
|
1
1
|
from datetime import datetime
|
2
2
|
from typing import List, Optional
|
3
3
|
|
4
|
-
from pydantic import BaseModel
|
4
|
+
from pydantic import BaseModel
|
5
5
|
|
6
6
|
from classiq.interface.jobs import JobStatus
|
7
7
|
|
8
8
|
|
9
|
-
class ExecutionJobDetailsV1(BaseModel, extra=
|
9
|
+
class ExecutionJobDetailsV1(BaseModel, extra="ignore"):
|
10
10
|
id: str
|
11
11
|
|
12
|
-
name: Optional[str]
|
12
|
+
name: Optional[str] = None
|
13
13
|
start_time: datetime
|
14
|
-
end_time: Optional[datetime]
|
14
|
+
end_time: Optional[datetime] = None
|
15
15
|
|
16
|
-
provider: Optional[str]
|
17
|
-
backend_name: Optional[str]
|
16
|
+
provider: Optional[str] = None
|
17
|
+
backend_name: Optional[str] = None
|
18
18
|
|
19
19
|
status: JobStatus
|
20
20
|
|
21
|
-
num_shots: Optional[int]
|
22
|
-
program_id: Optional[str]
|
21
|
+
num_shots: Optional[int] = None
|
22
|
+
program_id: Optional[str] = None
|
23
23
|
|
24
|
-
error: Optional[str]
|
24
|
+
error: Optional[str] = None
|
25
25
|
|
26
26
|
|
27
|
-
class ExecutionJobsQueryResultsV1(BaseModel, extra=
|
27
|
+
class ExecutionJobsQueryResultsV1(BaseModel, extra="ignore"):
|
28
28
|
results: List[ExecutionJobDetailsV1]
|