qhyper 0.dev1__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.
Files changed (41) hide show
  1. QHyper/__init__.py +0 -0
  2. QHyper/optimizers/__init__.py +17 -0
  3. QHyper/optimizers/base.py +39 -0
  4. QHyper/optimizers/basinhopping.py +79 -0
  5. QHyper/optimizers/cem.py +128 -0
  6. QHyper/optimizers/qml_gradient_descent.py +72 -0
  7. QHyper/optimizers/random.py +90 -0
  8. QHyper/optimizers/scipy_minimizer.py +65 -0
  9. QHyper/problems/__init__.py +0 -0
  10. QHyper/problems/base.py +62 -0
  11. QHyper/problems/community_detection.py +185 -0
  12. QHyper/problems/knapsack.py +176 -0
  13. QHyper/problems/maxcut.py +37 -0
  14. QHyper/problems/tsp.py +190 -0
  15. QHyper/problems/workflow_scheduling.py +220 -0
  16. QHyper/solvers/__init__.py +14 -0
  17. QHyper/solvers/base.py +86 -0
  18. QHyper/solvers/converter.py +128 -0
  19. QHyper/solvers/cqm/__init__.py +1 -0
  20. QHyper/solvers/cqm/cqm.py +66 -0
  21. QHyper/solvers/dqm/__init__.py +1 -0
  22. QHyper/solvers/dqm/dqm.py +23 -0
  23. QHyper/solvers/gurobi/__init__.py +1 -0
  24. QHyper/solvers/gurobi/gurobi.py +77 -0
  25. QHyper/solvers/vqa/__init__.py +25 -0
  26. QHyper/solvers/vqa/base.py +108 -0
  27. QHyper/solvers/vqa/eval_funcs/__init__.py +0 -0
  28. QHyper/solvers/vqa/eval_funcs/base.py +40 -0
  29. QHyper/solvers/vqa/eval_funcs/wfeval.py +32 -0
  30. QHyper/solvers/vqa/pqc/__init__.py +0 -0
  31. QHyper/solvers/vqa/pqc/base.py +133 -0
  32. QHyper/solvers/vqa/pqc/h_qaoa.py +86 -0
  33. QHyper/solvers/vqa/pqc/mixers.py +12 -0
  34. QHyper/solvers/vqa/pqc/qaoa.py +130 -0
  35. QHyper/solvers/vqa/pqc/wf_qaoa.py +80 -0
  36. QHyper/util.py +4 -0
  37. qhyper-0.dev1.dist-info/LICENSE.txt +21 -0
  38. qhyper-0.dev1.dist-info/METADATA +26 -0
  39. qhyper-0.dev1.dist-info/RECORD +41 -0
  40. qhyper-0.dev1.dist-info/WHEEL +5 -0
  41. qhyper-0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,108 @@
