Source code for NiaPy.algorithms.other.aso

# encoding=utf8
import logging
from scipy.spatial.distance import euclidean
from numpy import apply_along_axis, argmin, full, inf, where, asarray, random as rand, sort, exp
from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import fullArray

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.other')
logger.setLevel('INFO')

__all__ = ['AnarchicSocietyOptimization', 'Elitism', 'Sequential', 'Crossover']

def Elitism(x, xpb, xb, xr, MP_c, MP_s, MP_p, F, CR, task, rnd=rand):
	r"""Select the best of all three strategies.

	Args:
		x (numpy.ndarray): individual position.
		xpb (numpy.ndarray): individuals best position.
		xb (numpy.ndarray): current best position.
		xr (numpy.ndarray): random individual.
		MP_c (float): Fickleness index value.
		MP_s (float): External irregularity index value.
		MP_p (float): Internal irregularity index value.
		F (float): scale factor.
		CR (float): crossover factor.
		task (Task): optimization task.
		rnd (mtrand.randomstate): random number generator.

	Returns:
		Tuple[numpy.ndarray, float]:
			1. New position of individual
			2. New positions fitness/function value
	"""
	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)]
	xn_f = apply_along_axis(task.eval, 1, xn)
	ib = argmin(xn_f)
	return xn[ib], xn_f[ib]

def Sequential(x, xpb, xb, xr, MP_c, MP_s, MP_p, F, CR, task, rnd=rand):
	r"""Sequentialy combines all three strategies.

	Args:
		x (numpy.ndarray): individual position.
		xpb (numpy.ndarray): individuals best position.
		xb (numpy.ndarray): current best position.
		xr (numpy.ndarray): random individual.
		MP_c (float): Fickleness index value.
		MP_s (float): External irregularity index value.
		MP_p (float): Internal irregularity index value.
		F (float): scale factor.
		CR (float): crossover factor.
		task (Task): optimization task.
		rnd (mtrand.randomstate): random number generator.

	Returns:
		tuple[numpy.ndarray, float]:
			1. new position
			2. new positions function/fitness value
	"""
	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)
	return xn, task.eval(xn)

def Crossover(x, xpb, xb, xr, MP_c, MP_s, MP_p, F, CR, task, rnd=rand):
	r"""Create a crossover over all three strategies.

	Args:
		x (numpy.ndarray): individual position.
		xpb (numpy.ndarray): individuals best position.
		xb (numpy.ndarray): current best position.
		xr (numpy.ndarray): random individual.
		MP_c (float): Fickleness index value.
		MP_s (float): External irregularity index value.
		MP_p (float): Internal irregularity index value.
		F (float): scale factor.
		CR (float): crossover factor.
		task (Task): optimization task.
		rnd (mtrand.randomstate): random number generator.

	Returns:
		Tuple[numpy.ndarray, float]:
			1. new position
			2. new positions function/fitness value
	"""
	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)]
	x = asarray([xns[rnd.randint(len(xns))][i] if rnd.rand() < CR else x[i] for i in range(len(x))])
	return x, task.eval(x)

def MP_C(x, F, CR, MP, rnd=rand):
	r"""Get bew position based on fickleness.

	Args:
		x (numpy.ndarray): Current individuals position.
		F (float): Scale factor.
		CR (float): Crossover probability.
		MP (float): Fickleness index value
		rnd (mtrand.RandomState): Random number generator

	Returns:
		numpy.ndarray: New position
	"""
	if MP < 0.5:
		b = sort(rnd.choice(len(x), 2, replace=False))
		x[b[0]:b[1]] = x[b[0]:b[1]] + F * rnd.normal(0, 1, b[1] - b[0])
		return x
	return asarray([x[i] + F * rnd.normal(0, 1) if rnd.rand() < CR else x[i] for i in range(len(x))])

def MP_S(x, xr, xb, CR, MP, rnd=rand):
	r"""Get new position based on external irregularity.

	Args:
		x (numpy.ndarray): Current individuals position.
		xr (numpy.ndarray): Random individuals position.
		xb (numpy.ndarray): Global best individuals position.
		CR (float): Crossover probability.
		MP (float): External irregularity index.
		rnd (mtrand.RandomState): Random number generator.

	Returns:
		numpy.ndarray: New position.
	"""
	if MP < 0.25:
		b = sort(rnd.choice(len(x), 2, replace=False))
		x[b[0]:b[1]] = xb[b[0]:b[1]]
		return x
	elif MP < 0.5: return asarray([xb[i] if rnd.rand() < CR else x[i] for i in range(len(x))])
	elif MP < 0.75:
		b = sort(rnd.choice(len(x), 2, replace=False))
		x[b[0]:b[1]] = xr[b[0]:b[1]]
		return x
	return asarray([xr[i] if rnd.rand() < CR else x[i] for i in range(len(x))])

