classiq 0.94.2__py3-none-any.whl → 0.96.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.
Potentially problematic release.
This version of classiq might be problematic. Click here for more details.
- classiq/_internals/api_wrapper.py +0 -83
- classiq/_internals/authentication/auth0.py +32 -3
- classiq/_internals/authentication/authorization_code.py +9 -0
- classiq/_internals/authentication/authorization_flow.py +41 -0
- classiq/_internals/authentication/device.py +31 -50
- classiq/_internals/authentication/hybrid_flow.py +19 -0
- classiq/_internals/authentication/token_manager.py +5 -4
- classiq/applications/__init__.py +2 -2
- classiq/applications/iqae/iqae.py +6 -3
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/qlayer.py +1 -1
- classiq/applications/qnn/torch_utils.py +2 -2
- classiq/applications/qsp/qsp.py +6 -5
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +10 -0
- classiq/execution/__init__.py +0 -3
- classiq/execution/user_budgets.py +0 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +11 -35
- classiq/interface/backend/quantum_backend_providers.py +0 -2
- classiq/interface/exceptions.py +0 -4
- classiq/interface/generator/application_apis/__init__.py +0 -1
- classiq/interface/generator/arith/register_user_input.py +1 -1
- classiq/interface/generator/function_param_list.py +0 -2
- classiq/interface/generator/generated_circuit_data.py +1 -6
- classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
- classiq/interface/generator/quantum_function_call.py +1 -1
- classiq/interface/generator/quantum_program.py +0 -4
- classiq/interface/generator/transpiler_basis_gates.py +3 -0
- classiq/interface/generator/types/builtin_enum_declarations.py +0 -9
- classiq/interface/hardware.py +0 -1
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/block.py +4 -0
- classiq/interface/model/classical_if.py +4 -0
- classiq/interface/model/control.py +7 -0
- classiq/interface/model/invert.py +4 -0
- classiq/interface/model/model_visitor.py +40 -1
- classiq/interface/model/power.py +4 -0
- classiq/interface/model/quantum_statement.py +8 -1
- classiq/interface/model/repeat.py +4 -0
- classiq/interface/model/skip_control.py +4 -0
- classiq/interface/model/within_apply_operation.py +4 -0
- classiq/interface/server/routes.py +0 -12
- classiq/model_expansions/generative_functions.py +6 -8
- classiq/model_expansions/interpreters/base_interpreter.py +1 -1
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +2 -1
- classiq/model_expansions/visitors/symbolic_param_inference.py +3 -3
- classiq/model_expansions/visitors/uncomputation_signature_inference.py +14 -3
- classiq/open_library/functions/__init__.py +3 -2
- classiq/open_library/functions/amplitude_loading.py +85 -0
- classiq/open_library/functions/lcu.py +47 -18
- classiq/open_library/functions/modular_exponentiation.py +5 -8
- classiq/open_library/functions/qsvt.py +4 -4
- classiq/open_library/functions/state_preparation.py +7 -7
- classiq/qmod/builtins/classical_execution_primitives.py +0 -12
- classiq/qmod/builtins/enums.py +15 -17
- classiq/qmod/builtins/functions/__init__.py +5 -5
- classiq/qmod/builtins/functions/allocation.py +21 -0
- classiq/qmod/builtins/functions/mcx.py +7 -0
- classiq/qmod/builtins/operations.py +125 -23
- classiq/qmod/builtins/structs.py +22 -33
- classiq/qmod/semantics/annotation/call_annotation.py +3 -3
- classiq/qmod/semantics/error_manager.py +7 -8
- classiq/qmod/utilities.py +0 -10
- {classiq-0.94.2.dist-info → classiq-0.96.0.dist-info}/METADATA +1 -1
- {classiq-0.94.2.dist-info → classiq-0.96.0.dist-info}/RECORD +67 -71
- {classiq-0.94.2.dist-info → classiq-0.96.0.dist-info}/WHEEL +1 -1
- classiq/applications/qsvm/__init__.py +0 -8
- classiq/applications/qsvm/qsvm.py +0 -11
- classiq/execution/iqcc.py +0 -128
- classiq/interface/applications/qsvm.py +0 -114
- classiq/interface/execution/iqcc.py +0 -42
- classiq/interface/generator/application_apis/qsvm_declarations.py +0 -6
- classiq/interface/generator/qsvm.py +0 -96
- classiq/open_library/functions/lookup_table.py +0 -58
- classiq/qmod/builtins/functions/qsvm.py +0 -24
- {classiq-0.94.2.dist-info → classiq-0.96.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -12,15 +12,6 @@ from classiq.interface.analyzer.analysis_params import AnalysisRBParams
|
|
|
12
12
|
from classiq.interface.analyzer.result import GraphStatus, QmodCode
|
|
13
13
|
from classiq.interface.enum_utils import StrEnum
|
|
14
14
|
from classiq.interface.exceptions import ClassiqAPIError, ClassiqValueError
|
|
15
|
-
from classiq.interface.execution.iqcc import (
|
|
16
|
-
IQCCAuthItemsDetails,
|
|
17
|
-
IQCCInitAuthData,
|
|
18
|
-
IQCCInitAuthResponse,
|
|
19
|
-
IQCCListAuthMethods,
|
|
20
|
-
IQCCListAuthTargets,
|
|
21
|
-
IQCCProbeAuthData,
|
|
22
|
-
IQCCProbeAuthResponse,
|
|
23
|
-
)
|
|
24
15
|
from classiq.interface.execution.primitives import PrimitivesInput
|
|
25
16
|
from classiq.interface.executor import execution_request
|
|
26
17
|
from classiq.interface.executor.quantum_program_params import (
|
|
@@ -488,80 +479,6 @@ class ApiWrapper:
|
|
|
488
479
|
raise ClassiqAPIError(f"Unexpected value: {data}")
|
|
489
480
|
return [HardwareInformation.model_validate(info) for info in data]
|
|
490
481
|
|
|
491
|
-
@classmethod
|
|
492
|
-
async def call_iqcc_init_auth(
|
|
493
|
-
cls,
|
|
494
|
-
data: IQCCInitAuthData,
|
|
495
|
-
http_client: httpx.AsyncClient | None = None,
|
|
496
|
-
) -> IQCCInitAuthResponse:
|
|
497
|
-
response = await cls._call_task_pydantic(
|
|
498
|
-
http_method=HTTPMethod.PUT,
|
|
499
|
-
url=f"{routes.IQCC_INIT_AUTH_FULL_PATH}",
|
|
500
|
-
model=data,
|
|
501
|
-
http_client=http_client,
|
|
502
|
-
)
|
|
503
|
-
return IQCCInitAuthResponse.model_validate(response)
|
|
504
|
-
|
|
505
|
-
@classmethod
|
|
506
|
-
async def call_iqcc_probe_auth(
|
|
507
|
-
cls,
|
|
508
|
-
data: IQCCProbeAuthData,
|
|
509
|
-
http_client: httpx.AsyncClient | None = None,
|
|
510
|
-
) -> IQCCProbeAuthResponse | None:
|
|
511
|
-
try:
|
|
512
|
-
response = await cls._call_task_pydantic(
|
|
513
|
-
http_method=HTTPMethod.PUT,
|
|
514
|
-
url=f"{routes.IQCC_PROBE_AUTH_FULL_PATH}",
|
|
515
|
-
model=data,
|
|
516
|
-
http_client=http_client,
|
|
517
|
-
)
|
|
518
|
-
except ClassiqAPIError as ex:
|
|
519
|
-
if ex.status_code == 418:
|
|
520
|
-
return None
|
|
521
|
-
raise
|
|
522
|
-
|
|
523
|
-
return IQCCProbeAuthResponse.model_validate(response)
|
|
524
|
-
|
|
525
|
-
@classmethod
|
|
526
|
-
async def call_iqcc_list_auth_scopes(
|
|
527
|
-
cls,
|
|
528
|
-
http_client: httpx.AsyncClient | None = None,
|
|
529
|
-
) -> IQCCAuthItemsDetails:
|
|
530
|
-
response = await cls._call_task(
|
|
531
|
-
http_method=HTTPMethod.GET,
|
|
532
|
-
url=routes.IQCC_LIST_AUTH_SCOPES_FULL_PATH,
|
|
533
|
-
http_client=http_client,
|
|
534
|
-
)
|
|
535
|
-
return IQCCAuthItemsDetails.model_validate(response)
|
|
536
|
-
|
|
537
|
-
@classmethod
|
|
538
|
-
async def call_iqcc_list_auth_methods(
|
|
539
|
-
cls,
|
|
540
|
-
data: IQCCListAuthMethods,
|
|
541
|
-
http_client: httpx.AsyncClient | None = None,
|
|
542
|
-
) -> IQCCAuthItemsDetails:
|
|
543
|
-
response = await cls._call_task_pydantic(
|
|
544
|
-
http_method=HTTPMethod.PUT,
|
|
545
|
-
url=routes.IQCC_LIST_AUTH_METHODS_FULL_PATH,
|
|
546
|
-
model=data,
|
|
547
|
-
http_client=http_client,
|
|
548
|
-
)
|
|
549
|
-
return IQCCAuthItemsDetails.model_validate(response)
|
|
550
|
-
|
|
551
|
-
@classmethod
|
|
552
|
-
async def call_iqcc_list_auth_targets(
|
|
553
|
-
cls,
|
|
554
|
-
data: IQCCListAuthTargets,
|
|
555
|
-
http_client: httpx.AsyncClient | None = None,
|
|
556
|
-
) -> IQCCAuthItemsDetails:
|
|
557
|
-
response = await cls._call_task_pydantic(
|
|
558
|
-
http_method=HTTPMethod.PUT,
|
|
559
|
-
url=routes.IQCC_LIST_AUTH_TARGETS_FULL_PATH,
|
|
560
|
-
model=data,
|
|
561
|
-
http_client=http_client,
|
|
562
|
-
)
|
|
563
|
-
return IQCCAuthItemsDetails.model_validate(response)
|
|
564
|
-
|
|
565
482
|
@classmethod
|
|
566
483
|
async def call_get_all_budgets(cls) -> list[UserBudget]:
|
|
567
484
|
data = await client().call_api(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import urllib.parse
|
|
2
|
+
import warnings
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
@@ -20,6 +21,7 @@ class AuthSettings(BaseSettings):
|
|
|
20
21
|
default="f6721qMOVoDAOVkzrv8YaWassRKSFX6Y",
|
|
21
22
|
validation_alias="CLASSIQ_AUTH_CLIENT_ID",
|
|
22
23
|
)
|
|
24
|
+
organization: str = Field(default="", validation_alias="CLASSIQ_AUTH_ORGANIZATION")
|
|
23
25
|
|
|
24
26
|
model_config = SettingsConfigDict(extra="allow")
|
|
25
27
|
|
|
@@ -53,6 +55,10 @@ class Auth0:
|
|
|
53
55
|
def _client_id(self) -> str:
|
|
54
56
|
return self._auth_settings.client_id
|
|
55
57
|
|
|
58
|
+
@property
|
|
59
|
+
def _organization(self) -> str:
|
|
60
|
+
return self._auth_settings.organization
|
|
61
|
+
|
|
56
62
|
async def _make_request(
|
|
57
63
|
self,
|
|
58
64
|
url: str,
|
|
@@ -76,13 +82,20 @@ class Auth0:
|
|
|
76
82
|
f"Request to Auth0 failed with error code {code}: {data.get('error')}"
|
|
77
83
|
)
|
|
78
84
|
|
|
79
|
-
async def get_device_data(
|
|
85
|
+
async def get_device_data(
|
|
86
|
+
self, require_refresh_token: bool = True
|
|
87
|
+
) -> dict[str, Any]:
|
|
80
88
|
payload = {
|
|
81
|
-
"client_id": self.
|
|
89
|
+
"client_id": self._client_id,
|
|
82
90
|
"audience": self._auth_settings.audience,
|
|
83
91
|
}
|
|
84
|
-
if
|
|
92
|
+
if require_refresh_token:
|
|
85
93
|
payload["scope"] = "offline_access"
|
|
94
|
+
if self._organization:
|
|
95
|
+
warnings.warn(
|
|
96
|
+
"Organizations are not supported in device auth flow.",
|
|
97
|
+
stacklevel=1,
|
|
98
|
+
)
|
|
86
99
|
|
|
87
100
|
return await self._make_request(
|
|
88
101
|
url="/oauth/device/code",
|
|
@@ -102,6 +115,22 @@ class Auth0:
|
|
|
102
115
|
allow_error=codes.FORBIDDEN,
|
|
103
116
|
)
|
|
104
117
|
|
|
118
|
+
def get_authorize_url(
|
|
119
|
+
self, redirect_uri: str, require_refresh_token: bool = True
|
|
120
|
+
) -> str:
|
|
121
|
+
params = {
|
|
122
|
+
"client_id": self._client_id,
|
|
123
|
+
"response_type": "code",
|
|
124
|
+
"audience": self._auth_settings.audience,
|
|
125
|
+
"redirect_uri": redirect_uri,
|
|
126
|
+
}
|
|
127
|
+
if require_refresh_token:
|
|
128
|
+
params["scope"] = "offline_access"
|
|
129
|
+
if self._organization:
|
|
130
|
+
# Otherwise, let the Auth0 handle
|
|
131
|
+
params["organization"] = self._organization
|
|
132
|
+
return f"{self._base_url}/authorize?{urllib.parse.urlencode(params)}"
|
|
133
|
+
|
|
105
134
|
async def refresh_access_token(self, refresh_token: str) -> Tokens:
|
|
106
135
|
# TODO handle failure
|
|
107
136
|
payload = {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from classiq._internals.authentication.authorization_flow import AuthorizationFlow
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AuthorizationCodeFlow(AuthorizationFlow):
|
|
5
|
+
async def authorize(self, redirect_uri: str) -> None:
|
|
6
|
+
auth_url = self.auth0_client.get_authorize_url(
|
|
7
|
+
redirect_uri, self.require_refresh_token
|
|
8
|
+
)
|
|
9
|
+
self.open_url(auth_url)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import webbrowser
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from classiq.interface.exceptions import ClassiqAuthenticationError
|
|
5
|
+
|
|
6
|
+
from classiq._internals.authentication.auth0 import Auth0, Tokens
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AuthorizationFlow:
|
|
10
|
+
def __init__(self, require_refresh_token: bool = True, text_only: bool = False):
|
|
11
|
+
self.require_refresh_token = require_refresh_token
|
|
12
|
+
self.text_only = text_only
|
|
13
|
+
self.auth0_client = Auth0()
|
|
14
|
+
|
|
15
|
+
async def get_tokens(self) -> Tokens:
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
|
|
18
|
+
def handle_ready_data(self, data: dict[str, Any]) -> Tokens:
|
|
19
|
+
access_token: str | None = data.get("access_token") or None
|
|
20
|
+
# If refresh token was not requested, this would be None
|
|
21
|
+
refresh_token: str | None = data.get("refresh_token") or None
|
|
22
|
+
|
|
23
|
+
if access_token is None or (
|
|
24
|
+
self.require_refresh_token is True and refresh_token is None
|
|
25
|
+
):
|
|
26
|
+
raise ClassiqAuthenticationError(
|
|
27
|
+
"Token generation failed for unknown reason (missing access token or refresh token)."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return Tokens(access_token=access_token, refresh_token=refresh_token)
|
|
31
|
+
|
|
32
|
+
def open_url(self, url: str) -> None:
|
|
33
|
+
if self.text_only:
|
|
34
|
+
print( # noqa: T201
|
|
35
|
+
f"Please visit this URL from any trusted device to authenticate: {url}"
|
|
36
|
+
)
|
|
37
|
+
else:
|
|
38
|
+
webbrowser.open(url)
|
|
39
|
+
print( # noqa: T201
|
|
40
|
+
f"If a browser doesn't automatically open, please visit this URL from any trusted device to authenticate: {url}"
|
|
41
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import webbrowser
|
|
3
2
|
from collections.abc import Iterable
|
|
3
|
+
from dataclasses import dataclass
|
|
4
4
|
from datetime import timedelta
|
|
5
5
|
from typing import Any, TypeVar
|
|
6
6
|
|
|
@@ -10,74 +10,55 @@ from classiq.interface.exceptions import (
|
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
from classiq._internals.async_utils import poll_for
|
|
13
|
-
from classiq._internals.authentication.auth0 import
|
|
13
|
+
from classiq._internals.authentication.auth0 import Tokens
|
|
14
|
+
from classiq._internals.authentication.authorization_flow import AuthorizationFlow
|
|
14
15
|
|
|
15
16
|
T = TypeVar("T")
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
@dataclass
|
|
20
|
+
class DeviceData:
|
|
21
|
+
user_code: str
|
|
22
|
+
device_code: str
|
|
23
|
+
interval: float
|
|
24
|
+
expires_in: float
|
|
25
|
+
verification_uri: str
|
|
26
|
+
verification_uri_complete: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DeviceCodeFlow(AuthorizationFlow):
|
|
19
30
|
_TIMEOUT_ERROR = (
|
|
20
31
|
"Device registration timed out. Please re-initiate the flow and "
|
|
21
32
|
"authorize the device within the timeout."
|
|
22
33
|
)
|
|
23
34
|
_TIMEOUT_SEC: float = timedelta(minutes=15).total_seconds()
|
|
24
35
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
) -> Tokens:
|
|
29
|
-
auth0_client = Auth0()
|
|
30
|
-
data: dict[str, Any] = await auth0_client.get_device_data(
|
|
31
|
-
get_refresh_token=get_refresh_token
|
|
36
|
+
async def get_device_data(self) -> DeviceData:
|
|
37
|
+
device_data: dict[str, Any] = await self.auth0_client.get_device_data(
|
|
38
|
+
require_refresh_token=self.require_refresh_token
|
|
32
39
|
)
|
|
40
|
+
return DeviceData(**device_data)
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
webbrowser.open(verification_url)
|
|
41
|
-
timeout = min(data["expires_in"], cls._TIMEOUT_SEC)
|
|
42
|
-
return await cls._poll_tokens(
|
|
43
|
-
auth0_client=auth0_client,
|
|
44
|
-
device_code=data["device_code"],
|
|
45
|
-
interval=data["interval"],
|
|
42
|
+
async def poll_tokens(self, device_data: DeviceData) -> Tokens:
|
|
43
|
+
interval = device_data.interval
|
|
44
|
+
timeout = min(device_data.expires_in, self._TIMEOUT_SEC)
|
|
45
|
+
return await self._poll_tokens(
|
|
46
|
+
device_code=device_data.device_code,
|
|
47
|
+
interval=interval,
|
|
46
48
|
timeout=timeout,
|
|
47
|
-
get_refresh_token=get_refresh_token,
|
|
48
49
|
)
|
|
49
50
|
|
|
50
|
-
@classmethod
|
|
51
|
-
def _handle_ready_data(
|
|
52
|
-
cls, data: dict[str, Any], get_refresh_token: bool
|
|
53
|
-
) -> Tokens:
|
|
54
|
-
access_token: str | None = data.get("access_token")
|
|
55
|
-
# If refresh token was not requested, this would be None
|
|
56
|
-
refresh_token: str | None = data.get("refresh_token")
|
|
57
|
-
|
|
58
|
-
if access_token is None or (
|
|
59
|
-
get_refresh_token is True and refresh_token is None
|
|
60
|
-
):
|
|
61
|
-
raise ClassiqAuthenticationError(
|
|
62
|
-
"Token generation failed for unknown reason."
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
return Tokens(access_token=access_token, refresh_token=refresh_token)
|
|
66
|
-
|
|
67
|
-
@classmethod
|
|
68
51
|
async def _poll_tokens(
|
|
69
|
-
|
|
70
|
-
auth0_client: Auth0,
|
|
52
|
+
self,
|
|
71
53
|
device_code: str,
|
|
72
|
-
interval:
|
|
54
|
+
interval: float,
|
|
73
55
|
timeout: float,
|
|
74
|
-
get_refresh_token: bool = True,
|
|
75
56
|
) -> Tokens:
|
|
76
57
|
async def poller() -> dict[str, Any]:
|
|
77
58
|
nonlocal device_code
|
|
78
|
-
return await auth0_client.poll_tokens(device_code=device_code)
|
|
59
|
+
return await self.auth0_client.poll_tokens(device_code=device_code)
|
|
79
60
|
|
|
80
|
-
def interval_coro() -> Iterable[
|
|
61
|
+
def interval_coro() -> Iterable[float]:
|
|
81
62
|
nonlocal interval
|
|
82
63
|
while True:
|
|
83
64
|
yield interval
|
|
@@ -88,14 +69,14 @@ class DeviceRegistrar:
|
|
|
88
69
|
):
|
|
89
70
|
error_code: str | None = data.get("error")
|
|
90
71
|
if error_code is None:
|
|
91
|
-
return
|
|
72
|
+
return self.handle_ready_data(data)
|
|
92
73
|
elif error_code == "authorization_pending":
|
|
93
74
|
pass
|
|
94
75
|
elif error_code == "slow_down":
|
|
95
76
|
# This value is used by poll_for via interval_coro
|
|
96
77
|
interval *= 2
|
|
97
78
|
elif error_code == "expired_token":
|
|
98
|
-
raise ClassiqExpiredTokenError(
|
|
79
|
+
raise ClassiqExpiredTokenError(self._TIMEOUT_ERROR)
|
|
99
80
|
elif error_code == "access_denied":
|
|
100
81
|
error_description = data.get("error_description")
|
|
101
82
|
if error_description is None:
|
|
@@ -109,4 +90,4 @@ class DeviceRegistrar:
|
|
|
109
90
|
f"Device registration failed with an unknown error: {error_code}."
|
|
110
91
|
)
|
|
111
92
|
else:
|
|
112
|
-
raise ClassiqAuthenticationError(
|
|
93
|
+
raise ClassiqAuthenticationError(self._TIMEOUT_ERROR)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from classiq._internals.authentication.auth0 import Tokens
|
|
2
|
+
from classiq._internals.authentication.authorization_code import AuthorizationCodeFlow
|
|
3
|
+
from classiq._internals.authentication.authorization_flow import AuthorizationFlow
|
|
4
|
+
from classiq._internals.authentication.device import DeviceCodeFlow
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class HybridFlow(AuthorizationFlow):
|
|
8
|
+
def __init__(
|
|
9
|
+
self, require_refresh_token: bool = True, text_only: bool = False
|
|
10
|
+
) -> None:
|
|
11
|
+
super().__init__(require_refresh_token, text_only)
|
|
12
|
+
self.device_flow = DeviceCodeFlow(require_refresh_token, text_only)
|
|
13
|
+
self.auth_code_flow = AuthorizationCodeFlow(require_refresh_token, text_only)
|
|
14
|
+
|
|
15
|
+
async def get_tokens(self) -> Tokens:
|
|
16
|
+
device_data = await self.device_flow.get_device_data()
|
|
17
|
+
await self.auth_code_flow.authorize(device_data.verification_uri_complete)
|
|
18
|
+
print(f"Your user code: {device_data.user_code}") # noqa: T201
|
|
19
|
+
return await self.device_flow.poll_tokens(device_data)
|
|
@@ -10,8 +10,8 @@ from classiq.interface.exceptions import (
|
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
from classiq._internals.authentication import password_manager as pm
|
|
13
|
-
from classiq._internals.authentication.auth0 import Auth0
|
|
14
|
-
from classiq._internals.authentication.
|
|
13
|
+
from classiq._internals.authentication.auth0 import Auth0, Tokens
|
|
14
|
+
from classiq._internals.authentication.hybrid_flow import HybridFlow
|
|
15
15
|
from classiq._internals.config import Configuration
|
|
16
16
|
|
|
17
17
|
PASSWORD_MANAGERS: Sequence[type[pm.PasswordManager]] = [
|
|
@@ -126,7 +126,8 @@ class TokenManager:
|
|
|
126
126
|
async def _authentication_helper(self) -> None:
|
|
127
127
|
# TODO: consider using refresh token rotation
|
|
128
128
|
# (https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation)
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
authorization_flow = HybridFlow(
|
|
130
|
+
require_refresh_token=True, text_only=self._config.text_only
|
|
131
131
|
)
|
|
132
|
+
tokens = await authorization_flow.get_tokens()
|
|
132
133
|
self._save_tokens(tokens, force_override_refresh_token=True)
|
classiq/applications/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from classiq.applications import chemistry, combinatorial_optimization, qsp
|
|
1
|
+
from classiq.applications import chemistry, combinatorial_optimization, qsp
|
|
2
2
|
|
|
3
|
-
__all__ = ["chemistry", "combinatorial_optimization", "qsp"
|
|
3
|
+
__all__ = ["chemistry", "combinatorial_optimization", "qsp"]
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
_NON_IMPORTED_PUBLIC_SUBMODULES = ["qnn"]
|
|
@@ -20,8 +20,10 @@ from classiq.qmod import (
|
|
|
20
20
|
QCallable,
|
|
21
21
|
)
|
|
22
22
|
from classiq.qmod.builtins import Z, allocate, bind, within_apply
|
|
23
|
+
from classiq.qmod.builtins.functions.allocation import drop
|
|
23
24
|
from classiq.qmod.create_model_function import create_model
|
|
24
|
-
from classiq.qmod.qfunc import qfunc
|
|
25
|
+
from classiq.qmod.qfunc import qfunc, qperm
|
|
26
|
+
from classiq.qmod.qmod_variable import Const
|
|
25
27
|
from classiq.synthesis import synthesize
|
|
26
28
|
|
|
27
29
|
|
|
@@ -83,8 +85,8 @@ class IQAE:
|
|
|
83
85
|
def space_transform(est_reg: QArray) -> None:
|
|
84
86
|
state_prep_op(est_reg[0 : est_reg.len - 1], est_reg[est_reg.len - 1])
|
|
85
87
|
|
|
86
|
-
@
|
|
87
|
-
def oracle(est_reg: QArray) -> None:
|
|
88
|
+
@qperm
|
|
89
|
+
def oracle(est_reg: Const[QArray]) -> None:
|
|
88
90
|
Z(est_reg[est_reg.len - 1])
|
|
89
91
|
|
|
90
92
|
@qfunc
|
|
@@ -105,6 +107,7 @@ class IQAE:
|
|
|
105
107
|
est_reg,
|
|
106
108
|
),
|
|
107
109
|
)
|
|
110
|
+
drop(problem_vars)
|
|
108
111
|
|
|
109
112
|
if self._model is None:
|
|
110
113
|
self._model = create_model(
|
|
@@ -59,7 +59,7 @@ def _differentiate_tensor(
|
|
|
59
59
|
# The minus comes from the way pytorch defines diff
|
|
60
60
|
# it diffs the second object minus the first
|
|
61
61
|
# where we want the first minus the second
|
|
62
|
-
diff = -tensor.diff(axis=axis).squeeze(axis)
|
|
62
|
+
diff = -tensor.diff(axis=axis).squeeze(axis)
|
|
63
63
|
return diff / (2 * epsilon)
|
|
64
64
|
|
|
65
65
|
|
|
@@ -23,7 +23,7 @@ def get_shape_second_dimension(shape: torch.Size) -> int:
|
|
|
23
23
|
if len(shape) == 1:
|
|
24
24
|
return 1
|
|
25
25
|
elif len(shape) == 2:
|
|
26
|
-
return shape[1]
|
|
26
|
+
return shape[1] # type: ignore[index]
|
|
27
27
|
else:
|
|
28
28
|
raise ClassiqValueError("Invalid shape dimension - must be 1D or 2D")
|
|
29
29
|
|
|
@@ -33,7 +33,7 @@ def get_shape_first_dimension(shape: torch.Size) -> int:
|
|
|
33
33
|
raise ClassiqValueError("Invalid shape type - must have `__len__`")
|
|
34
34
|
|
|
35
35
|
if len(shape) in (1, 2):
|
|
36
|
-
return shape[0]
|
|
36
|
+
return shape[0] # type: ignore[index]
|
|
37
37
|
else:
|
|
38
38
|
raise ClassiqValueError("Invalid shape dimension - must be 1D or 2D")
|
|
39
39
|
|
classiq/applications/qsp/qsp.py
CHANGED
|
@@ -50,7 +50,7 @@ def qsvt_phases(
|
|
|
50
50
|
) -> np.ndarray:
|
|
51
51
|
r"""
|
|
52
52
|
Get QSVT phases that will generate the given Chebyshev polynomial.
|
|
53
|
-
The phases are ready to be used in `qsvt` and `qsvt_lcu` functions in the classiq library. The
|
|
53
|
+
The phases are ready to be used in `qsvt` and `qsvt_lcu` functions in the classiq library. The convention
|
|
54
54
|
is the reflection signal operator, and the measurement basis is the hadamard basis (see https://arxiv.org/abs/2105.02859
|
|
55
55
|
APPENDIX A.).
|
|
56
56
|
The current implementation is using the pyqsp package, based on techniques in https://arxiv.org/abs/2003.02831.
|
|
@@ -118,7 +118,7 @@ def qsvt_phases(
|
|
|
118
118
|
|
|
119
119
|
def _plot_qsp_approx(
|
|
120
120
|
poly_cheb: np.ndarray,
|
|
121
|
-
f_target: Callable[[
|
|
121
|
+
f_target: Callable[[float], complex],
|
|
122
122
|
interval: tuple[float, float] = (-1, 1),
|
|
123
123
|
) -> None:
|
|
124
124
|
from matplotlib import pyplot as plt
|
|
@@ -126,7 +126,7 @@ def _plot_qsp_approx(
|
|
|
126
126
|
grid_full = np.linspace(-1, 1, 3000)
|
|
127
127
|
grid_interval = np.linspace(interval[0], interval[1], 3000)
|
|
128
128
|
|
|
129
|
-
y_target = f_target(grid_interval)
|
|
129
|
+
y_target = np.vectorize(f_target, otypes=[float])(grid_interval)
|
|
130
130
|
y_approx = np.polynomial.Chebyshev(poly_cheb)(grid_full)
|
|
131
131
|
|
|
132
132
|
# Plot
|
|
@@ -153,7 +153,7 @@ def _plot_qsp_approx(
|
|
|
153
153
|
|
|
154
154
|
|
|
155
155
|
def qsp_approximate(
|
|
156
|
-
f_target: Callable[[
|
|
156
|
+
f_target: Callable[[float], complex],
|
|
157
157
|
degree: int,
|
|
158
158
|
parity: int | None = None,
|
|
159
159
|
interval: tuple[float, float] = (-1, 1),
|
|
@@ -193,7 +193,8 @@ def qsp_approximate(
|
|
|
193
193
|
# Select grid points for the objective in [w_min, w_max]
|
|
194
194
|
xj_obj = xj_full[(xj_full >= interval[0]) & (xj_full <= interval[1])]
|
|
195
195
|
|
|
196
|
-
yj_obj = f_target(xj_obj)
|
|
196
|
+
yj_obj = np.vectorize(f_target, otypes=[float])(xj_obj)
|
|
197
|
+
|
|
197
198
|
# heuristic verification
|
|
198
199
|
bound = min(1, bound)
|
|
199
200
|
assert (
|
|
@@ -7,6 +7,7 @@ import sympy
|
|
|
7
7
|
from classiq.interface.exceptions import (
|
|
8
8
|
ClassiqExpansionError,
|
|
9
9
|
ClassiqInternalExpansionError,
|
|
10
|
+
ClassiqValueError,
|
|
10
11
|
)
|
|
11
12
|
from classiq.interface.generator.functions.classical_function_declaration import (
|
|
12
13
|
ClassicalFunctionDeclaration,
|
|
@@ -208,6 +209,15 @@ def try_eval_sympy_function(
|
|
|
208
209
|
|
|
209
210
|
def try_eval_builtin_function(
|
|
210
211
|
expr_val: QmodAnnotatedExpression, node: ast.Call, func_name: str
|
|
212
|
+
) -> bool:
|
|
213
|
+
try:
|
|
214
|
+
return _try_eval_builtin_function(expr_val, node, func_name)
|
|
215
|
+
except ValueError as e:
|
|
216
|
+
raise ClassiqValueError(str(e)) from e
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _try_eval_builtin_function(
|
|
220
|
+
expr_val: QmodAnnotatedExpression, node: ast.Call, func_name: str
|
|
211
221
|
) -> bool:
|
|
212
222
|
args_are_int = all(isinstance(expr_val.get_type(arg), Integer) for arg in node.args)
|
|
213
223
|
args_are_real = all(
|
classiq/execution/__init__.py
CHANGED
|
@@ -8,7 +8,6 @@ from ..interface.executor.execution_preferences import __all__ as _ep_all
|
|
|
8
8
|
from ..interface.executor.result import ExecutionDetails
|
|
9
9
|
from ..interface.executor.vqe_result import VQESolverResult
|
|
10
10
|
from .execution_session import ExecutionSession
|
|
11
|
-
from .iqcc import generate_iqcc_token, generate_iqcc_token_async
|
|
12
11
|
from .jobs import ExecutionJob, get_execution_jobs, get_execution_jobs_async
|
|
13
12
|
from .qnn import execute_qnn
|
|
14
13
|
from .user_budgets import (
|
|
@@ -33,8 +32,6 @@ __all__ = (
|
|
|
33
32
|
"get_execution_jobs_async",
|
|
34
33
|
"ExecutionSession",
|
|
35
34
|
"execute_qnn",
|
|
36
|
-
"generate_iqcc_token",
|
|
37
|
-
"generate_iqcc_token_async",
|
|
38
35
|
"get_budget",
|
|
39
36
|
"get_budget_async",
|
|
40
37
|
"set_budget_limit",
|
classiq/interface/_version.py
CHANGED
|
@@ -172,10 +172,11 @@ class AwsBackendPreferences(BackendPreferences):
|
|
|
172
172
|
backend_service_provider (ProviderTypeVendor.AMAZON_BRAKET):
|
|
173
173
|
The service provider for the backend, which is Amazon Braket.
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
The
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
aws_access_key_id (str):
|
|
176
|
+
The access key id of AWS user with full braket access
|
|
177
|
+
|
|
178
|
+
aws_secret_access_key (str):
|
|
179
|
+
The secret key assigned to the access key id for the user with full braket access.
|
|
179
180
|
|
|
180
181
|
s3_bucket_name (str):
|
|
181
182
|
The name of the S3 bucket where results and other related data will be stored.
|
|
@@ -193,9 +194,13 @@ class AwsBackendPreferences(BackendPreferences):
|
|
|
193
194
|
backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET = pydantic.Field(
|
|
194
195
|
default=ProviderVendor.AMAZON_BRAKET
|
|
195
196
|
)
|
|
196
|
-
|
|
197
|
+
aws_access_key_id: str | None = pydantic.Field(
|
|
198
|
+
default=None,
|
|
199
|
+
description="Key id assigned to user with credentials to access Braket service",
|
|
200
|
+
)
|
|
201
|
+
aws_secret_access_key: str | None = pydantic.Field(
|
|
197
202
|
default=None,
|
|
198
|
-
description="
|
|
203
|
+
description="Secret access key assigned to user with credentials to access Braket service",
|
|
199
204
|
)
|
|
200
205
|
s3_bucket_name: str | None = pydantic.Field(
|
|
201
206
|
default=None, description="S3 Bucket Name"
|
|
@@ -428,33 +433,6 @@ class AQTBackendPreferences(BackendPreferences):
|
|
|
428
433
|
workspace: str = pydantic.Field(description="AQT workspace")
|
|
429
434
|
|
|
430
435
|
|
|
431
|
-
class IQCCBackendPreferences(BackendPreferences):
|
|
432
|
-
"""
|
|
433
|
-
NOTE: This is a work in progress and is subject to change.
|
|
434
|
-
|
|
435
|
-
Represents the backend preferences specific to IQCC (Israeli Quantum Computing
|
|
436
|
-
Center).
|
|
437
|
-
|
|
438
|
-
Attributes:
|
|
439
|
-
auth_token: The authorization token generated by calling `generate_iqcc_token`.
|
|
440
|
-
target_id: The target ID of the login node.
|
|
441
|
-
target_scope_id: The scope ID of the specified target.
|
|
442
|
-
ssh_user_name: The user name to use when connecting to the SSH server on the login node.
|
|
443
|
-
ssh_key: The private key to use when connecting to the SSH server on the login node.
|
|
444
|
-
slurm_account: The account to use when initiating SLURM jobs.
|
|
445
|
-
"""
|
|
446
|
-
|
|
447
|
-
backend_service_provider: ProviderTypeVendor.IQCC = pydantic.Field(
|
|
448
|
-
default=ProviderVendor.IQCC
|
|
449
|
-
)
|
|
450
|
-
auth_token: str
|
|
451
|
-
target_id: str
|
|
452
|
-
target_scope_id: str
|
|
453
|
-
ssh_user_name: str
|
|
454
|
-
ssh_key: str
|
|
455
|
-
slurm_account: str
|
|
456
|
-
|
|
457
|
-
|
|
458
436
|
class CINECABackendPreferences(BackendPreferences):
|
|
459
437
|
"""
|
|
460
438
|
Represents the backend preferences specific to CINECA.
|
|
@@ -507,7 +485,6 @@ BackendPreferencesTypes = Union[
|
|
|
507
485
|
OQCBackendPreferences,
|
|
508
486
|
IntelBackendPreferences,
|
|
509
487
|
AQTBackendPreferences,
|
|
510
|
-
IQCCBackendPreferences,
|
|
511
488
|
CINECABackendPreferences,
|
|
512
489
|
]
|
|
513
490
|
|
|
@@ -525,7 +502,6 @@ __all__ = [
|
|
|
525
502
|
"ClassiqSimulatorBackendNames",
|
|
526
503
|
"GCPBackendPreferences",
|
|
527
504
|
"IBMBackendPreferences",
|
|
528
|
-
"IQCCBackendPreferences",
|
|
529
505
|
"IntelBackendNames",
|
|
530
506
|
"IntelBackendPreferences",
|
|
531
507
|
"IonqBackendNames",
|