Passed
Branch master (13db34)
by Grega
02:16
created

KrillHerdV11.runIteration()   A

Complexity

Conditions 1

Size

Total Lines 13
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nop 12
dl 0
loc 13
rs 9.75
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
# pylint: disable=mixed-indentation, trailing-whitespace, multiple-statements, attribute-defined-outside-init, logging-not-lazy, arguments-differ, line-too-long, redefined-builtin, singleton-comparison, no-self-use, bad-continuation
3
import logging
4
from scipy.spatial.distance import euclidean as ed
5
from numpy import apply_along_axis, argmin, argmax, sum, full, inf, asarray, mean, where, sqrt
6
from NiaPy.util import fullArray
7
from NiaPy.algorithms.algorithm import Algorithm
8
9
logging.basicConfig()
10
logger = logging.getLogger('NiaPy.algorithms.basic')
11
logger.setLevel('INFO')
12
13
__all__ = ['KrillHerdV1', 'KrillHerdV2', 'KrillHerdV3', 'KrillHerdV4', 'KrillHerdV11']
14
15
class KrillHerd(Algorithm):
16
	r"""Implementation of krill herd algorithm.
17
18
	Algorithm:
19
		Krill Herd Algorithm
20
21
	Date:
22
		2018
23
24
	Authors:
25
		Klemen Berkovič
26
27
	License:
28
		MIT
29
30
	Reference URL:
31
		http://www.sciencedirect.com/science/article/pii/S1007570412002171
32
33
	Reference paper:
34
		Amir Hossein Gandomi, Amir Hossein Alavi, Krill herd: A new bio-inspired optimization algorithm, Communications in Nonlinear Science and Numerical Simulation, Volume 17, Issue 12, 2012, Pages 4831-4845, ISSN 1007-5704, https://doi.org/10.1016/j.cnsns.2012.05.010.
35
36
	Attributes:
37
		Name (List[str]): List of strings representing algorithm names..
38
		NP (int): Number of krill herds in population.
39
		N_max (float): Maximum induced speed.
40
		V_f (float): Foraging speed.
41
		D_max (float): Maximum diffusion speed.
42
		C_t (float): Constant :math:`\in [0, 2]`
43
		W_n (Union[int, float, numpy.ndarray]): Interta weights of the motion induced from neighbors :math:`\in [0, 1]`.
44
		W_f (Union[int, float, numpy.ndarray]): Interta weights of the motion induced from foraging :math`\in [0, 1]`.
45
		d_s (float): Maximum euclidean distance for neighbors.
46
		nn (int): Maximum neighbors for neighbors effect.
47
		Cr (float): Crossover probability.
48
		Mu (float): Mutation probability.
49
		epsilon (float): Small numbers for division.
50
51
	See Also:
52
		* :class:`NiaPy.algorithms.algorithm.Algorithm`
53
	"""
54
	Name = ['KrillHerd', 'KH']
55
56
	@staticmethod
57
	def typeParameters():
58
		r"""Get dictionary with functions for checking values of parameters.
59
60
		Returns:
61
			Dict[str, Callable]:
62
				* N_max (Callable[[Union[int, float]], bool]): TODO
63
				* V_f (Callable[[Union[int, float]], bool]): TODO
64
				* D_max (Callable[[Union[int, float]], bool]): TODO
65
				* C_t (Callable[[Union[int, float]], bool]): TODO
66
				* W_n (Callable[[Union[int, float]], bool]): TODO
67
				* W_f (Callable[[Union[int, float]], bool]): TODO
68
				* d_s (Callable[[Union[int, float]], boool]): TODO
69
				* nn (Callable[[int], bool]): TODO
70
				* Cr (Callable[[float], bool]): TODO
71
				* Mu (Callable[[float], bool]): TODO
72
				* epsilon (Callable[[float], bool]): TODO
73
74
		See Also:
75
			* :func:`NiaPy.algorithms.algorithm.Algorithm`
76
		"""
77
		d = Algorithm.typeParameters()
