classiq 0.102.0__py3-none-any.whl → 0.104.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/applications/chemistry/op_utils.py +32 -0
- 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/execution_session.py +1 -1
- classiq/execution/functions/__init__.py +3 -0
- classiq/execution/functions/_logging.py +19 -0
- classiq/execution/functions/constants.py +9 -0
- classiq/execution/functions/parse_provider_backend.py +90 -0
- classiq/execution/functions/sample.py +257 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +15 -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 +3 -0
- classiq/interface/executor/result.py +9 -5
- classiq/interface/generator/arith/binary_ops.py +38 -2
- classiq/interface/generator/function_param_list.py +4 -2
- classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
- classiq/interface/generator/functions/classical_type.py +45 -0
- classiq/interface/generator/functions/type_name.py +23 -0
- classiq/interface/generator/generated_circuit_data.py +0 -2
- classiq/interface/generator/types/compilation_metadata.py +9 -0
- classiq/interface/hardware.py +1 -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_visitor.py +4 -2
- classiq/interface/model/quantum_type.py +21 -0
- classiq/interface/model/statement_block.py +0 -4
- 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 +9 -0
- classiq/qmod/builtins/functions/arithmetic.py +131 -0
- classiq/qmod/builtins/functions/exponentiation.py +32 -2
- classiq/qmod/builtins/operations.py +2 -38
- 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-0.102.0.dist-info → classiq-0.104.0.dist-info}/METADATA +1 -1
- {classiq-0.102.0.dist-info → classiq-0.104.0.dist-info}/RECORD +63 -59
- 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-0.104.0.dist-info}/WHEEL +0 -0
- {classiq-0.102.0.dist-info → classiq-0.104.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from pandas import DataFrame
|
|
7
|
+
|
|
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
|
+
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
|
+
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
|
33
|
+
from classiq.interface.generator.model.preferences import create_random_seed
|
|
34
|
+
from classiq.interface.generator.model.preferences.preferences import (
|
|
35
|
+
TranspilationOption,
|
|
36
|
+
)
|
|
37
|
+
from classiq.interface.hardware import Provider
|
|
38
|
+
|
|
39
|
+
from classiq import (
|
|
40
|
+
ExecutionParams,
|
|
41
|
+
QuantumProgram,
|
|
42
|
+
)
|
|
43
|
+
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
|
+
|
|
205
|
+
|
|
206
|
+
_DEFAULT_BACKEND_NAME = "simulator"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _new_sample(
|
|
210
|
+
qprog: QuantumProgram,
|
|
211
|
+
backend: str | None = None,
|
|
212
|
+
*,
|
|
213
|
+
parameters: ExecutionParams | None = None,
|
|
214
|
+
config: dict[str, Any] | ProviderConfig | None = None,
|
|
215
|
+
num_shots: int | None = None,
|
|
216
|
+
random_seed: int | None = None,
|
|
217
|
+
transpilation_option: TranspilationOption = TranspilationOption.DECOMPOSE,
|
|
218
|
+
verbosity: Verbosity = Verbosity.INFO,
|
|
219
|
+
) -> "DataFrame":
|
|
220
|
+
"""
|
|
221
|
+
Sample a quantum program.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
qprog: The quantum program
|
|
225
|
+
backend: The device (hardware or simulator) on which to run the quantum program. Specified as "provider/device_id"
|
|
226
|
+
parameters: The classical parameters for the quantum program
|
|
227
|
+
config: Provider-specific configuration, such as api keys
|
|
228
|
+
num_shots: The number of times to sample
|
|
229
|
+
random_seed: The random seed used for transpilation and simulation
|
|
230
|
+
transpilation_option: Advanced configuration for hardware-specific transpilation
|
|
231
|
+
verbosity: What level of information should be logged
|
|
232
|
+
|
|
233
|
+
Returns: A dataframe containing the histogram
|
|
234
|
+
"""
|
|
235
|
+
if num_shots is not None and num_shots < 1:
|
|
236
|
+
raise ValueError(f"Argument num_shots must be greater than 0, got {num_shots}")
|
|
237
|
+
if config is None:
|
|
238
|
+
config = {}
|
|
239
|
+
if backend is None:
|
|
240
|
+
backend = _DEFAULT_BACKEND_NAME
|
|
241
|
+
backend_preferences = _get_backend_preferences_from_specifier(backend, config)
|
|
242
|
+
ep = ExecutionPreferences(
|
|
243
|
+
backend_preferences=backend_preferences,
|
|
244
|
+
num_shots=num_shots,
|
|
245
|
+
random_seed=create_random_seed() if random_seed is None else random_seed,
|
|
246
|
+
transpile_to_hardware=transpilation_option,
|
|
247
|
+
)
|
|
248
|
+
if verbosity != Verbosity.QUIET:
|
|
249
|
+
_logger.info(f"Submitting job to {backend}")
|
|
250
|
+
with ExecutionSession(qprog, execution_preferences=ep) as session:
|
|
251
|
+
job = session.submit_sample(parameters)
|
|
252
|
+
if verbosity != Verbosity.QUIET:
|
|
253
|
+
_logger.info(f"Job id: {job.id}")
|
|
254
|
+
result = job.get_sample_result()
|
|
255
|
+
|
|
256
|
+
df = result.dataframe
|
|
257
|
+
return df
|
classiq/interface/_version.py
CHANGED
|
@@ -454,6 +454,20 @@ 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
|
+
|
|
457
471
|
def is_exact_simulator(backend_preferences: BackendPreferences) -> bool:
|
|
458
472
|
return backend_preferences.backend_name in EXACT_SIMULATORS
|
|
459
473
|
|
|
@@ -486,6 +500,7 @@ BackendPreferencesTypes = Union[
|
|
|
486
500
|
IntelBackendPreferences,
|
|
487
501
|
AQTBackendPreferences,
|
|
488
502
|
CINECABackendPreferences,
|
|
503
|
+
SoftbankBackendPreferences,
|
|
489
504
|
]
|
|
490
505
|
|
|
491
506
|
__all__ = [
|
|
@@ -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,7 @@ class ProviderVendor(StrEnum):
|
|
|
27
27
|
INTEL = "Intel"
|
|
28
28
|
AQT = "AQT"
|
|
29
29
|
CINECA = "CINECA"
|
|
30
|
+
SOFTBANK = "Softbank"
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
class ProviderTypeVendor:
|
|
@@ -41,6 +42,7 @@ class ProviderTypeVendor:
|
|
|
41
42
|
INTEL = Literal[ProviderVendor.INTEL]
|
|
42
43
|
AQT = Literal[ProviderVendor.AQT]
|
|
43
44
|
CINECA = Literal[ProviderVendor.CINECA]
|
|
45
|
+
SOFTBANK = Literal[ProviderVendor.SOFTBANK]
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
PROVIDER_NAME_MAPPER = {
|
|
@@ -54,6 +56,7 @@ PROVIDER_NAME_MAPPER = {
|
|
|
54
56
|
ProviderVendor.INTEL: "INTEL",
|
|
55
57
|
ProviderVendor.AQT: "AQT",
|
|
56
58
|
ProviderVendor.CLASSIQ: "CLASSIQ",
|
|
59
|
+
ProviderVendor.SOFTBANK: "SOFTBANK",
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
|
|
@@ -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 (
|
|
@@ -533,10 +536,43 @@ class Multiplier(BinaryOpWithFloatInputs):
|
|
|
533
536
|
|
|
534
537
|
def garbage_output_size(self) -> pydantic.NonNegativeInt:
|
|
535
538
|
return max(
|
|
536
|
-
0,
|
|
539
|
+
0,
|
|
540
|
+
self.expected_fraction_places() - self.result_register.fraction_places - 1,
|
|
537
541
|
)
|
|
538
542
|
|
|
539
543
|
|
|
544
|
+
class CanonicalMultiplier(FunctionParams):
|
|
545
|
+
left_size: pydantic.PositiveInt
|
|
546
|
+
extend_left: bool
|
|
547
|
+
right_size: pydantic.PositiveInt
|
|
548
|
+
extend_right: bool
|
|
549
|
+
result_size: pydantic.PositiveInt
|
|
550
|
+
trim_result_lsb: bool
|
|
551
|
+
|
|
552
|
+
def _create_ios(self) -> None:
|
|
553
|
+
self._inputs = {
|
|
554
|
+
"left": RegisterArithmeticInfo(size=self.left_size),
|
|
555
|
+
"right": RegisterArithmeticInfo(size=self.right_size),
|
|
556
|
+
"result": RegisterArithmeticInfo(size=self.result_size),
|
|
557
|
+
}
|
|
558
|
+
self._outputs = {**self._inputs}
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
class CanonicalConstantMultiplier(FunctionParams):
|
|
562
|
+
left: int
|
|
563
|
+
right_size: pydantic.PositiveInt
|
|
564
|
+
extend_right: bool
|
|
565
|
+
result_size: pydantic.PositiveInt
|
|
566
|
+
trim_result_lsb: bool
|
|
567
|
+
|
|
568
|
+
def _create_ios(self) -> None:
|
|
569
|
+
self._inputs = {
|
|
570
|
+
"right": RegisterArithmeticInfo(size=self.right_size),
|
|
571
|
+
"result": RegisterArithmeticInfo(size=self.result_size),
|
|
572
|
+
}
|
|
573
|
+
self._outputs = {**self._inputs}
|
|
574
|
+
|
|
575
|
+
|
|
540
576
|
class Comparator(BinaryOpWithFloatInputs):
|
|
541
577
|
output_size: Literal[1] = 1
|
|
542
578
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import itertools
|
|
2
2
|
|
|
3
|
-
from classiq.interface.generator.amplitude_loading import AmplitudeLoading
|
|
4
3
|
from classiq.interface.generator.arith.arithmetic import Arithmetic
|
|
5
4
|
from classiq.interface.generator.arith.binary_ops import (
|
|
6
5
|
Adder,
|
|
7
6
|
BitwiseAnd,
|
|
8
7
|
BitwiseOr,
|
|
9
8
|
BitwiseXor,
|
|
9
|
+
CanonicalConstantMultiplier,
|
|
10
|
+
CanonicalMultiplier,
|
|
10
11
|
Equal,
|
|
11
12
|
GreaterEqual,
|
|
12
13
|
GreaterThan,
|
|
@@ -79,6 +80,8 @@ function_param_library: FunctionParamLibrary = FunctionParamLibrary(
|
|
|
79
80
|
HardwareEfficientAnsatz,
|
|
80
81
|
UnitaryGate,
|
|
81
82
|
Multiplier,
|
|
83
|
+
CanonicalMultiplier,
|
|
84
|
+
CanonicalConstantMultiplier,
|
|
82
85
|
Power,
|
|
83
86
|
Min,
|
|
84
87
|
Max,
|
|
@@ -88,7 +91,6 @@ function_param_library: FunctionParamLibrary = FunctionParamLibrary(
|
|
|
88
91
|
Identity,
|
|
89
92
|
RandomizedBenchmarking,
|
|
90
93
|
UGate,
|
|
91
|
-
AmplitudeLoading,
|
|
92
94
|
HadamardTransform,
|
|
93
95
|
Copy,
|
|
94
96
|
Reset,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
CTRL_VAR_PREFIX = "ctrl__"
|
|
2
2
|
CONTROL_OPERATOR_NAME = "control"
|
|
3
3
|
SKIP_CONTROL_OPERATOR_NAME = "skip_control"
|
|
4
|
-
|
|
4
|
+
COMPOUND_INVERT_OPERATOR_NAME = "compound_invert"
|
|
5
|
+
SINGLE_CALL_INVERT_OPERATOR_NAME = "single_call_invert"
|
|
5
6
|
REPEAT_OPERATOR_NAME = "iteration"
|
|
6
7
|
CLASSICAL_IF_OPERATOR_NAME = "classical_if"
|
|
7
8
|
POWER_OPERATOR_NAME = "power"
|
|
@@ -9,12 +10,7 @@ UNCOMPUTE_OPERATOR_NAME = "uncompute"
|
|
|
9
10
|
WITHIN_APPLY_NAME = "within_apply"
|
|
10
11
|
BLOCK_OPERATOR_NAME = "block"
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
REPEAT_OPERATOR_NAME,
|
|
16
|
-
POWER_OPERATOR_NAME,
|
|
17
|
-
UNCOMPUTE_OPERATOR_NAME,
|
|
18
|
-
WITHIN_APPLY_NAME,
|
|
19
|
-
BLOCK_OPERATOR_NAME,
|
|
13
|
+
INVERT_OPERATOR_NAMES = {
|
|
14
|
+
COMPOUND_INVERT_OPERATOR_NAME,
|
|
15
|
+
SINGLE_CALL_INVERT_OPERATOR_NAME,
|
|
20
16
|
}
|
|
@@ -61,6 +61,10 @@ class ClassicalType(HashableASTNode):
|
|
|
61
61
|
def raw_qmod_type_name(self) -> str:
|
|
62
62
|
return self.qmod_type_name
|
|
63
63
|
|
|
64
|
+
@property
|
|
65
|
+
def python_type_name(self) -> str:
|
|
66
|
+
raise NotImplementedError
|
|
67
|
+
|
|
64
68
|
@property
|
|
65
69
|
def expressions(self) -> list[Expression]:
|
|
66
70
|
return []
|
|
@@ -76,6 +80,9 @@ class ClassicalType(HashableASTNode):
|
|
|
76
80
|
def without_symbolic_attributes(self) -> Self:
|
|
77
81
|
return self
|
|
78
82
|
|
|
83
|
+
def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
|
|
84
|
+
return {}
|
|
85
|
+
|
|
79
86
|
|
|
80
87
|
class Integer(ClassicalType):
|
|
81
88
|
kind: Literal["int"]
|
|
@@ -89,6 +96,10 @@ class Integer(ClassicalType):
|
|
|
89
96
|
def qmod_type_name(self) -> str:
|
|
90
97
|
return "CInt"
|
|
91
98
|
|
|
99
|
+
@property
|
|
100
|
+
def python_type_name(self) -> str:
|
|
101
|
+
return "int"
|
|
102
|
+
|
|
92
103
|
|
|
93
104
|
class Real(ClassicalType):
|
|
94
105
|
kind: Literal["real"]
|
|
@@ -102,6 +113,10 @@ class Real(ClassicalType):
|
|
|
102
113
|
def qmod_type_name(self) -> str:
|
|
103
114
|
return "CReal"
|
|
104
115
|
|
|
116
|
+
@property
|
|
117
|
+
def python_type_name(self) -> str:
|
|
118
|
+
return "float"
|
|
119
|
+
|
|
105
120
|
|
|
106
121
|
class Bool(ClassicalType):
|
|
107
122
|
kind: Literal["bool"]
|
|
@@ -115,6 +130,10 @@ class Bool(ClassicalType):
|
|
|
115
130
|
def qmod_type_name(self) -> str:
|
|
116
131
|
return "CBool"
|
|
117
132
|
|
|
133
|
+
@property
|
|
134
|
+
def python_type_name(self) -> str:
|
|
135
|
+
return "bool"
|
|
136
|
+
|
|
118
137
|
|
|
119
138
|
class StructMetaType(ClassicalType):
|
|
120
139
|
kind: Literal["type_proxy"]
|
|
@@ -201,6 +220,10 @@ class ClassicalArray(ClassicalType):
|
|
|
201
220
|
def raw_qmod_type_name(self) -> str:
|
|
202
221
|
return "CArray"
|
|
203
222
|
|
|
223
|
+
@property
|
|
224
|
+
def python_type_name(self) -> str:
|
|
225
|
+
return f"list[{self.element_type.python_type_name}]"
|
|
226
|
+
|
|
204
227
|
def without_symbolic_attributes(self) -> "ClassicalArray":
|
|
205
228
|
length = (
|
|
206
229
|
None
|
|
@@ -213,6 +236,14 @@ class ClassicalArray(ClassicalType):
|
|
|
213
236
|
element_type=self.element_type.without_symbolic_attributes(), length=length
|
|
214
237
|
)
|
|
215
238
|
|
|
239
|
+
def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
|
|
240
|
+
attrs: dict[str, Any] = {}
|
|
241
|
+
if self.has_constant_length:
|
|
242
|
+
attrs[f"{path_expr_prefix}.len"] = self.length_value
|
|
243
|
+
return attrs | self.element_type.get_compile_time_attributes(
|
|
244
|
+
f"{path_expr_prefix}[0]"
|
|
245
|
+
)
|
|
246
|
+
|
|
216
247
|
|
|
217
248
|
class ClassicalTuple(ClassicalType):
|
|
218
249
|
kind: Literal["tuple"]
|
|
@@ -283,6 +314,13 @@ class ClassicalTuple(ClassicalType):
|
|
|
283
314
|
def raw_qmod_type_name(self) -> str:
|
|
284
315
|
return "CArray"
|
|
285
316
|
|
|
317
|
+
@property
|
|
318
|
+
def python_type_name(self) -> str:
|
|
319
|
+
raw_type = self.get_raw_type(preserve_length=True)
|
|
320
|
+
if isinstance(raw_type, ClassicalTuple):
|
|
321
|
+
return "list"
|
|
322
|
+
return raw_type.python_type_name
|
|
323
|
+
|
|
286
324
|
def without_symbolic_attributes(self) -> "ClassicalTuple":
|
|
287
325
|
return ClassicalTuple(
|
|
288
326
|
element_types=[
|
|
@@ -291,6 +329,13 @@ class ClassicalTuple(ClassicalType):
|
|
|
291
329
|
]
|
|
292
330
|
)
|
|
293
331
|
|
|
332
|
+
def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
|
|
333
|
+
raw_type = self.get_raw_type(preserve_length=True)
|
|
334
|
+
attrs = {f"{path_expr_prefix}.len": len(self.element_types)}
|
|
335
|
+
if isinstance(raw_type, ClassicalTuple):
|
|
336
|
+
return attrs
|
|
337
|
+
return attrs | raw_type.get_compile_time_attributes(path_expr_prefix)
|
|
338
|
+
|
|
294
339
|
|
|
295
340
|
class OpaqueHandle(ClassicalType):
|
|
296
341
|
pass
|
|
@@ -60,6 +60,10 @@ class TypeName(ClassicalType, QuantumType):
|
|
|
60
60
|
def qmod_type_name(self) -> str:
|
|
61
61
|
return self.name
|
|
62
62
|
|
|
63
|
+
@property
|
|
64
|
+
def python_type_name(self) -> str:
|
|
65
|
+
return self.name
|
|
66
|
+
|
|
63
67
|
@property
|
|
64
68
|
def type_name(self) -> str:
|
|
65
69
|
return self.name
|
|
@@ -202,6 +206,25 @@ class TypeName(ClassicalType, QuantumType):
|
|
|
202
206
|
return type_name
|
|
203
207
|
return self
|
|
204
208
|
|
|
209
|
+
def get_compile_time_attributes(self, path_expr_prefix: str) -> dict[str, Any]:
|
|
210
|
+
attrs: dict[str, Any] = {}
|
|
211
|
+
if self.has_fields:
|
|
212
|
+
for field_name, field_type in self.fields.items():
|
|
213
|
+
field_prefix = f"{path_expr_prefix}.{field_name}"
|
|
214
|
+
attrs[field_prefix] = field_type.get_compile_time_attributes(
|
|
215
|
+
field_prefix
|
|
216
|
+
)
|
|
217
|
+
elif self.has_classical_struct_decl:
|
|
218
|
+
for (
|
|
219
|
+
field_name,
|
|
220
|
+
classical_field_type,
|
|
221
|
+
) in self.classical_struct_decl.variables.items():
|
|
222
|
+
field_prefix = f"{path_expr_prefix}.{field_name}"
|
|
223
|
+
attrs[field_prefix] = classical_field_type.get_compile_time_attributes(
|
|
224
|
+
field_prefix
|
|
225
|
+
)
|
|
226
|
+
return attrs
|
|
227
|
+
|
|
205
228
|
|
|
206
229
|
class Enum(TypeName):
|
|
207
230
|
pass
|
|
@@ -140,7 +140,6 @@ class StatementType(StrEnum):
|
|
|
140
140
|
WITHIN = "within"
|
|
141
141
|
APPLY = "apply"
|
|
142
142
|
ASSIGN = "assign"
|
|
143
|
-
ASSIGN_AMPLITUDE = "assign amplitude"
|
|
144
143
|
PHASE = "phase"
|
|
145
144
|
INPLACE_XOR = "inplace xor"
|
|
146
145
|
INPLACE_ADD = "inplace add"
|
|
@@ -163,7 +162,6 @@ STATEMENTS_NAME: dict[str, StatementType] = {
|
|
|
163
162
|
"Uncompute": StatementType.WITHIN,
|
|
164
163
|
ArithmeticOperationKind.Assignment.value: StatementType.ASSIGN,
|
|
165
164
|
"InplaceBinaryOperation": StatementType.ASSIGN,
|
|
166
|
-
"AmplitudeLoadingOperation": StatementType.ASSIGN_AMPLITUDE,
|
|
167
165
|
"PhaseOperation": StatementType.PHASE,
|
|
168
166
|
ArithmeticOperationKind.InplaceXor.value: StatementType.INPLACE_XOR,
|
|
169
167
|
ArithmeticOperationKind.InplaceAdd.value: StatementType.INPLACE_ADD,
|