classiq 0.100.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.
Files changed (95) hide show
  1. classiq/__init__.py +3 -0
  2. classiq/_internals/api_wrapper.py +29 -4
  3. classiq/applications/chemistry/op_utils.py +63 -1
  4. classiq/applications/chemistry/problems.py +18 -6
  5. classiq/applications/chemistry/ucc.py +2 -2
  6. classiq/evaluators/parameter_types.py +1 -4
  7. classiq/evaluators/qmod_annotated_expression.py +1 -1
  8. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
  9. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
  10. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
  11. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
  12. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
  13. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
  14. classiq/evaluators/qmod_node_evaluators/utils.py +6 -3
  15. classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
  16. classiq/execution/__init__.py +11 -1
  17. classiq/execution/execution_session.py +1 -1
  18. classiq/execution/functions/__init__.py +3 -0
  19. classiq/execution/functions/_logging.py +19 -0
  20. classiq/execution/functions/constants.py +9 -0
  21. classiq/execution/functions/parse_provider_backend.py +90 -0
  22. classiq/execution/functions/sample.py +257 -0
  23. classiq/execution/jobs.py +122 -5
  24. classiq/interface/_version.py +1 -1
  25. classiq/interface/backend/backend_preferences.py +15 -0
  26. classiq/interface/backend/provider_config/providers/aqt.py +1 -1
  27. classiq/interface/backend/provider_config/providers/azure.py +1 -2
  28. classiq/interface/backend/provider_config/providers/ibm.py +1 -1
  29. classiq/interface/backend/quantum_backend_providers.py +3 -0
  30. classiq/interface/exceptions.py +0 -42
  31. classiq/interface/executor/execution_request.py +1 -0
  32. classiq/interface/executor/quantum_code.py +0 -6
  33. classiq/interface/executor/result.py +9 -5
  34. classiq/interface/generator/arith/binary_ops.py +38 -2
  35. classiq/interface/generator/function_param_list.py +4 -2
  36. classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
  37. classiq/interface/generator/functions/classical_type.py +45 -0
  38. classiq/interface/generator/functions/type_name.py +23 -0
  39. classiq/interface/generator/generated_circuit_data.py +0 -2
  40. classiq/interface/generator/generation_request.py +9 -4
  41. classiq/interface/generator/quantum_program.py +8 -36
  42. classiq/interface/generator/types/compilation_metadata.py +9 -0
  43. classiq/interface/hardware.py +1 -0
  44. classiq/interface/helpers/model_normalizer.py +62 -2
  45. classiq/interface/helpers/text_utils.py +17 -6
  46. classiq/interface/interface_version.py +1 -1
  47. classiq/interface/model/invert.py +15 -0
  48. classiq/interface/model/model.py +42 -3
  49. classiq/interface/model/model_visitor.py +4 -2
  50. classiq/interface/model/quantum_function_call.py +17 -5
  51. classiq/interface/model/quantum_type.py +21 -0
  52. classiq/interface/model/statement_block.py +0 -4
  53. classiq/model_expansions/capturing/captured_vars.py +16 -12
  54. classiq/model_expansions/function_builder.py +9 -1
  55. classiq/model_expansions/interpreters/base_interpreter.py +12 -10
  56. classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
  57. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
  58. classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
  59. classiq/model_expansions/quantum_operations/bind.py +4 -0
  60. classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
  61. classiq/model_expansions/quantum_operations/emitter.py +1 -4
  62. classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
  63. classiq/model_expansions/visitors/uncomputation_signature_inference.py +15 -47
  64. classiq/open_library/functions/__init__.py +42 -27
  65. classiq/open_library/functions/bit_operations.py +30 -0
  66. classiq/open_library/functions/modular_arithmetics.py +597 -0
  67. classiq/open_library/functions/qft_space_arithmetics.py +81 -0
  68. classiq/open_library/functions/state_preparation.py +6 -3
  69. classiq/open_library/functions/utility_functions.py +22 -3
  70. classiq/qmod/builtins/functions/__init__.py +9 -0
  71. classiq/qmod/builtins/functions/arithmetic.py +131 -0
  72. classiq/qmod/builtins/functions/exponentiation.py +34 -4
  73. classiq/qmod/builtins/operations.py +30 -41
  74. classiq/qmod/native/pretty_printer.py +12 -12
  75. classiq/qmod/pretty_print/pretty_printer.py +11 -15
  76. classiq/qmod/qmod_parameter.py +4 -0
  77. classiq/qmod/qmod_variable.py +38 -63
  78. classiq/qmod/quantum_callable.py +8 -2
  79. classiq/qmod/quantum_expandable.py +3 -1
  80. classiq/qmod/quantum_function.py +45 -8
  81. classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
  82. classiq/qmod/semantics/validation/model_validation.py +7 -2
  83. classiq/qmod/symbolic_type.py +4 -2
  84. classiq/qmod/utilities.py +7 -4
  85. classiq/synthesis_action/__init__.py +20 -0
  86. classiq/synthesis_action/actions.py +106 -0
  87. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/METADATA +1 -1
  88. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/RECORD +90 -84
  89. classiq/interface/executor/register_initialization.py +0 -36
  90. classiq/interface/generator/amplitude_loading.py +0 -103
  91. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
  92. classiq/open_library/functions/modular_exponentiation.py +0 -272
  93. classiq/open_library/functions/qsvt_temp.py +0 -536
  94. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/WHEEL +0 -0
  95. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,19 @@
