luna-quantum 0.0.16__py3-none-any.whl → 0.0.33__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.16.dist-info → luna_quantum-0.0.33.dist-info}/METADATA +2 -1
- {luna_quantum-0.0.16.dist-info → luna_quantum-0.0.33.dist-info}/RECORD +64 -58
- luna_sdk/controllers/luna_http_client.py +27 -0
- luna_sdk/controllers/luna_platform_client.py +41 -23
- luna_sdk/controllers/luna_q.py +11 -16
- luna_sdk/controllers/luna_solve.py +12 -17
- luna_sdk/controllers/luna_transform.py +14 -15
- luna_sdk/error/http_error_utils.py +10 -3
- luna_sdk/interfaces/circuit_repo_i.py +18 -12
- luna_sdk/interfaces/cplex_repo_i.py +25 -10
- luna_sdk/interfaces/info_repo_i.py +10 -3
- luna_sdk/interfaces/lp_repo_i.py +20 -8
- luna_sdk/interfaces/optimization_repo_i.py +35 -60
- luna_sdk/interfaces/qpu_token_repo_i.py +40 -38
- luna_sdk/interfaces/solutions_repo_i.py +44 -24
- luna_sdk/repositories/circuit_repo.py +11 -44
- luna_sdk/repositories/cplex_repo.py +32 -20
- luna_sdk/repositories/info_repo.py +4 -7
- luna_sdk/repositories/lp_repo.py +21 -15
- luna_sdk/repositories/optimization_repo.py +36 -210
- luna_sdk/repositories/qpu_token_repo.py +52 -128
- luna_sdk/repositories/solutions_repo.py +109 -181
- luna_sdk/schemas/create/solution.py +2 -2
- luna_sdk/schemas/enums/optimization.py +8 -7
- luna_sdk/schemas/enums/qpu_token_type.py +1 -1
- luna_sdk/schemas/optimization.py +15 -24
- luna_sdk/schemas/optimization_formats/qubo.py +8 -0
- luna_sdk/schemas/pretty_base.py +10 -3
- luna_sdk/schemas/qpu_token.py +4 -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 +7 -6
- luna_sdk/schemas/solver_info.py +31 -1
- luna_sdk/schemas/solver_parameters/aws/optimizer_params.py +40 -0
- luna_sdk/schemas/solver_parameters/aws/qaoa.py +36 -4
- luna_sdk/schemas/solver_parameters/base_parameter.py +5 -0
- luna_sdk/schemas/solver_parameters/dwave/base.py +15 -14
- luna_sdk/schemas/solver_parameters/dwave/dialectic_search.py +3 -2
- luna_sdk/schemas/solver_parameters/dwave/kerberos.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/leap_hybrid_bqm.py +2 -2
- luna_sdk/schemas/solver_parameters/dwave/leap_hybrid_cqm.py +2 -2
- luna_sdk/schemas/solver_parameters/dwave/parallel_tempering.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/parallel_tempering_qpu.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/population_annealing.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/population_annealing_qpu.py +2 -1
- luna_sdk/schemas/solver_parameters/dwave/qaga.py +4 -2
- luna_sdk/schemas/solver_parameters/dwave/qbsolv_like_qpu.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/qbsolv_like_simulated_annealing.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/qbsolv_like_tabu_search.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/quantum_annealing.py +2 -3
- luna_sdk/schemas/solver_parameters/dwave/repeated_reverse_quantum_annealing.py +4 -2
- luna_sdk/schemas/solver_parameters/dwave/repeated_reverse_simulated_annealing.py +3 -2
- luna_sdk/schemas/solver_parameters/dwave/saga.py +1 -1
- luna_sdk/schemas/solver_parameters/dwave/tabu_search.py +3 -1
- luna_sdk/schemas/solver_parameters/fujitsu/base.py +5 -4
- luna_sdk/schemas/solver_parameters/fujitsu/partial_config.py +7 -5
- luna_sdk/schemas/solver_parameters/ibm/standard_parameters.py +121 -7
- luna_sdk/schemas/solver_parameters/qctrl/qaoa.py +2 -2
- luna_sdk/schemas/wrappers/__init__.py +1 -0
- luna_sdk/schemas/wrappers/datetime_wrapper.py +31 -0
- luna_sdk/utils/parameter_finder.py +90 -0
- luna_sdk/utils/qpu_tokens.py +14 -13
- luna_sdk/constants.py +0 -1
- luna_sdk/controllers/custom_login_client.py +0 -61
- {luna_quantum-0.0.16.dist-info → luna_quantum-0.0.33.dist-info}/LICENSE +0 -0
- {luna_quantum-0.0.16.dist-info → luna_quantum-0.0.33.dist-info}/WHEEL +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
from time import sleep
|
|
4
|
-
from typing import Dict, List, Optional, Union
|
|
4
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
5
5
|
|
|
6
|
-
from pydantic import BaseModel
|
|
6
|
+
from pydantic import BaseModel, ValidationError
|
|
7
7
|
|
|
8
8
|
from luna_sdk.exceptions.encryption_exception import EncryptionNotSetException
|
|
9
9
|
from luna_sdk.interfaces.solutions_repo_i import ISolutionsRepo
|
|
@@ -19,32 +19,15 @@ from luna_sdk.schemas.solution import (
|
|
|
19
19
|
UseCaseRepresentation,
|
|
20
20
|
UseCaseResult,
|
|
21
21
|
)
|
|
22
|
+
from luna_sdk.utils.parameter_finder import get_parameter_by_solver
|
|
22
23
|
from luna_sdk.utils.qpu_tokens import extract_qpu_tokens_from_env
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class SolutionsRepo(ISolutionsRepo):
|
|
26
27
|
_endpoint = "/solutions"
|
|
27
28
|
|
|
28
|
-
def get(
|
|
29
|
-
self,
|
|
30
|
-
solution_id: str,
|
|
31
|
-
) -> Solution:
|
|
32
|
-
"""
|
|
33
|
-
Retrieve one solution by id.
|
|
34
|
-
|
|
35
|
-
Parameters
|
|
36
|
-
----------
|
|
37
|
-
solution_id: str
|
|
38
|
-
Id of the solution that should be retrieved
|
|
39
|
-
|
|
40
|
-
Returns
|
|
41
|
-
-------
|
|
42
|
-
Solution
|
|
43
|
-
Solution instance
|
|
44
|
-
"""
|
|
45
|
-
response = self._client.get(
|
|
46
|
-
f"{self._endpoint}/{solution_id}",
|
|
47
|
-
)
|
|
29
|
+
def get(self, solution_id: str, **kwargs) -> Solution:
|
|
30
|
+
response = self._client.get(f"{self._endpoint}/{solution_id}", **kwargs)
|
|
48
31
|
|
|
49
32
|
response.raise_for_status()
|
|
50
33
|
|
|
@@ -56,26 +39,8 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
56
39
|
limit: int = 50,
|
|
57
40
|
offset: int = 0,
|
|
58
41
|
optimization_id: Optional[str] = None,
|
|
42
|
+
**kwargs,
|
|
59
43
|
) -> List[Solution]:
|
|
60
|
-
"""
|
|
61
|
-
Get list of available optimizations.
|
|
62
|
-
|
|
63
|
-
Parameters
|
|
64
|
-
----------
|
|
65
|
-
timeframe: Optional[TimeframeEnum]
|
|
66
|
-
Only return Solutions created within a specified timeframe. Default None.
|
|
67
|
-
limit:
|
|
68
|
-
Limit the number of Optimizations to be returned. Default value 10.
|
|
69
|
-
offset:
|
|
70
|
-
Offset the list of solutions by this amount. Default value 0.
|
|
71
|
-
optimization_id: Optional[str]
|
|
72
|
-
Show solutions for only this optimization id. Default None.
|
|
73
|
-
|
|
74
|
-
Returns
|
|
75
|
-
-------
|
|
76
|
-
List[SolutionOut]
|
|
77
|
-
List of SolutionOut instances.
|
|
78
|
-
"""
|
|
79
44
|
params = {}
|
|
80
45
|
if timeframe and timeframe != TimeframeEnum.all_time: # no value == all_time
|
|
81
46
|
params["timeframe"] = timeframe.value
|
|
@@ -89,30 +54,14 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
89
54
|
|
|
90
55
|
params["limit"] = str(limit)
|
|
91
56
|
params["offset"] = str(offset)
|
|
92
|
-
response = self._client.get(
|
|
93
|
-
self._endpoint,
|
|
94
|
-
params=params,
|
|
95
|
-
)
|
|
57
|
+
response = self._client.get(self._endpoint, params=params, **kwargs)
|
|
96
58
|
|
|
97
59
|
response.raise_for_status()
|
|
98
60
|
|
|
99
61
|
return [Solution.model_validate(i) for i in response.json()]
|
|
100
62
|
|
|
101
|
-
def delete(self, solution_id: str) -> None:
|
|
102
|
-
""
|
|
103
|
-
Delete one optimization by id.
|
|
104
|
-
|
|
105
|
-
Parameters
|
|
106
|
-
----------
|
|
107
|
-
solution_id: str
|
|
108
|
-
Id of the optimization that should be deleted
|
|
109
|
-
|
|
110
|
-
Returns
|
|
111
|
-
-------
|
|
112
|
-
"""
|
|
113
|
-
self._client.delete(
|
|
114
|
-
f"{self._endpoint}/{solution_id}",
|
|
115
|
-
)
|
|
63
|
+
def delete(self, solution_id: str, **kwargs) -> None:
|
|
64
|
+
self._client.delete(f"{self._endpoint}/{solution_id}", **kwargs)
|
|
116
65
|
|
|
117
66
|
def create(
|
|
118
67
|
self,
|
|
@@ -120,39 +69,16 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
120
69
|
solver_name: str,
|
|
121
70
|
provider: str,
|
|
122
71
|
qpu_tokens: Optional[TokenProvider] = None,
|
|
123
|
-
solver_parameters: Optional[Union[Dict, BaseModel]] = None,
|
|
72
|
+
solver_parameters: Optional[Union[Dict[str, Any], BaseModel]] = None,
|
|
124
73
|
encryption_key: Optional[str] = None,
|
|
125
74
|
name: Optional[str] = None,
|
|
75
|
+
fail_on_invalid_params: bool = True,
|
|
76
|
+
**kwargs,
|
|
126
77
|
) -> Solution:
|
|
127
|
-
"""
|
|
128
|
-
Create a solution for an optimization
|
|
129
|
-
|
|
130
|
-
Parameters
|
|
131
|
-
----------
|
|
132
|
-
optimization_id: str
|
|
133
|
-
The id of the optimization for which solution should be created
|
|
134
|
-
solver_name: str
|
|
135
|
-
The name of the solver to use.
|
|
136
|
-
provider: str
|
|
137
|
-
The name of the QPU provider to use.
|
|
138
|
-
qpu_tokens: Optional[TokenProvider]
|
|
139
|
-
The tokens to be used for the QPU.
|
|
140
|
-
solver_parameters: Optional[Dict]
|
|
141
|
-
Parameters to be passed to the solver.
|
|
142
|
-
encryption_key: Optional[str]
|
|
143
|
-
Encryption key to be used for encryption of QPU tokens.
|
|
144
|
-
name: Optional[str]
|
|
145
|
-
Default: None, The name of the solution to create.
|
|
146
|
-
|
|
147
|
-
Returns
|
|
148
|
-
-------
|
|
149
|
-
SolutionOut
|
|
150
|
-
Returns the location where the solution can be found once solving is complete.
|
|
151
|
-
"""
|
|
152
|
-
if solver_parameters is None:
|
|
153
|
-
solver_parameters = {}
|
|
154
78
|
if qpu_tokens is not None:
|
|
155
|
-
rest_qpu_tokens = RestAPITokenProvider.from_sdk_token_provider(
|
|
79
|
+
rest_qpu_tokens = RestAPITokenProvider.from_sdk_token_provider(
|
|
80
|
+
TokenProvider.model_validate(qpu_tokens)
|
|
81
|
+
)
|
|
156
82
|
else:
|
|
157
83
|
rest_qpu_tokens = None
|
|
158
84
|
# try to retrieve qpu tokens from env variables
|
|
@@ -162,21 +88,21 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
162
88
|
encryption_key = encryption_key or os.environ.get("LUNA_ENCRYPTION_KEY")
|
|
163
89
|
if encryption_key is None:
|
|
164
90
|
raise EncryptionNotSetException
|
|
91
|
+
params = SolutionsRepo.validate_solver_params(
|
|
92
|
+
solver_name, provider, solver_parameters, fail_on_invalid_params
|
|
93
|
+
)
|
|
94
|
+
|
|
165
95
|
solution_in = SolutionIn(
|
|
166
96
|
optimization=optimization_id,
|
|
167
97
|
solver_name=solver_name,
|
|
168
98
|
provider=provider,
|
|
169
|
-
parameters=
|
|
170
|
-
solver_parameters.model_dump()
|
|
171
|
-
if isinstance(solver_parameters, BaseModel)
|
|
172
|
-
else solver_parameters
|
|
173
|
-
),
|
|
99
|
+
parameters=params,
|
|
174
100
|
qpu_tokens=rest_qpu_tokens,
|
|
175
101
|
encryption_key=encryption_key,
|
|
176
102
|
name=name,
|
|
177
103
|
)
|
|
178
104
|
response = self._client.post(
|
|
179
|
-
self._endpoint, content=solution_in.model_dump_json()
|
|
105
|
+
self._endpoint, content=solution_in.model_dump_json(), **kwargs
|
|
180
106
|
)
|
|
181
107
|
response.raise_for_status()
|
|
182
108
|
|
|
@@ -188,53 +114,19 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
188
114
|
solver_name: str,
|
|
189
115
|
provider: str,
|
|
190
116
|
qpu_tokens: Optional[TokenProvider] = None,
|
|
191
|
-
solver_parameters: Optional[Union[Dict, BaseModel]] = None,
|
|
117
|
+
solver_parameters: Optional[Union[Dict[str, Any], BaseModel]] = None,
|
|
192
118
|
sleep_time_max: float = 60.0,
|
|
193
119
|
sleep_time_increment: float = 5.0,
|
|
194
120
|
sleep_time_initial: float = 5.0,
|
|
195
121
|
encryption_key: Optional[str] = None,
|
|
196
122
|
name: Optional[str] = None,
|
|
123
|
+
fail_on_invalid_params: bool = True,
|
|
124
|
+
**kwargs,
|
|
197
125
|
) -> Solution:
|
|
198
|
-
"""
|
|
199
|
-
Create a solution for optimization. This method will block your code until the solution is ready.
|
|
200
|
-
Depending on the problem size, this can take a long time.
|
|
201
|
-
|
|
202
|
-
Parameters
|
|
203
|
-
----------
|
|
204
|
-
optimization_id: str
|
|
205
|
-
The id of the optimization for which solution should be created
|
|
206
|
-
solver_name: str
|
|
207
|
-
The name of the solver to use.
|
|
208
|
-
provider: str
|
|
209
|
-
The name of the provider to use.
|
|
210
|
-
|
|
211
|
-
qpu_tokens: Optional[TokenProvider] = None
|
|
212
|
-
The tokens to be used for the QPU.
|
|
213
|
-
solver_parameters: Optional[Dict]
|
|
214
|
-
Parameters to be passed to the solver.
|
|
215
|
-
|
|
216
|
-
sleep_time_max: float
|
|
217
|
-
Maximum time to sleep between requests.
|
|
218
|
-
sleep_time_increment: float
|
|
219
|
-
Increment of sleep time between requests. Initial sleep time will be
|
|
220
|
-
sleep_time_initial: float
|
|
221
|
-
Initial sleep time.
|
|
222
|
-
encryption_key: Optional[str]
|
|
223
|
-
Encryption key to be used for encryption of QPU tokens.
|
|
224
|
-
name: Optional[str]
|
|
225
|
-
Default: None, The name of the solution to create.
|
|
226
|
-
Returns
|
|
227
|
-
-------
|
|
228
|
-
SolutionOut
|
|
229
|
-
Returns the location where the solution can be found once solving is complete.
|
|
230
|
-
"""
|
|
231
126
|
# First create the solution
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
params = solver_parameters
|
|
236
|
-
if isinstance(solver_parameters, BaseModel):
|
|
237
|
-
params = solver_parameters.dict()
|
|
127
|
+
params = SolutionsRepo.validate_solver_params(
|
|
128
|
+
solver_name, provider, solver_parameters, fail_on_invalid_params
|
|
129
|
+
)
|
|
238
130
|
|
|
239
131
|
solution: Solution = self.create(
|
|
240
132
|
optimization_id=optimization_id,
|
|
@@ -244,6 +136,7 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
244
136
|
qpu_tokens=qpu_tokens,
|
|
245
137
|
encryption_key=encryption_key,
|
|
246
138
|
name=name,
|
|
139
|
+
**kwargs,
|
|
247
140
|
)
|
|
248
141
|
# times are in sec
|
|
249
142
|
|
|
@@ -271,44 +164,20 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
271
164
|
if cur_sleep_time > sleep_time_max:
|
|
272
165
|
cur_sleep_time = sleep_time_max
|
|
273
166
|
|
|
274
|
-
solution = self.get(solution_id=solution.id)
|
|
167
|
+
solution = self.get(solution_id=solution.id, **kwargs)
|
|
275
168
|
|
|
276
169
|
return solution
|
|
277
170
|
|
|
278
|
-
def get_use_case_representation(
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
solution_id: str
|
|
285
|
-
Id of the solution that should be retrieved
|
|
286
|
-
|
|
287
|
-
Returns
|
|
288
|
-
-------
|
|
289
|
-
UseCaseRepresentation
|
|
290
|
-
The use-case-specific representation
|
|
291
|
-
"""
|
|
292
|
-
response = self._client.get(f"{self._endpoint}/{solution_id}/representation")
|
|
171
|
+
def get_use_case_representation(
|
|
172
|
+
self, solution_id: str, **kwargs
|
|
173
|
+
) -> UseCaseRepresentation:
|
|
174
|
+
response = self._client.get(
|
|
175
|
+
f"{self._endpoint}/{solution_id}/representation", **kwargs
|
|
176
|
+
)
|
|
293
177
|
response.raise_for_status()
|
|
294
178
|
return UseCaseRepresentation.model_validate_json(response.text)
|
|
295
179
|
|
|
296
180
|
def get_best_result(self, solution: Solution) -> Optional[Result]:
|
|
297
|
-
"""
|
|
298
|
-
Retrieves the best result from a solution.
|
|
299
|
-
|
|
300
|
-
Parameters
|
|
301
|
-
----------
|
|
302
|
-
solution : Solution
|
|
303
|
-
The solution received via `solutions.get` or `solutions.get_all`.
|
|
304
|
-
|
|
305
|
-
Returns
|
|
306
|
-
-------
|
|
307
|
-
Result | None
|
|
308
|
-
The best result of the solution. If there are several best solutions with
|
|
309
|
-
the same objective value, return only the first. If the solution results are
|
|
310
|
-
not (yet) available or no the solution sense is `None`, return `None`.
|
|
311
|
-
"""
|
|
312
181
|
if solution.results is None or solution.sense is None:
|
|
313
182
|
return None
|
|
314
183
|
|
|
@@ -320,21 +189,6 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
320
189
|
def get_best_use_case_result(
|
|
321
190
|
self, use_case_representation: UseCaseRepresentation
|
|
322
191
|
) -> Optional[UseCaseResult]:
|
|
323
|
-
"""
|
|
324
|
-
Retrieves the best result from a solution's use case representation.
|
|
325
|
-
|
|
326
|
-
Parameters
|
|
327
|
-
----------
|
|
328
|
-
use_case_representation : UseCaseRepresentation
|
|
329
|
-
A solution's use case representation.
|
|
330
|
-
|
|
331
|
-
Returns
|
|
332
|
-
-------
|
|
333
|
-
UseCaseResult | None
|
|
334
|
-
The best result of the solution. If there are several best solutions with
|
|
335
|
-
the same objective value, return only the first. If the solution results are
|
|
336
|
-
not (yet) available or no the solution sense is `None`, return `None`.
|
|
337
|
-
"""
|
|
338
192
|
if (
|
|
339
193
|
use_case_representation.results is None
|
|
340
194
|
or use_case_representation.sense is None
|
|
@@ -345,3 +199,77 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
345
199
|
best_result = agg(use_case_representation.results, key=lambda x: x.obj_value)
|
|
346
200
|
|
|
347
201
|
return best_result
|
|
202
|
+
|
|
203
|
+
@staticmethod
|
|
204
|
+
def validate_solver_params(
|
|
205
|
+
solver: str,
|
|
206
|
+
provider: str,
|
|
207
|
+
solver_parameter: Optional[Union[Dict[str, Any], BaseModel]],
|
|
208
|
+
fail_on_invalid_params: bool = True,
|
|
209
|
+
) -> Dict[str, Any]:
|
|
210
|
+
"""
|
|
211
|
+
This function checks if the params provided are valid for the provided solver
|
|
212
|
+
and provider.
|
|
213
|
+
If no parameter class was found, there will be no check.
|
|
214
|
+
|
|
215
|
+
Parameters
|
|
216
|
+
----------
|
|
217
|
+
solver: str
|
|
218
|
+
The solver
|
|
219
|
+
provider: str
|
|
220
|
+
The provider
|
|
221
|
+
solver_parameter: Optional[Union[Dict[str, Any], BaseModel]]
|
|
222
|
+
The solver parameter
|
|
223
|
+
fail_on_invalid_params: bool
|
|
224
|
+
Default true.
|
|
225
|
+
If True, a ValueError will be raised, if the solver_parameter are invalid.
|
|
226
|
+
Otherwise, there will only a warning.
|
|
227
|
+
|
|
228
|
+
Returns
|
|
229
|
+
-------
|
|
230
|
+
Dict[str, Any]
|
|
231
|
+
Validated solver params
|
|
232
|
+
|
|
233
|
+
Raises
|
|
234
|
+
-------
|
|
235
|
+
ValidationError
|
|
236
|
+
If the object could not be validated.
|
|
237
|
+
|
|
238
|
+
"""
|
|
239
|
+
if solver_parameter is None:
|
|
240
|
+
logging.info(
|
|
241
|
+
"You didn't provide any specific solver parameters, so we chose the "
|
|
242
|
+
"default ones for this solver."
|
|
243
|
+
)
|
|
244
|
+
return {}
|
|
245
|
+
|
|
246
|
+
params: Dict[str, Any]
|
|
247
|
+
if isinstance(solver_parameter, BaseModel):
|
|
248
|
+
params = solver_parameter.dict()
|
|
249
|
+
else:
|
|
250
|
+
params = solver_parameter
|
|
251
|
+
|
|
252
|
+
parameter_class: Optional[Type[BaseModel]] = get_parameter_by_solver(
|
|
253
|
+
solver, provider
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
if parameter_class is None:
|
|
257
|
+
logging.info(
|
|
258
|
+
f"SDK was not able to find a parameter for solver {solver} "
|
|
259
|
+
f"and provider {provider}."
|
|
260
|
+
)
|
|
261
|
+
return params
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
parameter_class.model_validate(params)
|
|
265
|
+
|
|
266
|
+
except ValidationError as e:
|
|
267
|
+
if fail_on_invalid_params:
|
|
268
|
+
raise e
|
|
269
|
+
logging.warning(
|
|
270
|
+
"The validation for the provided solver parameter failed.\n"
|
|
271
|
+
f"Detected error:\n{e}\n"
|
|
272
|
+
"Since continue on error is enabled, no error was raised.\n"
|
|
273
|
+
"Solving with Luna can still fail due to the parameters."
|
|
274
|
+
)
|
|
275
|
+
return params
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Dict, Optional
|
|
1
|
+
from typing import Dict, Optional, Any
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ class SolutionIn(BaseModel):
|
|
|
9
9
|
optimization: str # id of the optimization
|
|
10
10
|
solver_name: str
|
|
11
11
|
provider: str
|
|
12
|
-
parameters: Dict
|
|
12
|
+
parameters: Dict[str, Any]
|
|
13
13
|
qpu_tokens: Optional[RestAPITokenProvider] = None
|
|
14
14
|
encryption_key: str
|
|
15
15
|
name: Optional[str] = None
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
class OptFormat(str, Enum):
|
|
5
|
+
"""Enumeration of all supported formats."""
|
|
6
|
+
|
|
7
|
+
AQ_MODEL = "AQ_MODEL"
|
|
8
|
+
LP = "LP"
|
|
9
|
+
QUBO = "QUBO_MATRIX"
|
|
10
|
+
CQM = "CQM"
|
|
11
|
+
BQM = "BQM"
|
luna_sdk/schemas/optimization.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
from
|
|
2
|
-
from typing import Any, Dict, Generic, List, Optional, TypeVar
|
|
1
|
+
from typing import Any, Dict, Generic, Optional, TypeVar
|
|
3
2
|
|
|
4
|
-
from pydantic import BaseModel,
|
|
3
|
+
from pydantic import BaseModel, ConfigDict
|
|
5
4
|
|
|
6
|
-
from luna_sdk.schemas.enums.optimization import
|
|
5
|
+
from luna_sdk.schemas.enums.optimization import OptFormat
|
|
7
6
|
from luna_sdk.schemas.optimization_formats.bqm import BQMSchema
|
|
8
7
|
from luna_sdk.schemas.optimization_formats.cqm import CQMSchema
|
|
9
8
|
from luna_sdk.schemas.optimization_formats.lp import LPSchema
|
|
9
|
+
from luna_sdk.schemas.optimization_formats.qubo import QuboSchema
|
|
10
10
|
from luna_sdk.schemas.pretty_base import PrettyBase
|
|
11
|
+
from luna_sdk.schemas.wrappers import PydanticDatetimeWrapper
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class Optimization(PrettyBase):
|
|
@@ -17,11 +18,11 @@ class Optimization(PrettyBase):
|
|
|
17
18
|
----------
|
|
18
19
|
id: str
|
|
19
20
|
Id of the optimization
|
|
20
|
-
created_date: Optional[
|
|
21
|
+
created_date: Optional[DatetimeWrapper]
|
|
21
22
|
Date when optimization was created
|
|
22
23
|
created_by: Optional[str]
|
|
23
24
|
Id of the user who created optimization
|
|
24
|
-
modified_date: Optional[
|
|
25
|
+
modified_date: Optional[DatetimeWrapper]
|
|
25
26
|
Date when optimization was modified
|
|
26
27
|
modified_by: Optional[str]
|
|
27
28
|
Id of the user who modified optimization
|
|
@@ -29,28 +30,15 @@ class Optimization(PrettyBase):
|
|
|
29
30
|
|
|
30
31
|
id: str
|
|
31
32
|
name: Optional[str] = None
|
|
32
|
-
created_date:
|
|
33
|
+
created_date: PydanticDatetimeWrapper
|
|
33
34
|
created_by: str
|
|
34
|
-
modified_date: Optional[
|
|
35
|
+
modified_date: Optional[PydanticDatetimeWrapper] = None
|
|
35
36
|
modified_by: Optional[str] = None
|
|
36
|
-
|
|
37
|
+
original_format: Optional[OptFormat] = None
|
|
37
38
|
use_case_name: Optional[str] = None
|
|
38
39
|
params: Optional[Dict[str, Any]] = None
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
extra = Extra.ignore
|
|
42
|
-
from_attributes = False
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class OptimizationQubo(BaseModel):
|
|
46
|
-
id: str
|
|
47
|
-
name: Optional[str] = None
|
|
48
|
-
created_date: datetime
|
|
49
|
-
created_by: str
|
|
50
|
-
modified_date: Optional[datetime] = None
|
|
51
|
-
modified_by: Optional[str] = None
|
|
52
|
-
|
|
53
|
-
matrix: List[List[float]]
|
|
41
|
+
model_config = ConfigDict(extra="ignore", from_attributes=False)
|
|
54
42
|
|
|
55
43
|
|
|
56
44
|
class OptimizationBQM(Optimization, BQMSchema): ...
|
|
@@ -62,10 +50,13 @@ class OptimizationCQM(Optimization, CQMSchema): ...
|
|
|
62
50
|
class OptimizationLP(Optimization, LPSchema): ...
|
|
63
51
|
|
|
64
52
|
|
|
65
|
-
class OptimizationUseCase(Optimization,
|
|
53
|
+
class OptimizationUseCase(Optimization, QuboSchema):
|
|
66
54
|
use_case: Dict[str, Any]
|
|
67
55
|
|
|
68
56
|
|
|
57
|
+
class OptimizationQubo(Optimization, QuboSchema): ...
|
|
58
|
+
|
|
59
|
+
|
|
69
60
|
T = TypeVar("T")
|
|
70
61
|
|
|
71
62
|
|
luna_sdk/schemas/pretty_base.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
1
3
|
from pydantic import BaseModel
|
|
2
4
|
|
|
3
5
|
|
|
@@ -8,10 +10,15 @@ class PrettyBase(BaseModel):
|
|
|
8
10
|
for key, value in data.items():
|
|
9
11
|
output += " " * indent + str(key) + ":"
|
|
10
12
|
if isinstance(value, dict):
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
if value == {}:
|
|
14
|
+
output += " {}\n"
|
|
15
|
+
else:
|
|
16
|
+
output += "\n"
|
|
17
|
+
output += self._pretty_print(value, indent + 1)
|
|
18
|
+
elif isinstance(value, datetime):
|
|
19
|
+
output += f" {value.strftime('%Y-%m-%d %H:%M:%S (%Z)')}\n"
|
|
13
20
|
else:
|
|
14
|
-
output += "
|
|
21
|
+
output += f" {value}\n"
|
|
15
22
|
return output
|
|
16
23
|
|
|
17
24
|
def __str__(self):
|
luna_sdk/schemas/qpu_token.py
CHANGED
|
@@ -3,6 +3,8 @@ from typing import Optional
|
|
|
3
3
|
|
|
4
4
|
from pydantic import BaseModel, Extra
|
|
5
5
|
|
|
6
|
+
from luna_sdk.schemas.enums.qpu_token_type import QpuTokenTypeEnum
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class QpuTokenSource(str, Enum):
|
|
8
10
|
# token currently passed in from the API call (not stored by us)
|
|
@@ -10,7 +12,7 @@ class QpuTokenSource(str, Enum):
|
|
|
10
12
|
# stored token in user account
|
|
11
13
|
PERSONAL = "personal"
|
|
12
14
|
# stored token in group account
|
|
13
|
-
|
|
15
|
+
GROUP = "group"
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
class QpuToken(BaseModel):
|
|
@@ -42,18 +44,15 @@ class QpuTokenOut(BaseModel):
|
|
|
42
44
|
|
|
43
45
|
Attributes
|
|
44
46
|
----------
|
|
45
|
-
id: str
|
|
46
|
-
Id of the QPU token
|
|
47
47
|
name: Optional[str]
|
|
48
48
|
Name of the QPU token
|
|
49
49
|
provider: ProviderEnum
|
|
50
50
|
Name of provider: dwave | ibm
|
|
51
51
|
"""
|
|
52
52
|
|
|
53
|
-
id: str
|
|
54
|
-
|
|
55
53
|
name: str
|
|
56
54
|
provider: str
|
|
55
|
+
token_type: QpuTokenTypeEnum
|
|
57
56
|
|
|
58
57
|
class Config:
|
|
59
58
|
extra = Extra.ignore
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class _RESTQpuTokenSource(str, Enum):
|
|
5
|
+
"""
|
|
6
|
+
This schema allow us not to change entire backend,
|
|
7
|
+
but just sync SDK and everything else in terms of qpu token source.
|
|
8
|
+
Currently, the difference is that
|
|
9
|
+
SDK has group qpu token source
|
|
10
|
+
and backend has organization qpu token source which are mapped to each other.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# token currently passed in from the API call (not stored by us)
|
|
14
|
+
INLINE = "inline"
|
|
15
|
+
# stored token in user account
|
|
16
|
+
PERSONAL = "personal"
|
|
17
|
+
# stored token in group account
|
|
18
|
+
ORGANIZATION = "organization"
|