classiq 0.102.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/chemistry/op_utils.py +32 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +1 -1
- classiq/evaluators/qmod_annotated_expression.py +1 -1
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
- classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
- classiq/execution/all_hardware_devices.py +59 -1
- classiq/execution/execution_session.py +1 -1
- classiq/execution/functions/__init__.py +13 -0
- classiq/execution/functions/expectation_value.py +106 -0
- classiq/execution/functions/minimize.py +90 -0
- classiq/execution/functions/sample.py +76 -0
- classiq/execution/functions/state_vector.py +113 -0
- classiq/execution/functions/util/__init__.py +0 -0
- classiq/execution/functions/util/_logging.py +19 -0
- classiq/execution/functions/util/backend_preferences.py +188 -0
- classiq/execution/functions/util/constants.py +9 -0
- classiq/execution/functions/util/parse_provider_backend.py +90 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +81 -0
- classiq/interface/backend/provider_config/providers/aqt.py +1 -1
- classiq/interface/backend/provider_config/providers/azure.py +1 -2
- classiq/interface/backend/provider_config/providers/ibm.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +14 -0
- classiq/interface/exceptions.py +0 -4
- classiq/interface/executor/result.py +9 -5
- classiq/interface/generator/arith/binary_ops.py +62 -2
- classiq/interface/generator/arith/number_utils.py +15 -6
- classiq/interface/generator/compiler_keywords.py +1 -0
- classiq/interface/generator/function_param_list.py +8 -2
- classiq/interface/generator/function_params.py +1 -1
- classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
- classiq/interface/generator/functions/classical_type.py +60 -0
- classiq/interface/generator/functions/type_name.py +36 -0
- classiq/interface/generator/generated_circuit_data.py +0 -2
- classiq/interface/generator/transpiler_basis_gates.py +1 -0
- classiq/interface/generator/types/compilation_metadata.py +18 -0
- classiq/interface/hardware.py +2 -0
- classiq/interface/helpers/model_normalizer.py +42 -6
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/invert.py +8 -0
- classiq/interface/model/model.py +19 -0
- classiq/interface/model/model_visitor.py +4 -2
- classiq/interface/model/quantum_type.py +36 -0
- classiq/interface/model/statement_block.py +0 -4
- 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/model_expansions/capturing/captured_vars.py +16 -12
- classiq/model_expansions/function_builder.py +9 -1
- classiq/model_expansions/interpreters/base_interpreter.py +9 -8
- classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
- classiq/model_expansions/quantum_operations/bind.py +4 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
- classiq/model_expansions/quantum_operations/emitter.py +1 -4
- classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
- classiq/model_expansions/visitors/uncomputation_signature_inference.py +0 -9
- classiq/qmod/builtins/functions/__init__.py +21 -9
- classiq/qmod/builtins/functions/allocation.py +0 -36
- classiq/qmod/builtins/functions/arithmetic.py +183 -0
- classiq/qmod/builtins/functions/exponentiation.py +32 -2
- classiq/qmod/builtins/functions/gray_code.py +23 -0
- classiq/qmod/builtins/functions/mcx_func.py +10 -0
- classiq/qmod/builtins/operations.py +2 -38
- classiq/qmod/builtins/structs.py +22 -3
- classiq/qmod/native/pretty_printer.py +1 -12
- classiq/qmod/pretty_print/pretty_printer.py +1 -17
- classiq/qmod/qmod_parameter.py +4 -0
- classiq/qmod/qmod_variable.py +38 -63
- classiq/qmod/quantum_function.py +43 -7
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
- classiq/qmod/semantics/validation/model_validation.py +7 -2
- classiq/qmod/symbolic_type.py +4 -2
- classiq/qprog_to_cudaq.py +347 -0
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/METADATA +4 -1
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/RECORD +93 -76
- classiq/interface/generator/amplitude_loading.py +0 -103
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/WHEEL +0 -0
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -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)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from classiq.interface.hardware import Provider
|
|
2
|
+
|
|
3
|
+
_PROVIDER_BACKEND_SEPARATOR = "/"
|
|
4
|
+
|
|
5
|
+
_PROVIDER_TO_CANONICAL_NAME: dict[Provider, str] = {
|
|
6
|
+
Provider.IBM_QUANTUM: "ibm",
|
|
7
|
+
Provider.AZURE_QUANTUM: "azure",
|
|
8
|
+
Provider.AMAZON_BRAKET: "braket",
|
|
9
|
+
Provider.IONQ: "ionq",
|
|
10
|
+
Provider.CLASSIQ: "classiq",
|
|
11
|
+
Provider.GOOGLE: "google",
|
|
12
|
+
Provider.ALICE_AND_BOB: "alice&bob",
|
|
13
|
+
Provider.OQC: "oqc",
|
|
14
|
+
Provider.INTEL: "intel",
|
|
15
|
+
Provider.AQT: "aqt",
|
|
16
|
+
Provider.CINECA: "cineca",
|
|
17
|
+
Provider.SOFTBANK: "softbank",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_CANONICAL_NAMES_TO_PROVIDER: dict[str, Provider] = {
|
|
21
|
+
name: provider for provider, name in _PROVIDER_TO_CANONICAL_NAME.items()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _error_suggested_provider(provider_name: str) -> Provider | None:
|
|
26
|
+
"""
|
|
27
|
+
In the case that receive an incorrect provider name, return a possible suggestion.
|
|
28
|
+
"""
|
|
29
|
+
provider_name = provider_name.strip().lower()
|
|
30
|
+
for canonical_name in _CANONICAL_NAMES_TO_PROVIDER:
|
|
31
|
+
if canonical_name in provider_name:
|
|
32
|
+
return _CANONICAL_NAMES_TO_PROVIDER[canonical_name]
|
|
33
|
+
# Special cases
|
|
34
|
+
if "gcp" in provider_name:
|
|
35
|
+
return Provider.GOOGLE
|
|
36
|
+
if "microsoft" in provider_name:
|
|
37
|
+
return Provider.AZURE_QUANTUM
|
|
38
|
+
if "amazon" in provider_name or "aws" in provider_name:
|
|
39
|
+
return Provider.AMAZON_BRAKET
|
|
40
|
+
if "oxford" in provider_name:
|
|
41
|
+
return Provider.OQC
|
|
42
|
+
if "alice" in provider_name or "bob" in provider_name:
|
|
43
|
+
return Provider.ALICE_AND_BOB
|
|
44
|
+
if "alpine" in provider_name:
|
|
45
|
+
return Provider.AQT
|
|
46
|
+
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _parse_provider_backend(spec: str) -> tuple[Provider, str]:
|
|
51
|
+
"""
|
|
52
|
+
Parse a backend specification into (provider, backend). Provider is case-insensitive.
|
|
53
|
+
Backend must NOT contain the separator. If provider is not specified, it defaults to
|
|
54
|
+
Classiq.
|
|
55
|
+
"""
|
|
56
|
+
if not spec.strip():
|
|
57
|
+
raise ValueError("Backend specification must be a non-empty string")
|
|
58
|
+
|
|
59
|
+
spec = spec.strip()
|
|
60
|
+
|
|
61
|
+
if _PROVIDER_BACKEND_SEPARATOR not in spec:
|
|
62
|
+
return Provider.CLASSIQ, spec
|
|
63
|
+
|
|
64
|
+
provider_raw, backend = spec.split(_PROVIDER_BACKEND_SEPARATOR, 1)
|
|
65
|
+
|
|
66
|
+
if _PROVIDER_BACKEND_SEPARATOR in backend:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Backend name must not contain '{_PROVIDER_BACKEND_SEPARATOR}': '{backend}'"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
provider_key = provider_raw.strip().lower()
|
|
72
|
+
backend = backend.strip()
|
|
73
|
+
|
|
74
|
+
if not provider_key:
|
|
75
|
+
raise ValueError("Provider name cannot be empty")
|
|
76
|
+
if not backend:
|
|
77
|
+
raise ValueError("Backend name cannot be empty")
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
provider = _CANONICAL_NAMES_TO_PROVIDER[provider_key]
|
|
81
|
+
except KeyError:
|
|
82
|
+
error_message = f"Unrecognized provider '{provider_raw}'."
|
|
83
|
+
suggested_provider = _error_suggested_provider(provider_key)
|
|
84
|
+
if suggested_provider is not None:
|
|
85
|
+
error_message += (
|
|
86
|
+
f" Did you mean '{_PROVIDER_TO_CANONICAL_NAME[suggested_provider]}'?"
|
|
87
|
+
)
|
|
88
|
+
raise ValueError(error_message) from None
|
|
89
|
+
|
|
90
|
+
return provider, backend
|
classiq/interface/_version.py
CHANGED
|
@@ -454,6 +454,84 @@ class CINECABackendPreferences(BackendPreferences):
|
|
|
454
454
|
)
|
|
455
455
|
|
|
456
456
|
|
|
457
|
+
class SoftbankBackendPreferences(BackendPreferences):
|
|
458
|
+
"""
|
|
459
|
+
Represents the backend preferences specific to Softbank.
|
|
460
|
+
"""
|
|
461
|
+
|
|
462
|
+
backend_service_provider: ProviderTypeVendor.SOFTBANK = pydantic.Field(
|
|
463
|
+
default=ProviderVendor.SOFTBANK
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
priority: int | None = pydantic.Field(
|
|
467
|
+
default=None, description="Priority of the job"
|
|
468
|
+
)
|
|
469
|
+
|
|
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
|
+
|
|
457
535
|
def is_exact_simulator(backend_preferences: BackendPreferences) -> bool:
|
|
458
536
|
return backend_preferences.backend_name in EXACT_SIMULATORS
|
|
459
537
|
|
|
@@ -486,6 +564,8 @@ BackendPreferencesTypes = Union[
|
|
|
486
564
|
IntelBackendPreferences,
|
|
487
565
|
AQTBackendPreferences,
|
|
488
566
|
CINECABackendPreferences,
|
|
567
|
+
SoftbankBackendPreferences,
|
|
568
|
+
C12BackendPreferences,
|
|
489
569
|
]
|
|
490
570
|
|
|
491
571
|
__all__ = [
|
|
@@ -497,6 +577,7 @@ __all__ = [
|
|
|
497
577
|
"AzureBackendPreferences",
|
|
498
578
|
"AzureCredential",
|
|
499
579
|
"AzureQuantumBackendNames",
|
|
580
|
+
"C12BackendPreferences",
|
|
500
581
|
"ClassiqBackendPreferences",
|
|
501
582
|
"ClassiqNvidiaBackendNames",
|
|
502
583
|
"ClassiqSimulatorBackendNames",
|
|
@@ -12,5 +12,5 @@ class AQTConfig(ProviderConfig):
|
|
|
12
12
|
workspace: The AQT workspace where the simulator/hardware is located.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
api_key: str
|
|
15
|
+
api_key: str = pydantic.Field(description="AQT API key")
|
|
16
16
|
workspace: str = pydantic.Field(description="AQT workspace")
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import pydantic
|
|
2
2
|
|
|
3
|
-
from classiq.interface.backend import pydantic_backend
|
|
4
3
|
from classiq.interface.backend.provider_config.provider_config import ProviderConfig
|
|
5
4
|
|
|
6
5
|
|
|
@@ -26,7 +25,7 @@ class AzureConfig(ProviderConfig):
|
|
|
26
25
|
client_secret: str | None = pydantic.Field(
|
|
27
26
|
default=None, description="Azure Client Secret"
|
|
28
27
|
)
|
|
29
|
-
resource_id:
|
|
28
|
+
resource_id: str | None = pydantic.Field(
|
|
30
29
|
default=None,
|
|
31
30
|
description="Azure Resource ID (including Azure subscription ID, resource "
|
|
32
31
|
"group and workspace), for personal resource",
|
|
@@ -10,7 +10,7 @@ class IBMConfig(ProviderConfig):
|
|
|
10
10
|
Attributes:
|
|
11
11
|
access_token (str | None): The IBM Cloud access token to be used with IBM Quantum hosted backends. Defaults to `None`.
|
|
12
12
|
channel (str): Channel to use for IBM cloud backends. Defaults to `"ibm_cloud"`.
|
|
13
|
-
instance_crn (str): The IBM Cloud instance CRN (Cloud Resource Name) for the IBM Quantum service.
|
|
13
|
+
instance_crn (str | None): The IBM Cloud instance CRN (Cloud Resource Name) for the IBM Quantum service.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
access_token: str | None = pydantic.Field(
|
|
@@ -27,6 +27,8 @@ class ProviderVendor(StrEnum):
|
|
|
27
27
|
INTEL = "Intel"
|
|
28
28
|
AQT = "AQT"
|
|
29
29
|
CINECA = "CINECA"
|
|
30
|
+
SOFTBANK = "Softbank"
|
|
31
|
+
C12 = "C12"
|
|
30
32
|
|
|
31
33
|
|
|
32
34
|
class ProviderTypeVendor:
|
|
@@ -41,6 +43,8 @@ class ProviderTypeVendor:
|
|
|
41
43
|
INTEL = Literal[ProviderVendor.INTEL]
|
|
42
44
|
AQT = Literal[ProviderVendor.AQT]
|
|
43
45
|
CINECA = Literal[ProviderVendor.CINECA]
|
|
46
|
+
SOFTBANK = Literal[ProviderVendor.SOFTBANK]
|
|
47
|
+
C12 = Literal[ProviderVendor.C12]
|
|
44
48
|
|
|
45
49
|
|
|
46
50
|
PROVIDER_NAME_MAPPER = {
|
|
@@ -54,6 +58,8 @@ PROVIDER_NAME_MAPPER = {
|
|
|
54
58
|
ProviderVendor.INTEL: "INTEL",
|
|
55
59
|
ProviderVendor.AQT: "AQT",
|
|
56
60
|
ProviderVendor.CLASSIQ: "CLASSIQ",
|
|
61
|
+
ProviderVendor.SOFTBANK: "SOFTBANK",
|
|
62
|
+
ProviderVendor.C12: "C12",
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
|
|
@@ -245,6 +251,11 @@ class OQCBackendNames(StrEnum):
|
|
|
245
251
|
LUCY = "Lucy"
|
|
246
252
|
|
|
247
253
|
|
|
254
|
+
class C12BackendNames(StrEnum):
|
|
255
|
+
SIMULATOR = "c12sim-iswap"
|
|
256
|
+
SQUARED = "squared-iswap"
|
|
257
|
+
|
|
258
|
+
|
|
248
259
|
EXACT_SIMULATORS = {
|
|
249
260
|
IonqBackendNames.SIMULATOR,
|
|
250
261
|
AzureQuantumBackendNames.IONQ_SIMULATOR,
|
|
@@ -255,6 +266,7 @@ EXACT_SIMULATORS = {
|
|
|
255
266
|
*ClassiqSimulatorBackendNames,
|
|
256
267
|
*IntelBackendNames,
|
|
257
268
|
*ClassiqNvidiaBackendNames,
|
|
269
|
+
*C12BackendNames,
|
|
258
270
|
}
|
|
259
271
|
|
|
260
272
|
AllIBMQBackendNames = IBMQHardwareNames
|
|
@@ -268,6 +280,7 @@ AllBackendsNameByVendor = Union[
|
|
|
268
280
|
ClassiqNvidiaBackendNames,
|
|
269
281
|
AliceBobBackendNames,
|
|
270
282
|
OQCBackendNames,
|
|
283
|
+
C12BackendNames,
|
|
271
284
|
]
|
|
272
285
|
|
|
273
286
|
AllBackendsNameEnums = [
|
|
@@ -279,4 +292,5 @@ AllBackendsNameEnums = [
|
|
|
279
292
|
IntelBackendNames,
|
|
280
293
|
ClassiqNvidiaBackendNames,
|
|
281
294
|
OQCBackendNames,
|
|
295
|
+
C12BackendNames,
|
|
282
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
|
|
@@ -47,7 +47,7 @@ StateVector: TypeAlias = Optional[dict[str, Complex]]
|
|
|
47
47
|
BITSTRING = "bitstring"
|
|
48
48
|
PROBABILITY = "probability"
|
|
49
49
|
AMPLITUDE = "amplitude"
|
|
50
|
-
|
|
50
|
+
COUNTS = "counts"
|
|
51
51
|
MAGNITUDE = "magnitude"
|
|
52
52
|
PHASE = "phase"
|
|
53
53
|
|
|
@@ -374,7 +374,9 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
|
374
374
|
|
|
375
375
|
for bitstring, count in self.counts.items():
|
|
376
376
|
data[BITSTRING].append(bitstring)
|
|
377
|
-
|
|
377
|
+
# TODO CLS-4767: delete "count"
|
|
378
|
+
data["count"].append(count)
|
|
379
|
+
data[COUNTS].append(count)
|
|
378
380
|
if self.probabilities:
|
|
379
381
|
data[PROBABILITY].append(self.probabilities[bitstring])
|
|
380
382
|
elif self.num_shots:
|
|
@@ -383,7 +385,8 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
|
383
385
|
for name, value in self.parsed_states[bitstring].items():
|
|
384
386
|
data[name].append(value)
|
|
385
387
|
|
|
386
|
-
|
|
388
|
+
# TODO CLS-4767: delete "count"
|
|
389
|
+
final_columns = [COUNTS, "count", PROBABILITY, BITSTRING]
|
|
387
390
|
columns = [
|
|
388
391
|
col for col in data.keys() if col not in final_columns
|
|
389
392
|
] + final_columns
|
|
@@ -419,8 +422,9 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
|
419
422
|
|
|
420
423
|
@functools.cached_property
|
|
421
424
|
def dataframe(self) -> "pd.DataFrame":
|
|
425
|
+
# TODO CLS-4767: remove "count"
|
|
422
426
|
reserved_words = frozenset(
|
|
423
|
-
[BITSTRING, PROBABILITY,
|
|
427
|
+
["count", BITSTRING, PROBABILITY, COUNTS, AMPLITUDE, PHASE, MAGNITUDE]
|
|
424
428
|
)
|
|
425
429
|
_invalid_output_names = reserved_words.intersection(
|
|
426
430
|
self.output_qubits_map.keys()
|
|
@@ -436,7 +440,7 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
|
436
440
|
df = self._counts_df()
|
|
437
441
|
|
|
438
442
|
df.sort_values(
|
|
439
|
-
by=[AMPLITUDE if self.state_vector else
|
|
443
|
+
by=[AMPLITUDE if self.state_vector else COUNTS, BITSTRING],
|
|
440
444
|
inplace=True,
|
|
441
445
|
ascending=[False, True],
|
|
442
446
|
ignore_index=True,
|
|
@@ -29,7 +29,10 @@ from classiq.interface.generator.arith.ast_node_rewrite import (
|
|
|
29
29
|
)
|
|
30
30
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
|
31
31
|
from classiq.interface.generator.arith.unary_ops import Negation
|
|
32
|
-
from classiq.interface.generator.function_params import
|
|
32
|
+
from classiq.interface.generator.function_params import (
|
|
33
|
+
FunctionParams,
|
|
34
|
+
get_zero_input_name,
|
|
35
|
+
)
|
|
33
36
|
|
|
34
37
|
from classiq.model_expansions.arithmetic import NumericAttributes
|
|
35
38
|
from classiq.model_expansions.arithmetic_compute_result_attrs import (
|
|
@@ -335,6 +338,30 @@ class Adder(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
|
|
|
335
338
|
return isinstance(arg, float) and arg == 0
|
|
336
339
|
|
|
337
340
|
|
|
341
|
+
class CanonicalAdder(FunctionParams):
|
|
342
|
+
left_size: pydantic.PositiveInt
|
|
343
|
+
extend_left: bool
|
|
344
|
+
right_size: pydantic.PositiveInt
|
|
345
|
+
|
|
346
|
+
def _create_ios(self) -> None:
|
|
347
|
+
self._inputs = {
|
|
348
|
+
DEFAULT_LEFT_ARG_NAME: RegisterArithmeticInfo(size=self.left_size),
|
|
349
|
+
DEFAULT_RIGHT_ARG_NAME: RegisterArithmeticInfo(size=self.right_size),
|
|
350
|
+
}
|
|
351
|
+
self._outputs = {**self._inputs}
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class CanonicalConstantAdder(FunctionParams):
|
|
355
|
+
left: int
|
|
356
|
+
right_size: pydantic.PositiveInt
|
|
357
|
+
|
|
358
|
+
def _create_ios(self) -> None:
|
|
359
|
+
self._inputs = {
|
|
360
|
+
"right_arg": RegisterArithmeticInfo(size=self.right_size),
|
|
361
|
+
}
|
|
362
|
+
self._outputs = {**self._inputs}
|
|
363
|
+
|
|
364
|
+
|
|
338
365
|
class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
|
|
339
366
|
output_name = "difference"
|
|
340
367
|
|
|
@@ -533,10 +560,43 @@ class Multiplier(BinaryOpWithFloatInputs):
|
|
|
533
560
|
|
|
534
561
|
def garbage_output_size(self) -> pydantic.NonNegativeInt:
|
|
535
562
|
return max(
|
|
536
|
-
0,
|
|
563
|
+
0,
|
|
564
|
+
self.expected_fraction_places() - self.result_register.fraction_places - 1,
|
|
537
565
|
)
|
|
538
566
|
|
|
539
567
|
|
|
568
|
+
class CanonicalMultiplier(FunctionParams):
|
|
569
|
+
left_size: pydantic.PositiveInt
|
|
570
|
+
extend_left: bool
|
|
571
|
+
right_size: pydantic.PositiveInt
|
|
572
|
+
extend_right: bool
|
|
573
|
+
result_size: pydantic.PositiveInt
|
|
574
|
+
trim_result_lsb: bool
|
|
575
|
+
|
|
576
|
+
def _create_ios(self) -> None:
|
|
577
|
+
self._inputs = {
|
|
578
|
+
"left": RegisterArithmeticInfo(size=self.left_size),
|
|
579
|
+
"right": RegisterArithmeticInfo(size=self.right_size),
|
|
580
|
+
"result": RegisterArithmeticInfo(size=self.result_size),
|
|
581
|
+
}
|
|
582
|
+
self._outputs = {**self._inputs}
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
class CanonicalConstantMultiplier(FunctionParams):
|
|
586
|
+
left: int
|
|
587
|
+
right_size: pydantic.PositiveInt
|
|
588
|
+
extend_right: bool
|
|
589
|
+
result_size: pydantic.PositiveInt
|
|
590
|
+
trim_result_lsb: bool
|
|
591
|
+
|
|
592
|
+
def _create_ios(self) -> None:
|
|
593
|
+
self._inputs = {
|
|
594
|
+
"right": RegisterArithmeticInfo(size=self.right_size),
|
|
595
|
+
"result": RegisterArithmeticInfo(size=self.result_size),
|
|
596
|
+
}
|
|
597
|
+
self._outputs = {**self._inputs}
|
|
598
|
+
|
|
599
|
+
|
|
540
600
|
class Comparator(BinaryOpWithFloatInputs):
|
|
541
601
|
output_size: Literal[1] = 1
|
|
542
602
|
|
|
@@ -3,13 +3,22 @@ from typing import Final
|
|
|
3
3
|
MAXIMAL_MACHINE_PRECISION: Final[int] = 20
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def signed_int_to_unsigned(number: int) -> int:
|
|
6
|
+
def signed_int_to_unsigned(number: int, reg_size: int | None = None) -> int:
|
|
7
7
|
"""Return the integer value of a signed int if it would we read as un-signed in binary representation"""
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
signed: bool = False
|
|
9
|
+
if number < 0:
|
|
10
|
+
signed = True
|
|
11
|
+
not_power2 = abs(number) & (abs(number) - 1) != 0
|
|
12
|
+
number = number + 2 ** (number.bit_length() + 1 * not_power2)
|
|
13
|
+
|
|
14
|
+
if reg_size is not None:
|
|
15
|
+
bits = bin(number)[2:][::-1]
|
|
16
|
+
bits = bits[:reg_size]
|
|
17
|
+
if signed and len(bits) < reg_size:
|
|
18
|
+
bits += "1" * (reg_size - len(bits))
|
|
19
|
+
number = int(bits[::-1], 2)
|
|
20
|
+
|
|
21
|
+
return number
|
|
13
22
|
|
|
14
23
|
|
|
15
24
|
def binary_to_int(bin_rep: str, is_signed: bool = False) -> int:
|