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

EvolutionStrategyOptimizer.iterate()   A

Complexity

Conditions 3

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nop 1
dl 0
loc 18
rs 9.75
c 0
b 0
f 0
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