78
		d.update({
79
			'N_max': lambda x: isinstance(x, (int, float)) and x > 0,
80
			'V_f': lambda x: isinstance(x, (int, float)) and x > 0,
81
			'D_max': lambda x: isinstance(x, (int, float)) and x > 0,
82
			'C_t': lambda x: isinstance(x, (int, float)) and x > 0,
83
			'W_n': lambda x: isinstance(x, (int, float)) and x > 0,
84
			'W_f': lambda x: isinstance(x, (int, float)) and x > 0,
85
			'd_s': lambda x: isinstance(x, (int, float)) and x > 0,
86
			'nn': lambda x: isinstance(x, int) and x > 0,
87
			'Cr': lambda x: isinstance(x, float) and 0 <= x <= 1,
88
			'Mu': lambda x: isinstance(x, float) and 0 <= x <= 1,
89
			'epsilon': lambda x: isinstance(x, float) and 0 < x < 1
90
		})
91
		return d
92
93
	def setParameters(self, NP=50, N_max=0.01, V_f=0.02, D_max=0.002, C_t=0.93, W_n=0.42, W_f=0.38, d_s=2.63, nn=5, Cr=0.2, Mu=0.05, epsilon=1e-31, **ukwargs):
94
		r"""Set the arguments of an algorithm.
95
96
		Arguments:
97
			NP (Optional[int]): Number of krill herds in population.
98
			N_max (Optional[float]): Maximum induced speed.
99
			V_f (Optional[float]): Foraging speed.
100
			D_max (Optional[float]): Maximum diffusion speed.
101
			C_t (Optional[float]): Constant $\in [0, 2]$.
102
			W_n (Optional[Union[int, float, numpy.ndarray]]): Intera weights of the motion induced from neighbors :math:`\in [0, 1]`.
103
			W_f (Optional[Union[int, float, numpy.ndarray]]): Intera weights of the motion induced from foraging :math:`\in [0, 1]`.
104
			d_s (Optional[float]): Maximum euclidean distance for neighbors.
105
			nn (Optional[int]): Maximum neighbors for neighbors effect.
106
			Cr (Optional[float]): Crossover probability.
107
			Mu (Optional[float]): Mutation probability.
108
			epsilon (Optional[float]): Small numbers for division.
109
110
		See Also:
111
			* :func:`NiaPy.algorithms.algorithm.Algorithm.setParameters`
112
		"""
113
		Algorithm.setParameters(self, NP=NP, **ukwargs)
114
		self.N_max, self.V_f, self.D_max, self.C_t, self.W_n, self.W_f, self.d_s, self.nn, self._Cr, self._Mu, self.epsilon = N_max, V_f, D_max, C_t, W_n, W_f, d_s, nn, Cr, Mu, epsilon
115
		if ukwargs: logger.info('Unused arguments: %s' % (ukwargs))
116
117
	def initWeights(self, task):
118
		r"""Initialize weights.
119
120
		Args:
121
			task (Task): Optimization task.
122
123
		Returns:
124
			Tuple[numpy.ndarray, numpy.ndarray]:
125
				1. Weights for neighborhood.
126
				2. Weights for foraging.
127
		"""
128
		return fullArray(self.W_n, task.D), fullArray(self.W_f, task.D)
129
130
	def sensRange(self, ki, KH):
131
		r"""Calculate sense range for selected individual.
132
133
		Args:
134
			ki (int): Selected individual.
135
			KH (numpy.ndarray): Krill heard population.
136
137
		Returns:
138
			TODO
139
		"""
140
		return sum([ed(KH[ki], KH[i]) for i in range(self.NP)]) / (self.nn * self.NP)
141
142
	def getNeighbours(self, i, ids, KH):
143
		r"""Get neighbours.
144
145
		Args:
146
			i (int): Individual looking for neighbours.
147
			ids (float): Maximal distance for being a neighbour.
148
			KH (numpy.ndarray): Current population.
149
150
		Returns:
151
			numpy.ndarray: Neighbours of krill heard.
152
		"""
153
		N = list()
154
		for j in range(self.NP):
155
			if j != i and ids > ed(KH[i], KH[j]): N.append(j)
156
		if not N: N.append(self.randint(self.NP))
157
		return asarray(N)
158
159
	def funX(self, x, y): return ((y - x) + self.epsilon) / (ed(y, x) + self.epsilon)
160
161
	def funK(self, x, y, b, w): return ((x - y) + self.epsilon) / ((w - b) + self.epsilon)
