NiaPy.algorithms.other.aso.Crossover()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 24
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nop 11
dl 0
loc 24
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

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
import logging
3
from scipy.spatial.distance import euclidean
4
from numpy import apply_along_axis, argmin, full, inf, where, asarray, random as rand, sort, exp
5
from NiaPy.algorithms.algorithm import Algorithm
6
from NiaPy.util import fullArray
7
8
logging.basicConfig()
9
logger = logging.getLogger('NiaPy.algorithms.other')
10
logger.setLevel('INFO')
11
12
__all__ = ['AnarchicSocietyOptimization', 'Elitism', 'Sequential', 'Crossover']
13
14
def Elitism(x, xpb, xb, xr, MP_c, MP_s, MP_p, F, CR, task, rnd=rand):
15
	r"""Select the best of all three strategies.
16
17
	Args:
18
		x (numpy.ndarray): individual position.
19
		xpb (numpy.ndarray): individuals best position.
20
		xb (numpy.ndarray): current best position.
21
		xr (numpy.ndarray): random individual.
22
		MP_c (float): Fickleness index value.
23
		MP_s (float): External irregularity index value.
24
		MP_p (float): Internal irregularity index value.
25
		F (float): scale factor.
26
		CR (float): crossover factor.
27
		task (Task): optimization task.
28
		rnd (mtrand.randomstate): random number generator.
29
30
	Returns:
31
		Tuple[numpy.ndarray, float]:
32
			1. New position of individual
33
			2. New positions fitness/function value
34
	"""
35
	xn = [task.repair(MP_C(x, F, CR, MP_c, rnd), rnd=rnd), task.repair(MP_S(x, xr, xb, CR, MP_s, rnd), rnd=rnd), task.repair(MP_P(x, xpb, CR, MP_p, rnd), rnd=rnd)]
36
	xn_f = apply_along_axis(task.eval, 1, xn)
37
	ib = argmin(xn_f)
38
	return xn[ib], xn_f[ib]
39
40
def Sequential(x, xpb, xb, xr, MP_c, MP_s, MP_p, F, CR, task, rnd=rand):
41
	r"""Sequentialy combines all three strategies.
42
43
	Args:
44
		x (numpy.ndarray): individual position.
45
		xpb (numpy.ndarray): individuals best position.
46
		xb (numpy.ndarray): current best position.
47
		xr (numpy.ndarray): random individual.
48
		MP_c (float): Fickleness index value.
49
		MP_s (float): External irregularity index value.
50
		MP_p (float): Internal irregularity index value.
51
		F (float): scale factor.
52
		CR (float): crossover factor.
53
		task (Task): optimization task.
54
		rnd (mtrand.randomstate): random number generator.
55
56
	Returns:
57
		tuple[numpy.ndarray, float]:
58
			1. new position
59
			2. new positions function/fitness value
60
	"""
61
	xn = task.repair(MP_S(MP_P(MP_C(x, F, CR, MP_c, rnd), xpb, CR, MP_p, rnd), xr, xb, CR, MP_s, rnd), rnd=rnd)
62
	return xn, task.eval(xn)
63
64
def Crossover(x, xpb, xb, xr, MP_c, MP_s, MP_p, F, CR, task, rnd=rand):
65
	r"""Create a crossover over all three strategies.
66
67
	Args:
68
		x (numpy.ndarray): individual position.
69
		xpb (numpy.ndarray): individuals best position.
70
		xb (numpy.ndarray): current best position.
71
		xr (numpy.ndarray): random individual.
72
		MP_c (float): Fickleness index value.
73
		MP_s (float): External irregularity index value.
74
		MP_p (float): Internal irregularity index value.
75
		F (float): scale factor.
76
		CR (float): crossover factor.
77
		task (Task): optimization task.
78
		rnd (mtrand.randomstate): random number generator.
79
80
	Returns:
81
		Tuple[numpy.ndarray, float]:
82
			1. new position
83
			2. new positions function/fitness value
84
	"""