1
+ from dataclasses import dataclass
2
+ import numpy as np
3
+ from typing import Optional, Any, cast
4
+ import numpy.typing as npt
5
+
6
+ from QHyper.problems.base import Problem
7
+
8
+ from QHyper.optimizers import OPTIMIZERS_BY_NAME
9
+ from QHyper.optimizers.base import Optimizer
10
+ from .pqc.base import PQC
11
+
12
+ from QHyper.solvers.base import Solver
13
+ from QHyper.solvers.vqa import PQC_BY_NAME
14
+
15
+
16
+ @dataclass
17
+ class OptWrapper:
18
+ pqc: PQC
19
+ problem: Problem
20
+ hyper_params: npt.NDArray[np.float64]
21
+
22
+ def __call__(self, args: npt.NDArray[np.float64]) -> float:
23
+ return self.pqc.run_opt(self.problem, args, self.hyper_params)
24
+
25
+
26
+ @dataclass
27
+ class Wrapper:
28
+ pqc: PQC
29
+ problem: Problem
30
+ optimizer: Optional[Optimizer]
31
+ params_config: dict[str, Any]
32
+
33
+ def __call__(self, hargs: npt.NDArray[np.float64]) -> float:
34
+ opt_args = self.pqc.get_opt_args(self.params_config, hyper_args=hargs)
35
+ opt_wrapper = OptWrapper(self.pqc, self.problem, hargs)
36
+
37
+ if self.optimizer:
38
+ value, _ = self.optimizer.minimize(opt_wrapper, opt_args)
39
+ else:
40
+ value = opt_wrapper(opt_args)
41
+ return value
42
+
43
+
44
+ @dataclass
45
+ class VQA(Solver):
46
+ problem: Problem
47
+ pqc: PQC
48
+ optimizer: Optional[Optimizer]
49
+
50
+ def __init__(
51
+ self,
52
+ problem: Problem,
53
+ pqc: PQC | str = "",
54
+ optimizer: Optimizer | str = "",
55
+ hyper_optimizer: Optimizer = None,
56
+ config: dict[str, dict[str, Any]] = {}
57
+ ) -> None:
58
+ self.problem = problem
59
+ self.hyper_optimizer = hyper_optimizer
60
+
61
+ if isinstance(pqc, str):
62
+ if pqc == "":
63
+ try:
64
+ pqc = config['pqc'].pop('type')
65
+ except KeyError:
66
+ raise Exception("Configuration for PQC was not provided")
67
+ self.pqc = PQC_BY_NAME[cast(str, pqc)](**config.get('pqc', {}))
68
+ else:
69
+ self.pqc = pqc
70
+
71
+ if isinstance(optimizer, str):
72
+ if optimizer == "" and 'optimizer' not in config:
73
+ self.optimizer = None
74
+ else:
75
+ if optimizer == "":
76
+ optimizer = config['optimizer'].pop('type')
77
+ self.optimizer = OPTIMIZERS_BY_NAME[cast(str, optimizer)](
78
+ **config.get('optimizer', {}))
79
+ else:
80
+ self.optimizer = optimizer
81
+
82
+ def solve(self, params_inits: dict[str, Any]) -> Any:
83
+ hyper_args = self.pqc.get_hopt_args(params_inits)
84
+
85
+ if self.hyper_optimizer:
86
+ # TODO
87
+ wrapper = Wrapper(
88
+ self.pqc, self.problem, self.optimizer, params_inits)
89
+ _, best_hargs = self.hyper_optimizer.minimize(wrapper, hyper_args)
90
+ else:
91
+ best_hargs = hyper_args
92
+
93
+ opt_args = self.pqc.get_opt_args(params_inits, hyper_args=best_hargs)
94
+ opt_wrapper = OptWrapper(self.pqc, self.problem, hyper_args)
95
+ if self.optimizer:
96
+ _, best_opt_args = self.optimizer.minimize(opt_wrapper, opt_args)
97
+ else:
98
+ best_opt_args = opt_args
99
+
100
+ return self.pqc.get_params_init_format(best_opt_args, best_hargs)
101
+
102
+ def evaluate(
103
+ self, params_inits: dict[str, Any], print_results: bool = False
104
+ ) -> float:
105
+ hyper_args = self.pqc.get_hopt_args(params_inits)
106
+ opt_args = self.pqc.get_opt_args(params_inits)
107
+ return self.pqc.run_opt(
108
+ self.problem, opt_args, hyper_args, print_results)
File without changes
@@ -0,0 +1,40 @@
1
+ from abc import abstractmethod
2
+
3
+ from QHyper.problems.base import Problem
4
+
5
+
6
+ class EvalFunc:
7
+ """
8
+ Abstract base class for evaluation functions.
9
+
10
+ Methods
11
+ -------
12
+ evaluate(results, problem, const_params)
13
+ Evaluate the results based on the problem and constant parameters.
14
+ """
15
+
16
+ @abstractmethod
17
+ def evaluate(
18
+ self,
19
+ results: dict[str, float],
20
+ problem: Problem,
21
+ const_params: list[float]
22
+ ) -> float:
23
+ """
24
+ Evaluate the results based on the problem and constant parameters.
25
+
26
+ Parameters
27
+ ----------
28
+ results : dict[str, float]
29
+ The results to be evaluated.
30
+ problem : Problem
31
+ The problem definition.
32
+ const_params : list[float]
33
+ The constant parameters.
34
+
35
+ Returns
36
+ -------
37
+ float
38
+ The evaluation result.
39
+ """
40
+ ...
@@ -0,0 +1,32 @@
1
+ from .base import EvalFunc
2
+ from QHyper.problems.base import Problem
3
+
4
+
5
+ class WFEval(EvalFunc):
6
+ def __init__(self, penalty: float = 0) -> None:
7
+ self.penalty = penalty
8
+
9
+ def evaluate(
10
+ self,
11
+ results: dict[str, float],
12
+ problem: Problem,
13
+ const_params: list[float]
14
+ ) -> float:
15
+ score: float = 0
16
+
17
+ sorted_results = {
18
+ k: v for k, v in
19
+ sorted(
20
+ results.items(),
21
+ key=lambda item: item[1],
22
+ reverse=True
23
+ )[:40]
24
+ }
25
+
26
+ # print(sorted_results)
27
+ scaler = 1/sum([v for v in sorted_results.values()])
28
+ # print(scaler)
29
+
30
+ for result, prob in sorted_results.items():
31
+ score += scaler * prob * problem.get_score(result, self.penalty)
32
+ return score
File without changes
@@ -0,0 +1,133 @@
1
+ from abc import abstractmethod
2
+
3
+ import numpy as np
4
+ import numpy.typing as npt
5
+ from typing import Any, Optional
6
+
7
+ from QHyper.problems.base import Problem
8
+
9
+
10
+ PQCResults = tuple[dict[str, float], list[float]]
11
+
12
+
13
+ class PQC:
14
+ """
15
+ Abstract base class for Parameterized Quantum Circuit (PQC).
16
+
17
+ Attributes
18
+ ----------
19
+ pqc_type : str
20
+ Type of the parameterized quantum circuit.
21
+ """
22
+
23
+ pqc_type: str
24
+
25
+ @abstractmethod
26
+ def __init__(self, **kwargs: Any) -> None: ...
27
+
28
+ @abstractmethod
29
+ def run_opt(
30
+ self,
31
+ problem: Problem,
32
+ opt_args: npt.NDArray[np.float64],
33
+ hyper_args: npt.NDArray[np.float64]
34
+ ) -> float:
35
+ """
36
+ Run optimization using the PQC.
37
+
38
+ Parameters
39
+ ----------
40
+ problem : Problem
41
+ The problem to be solved.
42
+ opt_args : npt.NDArray[np.float64]
43
+ Optimization arguments.
44
+ hyper_args : npt.NDArray[np.float64]
45
+ Hyperparameter optimization arguments.
46
+
47
+ Returns
48
+ -------
49
+ float
50
+ The result of the optimization.
51
+ """
52
+ ...
53
+
54
+ @abstractmethod
55
+ def get_opt_args(
56
+ self,
57
+ params_init: dict[str, Any],
58
+ args: Optional[npt.NDArray[np.float64]] = None,
59
+ hyper_args: Optional[npt.NDArray[np.float64]] = None
60
+ ) -> npt.NDArray[np.float64]:
61
+ """
62
+ Get optimization arguments. This method should return arguments for
63
+ optimizer. These arguments may come from initial parameters
64
+ (params_init) or might be override by args or hyper_args.
65
+
66
+ Parameters
67
+ ----------
68
+ params_init : dict[str, Any]
69
+ Initial parameters for the optimization.
70
+ args : Optional[npt.NDArray[np.float64]], optional
71
+ Additional arguments, by default None.
72
+ hyper_args : Optional[npt.NDArray[np.float64]], optional
73
+ Hyperparameter optimization arguments, by default None.
74
+
75
+ Returns
76
+ -------
77
+ npt.NDArray[np.float64]
78
+ Optimization arguments.
79
+ """
80
+ ...
81
+
82
+ @abstractmethod
83
+ def get_hopt_args(
84
+ self,
85
+ params_init: dict[str, Any],
86
+ args: Optional[npt.NDArray[np.float64]] = None,
87
+ hyper_args: Optional[npt.NDArray[np.float64]] = None
88
+ ) -> npt.NDArray[np.float64]:
89
+ """
90
+ Get hyperparameter optimization arguments.
91
+ This method should return arguments for hyperoptimizer.
92
+ These arguments may come from initial parameters
93
+ (params_init) or might be override by args or hyper_args.
94
+
95
+ Parameters
96
+ ----------
97
+ params_init : dict[str, Any]
98
+ Initial parameters for the optimization.
99
+ args : Optional[npt.NDArray[np.float64]], optional
100
+ Additional arguments, by default None.
101
+ hyper_args : Optional[npt.NDArray[np.float64]], optional
102
+ Hyperparameter optimization arguments, by default None.
103
+
104
+ Returns
105
+ -------
106
+ npt.NDArray[np.float64]
107
+ Hyperparameter optimization arguments.
108
+ """
109
+ ...
110
+
111
+ @abstractmethod
112
+ def get_params_init_format(
113
+ self,
114
+ opt_args: npt.NDArray[np.float64],
115
+ hyper_args: npt.NDArray[np.float64]
116
+ ) -> dict[str, Any]:
117
+ """
118
+ Get initial params format. Method changes opt_args and hyper_args into
119
+ dict in same format at provided params_init in different methods.
120
+
121
+ Parameters
122
+ ----------
123
+ opt_args : npt.NDArray[np.float64]
124
+ Optimization arguments.
125
+ hyper_args : npt.NDArray[np.float64]
126
+ Hyperparameter optimization arguments.
127
+
128
+ Returns
129
+ -------
130
+ dict[str, Any]
131
+ Initial arguments.
132
+ """
133
+ ...
@@ -0,0 +1,86 @@
1
+ from dataclasses import dataclass
2
+ import pennylane as qml
3
+ import numpy as np
4
+
5
+ import numpy.typing as npt
6
+ from typing import Any, Callable, cast, Optional
7
+
8
+ from QHyper.problems.base import Problem
9
+
10
+ from QHyper.solvers.vqa.pqc.qaoa import QAOA
11
+ from QHyper.solvers.converter import Converter
12
+ from QHyper.solvers.vqa.eval_funcs.wfeval import WFEval
13
+
14
+
15
+ @dataclass
16
+ class HQAOA(QAOA):
17
+ layers: int = 3
18
+ mixer: str = "pl_x_mixer"
19
+ backend: str = "default.qubit"
20
+
21
+ def get_probs_func(self, problem: Problem, weights: list[float]
22
+ ) -> Callable[[npt.NDArray[np.float64]], list[float]]:
23
+ """Returns function that takes angles and returns probabilities
24
+
25
+ Parameters
26
+ ----------
27
+ weights : list[float]
28
+ weights for converting Problem to QUBO
29
+
30
+ Returns
31
+ -------
32
+ Callable[[list[float]], float]
33
+ Returns function that takes angles and returns probabilities
34
+ """
35
+ qubo = Converter.create_qubo(problem, weights)
36
+ cost_operator = self._create_cost_operator(qubo)
37
+
38
+ @qml.qnode(self.dev)
39
+ def probability_circuit(params: npt.NDArray[np.float64]
40
+ ) -> list[float]:
41
+ self._circuit(problem, params, cost_operator)
42
+ return cast(list[float],
43
+ qml.probs(wires=[str(x) for x in problem.variables]))
44
+
45
+ return cast(Callable[[npt.NDArray[np.float64]], list[float]],
46
+ probability_circuit)
47
+
48
+ def run_opt(
49
+ self,
50
+ problem: Problem,
51
+ opt_args: npt.NDArray[np.float64],
52
+ hyper_args: npt.NDArray[np.float64]
53
+ ) -> float:
54
+ self.dev = qml.device(
55
+ self.backend, wires=[str(x) for x in problem.variables])
56
+ # const_params = params_config['weights']
57
+ weights = list(opt_args[:1 + len(problem.constraints)])
58
+ probs = self.get_probs_func(problem, list(weights))(
59
+ opt_args[1 + len(problem.constraints):].reshape(2, -1))
60
+ results_by_probabilites = {
61
+ format(result, 'b').zfill(len(problem.variables)): float(prob)
62
+ for result, prob in enumerate(probs)
63
+ }
64
+ return WFEval().evaluate(results_by_probabilites, problem, weights)
65
+
66
+ def get_opt_args(
67
+ self,
68
+ params_init: dict[str, Any],
69
+ args: Optional[npt.NDArray[np.float64]] = None,
70
+ hyper_args: Optional[npt.NDArray[np.float64]] = None
71
+ ) -> npt.NDArray[np.float64]:
72
+ return np.concatenate((
73
+ hyper_args if hyper_args is not None
74
+ else params_init['hyper_args'],
75
+ np.array(args if args else params_init['angles']).flatten()
76
+ ))
77
+
78
+ def get_params_init_format(
79
+ self,
80
+ opt_args: npt.NDArray[np.float64],
81
+ hyper_args: npt.NDArray[np.float64]
82
+ ) -> dict[str, Any]:
83
+ return {
84
+ 'angles': opt_args[len(hyper_args):],
85
+ 'hyper_args': opt_args[:len(hyper_args)],
86
+ }
@@ -0,0 +1,12 @@
1
+ import pennylane as qml
2
+
3
+ from typing import Iterable, Callable
4
+
5
+
6
+ def mixer(wires: Iterable[str]) -> qml.Hamiltonian:
7
+ return qml.qaoa.x_mixer(wires)
8
+
9
+
10
+ MIXERS_BY_NAME: dict[str, Callable[[Iterable[str]], qml.Hamiltonian]] = {
11
+ 'pl_x_mixer': mixer
12
+ }
@@ -0,0 +1,130 @@
1
+ from dataclasses import dataclass
2
+ import pennylane as qml
3
+ import numpy as np
4
+ from scipy.sparse import csr_matrix
5
+
6
+ import numpy.typing as npt
7
+ from typing import Any, Callable, cast, Optional
8
+
9
+ from QHyper.problems.base import Problem
10
+
11
+ from QHyper.solvers.vqa.pqc.base import PQC
12
+ from QHyper.solvers.converter import QUBO, Converter
13
+
14
+ from .mixers import MIXERS_BY_NAME
15
+
16
+
17
+ @dataclass
18
+ class QAOA(PQC):
19
+ layers: int = 3
20
+ backend: str = "default.qubit"
21
+ mixer: str = 'pl_x_mixer'
22
+
23
+ def _create_cost_operator(self, qubo: QUBO) -> qml.Hamiltonian:
24
+ result = qml.Identity(0)
25
+ for variables, coeff in qubo.items():
26
+ if not variables:
27
+ continue
28
+ tmp = coeff * (
29
+ 0.5 * qml.Identity(str(variables[0]))
30
+ - 0.5 * qml.PauliZ(str(variables[0]))
31
+ )
32
+ if len(variables) == 2 and variables[0] != variables[1]:
33
+ tmp = tmp @ (
34
+ 0.5 * qml.Identity(str(variables[1]))
35
+ - 0.5 * qml.PauliZ(str(variables[1]))
36
+ )
37
+ result += tmp
38
+ return result
39
+
40
+ def _create_weight_free_hamiltonian(
41
+ self, problem: Problem) -> qml.Hamiltonian:
42
+ row = []
43
+ col = []
44
+ data = []
45
+
46
+ for i in range(2**len(problem.variables)):
47
+ row.append(i)
48
+ col.append(i)
49
+ data.append(problem.get_score(
50
+ format(i, 'b').zfill(len(problem.variables)),
51
+ penalty=0.1
52
+ ))
53
+ sparse_matrix = csr_matrix((data, (row, col)))
54
+ ham = qml.SparseHamiltonian(sparse_matrix, problem.variables)
55
+ return ham
56
+
57
+ def _hadamard_layer(self, problem: Problem) -> None:
58
+ for i in problem.variables:
59
+ qml.Hadamard(str(i))
60
+
61
+ def _create_mixing_hamiltonian(self, problem: Problem) -> qml.Hamiltonian:
62
+ if self.mixer not in MIXERS_BY_NAME:
63
+ raise Exception(f"Unknown {self.mixer} mixer")
64
+ return MIXERS_BY_NAME[self.mixer]([str(v) for v in problem.variables])
65
+
66
+ def _circuit(self, problem: Problem, params: npt.NDArray[np.float64],
67
+ cost_operator: qml.Hamiltonian) -> None:
68
+
69
+ def qaoa_layer(gamma: list[float], beta: list[float]) -> None:
70
+ qml.qaoa.cost_layer(gamma, cost_operator)
71
+ qml.qaoa.mixer_layer(
72
+ beta, self._create_mixing_hamiltonian(problem))
73
+
74
+ self._hadamard_layer(problem)
75
+ qml.layer(qaoa_layer, self.layers, params[0], params[1])
76
+
77
+ def get_expval_circuit(self, problem: Problem, weights: list[float]
78
+ ) -> Callable[[npt.NDArray[np.float64]], float]:
79
+ qubo = Converter.create_qubo(problem, weights)
80
+ cost_operator = self._create_cost_operator(qubo)
81
+
82
+ @qml.qnode(self.dev)
83
+ def expval_circuit(params: npt.NDArray[np.float64]) -> float:
84
+ self._circuit(problem, params, cost_operator)
85
+ return cast(float, qml.expval(
86
+ cost_operator
87
+ # self._create_weight_free_hamiltonian(problem)
88
+ ))
89
+
90
+ return cast(Callable[[npt.NDArray[np.float64]], float], expval_circuit)
91
+
92
+ def run_opt(
93
+ self,
94
+ problem: Problem,
95
+ opt_args: npt.NDArray[np.float64],
96
+ hyper_args: npt.NDArray[np.float64]
97
+ ) -> float:
98
+ self.dev = qml.device(
99
+ self.backend, wires=[str(x) for x in problem.variables])
100
+ return self.get_expval_circuit(problem, list(hyper_args))(
101
+ opt_args.reshape(2, -1))
102
+
103
+ def get_opt_args(
104
+ self,
105
+ params_init: dict[str, Any],
106
+ args: Optional[npt.NDArray[np.float64]] = None,
107
+ hyper_args: Optional[npt.NDArray[np.float64]] = None
108
+ ) -> npt.NDArray[np.float64]:
109
+ return args if args is not None else np.array(params_init['angles'])
110
+
111
+ def get_hopt_args(
112
+ self,
113
+ params_init: dict[str, Any],
114
+ args: Optional[npt.NDArray[np.float64]] = None,
115
+ hyper_args: Optional[npt.NDArray[np.float64]] = None
116
+ ) -> npt.NDArray[np.float64]:
117
+ return (
118
+ hyper_args if hyper_args is not None
119
+ else np.array(params_init['hyper_args'])
120
+ )
121
+
122
+ def get_params_init_format(
123
+ self,
124
+ opt_args: npt.NDArray[np.float64],
125
+ hyper_args: npt.NDArray[np.float64]
126
+ ) -> dict[str, Any]:
127
+ return {
128
+ 'angles': opt_args,
129
+ 'hyper_args': hyper_args,
130
+ }
@@ -0,0 +1,80 @@
1
+ from dataclasses import dataclass
2
+ import pennylane as qml
3
+ import numpy as np
4
+
5
+ import numpy.typing as npt
6
+ from typing import Callable, cast
7
+
8
+ from QHyper.problems.base import Problem
9
+
10
+ from QHyper.solvers.vqa.pqc.qaoa import QAOA
11
+ from QHyper.solvers.converter import Converter
12
+ from QHyper.solvers.vqa.eval_funcs.wfeval import WFEval
13
+
14
+
15
+ @dataclass
16
+ class WFQAOA(QAOA):
17
+ layers: int = 3
18
+ penalty: float = 0
19
+ mixer: str = "pl_x_mixer"
20
+ backend: str = "default.qubit"
21
+
22
+ def get_probs_func(self, problem: Problem, weights: list[float]
23
+ ) -> Callable[[npt.NDArray[np.float64]], list[float]]:
24
+ """Returns function that takes angles and returns probabilities
25
+
26
+ Parameters
27
+ ----------
28
+ weights : list[float]
29
+ weights for converting Problem to QUBO
30
+
31
+ Returns
32
+ -------
33
+ Callable[[list[float]], float]
34
+ Returns function that takes angles and returns probabilities
35
+ """
36
+ qubo = Converter.create_qubo(problem, weights)
37
+ cost_operator = self._create_cost_operator(qubo)
38
+
39
+ @qml.qnode(self.dev)
40
+ def probability_circuit(params: npt.NDArray[np.float64]
41
+ ) -> list[float]:
42
+ self._circuit(problem, params, cost_operator)
43
+ return cast(list[float],
44
+ qml.probs(wires=[str(x) for x in problem.variables]))
45
+
46
+ return cast(Callable[[npt.NDArray[np.float64]], list[float]],
47
+ probability_circuit)
48
+
49
+ def run_opt(
50
+ self,
51
+ problem: Problem,
52
+ opt_args: npt.NDArray[np.float64],
53
+ hyper_args: npt.NDArray[np.float64],
54
+ print_probabilities: bool = False
55
+ ) -> float:
56
+ self.dev = qml.device(
57
+ self.backend, wires=[str(x) for x in problem.variables])
58
+ probs = self.get_probs_func(problem, list(hyper_args))(
59
+ opt_args.reshape(2, -1))
60
+
61
+ if isinstance(probs, qml.numpy.numpy_boxes.ArrayBox):
62
+ probs = probs._value
63
+ results_by_probabilites = {
64
+ format(result, 'b').zfill(len(problem.variables)): float(prob)
65
+ for result, prob in enumerate(probs)
66
+ }
67
+ if print_probabilities:
68
+ sorted_results = {
69
+ k: v for k, v in
70
+ sorted(
71
+ results_by_probabilites.items(),
72
+ key=lambda item: item[1],
73
+ reverse=True
74
+ )[:8]
75
+ }
76
+ for k, v in sorted_results.items():
77
+ print(f'{k}, {v:.3f}, {problem.get_score(k)}')
78
+
79
+ return WFEval(self.penalty).evaluate(
80
+ results_by_probabilites, problem, list(hyper_args))
QHyper/util.py ADDED
@@ -0,0 +1,4 @@
1
+ from typing import Union
2
+
3
+ VARIABLES = Union[tuple[()], tuple[str], tuple[str, str], tuple[str, ...]]
4
+ QUBO = dict[VARIABLES, float]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Tomasz Lamża
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.1
2
+ Name: qhyper
3
+ Version: 0.dev1
4
+ Summary: Quantum and classical problem solvers
5
+ Author: ACK Cyfronet AGH
6
+ Author-email: tomasz.lamza@cyfronet.pl
7
+ License: MIT
8
+ Keywords: python,qhyper,quantum,solver,experiment
9
+ Classifier: Development Status :: 1 - Planning
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: Unix
13
+ Classifier: Operating System :: MacOS :: MacOS X
14
+ Classifier: Operating System :: Microsoft :: Windows
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE.txt
17
+ Requires-Dist: numpy
18
+ Requires-Dist: PennyLane
19
+ Requires-Dist: tdqm
20
+ Requires-Dist: sympy
21
+ Requires-Dist: dwave-system
22
+ Requires-Dist: gurobipy
23
+ Requires-Dist: pandas
24
+ Requires-Dist: wfcommons
25
+
26
+ A package that allows to build and solve quantum and classical problems using predefined solvers and problems.