luna-quantum 0.0.16__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/LICENSE +201 -0
- luna_quantum-0.0.16.dist-info/METADATA +46 -0
- luna_quantum-0.0.16.dist-info/RECORD +160 -0
- luna_quantum-0.0.16.dist-info/WHEEL +4 -0
- luna_sdk/__init__.py +2 -0
- luna_sdk/constants.py +1 -0
- luna_sdk/controllers/__init__.py +2 -0
- luna_sdk/controllers/custom_login_client.py +61 -0
- luna_sdk/controllers/luna_platform_client.py +62 -0
- luna_sdk/controllers/luna_q.py +36 -0
- luna_sdk/controllers/luna_solve.py +49 -0
- luna_sdk/controllers/luna_transform.py +41 -0
- luna_sdk/error/__init__.py +0 -0
- luna_sdk/error/http_error_utils.py +100 -0
- luna_sdk/exceptions/__init__.py +1 -0
- luna_sdk/exceptions/encryption_exception.py +6 -0
- luna_sdk/exceptions/luna_exception.py +7 -0
- luna_sdk/exceptions/luna_server_exception.py +18 -0
- luna_sdk/exceptions/timeout_exception.py +10 -0
- luna_sdk/exceptions/transformation.py +11 -0
- luna_sdk/interfaces/__init__.py +5 -0
- luna_sdk/interfaces/circuit_repo_i.py +62 -0
- luna_sdk/interfaces/clients/__init__.py +0 -0
- luna_sdk/interfaces/clients/client_i.py +10 -0
- luna_sdk/interfaces/clients/luna_q_i.py +39 -0
- luna_sdk/interfaces/clients/luna_solve_i.py +37 -0
- luna_sdk/interfaces/clients/luna_transform_i.py +33 -0
- luna_sdk/interfaces/cplex_repo_i.py +121 -0
- luna_sdk/interfaces/info_repo_i.py +40 -0
- luna_sdk/interfaces/lp_repo_i.py +106 -0
- luna_sdk/interfaces/optimization_repo_i.py +262 -0
- luna_sdk/interfaces/qpu_token_repo_i.py +151 -0
- luna_sdk/interfaces/repository_i.py +14 -0
- luna_sdk/interfaces/solutions_repo_i.py +219 -0
- luna_sdk/py.typed +0 -0
- luna_sdk/repositories/__init__.py +4 -0
- luna_sdk/repositories/circuit_repo.py +104 -0
- luna_sdk/repositories/cplex_repo.py +118 -0
- luna_sdk/repositories/info_repo.py +45 -0
- luna_sdk/repositories/lp_repo.py +105 -0
- luna_sdk/repositories/optimization_repo.py +358 -0
- luna_sdk/repositories/qpu_token_repo.py +226 -0
- luna_sdk/repositories/solutions_repo.py +347 -0
- luna_sdk/schemas/__init__.py +4 -0
- luna_sdk/schemas/circuit.py +43 -0
- luna_sdk/schemas/create/__init__.py +3 -0
- luna_sdk/schemas/create/circuit.py +29 -0
- luna_sdk/schemas/create/optimization.py +22 -0
- luna_sdk/schemas/create/qpu_token.py +26 -0
- luna_sdk/schemas/create/qubo.py +19 -0
- luna_sdk/schemas/create/solution.py +15 -0
- luna_sdk/schemas/enums/__init__.py +0 -0
- luna_sdk/schemas/enums/circuit.py +14 -0
- luna_sdk/schemas/enums/optimization.py +10 -0
- luna_sdk/schemas/enums/problem.py +48 -0
- luna_sdk/schemas/enums/qpu_token_type.py +6 -0
- luna_sdk/schemas/enums/solution.py +8 -0
- luna_sdk/schemas/enums/status.py +10 -0
- luna_sdk/schemas/enums/timeframe.py +11 -0
- luna_sdk/schemas/error_message.py +12 -0
- luna_sdk/schemas/optimization.py +75 -0
- luna_sdk/schemas/optimization_formats/__init__.py +0 -0
- luna_sdk/schemas/optimization_formats/bqm.py +34 -0
- luna_sdk/schemas/optimization_formats/cqm.py +127 -0
- luna_sdk/schemas/optimization_formats/lp.py +9 -0
- luna_sdk/schemas/optimization_formats/qm.py +30 -0
- luna_sdk/schemas/pretty_base.py +49 -0
- luna_sdk/schemas/qpu_token.py +60 -0
- luna_sdk/schemas/representation.py +19 -0
- luna_sdk/schemas/rest/__init__.py +0 -0
- luna_sdk/schemas/rest/qpu_token/__init__.py +0 -0
- luna_sdk/schemas/rest/qpu_token/token_provider.py +45 -0
- luna_sdk/schemas/solution.py +227 -0
- luna_sdk/schemas/solver_info.py +11 -0
- luna_sdk/schemas/solver_parameters/aws/__init__.py +1 -0
- luna_sdk/schemas/solver_parameters/aws/qaoa.py +24 -0
- luna_sdk/schemas/solver_parameters/dwave/__init__.py +72 -0
- luna_sdk/schemas/solver_parameters/dwave/base.py +409 -0
- luna_sdk/schemas/solver_parameters/dwave/dialectic_search.py +31 -0
- luna_sdk/schemas/solver_parameters/dwave/kerberos.py +71 -0
- luna_sdk/schemas/solver_parameters/dwave/leap_hybrid_bqm.py +19 -0
- luna_sdk/schemas/solver_parameters/dwave/leap_hybrid_cqm.py +22 -0
- luna_sdk/schemas/solver_parameters/dwave/parallel_tempering.py +30 -0
- luna_sdk/schemas/solver_parameters/dwave/parallel_tempering_qpu.py +37 -0
- luna_sdk/schemas/solver_parameters/dwave/population_annealing.py +25 -0
- luna_sdk/schemas/solver_parameters/dwave/population_annealing_qpu.py +35 -0
- luna_sdk/schemas/solver_parameters/dwave/qaga.py +56 -0
- luna_sdk/schemas/solver_parameters/dwave/qbsolv_like_qpu.py +19 -0
- luna_sdk/schemas/solver_parameters/dwave/qbsolv_like_simulated_annealing.py +22 -0
- luna_sdk/schemas/solver_parameters/dwave/qbsolv_like_tabu_search.py +21 -0
- luna_sdk/schemas/solver_parameters/dwave/quantum_annealing.py +20 -0
- luna_sdk/schemas/solver_parameters/dwave/repeated_reverse_quantum_annealing.py +82 -0
- luna_sdk/schemas/solver_parameters/dwave/repeated_reverse_simulated_annealing.py +89 -0
- luna_sdk/schemas/solver_parameters/dwave/saga.py +61 -0
- luna_sdk/schemas/solver_parameters/dwave/simulated_annealing.py +74 -0
- luna_sdk/schemas/solver_parameters/dwave/tabu_search.py +72 -0
- luna_sdk/schemas/solver_parameters/fujitsu/__init__.py +20 -0
- luna_sdk/schemas/solver_parameters/fujitsu/base.py +47 -0
- luna_sdk/schemas/solver_parameters/fujitsu/digital_annealer_cpu.py +129 -0
- luna_sdk/schemas/solver_parameters/fujitsu/digital_annealer_v2.py +149 -0
- luna_sdk/schemas/solver_parameters/fujitsu/digital_annealer_v3.py +150 -0
- luna_sdk/schemas/solver_parameters/fujitsu/partial_config.py +177 -0
- luna_sdk/schemas/solver_parameters/ibm/__init__.py +4 -0
- luna_sdk/schemas/solver_parameters/ibm/qaoa.py +64 -0
- luna_sdk/schemas/solver_parameters/ibm/standard_parameters.py +27 -0
- luna_sdk/schemas/solver_parameters/ibm/vqe.py +49 -0
- luna_sdk/schemas/solver_parameters/qctrl/__init__.py +1 -0
- luna_sdk/schemas/solver_parameters/qctrl/qaoa.py +47 -0
- luna_sdk/schemas/transformations/__init__.py +2 -0
- luna_sdk/schemas/transformations/bqm.py +33 -0
- luna_sdk/schemas/transformations/matrix.py +12 -0
- luna_sdk/schemas/use_cases/__init__.py +54 -0
- luna_sdk/schemas/use_cases/arbitrage_edge_based.py +49 -0
- luna_sdk/schemas/use_cases/arbitrage_node_based.py +54 -0
- luna_sdk/schemas/use_cases/base.py +5 -0
- luna_sdk/schemas/use_cases/binary_integer_linear_programming.py +53 -0
- luna_sdk/schemas/use_cases/binary_paint_shop_problem.py +36 -0
- luna_sdk/schemas/use_cases/credit_scoring_feature_selection.py +39 -0
- luna_sdk/schemas/use_cases/dynamic_portfolio_optimization.py +63 -0
- luna_sdk/schemas/use_cases/exact_cover.py +50 -0
- luna_sdk/schemas/use_cases/flight_gate_assignment.py +78 -0
- luna_sdk/schemas/use_cases/graph_coloring.py +41 -0
- luna_sdk/schemas/use_cases/graph_isomorphism.py +53 -0
- luna_sdk/schemas/use_cases/graph_partitioning.py +45 -0
- luna_sdk/schemas/use_cases/hamiltonian_cycle.py +48 -0
- luna_sdk/schemas/use_cases/induced_subgraph_isomorphism.py +49 -0
- luna_sdk/schemas/use_cases/job_shop_scheduling.py +43 -0
- luna_sdk/schemas/use_cases/k_medoids_clustering.py +48 -0
- luna_sdk/schemas/use_cases/knapsack_integer_weights.py +55 -0
- luna_sdk/schemas/use_cases/linear_regression.py +59 -0
- luna_sdk/schemas/use_cases/lmwcs.py +80 -0
- luna_sdk/schemas/use_cases/longest_path.py +49 -0
- luna_sdk/schemas/use_cases/market_graph_clustering.py +60 -0
- luna_sdk/schemas/use_cases/max2sat.py +51 -0
- luna_sdk/schemas/use_cases/max3sat.py +52 -0
- luna_sdk/schemas/use_cases/max_clique.py +59 -0
- luna_sdk/schemas/use_cases/max_cut.py +47 -0
- luna_sdk/schemas/use_cases/max_independent_set.py +36 -0
- luna_sdk/schemas/use_cases/minimal_maximal_matching.py +53 -0
- luna_sdk/schemas/use_cases/minimal_spanning_tree.py +87 -0
- luna_sdk/schemas/use_cases/minimum_vertex_cover.py +44 -0
- luna_sdk/schemas/use_cases/number_partitioning.py +31 -0
- luna_sdk/schemas/use_cases/portfolio_optimization.py +45 -0
- luna_sdk/schemas/use_cases/portfolio_optimization_ib_tv.py +62 -0
- luna_sdk/schemas/use_cases/quadratic_assignment.py +48 -0
- luna_sdk/schemas/use_cases/quadratic_knapsack.py +47 -0
- luna_sdk/schemas/use_cases/satellite_scheduling.py +72 -0
- luna_sdk/schemas/use_cases/sensor_placement.py +57 -0
- luna_sdk/schemas/use_cases/set_cover.py +55 -0
- luna_sdk/schemas/use_cases/set_packing.py +53 -0
- luna_sdk/schemas/use_cases/set_partitioning.py +51 -0
- luna_sdk/schemas/use_cases/subgraph_isomorphism.py +56 -0
- luna_sdk/schemas/use_cases/subset_sum.py +36 -0
- luna_sdk/schemas/use_cases/support_vector_machine.py +63 -0
- luna_sdk/schemas/use_cases/traffic_flow.py +34 -0
- luna_sdk/schemas/use_cases/travelling_salesman_problem.py +52 -0
- luna_sdk/schemas/use_cases/type_aliases.py +11 -0
- luna_sdk/schemas/use_cases/weighted_max_cut.py +36 -0
- luna_sdk/utils/__init__.py +0 -0
- luna_sdk/utils/qpu_tokens.py +52 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any, Dict, Optional
|
|
3
|
+
|
|
4
|
+
from luna_sdk.exceptions.encryption_exception import EncryptionNotSetException
|
|
5
|
+
from luna_sdk.interfaces.circuit_repo_i import ICircuitRepo
|
|
6
|
+
from luna_sdk.schemas.circuit import CircuitJob, CircuitResult
|
|
7
|
+
from luna_sdk.schemas.create.circuit import CircuitIn
|
|
8
|
+
from luna_sdk.schemas.enums.circuit import CircuitProviderEnum
|
|
9
|
+
from luna_sdk.schemas.qpu_token import TokenProvider, QpuToken, QpuTokenSource
|
|
10
|
+
from luna_sdk.schemas.rest.qpu_token.token_provider import RestAPITokenProvider
|
|
11
|
+
from luna_sdk.utils.qpu_tokens import extract_qpu_tokens_from_env
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CircuitRepo(ICircuitRepo):
|
|
15
|
+
_endpoint = "/circuits"
|
|
16
|
+
|
|
17
|
+
def create(
|
|
18
|
+
self,
|
|
19
|
+
circuit: str,
|
|
20
|
+
provider: CircuitProviderEnum,
|
|
21
|
+
params: Dict[str, Any] = {},
|
|
22
|
+
qpu_tokens: Optional[TokenProvider] = None,
|
|
23
|
+
timeout: Optional[float] = 10800.0,
|
|
24
|
+
encryption_key: Optional[str] = None,
|
|
25
|
+
) -> CircuitJob:
|
|
26
|
+
"""
|
|
27
|
+
Create a circuit solution.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
circuit: str
|
|
32
|
+
The circuit which to create a solution for.
|
|
33
|
+
provider: CircuitProviderEnum
|
|
34
|
+
Which provider to use to solve the circuit.
|
|
35
|
+
params: Dict[str, Any]
|
|
36
|
+
Additional parameters of the circuit.
|
|
37
|
+
qpu_tokens: Optional[TokenProvider]
|
|
38
|
+
The tokens to be used for the QPU.
|
|
39
|
+
timeout: Optional[float]
|
|
40
|
+
Default = 10800.0. Timeout for the api request. If set to None,
|
|
41
|
+
there won't be any timeout. Increase or disable the timeout if you face
|
|
42
|
+
issues uploading big Problems.
|
|
43
|
+
encryption_key: Optional[str]
|
|
44
|
+
Encryption key to be used for encryption of QPU tokens.
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
CircuitJob
|
|
48
|
+
The created circuit job.
|
|
49
|
+
"""
|
|
50
|
+
if qpu_tokens is not None:
|
|
51
|
+
rest_qpu_tokens = RestAPITokenProvider.from_sdk_token_provider(qpu_tokens)
|
|
52
|
+
else:
|
|
53
|
+
rest_qpu_tokens = None
|
|
54
|
+
|
|
55
|
+
# try to retrieve qpu tokens from env variables
|
|
56
|
+
if rest_qpu_tokens is None:
|
|
57
|
+
rest_qpu_tokens = extract_qpu_tokens_from_env()
|
|
58
|
+
|
|
59
|
+
encryption_key = encryption_key or os.environ.get("LUNA_ENCRYPTION_KEY")
|
|
60
|
+
if encryption_key is None:
|
|
61
|
+
raise EncryptionNotSetException
|
|
62
|
+
circuit_in: CircuitIn = CircuitIn(
|
|
63
|
+
provider=provider,
|
|
64
|
+
circuit=circuit,
|
|
65
|
+
params=params,
|
|
66
|
+
qpu_tokens=rest_qpu_tokens,
|
|
67
|
+
encryption_key=encryption_key,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
response = self._client.post(
|
|
71
|
+
self._endpoint, content=circuit_in.model_dump_json(), timeout=timeout
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
response.raise_for_status()
|
|
75
|
+
return CircuitJob(id=response.json(), provider=provider, params=params)
|
|
76
|
+
|
|
77
|
+
def get(
|
|
78
|
+
self, job: CircuitJob, encryption_key: Optional[str] = None
|
|
79
|
+
) -> CircuitResult:
|
|
80
|
+
"""
|
|
81
|
+
Retrieve a circuit result from a job.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
job: CircuitJob
|
|
86
|
+
The job received upon circuit creation.
|
|
87
|
+
encryption_key: Optional[str]
|
|
88
|
+
The encryption key to be used for the QPU.
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
CircuitResult
|
|
92
|
+
The result of solving the circuit.
|
|
93
|
+
"""
|
|
94
|
+
url = f"{self._endpoint}/{job.id}/{job.provider.value}"
|
|
95
|
+
encryption_key = encryption_key or os.environ.get("LUNA_ENCRYPTION_KEY")
|
|
96
|
+
if encryption_key is None:
|
|
97
|
+
raise EncryptionNotSetException
|
|
98
|
+
if job.params is None:
|
|
99
|
+
job.params = {}
|
|
100
|
+
job.params["encryption_key"] = encryption_key
|
|
101
|
+
response = self._client.get(url, params=job.params, timeout=60)
|
|
102
|
+
|
|
103
|
+
response.raise_for_status()
|
|
104
|
+
return CircuitResult.model_validate(response.json())
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pickle
|
|
3
|
+
import tempfile
|
|
4
|
+
from functools import partial
|
|
5
|
+
from typing import Tuple, List, Dict
|
|
6
|
+
|
|
7
|
+
import dimod
|
|
8
|
+
from dimod import ConstrainedQuadraticModel
|
|
9
|
+
from dimod.constrained.constrained import CQMToBQMInverter
|
|
10
|
+
from docplex.mp.model import Model as DOCplexModel
|
|
11
|
+
from qiskit_optimization import QuadraticProgram
|
|
12
|
+
|
|
13
|
+
from luna_sdk.exceptions.transformation import TransformationException
|
|
14
|
+
from luna_sdk.interfaces.cplex_repo_i import ICplexRepo
|
|
15
|
+
from luna_sdk.schemas.transformations.bqm import BQMResultSchema, BQMSchema
|
|
16
|
+
from luna_sdk.schemas.transformations.matrix import MatrixSchema
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CplexRepo(ICplexRepo):
|
|
20
|
+
_endpoint = "/transformations/docplex"
|
|
21
|
+
|
|
22
|
+
def _send_request_with_pickle_file_response(
|
|
23
|
+
self, docplex_model: DOCplexModel, endpoint: str
|
|
24
|
+
):
|
|
25
|
+
file = tempfile.NamedTemporaryFile(delete=False)
|
|
26
|
+
with open(file.name, "wb") as tmp:
|
|
27
|
+
pickle.dump(docplex_model, tmp)
|
|
28
|
+
response = self._client.post(endpoint, files={"file": (file.name, file.file)})
|
|
29
|
+
os.remove(file.name)
|
|
30
|
+
try:
|
|
31
|
+
parsed_model = pickle.loads(response.content)
|
|
32
|
+
except Exception:
|
|
33
|
+
raise TransformationException()
|
|
34
|
+
return parsed_model
|
|
35
|
+
|
|
36
|
+
def to_qubo_qiskit(self, docplex_model: DOCplexModel) -> QuadraticProgram:
|
|
37
|
+
qubo_qiskit_model = self._send_request_with_pickle_file_response(
|
|
38
|
+
docplex_model, f"{self._endpoint}/to-qubo-qiskit"
|
|
39
|
+
)
|
|
40
|
+
try:
|
|
41
|
+
assert isinstance(qubo_qiskit_model, QuadraticProgram)
|
|
42
|
+
except AssertionError:
|
|
43
|
+
raise TransformationException()
|
|
44
|
+
return qubo_qiskit_model
|
|
45
|
+
|
|
46
|
+
def to_lp_file(self, docplex_model: DOCplexModel, filepath: str) -> None:
|
|
47
|
+
file = tempfile.NamedTemporaryFile(delete=False)
|
|
48
|
+
with open(file.name, "wb") as tmp:
|
|
49
|
+
pickle.dump(docplex_model, tmp)
|
|
50
|
+
response = self._client.post(
|
|
51
|
+
f"{self._endpoint}/to-lp-file", files={"file": (file.name, file.file)}
|
|
52
|
+
)
|
|
53
|
+
with open(filepath, "w") as file: # type: ignore
|
|
54
|
+
file.write(response.content.decode("utf-8")) # type: ignore
|
|
55
|
+
|
|
56
|
+
def to_lp_string(self, docplex_model: DOCplexModel) -> str:
|
|
57
|
+
file = tempfile.NamedTemporaryFile(delete=False)
|
|
58
|
+
with open(file.name, "wb") as tmp:
|
|
59
|
+
pickle.dump(docplex_model, tmp)
|
|
60
|
+
response = self._client.post(
|
|
61
|
+
f"{self._endpoint}/to-lp-file", files={"file": (file.name, file.file)}
|
|
62
|
+
)
|
|
63
|
+
return response.content.decode("utf-8")
|
|
64
|
+
|
|
65
|
+
def to_qubo_matrix(
|
|
66
|
+
self, docplex_model: DOCplexModel
|
|
67
|
+
) -> Tuple[List[List[float]], partial]:
|
|
68
|
+
file = tempfile.NamedTemporaryFile(delete=False)
|
|
69
|
+
with open(file.name, "wb") as tmp:
|
|
70
|
+
pickle.dump(docplex_model, tmp)
|
|
71
|
+
response = self._client.post(
|
|
72
|
+
f"{self._endpoint}/to-qubo-matrix", files={"file": (file.name, file.file)}
|
|
73
|
+
)
|
|
74
|
+
retrieved_matrix = MatrixSchema.validate(response.json())
|
|
75
|
+
return retrieved_matrix.matrix, partial(
|
|
76
|
+
self.inverter,
|
|
77
|
+
var_indices=retrieved_matrix.variable_indices,
|
|
78
|
+
inverter_bqm=CQMToBQMInverter.from_dict(retrieved_matrix.inverter.dict()),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def to_bqm(
|
|
82
|
+
self, docplex_model: DOCplexModel
|
|
83
|
+
) -> Tuple[dimod.BinaryQuadraticModel, CQMToBQMInverter]:
|
|
84
|
+
file = tempfile.NamedTemporaryFile(delete=False)
|
|
85
|
+
with open(file.name, "wb") as tmp:
|
|
86
|
+
pickle.dump(docplex_model, tmp)
|
|
87
|
+
response = self._client.post(
|
|
88
|
+
f"{self._endpoint}/to-bqm", files={"file": (file.name, file.file)}
|
|
89
|
+
)
|
|
90
|
+
retrieved_bqm = BQMResultSchema.validate(response.json())
|
|
91
|
+
|
|
92
|
+
quadratic: Dict[Tuple[str, str], float] = {}
|
|
93
|
+
for key, value in retrieved_bqm.bqm.quadratic.items():
|
|
94
|
+
split_key = tuple(key.split(","))
|
|
95
|
+
if len(split_key) != 2:
|
|
96
|
+
raise TransformationException
|
|
97
|
+
quadratic[split_key[0], split_key[1]] = value
|
|
98
|
+
try:
|
|
99
|
+
bqm = dimod.BinaryQuadraticModel(
|
|
100
|
+
retrieved_bqm.bqm.linear,
|
|
101
|
+
quadratic,
|
|
102
|
+
offset=retrieved_bqm.bqm.offset,
|
|
103
|
+
vartype=retrieved_bqm.bqm.var_type,
|
|
104
|
+
)
|
|
105
|
+
except Exception:
|
|
106
|
+
raise TransformationException()
|
|
107
|
+
inverter = CQMToBQMInverter.from_dict(retrieved_bqm.inverter.dict())
|
|
108
|
+
return bqm, inverter
|
|
109
|
+
|
|
110
|
+
def to_cqm(self, docplex_model: DOCplexModel) -> ConstrainedQuadraticModel:
|
|
111
|
+
file = tempfile.NamedTemporaryFile(delete=False)
|
|
112
|
+
with open(file.name, "wb") as tmp:
|
|
113
|
+
pickle.dump(docplex_model, tmp)
|
|
114
|
+
response = self._client.post(
|
|
115
|
+
f"{self._endpoint}/to-cqm", files={"file": (file.name, file.file)}
|
|
116
|
+
)
|
|
117
|
+
cqm = ConstrainedQuadraticModel.from_file(response.content)
|
|
118
|
+
return cqm
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
from luna_sdk.interfaces.info_repo_i import IInfoRepo
|
|
4
|
+
from luna_sdk.schemas.solver_info import SolverInfo
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class InfoRepo(IInfoRepo):
|
|
8
|
+
_endpoint = "/"
|
|
9
|
+
|
|
10
|
+
_endpoint_solvers = "/solvers"
|
|
11
|
+
_endpoint_providers = "/providers"
|
|
12
|
+
|
|
13
|
+
def solvers_available(
|
|
14
|
+
self, solver_name: Optional[str] = None
|
|
15
|
+
) -> Dict[str, Dict[str, SolverInfo]]:
|
|
16
|
+
params = {}
|
|
17
|
+
if solver_name:
|
|
18
|
+
params["solver_name"] = solver_name
|
|
19
|
+
|
|
20
|
+
response = self._client.get(
|
|
21
|
+
f"{self._endpoint_solvers}/available",
|
|
22
|
+
params=params,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
response.raise_for_status()
|
|
26
|
+
|
|
27
|
+
json: Dict[str, Dict[str, Any]] = response.json()
|
|
28
|
+
to_return: Dict[str, Dict[str, SolverInfo]] = {}
|
|
29
|
+
for provider in json:
|
|
30
|
+
to_return[provider] = {}
|
|
31
|
+
for solver in json[provider]:
|
|
32
|
+
to_return[provider][solver] = SolverInfo.model_validate(
|
|
33
|
+
json[provider][solver]
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return to_return
|
|
37
|
+
|
|
38
|
+
def providers_available(self) -> List[str]:
|
|
39
|
+
response = self._client.get(
|
|
40
|
+
f"{self._endpoint_providers}/available",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
response.raise_for_status()
|
|
44
|
+
|
|
45
|
+
return [i for i in response.json()]
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pickle
|
|
3
|
+
import tempfile
|
|
4
|
+
from functools import partial
|
|
5
|
+
from typing import Tuple, List, Dict
|
|
6
|
+
|
|
7
|
+
import dimod
|
|
8
|
+
from dimod import ConstrainedQuadraticModel
|
|
9
|
+
from dimod.constrained.constrained import CQMToBQMInverter
|
|
10
|
+
from docplex.mp.model import Model as DOCplexModel
|
|
11
|
+
from qiskit_optimization import QuadraticProgram
|
|
12
|
+
|
|
13
|
+
from luna_sdk.exceptions.transformation import TransformationException
|
|
14
|
+
from luna_sdk.interfaces.lp_repo_i import ILPRepo
|
|
15
|
+
from luna_sdk.schemas.transformations.bqm import BQMResultSchema, BQMSchema
|
|
16
|
+
from luna_sdk.schemas.transformations.matrix import MatrixSchema
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LPRepo(ILPRepo):
|
|
20
|
+
_endpoint = "/transformations/lp"
|
|
21
|
+
|
|
22
|
+
def _send_request_with_pickle_file_response(self, lp_string: str, endpoint: str):
|
|
23
|
+
file = tempfile.NamedTemporaryFile(delete=False, suffix=".lp")
|
|
24
|
+
with open(file.name, "w") as tmp:
|
|
25
|
+
tmp.write(lp_string)
|
|
26
|
+
response = self._client.post(endpoint, files={"file": (file.name, file.file)})
|
|
27
|
+
os.remove(file.name)
|
|
28
|
+
try:
|
|
29
|
+
parsed_model = pickle.loads(response.content)
|
|
30
|
+
except Exception:
|
|
31
|
+
raise TransformationException()
|
|
32
|
+
return parsed_model
|
|
33
|
+
|
|
34
|
+
def to_qubo_qiskit(self, lp_string: str) -> QuadraticProgram:
|
|
35
|
+
qubo_qiskit_model = self._send_request_with_pickle_file_response(
|
|
36
|
+
lp_string, f"{self._endpoint}/to-qubo-qiskit"
|
|
37
|
+
)
|
|
38
|
+
try:
|
|
39
|
+
assert isinstance(qubo_qiskit_model, QuadraticProgram)
|
|
40
|
+
except AssertionError:
|
|
41
|
+
raise TransformationException()
|
|
42
|
+
return qubo_qiskit_model
|
|
43
|
+
|
|
44
|
+
def to_docplex(self, lp_string: str) -> DOCplexModel:
|
|
45
|
+
docplex_model = self._send_request_with_pickle_file_response(
|
|
46
|
+
lp_string, f"{self._endpoint}/to-docplex"
|
|
47
|
+
)
|
|
48
|
+
try:
|
|
49
|
+
assert isinstance(docplex_model, DOCplexModel)
|
|
50
|
+
except AssertionError:
|
|
51
|
+
raise TransformationException()
|
|
52
|
+
return docplex_model
|
|
53
|
+
|
|
54
|
+
def to_qubo_matrix(self, lp_string: str) -> Tuple[List[List[float]], partial]:
|
|
55
|
+
file = tempfile.NamedTemporaryFile(delete=False, suffix=".lp")
|
|
56
|
+
with open(file.name, "w") as tmp:
|
|
57
|
+
tmp.write(lp_string)
|
|
58
|
+
response = self._client.post(
|
|
59
|
+
f"{self._endpoint}/to-qubo-matrix", files={"file": (file.name, file.file)}
|
|
60
|
+
)
|
|
61
|
+
retrieved_matrix = MatrixSchema.validate(response.json())
|
|
62
|
+
return retrieved_matrix.matrix, partial(
|
|
63
|
+
self.inverter,
|
|
64
|
+
var_indices=retrieved_matrix.variable_indices,
|
|
65
|
+
inverter_bqm=CQMToBQMInverter.from_dict(retrieved_matrix.inverter.dict()),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def to_bqm(
|
|
69
|
+
self, lp_string: str
|
|
70
|
+
) -> Tuple[dimod.BinaryQuadraticModel, CQMToBQMInverter]:
|
|
71
|
+
file = tempfile.NamedTemporaryFile(delete=False, suffix=".lp")
|
|
72
|
+
with open(file.name, "w") as tmp:
|
|
73
|
+
tmp.write(lp_string)
|
|
74
|
+
response = self._client.post(
|
|
75
|
+
f"{self._endpoint}/to-bqm", files={"file": (file.name, file.file)}
|
|
76
|
+
)
|
|
77
|
+
retrieved_bqm = BQMResultSchema.validate(response.json())
|
|
78
|
+
|
|
79
|
+
quadratic: Dict[Tuple[str, str], float] = {}
|
|
80
|
+
for key, value in retrieved_bqm.bqm.quadratic.items():
|
|
81
|
+
split_key = tuple(key.split(","))
|
|
82
|
+
if len(split_key) != 2:
|
|
83
|
+
raise TransformationException
|
|
84
|
+
quadratic[split_key[0], split_key[1]] = value
|
|
85
|
+
try:
|
|
86
|
+
bqm = dimod.BinaryQuadraticModel(
|
|
87
|
+
retrieved_bqm.bqm.linear,
|
|
88
|
+
quadratic,
|
|
89
|
+
offset=retrieved_bqm.bqm.offset,
|
|
90
|
+
vartype=retrieved_bqm.bqm.var_type,
|
|
91
|
+
)
|
|
92
|
+
except Exception:
|
|
93
|
+
raise TransformationException()
|
|
94
|
+
inverter = CQMToBQMInverter.from_dict(retrieved_bqm.inverter.dict())
|
|
95
|
+
return bqm, inverter
|
|
96
|
+
|
|
97
|
+
def to_cqm(self, lp_string: str) -> ConstrainedQuadraticModel:
|
|
98
|
+
file = tempfile.NamedTemporaryFile(delete=False, suffix=".lp")
|
|
99
|
+
with open(file.name, "w") as tmp:
|
|
100
|
+
tmp.write(lp_string)
|
|
101
|
+
response = self._client.post(
|
|
102
|
+
f"{self._endpoint}/to-cqm", files={"file": (file.name, file.file)}
|
|
103
|
+
)
|
|
104
|
+
cqm = ConstrainedQuadraticModel.from_file(response.content)
|
|
105
|
+
return cqm
|