GeneticAlgorithm.setParameters()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 30
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 9
dl 0
loc 30
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
4
from numpy import argmin, sort, random as rand, asarray, fmin, fmax, sum, empty
5
6
from NiaPy.algorithms.algorithm import Algorithm, Individual, defaultIndividualInit
7
8
logging.basicConfig()
9
logger = logging.getLogger('NiaPy.algorithms.basic')
10
logger.setLevel('INFO')
11
12
__all__ = ['GeneticAlgorithm', 'TournamentSelection', 'RouletteSelection', 'TwoPointCrossover', 'MultiPointCrossover', 'UniformCrossover', 'UniformMutation', 'CreepMutation', 'CrossoverUros', 'MutationUros']
13
14
def TournamentSelection(pop, ic, ts, x_b, rnd=rand):
15
	r"""Tournament selection method.
16
17
	Args:
18
		pop (numpy.ndarray[Individual]): Current population.
19
		ic (int): Index of current individual in population.
20
		ts (int): Tournament size.
21
		x_b (Individual): Global best individual.
22
		rnd (mtrand.RandomState): Random generator.
23
24
	Returns:
25
		Individual: Winner of the tournament.
26
	"""
27
	comps = [pop[i] for i in rand.choice(len(pop), ts, replace=False)]
28
	return comps[argmin([c.f for c in comps])]
29
30
def RouletteSelection(pop, ic, ts, x_b, rnd=rand):
31
	r"""Roulette selection method.
32
33
	Args:
34
		pop (numpy.ndarray[Individual]): Current population.
35
		ic (int): Index of current individual in population.
36
		ts (int): Unused argument.
37
		x_b (Individual): Global best individual.
38
		rnd (mtrand.RandomState): Random generator.
39
40
	Returns:
41
		Individual: selected individual.
42
	"""
43
	f = sum([x.f for x in pop])
44
	qi = sum([pop[i].f / f for i in range(ic + 1)])
45
	return pop[ic].x if rnd.rand() < qi else x_b
46
47
def TwoPointCrossover(pop, ic, cr, rnd=rand):
48
	r"""Two point crossover method.
49
50
	Args:
51
		pop (numpy.ndarray[Individual]): Current population.
52
		ic (int): Index of current individual.
53
		cr (float): Crossover probability.
54
		rnd (mtrand.RandomState): Random generator.
55
56
	Returns:
57
		numpy.ndarray: New genotype.
58
	"""
59
	io = ic
60
	while io != ic: io = rnd.randint(len(pop))
61
	r = sort(rnd.choice(len(pop[ic]), 2))
62
	x = pop[ic].x
63
	x[r[0]:r[1]] = pop[io].x[r[0]:r[1]]
64
	return asarray(x)
65
66
def MultiPointCrossover(pop, ic, n, rnd=rand):
67
	r"""Multi point crossover method.
68
69
	Args:
70
		pop (numpy.ndarray[Individual]): Current population.
71
		ic (int): Index of current individual.
72
		n (flat): TODO.
73
		rnd (mtrand.RandomState): Random generator.
74
75
	Returns:
76
		numpy.ndarray: New genotype.
77
	"""
78
	io = ic
79
	while io != ic: io = rnd.randint(len(pop))
80
	r, x = sort(rnd.choice(len(pop[ic]), 2 * n)), pop[ic].x
81
	for i in range(n): x[r[2 * i]:r[2 * i + 1]] = pop[io].x[r[2 * i]:r[2 * i + 1]]
82
	return asarray(x)
83
84
def UniformCrossover(pop, ic, cr, rnd=rand):
85
	r"""Uniform crossover method.
86
87
	Args:
88
		pop (numpy.ndarray[Individual]): Current population.
89
		ic (int): Index of current individual.
90
		cr (float): Crossover probability.
91
		rnd (mtrand.RandomState): Random generator.
92
93
	Returns:
94
		numpy.ndarray: New genotype.
95
	"""
96
	io = ic
97
	while io != ic: io = rnd.randint(len(pop))
98
	j = rnd.randint(len(pop[ic]))
99
	x = [pop[io][i] if rnd.rand() < cr or i == j else pop[ic][i] for i in range(len(pop[ic]))]
100
	return asarray(x)