def MP_P(x, xpb, CR, MP, rnd=rand):
	r"""Get new position based on internal irregularity.

	Args:
		x (numpy.ndarray): Current individuals position.
		xpb (numpy.ndarray): Current individuals personal best position.
		CR (float): Crossover probability.
		MP (float): Internal irregularity index value.
		rnd (mtrand.RandomState): Random number generator.

	Returns:
		numpy.ndarray: Current individuals new position.
	"""
	if MP < 0.5:
		b = sort(rnd.choice(len(x), 2, replace=False))
		x[b[0]:b[1]] = xpb[b[0]:b[1]]
		return x
	return asarray([xpb[i] if rnd.rand() < CR else x[i] for i in range(len(x))])

[docs]class AnarchicSocietyOptimization(Algorithm): r"""Implementation of Anarchic Society Optimization algorithm. Algorithm: Anarchic Society Optimization algorithm Date: 2018 Authors: Klemen Berkovič License: MIT Reference paper: Ahmadi-Javid, Amir. "Anarchic Society Optimization: A human-inspired method." Evolutionary Computation (CEC), 2011 IEEE Congress on. IEEE, 2011. Attributes: Name (list of str): List of stings representing name of algorithm. alpha (List[float]): Factor for fickleness index function :math:`\in [0, 1]`. gamma (List[float]): Factor for external irregularity index function :math:`\in [0, \infty)`. theta (List[float]): Factor for internal irregularity index function :math:`\in [0, \infty)`. d (Callable[[float, float], float]): function that takes two arguments that are function values and calcs the distance between them. dn (Callable[[numpy.ndarray, numpy.ndarray], float]): function that takes two arguments that are points in function landscape and calcs the distance between them. nl (float): Normalized range for neighborhood search :math:`\in (0, 1]`. F (float): Mutation parameter. CR (float): Crossover parameter :math:`\in [0, 1]`. 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. See Also: * :class:`NiaPy.algorithms.Algorithm` """ Name = ['AnarchicSocietyOptimization', 'ASO']
[docs] @staticmethod def algorithmInfo(): r"""Get basic information about the algorithm. Returns: str: Basic information. See Also: :func:`NiaPy.algorithms.algorithm.Algorithm.algorithmInfo` """ return r"""Ahmadi-Javid, Amir. "Anarchic Society Optimization: A human-inspired method." Evolutionary Computation (CEC), 2011 IEEE Congress on. IEEE, 2011."""
[docs] @staticmethod def typeParameters(): r"""Get dictionary with functions for checking values of parameters. Returns: Dict[str, Callable]: * alpha (Callable): TODO * gamma (Callable): TODO * theta (Callable): TODO * nl (Callable): TODO * F (Callable[[Union[float, int]], bool]): TODO * CR (Callable[[Union[float, int]], bool]): TODO See Also: * :func:`NiaPy.algorithms.Algorithm.typeParameters` """ d = Algorithm.typeParameters() d.update({ 'alpha': lambda x: True, 'gamma': lambda x: True, 'theta': lambda x: True, 'nl': lambda x: True, 'F': lambda x: isinstance(x, (int, float)) and x > 0, 'CR': lambda x: isinstance(x, float) and 0 <= x <= 1 }) return d
[docs] 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): r"""Set the parameters for the algorith. Arguments: alpha (Optional[List[float]]): Factor for fickleness index function :math:`\in [0, 1]`. gamma (Optional[List[float]]): Factor for external irregularity index function :math:`\in [0, \infty)`. theta (Optional[List[float]]): Factor for internal irregularity index function :math:`\in [0, \infty)`. d (Optional[Callable[[float, float], float]]): function that takes two arguments that are function values and calcs the distance between them. 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. nl (Optional[float]): Normalized range for neighborhood search :math:`\in (0, 1]`. F (Optional[float]): Mutation parameter. CR (Optional[float]): Crossover parameter :math:`\in [0, 1]`. 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. See Also: * :func:`NiaPy.algorithms.Algorithm.setParameters` * Combination methods: * :func:`NiaPy.algorithms.other.Elitism` * :func:`NiaPy.algorithms.other.Crossover` * :func:`NiaPy.algorithms.other.Sequential` """ Algorithm.setParameters(self, NP=NP, **ukwargs) 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
[docs] def init(self, task): r"""Initialize dynamic parameters of algorithm. Args: task (Task): Optimization task. Returns: Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray] 1. Array of `self.alpha` propagated values 2. Array of `self.gamma` propagated values 3. Array of `self.theta` propagated values """ return fullArray(self.alpha, self.NP), fullArray(self.gamma, self.NP), fullArray(self.theta, self.NP)
[docs] def FI(self, x_f, xpb_f, xb_f, alpha): r"""Get fickleness index. Args: x_f (float): Individuals fitness/function value. xpb_f (float): Individuals personal best fitness/function value. xb_f (float): Current best found individuals fitness/function value. alpha (float): TODO. Returns: float: Fickleness index. """ return 1 - alpha * xb_f / x_f - (1 - alpha) * xpb_f / x_f
[docs] def EI(self, x_f, xnb_f, gamma): r"""Get external irregularity index. Args: x_f (float): Individuals fitness/function value. xnb_f (float): Individuals new fitness/function value. gamma (float): TODO. Returns: float: External irregularity index. """ return 1 - exp(-gamma * self.d(x_f, xnb_f))
[docs] def II(self, x_f, xpb_f, theta): r"""Get internal irregularity index. Args: x_f (float): Individuals fitness/function value. xpb_f (float): Individuals personal best fitness/function value. theta (float): TODO. Returns: float: Internal irregularity index """ return 1 - exp(-theta * self.d(x_f, xpb_f))
[docs] def getBestNeighbors(self, i, X, X_f, rs): r"""Get neighbors of individual. Mesurment of distance for neighborhud is defined with `self.nl`. Function for calculating distances is define with `self.dn`. Args: i (int): Index of individual for hum we are looking for neighbours. X (numpy.ndarray): Current population. X_f (numpy.ndarray[float]): Current population fitness/function values. rs (numpy.ndarray[float]): Distance between individuals. Returns: numpy.ndarray[int]: Indexes that represent individuals closest to `i`-th individual. """ nn = asarray([self.dn(X[i], X[j]) / rs for j in range(len(X))]) return argmin(X_f[where(nn <= self.nl)])
[docs] def uBestAndPBest(self, X, X_f, Xpb, Xpb_f): r"""Update personal best solution of all individuals in population. Args: X (numpy.ndarray): Current population. X_f (numpy.ndarray[float]): Current population fitness/function values. Xpb (numpy.ndarray): Current population best positions. Xpb_f (numpy.ndarray[float]): Current populations best positions fitness/function values. Returns: Tuple[numpy.ndarray, numpy.ndarray[float], numpy.ndarray, float]: 1. New personal best positions for current population. 2. New personal best positions function/fitness values for current population. 3. New best individual. 4. New best individual fitness/function value. """ ix_pb = where(X_f < Xpb_f) Xpb[ix_pb], Xpb_f[ix_pb] = X[ix_pb], X_f[ix_pb] return Xpb, Xpb_f
[docs] def initPopulation(self, task): r"""Initialize first population and additional arguments. Args: task (Task): Optimization task Returns: Tuple[numpy.ndarray, numpy.ndarray, dict]: 1. Initialized population 2. Initialized population fitness/function values 3. Dict[str, Any]: * Xpb (numpy.ndarray): Initialized populations best positions. * Xpb_f (numpy.ndarray): Initialized populations best positions function/fitness values. * alpha (numpy.ndarray): * gamma (numpy.ndarray): * theta (numpy.ndarray): * rs (float): Distance of search space. See Also: * :func:`NiaPy.algorithms.algorithm.Algorithm.initPopulation` * :func:`NiaPy.algorithms.other.aso.AnarchicSocietyOptimization.init` """ X, X_f, d = Algorithm.initPopulation(self, task) alpha, gamma, theta = self.init(task) Xpb, Xpb_f = self.uBestAndPBest(X, X_f, full([self.NP, task.D], 0.0), full(self.NP, task.optType.value * inf)) d.update({'Xpb': Xpb, 'Xpb_f': Xpb_f, 'alpha': alpha, 'gamma': gamma, 'theta': theta, 'rs': self.d(task.Upper, task.Lower)}) return X, X_f, d
[docs] def runIteration(self, task, X, X_f, xb, fxb, Xpb, Xpb_f, alpha, gamma, theta, rs, **dparams): r"""Core function of AnarchicSocietyOptimization algorithm. Args: task (Task): Optimization task. X (numpy.ndarray): Current populations positions. X_f (numpy.ndarray): Current populations function/fitness values. xb (numpy.ndarray): Current global best individuals position. fxb (float): Current global best individual function/fitness value. Xpb (numpy.ndarray): Current populations best positions. Xpb_f (numpy.ndarray): Current population best positions function/fitness values. alpha (numpy.ndarray): TODO. gamma (numpy.ndarray): theta (numpy.ndarray): **dparams: Additional arguments. Returns: Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, dict]: 1. Initialized population 2. Initialized population fitness/function values 3. New global best solution 4. New global best solutions fitness/objective value 5. Dict[str, Union[float, int, numpy.ndarray]: * Xpb (numpy.ndarray): Initialized populations best positions. * Xpb_f (numpy.ndarray): Initialized populations best positions function/fitness values. * alpha (numpy.ndarray): * gamma (numpy.ndarray): * theta (numpy.ndarray): * rs (float): Distance of search space. """ Xin = [self.getBestNeighbors(i, X, X_f, rs) for i in range(len(X))] 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))]) 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))]) X, X_f = asarray([Xtmp[i][0] for i in range(len(X))]), asarray([Xtmp[i][1] for i in range(len(X))]) Xpb, Xpb_f = self.uBestAndPBest(X, X_f, Xpb, Xpb_f) xb, fxb = self.getBest(X, X_f, xb, fxb) return X, X_f, xb, fxb, {'Xpb': Xpb, 'Xpb_f': Xpb_f, 'alpha': alpha, 'gamma': gamma, 'theta': theta, 'rs': rs}
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3