Source code for NiaPy.algorithms.basic.foa

# encoding=utf8
import logging
from numpy import where, apply_along_axis, zeros, append, ndarray, delete, arange, argmin, absolute, int32
from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import limit_repair

__all__ = ['ForestOptimizationAlgorithm']

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

[docs]class ForestOptimizationAlgorithm(Algorithm): r"""Implementation of Forest Optimization Algorithm. Algorithm: Forest Optimization Algorithm Date: 2019 Authors: Luka Pečnik License: MIT Reference paper: Manizheh Ghaemi, Mohammad-Reza Feizi-Derakhshi, Forest Optimization Algorithm, Expert Systems with Applications, Volume 41, Issue 15, 2014, Pages 6676-6687, ISSN 0957-4174, https://doi.org/10.1016/j.eswa.2014.05.009. References URL: Implementation is based on the following MATLAB code: https://github.com/cominsys/FOA Attributes: Name (List[str]): List of strings representing algorithm name. lt (int): Life time of trees parameter. al (int): Area limit parameter. lsc (int): Local seeding changes parameter. gsc (int): Global seeding changes parameter. tr (float): Transfer rate parameter. See Also: * :class:`NiaPy.algorithms.Algorithm` """ Name = ['ForestOptimizationAlgorithm', 'FOA']
[docs] @staticmethod def algorithmInfo(): r"""Get algorithms information. Returns: str: Algorithm information. """ return r""" Description: Forest Optimization Algorithm is inspired by few trees in the forests which can survive for several decades, while other trees could live for a limited period. Authors: Manizheh Ghaemi, Mohammad-Reza Feizi-Derakhshi Year: 2014 Main reference: Manizheh Ghaemi, Mohammad-Reza Feizi-Derakhshi, Forest Optimization Algorithm, Expert Systems with Applications, Volume 41, Issue 15, 2014, Pages 6676-6687, ISSN 0957-4174, https://doi.org/10.1016/j.eswa.2014.05.009. """
[docs] @staticmethod def typeParameters(): r"""Get dictionary with functions for checking values of parameters. Returns: Dict[str, Callable]: * lt (Callable[[int], bool]): Checks if life time parameter has a proper value. * al (Callable[[int], bool]): Checks if area limit parameter has a proper value. * lsc (Callable[[int], bool]): Checks if local seeding changes parameter has a proper value. * gsc (Callable[[int], bool]): Checks if global seeding changes parameter has a proper value. * tr (Callable[[float], bool]): Checks if transfer rate parameter has a proper value. See Also: * :func:`NiaPy.algorithms.algorithm.Algorithm.typeParameters` """ d = Algorithm.typeParameters() d.update({ 'lt': lambda x: isinstance(x, int) and x > 0, 'al': lambda x: isinstance(x, int) and x > 0, 'lsc': lambda x: isinstance(x, int) and x > 0, 'gsc': lambda x: isinstance(x, int) and x > 0, 'tr': lambda x: isinstance(x, float) and 0 <= x <= 1, }) return d
[docs] def setParameters(self, NP=10, lt=3, al=10, lsc=1, gsc=1, tr=0.3, **ukwargs): r"""Set the parameters of the algorithm. Args: NP (Optional[int]): Population size. lt (Optional[int]): Life time parameter. al (Optional[int]): Area limit parameter. lsc (Optional[int]): Local seeding changes parameter. gsc (Optional[int]): Global seeding changes parameter. tr (Optional[float]): Transfer rate parameter. ukwargs (Dict[str, Any]): Additional arguments. See Also: * :func:`NiaPy.algorithms.Algorithm.setParameters` """ Algorithm.setParameters(self, NP=NP, **ukwargs) self.lt, self.al, self.lsc, self.gsc, self.tr = lt, al, lsc, gsc, tr
[docs] def getParameters(self): r"""Get parameters values of the algorithm. Returns: Dict[str, Any]: TODO. """ d = Algorithm.getParameters(self) d.update({ 'lt': self.lt, 'al': self.al, 'lsc': self.lsc, 'gsc': self.gsc, 'tr': self.tr }) return d
[docs] def localSeeding(self, task, trees): r"""Local optimum search stage. Args: task (Task): Optimization task. trees (numpy.ndarray): Zero age trees for local seeding. Returns: numpy.ndarray: Resulting zero age trees. """ n = trees.shape[0] deltas = self.uniform(-self.dx, self.dx, (n, self.lsc)) deltas = append(deltas, zeros((n, task.D - self.lsc)), axis=1) perms = self.rand([deltas.shape[0], deltas.shape[1]]).argsort(1) deltas = deltas[arange(deltas.shape[0])[:, None], perms] trees += deltas trees = apply_along_axis(limit_repair, 1, trees, task.Lower, task.Upper) return trees
[docs] def globalSeeding(self, task, candidates, size): r"""Global optimum search stage that should prevent getting stuck in a local optimum. Args: task (Task): Optimization task. candidates (numpy.ndarray): Candidate population for global seeding. size (int): Number of trees to produce. Returns: numpy.ndarray: Resulting trees. """ seeds = candidates[self.randint(len(candidates), D=size)] deltas = self.uniform(task.benchmark.Lower, task.benchmark.Upper, (size, self.gsc)) deltas = append(deltas, zeros((size, task.D - self.gsc)), axis=1) perms = self.rand([deltas.shape[0], deltas.shape[1]]).argsort(1) deltas = deltas[arange(deltas.shape[0])[:, None], perms] deltas = deltas.flatten() seeds = seeds.flatten() seeds[deltas != 0] = deltas[deltas != 0] return seeds.reshape(size, task.D)
[docs] def removeLifeTimeExceeded(self, trees, candidates, age): r"""Remove dead trees. Args: trees (numpy.ndarray): Population to test. candidates (numpy.ndarray): Candidate population array to be updated. age (numpy.ndarray[int32]): Age of trees. Returns: Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray[int32]]: 1. Alive trees. 2. New candidate population. 3. Age of trees. """ lifeTimeExceeded = where(age > self.lt) candidates = trees[lifeTimeExceeded] trees = delete(trees, lifeTimeExceeded, axis=0) age = delete(age, lifeTimeExceeded, axis=0) return trees, candidates, age
[docs] def survivalOfTheFittest(self, task, trees, candidates, age): r"""Evaluate and filter current population. Args: task (Task): Optimization task. trees (numpy.ndarray): Population to evaluate. candidates (numpy.ndarray): Candidate population array to be updated. age (numpy.ndarray[int32]): Age of trees. Returns: Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray[float], numpy.ndarray[int32]]: 1. Trees sorted by fitness value. 2. Updated candidate population. 3. Population fitness values. 4. Age of trees """ evaluations = apply_along_axis(task.eval, 1, trees) ei = evaluations.argsort() candidates = append(candidates, trees[ei[self.al:]], axis=0) trees = trees[ei[:self.al]] age = age[ei[:self.al]] evaluations = evaluations[ei[:self.al]] return trees, candidates, evaluations, age
[docs] def initPopulation(self, task): r"""Initialize the starting population. Args: task (Task): Optimization task Returns: Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]: 1. New population. 2. New population fitness/function values. 3. Additional arguments: * age (numpy.ndarray[int32]): Age of trees. See Also: * :func:`NiaPy.algorithms.Algorithm.initPopulation` """ Trees, Evaluations, _ = Algorithm.initPopulation(self, task) age = zeros(self.NP, dtype=int32) self.dx = absolute(task.benchmark.Upper) / 5 return Trees, Evaluations, {'age': age}
[docs] def runIteration(self, task, Trees, Evaluations, xb, fxb, age, **dparams): r"""Core function of Forest Optimization Algorithm. Args: task (Task): Optimization task. Trees (numpy.ndarray): Current population. Evaluations (numpy.ndarray[float]): Current population function/fitness values. xb (numpy.ndarray): Global best individual. fxb (float): Global best individual fitness/function value. age (numpy.ndarray[int32]): Age of trees. **dparams (Dict[str, Any]): Additional arguments. Returns: Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]: 1. New population. 2. New population fitness/function values. 3. Additional arguments: * age (numpy.ndarray[int32]): Age of trees. """ candidatePopulation = ndarray((0, task.D + 1)) zeroAgeTrees = Trees[age == 0] localSeeds = self.localSeeding(task, zeroAgeTrees) age += 1 Trees, candidatePopulation, age = self.removeLifeTimeExceeded(Trees, candidatePopulation, age) Trees = append(Trees, localSeeds, axis=0) age = append(age, zeros(len(localSeeds), dtype=int32)) Trees, candidatePopulation, Evaluations, age = self.survivalOfTheFittest(task, Trees, candidatePopulation, age) gsn = int(self.tr * len(candidatePopulation)) if gsn > 0: globalSeeds = self.globalSeeding(task, candidatePopulation, gsn) Trees = append(Trees, globalSeeds, axis=0) age = append(age, zeros(len(globalSeeds), dtype=int32)) gste = apply_along_axis(task.eval, 1, globalSeeds) Evaluations = append(Evaluations, gste) ib = argmin(Evaluations) age[ib] = 0 if Evaluations[ib] < fxb: xb, fxb = Trees[ib].copy(), Evaluations[ib] return Trees, Evaluations, xb, fxb, {'age': age}