162
163
	def induceNeighborsMotion(self, i, n, W, KH, KH_f, ikh_b, ikh_w, task):
164
		Ni = self.getNeighbours(i, self.sensRange(i, KH), KH)
165
		Nx, Nf, f_b, f_w = KH[Ni], KH_f[Ni], KH_f[ikh_b], KH_f[ikh_w]
166
		alpha_l = sum(asarray([self.funK(KH_f[i], j, f_b, f_w) for j in Nf]) * asarray([self.funX(KH[i], j) for j in Nx]).T)
167
		alpha_t = 2 * (1 + self.rand() * task.Iters / task.nGEN)
168
		return self.N_max * (alpha_l + alpha_t) + W * n
169
170
	def induceForagingMotion(self, i, x, x_f, f, W, KH, KH_f, ikh_b, ikh_w, task):
171
		beta_f = 2 * (1 - task.Iters / task.nGEN) * self.funK(KH_f[i], x_f, KH_f[ikh_b], KH_f[ikh_w]) * self.funX(KH[i], x) if KH_f[ikh_b] < KH_f[i] else 0
172
		beta_b = self.funK(KH_f[i], KH_f[ikh_b], KH_f[ikh_b], KH_f[ikh_w]) * self.funX(KH[i], KH[ikh_b])
173
		return self.V_f * (beta_f + beta_b) + W * f
174
175
	def inducePhysicalDiffusion(self, task): return self.D_max * (1 - task.Iters / task.nGEN) * self.uniform(-1, 1, task.D)
176
177
	def deltaT(self, task): return self.C_t * sum(task.bcRange())
178
179
	def crossover(self, x, xo, Cr): return [xo[i] if self.rand() < Cr else x[i] for i in range(len(x))]
180
181
	def mutate(self, x, x_b, Mu):
182
		return [x[i] if self.rand() < Mu else (x_b[i] + self.rand()) for i in range(len(x))]
183
184
	def getFoodLocation(self, KH, KH_f, task):
185
		x_food = task.repair(asarray([sum(KH[:, i] / KH_f) for i in range(task.D)]) / sum(1 / KH_f), rnd=self.Rand)
186
		x_food_f = task.eval(x_food)
187
		return x_food, x_food_f
188
189
	def Mu(self, xf, yf, xf_best, xf_worst): return self._Mu / (self.funK(xf, yf, xf_best, xf_worst) + 1e-31)
190
191
	def Cr(self, xf, yf, xf_best, xf_worst): return self._Cr * self.funK(xf, yf, xf_best, xf_worst)
192
193
	def initPopulation(self, task):
194
		r"""Initialize stating population.
195
196
		Args:
197
			task (Task): Optimization task.
198
199
		Returns:
200
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
201
				1. Initialized population.
202
				2. Initialized populations function/fitness values.
203
				3. Additional arguments:
204
					* W_n (numpy.ndarray): Weights neighborhood.
205
					* W_f (numpy.ndarray): Weights foraging.
206
					* N (numpy.ndarray): TODO
207
					* F (numpy.ndarray): TODO
208
209
		See Also:
210
			* :func:`NiaPy.algorithms.algorithm.Algorithm.initPopulation`
211
		"""
212
		KH, KH_f, d = Algorithm.initPopulation(self, task)
213
		W_n, W_f = self.initWeights(task)
214
		N, F = full(self.NP, .0), full(self.NP, .0)
215
		d.update({'W_n': W_n, 'W_f': W_f, 'N': N, 'F': F})
216
		return KH, KH_f, d
217
218
	def runIteration(self, task, KH, KH_f, xb, fxb, W_n, W_f, N, F, **dparams):
219
		ikh_b, ikh_w = argmin(KH_f), argmax(KH_f)
220
		x_food, x_food_f = self.getFoodLocation(KH, KH_f, task)
221
		N = asarray([self.induceNeighborsMotion(i, N[i], W_n, KH, KH_f, ikh_b, ikh_w, task) for i in range(self.NP)])
222
		F = asarray([self.induceForagingMotion(i, x_food, x_food_f, F[i], W_f, KH, KH_f, ikh_b, ikh_w, task) for i in range(self.NP)])
223
		D = asarray([self.inducePhysicalDiffusion(task) for i in range(self.NP)])
