Passed
Branch master (13db34)
by Grega
02:16
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
# pylint: disable=line-too-long, mixed-indentation, bad-continuation,multiple-statements, unused-argument, no-self-use, trailing-comma-tuple, logging-not-lazy, no-else-return, dangerous-default-value, assignment-from-no-return, superfluous-parens
3
4
"""Implementation of benchmarks utility function."""
5
import logging
6
# from datetime import datetime
7
from enum import Enum
8
9
from numpy import ndarray, asarray, full, empty, inf, dot, where, random as rand, fabs, ceil, amin, amax
10
from matplotlib import pyplot as plt, animation as anim
11
12
from NiaPy.benchmarks import Rastrigin, Rosenbrock, Griewank, Sphere, Ackley, Schwefel, Schwefel221, Schwefel222, Whitley, Alpine1, Alpine2, HappyCat, Ridge, ChungReynolds, Csendes, Pinter, Qing, Quintic, Salomon, SchumerSteiglitz, Step, Step2, Step3, Stepint, SumSquares, StyblinskiTang, BentCigar, Discus, Elliptic, ExpandedGriewankPlusRosenbrock, HGBat, Katsuura, ExpandedSchaffer, ModifiedSchwefel, Weierstrass, Michalewichz, Levy, Sphere2, Sphere3, Trid, Perm, Zakharov, DixonPrice, Powell, CosineMixture, Infinity, SchafferN2, SchafferN4
13
from NiaPy.util.exception import FesException, GenException, RefException  # TimeException,
14
15
logging.basicConfig()
16
logger = logging.getLogger('NiaPy.util.utility')
17
logger.setLevel('INFO')
18
19
__all__ = [
20
	'Utility',
21
	'limitRepair',
22
	'limitInversRepair',
23
	'wangRepair',
24
	'randRepair',
25
	'Task',
26
	'CountingTask',
27
	'StoppingTask',
28
	'ThrowingTask',
29
	'TaskConvPrint',
30
	'TaskConvPlot',
31
	'TaskConvSave',
32
	'fullArray',
33
	'objects2array',
34
	'TaskComposition',
35
	'OptimizationType',
36
	'ScaledTask'
37
]
38
39
def fullArray(a, D):
40
	r"""Fill or create array of length D, from value or value form a.
41
42
	Arguments:
43
		a (Union[int, float, numpy.ndarray], Iterable[Any]): Input values for fill.
44
		D (int): Length of new array.
45
46
	Returns:
47
		numpy.ndarray: Array filled with passed values or value.
48
	"""
49
	A = []
50
	if isinstance(a, (int, float)):	A = full(D, a)
51
	elif isinstance(a, (ndarray, list, tuple)):
52
		if len(a) == D: A = a if isinstance(a, ndarray) else asarray(a)
53
		elif len(a) > D: A = a[:D] if isinstance(a, ndarray) else asarray(a[:D])
54
		else:
55
			for i in range(int(ceil(float(D) / len(a)))): A.extend(a[:D if (D - i * len(a)) >= len(a) else D - i * len(a)])
56
			A = asarray(A)
57
	return A
58
59
def objects2array(objs):
60
	r"""Convert `Iterable` array or list to `NumPy` array.
61
62
	Args:
63
		objs (Iterable[Any]): Array or list to convert.
64
65
	Returns:
66
		numpy.ndarray: Array of objects.
67
	"""
68
	a = empty(len(objs), dtype=object)
69
	for i, e in enumerate(objs): a[i] = e
70
	return a
71
72
class Utility:
73
	r"""Base class with string mappings to benchmarks.
74
75
	Attributes:
76
		classes (Dict[str, Benchmark]): Mapping from stings to benchmark.
77
	"""
78
	def __init__(self):
79
		r"""
80
81
		"""