101
102
def CrossoverUros(pop, ic, cr, rnd=rand):
103
	r"""Crossover made by Uros Mlakar.
104
105
	Args:
106
		pop (numpy.ndarray[Individual]): Current population.
107
		ic (int): Index of current individual.
108
		cr (float): Crossover probability.
109
		rnd (mtrand.RandomState): Random generator.
110
111
	Returns:
112
		numpy.ndarray: New genotype.
113
	"""
114
	io = ic
115
	while io != ic: io = rnd.randint(len(pop))
116
	alpha = cr + (1 + 2 * cr) * rnd.rand(len(pop[ic]))
117
	x = alpha * pop[ic] + (1 - alpha) * pop[io]
118
	return x
119
120 View Code Duplication
def UniformMutation(pop, ic, mr, task, rnd=rand):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
121
	r"""Uniform mutation method.
122
123
	Args:
124
		pop (numpy.ndarray[Individual]): Current population.
125
		ic (int): Index of current individual.
126
		mr (float): Mutation probability.
127
		task (Task): Optimization task.
128
		rnd (mtrand.RandomState): Random generator.
129
130
	Returns:
131
		numpy.ndarray: New genotype.
132
	"""
133
	j = rnd.randint(task.D)
134
	nx = [rnd.uniform(task.Lower[i], task.Upper[i]) if rnd.rand() < mr or i == j else pop[ic][i] for i in range(task.D)]
135
	return asarray(nx)
136
137
def MutationUros(pop, ic, mr, task, rnd=rand):
138
	r"""Mutation method made by Uros Mlakar.
139
140
	Args:
141
		pop (numpy.ndarray[Individual]): Current population.
142
		ic (int): Index of individual.
143
		mr (float): Mutation rate.
144
		task (Task): Optimization task.
145
		rnd (mtrand.RandomState): Random generator.
146
147
	Returns:
148
		numpy.ndarray: New genotype.
149
	"""
150
	return fmin(fmax(rnd.normal(pop[ic], mr * task.bRange), task.Lower), task.Upper)
151
152 View Code Duplication
def CreepMutation(pop, ic, mr, task, rnd=rand):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
153
	r"""Creep mutation method.
154
155
	Args:
156
		pop (numpy.ndarray[Individual]): Current population.
157
		ic (int): Index of current individual.
158
		mr (float): Mutation probability.
159
		task (Task): Optimization task.
160
		rnd (mtrand.RandomState): Random generator.
161
162
	Returns:
163
		numpy.ndarray: New genotype.
164
	"""
165
	ic, j = rnd.randint(len(pop)), rnd.randint(task.D)
166
	nx = [rnd.uniform(task.Lower[i], task.Upper[i]) if rnd.rand() < mr or i == j else pop[ic][i] for i in range(task.D)]
167
	return asarray(nx)
168
169
class GeneticAlgorithm(Algorithm):
170
	r"""Implementation of Genetic Algorithm.
171
172
	Algorithm:
173
		Genetic algorithm
174
175
	Date:
176
		2018
177
178
	Author:
179
		Klemen Berkovič
180
181
	Reference paper:
182
		Goldberg, David (1989). Genetic Algorithms in Search, Optimization and Machine Learning. Reading, MA: Addison-Wesley Professional.
183
184
	License:
185
		MIT
186
187
	Attributes:
188
		Name (List[str]): List of strings representing algorithm name.
189
		Ts (int): Tournament size.
190
		Mr (float): Mutation rate.
191
		Cr (float): Crossover rate.
192
		Selection (Callable[[numpy.ndarray[Individual], int, int, Individual, mtrand.RandomState], Individual]): Selection operator.
193
		Crossover (Callable[[numpy.ndarray[Individual], int, float, mtrand.RandomState], Individual]): Crossover operator.
194
		Mutation (Callable[[numpy.ndarray[Individual], int, float, Task, mtrand.RandomState], Individual]): Mutation operator.
195
196
	See Also:
197
		* :class:`NiaPy.algorithms.Algorithm`
198
	"""
199
	Name = ['GeneticAlgorithm', 'GA']
200
201
	@staticmethod
202
	def algorithmInfo():
203
		r"""Get basic information of algorithm.
204
205
		Returns:
206
			str: Basic information of algorithm.
207
208
		See Also:
209
			* :func:`NiaPy.algorithms.Algorithm.algorithmInfo`
210
		"""
211
		return r"""On info"""
212
213
	@staticmethod
214
	def typeParameters():
