classiq 0.51.1__py3-none-any.whl → 0.52.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/_internals/api_wrapper.py +41 -15
- classiq/_internals/authentication/auth0.py +20 -4
- classiq/_internals/authentication/password_manager.py +16 -4
- classiq/_internals/client.py +2 -2
- classiq/_internals/host_checker.py +5 -3
- classiq/_internals/jobs.py +3 -3
- classiq/analyzer/analyzer_utilities.py +1 -1
- classiq/applications/chemistry/ground_state_problem.py +1 -1
- classiq/applications/combinatorial_helpers/pyomo_utils.py +3 -1
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/qlayer.py +2 -2
- classiq/execution/__init__.py +3 -0
- classiq/execution/execution_session.py +2 -2
- classiq/execution/iqcc.py +63 -0
- classiq/execution/jobs.py +2 -2
- classiq/executor.py +2 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +19 -9
- classiq/interface/analyzer/cytoscape_graph.py +10 -3
- classiq/interface/analyzer/result.py +6 -5
- classiq/interface/applications/qsvm.py +13 -12
- classiq/interface/backend/backend_preferences.py +78 -105
- classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
- classiq/interface/backend/pydantic_backend.py +24 -12
- classiq/interface/backend/quantum_backend_providers.py +2 -0
- classiq/interface/chemistry/fermionic_operator.py +7 -7
- classiq/interface/chemistry/ground_state_problem.py +23 -18
- classiq/interface/chemistry/molecule.py +10 -5
- classiq/interface/chemistry/operator.py +71 -44
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
- classiq/interface/debug_info/debug_info.py +3 -4
- classiq/interface/execution/iqcc.py +21 -0
- classiq/interface/execution/jobs.py +10 -10
- classiq/interface/executor/aws_execution_cost.py +37 -20
- classiq/interface/executor/execution_preferences.py +1 -2
- classiq/interface/executor/execution_request.py +2 -2
- classiq/interface/executor/execution_result.py +4 -2
- classiq/interface/executor/iqae_result.py +1 -1
- classiq/interface/executor/optimizer_preferences.py +14 -10
- classiq/interface/executor/quantum_code.py +21 -16
- classiq/interface/executor/register_initialization.py +10 -10
- classiq/interface/executor/result.py +19 -16
- classiq/interface/executor/vqe_result.py +1 -1
- classiq/interface/finance/function_input.py +27 -18
- classiq/interface/finance/log_normal_model_input.py +2 -2
- classiq/interface/finance/model_input.py +3 -2
- classiq/interface/generator/amplitude_loading.py +8 -6
- classiq/interface/generator/arith/argument_utils.py +24 -0
- classiq/interface/generator/arith/arithmetic.py +5 -3
- classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
- classiq/interface/generator/arith/arithmetic_operations.py +6 -3
- classiq/interface/generator/arith/binary_ops.py +88 -63
- classiq/interface/generator/arith/extremum_operations.py +22 -13
- classiq/interface/generator/arith/logical_ops.py +6 -4
- classiq/interface/generator/arith/number_utils.py +3 -3
- classiq/interface/generator/arith/register_user_input.py +32 -17
- classiq/interface/generator/arith/unary_ops.py +5 -4
- classiq/interface/generator/chemistry_function_params.py +2 -1
- classiq/interface/generator/circuit_code/circuit_code.py +2 -1
- classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
- classiq/interface/generator/complex_type.py +14 -18
- classiq/interface/generator/control_state.py +32 -26
- classiq/interface/generator/expressions/expression.py +6 -5
- classiq/interface/generator/function_params.py +22 -39
- classiq/interface/generator/functions/classical_function_declaration.py +1 -1
- classiq/interface/generator/functions/classical_type.py +32 -23
- classiq/interface/generator/functions/concrete_types.py +8 -7
- classiq/interface/generator/functions/function_declaration.py +4 -5
- classiq/interface/generator/functions/type_name.py +5 -4
- classiq/interface/generator/generated_circuit_data.py +9 -6
- classiq/interface/generator/grover_diffuser.py +26 -18
- classiq/interface/generator/grover_operator.py +32 -22
- classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
- classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
- classiq/interface/generator/hardware/hardware_data.py +27 -26
- classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
- classiq/interface/generator/hartree_fock.py +2 -1
- classiq/interface/generator/identity.py +7 -2
- classiq/interface/generator/linear_pauli_rotations.py +27 -14
- classiq/interface/generator/mcu.py +15 -12
- classiq/interface/generator/mcx.py +18 -10
- classiq/interface/generator/model/constraints.py +4 -2
- classiq/interface/generator/model/model.py +2 -1
- classiq/interface/generator/model/preferences/preferences.py +30 -32
- classiq/interface/generator/oracles/custom_oracle.py +13 -10
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
- classiq/interface/generator/qpe.py +38 -26
- classiq/interface/generator/qsvm.py +4 -4
- classiq/interface/generator/quantum_function_call.py +57 -44
- classiq/interface/generator/quantum_program.py +8 -6
- classiq/interface/generator/range_types.py +10 -11
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
- classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
- classiq/interface/generator/standard_gates/u_gate.py +7 -10
- classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
- classiq/interface/generator/state_preparation/distributions.py +12 -12
- classiq/interface/generator/state_preparation/state_preparation.py +22 -16
- classiq/interface/generator/types/enum_declaration.py +2 -1
- classiq/interface/generator/ucc.py +2 -1
- classiq/interface/generator/unitary_gate.py +2 -1
- classiq/interface/generator/user_defined_function_params.py +3 -0
- classiq/interface/generator/visitor.py +1 -1
- classiq/interface/hardware.py +18 -3
- classiq/interface/helpers/custom_pydantic_types.py +38 -47
- classiq/interface/helpers/pydantic_model_helpers.py +3 -2
- classiq/interface/helpers/versioned_model.py +1 -4
- classiq/interface/ide/ide_data.py +5 -5
- classiq/interface/ide/visual_model.py +5 -5
- classiq/interface/interface_version.py +1 -1
- classiq/interface/jobs.py +12 -22
- classiq/interface/model/bind_operation.py +2 -1
- classiq/interface/model/classical_parameter_declaration.py +10 -4
- classiq/interface/model/handle_binding.py +20 -24
- classiq/interface/model/inplace_binary_operation.py +16 -9
- classiq/interface/model/model.py +21 -11
- classiq/interface/model/port_declaration.py +10 -7
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
- classiq/interface/model/quantum_function_declaration.py +22 -11
- classiq/interface/model/quantum_statement.py +6 -7
- classiq/interface/model/quantum_type.py +22 -19
- classiq/interface/model/statement_block.py +9 -9
- classiq/interface/server/global_versions.py +4 -5
- classiq/interface/server/routes.py +8 -0
- classiq/model_expansions/evaluators/parameter_types.py +3 -3
- classiq/model_expansions/expression_renamer.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +11 -12
- classiq/model_expansions/quantum_operations/emitter.py +22 -0
- classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +38 -9
- classiq/model_expansions/quantum_operations/invert.py +1 -1
- classiq/model_expansions/quantum_operations/phase.py +4 -5
- classiq/model_expansions/quantum_operations/power.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
- classiq/model_expansions/quantum_operations/within_apply.py +1 -1
- classiq/qmod/builtins/__init__.py +1 -3
- classiq/qmod/builtins/functions/__init__.py +4 -0
- classiq/qmod/builtins/functions/arithmetic.py +10 -0
- classiq/qmod/create_model_function.py +4 -4
- classiq/qmod/quantum_expandable.py +22 -9
- classiq/qmod/quantum_function.py +1 -1
- classiq/qmod/semantics/static_semantics_visitor.py +3 -1
- classiq/qmod/type_attribute_remover.py +1 -1
- classiq/qmod/write_qmod.py +2 -4
- classiq/synthesis.py +11 -13
- {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
- {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/RECORD +149 -147
- {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/WHEEL +0 -0
@@ -11,6 +11,12 @@ from classiq.interface.analyzer.result import GraphStatus
|
|
11
11
|
from classiq.interface.chemistry import ground_state_problem, operator
|
12
12
|
from classiq.interface.enum_utils import StrEnum
|
13
13
|
from classiq.interface.exceptions import ClassiqAPIError, ClassiqValueError
|
14
|
+
from classiq.interface.execution.iqcc import (
|
15
|
+
IQCCInitAuthData,
|
16
|
+
IQCCInitAuthResponse,
|
17
|
+
IQCCProbeAuthData,
|
18
|
+
IQCCProbeAuthResponse,
|
19
|
+
)
|
14
20
|
from classiq.interface.execution.jobs import (
|
15
21
|
ExecutionJobDetailsV1,
|
16
22
|
ExecutionJobsQueryResultsV1,
|
@@ -49,7 +55,7 @@ def _parse_job_response(
|
|
49
55
|
output_type: Type[ResultType],
|
50
56
|
) -> ResultType:
|
51
57
|
if job_result.result is not None:
|
52
|
-
return output_type.
|
58
|
+
return output_type.model_validate(job_result.result)
|
53
59
|
if job_result.failure_details:
|
54
60
|
raise ClassiqAPIError(job_result.failure_details)
|
55
61
|
|
@@ -68,7 +74,7 @@ class ApiWrapper:
|
|
68
74
|
# TODO: we can't use model.dict() - it doesn't serialize complex class.
|
69
75
|
# This was added because JSON serializer doesn't serialize complex type, and pydantic does.
|
70
76
|
# We should add support for smarter json serialization.
|
71
|
-
body = json.loads(model.
|
77
|
+
body = json.loads(model.model_dump_json())
|
72
78
|
return await cls._call_task(
|
73
79
|
http_method, url, body, use_versioned_url=use_versioned_url
|
74
80
|
)
|
@@ -126,7 +132,7 @@ class ApiWrapper:
|
|
126
132
|
body=execution_input,
|
127
133
|
use_versioned_url=False,
|
128
134
|
)
|
129
|
-
return execution_request.ExecutionJobDetails.
|
135
|
+
return execution_request.ExecutionJobDetails.model_validate(data)
|
130
136
|
|
131
137
|
@classmethod
|
132
138
|
async def call_get_execution_job_details(
|
@@ -140,7 +146,7 @@ class ApiWrapper:
|
|
140
146
|
url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}",
|
141
147
|
use_versioned_url=False,
|
142
148
|
)
|
143
|
-
return execution_request.ExecutionJobDetails.
|
149
|
+
return execution_request.ExecutionJobDetails.model_validate(data)
|
144
150
|
|
145
151
|
@classmethod
|
146
152
|
async def call_get_execution_job_result(
|
@@ -154,7 +160,7 @@ class ApiWrapper:
|
|
154
160
|
use_versioned_url=False,
|
155
161
|
headers={CLASSIQ_ACCEPT_HEADER: version},
|
156
162
|
)
|
157
|
-
return classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults.
|
163
|
+
return classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults.model_validate(
|
158
164
|
data
|
159
165
|
)
|
160
166
|
|
@@ -172,7 +178,7 @@ class ApiWrapper:
|
|
172
178
|
},
|
173
179
|
use_versioned_url=False,
|
174
180
|
)
|
175
|
-
return ExecutionJobDetailsV1.
|
181
|
+
return ExecutionJobDetailsV1.model_validate(data)
|
176
182
|
|
177
183
|
@classmethod
|
178
184
|
async def call_cancel_execution_job(
|
@@ -201,7 +207,7 @@ class ApiWrapper:
|
|
201
207
|
},
|
202
208
|
use_versioned_url=False,
|
203
209
|
)
|
204
|
-
return ExecutionJobsQueryResultsV1.
|
210
|
+
return ExecutionJobsQueryResultsV1.model_validate(data)
|
205
211
|
|
206
212
|
@classmethod
|
207
213
|
async def call_analysis_task(
|
@@ -213,7 +219,7 @@ class ApiWrapper:
|
|
213
219
|
model=params,
|
214
220
|
)
|
215
221
|
|
216
|
-
return analysis_result.Analysis.
|
222
|
+
return analysis_result.Analysis.model_validate(data)
|
217
223
|
|
218
224
|
@classmethod
|
219
225
|
async def call_analyzer_app(
|
@@ -224,7 +230,7 @@ class ApiWrapper:
|
|
224
230
|
url=routes.ANALYZER_DATA_FULL_PATH,
|
225
231
|
model=params,
|
226
232
|
)
|
227
|
-
return analysis_result.DataID.
|
233
|
+
return analysis_result.DataID.model_validate(data)
|
228
234
|
|
229
235
|
@classmethod
|
230
236
|
async def get_generated_circuit_from_qasm(
|
@@ -235,7 +241,7 @@ class ApiWrapper:
|
|
235
241
|
url=routes.IDE_QASM_FULL_PATH,
|
236
242
|
model=params,
|
237
243
|
)
|
238
|
-
return generator_result.QuantumProgram.
|
244
|
+
return generator_result.QuantumProgram.model_validate(data)
|
239
245
|
|
240
246
|
@classmethod
|
241
247
|
async def get_analyzer_app_data(
|
@@ -245,7 +251,7 @@ class ApiWrapper:
|
|
245
251
|
http_method=HTTPMethod.GET,
|
246
252
|
url=f"{routes.ANALYZER_DATA_FULL_PATH}/{params.id}",
|
247
253
|
)
|
248
|
-
return generator_result.QuantumProgram.
|
254
|
+
return generator_result.QuantumProgram.model_validate(data)
|
249
255
|
|
250
256
|
@classmethod
|
251
257
|
async def call_rb_analysis_task(
|
@@ -254,10 +260,10 @@ class ApiWrapper:
|
|
254
260
|
data = await cls._call_task(
|
255
261
|
http_method=HTTPMethod.POST,
|
256
262
|
url=routes.ANALYZER_RB_FULL_PATH,
|
257
|
-
body=params.
|
263
|
+
body=params.model_dump(),
|
258
264
|
)
|
259
265
|
|
260
|
-
return analysis_result.RbResults.
|
266
|
+
return analysis_result.RbResults.model_validate(data)
|
261
267
|
|
262
268
|
@classmethod
|
263
269
|
async def call_hardware_connectivity_task(
|
@@ -268,7 +274,7 @@ class ApiWrapper:
|
|
268
274
|
url=routes.ANALYZER_HC_GRAPH_FULL_PATH,
|
269
275
|
model=params,
|
270
276
|
)
|
271
|
-
return analysis_result.GraphResult.
|
277
|
+
return analysis_result.GraphResult.model_validate(data)
|
272
278
|
|
273
279
|
@classmethod
|
274
280
|
async def call_table_graphs_task(
|
@@ -320,7 +326,7 @@ class ApiWrapper:
|
|
320
326
|
)
|
321
327
|
if not isinstance(data, list):
|
322
328
|
raise ClassiqAPIError(f"Unexpected value: {data}")
|
323
|
-
return [HardwareInformation.
|
329
|
+
return [HardwareInformation.model_validate(info) for info in data]
|
324
330
|
|
325
331
|
@classmethod
|
326
332
|
async def call_generate_hamiltonian_task(
|
@@ -332,3 +338,23 @@ class ApiWrapper:
|
|
332
338
|
)
|
333
339
|
result = await poller.run_pydantic(problem, timeout_sec=None)
|
334
340
|
return _parse_job_response(result, operator.PauliOperator)
|
341
|
+
|
342
|
+
@classmethod
|
343
|
+
async def call_iqcc_init_auth(cls, data: IQCCInitAuthData) -> IQCCInitAuthResponse:
|
344
|
+
response = await cls._call_task_pydantic(
|
345
|
+
http_method=HTTPMethod.GET,
|
346
|
+
url=f"{routes.IQCC_INIT_AUTH_FULL_PATH}",
|
347
|
+
model=data,
|
348
|
+
)
|
349
|
+
return IQCCInitAuthResponse.parse_obj(response)
|
350
|
+
|
351
|
+
@classmethod
|
352
|
+
async def call_iqcc_probe_auth(
|
353
|
+
cls, data: IQCCProbeAuthData
|
354
|
+
) -> IQCCProbeAuthResponse:
|
355
|
+
response = await cls._call_task_pydantic(
|
356
|
+
http_method=HTTPMethod.GET,
|
357
|
+
url=f"{routes.IQCC_PROBE_AUTH_FULL_PATH}",
|
358
|
+
model=data,
|
359
|
+
)
|
360
|
+
return IQCCProbeAuthResponse.parse_obj(response)
|
@@ -3,18 +3,34 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import Any, Dict, Optional, Union
|
4
4
|
|
5
5
|
from httpx import AsyncClient, Response, codes
|
6
|
-
from pydantic import
|
6
|
+
from pydantic import Field
|
7
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
7
8
|
|
8
9
|
from classiq.interface.exceptions import ClassiqAuthenticationError
|
9
10
|
|
10
11
|
|
11
12
|
class AuthSettings(BaseSettings):
|
12
|
-
domain: str = Field(
|
13
|
-
|
13
|
+
domain: str = Field(
|
14
|
+
default="auth.classiq.io", validation_alias="CLASSIQ_AUTH_DOMAIN"
|
15
|
+
)
|
16
|
+
audience: str = Field(
|
17
|
+
default="https://cadmium-be", validation_alias="CLASSIQ_AUTH_AUDIENCE"
|
18
|
+
)
|
14
19
|
client_id: str = Field(
|
15
|
-
default="f6721qMOVoDAOVkzrv8YaWassRKSFX6Y",
|
20
|
+
default="f6721qMOVoDAOVkzrv8YaWassRKSFX6Y",
|
21
|
+
validation_alias="CLASSIQ_AUTH_CLIENT_ID",
|
16
22
|
)
|
17
23
|
|
24
|
+
model_config = SettingsConfigDict(extra="allow")
|
25
|
+
|
26
|
+
def __init__(self, **data: Any) -> None:
|
27
|
+
initial_data = {
|
28
|
+
field: data[field] for field in data if field in self.model_fields
|
29
|
+
}
|
30
|
+
super().__init__(**data)
|
31
|
+
for field, value in initial_data.items():
|
32
|
+
setattr(self, field, value)
|
33
|
+
|
18
34
|
|
19
35
|
@dataclass
|
20
36
|
class Tokens:
|
@@ -5,23 +5,35 @@ import os
|
|
5
5
|
import pathlib
|
6
6
|
import platform
|
7
7
|
import stat
|
8
|
-
from typing import Dict, Optional
|
8
|
+
from typing import Any, Dict, Optional
|
9
9
|
|
10
10
|
import keyring
|
11
11
|
from keyring.backends import fail
|
12
|
-
from pydantic import
|
12
|
+
from pydantic import Field
|
13
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
13
14
|
|
14
15
|
_logger = logging.getLogger(__name__)
|
15
16
|
|
16
17
|
|
17
18
|
class PasswordManagerSettings(BaseSettings):
|
18
19
|
ACCESS_TOKEN_KEY: str = Field(
|
19
|
-
default="classiqTokenAccount",
|
20
|
+
default="classiqTokenAccount", validation_alias="CLASSIQ_ACCESS_TOKEN_ACCOUNT"
|
20
21
|
)
|
21
22
|
REFRESH_TOKEN_KEY: str = Field(
|
22
|
-
default="classiqRefershTokenAccount",
|
23
|
+
default="classiqRefershTokenAccount",
|
24
|
+
validation_alias="CLASSIQ_REFRESH_TOKEN_ACCOUNT",
|
23
25
|
)
|
24
26
|
|
27
|
+
model_config = SettingsConfigDict(extra="allow")
|
28
|
+
|
29
|
+
def __init__(self, **data: Any) -> None:
|
30
|
+
initial_data = {
|
31
|
+
field: data[field] for field in data if field in self.model_fields
|
32
|
+
}
|
33
|
+
super().__init__(**data)
|
34
|
+
for field, value in initial_data.items():
|
35
|
+
setattr(self, field, value)
|
36
|
+
|
25
37
|
|
26
38
|
class PasswordManager(abc.ABC):
|
27
39
|
_SERVICE_NAME: str = "classiqTokenService"
|
classiq/_internals/client.py
CHANGED
@@ -207,7 +207,7 @@ class Client:
|
|
207
207
|
|
208
208
|
def _make_client_args(self) -> Dict[str, Any]:
|
209
209
|
return {
|
210
|
-
"base_url": self._config.host,
|
210
|
+
"base_url": str(self._config.host),
|
211
211
|
"timeout": self._HTTP_TIMEOUT_SECONDS,
|
212
212
|
"headers": self.get_headers(),
|
213
213
|
}
|
@@ -269,7 +269,7 @@ class Client:
|
|
269
269
|
await self._token_manager.update_expired_access_token()
|
270
270
|
|
271
271
|
def get_backend_uri(self) -> str:
|
272
|
-
return self._config.host
|
272
|
+
return self._config.host.unicode_string()
|
273
273
|
|
274
274
|
def check_host(self) -> None:
|
275
275
|
# This function is NOT async (despite the fact that it can be) because it's called from a non-async context.
|
@@ -39,7 +39,7 @@ class HostChecker:
|
|
39
39
|
self._interface_version = interface_version
|
40
40
|
|
41
41
|
def _get_interface_version(self) -> Optional[str]:
|
42
|
-
global_interfaces = GlobalVersions.
|
42
|
+
global_interfaces = GlobalVersions.model_validate(
|
43
43
|
self._client.sync_call_api(
|
44
44
|
"get", "/interface_versions", use_versioned_url=False
|
45
45
|
)
|
@@ -47,11 +47,13 @@ class HostChecker:
|
|
47
47
|
return global_interfaces.deployed.get(self._interface_version, None)
|
48
48
|
|
49
49
|
def _get_host_version(self) -> str:
|
50
|
-
host = HostVersions.
|
50
|
+
host = HostVersions.model_validate(
|
51
|
+
self._client.sync_call_api("get", "/versions")
|
52
|
+
)
|
51
53
|
return host.classiq_interface
|
52
54
|
|
53
55
|
def _get_deprecation_info(self) -> Optional[DeprecationInfo]:
|
54
|
-
global_versions = GlobalVersions.
|
56
|
+
global_versions = GlobalVersions.model_validate(
|
55
57
|
self._client.sync_call_api("get", "/versions", use_versioned_url=False)
|
56
58
|
)
|
57
59
|
return global_versions.deprecated.get(self._client_version, None)
|
classiq/_internals/jobs.py
CHANGED
@@ -37,7 +37,7 @@ def _join_url_path(*parts: str) -> str:
|
|
37
37
|
def _general_job_description_parser(
|
38
38
|
json_response: JSONObject,
|
39
39
|
) -> Optional[GeneralJobDescription]:
|
40
|
-
job_description = GeneralJobDescription.
|
40
|
+
job_description = GeneralJobDescription.model_validate(json_response)
|
41
41
|
if job_description.status.is_final():
|
42
42
|
return job_description
|
43
43
|
return None
|
@@ -68,7 +68,7 @@ class JobPoller:
|
|
68
68
|
self._mode = client_instance.config.mode
|
69
69
|
|
70
70
|
def _parse_job_id_response(self, response: httpx.Response) -> JobID:
|
71
|
-
return JobID.
|
71
|
+
return JobID.model_validate(response.json())
|
72
72
|
|
73
73
|
def _make_poll_url(self, job_id: JobID) -> str:
|
74
74
|
return _join_url_path(self._base_url, job_id.job_id)
|
@@ -171,5 +171,5 @@ class JobPoller:
|
|
171
171
|
# TODO: we can't use model.dict() - it doesn't serialize complex class.
|
172
172
|
# This was added because JSON serializer doesn't serialize complex and UUID,
|
173
173
|
# while pydantic does. We should add support for smarter json serialization.
|
174
|
-
body = json.loads(model.
|
174
|
+
body = json.loads(model.model_dump_json())
|
175
175
|
return await self.run(body, timeout_sec)
|
@@ -41,7 +41,7 @@ class AnalyzerUtilities:
|
|
41
41
|
qubit_count=self.circuit.data.width, providers=requested_providers
|
42
42
|
)
|
43
43
|
result = await ApiWrapper.call_available_devices_task(params=params)
|
44
|
-
self.available_devices.update(result.devices.
|
44
|
+
self.available_devices.update(result.devices.model_dump())
|
45
45
|
|
46
46
|
async def request_hardware_connectivity_async(
|
47
47
|
self, provider: ProviderNameEnum, device: DeviceName
|
@@ -33,7 +33,7 @@ async def update_problem_async(
|
|
33
33
|
) -> CHEMISTRY_PROBLEMS_TYPE:
|
34
34
|
if num_qubits is None:
|
35
35
|
num_qubits = await _get_num_qubits(problem)
|
36
|
-
return problem.
|
36
|
+
return problem.model_copy(update={"num_qubits": num_qubits})
|
37
37
|
|
38
38
|
|
39
39
|
ground_state_problem.GroundStateProblem.update_problem = async_utils.syncify_function( # type: ignore[attr-defined]
|
@@ -143,7 +143,9 @@ def convert_pyomo_to_global_presentation(
|
|
143
143
|
pyo_model: pyo.ConcreteModel,
|
144
144
|
) -> pyo.ConcreteModel:
|
145
145
|
pyo_model_str = pyomo2qmod("nativePyoModel", pyo_model)
|
146
|
-
problem_struct = CombinatorialOptimizationStructDeclaration.
|
146
|
+
problem_struct = CombinatorialOptimizationStructDeclaration.model_validate_json(
|
147
|
+
pyo_model_str
|
148
|
+
)
|
147
149
|
|
148
150
|
pyomo_model = pyo.ConcreteModel()
|
149
151
|
|
@@ -23,7 +23,7 @@ class QuantumGradient(abc.ABC):
|
|
23
23
|
self._execute = execute
|
24
24
|
self._post_process = post_process
|
25
25
|
|
26
|
-
circuit = QuantumProgram.
|
26
|
+
circuit = QuantumProgram.model_validate_json(quantum_program)
|
27
27
|
validate_circuit(circuit)
|
28
28
|
self._quantum_program = quantum_program
|
29
29
|
self._parameters_names = extract_parameters(circuit)
|
@@ -52,7 +52,7 @@ class QLayerFunction(torch.autograd.Function):
|
|
52
52
|
and returning a `Tensor`
|
53
53
|
|
54
54
|
"""
|
55
|
-
circuit = Circuit.
|
55
|
+
circuit = Circuit.model_validate_json(quantum_program)
|
56
56
|
validate_circuit(circuit)
|
57
57
|
|
58
58
|
# save for backward
|
@@ -144,7 +144,7 @@ class QLayer(nn.Module):
|
|
144
144
|
# Experimental parameters:
|
145
145
|
calc_num_out_features: CalcNumOutFeatures = calc_num_out_features_single_output,
|
146
146
|
) -> None:
|
147
|
-
circuit = Circuit.
|
147
|
+
circuit = Circuit.model_validate_json(quantum_program)
|
148
148
|
validate_circuit(circuit)
|
149
149
|
|
150
150
|
super().__init__()
|
classiq/execution/__init__.py
CHANGED
@@ -10,6 +10,7 @@ from ..interface.executor.iqae_result import IQAEResult
|
|
10
10
|
from ..interface.executor.result import ExecutionDetails
|
11
11
|
from ..interface.executor.vqe_result import VQESolverResult
|
12
12
|
from .execution_session import ExecutionSession
|
13
|
+
from .iqcc import generate_iqcc_token, generate_iqcc_token_async
|
13
14
|
from .jobs import ExecutionJob, get_execution_jobs, get_execution_jobs_async
|
14
15
|
from .qnn import execute_qnn
|
15
16
|
|
@@ -26,6 +27,8 @@ __all__ = (
|
|
26
27
|
"get_execution_jobs_async",
|
27
28
|
"ExecutionSession",
|
28
29
|
"execute_qnn",
|
30
|
+
"generate_iqcc_token",
|
31
|
+
"generate_iqcc_token_async",
|
29
32
|
]
|
30
33
|
)
|
31
34
|
|
@@ -48,7 +48,7 @@ def _deserialize_program(program: Program) -> QuantumProgram:
|
|
48
48
|
return (
|
49
49
|
program
|
50
50
|
if isinstance(program, QuantumProgram)
|
51
|
-
else QuantumProgram.
|
51
|
+
else QuantumProgram.model_validate(json.loads(program))
|
52
52
|
)
|
53
53
|
|
54
54
|
|
@@ -162,7 +162,7 @@ class ExecutionSession:
|
|
162
162
|
Returns:
|
163
163
|
SerializedQuantumProgram: The serialized quantum program (str). See `QuantumProgram`.
|
164
164
|
"""
|
165
|
-
return SerializedQuantumProgram(self.program.
|
165
|
+
return SerializedQuantumProgram(self.program.model_dump_json(indent=2))
|
166
166
|
|
167
167
|
def update_execution_preferences(
|
168
168
|
self, execution_preferences: Optional[ExecutionPreferences]
|
@@ -0,0 +1,63 @@
|
|
1
|
+
import time
|
2
|
+
import webbrowser
|
3
|
+
|
4
|
+
from classiq.interface.exceptions import ClassiqError
|
5
|
+
from classiq.interface.execution.iqcc import IQCCInitAuthData, IQCCProbeAuthData
|
6
|
+
|
7
|
+
from classiq._internals.api_wrapper import ApiWrapper
|
8
|
+
from classiq._internals.async_utils import syncify_function
|
9
|
+
|
10
|
+
|
11
|
+
async def generate_iqcc_token_async(
|
12
|
+
auth_scope_id: str,
|
13
|
+
auth_method_id: str,
|
14
|
+
timeout: float = 120,
|
15
|
+
probe_interval: float = 1,
|
16
|
+
print_auth_url: bool = True,
|
17
|
+
) -> str:
|
18
|
+
"""Interactively generate a token for use in IQCC backends.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
auth_scope_id: The ID of the IQCC Boundary authentication scope.
|
22
|
+
auth_method_id: The ID of the IQCC Boundary authentication method.
|
23
|
+
timeout: Number of seconds to wait for the interactive authentication to complete.
|
24
|
+
probe_interval: Number of seconds to wait between probes of the authentication.
|
25
|
+
print_auth_url: Whether to print the authentication URL, useful for headless machines with no browser.
|
26
|
+
|
27
|
+
Returns:
|
28
|
+
The authentication token string to use directly in `IQCCBackendPreferences`.
|
29
|
+
|
30
|
+
Raises:
|
31
|
+
ClassiqError: In case timeout has reached before a successful authentication.
|
32
|
+
"""
|
33
|
+
initiate_response = await ApiWrapper().call_iqcc_init_auth(
|
34
|
+
IQCCInitAuthData(auth_scope_id=auth_scope_id, auth_method_id=auth_method_id)
|
35
|
+
)
|
36
|
+
|
37
|
+
if print_auth_url:
|
38
|
+
print("Please proceed with authentication on your web browser.") # noqa: T201
|
39
|
+
print("If no window has opened, use this link to authenticate:") # noqa: T201
|
40
|
+
print(initiate_response.auth_url) # noqa: T201
|
41
|
+
|
42
|
+
webbrowser.open_new_tab(initiate_response.auth_url)
|
43
|
+
|
44
|
+
start_time = time.monotonic()
|
45
|
+
while True:
|
46
|
+
time.sleep(probe_interval)
|
47
|
+
probe_response = await ApiWrapper().call_iqcc_probe_auth(
|
48
|
+
IQCCProbeAuthData(
|
49
|
+
auth_scope_id=auth_scope_id,
|
50
|
+
auth_method_id=auth_method_id,
|
51
|
+
token_id=initiate_response.token_id,
|
52
|
+
)
|
53
|
+
)
|
54
|
+
if probe_response.auth_token is not None:
|
55
|
+
return probe_response.auth_token
|
56
|
+
|
57
|
+
if time.monotonic() - start_time > timeout:
|
58
|
+
raise ClassiqError(
|
59
|
+
f"Timeout has reached while probing IQCC authentication. Please try again and make sure to authenticate within {timeout} seconds, or increase the timeout."
|
60
|
+
)
|
61
|
+
|
62
|
+
|
63
|
+
generate_iqcc_token = syncify_function(generate_iqcc_token_async)
|
classiq/execution/jobs.py
CHANGED
@@ -226,7 +226,7 @@ class ExecutionJob:
|
|
226
226
|
|
227
227
|
async def _poll_job(self, timeout_sec: Optional[float] = None) -> None:
|
228
228
|
def response_parser(json_response: JSONObject) -> Optional[bool]:
|
229
|
-
self._details = ExecutionJobDetails.
|
229
|
+
self._details = ExecutionJobDetails.model_validate(json_response)
|
230
230
|
if self.status.is_final():
|
231
231
|
return True
|
232
232
|
return None
|
@@ -262,7 +262,7 @@ class ExecutionJob:
|
|
262
262
|
|
263
263
|
@property
|
264
264
|
def ide_url(self) -> str:
|
265
|
-
base_url = client().config.ide
|
265
|
+
base_url = client().config.ide.unicode_string()
|
266
266
|
return urljoin(base_url, f"jobs/{self.id}")
|
267
267
|
|
268
268
|
def open_in_ide(self) -> None:
|
classiq/executor.py
CHANGED
@@ -27,7 +27,7 @@ BackendPreferencesAndResult: TypeAlias = Tuple[
|
|
27
27
|
def _parse_serialized_qprog(
|
28
28
|
quantum_program: SerializedQuantumProgram,
|
29
29
|
) -> QuantumProgram:
|
30
|
-
return QuantumProgram.
|
30
|
+
return QuantumProgram.model_validate_json(quantum_program)
|
31
31
|
|
32
32
|
|
33
33
|
async def execute_async(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
|
@@ -57,7 +57,7 @@ def set_quantum_program_execution_preferences(
|
|
57
57
|
) -> SerializedQuantumProgram:
|
58
58
|
circuit = _parse_serialized_qprog(quantum_program)
|
59
59
|
circuit.model.execution_preferences = preferences
|
60
|
-
return SerializedQuantumProgram(circuit.
|
60
|
+
return SerializedQuantumProgram(circuit.model_dump_json())
|
61
61
|
|
62
62
|
|
63
63
|
__all__ = [
|
classiq/interface/_version.py
CHANGED
@@ -2,7 +2,7 @@ from typing import Dict, List, Optional
|
|
2
2
|
|
3
3
|
import numpy
|
4
4
|
import pydantic
|
5
|
-
from pydantic import
|
5
|
+
from pydantic import ConfigDict, Field, StringConstraints
|
6
6
|
from typing_extensions import Annotated
|
7
7
|
|
8
8
|
from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
|
@@ -36,7 +36,8 @@ class HardwareListParams(pydantic.BaseModel):
|
|
36
36
|
providers: List[Provider]
|
37
37
|
from_ide: bool = Field(default=False)
|
38
38
|
|
39
|
-
@pydantic.
|
39
|
+
@pydantic.field_validator("providers")
|
40
|
+
@classmethod
|
40
41
|
def set_default_providers(
|
41
42
|
cls, providers: Optional[List[AnalyzerProviderVendor]]
|
42
43
|
) -> List[AnalyzerProviderVendor]:
|
@@ -55,8 +56,12 @@ class AnalysisOptionalDevicesParams(HardwareListParams):
|
|
55
56
|
|
56
57
|
|
57
58
|
class GateNamsMapping(pydantic.BaseModel):
|
58
|
-
qasm_name: Annotated[
|
59
|
-
|
59
|
+
qasm_name: Annotated[
|
60
|
+
str, Annotated[str, StringConstraints(max_length=MAX_NAME_LENGTH)]
|
61
|
+
]
|
62
|
+
display_name: Annotated[
|
63
|
+
str, Annotated[str, StringConstraints(max_length=MAX_NAME_LENGTH)]
|
64
|
+
]
|
60
65
|
|
61
66
|
|
62
67
|
class LatexParams(AnalysisParams):
|
@@ -66,7 +71,7 @@ class LatexParams(AnalysisParams):
|
|
66
71
|
|
67
72
|
|
68
73
|
class AnalysisHardwareTranspilationParams(pydantic.BaseModel):
|
69
|
-
hardware_data: Optional[SynthesisHardwareData]
|
74
|
+
hardware_data: Optional[SynthesisHardwareData] = None
|
70
75
|
random_seed: int
|
71
76
|
transpilation_option: TranspilationOption
|
72
77
|
|
@@ -91,13 +96,18 @@ class CircuitAnalysisHardwareParams(AnalysisParams):
|
|
91
96
|
|
92
97
|
class AnalysisRBParams(pydantic.BaseModel):
|
93
98
|
hardware: str
|
94
|
-
counts: List[
|
95
|
-
|
99
|
+
counts: List[
|
100
|
+
Dict[
|
101
|
+
str, Annotated[int, Annotated[int, Field(strict=True, gt=0, le=MAX_COUNTS)]]
|
102
|
+
]
|
103
|
+
]
|
104
|
+
num_clifford: List[
|
105
|
+
Annotated[int, Annotated[int, Field(strict=True, gt=0, le=MAX_NUM_CLIFFORD)]]
|
106
|
+
]
|
96
107
|
|
97
108
|
|
98
109
|
class ChemistryGenerationParams(pydantic.BaseModel):
|
99
|
-
|
100
|
-
title = "Chemistry"
|
110
|
+
model_config = ConfigDict(title="Chemistry")
|
101
111
|
|
102
112
|
molecule: MoleculeProblem = pydantic.Field(
|
103
113
|
title="Molecule",
|
@@ -17,16 +17,23 @@ class CytoScapePosition(pydantic.BaseModel):
|
|
17
17
|
|
18
18
|
class CytoScapeEdgeData(pydantic.BaseModel):
|
19
19
|
source: str = pydantic.Field(
|
20
|
-
default
|
20
|
+
default=" ", description="the Id of the Node that is the Source of the edge"
|
21
21
|
)
|
22
22
|
target: str = pydantic.Field(
|
23
|
-
default
|
23
|
+
default=" ", description="the Id of the Node that is the Target the edge"
|
24
24
|
)
|
25
25
|
|
26
|
+
@pydantic.model_validator(mode="before")
|
27
|
+
@classmethod
|
28
|
+
def _validate_values(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
29
|
+
values["source"] = str(values["source"]) or " "
|
30
|
+
values["target"] = str(values["target"]) or " "
|
31
|
+
return values
|
32
|
+
|
26
33
|
|
27
34
|
class CytoScapeEdge(pydantic.BaseModel):
|
28
35
|
data: CytoScapeEdgeData = pydantic.Field(
|
29
|
-
|
36
|
+
description="Edge's Data, mainly the source and target of the Edge"
|
30
37
|
)
|
31
38
|
|
32
39
|
|
@@ -3,7 +3,7 @@ from uuid import UUID
|
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
from pydantic import Field
|
6
|
-
from typing_extensions import Annotated
|
6
|
+
from typing_extensions import Annotated, Self
|
7
7
|
|
8
8
|
from classiq.interface.analyzer.analysis_params import MAX_FILE_LENGTH
|
9
9
|
from classiq.interface.enum_utils import StrEnum
|
@@ -74,12 +74,13 @@ class HardwareComparisonInformation(pydantic.BaseModel):
|
|
74
74
|
default=..., description="Number of total gates."
|
75
75
|
)
|
76
76
|
|
77
|
-
@pydantic.
|
78
|
-
def validate_equal_length(
|
77
|
+
@pydantic.model_validator(mode="after")
|
78
|
+
def validate_equal_length(self) -> Self:
|
79
|
+
values = self.model_dump()
|
79
80
|
lengths = list(map(len, values.values()))
|
80
81
|
if len(set(lengths)) != 1:
|
81
82
|
raise ClassiqValueError("All lists should have the same length")
|
82
|
-
return
|
83
|
+
return self
|
83
84
|
|
84
85
|
|
85
86
|
# TODO: copy the types for `devices` & `providers` from `HardwareComparisonInformation`
|
@@ -112,7 +113,7 @@ HardwareComparisonGraphType = Annotated[
|
|
112
113
|
]
|
113
114
|
|
114
115
|
_HARDWARE_COMPARISON_TABLE_COLUMNS_NAMES: Dict[str, str] = {
|
115
|
-
s.upper(): s.capitalize() for s in SingleHardwareInformation.
|
116
|
+
s.upper(): s.capitalize() for s in SingleHardwareInformation.model_fields
|
116
117
|
}
|
117
118
|
|
118
119
|
|