82
		self.classes = {
83
			'ackley': Ackley,
84
			'alpine1': Alpine1,
85
			'alpine2': Alpine2,
86
			'bentcigar': BentCigar,
87
			'chungReynolds': ChungReynolds,
88
			'cosinemixture': CosineMixture,
89
			'csendes': Csendes,
90
			'discus': Discus,
91
			'dixonprice': DixonPrice,
92
			'conditionedellptic': Elliptic,
93
			'elliptic': Elliptic,
94
			'expandedgriewankplusrosenbrock': ExpandedGriewankPlusRosenbrock,
95
			'expandedschaffer': ExpandedSchaffer,
96
			'griewank': Griewank,
97
			'happyCat': HappyCat,
98
			'hgbat': HGBat,
99
			'infinity': Infinity,
100
			'katsuura': Katsuura,
101
			'levy': Levy,
102
			'michalewicz': Michalewichz,
103
			'modifiedscwefel': ModifiedSchwefel,
104
			'perm': Perm,
105
			'pinter': Pinter,
106
			'powell': Powell,
107
			'qing': Qing,
108
			'quintic': Quintic,
109
			'rastrigin': Rastrigin,
110
			'ridge': Ridge,
111
			'rosenbrock': Rosenbrock,
112
			'salomon': Salomon,
113
			'schaffer2': SchafferN2,
114
			'schaffer4': SchafferN4,
115
			'schumerSteiglitz': SchumerSteiglitz,
116
			'schwefel': Schwefel,
117
			'schwefel221': Schwefel221,
118
			'schwefel222': Schwefel222,
119
			'sphere': Sphere,
120
			'sphere2': Sphere2,
121
			'sphere3': Sphere3,
122
			'step': Step,
123
			'step2': Step2,
124
			'step3': Step3,
125
			'stepint': Stepint,
126
			'styblinskiTang': StyblinskiTang,
127
			'sumSquares': SumSquares,
128
			'trid': Trid,
129
			'weierstrass': Weierstrass,
130
			'whitley': Whitley,
131
			'zakharov': Zakharov
132
		}
133
134
	def get_benchmark(self, benchmark):
135
		r"""Get the optimization problem.
136
137
		Arguments:
138
			benchmark (Union[str, Benchmark]): String or class that represents the optimization problem.
139
140
		Returns:
141
			Benchmark: Optimization function with limits.
142
		"""
143
		if not isinstance(benchmark, str) and not callable(benchmark): return benchmark
144
		elif benchmark in self.classes: return self.classes[benchmark]()
145
		else: raise TypeError('Passed benchmark is not defined!')
146
147
	@classmethod
148
	def __raiseLowerAndUpperNotDefined(cls):
149
		r"""Trow exception if lower and upper bounds are not defined in benchmark.
150
151
		Raises:
152
			TypeError: Type error.
153
		"""
154
		raise TypeError('Upper and Lower value must be defined!')
155
156
class OptimizationType(Enum):
157
	r"""Enum representing type of optimization.
158
159
	Attributes:
160
		MINIMIZATION (int): Represents minimization problems and is default optimization type of all algorithms.
161
		MAXIMIZATION (int): Represents maximization problems.
162
	"""
163
	MINIMIZATION = 1.0
164
	MAXIMIZATION = -1.0
165
166
def limitRepair(x, Lower, Upper, **kwargs):
167
	r"""Repair solution and put the solution in the random position inside of the bounds of problem.
168
169
	Arguments:
170
		x (numpy.ndarray): Solution to check and repair if needed.
171
		Lower (numpy.ndarray): Lower bounds of search space.
172
		Upper (numpy.ndarray): Upper bounds of search space.
173
		kwargs (Dict[str, Any]): Additional arguments.
174
175
	Returns:
176
		numpy.ndarray: Solution in search space.
177
	"""
178
	ir = where(x < Lower)
179
	x[ir] = Lower[ir]
180
	ir = where(x > Upper)
181
	x[ir] = Lower[ir]
182
	return x
183
184
def limitInversRepair(x, Lower, Upper, **kwargs):
185
	r"""Repair solution and put the solution in the random position inside of the bounds of problem.
186
187
	Arguments:
188
		x (numpy.ndarray): Solution to check and repair if needed.
189
		Lower (numpy.ndarray): Lower bounds of search space.
190
		Upper (numpy.ndarray): Upper bounds of search space.
191
		kwargs (Dict[str, Any]): Additional arguments.
192
193
	Returns:
194
		numpy.ndarray: Solution in search space.
195
	"""
196
	ir = where(x < Lower)
197
	x[ir] = Upper[ir]
198
	ir = where(x > Upper)
