Completed
Push — master ( a7eabf...ab1ae9 )
by Andrei
01:17
created

distance_metric.__call__()   A

Complexity

Conditions 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
"""!
2
3
@brief Module provides various distance metrics - abstraction of the notion of distance in a metric space.
4
5
@authors Andrei Novikov ([email protected])
6
@date 2014-2018
7
@copyright GNU Public License
8
9
@cond GNU_PUBLIC_LICENSE
10
    PyClustering is free software: you can redistribute it and/or modify
11
    it under the terms of the GNU General Public License as published by
12
    the Free Software Foundation, either version 3 of the License, or
13
    (at your option) any later version.
14
15
    PyClustering is distributed in the hope that it will be useful,
16
    but WITHOUT ANY WARRANTY; without even the implied warranty of
17
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
    GNU General Public License for more details.
19
20
    You should have received a copy of the GNU General Public License
21
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
@endcond
23
24
"""
25
26
27
from enum import IntEnum;
28
29
30
class type_metric(IntEnum):
31
    """!
32
    @brief Enumeration of supported metrics in the module for distance calculation between two points.
33
34
    """
35
36
    ## Euclidean distance, for more information see function 'euclidean_distance'.
37
    EUCLIDEAN = 0;
38
39
    ## Square Euclidean distance, for more information see function 'euclidean_distance_square'.
40
    EUCLIDEAN_SQUARE = 1;
41
42
    ## Manhattan distance, for more information see function 'manhattan_distance'.
43
    MANHATTAN = 2;
44
45
    ## Chebyshev distance, for more information see function 'chebyshev_distance'.
46
    CHEBYSHEV = 3;
47
48
    ## Minkowski distance, for more information see function 'minkowski_distance'.
49
    MINKOWSKI = 4;
50
51
    ## User defined function for distance calculation between two points.
52
    USER_DEFINED = 1000;
53
54
55
56
class distance_metric:
57
    """!
58
    @brief Distance metric performs distance calculation between two points in line with encapsulated function, for
59
            example, euclidean distance or chebyshev distance, or even user-defined.
60
61
    @details
62
63
    Example of Euclidean distance metric:
64
    @code
65
        metric = distance_metric(type_metric.EUCLIDEAN);
66
        distance = metric([1.0, 2.5], [-1.2, 3.4]);
67
    @endcode
68
69
    Example of Chebyshev distance metric:
70
    @code
71
        metric = distance_metric(type_metric.CHEBYSHEV);
72
        distance = metric([0.0, 0.0], [2.5, 6.0]);
73
    @endcode
74
75
    In following example additional argument should be specified (generally, 'degree' is a optional argument that is
76
     equal to '2' by default) that is specific for Minkowski distance:
77
    @code
78
        metric = distance_metric(type_metric.MINKOWSKI, degree=4);
79
        distance = metric([4.0, 9.2, 1.0], [3.4, 2.5, 6.2]);
80
    @endcode
81
82
    User may define its own function for distance calculation:
83
    @code
84
        user_function = lambda point1, point2: point1[0] + point2[0] + 2;
85
        metric = distance_metric(type_metric.USER_DEFINED, func=user_function);
86
        distance = metric([2.0, 3.0], [1.0, 3.0]);
87
    @endcode
88
89
    """
90
    def __init__(self, type, **kwargs):
91
        """!
92
        @brief Creates distance metric instance for calculation distance between two points.
93
94
        @param[in] type (type_metric):
95
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'func' and corresponding additional argument for
96
                    for specific metric types).
97
98
        <b>Keyword Args:</b><br>
99
            - func (callable): Callable object with two arguments (point #1 and point #2) that is used only if metric is 'type_metric.USER_DEFINED'.
100
            - degree (numeric): Only for 'type_metric.MINKOWSKI' - degree of Minkowski equation.
101
102
        """
103
        self.__type = type;
104
        self.__args = kwargs;
105
        self.__func = self.__args.get('func', None);
106
107
        self.__calculator = self.__create_distance_calculator();
108
109
110
    def __call__(self, point1, point2):
111
        """!
112
        @brief Calculates distance between two points.
113
114
        @param[in] point1 (list): The first point.
115
        @param[in] point2 (list): The second point.
116
117
        @return (double) Distance between two points.
118
119
        """
120
        return self.__calculator(point1, point2);
121
122
123
    def get_type(self):
124
        """!
125
        @brief Return type of distance metric that is used.
126
127
        @return (type_metric) Type of distance metric.
128
129
        """
130
        return self.__type;
131
132
133
    def get_arguments(self):
134
        """!
135
        @brief Return additional arguments that are used by distance metric.
136
137
        @return (dict) Additional arguments.
138
139
        """
140
        return self.__args;
141
142
143
    def get_function(self):
144
        """!
145
        @brief Return user-defined function for calculation distance metric.
146
147
        @return (callable): User-defined distance metric function.
148
149
        """
150
        return self.__func;
151
152
153
    def __create_distance_calculator(self):
