luna-quantum 0.0.29__py3-none-any.whl → 0.0.37__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 luna-quantum might be problematic. Click here for more details.
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/METADATA +1 -1
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/RECORD +35 -33
- luna_sdk/controllers/luna_http_client.py +27 -0
- luna_sdk/controllers/luna_platform_client.py +34 -16
- luna_sdk/controllers/luna_q.py +5 -7
- luna_sdk/controllers/luna_solve.py +9 -7
- luna_sdk/controllers/luna_transform.py +13 -7
- luna_sdk/error/http_error_utils.py +10 -3
- luna_sdk/exceptions/encryption_exception.py +0 -6
- luna_sdk/interfaces/circuit_repo_i.py +0 -6
- luna_sdk/interfaces/optimization_repo_i.py +5 -4
- luna_sdk/interfaces/qpu_token_repo_i.py +18 -18
- luna_sdk/interfaces/solutions_repo_i.py +0 -6
- luna_sdk/repositories/circuit_repo.py +0 -11
- luna_sdk/repositories/optimization_repo.py +11 -10
- luna_sdk/repositories/qpu_token_repo.py +36 -27
- luna_sdk/repositories/solutions_repo.py +0 -8
- luna_sdk/schemas/create/circuit.py +0 -3
- luna_sdk/schemas/create/qpu_token.py +0 -3
- luna_sdk/schemas/create/solution.py +0 -1
- luna_sdk/schemas/enums/optimization.py +8 -7
- luna_sdk/schemas/enums/qpu_token_type.py +1 -1
- luna_sdk/schemas/optimization.py +53 -15
- luna_sdk/schemas/optimization_formats/qubo.py +8 -0
- luna_sdk/schemas/qpu_token.py +1 -5
- luna_sdk/schemas/rest/qpu_token/qpu_token_source.py +18 -0
- luna_sdk/schemas/rest/qpu_token/token_provider.py +47 -15
- luna_sdk/schemas/solution.py +89 -35
- luna_sdk/schemas/solver_parameters/dwave/base.py +4 -1
- luna_sdk/schemas/solver_parameters/dwave/quantum_annealing.py +13 -0
- luna_sdk/schemas/solver_parameters/dwave/repeated_reverse_quantum_annealing.py +13 -1
- luna_sdk/schemas/solver_parameters/dwave/tabu_search.py +2 -4
- luna_sdk/utils/qpu_tokens.py +14 -13
- luna_sdk/controllers/custom_login_client.py +0 -66
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/LICENSE +0 -0
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/WHEEL +0 -0
luna_sdk/schemas/solution.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
from typing import Any, Dict, List, Optional, Union
|
|
2
3
|
|
|
3
4
|
from pydantic import BaseModel
|
|
4
5
|
|
|
6
|
+
from luna_sdk.schemas.enums.optimization import OptFormat
|
|
5
7
|
from luna_sdk.schemas.enums.solution import SenseEnum
|
|
6
8
|
from luna_sdk.schemas.enums.status import StatusEnum
|
|
7
9
|
from luna_sdk.schemas.optimization import Optimization
|
|
@@ -105,45 +107,17 @@ class Solution(PrettyBase):
|
|
|
105
107
|
solver: str
|
|
106
108
|
provider: str
|
|
107
109
|
status: StatusEnum
|
|
110
|
+
status_timeline: Dict[StatusEnum, datetime] = {}
|
|
111
|
+
used_format: Optional[OptFormat] = None
|
|
108
112
|
optimization: Union[Optimization, str]
|
|
109
113
|
representation: Optional[Any] = None
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
"""Overwrite the default object string representation to use the custom pretty print console representation"""
|
|
113
|
-
data = self.model_dump()
|
|
114
|
-
results = data.pop("results") # Extract and remove results from data
|
|
115
|
-
metadata = data.pop("metadata") # Extract and remove metadata from data
|
|
116
|
-
provider = data["provider"]
|
|
115
|
+
verbose: bool = False
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
output += self._pretty_print(data)
|
|
123
|
-
|
|
124
|
-
# Build Results section
|
|
125
|
-
if results:
|
|
126
|
-
output += f"\n\n{divider}RESULTS:\n{divider}"
|
|
127
|
-
for i, result in enumerate(results, start=1):
|
|
128
|
-
r = f"Result {i}:\n"
|
|
129
|
-
r += f" {result}\n"
|
|
130
|
-
output += r
|
|
131
|
-
else:
|
|
132
|
-
output += f"\n\n{divider}RESULTS:\n{divider}"
|
|
133
|
-
output += " No results..\n"
|
|
134
|
-
output += " Solution has status: " + str(self.status.value) + "\n"
|
|
135
|
-
if self.error_message:
|
|
136
|
-
output += " Error message: " + str(self.error_message) + "\n"
|
|
137
|
-
|
|
138
|
-
# Build Provider Meta Data section
|
|
139
|
-
output += f"\n\n{divider}{provider.upper()} META DATA:\n{divider}"
|
|
140
|
-
output += (
|
|
141
|
-
self._pretty_print(metadata)
|
|
142
|
-
if metadata
|
|
143
|
-
else " No metadata from provider..\n"
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
return output
|
|
117
|
+
def __str__(self):
|
|
118
|
+
if self.verbose:
|
|
119
|
+
return self.details()
|
|
120
|
+
return self.subset()
|
|
147
121
|
|
|
148
122
|
@property
|
|
149
123
|
def head(self):
|
|
@@ -216,6 +190,86 @@ class Solution(PrettyBase):
|
|
|
216
190
|
|
|
217
191
|
return output
|
|
218
192
|
|
|
193
|
+
def details(self):
|
|
194
|
+
"""Overwrite the default object string representation to use the custom pretty print console representation"""
|
|
195
|
+
data = self.model_dump()
|
|
196
|
+
results = data.pop("results") # Extract and remove results from data
|
|
197
|
+
metadata = data.pop("metadata") # Extract and remove metadata from data
|
|
198
|
+
provider = data["provider"]
|
|
199
|
+
|
|
200
|
+
divider = "--------------------------------------------------------------------------------\n"
|
|
201
|
+
|
|
202
|
+
# Build Meta Data section
|
|
203
|
+
output = f"{divider}META DATA:\n{divider}"
|
|
204
|
+
output += self._pretty_print(data)
|
|
205
|
+
|
|
206
|
+
# Build Results section
|
|
207
|
+
if results:
|
|
208
|
+
output += f"\n\n{divider}RESULTS:\n{divider}"
|
|
209
|
+
for i, result in enumerate(results, start=1):
|
|
210
|
+
r = f"Result {i}:\n"
|
|
211
|
+
r += f" {result}\n"
|
|
212
|
+
output += r
|
|
213
|
+
else:
|
|
214
|
+
output += f"\n\n{divider}RESULTS:\n{divider}"
|
|
215
|
+
output += " No results..\n"
|
|
216
|
+
output += " Solution has status: " + str(self.status.value) + "\n"
|
|
217
|
+
if self.error_message:
|
|
218
|
+
output += " Error message: " + str(self.error_message) + "\n"
|
|
219
|
+
|
|
220
|
+
# Build Provider Meta Data section
|
|
221
|
+
output += f"\n\n{divider}{provider.upper()} META DATA:\n{divider}"
|
|
222
|
+
output += (
|
|
223
|
+
self._pretty_print(metadata)
|
|
224
|
+
if metadata
|
|
225
|
+
else " No metadata from provider..\n"
|
|
226
|
+
)
|
|
227
|
+
return output
|
|
228
|
+
|
|
229
|
+
def subset(self):
|
|
230
|
+
limit = 5
|
|
231
|
+
subset_keys = [
|
|
232
|
+
"id",
|
|
233
|
+
"name",
|
|
234
|
+
"status",
|
|
235
|
+
"solver",
|
|
236
|
+
"provider",
|
|
237
|
+
"runtime",
|
|
238
|
+
"optimization_name",
|
|
239
|
+
"created_date",
|
|
240
|
+
]
|
|
241
|
+
data = self.model_dump()
|
|
242
|
+
data["optimization_name"] = data["optimization"]["original_format"]
|
|
243
|
+
output = ""
|
|
244
|
+
data_subset = {key: data.get(key) for key in subset_keys if key in data}
|
|
245
|
+
output += self._pretty_print(data_subset)
|
|
246
|
+
|
|
247
|
+
# Build Results section
|
|
248
|
+
results = data.pop("results")
|
|
249
|
+
if results:
|
|
250
|
+
output += "results:\n"
|
|
251
|
+
output += (
|
|
252
|
+
f"{len(results)} results found. Displaying first {limit} results.\n"
|
|
253
|
+
)
|
|
254
|
+
for i, result in enumerate(results, start=1):
|
|
255
|
+
if i > limit:
|
|
256
|
+
output += "....\n"
|
|
257
|
+
break
|
|
258
|
+
r = f"Result {i}:\n"
|
|
259
|
+
r += (
|
|
260
|
+
f" {str(result)[:150]} ....\n"
|
|
261
|
+
if len(str(result)) > 150
|
|
262
|
+
else f" {result}\n"
|
|
263
|
+
)
|
|
264
|
+
output += r
|
|
265
|
+
else:
|
|
266
|
+
output += "results:\n"
|
|
267
|
+
output += " No results..\n"
|
|
268
|
+
output += " Solution has status: " + str(self.status.value) + "\n"
|
|
269
|
+
if self.error_message:
|
|
270
|
+
output += " Error message: " + str(self.error_message) + "\n"
|
|
271
|
+
return output
|
|
272
|
+
|
|
219
273
|
|
|
220
274
|
class UseCaseResult(BaseModel):
|
|
221
275
|
representation: Any
|
|
@@ -376,6 +376,8 @@ class Loop(BaseParameter):
|
|
|
376
376
|
Energy level that the algorithm tries to reach.
|
|
377
377
|
rtol: float
|
|
378
378
|
Relative tolerance for convergence.
|
|
379
|
+
rtol: float
|
|
380
|
+
Relative tolerance for convergence.
|
|
379
381
|
atol: float
|
|
380
382
|
Absolute tolerance for convergence.
|
|
381
383
|
"""
|
|
@@ -383,7 +385,8 @@ class Loop(BaseParameter):
|
|
|
383
385
|
max_iter: Optional[int] = 100
|
|
384
386
|
max_time: int = 5
|
|
385
387
|
convergence: int = 3
|
|
386
|
-
target: Optional[float] =
|
|
388
|
+
target: Optional[float] = None
|
|
389
|
+
rtol: float = DEFAULT_RTOL
|
|
387
390
|
atol: float = DEFAULT_ATOL
|
|
388
391
|
|
|
389
392
|
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
from luna_sdk.schemas.solver_parameters.base_parameter import BaseParameter
|
|
2
2
|
from luna_sdk.schemas.solver_parameters.dwave import Embedding, SamplingParams
|
|
3
|
+
from pydantic import StringConstraints
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
if sys.version_info >= (3, 9):
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
else:
|
|
10
|
+
from typing_extensions import Annotated
|
|
3
11
|
|
|
4
12
|
|
|
5
13
|
class QuantumAnnealingParameters(BaseParameter):
|
|
@@ -13,7 +21,12 @@ class QuantumAnnealingParameters(BaseParameter):
|
|
|
13
21
|
sampling_params: SamplingParams
|
|
14
22
|
Parameters for the sampling. See https://docs.dwavesys.com/docs/latest/c_solver_parameters.html
|
|
15
23
|
for more details.
|
|
24
|
+
qpu_backend: str
|
|
25
|
+
Specific D-Wave quantum processing unit (QPU) for your optimization
|
|
16
26
|
"""
|
|
17
27
|
|
|
18
28
|
embedding: Embedding = Embedding()
|
|
19
29
|
sampling_params: SamplingParams = SamplingParams()
|
|
30
|
+
qpu_backend: Annotated[
|
|
31
|
+
str, StringConstraints(strip_whitespace=True, min_length=1)
|
|
32
|
+
] = "default"
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
from typing import Any, Dict, List, Optional
|
|
2
2
|
|
|
3
|
-
from pydantic import
|
|
3
|
+
from pydantic import Field, StringConstraints
|
|
4
4
|
|
|
5
5
|
from luna_sdk.schemas.solver_parameters.base_parameter import BaseParameter
|
|
6
6
|
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
if sys.version_info >= (3, 9):
|
|
10
|
+
from typing import Annotated
|
|
11
|
+
else:
|
|
12
|
+
from typing_extensions import Annotated
|
|
13
|
+
|
|
7
14
|
|
|
8
15
|
class RRQuantumAnnealingSamplingParams(BaseParameter):
|
|
9
16
|
"""
|
|
@@ -69,6 +76,8 @@ class RepeatedReverseQuantumAnnealingParameters(BaseParameter):
|
|
|
69
76
|
The target energy for the solving process.
|
|
70
77
|
check_trivial: bool
|
|
71
78
|
Whether to check for trivial variables. Checking for trivial variables means an overhead. On the other hand, when set to `False`, trivial variables, i.e., variables without interactions, will lead to a runtime error.
|
|
79
|
+
qpu_backend: str
|
|
80
|
+
Specific D-Wave quantum processing unit (QPU) for your optimization
|
|
72
81
|
"""
|
|
73
82
|
|
|
74
83
|
sampling_params: RRQuantumAnnealingSamplingParams = (
|
|
@@ -82,3 +91,6 @@ class RepeatedReverseQuantumAnnealingParameters(BaseParameter):
|
|
|
82
91
|
max_iter: int = 10
|
|
83
92
|
target: Optional[Any] = None
|
|
84
93
|
check_trivial: bool = True
|
|
94
|
+
qpu_backend: Annotated[
|
|
95
|
+
str, StringConstraints(strip_whitespace=True, min_length=1)
|
|
96
|
+
] = "default"
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
from typing import Any, Optional
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from .base import Tabu
|
|
4
4
|
|
|
5
|
-
from luna_sdk.schemas.solver_parameters.base_parameter import BaseParameter
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
class TabuSearchParameters(BaseParameter):
|
|
6
|
+
class TabuSearchParameters(Tabu):
|
|
9
7
|
"""
|
|
10
8
|
Tabu Search is a heuristic optimization method that works with the help of a tabu list.
|
|
11
9
|
Initially, random states are chosen in the solution landscape.
|
luna_sdk/utils/qpu_tokens.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
|
-
from luna_sdk.schemas import
|
|
3
|
+
from luna_sdk.schemas.rest.qpu_token.qpu_token_source import _RESTQpuTokenSource
|
|
4
4
|
from luna_sdk.schemas.rest.qpu_token.token_provider import (
|
|
5
5
|
RestAPITokenProvider,
|
|
6
6
|
AWSQpuTokens,
|
|
7
|
+
_RestQpuToken,
|
|
7
8
|
)
|
|
8
9
|
|
|
9
10
|
|
|
@@ -15,37 +16,37 @@ def extract_qpu_tokens_from_env() -> RestAPITokenProvider:
|
|
|
15
16
|
aws_access_key = os.environ.get("LUNA_AWS_ACCESS_KEY")
|
|
16
17
|
aws_access_secret_key = os.environ.get("LUNA_AWS_SECRET_ACCESS_KEY")
|
|
17
18
|
return RestAPITokenProvider(
|
|
18
|
-
ibm=
|
|
19
|
-
source=
|
|
19
|
+
ibm=_RestQpuToken(
|
|
20
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
20
21
|
token=ibm_token,
|
|
21
22
|
)
|
|
22
23
|
if ibm_token
|
|
23
24
|
else None,
|
|
24
|
-
dwave=
|
|
25
|
-
source=
|
|
25
|
+
dwave=_RestQpuToken(
|
|
26
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
26
27
|
token=dwave_token,
|
|
27
28
|
)
|
|
28
29
|
if dwave_token
|
|
29
30
|
else None,
|
|
30
|
-
qctrl=
|
|
31
|
-
source=
|
|
31
|
+
qctrl=_RestQpuToken(
|
|
32
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
32
33
|
token=qctrl_token,
|
|
33
34
|
)
|
|
34
35
|
if qctrl_token
|
|
35
36
|
else None,
|
|
36
|
-
fujitsu=
|
|
37
|
-
source=
|
|
37
|
+
fujitsu=_RestQpuToken(
|
|
38
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
38
39
|
token=fujitsu_token,
|
|
39
40
|
)
|
|
40
41
|
if fujitsu_token
|
|
41
42
|
else None,
|
|
42
43
|
aws=AWSQpuTokens(
|
|
43
|
-
aws_access_key=
|
|
44
|
-
source=
|
|
44
|
+
aws_access_key=_RestQpuToken(
|
|
45
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
45
46
|
token=aws_access_key,
|
|
46
47
|
),
|
|
47
|
-
aws_secret_access_key=
|
|
48
|
-
source=
|
|
48
|
+
aws_secret_access_key=_RestQpuToken(
|
|
49
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
49
50
|
token=aws_access_secret_key,
|
|
50
51
|
),
|
|
51
52
|
),
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from http.client import UNAUTHORIZED
|
|
3
|
-
from importlib.metadata import version
|
|
4
|
-
|
|
5
|
-
from httpx import Client, ReadTimeout, Response
|
|
6
|
-
|
|
7
|
-
from luna_sdk.error.http_error_utils import HttpErrorUtils
|
|
8
|
-
from luna_sdk.exceptions.timeout_exception import TimeoutException
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class CustomLoginClient(Client):
|
|
12
|
-
_login_url: str
|
|
13
|
-
_email: str
|
|
14
|
-
_password: str
|
|
15
|
-
_bearer_token: str
|
|
16
|
-
|
|
17
|
-
_version: str = version("luna-quantum")
|
|
18
|
-
|
|
19
|
-
_user_agent: str = f"LunaSDK/{_version}"
|
|
20
|
-
|
|
21
|
-
def __init__(self, email: str, password: str, login_url: str, *args, **kwargs):
|
|
22
|
-
super().__init__(*args, **kwargs)
|
|
23
|
-
self._email = email
|
|
24
|
-
self._password = password
|
|
25
|
-
self._login_url = login_url
|
|
26
|
-
|
|
27
|
-
self.headers["User-Agent"] = self._user_agent
|
|
28
|
-
|
|
29
|
-
def login(self, email: str, password: str):
|
|
30
|
-
with Client() as client:
|
|
31
|
-
headers = {
|
|
32
|
-
"accept": "application/json",
|
|
33
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
34
|
-
"User-Agent": self._user_agent,
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
response: Response = client.post(
|
|
38
|
-
self._login_url,
|
|
39
|
-
data={"username": email, "password": password},
|
|
40
|
-
headers=headers,
|
|
41
|
-
# Ensure timeout is high enough. CustomLoginClient will be deleted in
|
|
42
|
-
# near future anyway.
|
|
43
|
-
timeout=None,
|
|
44
|
-
)
|
|
45
|
-
HttpErrorUtils.check_for_error(response)
|
|
46
|
-
|
|
47
|
-
self._bearer_token = response.json()["access_token"]
|
|
48
|
-
|
|
49
|
-
def request(self, *args, **kwargs) -> Response:
|
|
50
|
-
try:
|
|
51
|
-
response: Response = super().request(*args, **kwargs)
|
|
52
|
-
if response.status_code == UNAUTHORIZED:
|
|
53
|
-
logging.info("Unauthorized - trying to login")
|
|
54
|
-
|
|
55
|
-
self.login(self._email, self._password)
|
|
56
|
-
|
|
57
|
-
logging.info("Re-login successful")
|
|
58
|
-
self.headers.update(
|
|
59
|
-
headers={"authorization": f"Bearer {self._bearer_token}"}
|
|
60
|
-
)
|
|
61
|
-
logging.info("Trying request again")
|
|
62
|
-
response = super().request(*args, **kwargs)
|
|
63
|
-
except ReadTimeout:
|
|
64
|
-
raise TimeoutException()
|
|
65
|
-
HttpErrorUtils.check_for_error(response)
|
|
66
|
-
return response
|
|
File without changes
|
|
File without changes
|