199
	x[ir] = Lower[ir]
200
	return x
201
202
def wangRepair(x, Lower, Upper, **kwargs):
203
	r"""Repair solution and put the solution in the random position inside of the bounds of problem.
204
205
	Arguments:
206
		x (numpy.ndarray): Solution to check and repair if needed.
207
		Lower (numpy.ndarray): Lower bounds of search space.
208
		Upper (numpy.ndarray): Upper bounds of search space.
209
		kwargs (Dict[str, Any]): Additional arguments.
210
211
	Returns:
212
		numpy.ndarray: Solution in search space.
213
	"""
214
	ir = where(x < Lower)
215
	x[ir] = amin([Upper[ir], 2 * Lower[ir] - x[ir]], axis=0)
216
	ir = where(x > Upper)
217
	x[ir] = amax([Lower[ir], 2 * Upper[ir] - x[ir]], axis=0)
218
	return x
219
220
def randRepair(x, Lower, Upper, rnd=rand, **kwargs):
221
	r"""Repair solution and put the solution in the random position inside of the bounds of problem.
222
223
	Arguments:
224
		x (array): Solution to check and repair if needed.
225
		Lower (numpy.ndarray): Lower bounds of search space.
226
		Upper (numpy.ndarray): Upper bounds of search space.
227
		rnd (mtrand.RandomState): Random generator.
228
		kwargs (Dict[str, Any]): Additional arguments.
229
230
	Returns:
231
		numpy.ndarray: Fixed solution.
232
	"""
233
	ir = where(x < Lower)
234
	x[ir] = rnd.uniform(Lower[ir], Upper[ir])
235
	ir = where(x > Upper)
236
	x[ir] = rnd.uniform(Lower[ir], Upper[ir])
237
	return x
238
239
def reflectRepair(x, Lower, Upper, **kwargs):
240
	r"""Repair solution and put the solution in search space with reflection of how much the solution violates a bound.
241
242
	Args:
243
		x (numpy.ndarray): Solution to be fixed.
244
		Lower (numpy.ndarray): Lower bounds of search space.
245
		Upper (numpy.ndarray): Upper bounds of search space.
246
		kwargs (Dict[str, Any]): Additional arguments.
247
248
	Returns:
249
		numpy.ndarray: Fix solution.
250
	"""
251
	ir = where(x > Upper)
252
	x[ir] = Lower[ir] + x[ir] % (Upper[ir] - Lower[ir])
253
	ir = where(x < Lower)
254
	x[ir] = Lower[ir] + x[ir] % (Upper[ir] - Lower[ir])
255
	return x
256
257
class Task(Utility):
258
	r"""Class representing problem to solve with optimization.
259
260
	Date:
261
		2019
262
263
	Author:
264
		Klemen Berkovič
265
266
	Attributes:
267
		D (int): Dimension of the problem.
268
		Lower (numpy.ndarray): Lower bounds of the problem.
269
		Upper (numpy.ndarray): Upper bounds of the problem.
270
		bRange (numpy.ndarray): Search range between upper and lower limits.
271
		optType (OptimizationType): Optimization type to use.
272
273
	See Also:
274
		* :class:`NiaPy.util.Utility`
275
	"""
276
	D = 0
277
	benchmark = None
278
	Lower, Upper, bRange = inf, inf, inf
279
	optType = OptimizationType.MINIMIZATION
280
281
	def __init__(self, D=0, optType=OptimizationType.MINIMIZATION, benchmark=None, Lower=None, Upper=None, frepair=limitRepair, **kwargs):
282
		r"""Initialize task class for optimization.
283
284
		Arguments:
285
			D (Optional[int]): Number of dimensions.
286
			optType (Optional[OptimizationType]): Set the type of optimization.
287
			benchmark (Union[str, Benchmark]): Problem to solve with optimization.
288
			Lower (Optional[numpy.ndarray]): Lower limits of the problem.
289
			Upper (Optional[numpy.ndarray]): Upper limits of the problem.
290
			frepair (Optional[Callable[[numpy.ndarray, numpy.ndarray, numpy.ndarray, Dict[str, Any]], numpy.ndarray]]): Function for reparing individuals components to desired limits.
291
292
		See Also:
293
			* `func`:NiaPy.util.Utility.__init__`
294
			* `func`:NiaPy.util.Utility.repair`
295
		"""