224
		KH_n = KH + (self.deltaT(task) * (N + F + D))
225
		Cr = asarray([self.Cr(KH_f[i], KH_f[ikh_b], KH_f[ikh_b], KH_f[ikh_w]) for i in range(self.NP)])
226
		KH_n = asarray([self.crossover(KH_n[i], KH[i], Cr[i]) for i in range(self.NP)])
227
		Mu = asarray([self.Mu(KH_f[i], KH_f[ikh_b], KH_f[ikh_b], KH_f[ikh_w]) for i in range(self.NP)])
228
		KH_n = asarray([self.mutate(KH_n[i], KH[ikh_b], Mu[i]) for i in range(self.NP)])
229
		KH = apply_along_axis(task.repair, 1, KH_n, rnd=self.Rand)
230
		KH_f = apply_along_axis(task.eval, 1, KH)
231
		return KH, KH_f, {'W_n': W_n, 'W_f': W_f, 'N': N, 'F': F}
232
233
class KrillHerdV4(KrillHerd):
234
	r"""Implementation of krill herd algorithm.
235
236
	Algorithm:
237
		Krill Herd Algorithm
238
239
	Date:
240
		2018
241
242
	Authors:
243
		Klemen Berkovič
244
245
	License:
246
		MIT
247
248
	Reference URL:
249
		http://www.sciencedirect.com/science/article/pii/S1007570412002171
250
251
	Reference paper:
252
		Amir Hossein Gandomi, Amir Hossein Alavi, Krill herd: A new bio-inspired optimization algorithm, Communications in Nonlinear Science and Numerical Simulation, Volume 17, Issue 12, 2012, Pages 4831-4845, ISSN 1007-5704, https://doi.org/10.1016/j.cnsns.2012.05.010.
253
254
	Attributes:
255
		Name (List[str]): List of strings representing algorithm name.
256
	"""
257
	Name = ['KrillHerdV4', 'KHv4']
258
259
	@staticmethod
260
	def typeParameters():
261
		r"""Get dictionary with functions for checking values of parameters.
262
263
		Returns:
264
			Dict[str, Callable]:
265
				* TODO
266
267
		See Also:
268
			* :func:NiaPy.algorithms.basic.kh.KrillHerd.typeParameters`
269
		"""
270
		d = KrillHerd.typeParameters()
271
		del d['Cr']
272
		del d['Mu']
273
		del d['epsilon']
274
		return d
275
276
	def setParameters(self, NP=50, N_max=0.01, V_f=0.02, D_max=0.002, C_t=0.93, W_n=0.42, W_f=0.38, d_s=2.63, **ukwargs):
277
		r"""Set algorithm core parameters.
278
279
		Args:
280
			N_max (Optional[float]): TODO
281
			V_f (Optional[float]): TODO
282
			D_max (Optional[float]): TODO
283
			C_t (Optional[float]): TODO
284
			W_n (Optional]float]): TODO
285
			W_f (Optional[float]): TODO
286
			d_s (Optional[float]): TODO
287
			**ukwargs (Dict[str, Any]): Additional arguments.
288
289
      See Also:
290
      	* :func:NiaPy.algorithms.basic.kh.KrillHerd.KrillHerd.setParameters`
291
		"""
292
		KrillHerd.setParameters(self, NP, N_max, V_f, D_max, C_t, W_n, W_f, d_s, 4, 0.2, 0.05, 1e-31, **ukwargs)
293
294
class KrillHerdV1(KrillHerd):
295
	r"""Implementation of krill herd algorithm.
296
297
	Algorithm:
298
		Krill Herd Algorithm
299
300
	Date:
301
		2018
302
303
	Authors:
304
		Klemen Berkovič
305
306
	License:
307
		MIT
308
309
	Reference URL:
310
		http://www.sciencedirect.com/science/article/pii/S1007570412002171
311
312
	Reference paper:
313
		Amir Hossein Gandomi, Amir Hossein Alavi, Krill herd: A new bio-inspired optimization algorithm, Communications in Nonlinear Science and Numerical Simulation, Volume 17, Issue 12, 2012, Pages 4831-4845, ISSN 1007-5704, https://doi.org/10.1016/j.cnsns.2012.05.010.
314
315
	Attributes:
316
		Name (List[str]): List of strings representing algorithm name.
317
318
	See Also:
319
		* :func:NiaPy.algorithms.basic.kh.KrillHerd.KrillHerd`
320
	"""
