Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
77.46% |
55 / 71 |
|
88.89% |
8 / 9 |
CRAP | |
0.00% |
0 / 1 |
MetricsND | |
77.46% |
55 / 71 |
|
88.89% |
8 / 9 |
45.46 | |
0.00% |
0 / 1 |
__construct | n/a |
0 / 0 |
n/a |
0 / 0 |
1 | |||||
manhattan | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
euclidean | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
cosine | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
56 | |||
chebyshev | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
minkowski | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
canberra | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
brayCurtis | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
angularSeparation | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
3 | |||
hamming | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Math\Topology |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Math\Topology; |
16 | |
17 | use phpOMS\Math\Matrix\Exception\InvalidDimensionException; |
18 | |
19 | /** |
20 | * Metrics. |
21 | * |
22 | * @package phpOMS\Math\Topology |
23 | * @license OMS License 2.0 |
24 | * @link https://jingga.app |
25 | * @since 1.0.0 |
26 | */ |
27 | final class MetricsND |
28 | { |
29 | /** |
30 | * Constructor |
31 | * |
32 | * @since 1.0.0 |
33 | * @codeCoverageIgnore |
34 | */ |
35 | private function __construct() |
36 | { |
37 | } |
38 | |
39 | /** |
40 | * Manhatten metric. |
41 | * |
42 | * @latex d(p, q) = \sum_{n=1}^N{|p_i - q_i|} |
43 | * |
44 | * @param array<int|string, int|float> $a n-D array |
45 | * @param array<int|string, int|float> $b n-D array |
46 | * |
47 | * @return float |
48 | * |
49 | * @throws InvalidDimensionException |
50 | * |
51 | * @since 1.0.0 |
52 | */ |
53 | public static function manhattan(array $a, array $b) : float |
54 | { |
55 | if (\count($a) !== \count($b)) { |
56 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
57 | } |
58 | |
59 | $dist = 0.0; |
60 | foreach ($a as $key => $e) { |
61 | $dist += \abs($e - $b[$key]); |
62 | } |
63 | |
64 | return $dist; |
65 | } |
66 | |
67 | /** |
68 | * Euclidean metric. |
69 | * |
70 | * @latex d(p, q) = \sqrt{\sum_{n=1}^N{(p_i - q_i)^2}} |
71 | * |
72 | * @param array<int|string, int|float> $a n-D array |
73 | * @param array<int|string, int|float> $b n-D array |
74 | * |
75 | * @return float |
76 | * |
77 | * @throws InvalidDimensionException |
78 | * |
79 | * @since 1.0.0 |
80 | */ |
81 | public static function euclidean(array $a, array $b) : float |
82 | { |
83 | if (\count($a) !== \count($b)) { |
84 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
85 | } |
86 | |
87 | $dist = 0.0; |
88 | foreach ($a as $key => $e) { |
89 | $dist += \abs($e - $b[$key]) ** 2; |
90 | } |
91 | |
92 | return \sqrt($dist); |
93 | } |
94 | |
95 | /** |
96 | * Cosine metric. |
97 | * |
98 | * @param array<int|string, int|float> $a n-D array |
99 | * @param array<int|string, int|float> $b n-D array |
100 | * |
101 | * @return float |
102 | * |
103 | * @throws InvalidDimensionException |
104 | * |
105 | * @since 1.0.0 |
106 | */ |
107 | public static function cosine(array $a, array $b) : float |
108 | { |
109 | if (($length = \count($a)) !== \count($b)) { |
110 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
111 | } |
112 | |
113 | $dotProduct = 0; |
114 | for ($i = 0; $i < $length; ++$i) { |
115 | $dotProduct += $a[$i] * $b[$i]; |
116 | } |
117 | |
118 | $sumOfSquares = 0; |
119 | foreach ($a as $value) { |
120 | $sumOfSquares += $value * $value; |
121 | } |
122 | $magnitude1 = \sqrt($sumOfSquares); |
123 | |
124 | $sumOfSquares = 0; |
125 | foreach ($b as $value) { |
126 | $sumOfSquares += $value * $value; |
127 | } |
128 | $magnitude2 = \sqrt($sumOfSquares); |
129 | |
130 | if ($magnitude1 == 0 || $magnitude2 == 0) { |
131 | return \PHP_FLOAT_MAX; |
132 | } |
133 | |
134 | return $dotProduct / ($magnitude1 * $magnitude2); |
135 | } |
136 | |
137 | /** |
138 | * Chebyshev metric. |
139 | * |
140 | * @latex d(p, q) = \max_i{(|p_i - q_i|)} |
141 | * |
142 | * @param array<int|string, int|float> $a n-D array |
143 | * @param array<int|string, int|float> $b n-D array |
144 | * |
145 | * @return float |
146 | * |
147 | * @throws InvalidDimensionException |
148 | * |
149 | * @since 1.0.0 |
150 | */ |
151 | public static function chebyshev(array $a, array $b) : float |
152 | { |
153 | if (\count($a) !== \count($b)) { |
154 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
155 | } |
156 | |
157 | $dist = []; |
158 | foreach ($a as $key => $e) { |
159 | $dist[] = \abs($e - $b[$key]); |
160 | } |
161 | |
162 | return (float) \max($dist); |
163 | } |
164 | |
165 | /** |
166 | * Minkowski metric. |
167 | * |
168 | * @latex d(p, q) = \sqrt[\lambda]{\sum_{n=1}^N{|p_i - q_i|^\lambda}} |
169 | * |
170 | * @param array<int|string, int|float> $a n-D array |
171 | * @param array<int|string, int|float> $b n-D array |
172 | * @param int $lambda Lambda |
173 | * |
174 | * @return float |
175 | * |
176 | * @throws InvalidDimensionException |
177 | * |
178 | * @since 1.0.0 |
179 | */ |
180 | public static function minkowski(array $a, array $b, int $lambda) : float |
181 | { |
182 | if (\count($a) !== \count($b)) { |
183 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
184 | } |
185 | |
186 | $dist = 0.0; |
187 | foreach ($a as $key => $e) { |
188 | $dist += \pow(\abs($e - $b[$key]), $lambda); |
189 | } |
190 | |
191 | return \pow($dist, 1 / $lambda); |
192 | } |
193 | |
194 | /** |
195 | * Canberra metric. |
196 | * |
197 | * @latex d(p, q) = \sum_{n=1}^N{\frac{|p_i - q_i|}{|p_i| + |q_i|} |
198 | * |
199 | * @param array<int|string, int|float> $a n-D array |
200 | * @param array<int|string, int|float> $b n-D array |
201 | * |
202 | * @return float |
203 | * |
204 | * @throws InvalidDimensionException |
205 | * |
206 | * @since 1.0.0 |
207 | */ |
208 | public static function canberra(array $a, array $b) : float |
209 | { |
210 | if (\count($a) !== \count($b)) { |
211 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
212 | } |
213 | |
214 | $dist = 0.0; |
215 | foreach ($a as $key => $e) { |
216 | $dist += \abs($e - $b[$key]) / (\abs($e) + \abs($b[$key])); |
217 | } |
218 | |
219 | return $dist; |
220 | } |
221 | |
222 | /** |
223 | * Bray Curtis metric. |
224 | * |
225 | * @latex d(p, q) = \frac{\sum_{n=1}^N{|p_i - q_i|}}{\sum_{n=1}^N{(p_i + q_i)}} |
226 | * |
227 | * @param array<int|string, int|float> $a n-D array |
228 | * @param array<int|string, int|float> $b n-D array |
229 | * |
230 | * @return float |
231 | * |
232 | * @throws InvalidDimensionException |
233 | * |
234 | * @since 1.0.0 |
235 | */ |
236 | public static function brayCurtis(array $a, array $b) : float |
237 | { |
238 | if (\count($a) !== \count($b)) { |
239 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
240 | } |
241 | |
242 | $distTop = 0.0; |
243 | $distBottom = 0.0; |
244 | foreach ($a as $key => $e) { |
245 | $distTop += \abs($e - $b[$key]); |
246 | $distBottom += $e + $b[$key]; |
247 | } |
248 | |
249 | return $distTop / $distBottom; |
250 | } |
251 | |
252 | /** |
253 | * Angular separation metric. |
254 | * |
255 | * @latex d(p, q) = \frac{\sum_{n=1}^N{p_i * q_i}}{\left(\sum_{n=1}^N{p_i^2} * \sum_{n=1}^N{q_i^2}\right)^\frac{1}{2}} |
256 | * |
257 | * @param array<int|string, int|float> $a n-D array |
258 | * @param array<int|string, int|float> $b n-D array |
259 | * |
260 | * @return float |
261 | * |
262 | * @throws InvalidDimensionException |
263 | * |
264 | * @since 1.0.0 |
265 | */ |
266 | public static function angularSeparation(array $a, array $b) : float |
267 | { |
268 | if (\count($a) !== \count($b)) { |
269 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
270 | } |
271 | |
272 | $distTop = 0.0; |
273 | $distBottomA = 0.0; |
274 | $distBottomB = 0.0; |
275 | foreach ($a as $key => $e) { |
276 | $distTop += $e * $b[$key]; |
277 | $distBottomA += $e ** 2; |
278 | $distBottomB += $b[$key] ** 2; |
279 | } |
280 | |
281 | return $distTop / \pow($distBottomA * $distBottomB, 1 / 2); |
282 | } |
283 | |
284 | /** |
285 | * Hamming metric. |
286 | * |
287 | * @latex d(p, q) = \sum_{n=1}^N{|p_i - q_i|} |
288 | * |
289 | * @param array<int|string, int|float> $a n-D array |
290 | * @param array<int|string, int|float> $b n-D array |
291 | * |
292 | * @return int |
293 | * |
294 | * @throws InvalidDimensionException |
295 | * |
296 | * @since 1.0.0 |
297 | */ |
298 | public static function hamming(array $a, array $b) : int |
299 | { |
300 | if (($size = \count($a)) !== \count($b)) { |
301 | throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); |
302 | } |
303 | |
304 | $dist = 0; |
305 | for ($i = 0; $i < $size; ++$i) { |
306 | if ($a[$i] !== $b[$i]) { |
307 | ++$dist; |
308 | } |
309 | } |
310 | |
311 | return $dist; |
312 | } |
313 | } |