296
		Utility.__init__(self)
297
		# dimension of the problem
298
		self.D = D
299
		# set optimization type
300
		self.optType = optType
301
		# set optimization function
302
		self.benchmark = self.get_benchmark(benchmark) if benchmark is not None else None
303
		if self.benchmark is not None: self.Fun = self.benchmark.function() if self.benchmark is not None else None
304
		# set Lower limits
305
		if Lower is not None: self.Lower = fullArray(Lower, self.D)
306
		elif Lower is None and benchmark is not None: self.Lower = fullArray(self.benchmark.Lower, self.D)
307
		else: self.Lower = fullArray(0, self.D)
308
		# set Upper limits
309
		if Upper is not None: self.Upper = fullArray(Upper, self.D)
310
		elif Upper is None and benchmark is not None: self.Upper = fullArray(self.benchmark.Upper, self.D)
311
		else: self.Upper = fullArray(0, self.D)
312
		# set range
313
		self.bRange = self.Upper - self.Lower
314
		# set repair function
315
		self.frepair = frepair
316
317
	def dim(self):
318
		r"""Get the number of dimensions.
319
320
		Returns:
321
			int: Dimension of problem optimizing.
322
		"""
323
		return self.D
324
325
	def bcLower(self):
326
		r"""Get the array of lower bound constraint.
327
328
		Returns:
329
			numpy.ndarray: Lower bound.
330
		"""
331
		return self.Lower
332
333
	def bcUpper(self):
334
		r"""Get the array of upper bound constraint.
335
336
		Returns:
337
			numpy.ndarray: Upper bound.
338
		"""
339
		return self.Upper
340
341
	def bcRange(self):
342
		r"""Get the range of bound constraint.
343
344
		Returns:
345
			numpy.ndarray: Range between lower and upper bound.
346
		"""
347
		return self.Upper - self.Lower
348
349
	def repair(self, x, rnd=rand):
350
		r"""Repair solution and put the solution in the random position inside of the bounds of problem.
351
352
		Arguments:
353
			x (numpy.ndarray): Solution to check and repair if needed.
354
			rnd (mtrand.RandomState): Random number generator.
355
356
		Returns:
357
			numpy.ndarray: Fixed solution.
358
359
		See Also:
360
			* :func:`NiaPy.util.utility.limitRepair`
361
			* :func:`NiaPy.util.utility.limitInversRepair`
362
			* :func:`NiaPy.util.utility.wangRepair`
363
			* :func:`NiaPy.util.utility.randRepair`
364
			* :func:`NiaPy.util.utility.reflectRepair`
365
		"""
366
		return self.frepair(x, self.Lower, self.Upper, rnd=rnd)
367
368
	def nextIter(self):
369
		r"""Increments the number of algorithm iterations."""
370
371
	def start(self):
372
		r"""Start stopwatch."""
373
374
	def eval(self, A):
375
		r"""Evaluate the solution A.
376
377
		Arguments:
378
			A (numpy.ndarray): Solution to evaluate.
379
380
		Returns:
381
			float: Fitness/function values of solution.
382
		"""
383
		return self.Fun(self.D, A) * self.optType.value
384
385
	def isFeasible(self, A):
386
		r"""Check if the solution is feasible.
387
388
		Arguments:
389
			A (numpy.ndarray): Solution to check for feasibility.
390
391
		Returns:
392
			bool: `True` if solution is in feasible space else `False`.
393
		"""
394
		return False not in (A >= self.Lower) and False not in (A <= self.Upper)
395
396
	def stopCond(self):
397
		r"""Check if optimization task should stop.
398
399
		Returns:
400
			bool: `True` if stopping condition is meet else `False`.
401
		"""
402
		return False
403
404
class CountingTask(Task):
405
	r"""Optimization task with added counting of function evaluations and algorithm iterations/generations.
406
407
	Attributes:
408
		Iters (int): Number of algorithm iterations/generations.
409
		Evals (int): Number of function evaluations.
410
411
	See Also:
412
		* :class:`NiaPy.util.Task`
413
	"""