215
		r"""Get dictionary with functions for checking values of parameters.
216
217
		Returns:
218
			Dict[str, Callable]:
219
				* Ts (Callable[[int], bool]): Tournament size.
220
				* Mr (Callable[[float], bool]): Probability of mutation.
221
				* Cr (Callable[[float], bool]): Probability of crossover.
222
223
		See Also:
224
			* :func:`NiaPy.algorithms.Algorithm.typeParameters`
225
		"""
226
		d = Algorithm.typeParameters()
227
		d.update({
228
			'Ts': lambda x: isinstance(x, int) and x > 1,
229
			'Mr': lambda x: isinstance(x, float) and 0 <= x <= 1,
230
			'Cr': lambda x: isinstance(x, float) and 0 <= x <= 1
231
		})
232
		return d
233
234
	def setParameters(self, NP=25, Ts=5, Mr=0.25, Cr=0.25, Selection=TournamentSelection, Crossover=UniformCrossover, Mutation=UniformMutation, **ukwargs):
235
		r"""Set the parameters of the algorithm.
236
237
		Arguments:
238
			NP (Optional[int]): Population size.
239
			Ts (Optional[int]): Tournament selection.
240
			Mr (Optional[int]): Mutation rate.
241
			Cr (Optional[float]): Crossover rate.
242
			Selection (Optional[Callable[[numpy.ndarray[Individual], int, int, Individual, mtrand.RandomState], Individual]]): Selection operator.
243
			Crossover (Optional[Callable[[numpy.ndarray[Individual], int, float, mtrand.RandomState], Individual]]): Crossover operator.
244
			Mutation (Optional[Callable[[numpy.ndarray[Individual], int, float, Task, mtrand.RandomState], Individual]]): Mutation operator.
245
246
		See Also:
247
			* :func:`NiaPy.algorithms.Algorithm.setParameters`
248
			* Selection:
249
				* :func:`NiaPy.algorithms.basic.TournamentSelection`
250
				* :func:`NiaPy.algorithms.basic.RouletteSelection`
251
			* Crossover:
252
				* :func:`NiaPy.algorithms.basic.UniformCrossover`
253
				* :func:`NiaPy.algorithms.basic.TwoPointCrossover`
254
				* :func:`NiaPy.algorithms.basic.MultiPointCrossover`
255
				* :func:`NiaPy.algorithms.basic.CrossoverUros`
256
			* Mutations:
257
				* :func:`NiaPy.algorithms.basic.UniformMutation`
258
				* :func:`NiaPy.algorithms.basic.CreepMutation`
259
				* :func:`NiaPy.algorithms.basic.MutationUros`
260
		"""
261
		Algorithm.setParameters(self, NP=NP, itype=ukwargs.pop('itype', Individual), InitPopFunc=ukwargs.pop('InitPopFunc', defaultIndividualInit), **ukwargs)
262
		self.Ts, self.Mr, self.Cr = Ts, Mr, Cr
263
		self.Selection, self.Crossover, self.Mutation = Selection, Crossover, Mutation
264
265
	def runIteration(self, task, pop, fpop, xb, fxb, **dparams):
266
		r"""Core function of GeneticAlgorithm algorithm.
267
268
		Args:
269
			task (Task): Optimization task.
270
			pop (numpy.ndarray): Current population.
271
			fpop (numpy.ndarray): Current populations fitness/function values.
272
			xb (numpy.ndarray): Global best individual.
273
			fxb (float): Global best individuals function/fitness value.
274
			**dparams (Dict[str, Any]): Additional arguments.
275
276
		Returns:
277
			Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, Dict[str, Any]]:
278
				1. New population.
279
				2. New populations function/fitness values.
280
				3. New global best solution
281
				4. New global best solutions fitness/objective value
282
				5. Additional arguments.
283
		"""
284
		npop = empty(self.NP, dtype=object)
285
		for i in range(self.NP):
286
			ind = self.itype(x=self.Selection(pop, i, self.Ts, xb, self.Rand), e=False)
287
			ind.x = self.Crossover(pop, i, self.Cr, self.Rand)
288
			ind.x = self.Mutation(pop, i, self.Mr, task, self.Rand)
289
			ind.evaluate(task, rnd=self.Rand)
290
			npop[i] = ind
291
			if npop[i].f < fxb: xb, fxb = self.getBest(npop[i], npop[i].f, xb, fxb)
292
		return npop, asarray([i.f for i in npop]), xb, fxb, {}
293
294
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
295