Passed
Pull Request — master (#206)
by Grega
01:29
created

NiaPy.util.utility.Task.__init__()   C

Complexity

Conditions 10

Size

Total Lines 35
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 14
nop 8
dl 0
loc 35
rs 5.9999
c 0
b 0
f 0

How to fix   Complexity    Many Parameters   

Complexity

Complex classes like NiaPy.util.utility.Task.__init__() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
# encoding=utf8
2
3
"""Implementation of benchmarks utility function."""
4
5
import logging
6
7
from numpy import (
8
    ndarray,
9
    asarray,
10
    full,
11
    empty,
12
    where,
13
    random as rand,
14
    ceil,
15
    amin,
16
    amax
17
)
18
from NiaPy.benchmarks import (
19
    Benchmark,
20
    Rastrigin,
21
    Rosenbrock,
22
    Griewank,
23
    Sphere,
24
    Ackley,
25
    Schwefel,
26
    Schwefel221,
27
    Schwefel222,
28
    Whitley,
29
    Alpine1,
30
    Alpine2,
31
    HappyCat,
32
    Ridge,
33
    ChungReynolds,
34
    Csendes,
35
    Pinter,
36
    Qing,
37
    Quintic,
38
    Salomon,
39
    SchumerSteiglitz,
40
    Step,
41
    Step2,
42
    Step3,
43
    Stepint,
44
    SumSquares,
45
    StyblinskiTang,
46
    BentCigar,
47
    Discus,
48
    Elliptic,
49
    ExpandedGriewankPlusRosenbrock,
50
    HGBat,
51
    Katsuura,
52
    ExpandedSchaffer,
53
    ModifiedSchwefel,
54
    Weierstrass,
55
    Michalewichz,
56
    Levy,
57
    Sphere2,
58
    Sphere3,
59
    Trid,
60
    Perm,
61
    Zakharov,
62
    DixonPrice,
63
    Powell,
64
    CosineMixture,
65
    Infinity,
66
    SchafferN2,
67
    SchafferN4
68
)
69
70
logging.basicConfig()
71
logger = logging.getLogger("NiaPy.util.utility")
72
logger.setLevel("INFO")
73
74
__all__ = [
75
    "limit_repair",
76
    "limitInversRepair",
77
    "objects2array",
78
    "wangRepair",
79
    "randRepair",
80
    "fullArray",
81
    "reflectRepair"
82
]
83
84
85
class Utility:
86
    r"""Base class with string mappings to benchmarks and algorithms.
87
88
    Attributes:
89
        classes (Dict[str, Benchmark]): Mapping from stings to benchmark.
90
91
    """
92
93
    def __init__(self):
94
        r"""Initializing the algorithm and benchmark objects."""
95
96
        self.benchmark_classes = {
97
            "ackley": Ackley,
98
            "alpine1": Alpine1,
99
            "alpine2": Alpine2,
100
            "bentcigar": BentCigar,
101
            "chungReynolds": ChungReynolds,
102
            "cosinemixture": CosineMixture,
103
            "csendes": Csendes,
104
            "discus": Discus,
105
            "dixonprice": DixonPrice,
106
            "conditionedellptic": Elliptic,
107
            "elliptic": Elliptic,
108
            "expandedgriewankplusrosenbrock": ExpandedGriewankPlusRosenbrock,
109
            "expandedschaffer": ExpandedSchaffer,
110
            "griewank": Griewank,
111
            "happyCat": HappyCat,
112
            "hgbat": HGBat,
113
            "infinity": Infinity,
114
            "katsuura": Katsuura,
115
            "levy": Levy,
116
            "michalewicz": Michalewichz,
117
            "modifiedscwefel": ModifiedSchwefel,
118
            "perm": Perm,
119
            "pinter": Pinter,
120
            "powell": Powell,
121
            "qing": Qing,
122
            "quintic": Quintic,
123
            "rastrigin": Rastrigin,
124
            "ridge": Ridge,
125
            "rosenbrock": Rosenbrock,
126
            "salomon": Salomon,
127
            "schaffer2": SchafferN2,
128
            "schaffer4": SchafferN4,
129
            "schumerSteiglitz": SchumerSteiglitz,
130
            "schwefel": Schwefel,
131
            "schwefel221": Schwefel221,
132
            "schwefel222": Schwefel222,
133
            "sphere": Sphere,
134
            "sphere2": Sphere2,
135
            "sphere3": Sphere3,
136
            "step": Step,
137
            "step2": Step2,
138
            "step3": Step3,
139
            "stepint": Stepint,
140
            "styblinskiTang": StyblinskiTang,
141
            "sumSquares": SumSquares,
142
            "trid": Trid,
143
            "weierstrass": Weierstrass,
144
            "whitley": Whitley,
145
            "zakharov": Zakharov
146
        }
147
148
        self.algorithm_classes = {}
149
150
    def get_benchmark(self, benchmark):
151
        r"""Get the optimization problem.
152
153
        Arguments:
154
            benchmark (Union[str, Benchmark]): String or class that represents the optimization problem.
155
156
        Returns:
157
            Benchmark: Optimization function with limits.
158
159
        """
160
161
        if issubclass(type(benchmark), Benchmark):
162
            return benchmark
163
        elif benchmark in self.benchmark_classes.keys():
164
            return self.benchmark_classes[benchmark]()
165
        else:
166
            raise TypeError("Passed benchmark is not defined!")
167
168
    @classmethod
169
    def __raiseLowerAndUpperNotDefined(cls):
170
        r"""Trow exception if lower and upper bounds are not defined in benchmark.
171
172
        Raises:
173
            TypeError: Type error.
174
        """
175
        raise TypeError("Upper and Lower value must be defined!")
176
177
178
def limit_repair(x, Lower, Upper, **kwargs):
179
    r"""Repair solution and put the solution in the random position inside of the bounds of problem.
180
181
    Arguments:
182
            x (numpy.ndarray): Solution to check and repair if needed.
183
            Lower (numpy.ndarray): Lower bounds of search space.
184
            Upper (numpy.ndarray): Upper bounds of search space.
185
            kwargs (Dict[str, Any]): Additional arguments.
186
187
    Returns:
188
            numpy.ndarray: Solution in search space.
189
    """
190
    ir = where(x < Lower)
191
    x[ir] = Lower[ir]
192
    ir = where(x > Upper)
193
    x[ir] = Upper[ir]
194
    return x
195
196
197
def limitInversRepair(x, Lower, Upper, **kwargs):
198
    r"""Repair solution and put the solution in the random position inside of the bounds of problem.
199
200
    Arguments:
201
            x (numpy.ndarray): Solution to check and repair if needed.
202
            Lower (numpy.ndarray): Lower bounds of search space.
203
            Upper (numpy.ndarray): Upper bounds of search space.
204
            kwargs (Dict[str, Any]): Additional arguments.
205
206
    Returns:
207
            numpy.ndarray: Solution in search space.
208
    """
209
    ir = where(x < Lower)
210
    x[ir] = Upper[ir]
211
    ir = where(x > Upper)
212
    x[ir] = Lower[ir]
213
    return x
214
215
216
def wangRepair(x, Lower, Upper, **kwargs):
217
    r"""Repair solution and put the solution in the random position inside of the bounds of problem.
218
219
    Arguments:
220
            x (numpy.ndarray): Solution to check and repair if needed.
221
            Lower (numpy.ndarray): Lower bounds of search space.
222
            Upper (numpy.ndarray): Upper bounds of search space.
223
            kwargs (Dict[str, Any]): Additional arguments.
224
225
    Returns:
226
            numpy.ndarray: Solution in search space.
227
    """
228
    ir = where(x < Lower)
229
    x[ir] = amin([Upper[ir], 2 * Lower[ir] - x[ir]], axis=0)
230
    ir = where(x > Upper)
231
    x[ir] = amax([Lower[ir], 2 * Upper[ir] - x[ir]], axis=0)
232
    return x
233
234
235
def randRepair(x, Lower, Upper, rnd=rand, **kwargs):
236
    r"""Repair solution and put the solution in the random position inside of the bounds of problem.
237
238
    Arguments:
239
            x (numpy.ndarray): Solution to check and repair if needed.
240
            Lower (numpy.ndarray): Lower bounds of search space.
241
            Upper (numpy.ndarray): Upper bounds of search space.
242
            rnd (mtrand.RandomState): Random generator.
243
            kwargs (Dict[str, Any]): Additional arguments.
244
245
    Returns:
246
            numpy.ndarray: Fixed solution.
247
    """
248
    ir = where(x < Lower)
249
    x[ir] = rnd.uniform(Lower[ir], Upper[ir])
250
    ir = where(x > Upper)
251
    x[ir] = rnd.uniform(Lower[ir], Upper[ir])
252
    return x
253
254
255
def reflectRepair(x, Lower, Upper, **kwargs):
256
    r"""Repair solution and put the solution in search space with reflection of how much the solution violates a bound.
257
258
    Args:
259
            x (numpy.ndarray): Solution to be fixed.
260
            Lower (numpy.ndarray): Lower bounds of search space.
261
            Upper (numpy.ndarray): Upper bounds of search space.
262
            kwargs (Dict[str, Any]): Additional arguments.
263
264
    Returns:
265
            numpy.ndarray: Fix solution.
266
    """
267
    ir = where(x > Upper)
268
    x[ir] = Lower[ir] + x[ir] % (Upper[ir] - Lower[ir])
269
    ir = where(x < Lower)
270
    x[ir] = Lower[ir] + x[ir] % (Upper[ir] - Lower[ir])
271
    return x
272
273
274
def fullArray(a, D):
275
    r"""Fill or create array of length D, from value or value form a.
276
277
    Arguments:
278
        a (Union[int, float, numpy.ndarray], Iterable[Any]): Input values for fill.
279
        D (int): Length of new array.
280
281
    Returns:
282
        numpy.ndarray: Array filled with passed values or value.
283
284
    """
285
286
    A = []
287
288
    if isinstance(a, (int, float)):
289
        A = full(D, a)
290
    elif isinstance(a, (ndarray, list, tuple)):
291
        if len(a) == D:
292
            A = a if isinstance(a, ndarray) else asarray(a)
293
        elif len(a) > D:
294
            A = a[:D] if isinstance(a, ndarray) else asarray(a[:D])
295
        else:
296
            for i in range(int(ceil(float(D) / len(a)))):
297
                A.extend(a[:D if (D - i * len(a)) >= len(a) else D - i * len(a)])
298
            A = asarray(A)
299
    return A
300
301
302
def objects2array(objs):
303
    r"""Convert `Iterable` array or list to `NumPy` array.
304
305
    Args:
306
        objs (Iterable[Any]): Array or list to convert.
307
308
    Returns:
309
        numpy.ndarray: Array of objects.
310
311
    """
312
313
    a = empty(len(objs), dtype=object)
314
    for i, e in enumerate(objs):
315
        a[i] = e
316
    return a
317