AnarchicSocietyOptimization.init()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 13
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 2
dl 0
loc 13
rs 10
c 0
b 0
f 0
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