85
	xns = [task.repair(MP_C(x, F, CR, MP_c, rnd), rnd=rnd), task.repair(MP_S(x, xr, xb, CR, MP_s, rnd), rnd=rnd), task.repair(MP_P(x, xpb, CR, MP_p, rnd), rnd=rnd)]
86
	x = asarray([xns[rnd.randint(len(xns))][i] if rnd.rand() < CR else x[i] for i in range(len(x))])
87
	return x, task.eval(x)
88
89
def MP_C(x, F, CR, MP, rnd=rand):
90
	r"""Get bew position based on fickleness.
91
92
	Args:
93
		x (numpy.ndarray): Current individuals position.
94
		F (float): Scale factor.
95
		CR (float): Crossover probability.
96
		MP (float): Fickleness index value
97
		rnd (mtrand.RandomState): Random number generator
98
99
	Returns:
100
		numpy.ndarray: New position
101
	"""
102
	if MP < 0.5:
103
		b = sort(rnd.choice(len(x), 2, replace=False))
104
		x[b[0]:b[1]] = x[b[0]:b[1]] + F * rnd.normal(0, 1, b[1] - b[0])
105
		return x
106
	return asarray([x[i] + F * rnd.normal(0, 1) if rnd.rand() < CR else x[i] for i in range(len(x))])
107
108
def MP_S(x, xr, xb, CR, MP, rnd=rand):
109
	r"""Get new position based on external irregularity.
110
111
	Args:
112
		x (numpy.ndarray): Current individuals position.
113
		xr (numpy.ndarray): Random individuals position.
114
		xb (numpy.ndarray): Global best individuals position.
115
		CR (float): Crossover probability.
116
		MP (float): External irregularity index.
117
		rnd (mtrand.RandomState): Random number generator.
118
119
	Returns:
120
		numpy.ndarray: New position.
121
	"""
122
	if MP < 0.25:
123
		b = sort(rnd.choice(len(x), 2, replace=False))
124
		x[b[0]:b[1]] = xb[b[0]:b[1]]
125
		return x
126
	elif MP < 0.5: return asarray([xb[i] if rnd.rand() < CR else x[i] for i in range(len(x))])
127
	elif MP < 0.75:
128
		b = sort(rnd.choice(len(x), 2, replace=False))
129
		x[b[0]:b[1]] = xr[b[0]:b[1]]
130
		return x
131
	return asarray([xr[i] if rnd.rand() < CR else x[i] for i in range(len(x))])
132
133
def MP_P(x, xpb, CR, MP, rnd=rand):
134
	r"""Get new position based on internal irregularity.
135
136
	Args:
137
		x (numpy.ndarray): Current individuals position.
138
		xpb (numpy.ndarray): Current individuals personal best position.
139
		CR (float): Crossover probability.
140
		MP (float): Internal irregularity index value.
141
		rnd (mtrand.RandomState): Random number generator.
142
143
	Returns:
144
		numpy.ndarray: Current individuals new position.
145
	"""
146
	if MP < 0.5:
147
		b = sort(rnd.choice(len(x), 2, replace=False))
148
		x[b[0]:b[1]] = xpb[b[0]:b[1]]
149
		return x
150
	return asarray([xpb[i] if rnd.rand() < CR else x[i] for i in range(len(x))])
151
152
class AnarchicSocietyOptimization(Algorithm):
153
	r"""Implementation of Anarchic Society Optimization algorithm.
154
155
	Algorithm:
156
		Anarchic Society Optimization algorithm
157
158
	Date:
159
		2018
160
161
	Authors:
162
		Klemen Berkovič
163
164
	License:
165
		MIT
166
167
	Reference paper:
168
		Ahmadi-Javid, Amir. "Anarchic Society Optimization: A human-inspired method." Evolutionary Computation (CEC), 2011 IEEE Congress on. IEEE, 2011.
169
170
	Attributes:
171
		Name (list of str): List of stings representing name of algorithm.
172
		alpha (List[float]): Factor for fickleness index function :math:`\in [0, 1]`.
173
		gamma (List[float]): Factor for external irregularity index function :math:`\in [0, \infty)`.
174
		theta (List[float]): Factor for internal irregularity index function :math:`\in [0, \infty)`.
175
		d (Callable[[float, float], float]): function that takes two arguments that are function values and calcs the distance between them.
176
		dn (Callable[[numpy.ndarray, numpy.ndarray], float]): function that takes two arguments that are points in function landscape and calcs the distance between them.
177
		nl (float): Normalized range for neighborhood search :math:`\in (0, 1]`.
178
		F (float): Mutation parameter.
179
		CR (float): Crossover parameter :math:`\in [0, 1]`.
180
		Combination (Callable[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray, float, float, float, float, float, float, Task, mtrand.RandomState]): Function for combining individuals to get new position/individual.
181
182
	See Also:
183
		* :class:`NiaPy.algorithms.Algorithm`
184
	"""
