pyVolutionary 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyvolutionary/__init__.py +44 -0
- pyvolutionary/abstract.py +325 -0
- pyvolutionary/african_vulture/__init__.py +2 -0
- pyvolutionary/african_vulture/african_vulture_optimization.py +87 -0
- pyvolutionary/african_vulture/models.py +41 -0
- pyvolutionary/ant_colony/__init__.py +2 -0
- pyvolutionary/ant_colony/ant_colony_optimization.py +80 -0
- pyvolutionary/ant_colony/models.py +25 -0
- pyvolutionary/aquila/__init__.py +2 -0
- pyvolutionary/aquila/aquila_optimization.py +75 -0
- pyvolutionary/aquila/models.py +9 -0
- pyvolutionary/bacterial_foraging/__init__.py +2 -0
- pyvolutionary/bacterial_foraging/bacterial_foraging_optimization.py +152 -0
- pyvolutionary/bacterial_foraging/models.py +63 -0
- pyvolutionary/bat/__init__.py +2 -0
- pyvolutionary/bat/bat_optimization.py +66 -0
- pyvolutionary/bat/models.py +66 -0
- pyvolutionary/bee_colony/__init__.py +2 -0
- pyvolutionary/bee_colony/bee_colony_optimization.py +116 -0
- pyvolutionary/bee_colony/models.py +22 -0
- pyvolutionary/camel_caravan/__init__.py +2 -0
- pyvolutionary/camel_caravan/camel_caravan_optimization.py +96 -0
- pyvolutionary/camel_caravan/models.py +61 -0
- pyvolutionary/coral_reef/__init__.py +2 -0
- pyvolutionary/coral_reef/coral_reef_optimization.py +133 -0
- pyvolutionary/coral_reef/models.py +81 -0
- pyvolutionary/coyotes/__init__.py +2 -0
- pyvolutionary/coyotes/coyotes_optimization.py +96 -0
- pyvolutionary/coyotes/models.py +22 -0
- pyvolutionary/earthworms/__init__.py +2 -0
- pyvolutionary/earthworms/earthworms_optimization.py +124 -0
- pyvolutionary/earthworms/models.py +62 -0
- pyvolutionary/electromagnetic_field/__init__.py +2 -0
- pyvolutionary/electromagnetic_field/electromagnetic_field_optimization.py +58 -0
- pyvolutionary/electromagnetic_field/models.py +45 -0
- pyvolutionary/elephant_herd/__init__.py +2 -0
- pyvolutionary/elephant_herd/elephant_herd_optimization.py +56 -0
- pyvolutionary/elephant_herd/models.py +38 -0
- pyvolutionary/enums.py +39 -0
- pyvolutionary/firefly_swarm/__init__.py +2 -0
- pyvolutionary/firefly_swarm/firefly_swarm_optimization.py +76 -0
- pyvolutionary/firefly_swarm/models.py +37 -0
- pyvolutionary/fireworks/__init__.py +2 -0
- pyvolutionary/fireworks/fireworks_optimization.py +96 -0
- pyvolutionary/fireworks/models.py +41 -0
- pyvolutionary/fish_school_search/__init__.py +2 -0
- pyvolutionary/fish_school_search/fish_school_search_optimization.py +142 -0
- pyvolutionary/fish_school_search/models.py +27 -0
- pyvolutionary/flower_pollination_algorithm/__init__.py +2 -0
- pyvolutionary/flower_pollination_algorithm/flower_pollination_algorithm_optimization.py +46 -0
- pyvolutionary/flower_pollination_algorithm/models.py +29 -0
- pyvolutionary/forest_algorithm/__init__.py +2 -0
- pyvolutionary/forest_algorithm/forest_optimization_algorithm.py +121 -0
- pyvolutionary/forest_algorithm/models.py +53 -0
- pyvolutionary/fox/__init__.py +2 -0
- pyvolutionary/fox/fox_optimization.py +43 -0
- pyvolutionary/fox/models.py +29 -0
- pyvolutionary/genetic_algorithm/__init__.py +2 -0
- pyvolutionary/genetic_algorithm/genetic_algorithm_optimization.py +167 -0
- pyvolutionary/genetic_algorithm/models.py +21 -0
- pyvolutionary/grasshopper/__init__.py +2 -0
- pyvolutionary/grasshopper/grasshopper_optimization_algorithm.py +73 -0
- pyvolutionary/grasshopper/models.py +29 -0
- pyvolutionary/grey_wolf/__init__.py +2 -0
- pyvolutionary/grey_wolf/grey_wolf_optimization.py +62 -0
- pyvolutionary/grey_wolf/models.py +9 -0
- pyvolutionary/harmony_search/__init__.py +2 -0
- pyvolutionary/harmony_search/harmony_search_optimization.py +64 -0
- pyvolutionary/harmony_search/models.py +29 -0
- pyvolutionary/helpers.py +290 -0
- pyvolutionary/imperialist_competitive/__init__.py +2 -0
- pyvolutionary/imperialist_competitive/classes.py +119 -0
- pyvolutionary/imperialist_competitive/imperialist_competitive_optimization.py +198 -0
- pyvolutionary/imperialist_competitive/models.py +47 -0
- pyvolutionary/invasive_weed/__init__.py +2 -0
- pyvolutionary/invasive_weed/invasive_weed_optimization.py +52 -0
- pyvolutionary/invasive_weed/models.py +51 -0
- pyvolutionary/krill_herd/__init__.py +2 -0
- pyvolutionary/krill_herd/krill_herd_optimization.py +179 -0
- pyvolutionary/krill_herd/models.py +62 -0
- pyvolutionary/levi_jaya_swarm/__init__.py +2 -0
- pyvolutionary/levi_jaya_swarm/levy_flight_jaya_swarm_optimization.py +40 -0
- pyvolutionary/levi_jaya_swarm/models.py +9 -0
- pyvolutionary/models.py +130 -0
- pyvolutionary/monarch_butterfly/__init__.py +2 -0
- pyvolutionary/monarch_butterfly/models.py +25 -0
- pyvolutionary/monarch_butterfly/monarch_butterfly_optimization.py +104 -0
- pyvolutionary/mountain_gazelle/__init__.py +2 -0
- pyvolutionary/mountain_gazelle/models.py +9 -0
- pyvolutionary/mountain_gazelle/mountain_gazelle_optimization.py +118 -0
- pyvolutionary/osprey/__init__.py +2 -0
- pyvolutionary/osprey/models.py +9 -0
- pyvolutionary/osprey/osprey_optimization.py +54 -0
- pyvolutionary/particle_swarm/__init__.py +2 -0
- pyvolutionary/particle_swarm/models.py +40 -0
- pyvolutionary/particle_swarm/particle_swarm_optimization.py +78 -0
- pyvolutionary/pathfinder_algorithm/__init__.py +2 -0
- pyvolutionary/pathfinder_algorithm/models.py +12 -0
- pyvolutionary/pathfinder_algorithm/pathfinder_algorithm_optimization.py +56 -0
- pyvolutionary/pelican/__init__.py +2 -0
- pyvolutionary/pelican/models.py +9 -0
- pyvolutionary/pelican/pelican_optimization.py +46 -0
- pyvolutionary/seagull/__init__.py +2 -0
- pyvolutionary/seagull/models.py +21 -0
- pyvolutionary/seagull/seagull_optimization.py +43 -0
- pyvolutionary/siberian_tiger/__init__.py +2 -0
- pyvolutionary/siberian_tiger/models.py +9 -0
- pyvolutionary/siberian_tiger/siberian_tiger_optimization.py +53 -0
- pyvolutionary/tasmanian_devil/__init__.py +2 -0
- pyvolutionary/tasmanian_devil/models.py +9 -0
- pyvolutionary/tasmanian_devil/tasmanian_devil_optimization.py +69 -0
- pyvolutionary/tests/fixtures.py +21 -0
- pyvolutionary/tests/test_african_vulture_optimization.py +34 -0
- pyvolutionary/tests/test_ant_colony_optimization.py +34 -0
- pyvolutionary/tests/test_aquila_optimization.py +27 -0
- pyvolutionary/tests/test_bacterial_foraging_optimization.py +37 -0
- pyvolutionary/tests/test_bat_optimization.py +34 -0
- pyvolutionary/tests/test_bee_colony_optimization.py +32 -0
- pyvolutionary/tests/test_camel_caravan_optimization.py +37 -0
- pyvolutionary/tests/test_coral_reef_optimization.py +39 -0
- pyvolutionary/tests/test_coyotes_optimization.py +32 -0
- pyvolutionary/tests/test_earthworms_optimization.py +37 -0
- pyvolutionary/tests/test_electromagnetic_field_optimization.py +35 -0
- pyvolutionary/tests/test_elephant_herd_optimization.py +34 -0
- pyvolutionary/tests/test_firefly_swarm_optimization.py +34 -0
- pyvolutionary/tests/test_fireworks_algorithm_optimization.py +36 -0
- pyvolutionary/tests/test_fish_school_search_optimization.py +37 -0
- pyvolutionary/tests/test_flower_pollination_algorithm_optimization.py +33 -0
- pyvolutionary/tests/test_forest_algorithm_optimization.py +36 -0
- pyvolutionary/tests/test_foxes_optimization.py +33 -0
- pyvolutionary/tests/test_genetic_algorithm_optimization.py +32 -0
- pyvolutionary/tests/test_grasshopper_optimization_algorithm.py +33 -0
- pyvolutionary/tests/test_grey_wolf_optimization.py +27 -0
- pyvolutionary/tests/test_harmony_search_optimization.py +33 -0
- pyvolutionary/tests/test_imperialist_competitive_optimization.py +40 -0
- pyvolutionary/tests/test_invasive_weed_optimization.py +34 -0
- pyvolutionary/tests/test_krill_herd_optimization.py +40 -0
- pyvolutionary/tests/test_levy_flight_jaya_swarm_optimization.py +33 -0
- pyvolutionary/tests/test_monarch_butterfly_optimization.py +33 -0
- pyvolutionary/tests/test_mountain_gazelle_optimization.py +27 -0
- pyvolutionary/tests/test_osprey_optimization.py +26 -0
- pyvolutionary/tests/test_particle_swarm_optimization.py +34 -0
- pyvolutionary/tests/test_pathfinder_algorithm_optimization.py +27 -0
- pyvolutionary/tests/test_pelican_optimization.py +27 -0
- pyvolutionary/tests/test_seagull_optimization.py +32 -0
- pyvolutionary/tests/test_siberian_tiger_optimization.py +27 -0
- pyvolutionary/tests/test_task_bounds.py +9 -0
- pyvolutionary/tests/test_tasmanian_devil_optimization.py +27 -0
- pyvolutionary/tests/test_utils.py +43 -0
- pyvolutionary/tests/test_virus_colony_search_optimization.py +33 -0
- pyvolutionary/tests/test_walrus_optimization.py +27 -0
- pyvolutionary/tests/test_whales_optimization.py +27 -0
- pyvolutionary/tests/test_wildebeest_herd_optimization.py +41 -0
- pyvolutionary/tests/test_zebra_optimization.py +27 -0
- pyvolutionary/utils.py +94 -0
- pyvolutionary/virus_colony_search/__init__.py +2 -0
- pyvolutionary/virus_colony_search/models.py +29 -0
- pyvolutionary/virus_colony_search/virus_colony_search_optimization.py +99 -0
- pyvolutionary/walrus/__init__.py +2 -0
- pyvolutionary/walrus/models.py +9 -0
- pyvolutionary/walrus/walrus_optimization.py +43 -0
- pyvolutionary/whales/__init__.py +2 -0
- pyvolutionary/whales/models.py +12 -0
- pyvolutionary/whales/whales_optimization.py +56 -0
- pyvolutionary/wildebeest_herd/__init__.py +2 -0
- pyvolutionary/wildebeest_herd/models.py +94 -0
- pyvolutionary/wildebeest_herd/wildebeest_herd_optimization.py +143 -0
- pyvolutionary/zebra/__init__.py +2 -0
- pyvolutionary/zebra/models.py +9 -0
- pyvolutionary/zebra/zebra_optimization.py +53 -0
- pyvolutionary-1.0.1.dist-info/METADATA +350 -0
- pyvolutionary-1.0.1.dist-info/RECORD +173 -0
- pyvolutionary-1.0.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from pydantic import field_validator, model_validator
|
|
2
|
+
|
|
3
|
+
from ..models import Agent, BaseOptimizationConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Earthworm(Agent):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EarthwormsOptimizationConfig(BaseOptimizationConfig):
|
|
11
|
+
"""
|
|
12
|
+
Configuration class of the Earthworms Optimization algorithm.
|
|
13
|
+
prob_mutate (float): [0, 1), probability of mutation of an earthworm.\n
|
|
14
|
+
prob_crossover (float): [0, 1), probability of crossover of an earthworm.\n
|
|
15
|
+
keep (int): [2, int(population_size/2)], number of earthworms to keep.\n
|
|
16
|
+
alpha (float): [0, 1), similarity factor.\n
|
|
17
|
+
beta (float): [0, 1), the initial proportional factor.\n
|
|
18
|
+
gamma (float): [0, 1), a sort cooling factor for beta.
|
|
19
|
+
"""
|
|
20
|
+
prob_mutate: float
|
|
21
|
+
prob_crossover: float
|
|
22
|
+
keep: int
|
|
23
|
+
alpha: float
|
|
24
|
+
beta: float
|
|
25
|
+
gamma: float
|
|
26
|
+
|
|
27
|
+
@model_validator(mode="after")
|
|
28
|
+
def validate_keep(self) -> "EarthwormsOptimizationConfig":
|
|
29
|
+
if not 2 <= self.keep <= int(self.population_size / 2):
|
|
30
|
+
raise ValueError(f"keep must be a positive integer greater than 2 and lower than population_size / 2. "
|
|
31
|
+
f"Got {self.keep}")
|
|
32
|
+
return self
|
|
33
|
+
|
|
34
|
+
@field_validator("prob_mutate")
|
|
35
|
+
def correct_prob_mutate(cls, v):
|
|
36
|
+
if not 0 <= v < 1:
|
|
37
|
+
raise ValueError(f"\"prob_mutate\" must be a positive float lower than 1. Got {v}")
|
|
38
|
+
return v
|
|
39
|
+
|
|
40
|
+
@field_validator("prob_crossover")
|
|
41
|
+
def correct_prob_crossover(cls, v):
|
|
42
|
+
if not 0 <= v < 1:
|
|
43
|
+
raise ValueError(f"\"prob_crossover\" must be a positive float lower than 1. Got {v}")
|
|
44
|
+
return v
|
|
45
|
+
|
|
46
|
+
@field_validator("alpha")
|
|
47
|
+
def correct_alpha(cls, v):
|
|
48
|
+
if not 0 <= v < 1:
|
|
49
|
+
raise ValueError(f"\"alpha\" must be a positive float lower than 1. Got {v}")
|
|
50
|
+
return v
|
|
51
|
+
|
|
52
|
+
@field_validator("beta")
|
|
53
|
+
def correct_beta(cls, v):
|
|
54
|
+
if not 0 <= v < 1:
|
|
55
|
+
raise ValueError(f"\"beta\" must be a positive float lower than 1. Got {v}")
|
|
56
|
+
return v
|
|
57
|
+
|
|
58
|
+
@field_validator("gamma")
|
|
59
|
+
def correct_gamma(cls, v):
|
|
60
|
+
if not 0 <= v < 1:
|
|
61
|
+
raise ValueError(f"\"gamma\" must be a positive float lower than 1. Got {v}")
|
|
62
|
+
return v
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from ..helpers import parse_obj_doc # type: ignore
|
|
4
|
+
from ..abstract import OptimizationAbstract
|
|
5
|
+
from .models import Electromagnet, ElectromagneticFieldOptimizationConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ElectromagneticFieldOptimization(OptimizationAbstract):
|
|
9
|
+
"""
|
|
10
|
+
Implementation of the Electromagnetic Field Optimization (EFO) algorithm.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
config (ElectromagneticFieldOptimizationConfig): an instance of ElectromagneticFieldOptimizationConfig class.
|
|
14
|
+
{parse_obj_doc(ElectromagneticFieldOptimizationConfig)}
|
|
15
|
+
|
|
16
|
+
Bibliography
|
|
17
|
+
----------
|
|
18
|
+
[1] Abedinpourshotorban, H., Shamsuddin, S.M., Beheshti, Z. and Jawawi, D.N., 2016. Electromagnetic field
|
|
19
|
+
optimization: a physics-inspired metaheuristic optimization algorithm. Swarm and Evolutionary Computation, 26,
|
|
20
|
+
pp.8-22.
|
|
21
|
+
"""
|
|
22
|
+
def __init__(self, config: ElectromagneticFieldOptimizationConfig, debug: bool | None = False):
|
|
23
|
+
super().__init__(config, debug)
|
|
24
|
+
self.__phi = (1 + np.sqrt(5)) / 2 # golden ratio
|
|
25
|
+
|
|
26
|
+
def optimization_step(self):
|
|
27
|
+
pop_size = self._config.population_size
|
|
28
|
+
n_field = int(pop_size * (1 - self._config.n_field))
|
|
29
|
+
n_field1 = int(pop_size * self._config.p_field + 1)
|
|
30
|
+
p_field = int(pop_size * self._config.p_field)
|
|
31
|
+
ps_rate = self._config.ps_rate
|
|
32
|
+
|
|
33
|
+
phi = self.__phi
|
|
34
|
+
r_rate = self._config.r_rate
|
|
35
|
+
n_dims = self._task.space_dimension
|
|
36
|
+
|
|
37
|
+
best_pos = np.array(self._best_agent.position)
|
|
38
|
+
for idx, electromagnet in enumerate(self._population):
|
|
39
|
+
if np.random.random() < ps_rate:
|
|
40
|
+
r_idx1 = np.random.randint(0, p_field) # top
|
|
41
|
+
r_idx2 = np.random.randint(n_field, pop_size) # bottom
|
|
42
|
+
r_idx3 = np.random.randint(n_field1, n_field) # middle
|
|
43
|
+
|
|
44
|
+
pos_new = np.array(self._population[r_idx1].position) + phi * np.random.random() * (
|
|
45
|
+
best_pos - np.array(self._population[r_idx3].position)
|
|
46
|
+
) + np.random.random() * (best_pos - np.array(self._population[r_idx2].position))
|
|
47
|
+
else:
|
|
48
|
+
pos_new = self._init_position()
|
|
49
|
+
|
|
50
|
+
# replacement of one electromagnet of generated particle with a random number
|
|
51
|
+
# (only for some generated particles) to bring diversity to the population
|
|
52
|
+
if np.random.random() < r_rate:
|
|
53
|
+
pos_new[np.random.randint(0, n_dims)] = self._uniform_coordinates(np.random.randint(0, n_dims))
|
|
54
|
+
|
|
55
|
+
# checking whether the generated number is inside boundary or not
|
|
56
|
+
agent = self._init_agent(self._correct_position(pos_new))
|
|
57
|
+
|
|
58
|
+
self._population[idx] = self._greedy_select_agent(electromagnet, agent)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from pydantic import field_validator
|
|
2
|
+
|
|
3
|
+
from ..models import Agent, BaseOptimizationConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Electromagnet(Agent):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ElectromagneticFieldOptimizationConfig(BaseOptimizationConfig):
|
|
11
|
+
"""
|
|
12
|
+
Configuration class for the Electromagnetic Field Optimization algorithm.
|
|
13
|
+
r_rate (float): [0.1, 0.6], like mutation parameter in GA but for one variable.\n
|
|
14
|
+
ps_rate (float): [0.5, 0.95], like crossover parameter in GA.\n
|
|
15
|
+
p_field (float): [0.05, 0.3], portion of population, positive field.\n
|
|
16
|
+
n_field (float): [0.3, 0.7], portion of population, negative field.
|
|
17
|
+
"""
|
|
18
|
+
r_rate: float
|
|
19
|
+
ps_rate: float
|
|
20
|
+
p_field: float
|
|
21
|
+
n_field: float
|
|
22
|
+
|
|
23
|
+
@field_validator("r_rate")
|
|
24
|
+
def r_rate_validator(cls, v):
|
|
25
|
+
if not 0.1 <= v <= 0.6:
|
|
26
|
+
raise ValueError("r_rate must be between 0.1 and 0.6")
|
|
27
|
+
return v
|
|
28
|
+
|
|
29
|
+
@field_validator("ps_rate")
|
|
30
|
+
def ps_rate_validator(cls, v):
|
|
31
|
+
if not 0.5 <= v <= 0.95:
|
|
32
|
+
raise ValueError("ps_rate must be between 0.5 and 0.95")
|
|
33
|
+
return v
|
|
34
|
+
|
|
35
|
+
@field_validator("p_field")
|
|
36
|
+
def p_field_validator(cls, v):
|
|
37
|
+
if not 0.05 <= v <= 0.3:
|
|
38
|
+
raise ValueError("p_field must be between 0.05 and 0.3")
|
|
39
|
+
return v
|
|
40
|
+
|
|
41
|
+
@field_validator("n_field")
|
|
42
|
+
def n_field_validator(cls, v):
|
|
43
|
+
if not 0.3 <= v <= 0.7:
|
|
44
|
+
raise ValueError("n_field must be between 0.3 and 0.7")
|
|
45
|
+
return v
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from ..helpers import (
|
|
4
|
+
generate_group_population,
|
|
5
|
+
sort_by_cost,
|
|
6
|
+
parse_obj_doc, # type: ignore
|
|
7
|
+
)
|
|
8
|
+
from ..abstract import OptimizationAbstract
|
|
9
|
+
from .models import Elephant, ElephantHerdOptimizationConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ElephantHerdOptimization(OptimizationAbstract):
|
|
13
|
+
"""
|
|
14
|
+
Implementation of the Elephant Herd Optimization algorithm.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
config (ElephantHerdOptimizationConfig): an instance of ElephantHerdOptimizationConfig class.
|
|
18
|
+
{parse_obj_doc(ElephantHerdOptimizationConfig)}
|
|
19
|
+
|
|
20
|
+
Bibliography
|
|
21
|
+
----------
|
|
22
|
+
[1] Wang, G.G., Deb, S. and Coelho, L.D.S., 2015, December. Elephant herding optimization.
|
|
23
|
+
In 2015 3rd international symposium on computational and business intelligence (ISCBI) (pp. 1-5). IEEE.
|
|
24
|
+
"""
|
|
25
|
+
def __init__(self, config: ElephantHerdOptimizationConfig, debug: bool | None = False):
|
|
26
|
+
super().__init__(config, debug)
|
|
27
|
+
self.__n_individuals: int = int(self._config.population_size / self._config.n_clans)
|
|
28
|
+
self.__groups: list[list[Elephant]] = []
|
|
29
|
+
|
|
30
|
+
def _init_population(self):
|
|
31
|
+
super()._init_population()
|
|
32
|
+
self.__groups = generate_group_population(self._population, self._config.n_clans, self.__n_individuals)
|
|
33
|
+
|
|
34
|
+
def optimization_step(self):
|
|
35
|
+
n_individuals = self.__n_individuals
|
|
36
|
+
|
|
37
|
+
for idx in range(0, self._config.population_size):
|
|
38
|
+
clan_idx = int(idx / n_individuals)
|
|
39
|
+
pos_group = [np.array(elephant.position) for elephant in self.__groups[clan_idx]]
|
|
40
|
+
|
|
41
|
+
# pos_clan_idx == 0 means the best in clan, because all clans are sorted based on cost
|
|
42
|
+
pos_clan_idx = int(idx % n_individuals)
|
|
43
|
+
pos_new = self._config.beta * np.mean(pos_group, axis=0) if pos_clan_idx == 0 else (
|
|
44
|
+
pos_group[pos_clan_idx] + self._config.alpha * np.random.random() * (
|
|
45
|
+
pos_group[0] - pos_group[pos_clan_idx]
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
self._population[idx] = self._greedy_select_agent(self._population[idx], self._init_agent(pos_new))
|
|
49
|
+
|
|
50
|
+
self.__groups = generate_group_population(self._population, self._config.n_clans, n_individuals)
|
|
51
|
+
|
|
52
|
+
# Separating operator
|
|
53
|
+
for idx in range(0, self._config.n_clans):
|
|
54
|
+
sort_by_cost(self.__groups[idx])
|
|
55
|
+
self.__groups[idx][-1] = self._init_agent()
|
|
56
|
+
self._population = [elephant for pack in self.__groups for elephant in pack]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from pydantic import field_validator, model_validator
|
|
2
|
+
|
|
3
|
+
from ..models import Agent, BaseOptimizationConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Elephant(Agent):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ElephantHerdOptimizationConfig(BaseOptimizationConfig):
|
|
11
|
+
"""
|
|
12
|
+
Configuration class of the Earthworms Optimization algorithm.
|
|
13
|
+
alpha (float): (0, 3), a factor that determines the influence of the best in each clan.\n
|
|
14
|
+
beta (float): (0, 1), a factor that determines the influence of the x_center.\n
|
|
15
|
+
n_clans (int): [2, int(population_size/5)], the number of clans.
|
|
16
|
+
"""
|
|
17
|
+
alpha: float
|
|
18
|
+
beta: float
|
|
19
|
+
n_clans: int
|
|
20
|
+
|
|
21
|
+
@model_validator(mode="after")
|
|
22
|
+
def validate_n_clans(self) -> "ElephantHerdOptimizationConfig":
|
|
23
|
+
if not 2 <= self.n_clans <= int(self.population_size / 5):
|
|
24
|
+
raise ValueError(f"n_clans must be a positive integer greater than 2 and lower than population_size / 5. "
|
|
25
|
+
f"Got {self.n_clans}")
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
@field_validator("alpha")
|
|
29
|
+
def correct_alpha(cls, v):
|
|
30
|
+
if not 0 < v < 3:
|
|
31
|
+
raise ValueError(f"\"alpha\" must be a positive float lower than 3. Got {v}")
|
|
32
|
+
return v
|
|
33
|
+
|
|
34
|
+
@field_validator("beta")
|
|
35
|
+
def correct_beta(cls, v):
|
|
36
|
+
if not 0 < v < 1:
|
|
37
|
+
raise ValueError(f"\"beta\" must be a positive float lower than 1. Got {v}")
|
|
38
|
+
return v
|
pyvolutionary/enums.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from enum import Enum as BaseEnum, EnumMeta
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MetaEnum(EnumMeta):
|
|
5
|
+
"""
|
|
6
|
+
Enables the use of the `in` operator for enums.
|
|
7
|
+
For example:
|
|
8
|
+
if el not in Elements:
|
|
9
|
+
raise ValueError("invalid element")
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __contains__(cls, item):
|
|
13
|
+
try:
|
|
14
|
+
cls(item) # pylint: disable=E1120
|
|
15
|
+
except ValueError:
|
|
16
|
+
return False
|
|
17
|
+
return True
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Enum(BaseEnum, metaclass=MetaEnum):
|
|
21
|
+
def __str__(self):
|
|
22
|
+
return self.value
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TaskType(Enum):
|
|
26
|
+
"""
|
|
27
|
+
The type of task that the user wants to perform.
|
|
28
|
+
"""
|
|
29
|
+
MIN = "min"
|
|
30
|
+
MAX = "max"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ModeSolver(Enum):
|
|
34
|
+
"""
|
|
35
|
+
The mode of the solver.
|
|
36
|
+
"""
|
|
37
|
+
SERIAL = "serial"
|
|
38
|
+
THREAD = "thread"
|
|
39
|
+
PROCESS = "process"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from ..helpers import (
|
|
4
|
+
best_agent,
|
|
5
|
+
distance,
|
|
6
|
+
parse_obj_doc, # type: ignore
|
|
7
|
+
)
|
|
8
|
+
from ..abstract import OptimizationAbstract
|
|
9
|
+
from .models import Firefly, FireflySwarmOptimizationConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FireflySwarmOptimization(OptimizationAbstract):
|
|
13
|
+
"""
|
|
14
|
+
Implementation of the Firefly Swarm Optimization algorithm.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
config (FireflySwarmOptimizationConfig): an instance of FireflySwarmOptimizationConfig class.
|
|
18
|
+
{parse_obj_doc(FireflySwarmOptimizationConfig)}
|
|
19
|
+
|
|
20
|
+
Bibliography
|
|
21
|
+
----------
|
|
22
|
+
[1] Yang, Xin-She. "Firefly algorithms for multimodal optimization". International symposium on stochastic algorithms.
|
|
23
|
+
Springer, Berlin, Heidelberg, 2009.
|
|
24
|
+
[2] Yang, Xin-She. "Firefly algorithm, stochastic test functions and design optimization." International Journal of
|
|
25
|
+
Bio-Inspired Computation 2.2 (2010): 78-84. https://doi.org/10.1504/IJBIC.2010.032124
|
|
26
|
+
[3] Yang, Xin-She. "Firefly algorithm, Levy flights and global optimization." Research and development in intelligent
|
|
27
|
+
systems XXVI. Springer, London, 2010. 209-218. https://doi.org/10.1007/978-1-84996-153-4_15
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, config: FireflySwarmOptimizationConfig, debug: bool | None = False):
|
|
31
|
+
super().__init__(config, debug)
|
|
32
|
+
|
|
33
|
+
def __update_alpha__(self):
|
|
34
|
+
"""
|
|
35
|
+
Update alpha parameter. This parameter is used to control the randomness of the movement of the fireflies.
|
|
36
|
+
"""
|
|
37
|
+
delta = 1.0 - (10.0 ** -4.0 / 0.9) ** (1.0 / self._cycles)
|
|
38
|
+
self._config.alpha *= (1 - delta) * self._config.alpha
|
|
39
|
+
|
|
40
|
+
def __update_population__(self):
|
|
41
|
+
"""
|
|
42
|
+
Update the population of fireflies. This method is called at each iteration of the algorithm. It updates the
|
|
43
|
+
position of each firefly based on the position of the other fireflies. The fireflies with the best fitness
|
|
44
|
+
values will attract the other fireflies and the fireflies with the worst fitness values will be attracted by the
|
|
45
|
+
other fireflies. The fireflies with the best fitness values will move towards the fireflies with the worst
|
|
46
|
+
fitness values. The fireflies with the worst fitness values will move away from the fireflies with the best
|
|
47
|
+
fitness values.
|
|
48
|
+
"""
|
|
49
|
+
alpha = self._config.alpha
|
|
50
|
+
beta_min = self._config.beta_min
|
|
51
|
+
gamma = self._config.gamma
|
|
52
|
+
|
|
53
|
+
n_dims = self._task.space_dimension
|
|
54
|
+
pop_size = self._config.population_size
|
|
55
|
+
for idx in range(0, self._config.population_size):
|
|
56
|
+
position = self._population[idx].position
|
|
57
|
+
cost = self._population[idx].cost
|
|
58
|
+
weighted_pos = [np.array(position) + beta_min * np.exp(
|
|
59
|
+
-gamma * distance(position, firefly.position) / np.sqrt(n_dims)
|
|
60
|
+
) * np.matmul(
|
|
61
|
+
np.array(firefly.position) - np.array(position), np.random.uniform(0, 1, (n_dims, n_dims))
|
|
62
|
+
) + alpha * np.random.uniform(0, 1, n_dims)
|
|
63
|
+
for firefly in self._population[idx+1:] if firefly.cost < cost]
|
|
64
|
+
|
|
65
|
+
new_agents = (
|
|
66
|
+
[self._init_agent(position) for position in weighted_pos] +
|
|
67
|
+
[self._init_agent() for _ in range(0, pop_size - len(weighted_pos) + 1)]
|
|
68
|
+
)
|
|
69
|
+
self._population[idx] = best_agent(new_agents)
|
|
70
|
+
|
|
71
|
+
def optimization_step(self):
|
|
72
|
+
# update alpha
|
|
73
|
+
self.__update_alpha__()
|
|
74
|
+
|
|
75
|
+
# replace old population
|
|
76
|
+
self.__update_population__()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from pydantic import field_validator
|
|
2
|
+
|
|
3
|
+
from ..models import Agent, BaseOptimizationConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Firefly(Agent):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FireflySwarmOptimizationConfig(BaseOptimizationConfig):
|
|
11
|
+
"""
|
|
12
|
+
Configuration class of the Firefly Swarm Optimization algorithm.
|
|
13
|
+
alpha (float): [0, 1), the attractiveness constant of the fireflies.\n
|
|
14
|
+
beta_min (float): [0, 1), the minimum value of the attractiveness constant of the fireflies.\n
|
|
15
|
+
gamma (float): [0, 1), the light absorption coefficient.
|
|
16
|
+
"""
|
|
17
|
+
alpha: float
|
|
18
|
+
beta_min: float
|
|
19
|
+
gamma: float
|
|
20
|
+
|
|
21
|
+
@field_validator("alpha")
|
|
22
|
+
def correct_alpha(cls, v):
|
|
23
|
+
if not 0 <= v < 1:
|
|
24
|
+
raise ValueError(f"\"alpha\" must be a positive float lower than 1. Got {v}")
|
|
25
|
+
return v
|
|
26
|
+
|
|
27
|
+
@field_validator("beta_min")
|
|
28
|
+
def correct_beta_min(cls, v):
|
|
29
|
+
if not 0 <= v < 1:
|
|
30
|
+
raise ValueError(f"\"beta_min\" must be a positive float lower than 1. Got {v}")
|
|
31
|
+
return v
|
|
32
|
+
|
|
33
|
+
@field_validator("gamma")
|
|
34
|
+
def correct_gamma(cls, v):
|
|
35
|
+
if not 0 <= v < 1:
|
|
36
|
+
raise ValueError(f"\"gamma\" must be a positive float lower than 1. Got {v}")
|
|
37
|
+
return v
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from typing import Final
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from ..helpers import parse_obj_doc # type: ignore
|
|
5
|
+
from ..abstract import OptimizationAbstract
|
|
6
|
+
from .models import Firework, FireworksOptimizationConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FireworksOptimization(OptimizationAbstract):
|
|
10
|
+
"""
|
|
11
|
+
Implementation of the Fireworks Algorithm Optimization algorithm.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
config (FireworksOptimizationConfig): an instance of FireworksAlgorithmOptimizationConfig class.
|
|
15
|
+
{parse_obj_doc(FireworksOptimizationConfig)}
|
|
16
|
+
|
|
17
|
+
Bibliography
|
|
18
|
+
----------
|
|
19
|
+
[1] Yang, X. S. (2010). Fireworks algorithm for optimization. International Journal of Bio-Inspired Computation,
|
|
20
|
+
2(4), 78–84. https://doi.org/10.1504/IJBIC.2010.037285
|
|
21
|
+
[2] Yang, X. S. (2010). Fireworks Algorithm: A Novel Swarm Intelligence Optimization Method. In Nature Inspired
|
|
22
|
+
Cooperative Strategies for Optimization (pp. 355–364). Springer Berlin Heidelberg.
|
|
23
|
+
https://doi.org/10.1007/978-3-642-12538-6_35
|
|
24
|
+
[3] Yang, X. S. (2012). Fireworks Algorithm for Optimization. In Nature-Inspired Optimization Algorithms
|
|
25
|
+
(pp. 355–364). Elsevier. https://doi.org/10.1016/B978-0-12-416743-8.00016-2
|
|
26
|
+
[4] Yang, X. S. (2013). Fireworks Algorithm: Recent Advances and Applications. In Studies in Computational
|
|
27
|
+
Intelligence (Vol. 476, pp. 355–364). Springer Berlin Heidelberg. https://doi.org/10.1007/978-3-642-31688-4_17
|
|
28
|
+
[5] Yang, X. S. (2014). Fireworks Algorithm: A Novel Swarm Intelligence Optimization Method. In Nature-Inspired
|
|
29
|
+
Computation in Engineering (pp. 355–364). Springer Berlin Heidelberg. https://doi.org/10.1007/978-3-642-39829-2_35
|
|
30
|
+
[6] Yang, X. S. (2015). Fireworks Algorithm: A Survey. International Journal of Swarm Intelligence Research,
|
|
31
|
+
5(1), 1–18. https://doi.org/10.4018/IJSIR.2015010101
|
|
32
|
+
"""
|
|
33
|
+
EPS: Final[float] = np.finfo(float).eps
|
|
34
|
+
|
|
35
|
+
def __init__(self, config: FireworksOptimizationConfig, debug: bool | None = False):
|
|
36
|
+
super().__init__(config, debug)
|
|
37
|
+
|
|
38
|
+
def __explode__(self) -> list[Firework]:
|
|
39
|
+
"""
|
|
40
|
+
This method performs the explosion of the fireworks. It generates new fireworks by exploding the current ones.
|
|
41
|
+
Gaussian sparks are generated by each firework. The number of sparks is proportional to the cost of the
|
|
42
|
+
firework. The amplitude of the explosion is proportional to the cost of the firework. The new fireworks are
|
|
43
|
+
generated by adding the amplitude to the position of the firework. The new fireworks are then corrected to
|
|
44
|
+
be within the bounds of the search space. The new fireworks are then added to the population.
|
|
45
|
+
:return: the new population
|
|
46
|
+
:rtype: list[Firework]
|
|
47
|
+
"""
|
|
48
|
+
costs = sorted([firework.cost for firework in self._population])
|
|
49
|
+
|
|
50
|
+
sparks_num = self._config.sparks_num
|
|
51
|
+
pop_size = self._config.population_size
|
|
52
|
+
explosion_amplitude = self._config.explosion_amplitude
|
|
53
|
+
a = self._config.a
|
|
54
|
+
b = self._config.b
|
|
55
|
+
|
|
56
|
+
n_dims = self._task.space_dimension
|
|
57
|
+
|
|
58
|
+
pop_new = []
|
|
59
|
+
for firework in self._population:
|
|
60
|
+
si = sparks_num * (costs[-1] - firework.cost + self.EPS) / (pop_size * costs[-1] - np.sum(costs) + self.EPS)
|
|
61
|
+
Ai = explosion_amplitude * (firework.cost - costs[0] + self.EPS) / (np.sum(costs) - costs[0] + self.EPS)
|
|
62
|
+
|
|
63
|
+
si_ = int(round(si) + 1)
|
|
64
|
+
if si < a * sparks_num:
|
|
65
|
+
si_ = int(round(a * sparks_num) + 1)
|
|
66
|
+
elif si > b * sparks_num:
|
|
67
|
+
si_ = int(round(b * sparks_num) + 1)
|
|
68
|
+
|
|
69
|
+
# generate Gaussian sparks
|
|
70
|
+
for j in range(0, si_):
|
|
71
|
+
pos_new = firework.position
|
|
72
|
+
list_idx = np.random.choice(range(0, n_dims), round(np.random.uniform() * n_dims), replace=False)
|
|
73
|
+
pos_new = [pos_new[i] + int(i in list_idx) * Ai * np.random.uniform(-1, 1) for i in range(0, n_dims)]
|
|
74
|
+
pop_new.append(Firework(**self._init_agent(pos_new).model_dump()))
|
|
75
|
+
|
|
76
|
+
return pop_new
|
|
77
|
+
|
|
78
|
+
def __evolve__(self, candidates: list[Firework]) -> list[Firework]:
|
|
79
|
+
sparks_num = self._config.sparks_num
|
|
80
|
+
pop_size = self._config.population_size
|
|
81
|
+
n_dims = self._task.space_dimension
|
|
82
|
+
|
|
83
|
+
for _ in range(0, sparks_num):
|
|
84
|
+
idx = np.random.randint(0, pop_size)
|
|
85
|
+
pos_new = self._population[idx].position
|
|
86
|
+
list_idx = np.random.choice(range(0, n_dims), round(np.random.uniform() * n_dims), replace=False)
|
|
87
|
+
# Gaussian explosion
|
|
88
|
+
pos_new = [pos_new[i] + int(i in list_idx) * np.random.normal(0, 1) for i in range(0, n_dims)]
|
|
89
|
+
candidates.append(Firework(**self._init_agent(pos_new).model_dump()))
|
|
90
|
+
|
|
91
|
+
return candidates
|
|
92
|
+
|
|
93
|
+
def optimization_step(self):
|
|
94
|
+
candidates = self.__evolve__(self.__explode__())
|
|
95
|
+
self._extend_and_trim_population(candidates)
|
|
96
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from pydantic import model_validator, field_validator
|
|
2
|
+
|
|
3
|
+
from ..models import Agent, BaseOptimizationConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Firework(Agent):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FireworksOptimizationConfig(BaseOptimizationConfig):
|
|
11
|
+
"""
|
|
12
|
+
Configuration class of the Fireworks Algorithm.
|
|
13
|
+
sparks_num (int): number of sparks to be generated by each firework.\n
|
|
14
|
+
a (float): (0, 1), parameter to control the explosion amplitude.\n
|
|
15
|
+
b (float): (0, 1), parameter to control the explosion amplitude.\n
|
|
16
|
+
explosion_amplitude (int): maximum amplitude of the explosion.\n
|
|
17
|
+
gaussian_explosion_number (int): number of gaussian explosions (less than the population size).
|
|
18
|
+
"""
|
|
19
|
+
sparks_num: int
|
|
20
|
+
a: float
|
|
21
|
+
b: float
|
|
22
|
+
explosion_amplitude: int
|
|
23
|
+
gaussian_explosion_number: int
|
|
24
|
+
|
|
25
|
+
@model_validator(mode="after")
|
|
26
|
+
def validate_gaussian_explosion_number(self) -> "FireworksOptimizationConfig":
|
|
27
|
+
if self.gaussian_explosion_number > self.population_size:
|
|
28
|
+
raise ValueError("\"gaussian_explosion_number\" must be less than or equal to population_size")
|
|
29
|
+
return self
|
|
30
|
+
|
|
31
|
+
@field_validator("a")
|
|
32
|
+
def correct_a(cls, v):
|
|
33
|
+
if not 0 < v < 1:
|
|
34
|
+
raise ValueError(f"\"a\" must be a positive float lower than 1. Got {v}")
|
|
35
|
+
return v
|
|
36
|
+
|
|
37
|
+
@field_validator("b")
|
|
38
|
+
def correct_b(cls, v):
|
|
39
|
+
if not 0 < v < 1:
|
|
40
|
+
raise ValueError(f"\"b\" must be a positive float lower than 1. Got {v}")
|
|
41
|
+
return v
|