DownhillSimplexOptimizer.__init__()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 35
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 35
rs 9.184
c 0
b 0
f 0
cc 2
nop 11

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
# Author: Simon Blanke
2
# Email: [email protected]
3
# License: MIT License
4
5
6
import random
7
import numpy as np
8
9
from .hill_climbing_optimizer import HillClimbingOptimizer
10
11
12
def sort_list_idx(list_):
13
    list_np = np.array(list_)
14
    idx_sorted = list(list_np.argsort()[::-1])
15
    return idx_sorted
16
17
18 View Code Duplication
def centeroid(array_list):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
19
    centeroid = []
20
21
    for idx in range(array_list[0].shape[0]):
22
        center_dim_pos = []
23
        for array in array_list:
24
            center_dim_pos.append(array[idx])
25
26
        center_dim_mean = np.array(center_dim_pos).mean()
27
        centeroid.append(center_dim_mean)
28
29
    return centeroid
30
31
32
class DownhillSimplexOptimizer(HillClimbingOptimizer):
33
    name = "Downhill Simplex"
34
    _name_ = "downhill_simplex"
35
    __name__ = "DownhillSimplexOptimizer"
36
37
    optimizer_type = "local"
38
    computationally_expensive = False
39
40
    def __init__(
41
        self,
42
        search_space,
43
        initialize={"grid": 4, "random": 2, "vertices": 4},
44
        constraints=[],
45
        random_state=None,
46
        rand_rest_p=0,
47
        nth_process=None,
48
        alpha=1,
49
        gamma=2,
50
        beta=0.5,
51
        sigma=0.5,
52
    ):
53
        super().__init__(
54
            search_space=search_space,
55
            initialize=initialize,
56
            constraints=constraints,
57
            random_state=random_state,
58
            rand_rest_p=rand_rest_p,
59
            nth_process=nth_process,
60
        )
61
62
        self.alpha = alpha
63
        self.gamma = gamma
64
        self.beta = beta
65
        self.sigma = sigma
66
67
        self.n_simp_positions = len(self.conv.search_space) + 1
68
        self.simp_positions = []
69
70
        self.simplex_step = 0
71
72
        diff_init = self.n_simp_positions - self.init.n_inits
73
        if diff_init > 0:
74
            self.init.add_n_random_init_pos(diff_init)
75
76
    def finish_initialization(self):
77
        idx_sorted = sort_list_idx(self.scores_valid)
78
        self.simplex_pos = [self.positions_valid[idx] for idx in idx_sorted]
79
        self.simplex_scores = [self.scores_valid[idx] for idx in idx_sorted]
80
81
        self.simplex_step = 1
82
83
        self.i_x_0 = 0
84
        self.i_x_N_1 = -2
85
        self.i_x_N = -1
86
87
        self.search_state = "iter"
88
89
    @HillClimbingOptimizer.track_new_pos
90
    def iterate(self):
91
        simplex_stale = all(
92
            [
93
                np.array_equal(self.simplex_pos[0], array)
94
                for array in self.simplex_pos
95
            ]
96
        )
97
98
        if simplex_stale:
99
            idx_sorted = sort_list_idx(self.scores_valid)
100
            self.simplex_pos = [self.positions_valid[idx] for idx in idx_sorted]
101
            self.simplex_scores = [self.scores_valid[idx] for idx in idx_sorted]
102
103
            self.simplex_step = 1
104
105
        if self.simplex_step == 1:
106
            idx_sorted = sort_list_idx(self.simplex_scores)
107
            self.simplex_pos = [self.simplex_pos[idx] for idx in idx_sorted]
108
            self.simplex_scores = [
109
                self.simplex_scores[idx] for idx in idx_sorted
110
            ]
111
112
            self.center_array = centeroid(self.simplex_pos[:-1])
113
114
            r_pos = self.center_array + self.alpha * (
115
                self.center_array - self.simplex_pos[-1]
116
            )
117
            self.r_pos = self.conv2pos(r_pos)
118
            pos_new = self.r_pos
119
120
        elif self.simplex_step == 2:
121
            e_pos = self.center_array + self.gamma * (
122
                self.center_array - self.simplex_pos[-1]
123
            )
124
            self.e_pos = self.conv2pos(e_pos)
125
            self.simplex_step = 1
126
127
            pos_new = self.e_pos
128
129
        elif self.simplex_step == 3:
130
            # iter Contraction
131
            c_pos = self.h_pos + self.beta * (self.center_array - self.h_pos)
132
            c_pos = self.conv2pos(c_pos)
133
134
            pos_new = c_pos
135
136
        elif self.simplex_step == 4:
137
            # iter Shrink
138
            pos = self.simplex_pos[self.compress_idx]
139
            pos = pos + self.sigma * (self.simplex_pos[0] - pos)
140
141
            pos_new = self.conv2pos(pos)
142
143
        if self.conv.not_in_constraint(pos_new):
0 ignored issues
show
introduced by
The variable pos_new does not seem to be defined for all execution paths.
Loading history...
144
            return pos_new
145
146
        return self.move_climb(
147
            pos_new, epsilon=self.epsilon, distribution=self.distribution
148
        )
149
150
    @HillClimbingOptimizer.track_new_score
151
    def evaluate(self, score_new):
152
        if self.simplex_step != 0:
153
            self.prev_pos = self.positions_valid[-1]
154
155
        if self.simplex_step == 1:
156
            # self.r_pos = self.prev_pos
157
            self.r_score = score_new
158
159
            if self.r_score > self.simplex_scores[0]:
160
                self.simplex_step = 2
161
162
            elif self.r_score > self.simplex_scores[-2]:
163
                # if r is better than x N-1
164
                self.simplex_pos[-1] = self.r_pos
165
                self.simplex_scores[-1] = self.r_score
166
                self.simplex_step = 1
167
168
            if self.simplex_scores[-1] > self.r_score:
169
                self.h_pos = self.simplex_pos[-1]
170
                self.h_score = self.simplex_scores[-1]
171
            else:
172
                self.h_pos = self.r_pos
173
                self.h_score = self.r_score
174
175
            self.simplex_step = 3
176
177
        elif self.simplex_step == 2:
178
            self.e_score = score_new
179
180
            if self.e_score > self.r_score:
181
                self.simplex_scores[-1] = self.e_pos
182
            elif self.r_score > self.e_score:
183
                self.simplex_scores[-1] = self.r_pos
184
            else:
185
                self.simplex_scores[-1] = random.choice(
186
                    [self.e_pos, self.r_pos]
187
                )[0]
188
189
        elif self.simplex_step == 3:
190
            # eval Contraction
191
            self.c_pos = self.prev_pos
192
            self.c_score = score_new
193
194
            if self.c_score > self.simplex_scores[-1]:
195
                self.simplex_scores[-1] = self.c_score
196
                self.simplex_pos[-1] = self.c_pos
197
198
                self.simplex_step = 1
199
200
            else:
201
                # start Shrink
202
                self.simplex_step = 4
203
                self.compress_idx = 0
204
205
        elif self.simplex_step == 4:
206
            # eval Shrink
207
            self.simplex_scores[self.compress_idx] = score_new
208
            self.simplex_pos[self.compress_idx] = self.prev_pos
209
210
            self.compress_idx += 1
211
212
            if self.compress_idx == self.n_simp_positions:
213
                self.simplex_step = 1
214