414
415
	def __init__(self, **kwargs):
416
		r"""Initialize counting task.
417
418
		Args:
419
			**kwargs (Dict[str, Any]): Additional arguments.
420
421
		See Also:
422
			* :func:`NiaPy.util.Task.__init__`
423
		"""
424
		Task.__init__(self, **kwargs)
425
		self.Iters, self.Evals = 0, 0
426
427
	def eval(self, A):
428
		r"""Evaluate the solution A.
429
430
		This function increments function evaluation counter `self.Evals`.
431
432
		Arguments:
433
			A (numpy.ndarray): Solutions to evaluate.
434
435
		Returns:
436
			float: Fitness/function values of solution.
437
438
		See Also:
439
			* :func:`NiaPy.util.Task.eval`
440
		"""
441
		r = Task.eval(self, A)
442
		self.Evals += 1
443
		return r
444
445
	def evals(self):
446
		r"""Get the number of evaluations made.
447
448
		Returns:
449
			int: Number of evaluations made.
450
		"""
451
		return self.Evals
452
453
	def iters(self):
454
		r"""Get the number of algorithm iteratins made.
455
456
		Returns:
457
			int: Number of generations/iterations made by algorithm.
458
		"""
459
		return self.Iters
460
461
	def nextIter(self):
462
		r"""Increases the number of algorithm iterations made.
463
464
		This function increments number of algorithm iterations/generations counter `self.Iters`.
465
		"""
466
		self.Iters += 1
467
468
class StoppingTask(CountingTask):
469
	r"""Optimization task with implemented checking for stopping criterias.
470
471
	Attributes:
472
		nGEN (int): Maximum number of algorithm iterations/generations.
473
		nFES (int): Maximum number of function evaluations.
474
		refValue (float): Reference function/fitness values to reach in optimization.
475
		x (numpy.ndarray): Best found individual.
476
		x_f (float): Best found individual function/fitness value.
477
478
	See Also:
479
		* :class:`NiaPy.util.CountingTask`
480
	"""
481
482
	def __init__(self, nFES=inf, nGEN=inf, refValue=None, **kwargs):
483
		r"""Initialize task class for optimization.
484
485
		Arguments:
486
			nFES (Optional[int]): Number of function evaluations.
487
			nGEN (Optional[int]): Number of generations or iterations.
488
			refValue (Optional[float]): Reference value of function/fitness function.
489
490
		See Also:
491
			* :func:`NiaPy.util.CountingTask.__init__`
492
		"""
493
		CountingTask.__init__(self, **kwargs)
494
		self.refValue = (-inf if refValue is None else refValue)
495
		self.x, self.x_f = None, inf
496
		self.nFES, self.nGEN = nFES, nGEN
497
498
	def eval(self, A):
499
		r"""Evaluate solution.
500
501
		Args:
502
			A (numpy.ndarray): Solution to evaluate.
503
504
		Returns:
505
			float: Fitness/function value of solution.
506
507
		See Also:
508
			* :func:`NiaPy.util.StoppingTask.stopCond`
509
			* :func:`NiaPy.util.CountingTask.eval`
510
		"""
511
		if self.stopCond(): return inf * self.optType.value
512
		x_f = CountingTask.eval(self, A)
513
		if x_f < self.x_f: self.x_f = x_f
514
		return x_f
515
516
	def stopCond(self):
517
		r"""Check if stopping condition reached.
518
519
		Returns:
520
			bool: `True` if number of function evaluations or number of algorithm iterations/generations or reference values is reach else `False`
521
		"""
522
		return (self.Evals >= self.nFES) or (self.Iters >= self.nGEN) or (self.refValue > self.x_f)
523
524
	def stopCondI(self):
525
		r"""Check if stopping condition reached and increase number of iterations.
526
527
		Returns:
528
			bool: `True` if number of function evaluations or number of algorithm iterations/generations or reference values is reach else `False`.
529
530
		See Also:
531
			* :func:`NiaPy.util.StoppingTask.stopCond`
532
			* :func:`NiaPy.util.CountingTask.nextIter`
533
		"""
534
		r = self.stopCond()
535
		CountingTask.nextIter(self)
536
		return r
