Passed
Push — master ( 047469...b66fc0 )
by Simon
04:21 queued 12s
created

gradient_free_optimizers.optimizers.global_opt.direct_algorithm   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 145
rs 10
c 0
b 0
f 0
wmc 28

11 Methods

Rating   Name   Duplication   Size   Complexity  
A DirectAlgorithm.__init__() 0 3 1
A DirectAlgorithm.select_next_subspace() 0 4 3
A SubSpace.__init__() 0 6 1
A SubSpace.center_pos_() 0 11 2
A DirectAlgorithm.split_dim_into_n() 0 20 4
A DirectAlgorithm.select_subspace() 0 14 4
A SubSpace.lipschitz_bound_() 0 13 2
A DirectAlgorithm.evaluate() 0 11 3
A DirectAlgorithm.iterate() 0 12 2
A DirectAlgorithm.finish_initialization() 0 4 1
A SubSpace.biggest_dim_() 0 18 5
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 ...search import Search
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(furthest_pos.reshape(1, -1), self.center_pos.reshape(1, -1))
63
64
        self.lipschitz_bound = score + K * dist
65
66
67
class DirectAlgorithm(SMBO, Search):
68
    name = "Direct Algorithm"
69
    _name_ = "direct_algorithm"
70
71
    def __init__(self, *args, **kwargs):
72
        super().__init__(*args, **kwargs)
73
        self.subspace_l = []
74
75
    def select_next_subspace(self):
76
        for subspace in self.subspace_l:
77
            if subspace.score is None:
78
                return subspace
79
80
    def split_dim_into_n(self, subspace, n_splits=3):
81
        search_space = subspace.search_space
82
        dim_array = search_space[subspace.biggest_dim]
83
84
        sub_arrays = np.array_split(dim_array, n_splits)
85
86
        sub_search_space_l = []
87
        for sub_array in sub_arrays:
88
            sub_search_space_ = dict(search_space)
89
            sub_search_space_[subspace.biggest_dim] = sub_array
90
91
            sub_search_space_l.append(sub_search_space_)
92
93
        for search_space_ in sub_search_space_l:
94
            try:
95
                self.subspace_l.append(SubSpace(search_space_))
96
            except IndexError:
97
                pass
98
99
        self.subspace_l.remove(subspace)
100
101
    def select_subspace(self):
102
        lipschitz_bound_max = -np.inf
103
        next_subspace = None
104
105
        for subspace in self.subspace_l:
106
            if subspace.lipschitz_bound > lipschitz_bound_max:
107
                lipschitz_bound_max = subspace.lipschitz_bound
108
                next_subspace = subspace
109
110
        # if lipschitz_bound is nan or -inf
111
        if next_subspace is None:
112
            next_subspace = self.subspace_l[0]
113
114
        return next_subspace
115
116
    def finish_initialization(self):
117
        subspace = SubSpace(self.conv.pos_space)
118
        self.subspace_l.append(subspace)
119
        self.search_state = "iter"
120
121
    @SMBO.track_new_pos
122
    @SMBO.track_X_sample
123
    def iterate(self):
124
        self.current_subspace = self.select_next_subspace()
125
        if self.current_subspace:
126
            return self.current_subspace.center_pos
127
128
        else:
129
            self.current_subspace = self.select_subspace()
130
            self.split_dim_into_n(self.current_subspace)
131
132
            return self.subspace_l[-1].center_pos
133
134
    @SMBO.track_new_score
135
    def evaluate(self, score_new):
136
        if self.pos_best is None:
137
            self.pos_best = self.pos_new
138
            self.pos_current = self.pos_new
139
140
            self.score_best = score_new
141
            self.score_current = score_new
142
143
        if self.search_state == "iter":
144
            self.current_subspace.lipschitz_bound_(score_new)
145