qhyper 0.dev1__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.
Files changed (46) hide show
  1. qhyper-0.dev1/LICENSE.txt +21 -0
  2. qhyper-0.dev1/PKG-INFO +18 -0
  3. qhyper-0.dev1/QHyper/__init__.py +0 -0
  4. qhyper-0.dev1/QHyper/optimizers/__init__.py +17 -0
  5. qhyper-0.dev1/QHyper/optimizers/base.py +39 -0
  6. qhyper-0.dev1/QHyper/optimizers/basinhopping.py +79 -0
  7. qhyper-0.dev1/QHyper/optimizers/cem.py +128 -0
  8. qhyper-0.dev1/QHyper/optimizers/qml_gradient_descent.py +72 -0
  9. qhyper-0.dev1/QHyper/optimizers/random.py +90 -0
  10. qhyper-0.dev1/QHyper/optimizers/scipy_minimizer.py +65 -0
  11. qhyper-0.dev1/QHyper/problems/__init__.py +0 -0
  12. qhyper-0.dev1/QHyper/problems/base.py +62 -0
  13. qhyper-0.dev1/QHyper/problems/community_detection.py +185 -0
  14. qhyper-0.dev1/QHyper/problems/knapsack.py +176 -0
  15. qhyper-0.dev1/QHyper/problems/maxcut.py +37 -0
  16. qhyper-0.dev1/QHyper/problems/tsp.py +190 -0
  17. qhyper-0.dev1/QHyper/problems/workflow_scheduling.py +220 -0
  18. qhyper-0.dev1/QHyper/solvers/__init__.py +14 -0
  19. qhyper-0.dev1/QHyper/solvers/base.py +86 -0
  20. qhyper-0.dev1/QHyper/solvers/converter.py +128 -0
  21. qhyper-0.dev1/QHyper/solvers/cqm/__init__.py +1 -0
  22. qhyper-0.dev1/QHyper/solvers/cqm/cqm.py +66 -0
  23. qhyper-0.dev1/QHyper/solvers/dqm/__init__.py +1 -0
  24. qhyper-0.dev1/QHyper/solvers/dqm/dqm.py +23 -0
  25. qhyper-0.dev1/QHyper/solvers/gurobi/__init__.py +1 -0
  26. qhyper-0.dev1/QHyper/solvers/gurobi/gurobi.py +77 -0
  27. qhyper-0.dev1/QHyper/solvers/vqa/__init__.py +25 -0
  28. qhyper-0.dev1/QHyper/solvers/vqa/base.py +108 -0
  29. qhyper-0.dev1/QHyper/solvers/vqa/eval_funcs/__init__.py +0 -0
  30. qhyper-0.dev1/QHyper/solvers/vqa/eval_funcs/base.py +40 -0
  31. qhyper-0.dev1/QHyper/solvers/vqa/eval_funcs/wfeval.py +32 -0
  32. qhyper-0.dev1/QHyper/solvers/vqa/pqc/__init__.py +0 -0
  33. qhyper-0.dev1/QHyper/solvers/vqa/pqc/base.py +133 -0
  34. qhyper-0.dev1/QHyper/solvers/vqa/pqc/h_qaoa.py +86 -0
  35. qhyper-0.dev1/QHyper/solvers/vqa/pqc/mixers.py +12 -0
  36. qhyper-0.dev1/QHyper/solvers/vqa/pqc/qaoa.py +130 -0
  37. qhyper-0.dev1/QHyper/solvers/vqa/pqc/wf_qaoa.py +80 -0
  38. qhyper-0.dev1/QHyper/util.py +4 -0
  39. qhyper-0.dev1/README.md +54 -0
  40. qhyper-0.dev1/qhyper.egg-info/PKG-INFO +18 -0
  41. qhyper-0.dev1/qhyper.egg-info/SOURCES.txt +44 -0
  42. qhyper-0.dev1/qhyper.egg-info/dependency_links.txt +1 -0
  43. qhyper-0.dev1/qhyper.egg-info/requires.txt +8 -0
  44. qhyper-0.dev1/qhyper.egg-info/top_level.txt +1 -0
  45. qhyper-0.dev1/setup.cfg +4 -0
  46. qhyper-0.dev1/setup.py +46 -0
