Passed
Push — master ( 39ef7f...f70242 )
by Simon
01:57
created

EvolutionStrategyOptimizer._crossover()   A

Complexity

Conditions 3

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 12
rs 9.95
c 0
b 0
f 0
cc 3
nop 5
1
# Author: Simon Blanke
2
# Email: [email protected]
3
# License: MIT License
4
5
6
import numpy as np
7
import random
8
9
from .particle_swarm_optimization import ParticleSwarmOptimizer
10
from ...base_positioner import BasePositioner
11
12
13
class EvolutionStrategyOptimizer(ParticleSwarmOptimizer):
14
    def __init__(self, *args, **kwargs):
15
        super().__init__(*args, **kwargs)
16
        self.n_mutations = int(round(self._arg_.individuals * self._arg_.mutation_rate))
17
        self.n_crossovers = int(
18
            round(self._arg_.individuals * self._arg_.crossover_rate)
19
        )
20
21
    def _init_individuals(self, _cand_):
22
        _p_list_ = [Individual() for _ in range(self._arg_.individuals)]
23
        for _p_ in _p_list_:
24
            _p_.pos_current = _p_.move_random(_cand_)
25
            _p_.pos_best = _p_.pos_current
26
27
        return _p_list_
28
29
    def _mutate_individuals(self, _cand_, _p_list_, mutate_idx):
30
        _p_list_ = np.array(_p_list_)
31
        for _p_ in _p_list_[mutate_idx]:
32
            _p_.pos_new = _p_.move_climb(_cand_, _p_.pos_current)
33
34
    def _crossover(self, _cand_, _p_list_, cross_idx, replace_idx):
35
        _p_list_ = np.array(_p_list_)
36
        for i, _p_ in enumerate(_p_list_[replace_idx]):
37
            j = i + 1
38
            if j == len(cross_idx):
39
                j = 0
40
41
            pos_new = self._cross_two_ind(
42
                [_p_list_[cross_idx][i], _p_list_[cross_idx][j]]
43
            )
44
45
            _p_.pos_new = pos_new
46
47
    def _cross_two_ind(self, _p_list_):
48
        pos_new = []
49
50
        for pos1, pos2 in zip(_p_list_[0].pos_current, _p_list_[1].pos_current):
51
            rand = random.randint(0, 1)
52
            if rand == 0:
53
                pos_new.append(pos1)
54
            else:
55
                pos_new.append(pos2)
56
57
        return np.array(pos_new)
58
59
    def _move_positioners(self, _cand_, _p_list_):
60
        idx_sorted_ind = self._rank_individuals(_p_list_)
61
        mutate_idx, cross_idx, replace_idx = self._select_individuals(idx_sorted_ind)
62
63
        self._mutate_individuals(_cand_, _p_list_, mutate_idx)
64
        self._crossover(_cand_, _p_list_, cross_idx, replace_idx)
65
66
    def _rank_individuals(self, _p_list_):
67
        scores_list = []
68
        for _p_ in _p_list_:
69
            scores_list.append(_p_.score_current)
70
71
        scores_np = np.array(scores_list)
72
        idx_sorted_ind = list(scores_np.argsort()[::-1])
73
74
        return idx_sorted_ind
75
76
    def _select_individuals(self, index_best):
77
        mutate_idx = index_best[: self.n_mutations]
78
        cross_idx = index_best[: self.n_crossovers]
79
80
        n = self._arg_.individuals - max(self.n_mutations, self.n_crossovers)
81
        replace_idx = index_best[-n:]
82
83
        return mutate_idx, cross_idx, replace_idx
84
85
    # use _iterate from ParticleSwarmOptimizer
86
87
    def _init_opt_positioner(self, _cand_, X, y):
88
        _p_list_ = self._init_individuals(_cand_)
89
90
        for _p_ in _p_list_:
91
            _p_.score_current = _cand_.eval_pos(_p_.pos_current, X, y)
92
            _p_.score_best = _p_.score_current
93
94
        return _p_list_
95
96
97
class Individual(BasePositioner):
98
    def __init__(self, eps=1):
99
        super().__init__(eps)
100