def test_procrustes_rotation_translation(): # initial arrays array_a = np.array([[-7.3, 2.8], [-7.1, -0.2], [4.0, 1.4], [1.3, 0]]) # rotation by 20 degree & reflection in the x-axis theta = 0.34907 rotation = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) reflection = np.array([[1, 0], [0, -1]]) array_b = np.dot(array_a, np.dot(rotation, reflection)) # procrustes without translation and scaling new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(new_a, array_a, decimal=6) assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(array_u, np.dot(rotation, reflection), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # procrustes with translation new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=True) assert_almost_equal(new_a, array_a - np.mean(array_a, axis=0), decimal=6) assert_almost_equal(new_b, array_b - np.mean(array_b, axis=0), decimal=6) assert_almost_equal(array_u, np.dot(rotation, reflection), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # procrustes with translation and scaling new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=True, scale=True) assert_almost_equal(array_u, np.dot(rotation, reflection), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6)
def test_procrustes_shifted(): # square array array_a = np.array([[3.5, 0.1, 7.0], [0.5, 2.0, 1.0], [8.1, 0.3, 0.7]]) expected_a = array_a - np.mean(array_a, axis=0) # constant shift array_b = array_a + 4.1 new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=True) #assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(array_u, np.eye(3), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # different shift along each axis array_b = array_a + np.array([0, 3.2, 5.0]) new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=True) # assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(array_u, np.eye(3), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # rectangular (2 by 3) array_a = np.array([[1, 2, 3], [7, 9, 5]]) expected_a = array_a - np.array([4., 5.5, 4.]) # constant shift array_b = array_a + 0.71 new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=True) #assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # different shift along each axis array_b = array_a + np.array([0.3, 7.1, 4.2]) new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=True) # assert_almost_equal(new_b, array_b, decimal=6) assert_equal(array_u.shape, (3, 3)) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6)
def test_procrustes_orthogonal_identical(): # case of identical square arrays array_a = np.arange(9).reshape(3, 3) array_b = np.copy(array_a) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) # check transformation array is identity assert_almost_equal(new_a, array_a, decimal=6) assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # case of identical rectangular arrays (2 by 4) array_a = np.array([[1, 5, 6, 7], [1, 2, 9, 4]]) array_b = np.copy(array_a) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(new_a, array_a, decimal=6) assert_almost_equal(new_b, array_b, decimal=6) assert_equal(array_u.shape, (4, 4)) # assert_almost_equal(array_u, np.eye(4), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # case of identical rectangular arrays (5 by 3) array_a = np.arange(15).reshape(5, 3) array_b = np.copy(array_a) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(new_a, array_a, decimal=6) assert_almost_equal(new_b, array_b, decimal=6) assert_equal(array_u.shape, (3, 3)) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6)
def test_procrustes_reflection_square(): # square array array_a = np.array([[2.0, 0.1], [0.5, 3.0]]) # reflection through origin array_b = -array_a new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(new_a, array_a, decimal=6) assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(array_u, np.array([[-1, 0], [0, -1]]), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # reflection in the x-axis array_b = np.array([[2.0, -0.1], [0.5, -3.0]]) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, np.array([[1, 0], [0, -1]]), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # reflection in the y-axis array_b = np.array([[-2.0, 0.1], [-0.5, 3.0]]) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, np.array([[-1, 0], [0, 1]]), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # reflection in the line y=x array_b = np.array([[0.1, 2.0], [3.0, 0.5]]) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, np.array([[0, 1], [1, 0]]), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6)
def test_procrustes_shifted(): r"""Test orthogonal Procrustes with shifted array.""" # square array array_a = np.array([[3.5, 0.1, 7.0], [0.5, 2.0, 1.0], [8.1, 0.3, 0.7]]) # expected_a = array_a - np.mean(array_a, axis=0) # constant shift array_b = array_a + 4.1 res = orthogonal(array_a, array_b, translate=True) # assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(res["array_u"], np.eye(3), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # different shift along each axis array_b = array_a + np.array([0, 3.2, 5.0]) res = orthogonal(array_a, array_b, translate=True) # assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(res["array_u"], np.eye(3), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # rectangular (2 by 3) array_a = np.array([[1, 2, 3], [7, 9, 5]]) # expected_a = array_a - np.array([4., 5.5, 4.]) # constant shift array_b = array_a + 0.71 res = orthogonal(array_a, array_b, translate=True) # assert_almost_equal(new_b, array_b, decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # different shift along each axis array_b = array_a + np.array([0.3, 7.1, 4.2]) res = orthogonal(array_a, array_b, translate=True) # assert_almost_equal(new_b, array_b, decimal=6) assert_equal(res["array_u"].shape, (3, 3)) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6)
def test_procrustes_reflection_square(n): r"""Test orthogonal Procrustes with reflected squared array.""" # square array array_a = np.random.uniform(-10.0, 10.0, (n, n)) # reflection through diagonal plane array_b = -array_a res = orthogonal(array_a, array_b) assert_almost_equal(res.new_a, array_a, decimal=6) assert_almost_equal(res.new_b, array_b, decimal=6) assert_almost_equal(res.t, -np.eye(n), decimal=6) assert_almost_equal(res.error, 0., decimal=6) # General reflection through random hyperplane, see Wikipedia "Reflection (mathematics)" a = np.random.uniform(-10.0, 10.0, (n)) a /= np.linalg.norm(a) rotation = np.eye(n) - 2.0 * np.outer(a, a) / np.linalg.norm(a)**2.0 array_b = array_a.dot(rotation) res = orthogonal(array_a, array_b) assert_almost_equal(res.t, rotation, decimal=6) assert_almost_equal(res.error, 0., decimal=6) assert_almost_equal(array_a.dot(rotation), array_b, decimal=6) assert_equal(res.s, None)
def test_procrustes_rotation_square_lapack_driver(n): r"""Test orthogonal Procrustes with squared array with non-default lapack_driver.""" # square array array_a = np.random.uniform(-10.0, 10.0, (n, n)) # rotation by 90 degree ortho_arr = ortho_group.rvs(n) array_b = array_a.dot(ortho_arr) res = orthogonal(array_a, array_b, lapack_driver="gesdd") assert_almost_equal(res.error, 0., decimal=6) assert_almost_equal(res.t.dot(res.t.T), np.eye(n), decimal=6) assert_almost_equal(res.t, ortho_arr) assert_equal(res.s, None)
def test_procrustes_orthogonal_identical(m, n): r"""Test orthogonal Procrustes with identity matrix.""" # case of identical square arrays array_a = np.random.uniform(-10.0, 10.0, (m, n)) array_b = np.copy(array_a) res = orthogonal(array_a, array_b) assert_equal(res.s, None) assert_almost_equal(res.new_a, array_a, decimal=6) assert_almost_equal(res.new_b, array_b, decimal=6) assert_almost_equal(res.t.dot(res.t.T), np.eye(n), decimal=6) assert_almost_equal(res.error, 0., decimal=6) assert_almost_equal(array_a.dot(res.t), array_b)
def test_procrustes_reflection_square(): r"""Test orthogonal Procrustes with reflected squared array.""" # square array array_a = np.array([[2.0, 0.1], [0.5, 3.0]]) # reflection through origin array_b = -array_a res = orthogonal(array_a, array_b) assert_almost_equal(res["new_a"], array_a, decimal=6) assert_almost_equal(res["new_b"], array_b, decimal=6) assert_almost_equal(res["array_u"], np.array([[-1, 0], [0, -1]]), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # reflection in the x-axis array_b = np.array([[2.0, -0.1], [0.5, -3.0]]) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], np.array([[1, 0], [0, -1]]), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # reflection in the y-axis array_b = np.array([[-2.0, 0.1], [-0.5, 3.0]]) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], np.array([[-1, 0], [0, 1]]), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # reflection in the line y=x array_b = np.array([[0.1, 2.0], [3.0, 0.5]]) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], np.array([[0, 1], [1, 0]]), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6)
def test_procrustes_orthogonal_identical(): r"""Test orthogonal Procrustes with identity matrix.""" # case of identical square arrays array_a = np.arange(9).reshape(3, 3) array_b = np.copy(array_a) res = orthogonal(array_a, array_b) # check transformation array is identity assert_almost_equal(res["new_a"], array_a, decimal=6) assert_almost_equal(res["new_b"], array_b, decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # case of identical rectangular arrays (2 by 4) array_a = np.array([[1, 5, 6, 7], [1, 2, 9, 4]]) array_b = np.copy(array_a) res = orthogonal(array_a, array_b) assert_almost_equal(res["new_a"], array_a, decimal=6) assert_almost_equal(res["new_b"], array_b, decimal=6) assert_equal(res["array_u"].shape, (4, 4)) # assert_almost_equal(array_u, np.eye(4), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # case of identical rectangular arrays (5 by 3) array_a = np.arange(15).reshape(5, 3) array_b = np.copy(array_a) res = orthogonal(array_a, array_b) assert_almost_equal(res["new_a"], array_a, decimal=6) assert_almost_equal(res["new_b"], array_b, decimal=6) assert_equal(res["array_u"].shape, (3, 3)) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6)
def test_rotation_translate_scale(): # initial arrays array_a = np.array([[5.1, 0], [-1.1, 4.8], [3.9, 7.3], [9.1, 6.3]]) # rotation by 68 degree & reflection in the Y=X theta = 1.18682 rotation = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) reflection = np.array([[0, 1], [1, 0]]) array_b = np.dot(4 * array_a + 3.0, np.dot(rotation, reflection)) # procrustes with translation and scaling new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=True, scale=True) assert_almost_equal(array_u, np.dot(rotation, reflection), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6)
def test_procrustes_with_translation(m, n): r"""Test orthogonal Procrustes with translation.""" array_a = np.random.uniform(-10.0, 10.0, (m, n)) array_b = array_a + np.random.uniform(-10.0, 10.0, (n, )) res = orthogonal(array_a, array_b, translate=True) # Test that the new A and B are translation of the originals. assert_almost_equal(res.new_a, array_a - np.mean(array_a, axis=0), decimal=6) assert_almost_equal(res.new_b, array_a - np.mean(array_a, axis=0), decimal=6) # Test that optimal result is orthogonal, and error is zero assert_almost_equal(res.t.T.dot(res.t), np.eye(n), decimal=6) assert_almost_equal(res.error, 0., decimal=6) assert_almost_equal(res.new_a.dot(res.t), res.new_b, decimal=6) assert_equal(res.s, None)
def test_procrustes_orthogonal_translate_scale2(): # initial array array_a = np.array([[1, 4], [7, 9]]) # define a transformation composed of rotation & reflection theta = np.pi / 2 rot = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) ref = np.array([[1, 0], [0, -1]]) trans = np.dot(rot, ref) # define array_b by transforming array_a and padding with zero array_b = np.dot(array_a, trans) array_b = np.concatenate((array_b, np.zeros((2, 5))), axis=1) array_b = np.concatenate((array_b, np.zeros((5, 7))), axis=0) # compute procrustes transformation new_a, new_b, array_u, _ = orthogonal(array_a, array_b, translate=False, scale=False) assert_almost_equal(array_u, np.dot(rot, ref), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6)
def test_orthogonal_with_translate_and_scale(m, n): r"""Test orthogonal Procrustes with rotation, translation and scaling.""" # initial arrays array_a = np.random.uniform(-10.0, 10.0, (m, n)) # Generate reflection across random hyperplane a = np.random.uniform(-10.0, 10.0, (n)) a /= np.linalg.norm(a) reflection = np.eye(n) - 2.0 * np.outer(a, a) / np.linalg.norm(a)**2.0 rotation = ortho_group.rvs(n) # Translate and shift the rotated and reflected array_a. array_b = 4.0 * np.dot(array_a, rotation.dot(reflection)) + 3.0 # Procrustes with translation and scaling res = orthogonal(array_a, array_b, translate=True, scale=True) untranslated_array_a = (array_a - np.mean(array_a, axis=0)) assert_almost_equal( res.new_a, untranslated_array_a / np.linalg.norm(untranslated_array_a)) assert_almost_equal(res.t.T.dot(res.t), np.eye(n), decimal=6) assert_almost_equal(res.error, 0., decimal=6) assert_almost_equal(res.new_a.dot(res.t), res.new_b, decimal=6) assert_equal(res.s, None)
def test_orthogonal_translate_scale2(): r"""Test orthogonal Procrustes with rotation, translation and scaling with a different array.""" # initial array array_a = np.array([[1, 4], [7, 9]]) # define a transformation composed of rotation & reflection theta = np.pi / 2 rot = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) ref = np.array([[1, 0], [0, -1]]) trans = np.dot(rot, ref) # define array_b by transforming array_a and padding with zero array_b = np.dot(array_a, trans) array_b = np.concatenate((array_b, np.zeros((2, 5))), axis=1) array_b = np.concatenate((array_b, np.zeros((5, 7))), axis=0) # compute procrustes transformation res = orthogonal(array_a, array_b, translate=False, scale=False) assert_almost_equal(res["array_u"], np.dot(rot, ref), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6)
def test_orthogonal_translate_scale_with_unpadding(m, n, ncols, nrows): r"""Test orthogonal Procrustes with rotation, translation and scaling with unpadding.""" # initial array array_a = np.random.uniform(-10.0, 10.0, (m, n)) # obtain random orthogonal matrix ortho = ortho_group.rvs(n) # define array_b by transforming array_a and padding with zero array_b = np.dot(array_a, ortho) # Pad array b with additional "ncols" columns and "nrows" rows. array_b = np.concatenate((array_b, np.zeros((m, ncols))), axis=1) array_b = np.concatenate((array_b, np.zeros((nrows, n + ncols))), axis=0) # compute procrustes transformation res = orthogonal(array_a, array_b, translate=False, scale=False, unpad_col=True, unpad_row=True) assert_almost_equal(res.new_b, np.dot(array_a, ortho), decimal=6) assert_almost_equal(res.error, 0., decimal=6) assert_almost_equal(res.t.T.dot(res.t), np.eye(n), decimal=6) assert_almost_equal(res.new_a.dot(res.t), res.new_b, decimal=6) assert_equal(res.s, None)
def test_procrustes_rotation_square(): # square array array_a = np.arange(4).reshape(2, 2) # rotation by 90 degree array_b = np.array([[1, 0], [3, -2]]) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, np.array([[0., -1.], [1., 0.]]), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # rotation by 180 degree array_b = -array_a new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, np.array([[-1., 0.], [0., -1.]]), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # rotation by 270 degree array_b = np.array([[-1, 0], [-3, 2]]) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, np.array([[0., 1.], [-1., 0.]]), decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # rotation by 45 degree rotation = 0.5 * np.sqrt(2) * np.array([[1, -1], [1, 1]]) array_b = np.dot(array_a, rotation) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, rotation, decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # rotation by 30 degree theta = np.pi / 6 rotation = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) array_b = np.dot(array_a, rotation) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, rotation, decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6) # rotation by 72 degree theta = 1.25664 rotation = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) array_b = np.dot(array_a, rotation) new_a, new_b, array_u, _ = orthogonal(array_a, array_b) assert_almost_equal(array_u, rotation, decimal=6) assert_almost_equal(error(new_a, new_b, array_u), 0., decimal=6)
def test_procrustes_rotation_square(): r"""Test orthogonal Procrustes with squared array.""" # square array array_a = np.arange(4).reshape(2, 2) # rotation by 90 degree array_b = np.array([[1, 0], [3, -2]]) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], np.array([[0., -1.], [1., 0.]]), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # rotation by 180 degree array_b = -array_a res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], np.array([[-1., 0.], [0., -1.]]), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # rotation by 270 degree array_b = np.array([[-1, 0], [-3, 2]]) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], np.array([[0., 1.], [-1., 0.]]), decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # rotation by 45 degree rotation = 0.5 * np.sqrt(2) * np.array([[1, -1], [1, 1]]) array_b = np.dot(array_a, rotation) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], rotation, decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # rotation by 30 degree theta = np.pi / 6 rotation = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) array_b = np.dot(array_a, rotation) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], rotation, decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6) # rotation by 72 degree theta = 1.25664 rotation = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) array_b = np.dot(array_a, rotation) res = orthogonal(array_a, array_b) assert_almost_equal(res["array_u"], rotation, decimal=6) assert_almost_equal(compute_error(res["new_a"], res["new_b"], res["array_u"]), 0., decimal=6)