123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- from __future__ import division, absolute_import, print_function
- import numpy as np
- from numpy.testing import (assert_almost_equal,
- assert_array_equal,
- assert_equal,
- assert_)
- from scipy.spatial.distance import directed_hausdorff
- from scipy.spatial import distance
- from scipy._lib._util import check_random_state
- class TestHausdorff(object):
- # Test various properties of the directed Hausdorff code.
- def setup_method(self):
- np.random.seed(1234)
- random_angles = np.random.random(100) * np.pi * 2
- random_columns = np.column_stack(
- (random_angles, random_angles, np.zeros(100)))
- random_columns[..., 0] = np.cos(random_columns[..., 0])
- random_columns[..., 1] = np.sin(random_columns[..., 1])
- random_columns_2 = np.column_stack(
- (random_angles, random_angles, np.zeros(100)))
- random_columns_2[1:, 0] = np.cos(random_columns_2[1:, 0]) * 2.0
- random_columns_2[1:, 1] = np.sin(random_columns_2[1:, 1]) * 2.0
- # move one point farther out so we don't have two perfect circles
- random_columns_2[0, 0] = np.cos(random_columns_2[0, 0]) * 3.3
- random_columns_2[0, 1] = np.sin(random_columns_2[0, 1]) * 3.3
- self.path_1 = random_columns
- self.path_2 = random_columns_2
- self.path_1_4d = np.insert(self.path_1, 3, 5, axis=1)
- self.path_2_4d = np.insert(self.path_2, 3, 27, axis=1)
- def test_symmetry(self):
- # Ensure that the directed (asymmetric) Hausdorff distance is
- # actually asymmetric
- forward = directed_hausdorff(self.path_1, self.path_2)[0]
- reverse = directed_hausdorff(self.path_2, self.path_1)[0]
- assert_(forward != reverse)
- def test_brute_force_comparison_forward(self):
- # Ensure that the algorithm for directed_hausdorff gives the
- # same result as the simple / brute force approach in the
- # forward direction.
- actual = directed_hausdorff(self.path_1, self.path_2)[0]
- # brute force over rows:
- expected = max(np.amin(distance.cdist(self.path_1, self.path_2),
- axis=1))
- assert_almost_equal(actual, expected, decimal=9)
- def test_brute_force_comparison_reverse(self):
- # Ensure that the algorithm for directed_hausdorff gives the
- # same result as the simple / brute force approach in the
- # reverse direction.
- actual = directed_hausdorff(self.path_2, self.path_1)[0]
- # brute force over columns:
- expected = max(np.amin(distance.cdist(self.path_1, self.path_2),
- axis=0))
- assert_almost_equal(actual, expected, decimal=9)
- def test_degenerate_case(self):
- # The directed Hausdorff distance must be zero if both input
- # data arrays match.
- actual = directed_hausdorff(self.path_1, self.path_1)[0]
- assert_almost_equal(actual, 0.0, decimal=9)
- def test_2d_data_forward(self):
- # Ensure that 2D data is handled properly for a simple case
- # relative to brute force approach.
- actual = directed_hausdorff(self.path_1[..., :2],
- self.path_2[..., :2])[0]
- expected = max(np.amin(distance.cdist(self.path_1[..., :2],
- self.path_2[..., :2]),
- axis=1))
- assert_almost_equal(actual, expected, decimal=9)
- def test_4d_data_reverse(self):
- # Ensure that 4D data is handled properly for a simple case
- # relative to brute force approach.
- actual = directed_hausdorff(self.path_2_4d, self.path_1_4d)[0]
- # brute force over columns:
- expected = max(np.amin(distance.cdist(self.path_1_4d, self.path_2_4d),
- axis=0))
- assert_almost_equal(actual, expected, decimal=9)
- def test_indices(self):
- # Ensure that correct point indices are returned -- they should
- # correspond to the Hausdorff pair
- path_simple_1 = np.array([[-1,-12],[0,0], [1,1], [3,7], [1,2]])
- path_simple_2 = np.array([[0,0], [1,1], [4,100], [10,9]])
- actual = directed_hausdorff(path_simple_2, path_simple_1)[1:]
- expected = (2, 3)
- assert_array_equal(actual, expected)
- def test_random_state(self):
- # ensure that the global random state is not modified because
- # the directed Hausdorff algorithm uses randomization
- rs = check_random_state(None)
- old_global_state = rs.get_state()
- directed_hausdorff(self.path_1, self.path_2)
- rs2 = check_random_state(None)
- new_global_state = rs2.get_state()
- assert_equal(new_global_state, old_global_state)
- def test_random_state_None_int(self):
- # check that seed values of None or int do not alter global
- # random state
- for seed in [None, 27870671]:
- rs = check_random_state(None)
- old_global_state = rs.get_state()
- directed_hausdorff(self.path_1, self.path_2, seed)
- rs2 = check_random_state(None)
- new_global_state = rs2.get_state()
- assert_equal(new_global_state, old_global_state)
|