@@ -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.
qhyper-0.dev1/PKG-INFO ADDED
@@ -0,0 +1,18 @@
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
+
18
+ A package that allows to build and solve quantum and classical problems using predefined solvers and problems.
File without changes
@@ -0,0 +1,17 @@
1
+ from typing import Type
2
+
3
+ from .base import Optimizer
4
+
5
+ from .cem import CEM
6
+ from .qml_gradient_descent import QmlGradientDescent
7
+ from .random import Random
8
+ from .scipy_minimizer import ScipyOptimizer
9
+ from .basinhopping import Basinhopping
10
+
11
+ OPTIMIZERS_BY_NAME: dict[str, Type[Optimizer]] = {
12
+ 'scipy': ScipyOptimizer,
13
+ 'random': Random,
14
+ 'qml': QmlGradientDescent,
15
+ 'cem': CEM,
16
+ 'basinhopping': Basinhopping
17
+ }
@@ -0,0 +1,39 @@
1
+ from abc import abstractmethod
2
+ import numpy as np
3
+
4
+ import numpy.typing as npt
5
+ from typing import Callable
6
+
7
+
8
+ class Optimizer:
9
+ """
10
+ Abstract base class for optimizers.
11
+ """
12
+
13
+ @abstractmethod
14
+ def minimize(
15
+ self,
16
+ func: Callable[[npt.NDArray[np.float64]], float],
17
+ init: npt.NDArray[np.float64]
18
+ ) -> tuple[float, npt.NDArray[np.float64]]:
19
+ """
20
+ Abstract method that minimizes the given function using the implemented optimization algorithm.
21
+
22
+ Parameters
23
+ ----------
24
+ func : callable
25
+ The objective function to be minimized.
26
+ init : numpy.ndarray
27
+ The initial point for the optimization algorithm.
28
+
29
+ Returns
30
+ -------
31
+ tuple
32
+ A tuple containing the minimum function value and the corresponding optimal point.
33
+
34
+ Raises
35
+ ------
36
+ NotImplementedError
37
+ If the `minimize` method is not implemented by the derived class.
38
+ """
39
+ ...
@@ -0,0 +1,79 @@
1
+ from scipy.optimize import basinhopping
2
+ import numpy as np
3
+ import numpy.typing as npt
4
+ from typing import Callable, Any
5
+
6
+ from .base import Optimizer
7
+
8
+
9
+ class Basinhopping(Optimizer):
10
+ """
11
+ Class for the Basin-hopping algorithm for global optimization.
12
+
13
+ Parameters
14
+ ----------
15
+ bounds : list[tuple[float, float]]
16
+ A list of tuples specifying the lower and upper bounds for each dimension of the search space.
17
+ niter : int
18
+ The number of basin-hopping iterations to perform.
19
+ maxfun : int, optional
20
+ Maximum number of function evaluations.
21
+ Default is 200.
22
+ config : dict, optional
23
+ Additional configuration options for the basinhopping function.
24
+ Default is an empty dictionary.
25
+
26
+ Attributes
27
+ ----------
28
+ niter : int
29
+ The number of basin-hopping iterations to perform.
30
+ maxfun : int
31
+ Maximum number of function evaluations.
32
+ bounds : numpy.ndarray
33
+ An array of shape (n, 2) specifying the lower and upper bounds for each dimension of the search space.
34
+ config : dict
35
+ Additional configuration options for the basinhopping function.
36
+ """
37
+ def __init__(
38
+ self,
39
+ bounds: list[tuple[float, float]],
40
+ niter: int,
41
+ maxfun: int = 200,
42
+ config: dict[str, Any] = {}
43
+ ) -> None:
44
+ self.niter = niter
45
+ self.maxfun = maxfun
46
+ self.bounds = np.array(bounds)
47
+ self.config = config
48
+
49
+ def minimize(
50
+ self,
51
+ func: Callable[[npt.NDArray[np.float64]], float],
52
+ init: npt.NDArray[np.float64]
53
+ ) -> tuple[float, npt.NDArray[np.float64]]:
54
+ """
55
+ Minimize the given function using the Basin-hopping algorithm.
56
+
57
+ Parameters
58
+ ----------
59
+ func : callable
60
+ The objective function to be minimized.
61
+ The function should take a single argument, which is a NumPy array of type np.float64,
62
+ and return a float value.
63
+ init : numpy.ndarray
64
+ The initial point for the optimization algorithm.
65
+ The array should have dtype np.float64.
66
+
67
+ Returns
68
+ -------
69
+ tuple
70
+ A tuple containing the minimum function value and the corresponding optimal point.
71
+ """
72
+ result = basinhopping(
73
+ func, init.flatten(), niter=self.niter,
74
+ minimizer_kwargs={
75
+ 'options': {'maxfun': self.maxfun},
76
+ 'bounds': self.bounds
77
+ }, **self.config)
78
+
79
+ return result.fun, np.array(result.x).reshape(init.shape)
@@ -0,0 +1,128 @@
1
+ import multiprocessing as mp
2
+ from dataclasses import dataclass, field
3
+
4
+ from typing import Callable
5
+ import numpy.typing as npt
6
+
7
+ import numpy as np
8
+ import tqdm
9
+
10
+ from .base import Optimizer
11
+
12
+
13
+ @dataclass
14
+ class CEM(Optimizer):
15
+ bounds: npt.NDArray[np.float64]
16
+ epochs: int = 10
17
+ samples_per_epoch: int = 100
18
+ elite_frac: float = 0.1
19
+ processes: int = mp.cpu_count()
20
+ print_on_epochs: list[int] = field(default_factory=list)
21
+ disable_tqdm: bool = False
22
+ n_elite: int = field(init=False)
23
+
24
+ def __post_init__(self) -> None:
25
+ self.n_elite: int = max(
26
+ int(self.samples_per_epoch * self.elite_frac), 1)
27
+ self.bounds = np.array(self.bounds)
28
+
29
+ """Implementation of the Cross Entropy Method for hyperparameter tuning
30
+
31
+ Attributes
32
+ ----------
33
+ epochs : int
34
+ number of epochs (default 10)
35
+ samples_per_epoch : int
36
+ number of samples in each epoch (default 100)
37
+ elite_frac : float
38
+ indicate the percent of how many top samples will be used to calculate
39
+ the mean and cov for the next epoch (default 0.1)
40
+ processes : int
41
+ number of processors that will be used (default cpu count)
42
+ n_elite : int
43
+ calulated by multiplying samples_per_epoch by elite_frac
44
+ print_on_epochs: list[int]
45
+ list indicating after which epochs print best results
46
+ disable_tqdm: bool
47
+ if set to True, tdqm will be disabled
48
+ """
49
+
50
+ def _get_points(
51
+ self,
52
+ mean: npt.NDArray[np.float64],
53
+ cov: npt.NDArray[np.float64]
54
+ ) -> list[npt.NDArray[np.float64]]:
55
+ hyperparams: list[npt.NDArray[np.float64]] = []
56
+ while len(hyperparams) < self.samples_per_epoch:
57
+ point = np.random.multivariate_normal(mean, cov)
58
+ if (
59
+ (self.bounds[:, 0] <= point).all()
60
+ and (point < self.bounds[:, 1]).all()
61
+ ):
62
+ hyperparams.append(point)
63
+
64
+ return hyperparams
65
+
66
+ def minimize(
67
+ self,
68
+ func: Callable[[npt.NDArray[np.float64]], float],
69
+ init: npt.NDArray[np.float64]
70
+ ) -> tuple[float, npt.NDArray[np.float64]]:
71
+ """Returns hyperparameters which lead to the lowest values
72
+ returned by optimizer
73
+
74
+ Parameters
75
+ ----------
76
+ func_creator : Callable[[ArgsType], Callable[[ArgsType], float]]
77
+ function which receives hyperparameters, and returns
78
+ a function which will be optimized using an optimizer
79
+ optimizer : Optimizer
80
+ object of the Optimizer class
81
+ init : ArgsType
82
+ initial args for optimizer
83
+ hyperparams_init : ArgsType
84
+ initial hyperparameters
85
+ evaluation_func : Callable[[ArgsType], Callable[[ArgsType], float]]
86
+ function, which receives hyperparameters, and returns
87
+ function which receives params and return evaluation
88
+ bounds : list[float]
89
+ bounds for hyperparameters (default None)
90
+
91
+ Returns
92
+ -------
93
+ ArgsType
94
+ hyperparameters which lead to the lowest values
95
+ returned by the optimizer
96
+ """
97
+ # wrapper = Wrapper(func_creator, optimizer, evaluation_func, init)
98
+ _init = np.array(init)
99
+ mean = _init
100
+ cov = np.identity(len(_init))
101
+ best_hyperparams = _init
102
+ best_score = func(_init)
103
+
104
+ for _ in range(1, self.epochs+1):
105
+ hyperparams = self._get_points(mean, cov)
106
+
107
+ with mp.Pool(processes=self.processes) as p:
108
+ results = list(tqdm.tqdm(
109
+ p.imap(func, hyperparams),
110
+ total=len(hyperparams),
111
+ disable=self.disable_tqdm
112
+ ))
113
+
114
+ elite_idxs = np.array(results).argsort()[:self.n_elite]
115
+
116
+ elite_weights = [hyperparams[i].flatten() for i in elite_idxs]
117
+
118
+ best_hyperparams = elite_weights[0].reshape(_init.shape)
119
+
120
+ reward = func(best_hyperparams)
121
+ if reward < best_score:
122
+ best_hyperparams = best_hyperparams
123
+ best_score = reward
124
+
125
+ mean = np.mean(elite_weights, axis=0)
126
+ cov = np.cov(np.stack((elite_weights), axis=1), bias=True)
127
+
128
+ return func(best_hyperparams), best_hyperparams
@@ -0,0 +1,72 @@
1
+ from typing import Callable
2
+ import numpy.typing as npt
3
+
4
+ import pennylane as qml
5
+ from pennylane import numpy as np
6
+
7
+ from .base import Optimizer
8
+
9
+
10
+ class QmlGradientDescent(Optimizer):
11
+ """Gradient Descent Optimizer
12
+
13
+ Using GradientDescentOptimizer from library PennyLane.
14
+
15
+ Attributes
16
+ ----------
17
+ optimizer : qml.GradientDescentOptimizer
18
+ object of class GradientDescentOptimizer or inheriting from this class
19
+ optimization_steps : int
20
+ number of optimization steps
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ optimizer: qml.GradientDescentOptimizer = None,
26
+ optimization_steps: int = 200
27
+ ) -> None:
28
+ """
29
+ Parameters
30
+ ----------
31
+ optimizer : qml.GradientDescentOptimizer
32
+ object of class GradientDescentOptimizer
33
+ or inheriting from this class
34
+ optimization_steps : int
35
+ number of optimization steps
36
+ """
37
+
38
+ self.optimizer = optimizer if optimizer else qml.AdamOptimizer(
39
+ stepsize=0.005
40
+ )
41
+ self.optimization_steps = optimization_steps
42
+
43
+ def minimize(
44
+ self,
45
+ func: Callable[[npt.NDArray[np.float64]], float],
46
+ init: npt.NDArray[np.float64]
47
+ ) -> tuple[float, npt.NDArray[np.float64]]:
48
+ """Returns params which lead to the lowest value of
49
+ the provided function and cost history
50
+
51
+ Parameters
52
+ ----------
53
+ func : Callable[[ArgsType], float]
54
+ function which will be minimized
55
+ init : ArgsType
56
+ initial args for optimizer
57
+
58
+ Returns
59
+ -------
60
+ tuple[ArgsType, Any]
61
+ Returns tuple which contains params taht lead to the lowest value
62
+ of the provided function and cost history
63
+ """
64
+
65
+ cost_history = []
66
+ params = np.array(init, requires_grad=True)
67
+ if "reset" in dir(self.optimizer):
68
+ self.optimizer.reset()
69
+ for _ in range(self.optimization_steps):
70
+ params, cost = self.optimizer.step_and_cost(func, params)
71
+ cost_history.append(cost)
72
+ return cost, params
@@ -0,0 +1,90 @@
1
+ from dataclasses import dataclass
2
+ import multiprocessing as mp
3
+ from typing import Callable
4
+ import numpy.typing as npt
5
+
6
+ import numpy as np
7
+ import tqdm
8
+
9
+ from .base import Optimizer
10
+
11
+
12
+ @dataclass
13
+ class Random(Optimizer):
14
+ number_of_samples: int
15
+ processes: int
16
+ disable_tqdm: bool
17
+ bounds: npt.NDArray[np.float64]
18
+
19
+ def __init__(
20
+ self,
21
+ bounds: list[tuple[float, float]],
22
+ number_of_samples: int = 100,
23
+ processes: int = 1,
24
+ disable_tqdm: bool = False,
25
+ ) -> None:
26
+ """
27
+ Parameters
28
+ ----------
29
+ number_of_samples : int
30
+ number of random samples (default 100)
31
+ processes : int
32
+ number of processors that will be used (default cpu count)
33
+ disable_tqdm: bool
34
+ if set to True, tdqm will be disabled (default False)
35
+ """
36
+
37
+ self.number_of_samples: int = number_of_samples
38
+ self.processes: int = processes
39
+ self.disable_tqdm: bool = disable_tqdm
40
+ self.bounds = np.array(bounds)
41
+
42
+ def minimize(
43
+ self,
44
+ func: Callable[[npt.NDArray[np.float64]], float],
45
+ init: npt.NDArray[np.float64]
46
+ ) -> tuple[float, npt.NDArray[np.float64]]:
47
+ """Returns hyperparameters which lead to the lowest values
48
+ returned by the optimizer
49
+
50
+ Parameters
51
+ ----------
52
+ func_creator : Callable[[ArgsType], Callable[[ArgsType], float]]
53
+ function which receives hyperparameters and returns
54
+ a function which will be optimized using the optimizer
55
+ optimizer : Optimizer
56
+ object of the Optimizer class
57
+ init : ArgsType
58
+ initial args for the optimizer
59
+ hyperparams_init : ArgsType
60
+ initial hyperparameters
61
+ evaluation_func : Callable[[ArgsType], Callable[[ArgsType], float]]
62
+ function, which receives hyperparameters, and returns
63
+ function which receives params and return evaluation
64
+ bounds : list[float]
65
+ bounds for hyperparameters (default None)
66
+
67
+ Returns
68
+ -------
69
+ ArgsType
70
+ Returns hyperparameters which lead to the lowest values
71
+ returned by the optimizer
72
+ """
73
+ hyperparams_init = np.array(init)
74
+ hyperparams = (
75
+ (self.bounds[:, 1] - self.bounds[:, 0])
76
+ * np.random.rand(self.number_of_samples, *hyperparams_init.shape)
77
+ + self.bounds[:, 0])
78
+
79
+ # results = [func(hyperparam) for hyperparam in hyperparams]
80
+ with mp.Pool(processes=self.processes) as p:
81
+ results = list(tqdm.tqdm(
82
+ p.imap(func, hyperparams),
83
+ total=self.number_of_samples,
84
+ disable=self.disable_tqdm
85
+ ))
86
+
87
+ min_idx = np.argmin(results)
88
+ return results[min_idx], hyperparams[min_idx]
89
+ # return HyperOptimizerResults.from_solver_results(
90
+ # results[min_idx], hyperparams[min_idx])
@@ -0,0 +1,65 @@
1
+ import numpy.typing as npt
2
+ from typing import Optional, Callable
3
+
4
+ import scipy
5
+ import numpy as np
6
+
7
+ from .base import Optimizer
8
+
9
+
10
+ class ScipyOptimizer(Optimizer):
11
+ """
12
+ Class for the SciPy minimizer.
13
+
14
+ Attributes
15
+ ----------
16
+ maxfun : int
17
+ Maximum number of function evaluations.
18
+ bounds : list[tuple[float, float]] or None
19
+ A list of tuples specifying the lower and upper bounds for each dimension of the search space,
20
+ or None if no bounds are provided.
21
+ """
22
+ def __init__(
23
+ self,
24
+ maxfun: int,
25
+ bounds: Optional[list[tuple[float, float]]] = None
26
+ ) -> None:
27
+ self.maxfun = maxfun
28
+ self.bounds = bounds
29
+
30
+ def minimize(
31
+ self,
32
+ func: Callable[[npt.NDArray[np.float64]], float],
33
+ init: npt.NDArray[np.float64]
34
+ ) -> tuple[float, npt.NDArray[np.float64]]:
35
+ """
36
+ Minimize the given function using the SciPy minimize.
37
+
38
+ Parameters
39
+ ----------
40
+ func : callable
41
+ The objective function to be minimized.
42
+ The function should take a single argument, which is a NumPy array of type np.float64,
43
+ and return a float value.
44
+ init : numpy.ndarray
45
+ The initial point for the optimization algorithm.
46
+ The array should have dtype np.float64.
47
+
48
+ Returns
49
+ -------
50
+ tuple
51
+ A tuple containing the minimum function value and the corresponding optimal point.
52
+ """
53
+ def wrapper(params: npt.NDArray[np.float64]) -> float:
54
+ return func(np.array(params).reshape(np.array(init).shape))
55
+
56
+ result = scipy.optimize.minimize(
57
+ wrapper,
58
+ np.array(init).flatten(),
59
+ bounds=(
60
+ self.bounds if self.bounds is not None
61
+ else [(0, 2*np.pi)]*len(np.array(init).flatten())
62
+ ),
63
+ options={'maxfun': self.maxfun}
64
+ )
65
+ return result.fun, result.x.reshape(np.array(init).shape)
File without changes
@@ -0,0 +1,62 @@
1
+ from abc import ABC
2
+
3
+ import sympy
4
+
5
+ from QHyper.hyperparameter_gen.parser import Expression
6
+
7
+
8
+ class Problem(ABC):
9
+ """Interface for different combinatorial optimization problems
10
+
11
+ Objective function and constrians are the main components
12
+ and should be written in the SymPy syntax.
13
+ Depending on the selcted solver, these parts can be used
14
+ separately or, e.g., as a Quadratic Unconstrained
15
+ Binary Optimization (QUBO) formularion.
16
+
17
+ If the QUBO is provided, it should be passed to the
18
+ objective_function and the constraints should be empty.
19
+
20
+ Attributes
21
+ ----------
22
+ objective_function: Expression
23
+ objective function in SymPy syntax
24
+ constraints : list[Expression]
25
+ list of constraints in SymPy syntax
26
+ variables : list[Any]
27
+ list of variables in the problem
28
+ name: str
29
+ helps to differentiate various problems (default "")
30
+ cases: int
31
+ number of variable cases (values)
32
+ (default 1 - denoting binary variable)
33
+ """
34
+
35
+ objective_function: Expression
36
+ constraints: list[Expression]
37
+ variables: tuple[sympy.Symbol]
38
+ name: str = ""
39
+ cases: int = 1
40
+
41
+ def get_score(self, result: str, penalty: float = 0) -> float:
42
+ """Returns score of the outcome provided as a binary string
43
+
44
+ Necessary to evaluate results.
45
+
46
+ Parameters
47
+ ----------
48
+ result : str
49
+ outcome as a string of zeros and ones
50
+
51
+ Returns
52
+ -------
53
+ float
54
+ Returns float indicating the score, if function should be
55
+ maximized the returned value should be returned with negative sign
56
+ """
57
+ raise Exception("Unimplemented")
58
+
59
+ def __repr__(self) -> str:
60
+ if self.name == "":
61
+ return super().__repr__()
62
+ return f"{self.__class__.__name__}_{self.name}"