185
	Name = ['AnarchicSocietyOptimization', 'ASO']
186
187
	@staticmethod
188
	def algorithmInfo():
189
		r"""Get basic information about the algorithm.
190
191
		Returns:
192
			str: Basic information.
193
194
		See Also:
195
			:func:`NiaPy.algorithms.algorithm.Algorithm.algorithmInfo`
196
		"""
197
		return r"""Ahmadi-Javid, Amir. "Anarchic Society Optimization: A human-inspired method." Evolutionary Computation (CEC), 2011 IEEE Congress on. IEEE, 2011."""
198
199
	@staticmethod
200
	def typeParameters():
201
		r"""Get dictionary with functions for checking values of parameters.
202
203
		Returns:
204
			Dict[str, Callable]:
205
				* alpha (Callable): TODO
206
				* gamma (Callable): TODO
207
				* theta (Callable): TODO
208
				* nl (Callable): TODO
209
				* F (Callable[[Union[float, int]], bool]): TODO
210
				* CR (Callable[[Union[float, int]], bool]): TODO
211
212
		See Also:
213
			* :func:`NiaPy.algorithms.Algorithm.typeParameters`
214
		"""
215
		d = Algorithm.typeParameters()
216
		d.update({
217
			'alpha': lambda x: True,
218
			'gamma': lambda x: True,
219
			'theta': lambda x: True,
220
			'nl': lambda x: True,
221
			'F': lambda x: isinstance(x, (int, float)) and x > 0,
222
			'CR': lambda x: isinstance(x, float) and 0 <= x <= 1
223
		})
224
		return d
225
226
	def setParameters(self, NP=43, alpha=(1, 0.83), gamma=(1.17, 0.56), theta=(0.932, 0.832), d=euclidean, dn=euclidean, nl=1, F=1.2, CR=0.25, Combination=Elitism, **ukwargs):
227
		r"""Set the parameters for the algorith.
228
229
		Arguments:
230
			alpha (Optional[List[float]]): Factor for fickleness index function :math:`\in [0, 1]`.
231
			gamma (Optional[List[float]]): Factor for external irregularity index function :math:`\in [0, \infty)`.
232
			theta (Optional[List[float]]): Factor for internal irregularity index function :math:`\in [0, \infty)`.
233
			d (Optional[Callable[[float, float], float]]): function that takes two arguments that are function values and calcs the distance between them.
234
			dn (Optional[Callable[[numpy.ndarray, numpy.ndarray], float]]): function that takes two arguments that are points in function landscape and calcs the distance between them.
235
			nl (Optional[float]): Normalized range for neighborhood search :math:`\in (0, 1]`.
236
			F (Optional[float]): Mutation parameter.
237
			CR (Optional[float]): Crossover parameter :math:`\in [0, 1]`.
238
			Combination (Optional[Callable[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray, float, float, float, float, float, float, Task, mtrand.RandomState]]): Function for combining individuals to get new position/individual.
239
240
		See Also:
241
			* :func:`NiaPy.algorithms.Algorithm.setParameters`
242
			* Combination methods:
243
				* :func:`NiaPy.algorithms.other.Elitism`
244
				* :func:`NiaPy.algorithms.other.Crossover`
245
				* :func:`NiaPy.algorithms.other.Sequential`
246
		"""
247
		Algorithm.setParameters(self, NP=NP, **ukwargs)
