Coverage for src/km3pipe/tests/test_math.py: 100%
346 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 03:14 +0000
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 03:14 +0000
1# Filename: test_math.py
2# pylint: disable=locally-disabled,C0111,R0904,C0103
4import numpy as np
5from numpy.testing import assert_almost_equal, assert_allclose
6import pytest
8from km3pipe.testing import TestCase
9from km3pipe import Table
10from km3pipe.math import (
11 angle,
12 angle_between,
13 magnitude,
14 dist,
15 pld3,
16 com,
17 zenith,
18 azimuth,
19 Polygon,
20 IrregularPrism,
21 rotation_matrix,
22 spherecutmask,
23 spherecut,
24 SparseCone,
25 space_angle,
26 hsin,
27 phi,
28 theta,
29 unit_vector,
30 log_b,
31 qeuler,
32 qrot,
33 qrot_yaw,
34 intersect_3d,
35)
37__author__ = ["Tamas Gal", "Moritz Lotze"]
38__copyright__ = "Copyright 2016, KM3Pipe devs and the KM3NeT collaboration."
39__credits__ = ["Thomas Heid"]
40__license__ = "MIT"
41__maintainer__ = ["Tamas Gal", "Moritz Lotze"]
42__email__ = "tgal@km3net.de"
43__status__ = "Development"
46class TestMath(TestCase):
47 def setUp(self):
48 # self.vecs = np.array([[0., 1., 5.],
49 # [1., 1., 4.],
50 # [2., 1., 3.],
51 # [3., 1., 2.],
52 # [4., 1., 1.]])
53 # self.v = (1, 2, 3)
54 self.v = np.array([0.26726124, 0.53452248, 0.80178373])
55 self.vecs = np.array(
56 [
57 [0.0, 0.19611614, 0.98058068],
58 [0.23570226, 0.23570226, 0.94280904],
59 [0.53452248, 0.26726124, 0.80178373],
60 [0.80178373, 0.26726124, 0.53452248],
61 [0.94280904, 0.23570226, 0.23570226],
62 ]
63 )
65 def test_phi(self):
66 print(phi((1, 0, 0)))
67 assert_almost_equal(0, phi((1, 0, 0)))
68 assert_almost_equal(np.pi, phi((-1, 0, 0)))
69 assert_almost_equal(np.pi / 2, phi((0, 1, 0)))
70 assert_almost_equal(np.pi / 2 * 3, phi((0, -1, 0)))
71 assert_almost_equal(np.pi / 2 * 3, phi((0, -1, 0)))
72 assert_almost_equal(0, phi((0, 0, 0)))
73 assert_almost_equal(phi(self.v), 1.10714872)
74 assert_almost_equal(
75 phi(self.vecs),
76 np.array([1.57079633, 0.78539816, 0.46364761, 0.32175055, 0.24497866]),
77 )
79 def test_zenith(self):
80 assert_allclose(np.pi, zenith((0, 0, 1)))
81 assert_allclose(0, zenith((0, 0, -1)))
82 assert_allclose(np.pi / 2, zenith((0, 1, 0)))
83 assert_allclose(np.pi / 2, zenith((0, -1, 0)))
84 assert_allclose(np.pi / 4 * 3, zenith((0, 1, 1)))
85 assert_allclose(np.pi / 4 * 3, zenith((0, -1, 1)))
86 assert_almost_equal(zenith(self.v), 2.5010703409103687)
87 assert_allclose(
88 zenith(self.vecs),
89 np.array([2.94419709, 2.80175574, 2.50107034, 2.13473897, 1.80873745]),
90 )
92 def test_azimuth(self):
93 self.assertTrue(np.allclose(np.pi, azimuth((1, 0, 0))))
94 self.assertTrue(np.allclose(0, azimuth((-1, 0, 0))))
96 print(azimuth((0, 1, 0)))
97 print(azimuth((0, -1, 0)))
98 print(azimuth((0, 0, 0)))
99 print(azimuth(self.v))
100 print(azimuth(self.vecs))
101 self.assertTrue(np.allclose(np.pi / 2 * 3, azimuth((0, 1, 0))))
102 self.assertTrue(np.allclose(np.pi / 2, azimuth((0, -1, 0))))
103 self.assertTrue(np.allclose(np.pi, azimuth((0, 0, 0))))
104 self.assertTrue(np.allclose(azimuth(self.v), 4.24874137138))
105 self.assertTrue(
106 np.allclose(
107 azimuth(self.vecs),
108 np.array([4.71238898, 3.92699082, 3.60524026, 3.46334321, 3.38657132]),
109 )
110 )
112 def test_theta(self):
113 print(theta((0, 0, -1)))
114 print(theta((0, 0, 1)))
115 print(theta((0, 1, 0)))
116 print(theta((0, -1, 0)))
117 print(theta((0, 1, 1)))
118 print(theta((0, -1, 1)))
119 print(theta(self.v))
120 print(theta(self.vecs))
121 self.assertTrue(np.allclose(0, theta((0, 0, 1))))
122 self.assertTrue(np.allclose(np.pi, theta((0, 0, -1))))
123 self.assertTrue(np.allclose(np.pi / 2, theta((0, 1, 0))))
124 self.assertTrue(np.allclose(np.pi / 2, theta((0, -1, 0))))
125 self.assertTrue(np.allclose(0, theta((0, 1, 1))))
126 self.assertTrue(np.allclose(0, theta((0, -1, 1))))
127 self.assertTrue(np.allclose(theta(self.v), 0.64052231))
128 self.assertTrue(
129 np.allclose(
130 theta(self.vecs),
131 np.array([0.19739554, 0.33983691, 0.64052231, 1.00685369, 1.3328552]),
132 )
133 )
135 def test_unit_vector(self):
136 v1 = (1, 0, 0)
137 v2 = (1, 1, 0)
138 v3 = (-1, 2, 0)
139 assert np.allclose(v1, unit_vector(v1))
140 assert np.allclose(np.array(v2) / np.sqrt(2), unit_vector(v2))
141 assert np.allclose(np.array(v3) / np.sqrt(5), unit_vector(v3))
143 def test_magnitude(self):
144 assert 1 == magnitude(np.array([1, 0, 0]))
145 assert 2 == magnitude(np.array([0, 2, 0]))
146 assert 3 == magnitude(np.array([0, 0, 3]))
147 assert np.allclose(
148 [3.74165739, 8.77496439, 13.92838828],
149 magnitude(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])),
150 )
152 def test_angle(self):
153 v1 = np.array([1, 0, 0])
154 v2 = np.array([0, 1, 0])
155 v3 = np.array([-1, 0, 0])
156 self.assertAlmostEqual(0, angle(v1, v1))
157 self.assertAlmostEqual(np.pi / 2, angle(v1, v2))
158 self.assertAlmostEqual(np.pi, angle(v1, v3))
159 self.assertAlmostEqual(angle(self.v, v1), 1.3002465638163236)
160 self.assertAlmostEqual(angle(self.v, v2), 1.0068536854342678)
161 self.assertAlmostEqual(angle(self.v, v3), 1.8413460897734695)
163 assert np.allclose(
164 [1.300246563816323, 1.0068536854342678, 1.8413460897734695],
165 angle(np.array([self.v, self.v, self.v]), np.array([v1, v2, v3])),
166 )
168 def test_angle_between(self):
169 v1 = (1, 0, 0)
170 v2 = (0, 1, 0)
171 v3 = (-1, 0, 0)
172 self.assertAlmostEqual(0, angle_between(v1, v1))
173 self.assertAlmostEqual(np.pi / 2, angle_between(v1, v2))
174 self.assertAlmostEqual(np.pi, angle_between(v1, v3))
175 self.assertAlmostEqual(angle_between(self.v, v1), 1.3002465638163236)
176 self.assertAlmostEqual(angle_between(self.v, v2), 1.0068536854342678)
177 self.assertAlmostEqual(angle_between(self.v, v3), 1.8413460897734695)
179 assert np.allclose(
180 [0.0, 0.0, 0.0]
181 - angle_between(np.array([v1, v2, v3]), np.array([v1, v2, v3]), axis=1),
182 0,
183 )
184 assert np.allclose(
185 [np.pi / 2, np.pi]
186 - angle_between(np.array([v1, v1]), np.array([v2, v3]), axis=1),
187 0,
188 )
190 self.assertTrue(
191 np.allclose(
192 angle_between(self.vecs, v1),
193 np.array([1.57079633, 1.3328552, 1.0068537, 0.64052231, 0.33983691]),
194 )
195 )
196 self.assertTrue(
197 np.allclose(
198 angle_between(self.vecs, v2),
199 np.array([1.37340077, 1.3328552, 1.3002466, 1.30024656, 1.3328552]),
200 )
201 )
202 self.assertTrue(
203 np.allclose(
204 angle_between(self.vecs, v3),
205 np.array([1.57079633, 1.80873745, 2.13473897, 2.50107034, 2.80175574]),
206 )
207 )
209 def test_angle_between_returns_nan_for_zero_length_vectors(self):
210 v1 = (0, 0, 0)
211 v2 = (1, 0, 0)
212 with pytest.warns(RuntimeWarning):
213 self.assertTrue(np.isnan(angle_between(v1, v2)))
215 def test_space_angle(self):
216 p1 = (np.pi / 2, np.pi)
217 p2 = (np.pi, 0)
218 self.assertAlmostEqual(
219 space_angle(p1[0], p2[0], p1[1], p2[1]), 1.57079632679489
220 )
221 p3 = (0, np.pi)
222 p4 = (np.pi / 2, 0)
223 self.assertAlmostEqual(
224 space_angle(p3[0], p4[0], p3[1], p4[1]), 1.57079632679489
225 )
227 def test_hsin(self):
228 assert np.all(hsin((np.pi, 0)) == (1, 0))
229 self.assertAlmostEqual(hsin(np.pi / 2), 0.5)
231 def test_pld3(self):
232 p1 = np.array((0, 0, 0))
233 p2 = np.array((0, 0, 1))
234 d2 = np.array((0, 1, 0))
235 self.assertAlmostEqual(1, pld3(p1, p2, d2))
236 p1 = np.array((0, 0, 0))
237 p2 = np.array((0, 0, 2))
238 d2 = np.array((0, 1, 0))
239 self.assertAlmostEqual(2, pld3(p1, p2, d2))
240 p1 = np.array((0, 0, 0))
241 p2 = np.array((0, 0, 0))
242 d2 = np.array((0, 1, 0))
243 self.assertAlmostEqual(0, pld3(p1, p2, d2))
244 p1 = np.array((1, 2, 3))
245 p2 = np.array((4, 5, 6))
246 d2 = np.array((7, 8, 9))
247 self.assertAlmostEqual(0.5275893, pld3(p1, p2, d2))
248 p1 = np.array((0, 0, 2))
249 p2 = np.array((-100, 0, -100))
250 d2 = np.array((1, 0, 1))
251 self.assertAlmostEqual(1.4142136, pld3(p1, p2, d2))
252 p1 = np.array([183.0, -311.0, 351.96083871])
253 p2 = np.array([40.256, -639.888, 921.93])
254 d2 = np.array([0.185998, 0.476123, -0.859483])
255 self.assertAlmostEqual(21.25456308, pld3(p1, p2, d2))
257 def test_com(self):
258 center_of_mass = com(((1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)))
259 self.assertEqual((5.5, 6.5, 7.5), tuple(center_of_mass))
260 center_of_mass = com(((1, 2, 3), (4, 5, 6), (7, 8, 9)), masses=(1, 0, 0))
261 self.assertEqual((1, 2, 3), tuple(center_of_mass))
262 center_of_mass = com(((1, 1, 1), (0, 0, 0)))
263 self.assertEqual((0.5, 0.5, 0.5), tuple(center_of_mass))
266class TestShapes(TestCase):
267 def setUp(self):
268 self.poly = [
269 (-60, 120),
270 (80, 120),
271 (110, 60),
272 (110, -30),
273 (70, -110),
274 (-70, -110),
275 (-90, -70),
276 (-90, 60),
277 ]
279 def test_poly_containment(self):
280 polygon = Polygon(self.poly)
281 point_in = (-40, -40)
282 point_out = (-140, -140)
283 points = [
284 (-40, -40),
285 (-140, -140),
286 (40, -140),
287 ]
288 assert np.all(polygon.contains(point_in))
289 assert not np.any(polygon.contains(point_out))
290 assert np.all(polygon.contains(points) == [True, False, False])
292 def test_poly_xy(self):
293 polygon = Polygon(self.poly)
294 x = (-40, -140, 40)
295 y = (-40, -140, -140)
296 assert np.all(polygon.contains_xy(x, y) == [True, False, False])
298 def test_prism_contained(self):
299 z = (-90, 90)
300 prism = IrregularPrism(self.poly, z[0], z[1])
301 points = [
302 (0, 1, 2),
303 (-100, 20, 10),
304 (10, 90, 10),
305 ]
306 assert np.all(prism.contains(points) == [True, False, True])
308 def test_prism_contained_xyz(self):
309 z = (-90, 90)
310 prism = IrregularPrism(self.poly, z[0], z[1])
311 x = (0, -100, 10)
312 y = (1, 20, 90)
313 z = (2, 10, 10)
314 assert np.all(prism.contains_xyz(x, y, z) == [True, False, True])
317class TestRotation(TestCase):
318 def test_rotmat(self):
319 v = [3, 5, 0]
320 axis = [4, 4, 1]
321 theta = 1.2
322 newvec = np.dot(rotation_matrix(axis, theta), v)
323 self.assertTrue(
324 np.allclose(newvec, np.array([2.74911638, 4.77180932, 1.91629719]))
325 )
327 def test_cone(self):
328 spike = [1, 1, 0]
329 bottom = [0, 2, 0]
330 angle = np.pi / 4
331 n_angles = 20
332 cone = SparseCone(spike, bottom, angle)
333 circ_samp = cone.sample_circle(n_angles=n_angles)
334 axis_samp = cone.sample_axis
335 samp = cone.sample(n_angles)
336 assert len(circ_samp) == n_angles
337 assert len(axis_samp) == 2
338 assert len(samp) == len(circ_samp) + 2
341class TestSphereCut(TestCase):
342 def test_spherecut_mask(self):
343 center = (0.0, 0.0, 0.0)
344 items = Table(
345 {
346 "pos_x": [0, 10, 0, 20, 0],
347 "pos_y": [10, 0, 0, 0, 30],
348 "pos_z": [0, 0, 10, 0, 0],
349 }
350 )
351 rmin = 0.0
352 rmax = 10.0
353 self.assertListEqual(
354 list(spherecutmask(center, rmin, rmax, items)),
355 [True, True, True, False, False],
356 )
358 def test_with_table(self):
359 center = (0.0, 0.0, 0.0)
360 items = Table(
361 {
362 "pos_x": [0, 10, 0, 20, 0],
363 "pos_y": [10, 0, 0, 0, 30],
364 "pos_z": [0, 0, 10, 0, 0],
365 }
366 )
367 rmin = 0.0
368 rmax = 10.0
369 selected_items = spherecut(center, rmin, rmax, items)
370 assert len(selected_items) == 3
371 self.assertListEqual(
372 list(items[spherecutmask(center, rmin, rmax, items)]), list(selected_items)
373 )
375 def test_with_array(self):
376 center = (0.0, 0.0, 0.0)
377 items = np.array([[0, 10, 0], [10, 0, 0], [0, 0, 10], [20, 0, 0], [0, 30, 0]])
378 rmin = 0.0
379 rmax = 10.0
380 selected_items = [list(e) for e in spherecut(center, rmin, rmax, items)]
381 assert len(selected_items) == 3
382 assert [0, 10, 0] in selected_items
383 assert [10, 0, 0] in selected_items
384 assert [0, 0, 10] in selected_items
386 def test_center(self):
387 center = (0.0, 10.0, 0.0)
388 items = Table(
389 {
390 "pos_x": [0, 10, 0, 20, 0],
391 "pos_y": [10, 0, 0, 0, 30],
392 "pos_z": [0, 0, 10, 0, 0],
393 }
394 )
395 rmin = 0.0
396 rmax = 15.0
397 selected_items = spherecut(center, rmin, rmax, items)
398 assert len(selected_items) == 3
399 self.assertListEqual(
400 list(items[spherecutmask(center, rmin, rmax, items)]), list(selected_items)
401 )
403 def test_rmin(self):
404 center = (0.0, 0.0, 0.0)
405 items = np.array([[0, 10, 0], [10, 0, 0], [0, 0, 10], [20, 0, 0], [0, 30, 0]])
406 rmin = 20.0
407 rmax = 40.0
408 selected_items = [list(e) for e in spherecut(center, rmin, rmax, items)]
409 assert len(selected_items) == 2
410 assert [20, 0, 0] in selected_items
411 assert [0, 30, 0] in selected_items
414class TestLog(TestCase):
415 def test_val(self):
416 assert_allclose(log_b(5, 2), np.log2(5))
417 assert_allclose(log_b(5, 10), np.log10(5))
418 assert_allclose(log_b(5, np.e), np.log(5))
421class TestQeuler(TestCase):
422 def test_conversion_of_yaw(self):
423 assert np.allclose([1, 0, 0, 0], qeuler(0, 0, 0))
424 assert np.allclose([0.7071, 0, 0, 0.7071], qeuler(90, 0, 0))
425 assert np.allclose([0, 0, 0, 1], qeuler(180, 0, 0))
426 assert np.allclose([-0.7071, 0, 0, 0.7071], qeuler(270, 0, 0))
427 assert np.allclose([-1, 0, 0, 0], qeuler(360, 0, 0))
429 def test_conversion_of_pitch(self):
430 assert np.allclose([0.92388, 0, 0.38268, 0], qeuler(0, 45, 0))
431 assert np.allclose([0.92388, 0, -0.38268, 0], qeuler(0, -45, 0))
432 assert np.allclose([0.7071, 0, 0.7071, 0], qeuler(0, 90, 0))
433 assert np.allclose([0.8660254, 0, 0.5, 0], qeuler(0, 60, 0))
434 assert np.allclose([-0.96592583, 0, -0.25881905, 0], qeuler(0, 390, 0))
436 def test_conversion_of_roll(self):
437 assert np.allclose([0.92388, 0.38268, 0, 0], qeuler(0, 0, 45))
438 assert np.allclose([0.92388, -0.38268, 0, 0], qeuler(0, 0, -45))
439 assert np.allclose([0.70710, 0.70710, 0, 0], qeuler(0, 0, 90))
440 assert np.allclose([0.86602, 0.5, 0, 0], qeuler(0, 0, 60))
441 assert np.allclose([-0.96592583, -0.25881905, 0, 0], qeuler(0, 0, 390))
443 def test_mixed_conversion(self):
444 assert np.allclose(
445 [0.999471, 0.02601972, 0.01767416, 0.00826538], qeuler(1, 2, 3)
446 )
447 assert np.allclose(
448 [0.94371436, 0.26853582, -0.14487813, 0.12767944], qeuler(10, -20, 30)
449 )
450 assert np.allclose(
451 [-0.16575384, -0.69624819, 0.05479592, -0.69624819], qeuler(-999, 999, -999)
452 )
455class TestQrot(TestCase):
456 def test_rotation_of_x_vector(self):
457 assert np.allclose([0, 1, 0], qrot([1, 0, 0], qeuler(90, 0, 0)))
458 assert np.allclose([-1, 0, 0], qrot([1, 0, 0], qeuler(180, 0, 0)))
459 assert np.allclose([-1, 0, 0], qrot([1, 0, 0], qeuler(180, 0, -45)))
460 assert np.allclose([0, 0, -1], qrot([1, 0, 0], qeuler(180, 90, 45)))
462 def test_rotation_of_y_vector(self):
463 assert np.allclose([-1, 0, 0], qrot([0, 1, 0], qeuler(90, 0, 0)))
464 assert np.allclose([0, -1, 0], qrot([0, 1, 0], qeuler(180, 0, 0)))
465 assert np.allclose(
466 [0, -0.70710, -0.70710], qrot([0, 1, 0], qeuler(180, 0, -45))
467 )
468 assert np.allclose(
469 [-0.70710, -0.70710, 0], qrot([0, 1, 0], qeuler(180, 90, 45))
470 )
472 def test_rotation_of_z_vector(self):
473 assert np.allclose([0, 0, 1], qrot([0, 0, 1], qeuler(90, 0, 0)))
474 assert np.allclose([0, 0, 1], qrot([0, 0, 1], qeuler(180, 0, 0)))
475 assert np.allclose([0, -0.70710, 0.70710], qrot([0, 0, 1], qeuler(180, 0, -45)))
476 assert np.allclose([-0.70710, 0.70710, 0], qrot([0, 0, 1], qeuler(180, 90, 45)))
478 def test_mixed_rotation(self):
479 assert np.allclose([1, 2, 3], qrot([1, 2, 3], qeuler(0, 0, 0)))
480 assert np.allclose([0, -1.414213, 0], qrot([0, 1, -1], qeuler(180, 90, 45)))
481 assert np.allclose([-1.41421356, 0, -1], qrot([1, 1, 1], qeuler(180, 90, 45)))
482 assert np.allclose(
483 [-14.1421356, 0, -10], qrot([10, 10, 10], qeuler(180, 90, 45))
484 )
487class TestQrotYaw(TestCase):
488 def test_call_with_list(self):
489 qrot_yaw([1, 2, 3], 1)
491 def test_no_rotation(self):
492 vec = (1, 0, 0)
493 vec_rot = qrot_yaw(vec, 0)
494 assert np.allclose([1, 0, 0], vec_rot)
496 def test_a_rotation_of_90(self):
497 vec = (1, 0, 0)
498 vec_rot = qrot_yaw(vec, 90)
499 assert np.allclose([0, 1, 0], vec_rot)
501 def test_a_rotation_of_180(self):
502 vec = (1, 0, 0)
503 vec_rot = qrot_yaw(vec, 180)
504 assert np.allclose([-1, 0, 0], vec_rot)
506 def test_a_full_rotation(self):
507 vec = (1, 0, 0)
508 vec_rot = qrot_yaw(vec, 360)
509 assert np.allclose([1, 0, 0], vec_rot)
511 def test_a_rotation_of_45(self):
512 vec = (1, 0, 0)
513 vec_rot = qrot_yaw(vec, 45)
514 assert np.allclose([0.7071, 0.7071, 0], vec_rot)
517class TestIntersect3D(TestCase):
518 def test_intersection_at_zero(self):
519 p1 = np.array([(1, 0, 0), (0, 0, 1)])
520 p2 = -p1
521 intersection = intersect_3d(p1, p2)
522 assert np.allclose([0, 0, 0], intersection)
524 def test_intersection_of_multiple_lines_with_same_endpoints(self):
525 p1 = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
526 p2 = np.array([(4, 4, 4), (4, 4, 4), (4, 4, 4)])
527 intersection = intersect_3d(p1, p2)
528 assert np.allclose([4, 4, 4], intersection)
530 def test_intersection_of_multiple_lines_with_target(self):
531 p1 = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
532 target = np.array([23, 5, 42])
533 p2 = 2 * target - p1
534 intersection = intersect_3d(p1, p2)
535 assert np.allclose(target, intersection)
537 def test_another_intersection(self):
538 p1 = np.array([(1, 10, 0), (0, 10, 1)])
539 p2 = np.array([(-1, 10, 0), (0, 10, -1)])
540 intersection = intersect_3d(p1, p2)
541 assert np.allclose([0, 10, 0], intersection)
544class TestDist(TestCase):
545 def test_dist_between_two_2D_points(self):
546 self.assertAlmostEqual(1, dist(np.array([0, 0]), np.array([1, 0])))
547 self.assertAlmostEqual(np.sqrt(2), dist(np.array([0, 1]), np.array([1, 0])))
548 self.assertAlmostEqual(2 * np.sqrt(2), dist(np.array([1, 2]), np.array([3, 4])))
550 def test_dist_between_two_3D_points(self):
551 self.assertAlmostEqual(1, dist(np.array([0, 0, 0]), np.array([1, 0, 0])))
552 self.assertAlmostEqual(
553 np.sqrt(2), dist(np.array([0, 1, 0]), np.array([1, 0, 0]))
554 )
555 self.assertAlmostEqual(2, dist(np.array([0, 0, 2]), np.array([0, 0, 0])))
556 self.assertAlmostEqual(
557 5.1961524, dist(np.array([1, 2, 3]), np.array([4, 5, 6]))
558 )
560 def test_dist_to_many_points(self):
561 assert np.allclose(
562 [1, 1, 0, 1.73205081],
563 dist(
564 np.array([0, 0, 0]),
565 np.array([[0, 0, 1], [0, 0, 1], [0, 0, 0], [1, 1, 1]]),
566 axis=1,
567 ),
568 )