537
538
class ThrowingTask(StoppingTask):
539
	r"""Task that throw exceptions when stopping condition is meet.
540
541
	See Also:
542
		* :class:`NiaPy.util.StoppingTask`
543
	"""
544
	def __init__(self, **kwargs):
545
		r"""Initialize optimization task.
546
547
		Args:
548
			**kwargs (Dict[str, Any]): Additional arguments.
549
550
		See Also:
551
			* :func:`NiaPy.util.StoppingTask.__init__`
552
		"""
553
		StoppingTask.__init__(self, **kwargs)
554
555
	def stopCondE(self):
556
		r"""Throw exception for the given stopping condition.
557
558
		Raises:
559
			* FesException: Thrown when the number of function/fitness evaluations is reached.
560
			* GenException: Thrown when the number of algorithms generations/iterations is reached.
561
			* RefException: Thrown when the reference values is reached.
562
			* TimeException: Thrown when algorithm exceeds time run limit.
563
		"""
564
		# dtime = datetime.now() - self.startTime
565
		if self.Evals >= self.nFES: raise FesException()
566
		if self.Iters >= self.nGEN: raise GenException()
567
		# if self.runTime is not None and self.runTime >= dtime: raise TimeException()
568
		if self.refValue >= self.x_f: raise RefException()
569
570
	def eval(self, A):
571
		r"""Evaluate solution.
572
573
		Args:
574
			A (numpy.ndarray): Solution to evaluate.
575
576
		Returns:
577
			float: Function/fitness values of solution.
578
579
		See Also:
580
			* :func:`NiaPy.util.ThrowingTask.stopCondE`
581
			* :func:`NiaPy.util.StoppingTask.eval`
582
		"""
583
		self.stopCondE()
584
		return StoppingTask.eval(self, A)
585
586
class MoveTask(StoppingTask):
587
	def __init__(self, o=None, fo=None, M=None, fM=None, optF=None, **kwargs):
588
		r"""Initialize task class for optimization.
589
590
		Arguments:
591
			o (numpy.ndarray[Union[float, int]]): Array for shifting.
592
			of (Callable[numpy.ndarray[Union[float, int]]]): Function applied on shifted input.
593
			M (numpy.ndarray[Union[float, int]]): Matrix for rotating.
594
			fM (Callable[numpy.ndarray[Union[float, int]]]): Function applied after rotating.
595
596
		See Also:
597
			* :func:`NiaPy.util.StoppingTask.__init__`
598
		"""
599
		StoppingTask.__init__(self, **kwargs)
600
		self.o = o if isinstance(o, ndarray) or o is None else asarray(o)
601
		self.M = M if isinstance(M, ndarray) or M is None else asarray(M)
602
		self.fo, self.fM, self.optF = fo, fM, optF
603
604
	def eval(self, A):
605
		r"""Evaluate the solution.
606
607
		Args:
608
			A (numpy.ndarray): Solution to evaluate
609
610
		Returns:
611
			float: Fitness/function value of solution.
612
613
		See Also:
614
			* :func:`NiaPy.util.StoppingTask.stopCond`
615
			* :func:`NiaPy.util.StoppingTask.eval`
616
		"""
617
		if self.stopCond(): return inf * self.optType.value
618
		X = A - self.o if self.o is not None else A
619
		X = self.fo(X) if self.fo is not None else X
620
		X = dot(X, self.M) if self.M is not None else X
621
		X = self.fM(X) if self.fM is not None else X
622
		r = StoppingTask.eval(self, X) + (self.optF if self.optF is not None else 0)
623
		if r <= self.x_f: self.x, self.x_f = A, r
624
		return r
625
626
class ScaledTask(Task):
627
	r"""Scaled task.
628
629
	Attributes:
630
		_task (Task): Optimization task with evaluation function.
631
		Lower (numpy.ndarray): Scaled lower limit of search space.
632
		Upper (numpy.ndarray): Scaled upper limit of search space.
633
634
	See Also:
635
		* :class:`NiaPy.util.Task`
636
	"""
637
	def __init__(self, task, Lower, Upper, **kwargs):
