Source code for niapy.algorithms.basic.hs

# encoding=utf8
import logging

import numpy as np

from niapy.algorithms.algorithm import Algorithm

logging.basicConfig()
logger = logging.getLogger("niapy.algorithms.basic")
logger.setLevel("INFO")

__all__ = ["HarmonySearch", "HarmonySearchV1"]


[docs]class HarmonySearch(Algorithm): r"""Implementation of Harmony Search algorithm. Algorithm: Harmony Search Algorithm Date: 2018 Authors: Klemen Berkovič License: MIT Reference URL: https://journals.sagepub.com/doi/10.1177/003754970107600201 Reference paper: Geem, Z. W., Kim, J. H., & Loganathan, G. V. (2001). A new heuristic optimization algorithm: harmony search. Simulation, 76(2), 60-68. Attributes: Name (List[str]): List of strings representing algorithm names r_accept (float): Probability of accepting new bandwidth into harmony. r_pa (float): Probability of accepting random bandwidth into harmony. b_range (float): Range of bandwidth. See Also: * :class:`niapy.algorithms.algorithm.Algorithm` """ Name = ["HarmonySearch", "HS"]
[docs] @staticmethod def info(): r"""Get basic information about the algorithm. Returns: str: Basic information. """ return r"""Geem, Z. W., Kim, J. H., & Loganathan, G. V. (2001). A new heuristic optimization algorithm: harmony search. Simulation, 76(2), 60-68."""
[docs] def __init__(self, population_size=30, r_accept=0.7, r_pa=0.35, b_range=1.42, *args, **kwargs): """Initialize HarmonySearch. Args: population_size (Optional[int]): Number of harmony in the memory. r_accept (Optional[float]): Probability of accepting new bandwidth to harmony. r_pa (Optional[float]): Probability of accepting random bandwidth into harmony. b_range (Optional[float]): Bandwidth range. """ super().__init__(population_size, *args, **kwargs) self.r_accept = r_accept self.r_pa = r_pa self.b_range = b_range
[docs] def set_parameters(self, population_size=30, r_accept=0.7, r_pa=0.35, b_range=1.42, **kwargs): r"""Set the arguments of the algorithm. Args: population_size (Optional[int]): Number of harmony in the memory. r_accept (Optional[float]): Probability of accepting new bandwidth to harmony. r_pa (Optional[float]): Probability of accepting random bandwidth into harmony. b_range (Optional[float]): Bandwidth range. See Also: * :func:`niapy.algorithms.algorithm.Algorithm.set_parameters` """ super().set_parameters(population_size=population_size, **kwargs) self.r_accept = r_accept self.r_pa = r_pa self.b_range = b_range
[docs] def get_parameters(self): """Get algorithm parameters.""" d = super().get_parameters() d.update({ 'r_accept': self.r_accept, 'r_pa': self.r_pa, 'b_range': self.b_range }) return d
[docs] def bw(self, task): r"""Get bandwidth. Args: task (Task): Optimization task. Returns: float: Bandwidth. """ return self.uniform(-1, 1) * self.b_range
[docs] def adjustment(self, x, task): r"""Adjust value based on bandwidth. Args: x (Union[int, float]): Current position. task (Task): Optimization task. Returns: float: New position. """ return x + self.bw(task)
[docs] def improvise(self, harmonies, task): r"""Create new individual. Args: harmonies (numpy.ndarray): Current population. task (Task): Optimization task. Returns: numpy.ndarray: New individual. """ harmony = np.zeros(task.dimension) for i in range(task.dimension): r, j = self.random(), self.integers(self.population_size) harmony[i] = harmonies[j, i] if r > self.r_accept else self.adjustment(harmonies[j, i], task) if r > self.r_pa else self.uniform( task.lower[i], task.upper[i]) return harmony
[docs] def run_iteration(self, task, population, population_fitness, best_x, best_fitness, **params): r"""Core function of HarmonySearch algorithm. Args: task (Task): Optimization task. population (numpy.ndarray): Current population. population_fitness (numpy.ndarray): Current populations function/fitness values. best_x (numpy.ndarray): Global best individual. best_fitness (float): Global best fitness/function value. **params (Dict[str, Any]): Additional arguments. Returns: Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, Dict[str, Any]]: 1. New harmony/population. 2. New populations function/fitness values. 3. New global best solution 4. New global best solution fitness/objective value 5. Additional arguments. """ harmony = self.improvise(population, task) harmony_fitness = task.eval(task.repair(harmony, self.rng)) iw = np.argmax(population_fitness) if harmony_fitness <= population_fitness[iw]: population[iw], population_fitness[iw] = harmony, harmony_fitness best_x, best_fitness = self.get_best(harmony, harmony_fitness, best_x, best_fitness) return population, population_fitness, best_x, best_fitness, {}
[docs]class HarmonySearchV1(HarmonySearch): r"""Implementation of harmony search algorithm. Algorithm: Harmony Search Algorithm Date: 2018 Authors: Klemen Berkovič License: MIT Reference URL: https://link.springer.com/chapter/10.1007/978-3-642-00185-7_1 Reference paper: Yang, Xin-She. "Harmony search as a metaheuristic algorithm." Music-inspired harmony search algorithm. Springer, Berlin, Heidelberg, 2009. 1-14. Attributes: Name (List[str]): List of strings representing algorithm name. bw_min (float): Minimal bandwidth. bw_max (float): Maximal bandwidth. See Also: * :class:`niapy.algorithms.basic.hs.HarmonySearch` """ Name = ["HarmonySearchV1", "HSv1"]
[docs] @staticmethod def info(): r"""Get basic information about algorithm. Returns: str: Basic information. """ return r"""Yang, Xin-She. "Harmony search as a metaheuristic algorithm." Music-inspired harmony search algorithm. Springer, Berlin, Heidelberg, 2009. 1-14."""
[docs] def __init__(self, bw_min=1, bw_max=2, *args, **kwargs): """Initialize HarmonySearchV1. Args: bw_min (Optional[float]): Minimal bandwidth. bw_max (Optional[float]): Maximal bandwidth. """ super().__init__(*args, **kwargs) self.bw_min = bw_min self.bw_max = bw_max
[docs] def set_parameters(self, bw_min=1, bw_max=2, **kwargs): r"""Set the parameters of the algorithm. Args: bw_min (Optional[float]): Minimal bandwidth bw_max (Optional[float]): Maximal bandwidth See Also: * :func:`niapy.algorithms.basic.hs.HarmonySearch.set_parameters` """ super().set_parameters(**kwargs) self.bw_min, self.bw_max = bw_min, bw_max
[docs] def get_parameters(self): """Get algorithm parameters.""" d = super().get_parameters() d.update({ 'bw_min': self.bw_min, 'bw_max': self.bw_max }) return d
[docs] def bw(self, task): r"""Get new bandwidth. Args: task (Task): Optimization task. Returns: float: New bandwidth. """ return self.bw_min * np.exp(np.log(self.bw_min / self.bw_max) * (task.iters + 1) / task.max_iters)