154
        """!
155
        @brief Creates distance metric calculator.
156
157
        @return (callable) Callable object of distance metric calculator.
158
159
        """
160
        if self.__type == type_metric.EUCLIDEAN:
161
            return euclidean_distance;
162
163
        elif self.__type == type_metric.EUCLIDEAN_SQUARE:
164
            return euclidean_distance_square;
165
166
        elif self.__type == type_metric.MANHATTAN:
167
            return manhattan_distance;
168
169
        elif self.__type == type_metric.CHEBYSHEV:
170
            return chebyshev_distance;
171
172
        elif self.__type == type_metric.MINKOWSKI:
173
            return lambda point1, point2: minkowski_distance(point1, point2, self.__args.get('degree', 2));
174
175
        elif self.__type == type_metric.USER_DEFINED:
176
            return self.__func;
177
178
        else:
179
            raise ValueError("Unknown type of metric: '%d'", self.__type);
180
181
182
183
def euclidean_distance(point1, point2):
184
    """!
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \s was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
185
    @brief Calculate Euclidean distance between two vectors.
186
    @details The Euclidean between vectors (points) a and b is calculated by following formula:
187
188
    \f[
189
    dist(a, b) = \sqrt{ \sum_{i=0}^{N}(a_{i} - b_{i})^{2} };
190
    \f]
191
192
    Where N is a length of each vector.
193
194
    @param[in] point1 (list): The first vector.
195
    @param[in] point2 (list): The second vector.
196
197
    @return (double) Euclidean distance between two vectors.
198
199
    @see euclidean_distance_square, manhattan_distance, chebyshev_distance
200
201
    """
202
    distance = euclidean_distance_square(point1, point2);
203
    return distance ** 0.5;
204
205
206
def euclidean_distance_square(point1, point2):
207
    """!
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \s was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
208
    @brief Calculate square Euclidean distance between two vectors.
209
210
    \f[
211
    dist(a, b) = \sum_{i=0}^{N}(a_{i} - b_{i})^{2};
212
    \f]
213
214
    @param[in] point1 (list): The first vector.
215
    @param[in] point2 (list): The second vector.
216
217
    @return (double) Square Euclidean distance between two vectors.
218
219
    @see euclidean_distance, manhattan_distance, chebyshev_distance
220
221
    """
222
    distance = 0.0;
223
    for i in range(len(point1)):
224
        distance += (point1[i] - point2[i]) ** 2.0;
225
226
    return distance;
227
228
229
def manhattan_distance(point1, point2):
230
    """!
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \s was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
Bug introduced by
A suspicious escape sequence \l was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
231
    @brief Calculate Manhattan distance between between two vectors.
232
233
    \f[
234
    dist(a, b) = \sum_{i=0}^{N}\left | a_{i} - b_{i} \right |;
235
    \f]
236
237
    @param[in] point1 (list): The first vector.
238
    @param[in] point2 (list): The second vector.
239
240
    @return (double) Manhattan distance between two vectors.
241
242
    @see euclidean_distance_square, euclidean_distance, chebyshev_distance
243
244
    """
245
    distance = 0.0;
246
    dimension = len(point1);
247
248
    for i in range(dimension):
249
        distance += abs(point1[i] - point2[i]);
250
251
    return distance;
252
253
254
def chebyshev_distance(point1, point2):
255
    """!
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \m was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
Bug introduced by
A suspicious escape sequence \l was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
256
    @brief Calculate Chebyshev distance between between two vectors.
257
258
    \f[
259
    dist(a, b) = \max_{}i\left (\left | a_{i} - b_{i} \right |\right );
260
    \f]
261
262
    @param[in] point1 (list): The first vector.
263
    @param[in] point2 (list): The second vector.
264
265
    @return (double) Chebyshev distance between two vectors.
266
267
    @see euclidean_distance_square, euclidean_distance, minkowski_distance
268
269
    """
270
    distance = 0.0;
271
    dimension = len(point1);
272
273
    for i in range(dimension):
274
        distance = max(distance, abs(point1[i] - point2[i]));
275
276
    return distance;
277
278
279
def minkowski_distance(point1, point2, degree=2):
280
    """!
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \s was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
Bug introduced by
A suspicious escape sequence \l was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
281
    @brief Calculate Minkowski distance between two vectors.
282
283
    \f[
284
    dist(a, b) = \sqrt[p]{ \sum_{i=0}^{N}\left(a_{i} - b_{i}\right)^{p} };
285
    \f]
286
287
    @param[in] point1 (list): The first vector.
288
    @param[in] point2 (list): The second vector.
289
    @param[in] degree (numeric): Degree of that is used for Minkowski distance.
290
291
    @return (double) Minkowski distance between two vectors.
292
293
    @see euclidean_distance
294
295
    """
296
    distance = 0.0;
297
    for i in range(len(point1)):
298
        distance += (point1[i] - point2[i]) ** degree;
299
300
    return distance ** (1.0 / degree);