248
		self.alpha, self.gamma, self.theta, self.d, self.dn, self.nl, self.F, self.CR, self.Combination = alpha, gamma, theta, d, dn, nl, F, CR, Combination
249
250
	def init(self, task):
251
		r"""Initialize dynamic parameters of algorithm.
252
253
		Args:
254
			task (Task): Optimization task.
255
256
		Returns:
257
			Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]
258
				1. Array of `self.alpha` propagated values
259
				2. Array of `self.gamma` propagated values
260
				3. Array of `self.theta` propagated values
261
		"""
262
		return fullArray(self.alpha, self.NP), fullArray(self.gamma, self.NP), fullArray(self.theta, self.NP)
263
264
	def FI(self, x_f, xpb_f, xb_f, alpha):
265
		r"""Get fickleness index.
266
267
		Args:
268
			x_f (float): Individuals fitness/function value.
269
			xpb_f (float): Individuals personal best fitness/function value.
270
			xb_f (float): Current best found individuals fitness/function value.
271
			alpha (float): TODO.
272
273
		Returns:
274
			float: Fickleness index.
275
		"""
276
		return 1 - alpha * xb_f / x_f - (1 - alpha) * xpb_f / x_f
277
278
	def EI(self, x_f, xnb_f, gamma):
279
		r"""Get external irregularity index.
280
281
		Args:
282
			x_f (float): Individuals fitness/function value.
283
			xnb_f (float): Individuals new fitness/function value.
284
			gamma (float): TODO.
285
286
		Returns:
287
			float: External irregularity index.
288
		"""
289
		return 1 - exp(-gamma * self.d(x_f, xnb_f))
290
291
	def II(self, x_f, xpb_f, theta):
292
		r"""Get internal irregularity index.
293
294
		Args:
295
			x_f (float): Individuals fitness/function value.
296
			xpb_f (float): Individuals personal best fitness/function value.
297
			theta (float): TODO.
298
299
		Returns:
300
			float: Internal irregularity index
301
		"""
302
		return 1 - exp(-theta * self.d(x_f, xpb_f))
303
304
	def getBestNeighbors(self, i, X, X_f, rs):
305
		r"""Get neighbors of individual.
306
307
		Mesurment of distance for neighborhud is defined with `self.nl`.
308
		Function for calculating distances is define with `self.dn`.
309
310
		Args:
311
			i (int): Index of individual for hum we are looking for neighbours.
312
			X (numpy.ndarray): Current population.
313
			X_f (numpy.ndarray[float]): Current population fitness/function values.
314
			rs (numpy.ndarray[float]): Distance between individuals.
315
316
		Returns:
317
			numpy.ndarray[int]: Indexes that represent individuals closest to `i`-th individual.
318
		"""
319
		nn = asarray([self.dn(X[i], X[j]) / rs for j in range(len(X))])
320
		return argmin(X_f[where(nn <= self.nl)])
321
322
	def uBestAndPBest(self, X, X_f, Xpb, Xpb_f):
323
		r"""Update personal best solution of all individuals in population.
324
325
		Args:
326
			X (numpy.ndarray): Current population.
327
			X_f (numpy.ndarray[float]): Current population fitness/function values.
328
			Xpb (numpy.ndarray): Current population best positions.
329
			Xpb_f (numpy.ndarray[float]): Current populations best positions fitness/function values.
330
331
		Returns:
332
			Tuple[numpy.ndarray, numpy.ndarray[float], numpy.ndarray, float]:
333
				1. New personal best positions for current population.
334
				2. New personal best positions function/fitness values for current population.
335
				3. New best individual.
336
				4. New best individual fitness/function value.
337
		"""
338
		ix_pb = where(X_f < Xpb_f)
339
		Xpb[ix_pb], Xpb_f[ix_pb] = X[ix_pb], X_f[ix_pb]
340
		return Xpb, Xpb_f
341
342
	def initPopulation(self, task):
