classiq 0.104.0__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/__init__.py +2 -0
- classiq/_internals/authentication/auth0.py +29 -0
- classiq/_internals/authentication/auth_flow_factory.py +43 -0
- classiq/_internals/authentication/machine_credentials_flow.py +26 -0
- classiq/_internals/authentication/password_manager.py +84 -0
- classiq/_internals/authentication/token_manager.py +24 -8
- classiq/analyzer/show_interactive_hack.py +0 -8
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +1 -1
- classiq/execution/all_hardware_devices.py +59 -1
- classiq/execution/functions/__init__.py +11 -1
- classiq/execution/functions/expectation_value.py +106 -0
- classiq/execution/functions/minimize.py +90 -0
- classiq/execution/functions/sample.py +8 -189
- classiq/execution/functions/state_vector.py +113 -0
- classiq/execution/functions/util/__init__.py +0 -0
- classiq/execution/functions/util/backend_preferences.py +188 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +66 -0
- classiq/interface/backend/quantum_backend_providers.py +11 -0
- classiq/interface/exceptions.py +0 -4
- classiq/interface/generator/arith/binary_ops.py +24 -0
- classiq/interface/generator/arith/number_utils.py +15 -6
- classiq/interface/generator/compiler_keywords.py +1 -0
- classiq/interface/generator/function_param_list.py +4 -0
- classiq/interface/generator/function_params.py +1 -1
- classiq/interface/generator/functions/classical_type.py +15 -0
- classiq/interface/generator/functions/type_name.py +17 -4
- classiq/interface/generator/transpiler_basis_gates.py +1 -0
- classiq/interface/generator/types/compilation_metadata.py +15 -6
- classiq/interface/hardware.py +1 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/model.py +19 -0
- classiq/interface/model/quantum_type.py +15 -0
- classiq/interface/qubits_mapping/__init__.py +4 -0
- classiq/interface/qubits_mapping/path_expr_range.py +69 -0
- classiq/interface/qubits_mapping/qubits_mapping.py +231 -0
- classiq/interface/qubits_mapping/slices.py +112 -0
- classiq/model_expansions/arithmetic.py +6 -0
- classiq/qmod/builtins/functions/__init__.py +12 -9
- classiq/qmod/builtins/functions/allocation.py +0 -36
- classiq/qmod/builtins/functions/arithmetic.py +52 -0
- classiq/qmod/builtins/functions/gray_code.py +23 -0
- classiq/qmod/builtins/functions/mcx_func.py +10 -0
- classiq/qmod/builtins/structs.py +22 -3
- classiq/qprog_to_cudaq.py +347 -0
- {classiq-0.104.0.dist-info → classiq-1.0.0.dist-info}/METADATA +4 -1
- {classiq-0.104.0.dist-info → classiq-1.0.0.dist-info}/RECORD +52 -39
- /classiq/execution/functions/{_logging.py → util/_logging.py} +0 -0
- /classiq/execution/functions/{constants.py → util/constants.py} +0 -0
- /classiq/execution/functions/{parse_provider_backend.py → util/parse_provider_backend.py} +0 -0
- {classiq-0.104.0.dist-info → classiq-1.0.0.dist-info}/WHEEL +0 -0
- {classiq-0.104.0.dist-info → classiq-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -1,207 +1,26 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
|
+
|
|
3
|
+
from classiq.execution.functions.util.backend_preferences import (
|
|
4
|
+
_get_backend_preferences_from_specifier,
|
|
5
|
+
)
|
|
4
6
|
|
|
5
7
|
if TYPE_CHECKING:
|
|
6
8
|
from pandas import DataFrame
|
|
7
9
|
|
|
8
|
-
from classiq.interface.backend.backend_preferences import (
|
|
9
|
-
AliceBobBackendPreferences,
|
|
10
|
-
AQTBackendPreferences,
|
|
11
|
-
AwsBackendPreferences,
|
|
12
|
-
AzureBackendPreferences,
|
|
13
|
-
AzureCredential,
|
|
14
|
-
BackendPreferencesTypes,
|
|
15
|
-
ClassiqBackendPreferences,
|
|
16
|
-
GCPBackendPreferences,
|
|
17
|
-
IBMBackendPreferences,
|
|
18
|
-
IntelBackendPreferences,
|
|
19
|
-
IonqBackendPreferences,
|
|
20
|
-
)
|
|
21
10
|
from classiq.interface.backend.provider_config.provider_config import ProviderConfig
|
|
22
|
-
from classiq.interface.backend.provider_config.providers.alice_bob import AliceBobConfig
|
|
23
|
-
from classiq.interface.backend.provider_config.providers.aqt import AQTConfig
|
|
24
|
-
from classiq.interface.backend.provider_config.providers.azure import AzureConfig
|
|
25
|
-
from classiq.interface.backend.provider_config.providers.braket import BraketConfig
|
|
26
|
-
from classiq.interface.backend.provider_config.providers.ibm import IBMConfig
|
|
27
|
-
from classiq.interface.backend.provider_config.providers.ionq import IonQConfig
|
|
28
|
-
from classiq.interface.backend.quantum_backend_providers import (
|
|
29
|
-
ClassiqNvidiaBackendNames,
|
|
30
|
-
ClassiqSimulatorBackendNames,
|
|
31
|
-
)
|
|
32
11
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
|
33
12
|
from classiq.interface.generator.model.preferences import create_random_seed
|
|
34
13
|
from classiq.interface.generator.model.preferences.preferences import (
|
|
35
14
|
TranspilationOption,
|
|
36
15
|
)
|
|
37
|
-
from classiq.interface.hardware import Provider
|
|
38
16
|
|
|
39
17
|
from classiq import (
|
|
40
18
|
ExecutionParams,
|
|
41
19
|
QuantumProgram,
|
|
42
20
|
)
|
|
43
21
|
from classiq.execution import ExecutionSession
|
|
44
|
-
from classiq.execution.functions._logging import _logger
|
|
45
|
-
from classiq.execution.functions.constants import Verbosity
|
|
46
|
-
from classiq.execution.functions.parse_provider_backend import (
|
|
47
|
-
_PROVIDER_TO_CANONICAL_NAME,
|
|
48
|
-
_parse_provider_backend,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@dataclass
|
|
53
|
-
class _ProviderConfigToBackendPrefSpec:
|
|
54
|
-
backend_preferences_class: type[BackendPreferencesTypes]
|
|
55
|
-
config_class: type[ProviderConfig] | None = None
|
|
56
|
-
# Maps the config dict (either passed in directly or dumped from config class) to a
|
|
57
|
-
# dict that we can load into the given BackendPreferences class. This is in case
|
|
58
|
-
# we need to rename fields or change structure.
|
|
59
|
-
config_dict_to_backend_preferences_dict: (
|
|
60
|
-
Callable[[dict[str, Any]], dict[str, Any]] | None
|
|
61
|
-
) = None
|
|
62
|
-
# Maps from SDK names to names our backend recognizes, raising a useful error
|
|
63
|
-
# if the name is unrecognized.
|
|
64
|
-
backend_name_mapper: Callable[[str], str] | None = None
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _classiq_backend_name_mapper(backend_name: str) -> str:
|
|
68
|
-
backend_name = backend_name.lower()
|
|
69
|
-
if backend_name in [
|
|
70
|
-
ClassiqSimulatorBackendNames.SIMULATOR,
|
|
71
|
-
ClassiqSimulatorBackendNames.SIMULATOR_MATRIX_PRODUCT_STATE,
|
|
72
|
-
ClassiqSimulatorBackendNames.SIMULATOR_DENSITY_MATRIX,
|
|
73
|
-
]:
|
|
74
|
-
return backend_name
|
|
75
|
-
if backend_name == "nvidia_simulator":
|
|
76
|
-
return ClassiqNvidiaBackendNames.SIMULATOR
|
|
77
|
-
if any(keyword in backend_name for keyword in ["gpu", "nvidia"]):
|
|
78
|
-
suggested_backend_name = "nvidia_simulator"
|
|
79
|
-
else:
|
|
80
|
-
suggested_backend_name = "simulator"
|
|
81
|
-
raise ValueError(
|
|
82
|
-
f"Unsupported backend name {backend_name}. Did you mean '{suggested_backend_name}'?"
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def _ibm_backend_name_mapper(backend_name: str) -> str:
|
|
87
|
-
ibm_prefix: Literal["ibm_"] = "ibm_"
|
|
88
|
-
backend_name = backend_name.lower()
|
|
89
|
-
if backend_name.startswith(ibm_prefix):
|
|
90
|
-
backend_name_no_prefix = backend_name.removeprefix(ibm_prefix)
|
|
91
|
-
raise ValueError(
|
|
92
|
-
f"IBM backend names shouldn't start with ibm_. Try 'ibm/{backend_name_no_prefix}'."
|
|
93
|
-
)
|
|
94
|
-
return ibm_prefix + backend_name
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def _azure_config_dict_to_backend_preferences_dict(
|
|
98
|
-
config_dict: dict[str, Any],
|
|
99
|
-
) -> dict[str, Any]:
|
|
100
|
-
if "location" not in config_dict:
|
|
101
|
-
raise ValueError("Azure config must have 'location' property")
|
|
102
|
-
credentials = None
|
|
103
|
-
if all(
|
|
104
|
-
config_dict.get(key) is not None
|
|
105
|
-
for key in ["tenant_id", "client_id", "client_secret", "resource_id"]
|
|
106
|
-
):
|
|
107
|
-
credentials = AzureCredential.model_validate(
|
|
108
|
-
{
|
|
109
|
-
"tenant_id": config_dict["tenant_id"],
|
|
110
|
-
"client_id": config_dict["client_id"],
|
|
111
|
-
"client_secret": config_dict["client_secret"],
|
|
112
|
-
"resource_id": config_dict["resource_id"],
|
|
113
|
-
}
|
|
114
|
-
)
|
|
115
|
-
return {
|
|
116
|
-
"location": config_dict["location"],
|
|
117
|
-
"credentials": credentials,
|
|
118
|
-
"ionq_error_mitigation_flag": config_dict.get("ionq_error_mitigation"),
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def _braket_config_dict_to_backend_preferences_dict(
|
|
123
|
-
config_dict: dict[str, Any],
|
|
124
|
-
) -> dict[str, Any]:
|
|
125
|
-
config_dict["aws_access_key_id"] = config_dict.pop("braket_access_key_id", None)
|
|
126
|
-
config_dict["aws_secret_access_key"] = config_dict.pop(
|
|
127
|
-
"braket_secret_access_key", None
|
|
128
|
-
)
|
|
129
|
-
return config_dict
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
_PROVIDER_CONFIG_TO_BACKEND_PREFERENCES_SPEC = {
|
|
133
|
-
Provider.CLASSIQ: _ProviderConfigToBackendPrefSpec(
|
|
134
|
-
backend_preferences_class=ClassiqBackendPreferences,
|
|
135
|
-
backend_name_mapper=_classiq_backend_name_mapper,
|
|
136
|
-
),
|
|
137
|
-
Provider.GOOGLE: _ProviderConfigToBackendPrefSpec(
|
|
138
|
-
backend_preferences_class=GCPBackendPreferences
|
|
139
|
-
),
|
|
140
|
-
Provider.INTEL: _ProviderConfigToBackendPrefSpec(
|
|
141
|
-
backend_preferences_class=IntelBackendPreferences
|
|
142
|
-
),
|
|
143
|
-
Provider.IBM_QUANTUM: _ProviderConfigToBackendPrefSpec(
|
|
144
|
-
backend_preferences_class=IBMBackendPreferences,
|
|
145
|
-
config_class=IBMConfig,
|
|
146
|
-
backend_name_mapper=_ibm_backend_name_mapper,
|
|
147
|
-
),
|
|
148
|
-
Provider.AMAZON_BRAKET: _ProviderConfigToBackendPrefSpec(
|
|
149
|
-
backend_preferences_class=AwsBackendPreferences,
|
|
150
|
-
config_dict_to_backend_preferences_dict=_braket_config_dict_to_backend_preferences_dict,
|
|
151
|
-
config_class=BraketConfig,
|
|
152
|
-
),
|
|
153
|
-
Provider.IONQ: _ProviderConfigToBackendPrefSpec(
|
|
154
|
-
backend_preferences_class=IonqBackendPreferences,
|
|
155
|
-
config_class=IonQConfig,
|
|
156
|
-
),
|
|
157
|
-
Provider.ALICE_AND_BOB: _ProviderConfigToBackendPrefSpec(
|
|
158
|
-
backend_preferences_class=AliceBobBackendPreferences,
|
|
159
|
-
config_class=AliceBobConfig,
|
|
160
|
-
),
|
|
161
|
-
Provider.AQT: _ProviderConfigToBackendPrefSpec(
|
|
162
|
-
backend_preferences_class=AQTBackendPreferences,
|
|
163
|
-
config_class=AQTConfig,
|
|
164
|
-
),
|
|
165
|
-
Provider.AZURE_QUANTUM: _ProviderConfigToBackendPrefSpec(
|
|
166
|
-
backend_preferences_class=AzureBackendPreferences,
|
|
167
|
-
config_dict_to_backend_preferences_dict=_azure_config_dict_to_backend_preferences_dict,
|
|
168
|
-
config_class=AzureConfig,
|
|
169
|
-
),
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def _get_backend_preferences_from_specifier(
|
|
174
|
-
backend_spec: str, config: dict[str, Any] | ProviderConfig
|
|
175
|
-
) -> BackendPreferencesTypes:
|
|
176
|
-
provider, backend_name = _parse_provider_backend(backend_spec)
|
|
177
|
-
|
|
178
|
-
if provider not in _PROVIDER_CONFIG_TO_BACKEND_PREFERENCES_SPEC:
|
|
179
|
-
raise NotImplementedError(
|
|
180
|
-
f"Unsupported provider '{_PROVIDER_TO_CANONICAL_NAME.get(provider) or provider}'"
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
provider_spec = _PROVIDER_CONFIG_TO_BACKEND_PREFERENCES_SPEC[provider]
|
|
184
|
-
if isinstance(config, ProviderConfig):
|
|
185
|
-
if provider_spec.config_class is None:
|
|
186
|
-
raise ValueError(
|
|
187
|
-
f"This provider does not support any ProviderConfig classes. Received '{config.__class__.__name__}'"
|
|
188
|
-
)
|
|
189
|
-
if not isinstance(config, provider_spec.config_class):
|
|
190
|
-
raise ValueError(
|
|
191
|
-
f"{_PROVIDER_TO_CANONICAL_NAME[provider]} devices require {provider_spec.config_class.__name__}, got {config.__class__.__name__}"
|
|
192
|
-
)
|
|
193
|
-
config_dict = config.model_dump()
|
|
194
|
-
else:
|
|
195
|
-
config_dict = config
|
|
196
|
-
if provider_spec.backend_name_mapper is not None:
|
|
197
|
-
backend_name = provider_spec.backend_name_mapper(backend_name)
|
|
198
|
-
|
|
199
|
-
if provider_spec.config_dict_to_backend_preferences_dict is not None:
|
|
200
|
-
config_dict = provider_spec.config_dict_to_backend_preferences_dict(config_dict)
|
|
201
|
-
|
|
202
|
-
config_dict["backend_name"] = backend_name
|
|
203
|
-
return provider_spec.backend_preferences_class.model_validate(config_dict)
|
|
204
|
-
|
|
22
|
+
from classiq.execution.functions.util._logging import _logger
|
|
23
|
+
from classiq.execution.functions.util.constants import Verbosity
|
|
205
24
|
|
|
206
25
|
_DEFAULT_BACKEND_NAME = "simulator"
|
|
207
26
|
|
|
@@ -222,7 +41,7 @@ def _new_sample(
|
|
|
222
41
|
|
|
223
42
|
Args:
|
|
224
43
|
qprog: The quantum program
|
|
225
|
-
backend: The device (hardware or simulator) on which to run the quantum program. Specified as "provider/device_id"
|
|
44
|
+
backend: The device (hardware or simulator) on which to run the quantum program. Specified as "provider/device_id". Use the `get_backend_details` function to see supported devices.
|
|
226
45
|
parameters: The classical parameters for the quantum program
|
|
227
46
|
config: Provider-specific configuration, such as api keys
|
|
228
47
|
num_shots: The number of times to sample
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from pandas import DataFrame
|
|
5
|
+
|
|
6
|
+
from classiq.interface.backend.backend_preferences import (
|
|
7
|
+
BackendPreferencesTypes,
|
|
8
|
+
ClassiqBackendPreferences,
|
|
9
|
+
GCPBackendPreferences,
|
|
10
|
+
)
|
|
11
|
+
from classiq.interface.backend.quantum_backend_providers import (
|
|
12
|
+
ClassiqNvidiaBackendNames,
|
|
13
|
+
ClassiqSimulatorBackendNames,
|
|
14
|
+
GoogleNvidiaBackendNames,
|
|
15
|
+
)
|
|
16
|
+
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
|
17
|
+
from classiq.interface.generator.model.preferences import create_random_seed
|
|
18
|
+
from classiq.interface.generator.model.preferences.preferences import (
|
|
19
|
+
TranspilationOption,
|
|
20
|
+
)
|
|
21
|
+
from classiq.interface.hardware import Provider
|
|
22
|
+
|
|
23
|
+
from classiq import (
|
|
24
|
+
ExecutionParams,
|
|
25
|
+
QuantumProgram,
|
|
26
|
+
)
|
|
27
|
+
from classiq.execution import ExecutionSession
|
|
28
|
+
from classiq.execution.functions.util._logging import _logger
|
|
29
|
+
from classiq.execution.functions.util.constants import Verbosity
|
|
30
|
+
from classiq.execution.functions.util.parse_provider_backend import (
|
|
31
|
+
_PROVIDER_TO_CANONICAL_NAME,
|
|
32
|
+
_parse_provider_backend,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
_DEFAULT_STATE_VECTOR_BACKEND_NAME = "simulator"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _calculate_state_vector(
|
|
39
|
+
qprog: QuantumProgram,
|
|
40
|
+
backend: str | None = None,
|
|
41
|
+
*,
|
|
42
|
+
parameters: ExecutionParams | None = None,
|
|
43
|
+
filters: dict[str, Any] | None = None,
|
|
44
|
+
random_seed: int | None = None,
|
|
45
|
+
transpilation_option: TranspilationOption = TranspilationOption.DECOMPOSE,
|
|
46
|
+
verbosity: Verbosity = Verbosity.INFO,
|
|
47
|
+
) -> "DataFrame":
|
|
48
|
+
"""
|
|
49
|
+
Calculate the state vector of a quantum program.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
qprog: The quantum program
|
|
53
|
+
backend: The simulator on which to simulate the quantum program. Specified as "provider/device_id"
|
|
54
|
+
parameters: The classical parameters for the quantum program
|
|
55
|
+
filters: Only states where the variables match these values will be included in the state vector.
|
|
56
|
+
random_seed: The random seed used for transpilation and simulation
|
|
57
|
+
transpilation_option: Advanced configuration for hardware-specific transpilation
|
|
58
|
+
verbosity: What level of information should be logged
|
|
59
|
+
|
|
60
|
+
Returns: A dataframe containing the state vector
|
|
61
|
+
"""
|
|
62
|
+
if backend is None:
|
|
63
|
+
backend = _DEFAULT_STATE_VECTOR_BACKEND_NAME
|
|
64
|
+
|
|
65
|
+
provider, raw_backend_name = _parse_provider_backend(backend)
|
|
66
|
+
backend_name_lower = raw_backend_name.lower()
|
|
67
|
+
backend_preferences: BackendPreferencesTypes
|
|
68
|
+
|
|
69
|
+
if provider == Provider.CLASSIQ:
|
|
70
|
+
if backend_name_lower == "simulator":
|
|
71
|
+
backend_name = str(ClassiqSimulatorBackendNames.SIMULATOR_STATEVECTOR)
|
|
72
|
+
elif backend_name_lower == "nvidia_simulator":
|
|
73
|
+
backend_name = str(ClassiqNvidiaBackendNames.SIMULATOR_STATEVECTOR)
|
|
74
|
+
else:
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"Unsupported backend '{backend}'. "
|
|
77
|
+
"Under the Classiq provider, only 'classiq/simulator' and 'classiq/nvidia_simulator' are supported."
|
|
78
|
+
)
|
|
79
|
+
backend_preferences = ClassiqBackendPreferences(backend_name=backend_name)
|
|
80
|
+
elif provider == Provider.GOOGLE:
|
|
81
|
+
if backend_name_lower == "cuquantum":
|
|
82
|
+
backend_name = str(GoogleNvidiaBackendNames.CUQUANTUM_STATEVECTOR)
|
|
83
|
+
else:
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"Unsupported backend '{backend}'. "
|
|
86
|
+
"Under the Google provider, only 'google/cuquantum' is supported."
|
|
87
|
+
)
|
|
88
|
+
backend_preferences = GCPBackendPreferences(backend_name=backend_name)
|
|
89
|
+
else:
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"Provider '{_PROVIDER_TO_CANONICAL_NAME.get(provider) or provider}' does not support this operation."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
ep = ExecutionPreferences(
|
|
95
|
+
backend_preferences=backend_preferences,
|
|
96
|
+
random_seed=create_random_seed() if random_seed is None else random_seed,
|
|
97
|
+
transpile_to_hardware=transpilation_option,
|
|
98
|
+
)
|
|
99
|
+
if verbosity != Verbosity.QUIET:
|
|
100
|
+
_logger.info(f"Submitting job to {backend}")
|
|
101
|
+
with ExecutionSession(qprog, execution_preferences=ep) as session:
|
|
102
|
+
if filters is not None:
|
|
103
|
+
for output_name, value in filters.items():
|
|
104
|
+
session.set_measured_state_filter(
|
|
105
|
+
output_name, lambda state, val=value: state == val
|
|
106
|
+
)
|
|
107
|
+
job = session.submit_sample(parameters)
|
|
108
|
+
if verbosity != Verbosity.QUIET:
|
|
109
|
+
_logger.info(f"Job id: {job.id}")
|
|
110
|
+
result = job.get_sample_result()
|
|
111
|
+
|
|
112
|
+
df = result.dataframe
|
|
113
|
+
return df
|
|
File without changes
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, Literal
|
|
4
|
+
|
|
5
|
+
from classiq.interface.backend.backend_preferences import (
|
|
6
|
+
AliceBobBackendPreferences,
|
|
7
|
+
AQTBackendPreferences,
|
|
8
|
+
AwsBackendPreferences,
|
|
9
|
+
AzureBackendPreferences,
|
|
10
|
+
AzureCredential,
|
|
11
|
+
BackendPreferencesTypes,
|
|
12
|
+
ClassiqBackendPreferences,
|
|
13
|
+
GCPBackendPreferences,
|
|
14
|
+
IBMBackendPreferences,
|
|
15
|
+
IntelBackendPreferences,
|
|
16
|
+
IonqBackendPreferences,
|
|
17
|
+
)
|
|
18
|
+
from classiq.interface.backend.provider_config.provider_config import ProviderConfig
|
|
19
|
+
from classiq.interface.backend.provider_config.providers.alice_bob import AliceBobConfig
|
|
20
|
+
from classiq.interface.backend.provider_config.providers.aqt import AQTConfig
|
|
21
|
+
from classiq.interface.backend.provider_config.providers.azure import AzureConfig
|
|
22
|
+
from classiq.interface.backend.provider_config.providers.braket import BraketConfig
|
|
23
|
+
from classiq.interface.backend.provider_config.providers.ibm import IBMConfig
|
|
24
|
+
from classiq.interface.backend.provider_config.providers.ionq import IonQConfig
|
|
25
|
+
from classiq.interface.backend.quantum_backend_providers import (
|
|
26
|
+
ClassiqNvidiaBackendNames,
|
|
27
|
+
ClassiqSimulatorBackendNames,
|
|
28
|
+
)
|
|
29
|
+
from classiq.interface.hardware import Provider
|
|
30
|
+
|
|
31
|
+
from classiq.execution.functions.util.parse_provider_backend import (
|
|
32
|
+
_PROVIDER_TO_CANONICAL_NAME,
|
|
33
|
+
_parse_provider_backend,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class _ProviderConfigToBackendPrefSpec:
|
|
39
|
+
backend_preferences_class: type[BackendPreferencesTypes]
|
|
40
|
+
config_class: type[ProviderConfig] | None = None
|
|
41
|
+
# Maps the config dict (either passed in directly or dumped from config class) to a
|
|
42
|
+
# dict that we can load into the given BackendPreferences class. This is in case
|
|
43
|
+
# we need to rename fields or change structure.
|
|
44
|
+
config_dict_to_backend_preferences_dict: (
|
|
45
|
+
Callable[[dict[str, Any]], dict[str, Any]] | None
|
|
46
|
+
) = None
|
|
47
|
+
# Maps from SDK names to names our backend recognizes, raising a useful error
|
|
48
|
+
# if the name is unrecognized.
|
|
49
|
+
backend_name_mapper: Callable[[str], str] | None = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _classiq_backend_name_mapper(backend_name: str) -> str:
|
|
53
|
+
backend_name = backend_name.lower()
|
|
54
|
+
if backend_name in [
|
|
55
|
+
ClassiqSimulatorBackendNames.SIMULATOR,
|
|
56
|
+
ClassiqSimulatorBackendNames.SIMULATOR_MATRIX_PRODUCT_STATE,
|
|
57
|
+
ClassiqSimulatorBackendNames.SIMULATOR_DENSITY_MATRIX,
|
|
58
|
+
]:
|
|
59
|
+
return backend_name
|
|
60
|
+
if backend_name == "nvidia_simulator":
|
|
61
|
+
return ClassiqNvidiaBackendNames.SIMULATOR
|
|
62
|
+
if any(keyword in backend_name for keyword in ["gpu", "nvidia"]):
|
|
63
|
+
suggested_backend_name = "nvidia_simulator"
|
|
64
|
+
else:
|
|
65
|
+
suggested_backend_name = "simulator"
|
|
66
|
+
raise ValueError(
|
|
67
|
+
f"Unsupported backend name {backend_name}. Did you mean '{suggested_backend_name}'?"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _ibm_backend_name_mapper(backend_name: str) -> str:
|
|
72
|
+
ibm_prefix: Literal["ibm_"] = "ibm_"
|
|
73
|
+
backend_name = backend_name.lower()
|
|
74
|
+
if backend_name.startswith(ibm_prefix):
|
|
75
|
+
backend_name_no_prefix = backend_name.removeprefix(ibm_prefix)
|
|
76
|
+
raise ValueError(
|
|
77
|
+
f"IBM backend names shouldn't start with ibm_. Try 'ibm/{backend_name_no_prefix}'."
|
|
78
|
+
)
|
|
79
|
+
return ibm_prefix + backend_name
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _azure_config_dict_to_backend_preferences_dict(
|
|
83
|
+
config_dict: dict[str, Any],
|
|
84
|
+
) -> dict[str, Any]:
|
|
85
|
+
if "location" not in config_dict:
|
|
86
|
+
raise ValueError("Azure config must have 'location' property")
|
|
87
|
+
credentials = None
|
|
88
|
+
if all(
|
|
89
|
+
config_dict.get(key) is not None
|
|
90
|
+
for key in ["tenant_id", "client_id", "client_secret", "resource_id"]
|
|
91
|
+
):
|
|
92
|
+
credentials = AzureCredential.model_validate(
|
|
93
|
+
{
|
|
94
|
+
"tenant_id": config_dict["tenant_id"],
|
|
95
|
+
"client_id": config_dict["client_id"],
|
|
96
|
+
"client_secret": config_dict["client_secret"],
|
|
97
|
+
"resource_id": config_dict["resource_id"],
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
return {
|
|
101
|
+
"location": config_dict["location"],
|
|
102
|
+
"credentials": credentials,
|
|
103
|
+
"ionq_error_mitigation_flag": config_dict.get("ionq_error_mitigation"),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _braket_config_dict_to_backend_preferences_dict(
|
|
108
|
+
config_dict: dict[str, Any],
|
|
109
|
+
) -> dict[str, Any]:
|
|
110
|
+
config_dict["aws_access_key_id"] = config_dict.pop("braket_access_key_id", None)
|
|
111
|
+
config_dict["aws_secret_access_key"] = config_dict.pop(
|
|
112
|
+
"braket_secret_access_key", None
|
|
113
|
+
)
|
|
114
|
+
return config_dict
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
_PROVIDER_CONFIG_TO_BACKEND_PREFERENCES_SPEC = {
|
|
118
|
+
Provider.CLASSIQ: _ProviderConfigToBackendPrefSpec(
|
|
119
|
+
backend_preferences_class=ClassiqBackendPreferences,
|
|
120
|
+
backend_name_mapper=_classiq_backend_name_mapper,
|
|
121
|
+
),
|
|
122
|
+
Provider.GOOGLE: _ProviderConfigToBackendPrefSpec(
|
|
123
|
+
backend_preferences_class=GCPBackendPreferences
|
|
124
|
+
),
|
|
125
|
+
Provider.INTEL: _ProviderConfigToBackendPrefSpec(
|
|
126
|
+
backend_preferences_class=IntelBackendPreferences
|
|
127
|
+
),
|
|
128
|
+
Provider.IBM_QUANTUM: _ProviderConfigToBackendPrefSpec(
|
|
129
|
+
backend_preferences_class=IBMBackendPreferences,
|
|
130
|
+
config_class=IBMConfig,
|
|
131
|
+
backend_name_mapper=_ibm_backend_name_mapper,
|
|
132
|
+
),
|
|
133
|
+
Provider.AMAZON_BRAKET: _ProviderConfigToBackendPrefSpec(
|
|
134
|
+
backend_preferences_class=AwsBackendPreferences,
|
|
135
|
+
config_dict_to_backend_preferences_dict=_braket_config_dict_to_backend_preferences_dict,
|
|
136
|
+
config_class=BraketConfig,
|
|
137
|
+
),
|
|
138
|
+
Provider.IONQ: _ProviderConfigToBackendPrefSpec(
|
|
139
|
+
backend_preferences_class=IonqBackendPreferences,
|
|
140
|
+
config_class=IonQConfig,
|
|
141
|
+
),
|
|
142
|
+
Provider.ALICE_AND_BOB: _ProviderConfigToBackendPrefSpec(
|
|
143
|
+
backend_preferences_class=AliceBobBackendPreferences,
|
|
144
|
+
config_class=AliceBobConfig,
|
|
145
|
+
),
|
|
146
|
+
Provider.AQT: _ProviderConfigToBackendPrefSpec(
|
|
147
|
+
backend_preferences_class=AQTBackendPreferences,
|
|
148
|
+
config_class=AQTConfig,
|
|
149
|
+
),
|
|
150
|
+
Provider.AZURE_QUANTUM: _ProviderConfigToBackendPrefSpec(
|
|
151
|
+
backend_preferences_class=AzureBackendPreferences,
|
|
152
|
+
config_dict_to_backend_preferences_dict=_azure_config_dict_to_backend_preferences_dict,
|
|
153
|
+
config_class=AzureConfig,
|
|
154
|
+
),
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _get_backend_preferences_from_specifier(
|
|
159
|
+
backend_spec: str, config: dict[str, Any] | ProviderConfig
|
|
160
|
+
) -> BackendPreferencesTypes:
|
|
161
|
+
provider, backend_name = _parse_provider_backend(backend_spec)
|
|
162
|
+
|
|
163
|
+
if provider not in _PROVIDER_CONFIG_TO_BACKEND_PREFERENCES_SPEC:
|
|
164
|
+
raise NotImplementedError(
|
|
165
|
+
f"Unsupported provider '{_PROVIDER_TO_CANONICAL_NAME.get(provider) or provider}'"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
provider_spec = _PROVIDER_CONFIG_TO_BACKEND_PREFERENCES_SPEC[provider]
|
|
169
|
+
if isinstance(config, ProviderConfig):
|
|
170
|
+
if provider_spec.config_class is None:
|
|
171
|
+
raise ValueError(
|
|
172
|
+
f"This provider does not support any ProviderConfig classes. Received '{config.__class__.__name__}'"
|
|
173
|
+
)
|
|
174
|
+
if not isinstance(config, provider_spec.config_class):
|
|
175
|
+
raise ValueError(
|
|
176
|
+
f"{_PROVIDER_TO_CANONICAL_NAME[provider]} devices require {provider_spec.config_class.__name__}, got {config.__class__.__name__}"
|
|
177
|
+
)
|
|
178
|
+
config_dict = config.model_dump()
|
|
179
|
+
else:
|
|
180
|
+
config_dict = config
|
|
181
|
+
if provider_spec.backend_name_mapper is not None:
|
|
182
|
+
backend_name = provider_spec.backend_name_mapper(backend_name)
|
|
183
|
+
|
|
184
|
+
if provider_spec.config_dict_to_backend_preferences_dict is not None:
|
|
185
|
+
config_dict = provider_spec.config_dict_to_backend_preferences_dict(config_dict)
|
|
186
|
+
|
|
187
|
+
config_dict["backend_name"] = backend_name
|
|
188
|
+
return provider_spec.backend_preferences_class.model_validate(config_dict)
|
classiq/interface/_version.py
CHANGED
|
@@ -468,6 +468,70 @@ class SoftbankBackendPreferences(BackendPreferences):
|
|
|
468
468
|
)
|
|
469
469
|
|
|
470
470
|
|
|
471
|
+
class C12BackendPreferences(BackendPreferences):
|
|
472
|
+
"""
|
|
473
|
+
Represents the backend preferences specific to C12.
|
|
474
|
+
|
|
475
|
+
Attributes:
|
|
476
|
+
backend_name: Name of the requested backend or target.
|
|
477
|
+
result_format: Result format of the job; one of "counts",
|
|
478
|
+
"state_vector", or "density_matrix". Defaults to "counts".
|
|
479
|
+
inilabel: Initial state specified using a binary label format
|
|
480
|
+
(e.g. "00", "01"). Mutually exclusive with inistatevector.
|
|
481
|
+
inistatevector: Initial state vector as a comma-separated list of
|
|
482
|
+
complex values (e.g. "1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j").
|
|
483
|
+
Mutually exclusive with inilabel.
|
|
484
|
+
ininoisy: Whether to use noisy initialization of the circuit.
|
|
485
|
+
"""
|
|
486
|
+
|
|
487
|
+
backend_service_provider: ProviderTypeVendor.C12 = pydantic.Field(
|
|
488
|
+
default=ProviderVendor.C12
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
result_format: str = pydantic.Field(
|
|
492
|
+
default="counts", description="Result format of the job"
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
inilabel: str | None = pydantic.Field(
|
|
496
|
+
default=None, description="Initial label of the initial state."
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
inistatevector: str | None = pydantic.Field(
|
|
500
|
+
default=None, description="Initial state vector of the job."
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
ininoisy: bool | None = pydantic.Field(
|
|
504
|
+
default=None, description="Whether the initial state is noisy."
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
@pydantic.model_validator(mode="after")
|
|
508
|
+
def _validate_initial_label_statevector(
|
|
509
|
+
self: C12BackendPreferences,
|
|
510
|
+
) -> C12BackendPreferences:
|
|
511
|
+
if self.inilabel is not None and self.inistatevector is not None:
|
|
512
|
+
raise ValueError(
|
|
513
|
+
f"Cannot specify both inilabel and inistatevector.\n"
|
|
514
|
+
f"inilabel={self.inilabel}, inistatevector={self.inistatevector}"
|
|
515
|
+
)
|
|
516
|
+
return self
|
|
517
|
+
|
|
518
|
+
@pydantic.field_validator("result_format")
|
|
519
|
+
@classmethod
|
|
520
|
+
def _validate_result_format(cls, result_format: str) -> str:
|
|
521
|
+
if result_format not in ["density_matrix", "state_vector", "counts"]:
|
|
522
|
+
raise ValueError(f"Invalid result format: {result_format}")
|
|
523
|
+
return result_format
|
|
524
|
+
|
|
525
|
+
@property
|
|
526
|
+
def parameters(self) -> dict:
|
|
527
|
+
data = self.model_dump(exclude_none=True)
|
|
528
|
+
for field in ["inilabel", "inistatevector", "ininoisy"]:
|
|
529
|
+
if field in data and data[field] is None:
|
|
530
|
+
data.pop(field)
|
|
531
|
+
|
|
532
|
+
return data
|
|
533
|
+
|
|
534
|
+
|
|
471
535
|
def is_exact_simulator(backend_preferences: BackendPreferences) -> bool:
|
|
472
536
|
return backend_preferences.backend_name in EXACT_SIMULATORS
|
|
473
537
|
|
|
@@ -501,6 +565,7 @@ BackendPreferencesTypes = Union[
|
|
|
501
565
|
AQTBackendPreferences,
|
|
502
566
|
CINECABackendPreferences,
|
|
503
567
|
SoftbankBackendPreferences,
|
|
568
|
+
C12BackendPreferences,
|
|
504
569
|
]
|
|
505
570
|
|
|
506
571
|
__all__ = [
|
|
@@ -512,6 +577,7 @@ __all__ = [
|
|
|
512
577
|
"AzureBackendPreferences",
|
|
513
578
|
"AzureCredential",
|
|
514
579
|
"AzureQuantumBackendNames",
|
|
580
|
+
"C12BackendPreferences",
|
|
515
581
|
"ClassiqBackendPreferences",
|
|
516
582
|
"ClassiqNvidiaBackendNames",
|
|
517
583
|
"ClassiqSimulatorBackendNames",
|
|
@@ -28,6 +28,7 @@ class ProviderVendor(StrEnum):
|
|
|
28
28
|
AQT = "AQT"
|
|
29
29
|
CINECA = "CINECA"
|
|
30
30
|
SOFTBANK = "Softbank"
|
|
31
|
+
C12 = "C12"
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class ProviderTypeVendor:
|
|
@@ -43,6 +44,7 @@ class ProviderTypeVendor:
|
|
|
43
44
|
AQT = Literal[ProviderVendor.AQT]
|
|
44
45
|
CINECA = Literal[ProviderVendor.CINECA]
|
|
45
46
|
SOFTBANK = Literal[ProviderVendor.SOFTBANK]
|
|
47
|
+
C12 = Literal[ProviderVendor.C12]
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
PROVIDER_NAME_MAPPER = {
|
|
@@ -57,6 +59,7 @@ PROVIDER_NAME_MAPPER = {
|
|
|
57
59
|
ProviderVendor.AQT: "AQT",
|
|
58
60
|
ProviderVendor.CLASSIQ: "CLASSIQ",
|
|
59
61
|
ProviderVendor.SOFTBANK: "SOFTBANK",
|
|
62
|
+
ProviderVendor.C12: "C12",
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
|
|
@@ -248,6 +251,11 @@ class OQCBackendNames(StrEnum):
|
|
|
248
251
|
LUCY = "Lucy"
|
|
249
252
|
|
|
250
253
|
|
|
254
|
+
class C12BackendNames(StrEnum):
|
|
255
|
+
SIMULATOR = "c12sim-iswap"
|
|
256
|
+
SQUARED = "squared-iswap"
|
|
257
|
+
|
|
258
|
+
|
|
251
259
|
EXACT_SIMULATORS = {
|
|
252
260
|
IonqBackendNames.SIMULATOR,
|
|
253
261
|
AzureQuantumBackendNames.IONQ_SIMULATOR,
|
|
@@ -258,6 +266,7 @@ EXACT_SIMULATORS = {
|
|
|
258
266
|
*ClassiqSimulatorBackendNames,
|
|
259
267
|
*IntelBackendNames,
|
|
260
268
|
*ClassiqNvidiaBackendNames,
|
|
269
|
+
*C12BackendNames,
|
|
261
270
|
}
|
|
262
271
|
|
|
263
272
|
AllIBMQBackendNames = IBMQHardwareNames
|
|
@@ -271,6 +280,7 @@ AllBackendsNameByVendor = Union[
|
|
|
271
280
|
ClassiqNvidiaBackendNames,
|
|
272
281
|
AliceBobBackendNames,
|
|
273
282
|
OQCBackendNames,
|
|
283
|
+
C12BackendNames,
|
|
274
284
|
]
|
|
275
285
|
|
|
276
286
|
AllBackendsNameEnums = [
|
|
@@ -282,4 +292,5 @@ AllBackendsNameEnums = [
|
|
|
282
292
|
IntelBackendNames,
|
|
283
293
|
ClassiqNvidiaBackendNames,
|
|
284
294
|
OQCBackendNames,
|
|
295
|
+
C12BackendNames,
|
|
285
296
|
]
|
classiq/interface/exceptions.py
CHANGED
|
@@ -39,10 +39,6 @@ class ClassiqAnalyzerError(ClassiqError):
|
|
|
39
39
|
pass
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
class ClassiqAnalyzerVisualizationError(ClassiqError):
|
|
43
|
-
pass
|
|
44
|
-
|
|
45
|
-
|
|
46
42
|
class ClassiqAPIError(ClassiqError):
|
|
47
43
|
def __init__(self, message: str, status_code: int | None = None) -> None:
|
|
48
44
|
self.status_code = status_code
|