DirectAlgorithm.select_subspace()   A
last analyzed

Complexity

Conditions 4

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nop 1
dl 0
loc 14
rs 9.9
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
from scipy.spatial.distance import cdist
8
9
from ..smb_opt.smbo import SMBO
10
from ..local_opt import HillClimbingOptimizer
11
12
13
class SubSpace:
14
    def __init__(self, search_space):
15
        self.search_space = search_space
16
17
        self.score = None
18
        self.center_pos = self.center_pos_()
19
        self.biggest_dim = self.biggest_dim_()
20
21
    def center_pos_(self):
22
        center_pos = []
23
24
        for dim in list(self.search_space.keys()):
25
            dim_array = self.search_space[dim]
26
            array_size = dim_array.shape[0]
27
            center_idx = int(array_size / 2)
28
29
            center_pos.append(dim_array[center_idx])
30
31
        return np.array(center_pos).astype(int)
32
33
    def biggest_dim_(self):
34
        largest_dim = None
35
        largest_size = 0
36
37
        for dim in list(self.search_space.keys()):
38
            dim_array = self.search_space[dim]
39
            array_size = dim_array.shape[0]
40
41
            if array_size == largest_size:
42
                if random.randint(0, 1):
43
                    largest_size = array_size
44
                    largest_dim = dim
45
46
            elif array_size > largest_size:
47
                largest_size = array_size
48
                largest_dim = dim
49
50
        return largest_dim
51
52
    def lipschitz_bound_(self, score, K=1):
53
        self.score = score
54
55
        furthest_pos_ = []
56
57
        for dim in list(self.search_space.keys()):
58
            dim_array = self.search_space[dim]
59
            furthest_pos_.append(dim_array[0])
60
        furthest_pos = np.array(furthest_pos_)
61
62
        dist = cdist(
63
            furthest_pos.reshape(1, -1), self.center_pos.reshape(1, -1)
64
        )
65
66
        self.lipschitz_bound = score + K * dist
67
68
69
class DirectAlgorithm(SMBO):
70
    name = "Direct Algorithm"
71
    _name_ = "direct_algorithm"
72
    __name__ = "DirectAlgorithm"
73
74
    optimizer_type = "sequential"
75
    computationally_expensive = True
76
77 View Code Duplication
    def __init__(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
78
        self,
79
        search_space,
80
        initialize={"grid": 4, "random": 2, "vertices": 4},
81
        constraints=[],
82
        random_state=None,
83
        rand_rest_p=0,
84
        nth_process=None,
85
        warm_start_smbo=None,
86
        max_sample_size=10000000,
87
        sampling={"random": 1000000},
88
        replacement=True,
89
    ):
90
        super().__init__(
91
            search_space=search_space,
92
            initialize=initialize,
93
            constraints=constraints,
94
            random_state=random_state,
95
            rand_rest_p=rand_rest_p,
96
            nth_process=nth_process,
97
            warm_start_smbo=warm_start_smbo,
98
            max_sample_size=max_sample_size,
99
            sampling=sampling,
100
            replacement=replacement,
101
        )
102
103
        self.subspace_l = []
104
105
    def select_next_subspace(self):
106
        for subspace in self.subspace_l:
107
            if subspace.score is None:
108
                return subspace
109
110
    def split_dim_into_n(self, subspace, n_splits=3):
111
        search_space = subspace.search_space
112
        dim_array = search_space[subspace.biggest_dim]
113
114
        sub_arrays = np.array_split(dim_array, n_splits)
115
116
        sub_search_space_l = []
117
        for sub_array in sub_arrays:
118
            sub_search_space_ = dict(search_space)
119
            sub_search_space_[subspace.biggest_dim] = sub_array
120
121
            sub_search_space_l.append(sub_search_space_)
122
123
        for search_space_ in sub_search_space_l:
124
            try:
125
                self.subspace_l.append(SubSpace(search_space_))
126
            except IndexError:
127
                pass
128
129
        self.subspace_l.remove(subspace)
130
131
    def select_subspace(self):
132
        lipschitz_bound_max = -np.inf
133
        next_subspace = None
134
135
        for subspace in self.subspace_l:
136
            if subspace.lipschitz_bound > lipschitz_bound_max:
137
                lipschitz_bound_max = subspace.lipschitz_bound
138
                next_subspace = subspace
139
140
        # if lipschitz_bound is nan or -inf
141
        if next_subspace is None:
142
            next_subspace = self.subspace_l[0]
143
144
        return next_subspace
145
146
    def finish_initialization(self):
147
        subspace = SubSpace(self.conv.pos_space)
148
        self.subspace_l.append(subspace)
149
        self.search_state = "iter"
150
151
    @SMBO.track_new_pos
152
    @SMBO.track_X_sample
153
    def iterate(self):
154
        while True:
155
            self.current_subspace = self.select_next_subspace()
156
            if self.current_subspace:
157
                pos = self.current_subspace.center_pos
158
                if self.conv.not_in_constraint(pos):
159
                    return pos
160
161
            else:
162
                self.current_subspace = self.select_subspace()
163
                self.split_dim_into_n(self.current_subspace)
164
165
                pos = self.subspace_l[-1].center_pos
166
                if self.conv.not_in_constraint(pos):
167
                    return pos
168
169
            return self.move_climb(pos, epsilon_mod=0.3)
170
171
    @SMBO.track_new_score
172
    def evaluate(self, score_new):
173
        if self.pos_best is None:
174
            self.pos_best = self.pos_new
175
            self.pos_current = self.pos_new
176
177
            self.score_best = score_new
178
            self.score_current = score_new
179
180
        if self.search_state == "iter":
181
            self.current_subspace.lipschitz_bound_(score_new)
182