qhyper 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- {qhyper-0.2.0/qhyper.egg-info → qhyper-0.2.2}/PKG-INFO +4 -4
- qhyper-0.2.2/QHyper/solvers/classical/__init__.py +0 -0
- qhyper-0.2.2/QHyper/solvers/classical/gurobi.py +87 -0
- qhyper-0.2.2/QHyper/solvers/gurobi/__init__.py +0 -0
- qhyper-0.2.2/QHyper/solvers/quantum_annealing/__init__.py +0 -0
- qhyper-0.2.2/QHyper/solvers/quantum_annealing/advantage.py +192 -0
- qhyper-0.2.2/QHyper/solvers/quantum_annealing/cqm.py +81 -0
- qhyper-0.2.2/QHyper/solvers/quantum_annealing/dqm.py +64 -0
- {qhyper-0.2.0 → qhyper-0.2.2/qhyper.egg-info}/PKG-INFO +4 -4
- {qhyper-0.2.0 → qhyper-0.2.2}/qhyper.egg-info/SOURCES.txt +7 -0
- qhyper-0.2.2/qhyper.egg-info/requires.txt +8 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/setup.py +1 -1
- qhyper-0.2.0/qhyper.egg-info/requires.txt +0 -8
- {qhyper-0.2.0 → qhyper-0.2.2}/LICENSE.txt +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/__init__.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/constraint.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/converter.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/__init__.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/base.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/basinhopping.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/cem.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/dummy.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/grid_search.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/qml_gradient_descent.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/random.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/scipy_minimizer.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/optimizers/util.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/parser.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/polynomial.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/problems/__init__.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/problems/base.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/problems/community_detection.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/problems/knapsack.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/problems/maxcut.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/problems/tsp.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/problems/workflow_scheduling.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/__init__.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/base.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/__init__.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/base.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/eval_funcs/__init__.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/eval_funcs/base.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/eval_funcs/wfeval.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/pqc/__init__.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/pqc/base.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/pqc/h_qaoa.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/pqc/mixers.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/pqc/qaoa.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/pqc/qml_qaoa.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/solvers/vqa/pqc/wf_qaoa.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/QHyper/util.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/README.md +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/qhyper.egg-info/dependency_links.txt +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/qhyper.egg-info/top_level.txt +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/setup.cfg +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/tests/test_converter.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/tests/test_optimizers.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/tests/test_optimizers_full.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/tests/test_problems.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/tests/test_util.py +0 -0
- {qhyper-0.2.0 → qhyper-0.2.2}/tests/test_vqa.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qhyper
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Quantum and classical problem solvers
|
|
5
5
|
Author: ACK Cyfronet AGH
|
|
6
6
|
Author-email: tomasz.lamza@cyfronet.pl
|
|
@@ -14,10 +14,10 @@ Classifier: Operating System :: MacOS :: MacOS X
|
|
|
14
14
|
Classifier: Operating System :: Microsoft :: Windows
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE.txt
|
|
17
|
-
Requires-Dist: numpy
|
|
18
|
-
Requires-Dist: PennyLane
|
|
17
|
+
Requires-Dist: numpy==1.23.4
|
|
18
|
+
Requires-Dist: PennyLane==0.33.1
|
|
19
19
|
Requires-Dist: tdqm
|
|
20
|
-
Requires-Dist: sympy
|
|
20
|
+
Requires-Dist: sympy==1.11.1
|
|
21
21
|
Requires-Dist: dwave-system
|
|
22
22
|
Requires-Dist: gurobipy
|
|
23
23
|
Requires-Dist: pandas
|
|
File without changes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# This work was supported by the EuroHPC PL infrastructure funded at the
|
|
2
|
+
# Smart Growth Operational Programme (2014-2020), Measure 4.2
|
|
3
|
+
# under the grant agreement no. POIR.04.02.00-00-D014/20-00
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from typing import Any, Optional
|
|
7
|
+
|
|
8
|
+
import gurobipy as gp
|
|
9
|
+
from QHyper.problems.base import Problem
|
|
10
|
+
from QHyper.solvers.base import Solver
|
|
11
|
+
from QHyper.polynomial import Polynomial
|
|
12
|
+
from QHyper.constraint import Operator
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def polynomial_to_gurobi(gurobi_vars: dict[str, Any], poly: Polynomial) -> Any:
|
|
16
|
+
cost_function_1: float = 0
|
|
17
|
+
for vars, coeff in poly.terms.items():
|
|
18
|
+
tmp = 1
|
|
19
|
+
for v in vars:
|
|
20
|
+
tmp *= gurobi_vars[v]
|
|
21
|
+
cost_function_1 += tmp * coeff
|
|
22
|
+
return cost_function_1
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Gurobi(Solver): # todo works only for quadratic expressions
|
|
26
|
+
"""
|
|
27
|
+
Gurobi solver class.
|
|
28
|
+
|
|
29
|
+
Attributes
|
|
30
|
+
----------
|
|
31
|
+
problem : Problem
|
|
32
|
+
The problem to be solved.
|
|
33
|
+
model_name : str, optional
|
|
34
|
+
The name of the gurobi model.
|
|
35
|
+
mip_gap : float | None, optional
|
|
36
|
+
The MIP gap.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
problem: Problem
|
|
40
|
+
model_name: str
|
|
41
|
+
mip_gap: float | None
|
|
42
|
+
|
|
43
|
+
def __init__(self, problem: Problem, model_name: str = "",
|
|
44
|
+
mip_gap: float | None = None) -> None:
|
|
45
|
+
self.problem = problem
|
|
46
|
+
self.model_name = model_name
|
|
47
|
+
self.mip_gap = mip_gap
|
|
48
|
+
|
|
49
|
+
def solve(self, params_inits: Optional[dict[str, Any]] = None) -> Any:
|
|
50
|
+
gpm = gp.Model(self.model_name)
|
|
51
|
+
if self.mip_gap:
|
|
52
|
+
gpm.Params.MIPGap = self.mip_gap
|
|
53
|
+
|
|
54
|
+
vars = {
|
|
55
|
+
str(var_name): gpm.addVar(vtype=gp.GRB.BINARY, name=str(var_name))
|
|
56
|
+
for var_name in self.problem.objective_function.get_variables().union(
|
|
57
|
+
[con.get_variables() for con in self.problem.constraints]
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
objective_function = polynomial_to_gurobi(
|
|
62
|
+
vars, self.problem.objective_function
|
|
63
|
+
)
|
|
64
|
+
gpm.setObjective(objective_function, gp.GRB.MINIMIZE)
|
|
65
|
+
|
|
66
|
+
for i, constraint in enumerate(self.problem.constraints):
|
|
67
|
+
lhs = polynomial_to_gurobi(vars, constraint.lhs)
|
|
68
|
+
rhs = polynomial_to_gurobi(vars, constraint.rhs)
|
|
69
|
+
if constraint.operator == Operator.EQ:
|
|
70
|
+
gpm.addConstr(lhs == rhs, f"constr_{i}")
|
|
71
|
+
elif constraint.operator == Operator.LE:
|
|
72
|
+
gpm.addConstr(lhs <= rhs, f"constr_{i}")
|
|
73
|
+
elif constraint.operator == Operator.GE:
|
|
74
|
+
gpm.addConstr(lhs >= rhs, f"constr_{i}")
|
|
75
|
+
|
|
76
|
+
gpm.update()
|
|
77
|
+
gpm.optimize()
|
|
78
|
+
|
|
79
|
+
# print("Status ", gpm.Status)
|
|
80
|
+
# print("Is optimal? ", GRB.OPTIMAL)
|
|
81
|
+
|
|
82
|
+
allvars = gpm.getVars()
|
|
83
|
+
solution = {}
|
|
84
|
+
for v in allvars:
|
|
85
|
+
solution[v.VarName] = v.X
|
|
86
|
+
|
|
87
|
+
return solution
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
import numpy as np
|
|
3
|
+
import numpy.typing as npt
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
|
|
7
|
+
from QHyper.problems.base import Problem
|
|
8
|
+
from QHyper.solvers.base import Solver, SolverResult, SolverConfigException
|
|
9
|
+
from QHyper.converter import Converter
|
|
10
|
+
from QHyper.constraint import Polynomial
|
|
11
|
+
from QHyper.util import weighted_avg_evaluation
|
|
12
|
+
from QHyper.optimizers import (
|
|
13
|
+
OPTIMIZERS, Optimizer, OptimizationResult)
|
|
14
|
+
|
|
15
|
+
from dwave.system import DWaveSampler, EmbeddingComposite
|
|
16
|
+
from dimod import BinaryQuadraticModel
|
|
17
|
+
from dimod.sampleset import SampleSet
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class OptimizerFunction:
|
|
22
|
+
embedding_compose: DWaveSampler
|
|
23
|
+
problem: Problem
|
|
24
|
+
num_reads: int
|
|
25
|
+
chain_strength: float | None
|
|
26
|
+
|
|
27
|
+
def __call__(self, args: npt.NDArray) -> OptimizationResult:
|
|
28
|
+
sampleset = self.run_advantage(args)
|
|
29
|
+
|
|
30
|
+
result = np.recarray(
|
|
31
|
+
(len(sampleset),),
|
|
32
|
+
dtype=([(v, int) for v in sampleset.variables]
|
|
33
|
+
+ [('probability', float)]
|
|
34
|
+
+ [('energy', float)])
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
num_of_shots = sampleset.record.num_occurrences.sum()
|
|
38
|
+
for i, solution in enumerate(sampleset.data()):
|
|
39
|
+
for var in sampleset.variables:
|
|
40
|
+
result[var][i] = solution.sample[var]
|
|
41
|
+
|
|
42
|
+
result['probability'][i] = (
|
|
43
|
+
solution.num_occurrences / num_of_shots)
|
|
44
|
+
result['energy'][i] = solution.energy
|
|
45
|
+
|
|
46
|
+
result_energy = weighted_avg_evaluation(
|
|
47
|
+
result, self.problem.get_score, penalty=0
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return OptimizationResult(result_energy, args)
|
|
51
|
+
|
|
52
|
+
def run_advantage(self, args: npt.NDArray) -> SampleSet:
|
|
53
|
+
qubo = Converter.create_qubo(self.problem, args)
|
|
54
|
+
qubo_terms, offset = convert_qubo_keys(qubo)
|
|
55
|
+
bqm = BinaryQuadraticModel.from_qubo(qubo_terms, offset=offset)
|
|
56
|
+
sampleset = self.embedding_compose.sample(
|
|
57
|
+
bqm, num_reads=self.num_reads, chain_strength=self.chain_strength
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return sampleset
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Advantage(Solver):
|
|
64
|
+
"""
|
|
65
|
+
Class for solving a problem using Advantage
|
|
66
|
+
|
|
67
|
+
Attributes
|
|
68
|
+
----------
|
|
69
|
+
problem : Problem
|
|
70
|
+
The problem to be solved.
|
|
71
|
+
version: str, default 'Advantage_system5.4'
|
|
72
|
+
The version of the D-Wave Advantage system.
|
|
73
|
+
region : str, default 'eu-central-1'
|
|
74
|
+
The region in which D-Wave Advantage is available.
|
|
75
|
+
num_reads: int, default 1
|
|
76
|
+
The number of times the solver is run.
|
|
77
|
+
chain_strength: float or None, default None
|
|
78
|
+
The coupling strength between qubits.
|
|
79
|
+
hyper_optimizer: Optimizer or None, default None
|
|
80
|
+
The optimizer for hyperparameters.
|
|
81
|
+
params_inits: dict[str, Any] | None, default None
|
|
82
|
+
The initial parameter settings.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def __init__(self, problem: Problem,
|
|
86
|
+
version: str = "Advantage_system5.4",
|
|
87
|
+
region: str = "eu-central-1",
|
|
88
|
+
num_reads: int = 1,
|
|
89
|
+
chain_strength: float | None = None,
|
|
90
|
+
hyper_optimizer: Optimizer | None = None,
|
|
91
|
+
params_inits: dict[str, Any] | None = None) -> None:
|
|
92
|
+
self.problem = problem
|
|
93
|
+
self.version = version
|
|
94
|
+
self.region = region
|
|
95
|
+
self.num_reads = num_reads
|
|
96
|
+
self.chain_strength = chain_strength
|
|
97
|
+
self.hyper_optimizer = hyper_optimizer
|
|
98
|
+
self.params_inits = params_inits
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_config(cls, problem: Problem, config: dict[str, Any]) -> 'Advantage':
|
|
102
|
+
if not (hyper_optimizer_config := config.pop('hyper_optimizer', None)):
|
|
103
|
+
hyper_optimizer = None
|
|
104
|
+
elif not (hyper_optimizer_type := hyper_optimizer_config.pop('type', None)):
|
|
105
|
+
raise SolverConfigException(
|
|
106
|
+
"Optimizer type was not provided")
|
|
107
|
+
elif not (hyper_optimizer_class := OPTIMIZERS.get(
|
|
108
|
+
hyper_optimizer_type, None)):
|
|
109
|
+
raise SolverConfigException(
|
|
110
|
+
f"There is no {hyper_optimizer_type} optimizer type")
|
|
111
|
+
else:
|
|
112
|
+
hyper_optimizer = hyper_optimizer_class(**hyper_optimizer_config)
|
|
113
|
+
|
|
114
|
+
version = config.pop('version', "Advantage_system5.4")
|
|
115
|
+
region = config.pop('region', "eu-central-1")
|
|
116
|
+
num_reads = config.pop('num_reads', 1)
|
|
117
|
+
chain_strength = config.pop('chain_strength', None)
|
|
118
|
+
|
|
119
|
+
params_inits = config.pop('params_inits', None)
|
|
120
|
+
|
|
121
|
+
return cls(problem, version, region, num_reads, chain_strength, hyper_optimizer, params_inits)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def solve(self, params_inits: dict[str, Any] = {}) -> Any:
|
|
125
|
+
if not params_inits:
|
|
126
|
+
params_inits = self.params_inits
|
|
127
|
+
sampler = DWaveSampler(solver=self.version, region=self.region)
|
|
128
|
+
embedding_compose = EmbeddingComposite(sampler)
|
|
129
|
+
|
|
130
|
+
opt_result = None
|
|
131
|
+
wrapper = OptimizerFunction(
|
|
132
|
+
embedding_compose, self.problem, self.num_reads, self.chain_strength
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if self.hyper_optimizer:
|
|
136
|
+
args = (
|
|
137
|
+
np.array(params_inits["weights"]).flatten() if params_inits["weights"]
|
|
138
|
+
else None
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
result = self.hyper_optimizer.minimize(wrapper, args)
|
|
142
|
+
opt_result = result.params
|
|
143
|
+
|
|
144
|
+
qubo_arguments = opt_result if self.hyper_optimizer else params_inits.get("weights", [])
|
|
145
|
+
solutions = wrapper.run_advantage(qubo_arguments)
|
|
146
|
+
|
|
147
|
+
result = np.recarray(
|
|
148
|
+
(len(solutions),),
|
|
149
|
+
dtype=([(v, int) for v in solutions.variables]
|
|
150
|
+
+ [('probability', float)]
|
|
151
|
+
+ [('energy', float)])
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
num_of_shots = solutions.record.num_occurrences.sum()
|
|
155
|
+
for i, solution in enumerate(solutions.data()):
|
|
156
|
+
for var in solutions.variables:
|
|
157
|
+
result[var][i] = solution.sample[var]
|
|
158
|
+
|
|
159
|
+
result['probability'][i] = (
|
|
160
|
+
solution.num_occurrences / num_of_shots)
|
|
161
|
+
result['energy'][i] = solution.energy
|
|
162
|
+
|
|
163
|
+
return SolverResult(
|
|
164
|
+
result,
|
|
165
|
+
{"weights": qubo_arguments},
|
|
166
|
+
[]
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def prepare_solver_result(self, result: defaultdict, arguments: npt.NDArray) -> SolverResult:
|
|
170
|
+
sorted_keys = sorted(result.keys(), key=lambda x: int(''.join(filter(str.isdigit, x))))
|
|
171
|
+
values = ''.join(str(result[key]) for key in sorted_keys)
|
|
172
|
+
probabilities = {values: 100.0}
|
|
173
|
+
parameters = {values: arguments}
|
|
174
|
+
|
|
175
|
+
return SolverResult(probabilities, parameters)
|
|
176
|
+
|
|
177
|
+
def convert_qubo_keys(qubo: Polynomial) -> tuple[dict[tuple, float], float]:
|
|
178
|
+
new_qubo = defaultdict(float)
|
|
179
|
+
offset = 0.0
|
|
180
|
+
|
|
181
|
+
qubo, offset = qubo.separate_const()
|
|
182
|
+
for k, v in qubo.terms.items():
|
|
183
|
+
if len(k) == 1:
|
|
184
|
+
new_key = (k[0], k[0])
|
|
185
|
+
elif len(k) > 2:
|
|
186
|
+
raise ValueError("Only supports quadratic model")
|
|
187
|
+
else:
|
|
188
|
+
new_key = k
|
|
189
|
+
|
|
190
|
+
new_qubo[new_key] += v
|
|
191
|
+
|
|
192
|
+
return (new_qubo, offset)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# This work was supported by the EuroHPC PL infrastructure funded at the
|
|
2
|
+
# Smart Growth Operational Programme (2014-2020), Measure 4.2
|
|
3
|
+
# under the grant agreement no. POIR.04.02.00-00-D014/20-00
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import numpy as np
|
|
8
|
+
from dwave.system import LeapHybridCQMSampler
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from QHyper.converter import Converter
|
|
13
|
+
from QHyper.problems import Problem
|
|
14
|
+
from QHyper.solvers import Solver, SolverResult
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
DWAVE_API_TOKEN = os.environ.get('DWAVE_API_TOKEN')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CQM(Solver):
|
|
21
|
+
"""
|
|
22
|
+
Class for solving a problem using the
|
|
23
|
+
Constrained Quadratic Model (CQM) approach.
|
|
24
|
+
|
|
25
|
+
Attributes
|
|
26
|
+
----------
|
|
27
|
+
problem : Problem
|
|
28
|
+
The problem to be solved.
|
|
29
|
+
time : float
|
|
30
|
+
The maximum time allowed for the CQM solver.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, problem: Problem, time: float) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
problem : Problem
|
|
38
|
+
The problem to be solved.
|
|
39
|
+
time : float
|
|
40
|
+
The maximum time allowed for the CQM solver.
|
|
41
|
+
"""
|
|
42
|
+
self.problem: Problem = problem
|
|
43
|
+
self.time: float = time
|
|
44
|
+
|
|
45
|
+
def solve(self, params_inits: dict[str, Any] = {}) -> SolverResult:
|
|
46
|
+
"""
|
|
47
|
+
Solve the problem using the CQM approach.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
Any
|
|
52
|
+
The solution to the problem.
|
|
53
|
+
"""
|
|
54
|
+
converter = Converter()
|
|
55
|
+
cqm = converter.to_cqm(self.problem)
|
|
56
|
+
sampler = LeapHybridCQMSampler(token=DWAVE_API_TOKEN)
|
|
57
|
+
solutions = sampler.sample_cqm(cqm, self.time).aggregate()
|
|
58
|
+
|
|
59
|
+
recarray = np.recarray(
|
|
60
|
+
(len(solutions),),
|
|
61
|
+
dtype=([(v, int) for v in solutions.variables]
|
|
62
|
+
+ [('probability', float)]
|
|
63
|
+
+ [('energy', float)]
|
|
64
|
+
+ [('is_feasible', bool)])
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
num_of_shots = solutions.record.num_occurrences.sum()
|
|
68
|
+
for i, solution in enumerate(solutions.data()):
|
|
69
|
+
for var in solutions.variables:
|
|
70
|
+
recarray[var][i] = solution.sample[var]
|
|
71
|
+
|
|
72
|
+
recarray['probability'][i] = (
|
|
73
|
+
solution.num_occurrences / num_of_shots)
|
|
74
|
+
recarray['energy'][i] = solution.energy
|
|
75
|
+
recarray['is_feasible'][i] = solution.is_feasible
|
|
76
|
+
|
|
77
|
+
return SolverResult(
|
|
78
|
+
recarray,
|
|
79
|
+
{},
|
|
80
|
+
[]
|
|
81
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# This work was supported by the EuroHPC PL infrastructure funded at the
|
|
2
|
+
# Smart Growth Operational Programme (2014-2020), Measure 4.2
|
|
3
|
+
# under the grant agreement no. POIR.04.02.00-00-D014/20-00
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import numpy as np
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from dwave.system import LeapHybridDQMSampler
|
|
11
|
+
from QHyper.problems import Problem
|
|
12
|
+
from QHyper.solvers import Solver, SolverResult
|
|
13
|
+
from QHyper.converter import Converter
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
DWAVE_API_TOKEN = os.environ.get('DWAVE_API_TOKEN')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DQM(Solver):
|
|
20
|
+
"""
|
|
21
|
+
DQM solver class.
|
|
22
|
+
|
|
23
|
+
Attributes
|
|
24
|
+
----------
|
|
25
|
+
problem : Problem
|
|
26
|
+
The problem to be solved.
|
|
27
|
+
time : float
|
|
28
|
+
Maximum run time in seconds
|
|
29
|
+
cases: int, default 1
|
|
30
|
+
Number of variable cases (values)
|
|
31
|
+
1 is denoting binary variable.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, problem: Problem, time: float, cases: int = 1) -> None:
|
|
35
|
+
self.problem: Problem = problem
|
|
36
|
+
self.time: float = time
|
|
37
|
+
self.cases: int = cases
|
|
38
|
+
|
|
39
|
+
def solve(self, params_inits: dict[str, Any] = {}) -> SolverResult:
|
|
40
|
+
dqm = Converter.to_dqm(self.problem, self.cases)
|
|
41
|
+
sampler = LeapHybridDQMSampler(token=DWAVE_API_TOKEN)
|
|
42
|
+
solutions = sampler.sample_dqm(dqm, self.time)
|
|
43
|
+
|
|
44
|
+
recarray = np.recarray(
|
|
45
|
+
(len(solutions),),
|
|
46
|
+
dtype=([(v, int) for v in solutions.variables]
|
|
47
|
+
+ [('probability', float)]
|
|
48
|
+
+ [('energy', float)])
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
num_of_shots = solutions.record.num_occurrences.sum()
|
|
52
|
+
for i, solution in enumerate(solutions.data()):
|
|
53
|
+
for var in solutions.variables:
|
|
54
|
+
recarray[var][i] = solution.sample[var]
|
|
55
|
+
|
|
56
|
+
recarray['probability'][i] = (
|
|
57
|
+
solution.num_occurrences / num_of_shots)
|
|
58
|
+
recarray['energy'][i] = solution.energy
|
|
59
|
+
|
|
60
|
+
return SolverResult(
|
|
61
|
+
recarray,
|
|
62
|
+
{},
|
|
63
|
+
[]
|
|
64
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qhyper
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Quantum and classical problem solvers
|
|
5
5
|
Author: ACK Cyfronet AGH
|
|
6
6
|
Author-email: tomasz.lamza@cyfronet.pl
|
|
@@ -14,10 +14,10 @@ Classifier: Operating System :: MacOS :: MacOS X
|
|
|
14
14
|
Classifier: Operating System :: Microsoft :: Windows
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE.txt
|
|
17
|
-
Requires-Dist: numpy
|
|
18
|
-
Requires-Dist: PennyLane
|
|
17
|
+
Requires-Dist: numpy==1.23.4
|
|
18
|
+
Requires-Dist: PennyLane==0.33.1
|
|
19
19
|
Requires-Dist: tdqm
|
|
20
|
-
Requires-Dist: sympy
|
|
20
|
+
Requires-Dist: sympy==1.11.1
|
|
21
21
|
Requires-Dist: dwave-system
|
|
22
22
|
Requires-Dist: gurobipy
|
|
23
23
|
Requires-Dist: pandas
|
|
@@ -26,6 +26,13 @@ QHyper/problems/tsp.py
|
|
|
26
26
|
QHyper/problems/workflow_scheduling.py
|
|
27
27
|
QHyper/solvers/__init__.py
|
|
28
28
|
QHyper/solvers/base.py
|
|
29
|
+
QHyper/solvers/classical/__init__.py
|
|
30
|
+
QHyper/solvers/classical/gurobi.py
|
|
31
|
+
QHyper/solvers/gurobi/__init__.py
|
|
32
|
+
QHyper/solvers/quantum_annealing/__init__.py
|
|
33
|
+
QHyper/solvers/quantum_annealing/advantage.py
|
|
34
|
+
QHyper/solvers/quantum_annealing/cqm.py
|
|
35
|
+
QHyper/solvers/quantum_annealing/dqm.py
|
|
29
36
|
QHyper/solvers/vqa/__init__.py
|
|
30
37
|
QHyper/solvers/vqa/base.py
|
|
31
38
|
QHyper/solvers/vqa/eval_funcs/__init__.py
|
|
@@ -34,7 +34,7 @@ setup(
|
|
|
34
34
|
long_description_content_type="text/markdown",
|
|
35
35
|
long_description=LONG_DESCRIPTION,
|
|
36
36
|
packages=find_packages(exclude=['tests']),
|
|
37
|
-
install_requires=['numpy', 'PennyLane', 'tdqm', 'sympy', 'dwave-system', 'gurobipy', 'pandas', 'wfcommons'],
|
|
37
|
+
install_requires=['numpy==1.23.4', 'PennyLane==0.33.1', 'tdqm', 'sympy==1.11.1', 'dwave-system', 'gurobipy', 'pandas', 'wfcommons'],
|
|
38
38
|
keywords=['python', 'qhyper', 'quantum', 'solver', 'experiment'],
|
|
39
39
|
license='MIT',
|
|
40
40
|
classifiers=[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|