Passed
Push — master ( f6b58e...07671f )
by Simon
01:34
created

gradient_free_optimizers.optimizers.population.evolution_strategy   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 68
dl 0
loc 101
rs 10
c 0
b 0
f 0
wmc 12

7 Methods

Rating   Name   Duplication   Size   Complexity  
A EvolutionStrategyOptimizer.__init__() 0 15 1
A EvolutionStrategyOptimizer._random_cross() 0 11 2
A EvolutionStrategyOptimizer._sort_best() 0 9 2
A EvolutionStrategyOptimizer.iterate() 0 18 3
A EvolutionStrategyOptimizer.evaluate() 0 2 1
A EvolutionStrategyOptimizer.init_pos() 0 6 1
A EvolutionStrategyOptimizer._cross() 0 20 2
1
# Author: Simon Blanke
2
# Email: [email protected]
3
# License: MIT License
4
5
import random
6
import numpy as np
7
8
from .base_population_optimizer import BasePopulationOptimizer
9
from ...search import Search
10
from ._individual import Individual
11
12
13
class EvolutionStrategyOptimizer(BasePopulationOptimizer, Search):
14
    def __init__(
15
        self,
16
        search_space,
17
        initialize={"grid": 4, "random": 2, "vertices": 4},
18
        mutation_rate=0.7,
19
        crossover_rate=0.3,
20
        rand_rest_p=0.05,
21
    ):
22
        super().__init__(search_space, initialize)
23
24
        self.mutation_rate = mutation_rate
25
        self.crossover_rate = crossover_rate
26
        self.rand_rest_p = rand_rest_p
27
28
        self.individuals = self.optimizers
29
30
    def _random_cross(self, array_list):
31
        n_arrays = len(array_list)
32
        size = array_list[0].size
33
34
        choice = [True, False]
35
        if size > 2:
36
            add_choice = np.random.randint(n_arrays, size=size - 2).astype(bool)
37
            choice += list(add_choice)
38
39
        cross_array = np.choose(choice, array_list)
40
        return cross_array
41
42
    def _sort_best(self):
43
        scores_list = []
44
        for ind in self.individuals:
45
            scores_list.append(ind.score_current)
46
47
        scores_np = np.array(scores_list)
48
        idx_sorted_ind = list(scores_np.argsort()[::-1])
49
50
        return [self.individuals[idx] for idx in idx_sorted_ind]
51
52
    def _cross(self):
53
        if len(self.individuals) > 2:
54
            rnd_int2 = random.choice(
55
                [i for i in range(0, self.n_ind - 1) if i not in [self.rnd_int]]
56
            )
57
        else:
58
            rnd_int2 = random.choice(
59
                [i for i in range(0, self.n_ind) if i not in [self.rnd_int]]
60
            )
61
62
        p_sec = self.ind_sorted[rnd_int2]
63
        p_worst = self.ind_sorted[-1]
64
65
        two_best_pos = [self.p_current.pos_current, p_sec.pos_current]
66
        pos_new = self._random_cross(two_best_pos)
67
68
        self.p_current = p_worst
69
        p_worst.pos_new = pos_new
70
71
        return pos_new
72
73
    def init_pos(self, pos):
74
        individual = Individual(self.conv.search_space, rand_rest_p=self.rand_rest_p)
75
        self.individuals.append(individual)
76
77
        self.p_current = individual
78
        self.p_current.init_pos(pos)
79
80
    def iterate(self):
81
        self.n_ind = len(self.individuals)
82
83
        if self.n_ind == 1:
84
            self.p_current = self.individuals[0]
85
            return self.p_current.iterate()
86
87
        self.ind_sorted = self._sort_best()
88
        self.rnd_int = random.randint(0, len(self.ind_sorted) - 1)
89
        self.p_current = self.ind_sorted[self.rnd_int]
90
91
        total_rate = self.mutation_rate + self.crossover_rate
92
        rand = np.random.uniform(low=0, high=total_rate)
93
94
        if rand <= self.mutation_rate:
95
            return self.p_current.iterate()
96
        else:
97
            return self._cross()
98
99
    def evaluate(self, score_new):
100
        self.p_current.evaluate(score_new)
101