321
	Name = ['KrillHerdV1', 'KHv1']
322
323
	@staticmethod
324
	def typeParameters():
325
		r"""Get dictionary with functions for checking values of parameters.
326
327
		Returns:
328
			Dict[str, Callable]:
329
				* TODO
330
331
		See Also:
332
			* :func:NiaPy.algorithms.basic.kh.KrillHerd.typeParameters`
333
		"""
334
		return KrillHerd.typeParameters()
335
336
	def crossover(self, x, xo, Cr):
337
		r"""Preform a crossover operation on individual.
338
339
		Args:
340
			x (numpy.ndarray): Current individual
341
			xo (numpy.ndarray): New individual
342
			Cr (float): Crossover probability
343
344
		Returns:
345
			numpy.ndarray: Crossoved individual
346
		"""
347
		return x
348
349
	def mutate(self, x, x_b, Mu):
350
		r"""Mutate individual.
351
352
		Args:
353
			x (numpy.ndarray): Current individual.
354
			x_b (numpy.ndarray): Global best individual.
355
			Mu (float): TODO
356
357
		Returns:
358
			numpy.ndarray: TODO
359
		"""
360
		return x
361
362
class KrillHerdV2(KrillHerd):
363
	r"""Implementation of krill herd algorithm.
364
365
	Algorithm:
366
		Krill Herd Algorithm
367
368
	Date:
369
		2018
370
371
	Authors:
372
		Klemen Berkovič
373
374
	License:
375
		MIT
376
377
	Reference URL:
378
		http://www.sciencedirect.com/science/article/pii/S1007570412002171
379
380
	Reference paper:
381
		Amir Hossein Gandomi, Amir Hossein Alavi, Krill herd: A new bio-inspired optimization algorithm, Communications in Nonlinear Science and Numerical Simulation, Volume 17, Issue 12, 2012, Pages 4831-4845, ISSN 1007-5704, https://doi.org/10.1016/j.cnsns.2012.05.010.
382
383
	Attributes:
384
		Name (List[str]): List of strings representing algorithm name.
385
	"""
386
	Name = ['KrillHerdV2', 'KHv2']
387
388
	@staticmethod
389
	def typeParameters():
390
		r"""Get dictionary with functions for checking values of parameters.
391
392
		Returns:
393
			Dict[str, Callable]:
394
				* TODO
395
396
		See Also:
397
			* :func:NiaPy.algorithms.basic.kh.KrillHerd.typeParameters`
398
		"""
399
		d = KrillHerd.typeParameters()
400
		del d['Mu']
401
		return d
402
403
	def mutate(self, x, x_b, Mu): return x
404
405
class KrillHerdV3(KrillHerd):
406
	r"""Implementation of krill herd algorithm.
407
408
	Algorithm:
409
		Krill Herd Algorithm
410
411
	Date:
412
		2018
413
414
	Authors:
415
		Klemen Berkovič
416
417
	License:
418
		MIT
419
420
	Reference URL:
421
		http://www.sciencedirect.com/science/article/pii/S1007570412002171
422
423
	Reference paper:
424
		Amir Hossein Gandomi, Amir Hossein Alavi, Krill herd: A new bio-inspired optimization algorithm, Communications in Nonlinear Science and Numerical Simulation, Volume 17, Issue 12, 2012, Pages 4831-4845, ISSN 1007-5704, https://doi.org/10.1016/j.cnsns.2012.05.010.
425
	"""
426
	Name = ['KrillHerdV3', 'KHv3']
427
428
	@staticmethod
429
	def typeParameters():
430
		d = KrillHerd.typeParameters()
431
		del d['Cr']
432
		return d
433
434
	def crossover(self, x, xo, Cr): return x
435
436
class KrillHerdV11(KrillHerd):
437
	r"""Implementation of krill herd algorithm.
438
439
	Algorithm:
440
		Krill Herd Algorithm
441
442
	Date:
443
		2018
444
445
	Authors:
446
		Klemen Berkovič
447
448
	License:
449
		MIT
450
451
	Reference URL:
452
453
	Reference paper:
454
	"""