638
		r"""Initialize scaled task.
639
640
		Args:
641
			task (Task): Optimization task to scale to new bounds.
642
			Lower (Union[float, int, numpy.ndarray]): New lower bounds.
643
			Upper (Union[float, int, numpy.ndarray]): New upper bounds.
644
			**kwargs (Dict[str, Any]): Additional arguments.
645
646
		See Also:
647
			* :func:`NiaPy.util.fullArray`
648
		"""
649
		Task.__init__(self)
650
		self._task = task
651
		self.D = self._task.D
652
		self.Lower, self.Upper = fullArray(Lower, self.D), fullArray(Upper, self.D)
653
		self.bRange = fabs(Upper - Lower)
654
655
	def stopCond(self):
656
		r"""Test for stopping condition.
657
658
		This function uses `self._task` for checking the stopping criteria.
659
660
		Returns:
661
			bool: `True` if stopping condition is meet else `False`.
662
		"""
663
		return self._task.stopCond()
664
665
	def stopCondI(self):
666
		r"""Test for stopping condition and increments the number of algorithm generations/iterations.
667
668
		This function uses `self._task` for checking the stopping criteria.
669
670
		Returns:
671
			bool: `True` if stopping condition is meet else `False`.
672
		"""
673
		return self._task.stopCondI()
674
675
	def eval(self, A):
676
		r"""Evaluate solution.
677
678
		Args:
679
			A (numpy.ndarray): Solution for calculating function/fitness value.
680
681
		Returns:
682
			float: Function values of solution.
683
		"""
684
		return self._task.eval(A)
685
686
	def evals(self):
687
		r"""Get the number of function evaluations.
688
689
		Returns:
690
			int: Number of function evaluations.
691
		"""
692
		return self._task.evals()
693
694
	def iters(self):
695
		r"""Get the number of algorithms generations/iterations.
696
697
		Returns:
698
			int: Number of algorithms generations/iterations.
699
		"""
700
		return self._task.iters()
701
702
	def nextIter(self):
703
		r"""Increment the number of iterations/generations.
704
705
		Function uses `self._task` to increment number of generations/iterations.
706
		"""
707
		self._task.nextIter()
708
709
class TaskConvPrint(StoppingTask):
710
	r"""Task class with printing out new global best solutions found.
711
712
	Attributes:
713
		xb (numpy.ndarray): Global best solution.
714
		xb_f (float): Global best function/fitness values.
715
716
	See Also:
717
		* :class:`NiaPy.util.StoppingTask`
718
	"""
719
	def __init__(self, **kwargs):
720
		r"""Initialize TaskConvPrint class.
721
722
		Args:
723
			**kwargs (Dict[str, Any]): Additional arguments.
724
725
		See Also:
726
			* :func:`NiaPy.util.StoppingTask.__init__`
727
		"""
728
		StoppingTask.__init__(self, **kwargs)
729
		self.xb, self.xb_f = None, inf
730
731
	def eval(self, A):
732
		r"""Evaluate solution.
733
734
		Args:
735
			A (nupy.ndarray): Solution to evaluate.
736
737
		Returns:
738
			float: Function/Fitness values of solution.
739
740
		See Also:
741
			* :func:`NiaPy.util.StoppingTask.eval`
742
		"""
743
		x_f = StoppingTask.eval(self, A)
744
		if self.x_f != self.xb_f:
745
			self.xb, self.xb_f = A, x_f
746
			logger.info('nFES:%d nGEN:%d => %s -> %s' % (self.Evals, self.Iters, self.xb, self.xb_f * self.optType.value))
747
		return x_f
748
749
class TaskConvSave(StoppingTask):
750
	r"""Task class with logging of function evaluations need to reach some function vale.
751
752
	Attributes:
753
		evals (List[int]): List of ints representing when the new global best was found.
754
		x_f_vals (List[float]): List of floats representing function/fitness values found.
755
756
	See Also:
757
		* :class:`NiaPy.util.StoppingTask`
758
	"""
759
	def __init__(self, **kwargs):
760
		r"""Initialize TaskConvSave class.
761
762
		Args:
763
			**kwargs (Dict[str, Any]): Additional arguments.
764
765
		See Also:
766
			* :func:`NiaPy.util.StoppingTask.__init__`
767
		"""
768
		StoppingTask.__init__(self, **kwargs)
769
		self.evals = []
