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

gradient_free_optimizers.optimizers.core_optimizer.converter   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 112
dl 0
loc 167
rs 10
c 0
b 0
f 0
wmc 23

12 Methods

Rating   Name   Duplication   Size   Complexity  
A Converter.dataframe2memory_dict() 0 26 2
A Converter.para2value() 0 8 2
A Converter.memory_dict2positions_scores() 0 6 1
A Converter.value2position() 0 8 2
A Converter.positions2values() 0 12 2
A Converter.positions_scores2memory_dict() 0 8 1
A Converter.value2para() 0 7 2
A Converter.__init__() 0 24 2
A Converter.memory_dict2dataframe() 0 11 1
A Converter.returnNoneIfArgNone() 0 9 4
A Converter.values2positions() 0 16 2
A Converter.position2value() 0 8 2
1
# Author: Simon Blanke
2
# Email: [email protected]
3
# License: MIT License
4
5
import numpy as np
6
import pandas as pd
7
8
from functools import reduce
9
from typing import Optional
10
11
12
class Converter:
13
    def __init__(self, search_space: dict) -> None:
14
        self.n_dimensions = len(search_space)
15
        self.search_space = search_space
16
        self.para_names = list(search_space.keys())
17
18
        dim_sizes_list = [len(array) for array in search_space.values()]
19
        self.dim_sizes = np.array(dim_sizes_list)
20
21
        # product of list
22
        self.search_space_size = reduce((lambda x, y: x * y), dim_sizes_list)
23
        self.max_dim = np.amax(self.dim_sizes)
24
25
        self.search_space_positions = [
26
            list(range(len(array))) for array in search_space.values()
27
        ]
28
        self.pos_space = dict(
29
            zip(
30
                self.para_names,
31
                [np.arange(len(array)) for array in search_space.values()],
32
            )
33
        )
34
35
        self.max_positions = self.dim_sizes - 1
36
        self.search_space_values = list(search_space.values())
37
38
    def returnNoneIfArgNone(func_):
39
        def wrapper(self, *args):
40
            for arg in [*args]:
41
                if arg is None:
42
                    return None
43
            else:
44
                return func_(self, *args)
45
46
        return wrapper
47
48
    @returnNoneIfArgNone
49
    def position2value(self, position: Optional[list]) -> Optional[list]:
50
        value = []
51
52
        for n, space_dim in enumerate(self.search_space_values):
53
            value.append(space_dim[position[n]])
54
55
        return value
56
57
    @returnNoneIfArgNone
58
    def value2position(self, value: Optional[list]) -> Optional[list]:
59
        position = []
60
        for n, space_dim in enumerate(self.search_space_values):
61
            pos = np.abs(value[n] - np.array(space_dim)).argmin()
62
            position.append(int(pos))
63
64
        return np.array(position)
65
66
    @returnNoneIfArgNone
67
    def value2para(self, value: Optional[list]) -> Optional[dict]:
68
        para = {}
69
        for key, p_ in zip(self.para_names, value):
70
            para[key] = p_
71
72
        return para
73
74
    @returnNoneIfArgNone
75
    def para2value(self, para: Optional[dict]) -> Optional[list]:
76
77
        value = []
78
        for para_name in self.para_names:
79
            value.append(para[para_name])
80
81
        return value
82
83
    @returnNoneIfArgNone
84
    def values2positions(self, values: Optional[list]) -> Optional[list]:
85
        positions_temp = []
86
        values_np = np.array(values)
87
88
        for n, space_dim in enumerate(self.search_space_values):
89
            values_1d = values_np[:, n]
90
            # m_conv = np.abs(values_1d - space_dim[:, np.newaxis])
91
            # pos_list = m_conv.argmin(0)
92
            pos_list = space_dim.searchsorted(values_1d)
93
94
            positions_temp.append(pos_list)
95
96
        positions = list(np.array(positions_temp).T.astype(int))
97
98
        return positions
99
100
    @returnNoneIfArgNone
101
    def positions2values(self, positions: Optional[list]) -> Optional[list]:
102
        values = []
103
        positions_np = np.array(positions)
104
105
        for n, space_dim in enumerate(self.search_space_values):
106
            pos_1d = positions_np[:, n]
107
            value_ = np.take(space_dim, pos_1d, axis=0)
108
            values.append(value_)
109
110
        values = [list(t) for t in zip(*values)]
111
        return values
112
113
    @returnNoneIfArgNone
114
    def positions_scores2memory_dict(
115
        self, positions: Optional[list], scores: Optional[list]
116
    ) -> Optional[dict]:
117
        value_tuple_list = list(map(tuple, positions))
118
        memory_dict = dict(zip(value_tuple_list, scores))
119
120
        return memory_dict
121
122
    @returnNoneIfArgNone
123
    def memory_dict2positions_scores(self, memory_dict: Optional[dict]):
124
        positions = [np.array(pos).astype(int) for pos in list(memory_dict.keys())]
125
        scores = list(memory_dict.values())
126
127
        return positions, scores
128
129
    @returnNoneIfArgNone
130
    def dataframe2memory_dict(
131
        self, dataframe: Optional[pd.DataFrame]
132
    ) -> Optional[dict]:
133
        parameter = set(self.search_space.keys())
134
        memory_para = set(dataframe.columns)
135
136
        if parameter <= memory_para:
137
            values = list(dataframe[self.para_names].values)
138
            positions = self.values2positions(values)
139
            scores = dataframe["score"]
140
141
            memory_dict = self.positions_scores2memory_dict(positions, scores)
142
143
            return memory_dict
144
        else:
145
            missing = parameter - memory_para
146
147
            print(
148
                "\nWarning:",
149
                '"{}"'.format(*missing),
150
                "is in search_space but not in memory dataframe",
151
            )
152
            print("Optimization run will continue without memory warm start\n")
153
154
            return {}
155
156
    @returnNoneIfArgNone
157
    def memory_dict2dataframe(
158
        self, memory_dict: Optional[dict]
159
    ) -> Optional[pd.DataFrame]:
160
        positions, score = self.memory_dict2positions_scores(memory_dict)
161
        values = self.positions2values(positions)
162
163
        dataframe = pd.DataFrame(values, columns=self.para_names)
164
        dataframe["score"] = score
165
166
        return dataframe
167