455
	Name = ['KrillHerdV11', 'KHv11']
456
457
	def ElitistSelection(self, KH, KH_f, KHo, KHo_f):
458
		ipb = where(KHo_f >= KH_f)
459
		KHo[ipb], KHo_f[ipb] = KH[ipb], KH_f[ipb]
460
		return KHo, KHo_f
461
462
	def Neighbors(self, i, KH, KH_f, iw, ib, N, W_n, task):
463
		Rgb, RR, Kw_Kgb = KH[ib] - KH[i], KH - KH[i], KH_f[iw] - KH_f[ib]
464
		R = sqrt(sum(RR * RR))
465
		alpha_b = -2 * (1 + self.rand() * task.Iters / task.nGEN) * (KH_f[ib]) / Kw_Kgb / sqrt(sum(Rgb * Rgb)) * Rgb if KH_f[ib] < KH_f[i] else 0
466
		alpah_n, nn, ds = 0.0, 0, mean(R) / 5
467
		for n in range(self.NP):
468
			if R < ds and n != i:
469
				nn += 1
470
				if nn <= 4 and KH_f[i] != KH[n]: alpah_n -= (KH(n) - KH[i]) / Kw_Kgb / R[n] * RR[n]
471
		return W_n * N * self.N_max * (alpha_b + alpah_n)
472
473
	def Foraging(self, KH, KH_f, KHo, KHo_f, W_f, F, KH_wf, KH_bf, x_food, x_food_f, task):
474
		Rf, Kw_Kgb = x_food - KH, KH_wf - KH_bf
475
		beta_f = -2 * (1 - task.Iters / task.nGEN) * (x_food_f - KH_f) / Kw_Kgb / sqrt(sum(Rf * Rf)) * Rf if x_food_f < KH_f else 0
476
		Rib = KHo - KH
477
		beta_b = -(KHo_f - KH_f) / Kw_Kgb / sqrt(sum(Rib * Rib)) * Rib if KHo_f < KH_f else 0
478
		return W_f * F + self.V_f * (beta_b + beta_f)
479
480
	def Cr(self, KH_f, KHb_f, KHw_f): return 0.8 + 0.2 * (KH_f - KHb_f) / (KHw_f - KHb_f)
481
482
	def initPopulation(self, task):
483
		KH, KH_f, d = Algorithm.initPopulation(self, task)
484
		KHo, KHo_f = full([self.NP, task.D], task.optType.value * inf), full(self.NP, task.optType.value * inf)
485
		N, F, Dt = full(self.NP, .0), full(self.NP, .0), mean(task.bcRange()) / 2
486
		d.update({'KHo': KHo, 'KHo_f': KHo_f, 'N': N, 'F': F, 'Dt': Dt})
487
		return KH, KH_f, d
488
489
	def runIteration(self, task, KH, KH_f, xb, fxb, KHo, KHo_f, N, F, Dt, **dparams):
490
		w = full(task.D, 0.1 + 0.8 * (1 - task.Iters / task.nGEN))
491
		ib, iw = argmin(KH_f), argmax(KH_f)
492
		x_food, x_food_f = self.getFoodLocation(KH, KH_f, task)
493
		N = asarray([self.Neighbors(i, KH, KH_f, iw, ib, N[i], w, task) for i in range(self.NP)])
494
		F = asarray([self.Foraging(KH[i], KH_f[i], KHo[i], KHo_f[i], w, F[i], KH_f[iw], KH_f[ib], x_food, x_food_f, task) for i in range(self.NP)])
495
		Cr = asarray([self.Cr(KH_f[i], KH_f[ib], KH_f[iw]) for i in range(self.NP)])
496
		KH_n = asarray([self.crossover(KH[self.randint(self.NP)], KH[i], Cr[i]) for i in range(self.NP)])
497
		KH_n = KH + Dt * (F + N)
498
		KH = apply_along_axis(task.repair, 1, KH_n, self.Rand)
499
		KH_f = apply_along_axis(task.eval, 1, KH)
500
		KHo, KHo_f = self.ElitistSelection(KH, KH_f, KHo, KHo_f)
501
		return KH, KH_f, {'KHo': KHo, 'KHo_f': KHo_f, 'N': N, 'F': F, 'Dt': Dt}
502
503
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
504