Passed
Push — master ( accb4c...87b46e )
by Simon
01:44 queued 13s
created

Converter.values2paras()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
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
        value = []
77
        for para_name in self.para_names:
78
            value.append(para[para_name])
79
80
        return value
81
82
    @returnNoneIfArgNone
83
    def values2positions(self, values: Optional[list]) -> Optional[list]:
84
        positions_temp = []
85
        values_np = np.array(values)
86
87
        for n, space_dim in enumerate(self.search_space_values):
88
            values_1d = values_np[:, n]
89
            # m_conv = np.abs(values_1d - space_dim[:, np.newaxis])
90
            # pos_list = m_conv.argmin(0)
91
            pos_list = space_dim.searchsorted(values_1d)
92
93
            positions_temp.append(pos_list)
94
95
        positions = list(np.array(positions_temp).T.astype(int))
96
97
        return positions
98
99
    @returnNoneIfArgNone
100
    def positions2values(self, positions: Optional[list]) -> Optional[list]:
101
        values = []
102
        positions_np = np.array(positions)
103
104
        for n, space_dim in enumerate(self.search_space_values):
105
            pos_1d = positions_np[:, n]
106
            value_ = np.take(space_dim, pos_1d, axis=0)
107
            values.append(value_)
108
109
        values = [list(t) for t in zip(*values)]
110
        return values
111
112
    @returnNoneIfArgNone
113
    def values2paras(self, values: list) -> list:
114
        paras = []
115
        for value in values:
116
            paras.append(self.value2para(value))
117
        return paras
118
119
    @returnNoneIfArgNone
120
    def positions_scores2memory_dict(
121
        self, positions: Optional[list], scores: Optional[list]
122
    ) -> Optional[dict]:
123
        value_tuple_list = list(map(tuple, positions))
124
        memory_dict = dict(zip(value_tuple_list, scores))
125
126
        return memory_dict
127
128
    @returnNoneIfArgNone
129
    def memory_dict2positions_scores(self, memory_dict: Optional[dict]):
130
        positions = [np.array(pos).astype(int) for pos in list(memory_dict.keys())]
131
        scores = list(memory_dict.values())
132
133
        return positions, scores
134
135
    @returnNoneIfArgNone
136
    def dataframe2memory_dict(
137
        self, dataframe: Optional[pd.DataFrame]
138
    ) -> Optional[dict]:
139
        parameter = set(self.search_space.keys())
140
        memory_para = set(dataframe.columns)
141
142
        if parameter <= memory_para:
143
            values = list(dataframe[self.para_names].values)
144
            positions = self.values2positions(values)
145
            scores = dataframe["score"]
146
147
            memory_dict = self.positions_scores2memory_dict(positions, scores)
148
149
            return memory_dict
150
        else:
151
            missing = parameter - memory_para
152
153
            print(
154
                "\nWarning:",
155
                '"{}"'.format(*missing),
156
                "is in search_space but not in memory dataframe",
157
            )
158
            print("Optimization run will continue without memory warm start\n")
159
160
            return {}
161
162
    @returnNoneIfArgNone
163
    def memory_dict2dataframe(
164
        self, memory_dict: Optional[dict]
165
    ) -> Optional[pd.DataFrame]:
166
        positions, score = self.memory_dict2positions_scores(memory_dict)
167
        values = self.positions2values(positions)
168
169
        dataframe = pd.DataFrame(values, columns=self.para_names)
170
        dataframe["score"] = score
171
172
        return dataframe
173