1
+ import logging
2
+
3
+ _logger = logging.getLogger(__name__)
4
+
5
+
6
+ def _setup_logging() -> None:
7
+ if _logger.handlers:
8
+ return
9
+
10
+ handler = logging.StreamHandler()
11
+ formatter = logging.Formatter("%(message)s")
12
+ handler.setFormatter(formatter)
13
+ _logger.addHandler(handler)
14
+ _logger.setLevel(logging.INFO)
15
+
16
+ _logger.propagate = False
17
+
18
+
19
+ _setup_logging()
@@ -0,0 +1,9 @@
1
+ from enum import auto, unique
2
+
3
+ from classiq.interface.enum_utils import StrEnum
4
+
5
+
6
+ @unique
7
+ class Verbosity(StrEnum):
8
+ QUIET = auto()
9
+ INFO = auto()
@@ -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
@@ -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/execution/jobs.py CHANGED
@@ -1,7 +1,11 @@
1
1
  import warnings
2
2
  import webbrowser
3
+ from dataclasses import asdict, dataclass
3
4
  from datetime import datetime
4
- from typing import Any
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ if TYPE_CHECKING:
8
+ import pandas as pd
5
9
  from urllib.parse import urljoin
6
10
 
7
11
  import httpx
@@ -29,6 +33,10 @@ from classiq._internals.async_utils import syncify_function
29
33
  from classiq._internals.client import client
30
34
  from classiq._internals.jobs import JobID, JobPoller
31
35
 
36
+ TOTAL_COST = "total_cost"
37
+ CURRENCY_CODE = "currency_code"
38
+ COST = "cost"
39
+
32
40
 
33
41
  class ClassiqExecutionResultError(ClassiqError):
34
42
  def __init__(self, primitive: str) -> None:
@@ -37,6 +45,42 @@ class ClassiqExecutionResultError(ClassiqError):
37
45
  )
38
46
 
39
47
 
48
+ @dataclass
49
+ class ExecutionJobFilters:
50
+ """
51
+ Filter parameters for querying execution jobs.
52
+
53
+ All filters are combined using AND logic: only jobs matching all specified filters are returned.
54
+ Range filters (with _min/_max suffixes) are inclusive.
55
+ Datetime filters are compared against the job's timestamps.
56
+ """
57
+
58
+ id: str | None = None # Exact match on job ID
59
+ session_id: str | None = None # Exact match on session ID
60
+ status: JobStatus | None = (
61
+ None # Exact match on job status (e.g., "COMPLETED", "FAILED")
62
+ )
63
+ name: str | None = None # Exact match on job name
64
+ provider: str | None = None # Exact match on provider name (e.g., "ibm", "aws")
65
+ backend: str | None = None # Exact match on backend name
66
+ program_id: str | None = None # Exact match on program ID
67
+ total_cost_min: float | None = None # Minimum total cost (inclusive)
68
+ total_cost_max: float | None = None # Maximum total cost (inclusive)
69
+ start_time_min: datetime | None = None # Earliest job start time (inclusive)
70
+ start_time_max: datetime | None = None # Latest job start time (inclusive)
71
+ end_time_min: datetime | None = None # Earliest job end time (inclusive)
72
+ end_time_max: datetime | None = None # Latest job end time (inclusive)
73
+
74
+ def format_filters(self) -> dict[str, Any]:
75
+ """Convert filter fields to API kwargs, excluding None values and converting datetimes."""
76
+ filter_dict = asdict(self)
77
+ return {
78
+ k: (v.isoformat() if isinstance(v, datetime) else v)
79
+ for k, v in filter_dict.items()
80
+ if v is not None
81
+ }
82
+
83
+
40
84
  class ExecutionJob:
41
85
  _details: ExecutionJobDetails
42
86
  _result: ResultsCollection | None
@@ -352,10 +396,83 @@ class ExecutionJob:
352
396
 
353
397
 
354
398
  async def get_execution_jobs_async(
355
- offset: int = 0, limit: int = 50
399
+ offset: int = 0,
400
+ limit: int = 50,
356
401
  ) -> list[ExecutionJob]:
357
- result = await ApiWrapper().call_query_execution_jobs(offset=offset, limit=limit)
358
- return [ExecutionJob(details) for details in result.results]
402
+ execution_user_jobs = await ApiWrapper.call_query_execution_jobs(
403
+ offset, limit, http_client=None
404
+ )
405
+ return [ExecutionJob(details) for details in execution_user_jobs.results]
406
+
407
+
408
+ def get_execution_jobs(
409
+ offset: int = 0,
410
+ limit: int = 50,
411
+ ) -> list[ExecutionJob]:
412
+ """Query execution jobs.
413
+
414
+ Args:
415
+ offset: Number of results to skip (default: 0)
416
+ limit: Maximum number of results to return (default: 50)
417
+
418
+ Returns:
419
+ List of ExecutionJob objects.
420
+
421
+ Examples:
422
+ # Query all jobs:
423
+ jobs = get_execution_jobs(limit=10)
424
+ """
425
+ return syncify_function(get_execution_jobs_async)(offset, limit)
426
+
427
+
428
+ def _flatten_cost_field(action_dict: dict[str, Any]) -> dict[str, Any]:
429
+ cost_obj = action_dict.pop(COST, {}) or {}
430
+ action_dict[TOTAL_COST] = cost_obj.get(TOTAL_COST, 0)
431
+ action_dict[CURRENCY_CODE] = cost_obj.get(CURRENCY_CODE)
432
+ return action_dict
433
+
434
+
435
+ async def get_execution_actions_async(
436
+ offset: int = 0,
437
+ limit: int = 50,
438
+ filters: ExecutionJobFilters | None = None,
439
+ ) -> "pd.DataFrame":
440
+ import pandas as pd
441
+
442
+ api_kwargs = filters.format_filters() if filters is not None else {}
443
+ execution_user_actions = await ApiWrapper.call_query_execution_jobs(
444
+ offset, limit, http_client=None, **api_kwargs
445
+ )
446
+ execution_actions = execution_user_actions.results
447
+
448
+ if not execution_actions:
449
+ return pd.DataFrame()
450
+
451
+ data = [_flatten_cost_field(action.model_dump()) for action in execution_actions]
452
+ return pd.DataFrame(data)
453
+
454
+
455
+ def get_execution_actions(
456
+ offset: int = 0, limit: int = 50, filters: ExecutionJobFilters | None = None
457
+ ) -> "pd.DataFrame":
458
+ """Query execution jobs with optional filters.
459
+
460
+ Args:
461
+ offset: Number of results to skip (default: 0)
462
+ limit: Maximum number of results to return (default: 50)
463
+ filters: Optional ExecutionJobFilters object containing filter parameters.
464
+
465
+ Returns:
466
+ pandas.DataFrame containing execution job information with columns:
467
+ id, name, start_time, end_time, provider, backend_name, status,
468
+ num_shots, program_id, error, cost.
359
469
 
470
+ Examples:
471
+ # Query all jobs:
472
+ df = get_execution_actions(limit=10)
360
473
 
361
- get_execution_jobs = syncify_function(get_execution_jobs_async)
474
+ # Query with filters:
475
+ filters = ExecutionJobFilters(status="COMPLETED", provider="ibm")
476
+ df = get_execution_actions(filters=filters, limit=10)
477
+ """
478
+ return syncify_function(get_execution_actions_async)(offset, limit, filters)
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.100.0'
6
+ SEMVER_VERSION = '0.104.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -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 | None = pydantic.Field(default=None, description="AQT API key")
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: pydantic_backend.PydanticAzureResourceIDType | None = pydantic.Field(
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