343
		r"""Initialize first population and additional arguments.
344
345
		Args:
346
			task (Task): Optimization task
347
348
		Returns:
349
			Tuple[numpy.ndarray, numpy.ndarray, dict]:
350
				1. Initialized population
351
				2. Initialized population fitness/function values
352
				3. Dict[str, Any]:
353
					* Xpb (numpy.ndarray): Initialized populations best positions.
354
					* Xpb_f (numpy.ndarray): Initialized populations best positions function/fitness values.
355
					* alpha (numpy.ndarray):
356
					* gamma (numpy.ndarray):
357
					* theta (numpy.ndarray):
358
					* rs (float): Distance of search space.
359
360
		See Also:
361
			* :func:`NiaPy.algorithms.algorithm.Algorithm.initPopulation`
362
			* :func:`NiaPy.algorithms.other.aso.AnarchicSocietyOptimization.init`
363
		"""
364
		X, X_f, d = Algorithm.initPopulation(self, task)
365
		alpha, gamma, theta = self.init(task)
366
		Xpb, Xpb_f = self.uBestAndPBest(X, X_f, full([self.NP, task.D], 0.0), full(self.NP, task.optType.value * inf))
367
		d.update({'Xpb': Xpb, 'Xpb_f': Xpb_f, 'alpha': alpha, 'gamma': gamma, 'theta': theta, 'rs': self.d(task.Upper, task.Lower)})
368
		return X, X_f, d
369
370
	def runIteration(self, task, X, X_f, xb, fxb, Xpb, Xpb_f, alpha, gamma, theta, rs, **dparams):
371
		r"""Core function of AnarchicSocietyOptimization algorithm.
372
373
		Args:
374
			task (Task): Optimization task.
375
			X (numpy.ndarray): Current populations positions.
376
			X_f (numpy.ndarray): Current populations function/fitness values.
377
			xb (numpy.ndarray): Current global best individuals position.
378
			fxb (float): Current global best individual function/fitness value.
379
			Xpb (numpy.ndarray): Current populations best positions.
380
			Xpb_f (numpy.ndarray): Current population best positions function/fitness values.
381
			alpha (numpy.ndarray): TODO.
382
			gamma (numpy.ndarray):
383
			theta (numpy.ndarray):
384
			**dparams: Additional arguments.
385
386
		Returns:
387
			Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, dict]:
388
				1. Initialized population
389
				2. Initialized population fitness/function values
390
				3. New global best solution
391
				4. New global best solutions fitness/objective value
392
				5. Dict[str, Union[float, int, numpy.ndarray]:
393
					* Xpb (numpy.ndarray): Initialized populations best positions.
394
					* Xpb_f (numpy.ndarray): Initialized populations best positions function/fitness values.
395
					* alpha (numpy.ndarray):
396
					* gamma (numpy.ndarray):
397
					* theta (numpy.ndarray):
398
					* rs (float): Distance of search space.
399
		"""
400
		Xin = [self.getBestNeighbors(i, X, X_f, rs) for i in range(len(X))]
401
		MP_c, MP_s, MP_p = asarray([self.FI(X_f[i], Xpb_f[i], fxb, alpha[i]) for i in range(len(X))]), asarray([self.EI(X_f[i], X_f[Xin[i]], gamma[i]) for i in range(len(X))]), asarray([self.II(X_f[i], Xpb_f[i], theta[i]) for i in range(len(X))])
402
		Xtmp = asarray([self.Combination(X[i], Xpb[i], xb, X[self.randint(len(X), skip=[i])], MP_c[i], MP_s[i], MP_p[i], self.F, self.CR, task, self.Rand) for i in range(len(X))])
403
		X, X_f = asarray([Xtmp[i][0] for i in range(len(X))]), asarray([Xtmp[i][1] for i in range(len(X))])
404
		Xpb, Xpb_f = self.uBestAndPBest(X, X_f, Xpb, Xpb_f)
405
		xb, fxb = self.getBest(X, X_f, xb, fxb)
406
		return X, X_f, xb, fxb, {'Xpb': Xpb, 'Xpb_f': Xpb_f, 'alpha': alpha, 'gamma': gamma, 'theta': theta, 'rs': rs}
407
408
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
409