770
		self.x_f_vals = []
771
772
	def eval(self, A):
773
		r"""Evaluate solution.
774
775
		Args:
776
			A (numpy.ndarray): Individual/solution to evaluate.
777
778
		Returns:
779
			float: Function/fitness values of individual.
780
781
		See Also:
782
			* :func:`SNiaPy.util.toppingTask.eval`
783
		"""
784
		x_f = StoppingTask.eval(self, A)
785
		if x_f <= self.x_f:
786
			self.evals.append(self.Evals)
787
			self.x_f_vals.append(x_f)
788
		return x_f
789
790
	def return_conv(self):
791
		r"""Get values of x and y axis for plotting covariance graph.
792
793
		Returns:
794
			Tuple[List[int], List[float]]:
795
				1. List of ints of function evaluations.
796
				2. List of ints of function/fitness values.
797
		"""
798
		return self.evals, self.x_f_vals
799
800
class TaskConvPlot(StoppingTask):
801
	r"""Task class with ability of showing convergence graph.
802
803
	Attributes:
804
		iters (List[int]): List of ints representing when the new global best was found.
805
		x_fs (List[float]): List of floats representing function/fitness values found.
806
807
	See Also:
808
		* :class:`NiaPy.util.StoppingTask`
809
	"""
810
	def __init__(self, **kwargs):
811
		r"""TODO.
812
813
		Args:
814
			**kwargs (Dict[str, Any]): Additional arguments.
815
816
		See Also:
817
			* :func:`NiaPy.util.StoppingTask.__init__`
818
		"""
819
		StoppingTask.__init__(self, **kwargs)
820
		self.x_fs, self.iters = [], []
821
		self.fig = plt.figure()
822
		self.ax = self.fig.subplots(nrows=1, ncols=1)
823
		self.ax.set_xlim(0, self.nFES)
824
		self.line, = self.ax.plot(self.iters, self.x_fs, animated=True)
825
		self.ani = anim.FuncAnimation(self.fig, self.updatePlot, blit=True)
826
		self.showPlot()
827
828
	def eval(self, A):
829
		r"""Evaluate solution.
830
831
		Args:
832
			A (numpy.ndarray): Solution to evaluate.
833
834
		Returns:
835
			float: Fitness/function values of solution.
836
		"""
837
		x_f = StoppingTask.eval(self, A)
838
		if not self.x_fs: self.x_fs.append(x_f)
839
		elif x_f < self.x_fs[-1]: self.x_fs.append(x_f)
840
		else: self.x_fs.append(self.x_fs[-1])
841
		self.iters.append(self.Evals)
842
		return x_f
843
844
	def showPlot(self):
845
		r"""Animation updating function."""
846
		plt.show(block=False)
847
		plt.pause(0.001)
848
849
	def updatePlot(self, frame):
850
		r"""Update mathplotlib figure.
851
852
		Args:
853
			frame (): TODO
854
855
		Returns:
856
			Tuple[List[float], Any]:
857
				1. Line
858
		"""
859
		if self.x_fs:
860
			max_fs, min_fs = self.x_fs[0], self.x_fs[-1]
861
			self.ax.set_ylim(min_fs + 1, max_fs + 1)
862
			self.line.set_data(self.iters, self.x_fs)
863
		return self.line,
864
865
class TaskComposition(MoveTask):
866
	def __init__(self, benchmarks=None, rho=None, lamb=None, bias=None, **kwargs):
867
		r"""Initialize of composite function problem.
868
869
		Arguments:
870
			benchmarks (List[Benchmark]): Optimization function to use in composition
871
			delta (numpy.ndarray[float]): TODO
872
			lamb (numpy.ndarray[float]): TODO
873
			bias (numpy.ndarray[float]): TODO
874
875
		See Also:
876
			* :func:`NiaPy.util.MoveTask.__init__`
877
878
		TODO:
879
			Class is a work in progress.
880
		"""
881
		MoveTask.__init__(self, **kwargs)
882
883
	def eval(self, A):
884
		r"""TODO.
885
886
		Args:
887
			A:
888
889
		Returns:
890
			float:
891
892
		Todo:
893
			Usage of multiple functions on the same time
894
		"""
895
		return inf
896
897
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
898