# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- # vi: set ft=python sts=4 ts=4 sw=4 et: import numpy as np from ..affines import (apply_affine, append_diag, to_matvec, from_matvec, dot_reduce) from nose.tools import assert_equal, assert_raises from numpy.testing import assert_array_equal, assert_almost_equal, \ assert_array_almost_equal def validated_apply_affine(T, xyz): # This was the original apply_affine implementation that we've stashed here # to test against xyz = np.asarray(xyz) shape = xyz.shape[0:-1] XYZ = np.dot(np.reshape(xyz, (np.prod(shape), 3)), T[0:3,0:3].T) XYZ[:,0] += T[0,3] XYZ[:,1] += T[1,3] XYZ[:,2] += T[2,3] XYZ = np.reshape(XYZ, shape+(3,)) return XYZ def test_apply_affine(): rng = np.random.RandomState(20110903) aff = np.diag([2, 3, 4, 1]) pts = rng.uniform(size=(4,3)) assert_array_equal(apply_affine(aff, pts), pts * [[2, 3, 4]]) aff[:3,3] = [10, 11, 12] assert_array_equal(apply_affine(aff, pts), pts * [[2, 3, 4]] + [[10, 11, 12]]) aff[:3,:] = rng.normal(size=(3,4)) exp_res = np.concatenate((pts.T, np.ones((1,4))), axis=0) exp_res = np.dot(aff, exp_res)[:3,:].T assert_array_equal(apply_affine(aff, pts), exp_res) # Check we get the same result as the previous implementation assert_almost_equal(validated_apply_affine(aff, pts), apply_affine(aff, pts)) # Check that lists work for inputs assert_array_equal(apply_affine(aff.tolist(), pts.tolist()), exp_res) # Check that it's the same as a banal implementation in the simple case aff = np.array([[0,2,0,10],[3,0,0,11],[0,0,4,12],[0,0,0,1]]) pts = np.array([[1,2,3],[2,3,4],[4,5,6],[6,7,8]]) exp_res = (np.dot(aff[:3,:3], pts.T) + aff[:3,3:4]).T assert_array_equal(apply_affine(aff, pts), exp_res) # That points can be reshaped and you'll get the same shape output pts = pts.reshape((2,2,3)) exp_res = exp_res.reshape((2,2,3)) assert_array_equal(apply_affine(aff, pts), exp_res) # That ND also works for N in range(2,6): aff = np.eye(N) nd = N-1 aff[:nd,:nd] = rng.normal(size=(nd,nd)) pts = rng.normal(size=(2,3,nd)) res = apply_affine(aff, pts) # crude apply new_pts = np.ones((N,6)) new_pts[:-1,:] = np.rollaxis(pts, -1).reshape((nd,6)) exp_pts = np.dot(aff, new_pts) exp_pts = np.rollaxis(exp_pts[:-1,:], 0, 2) exp_res = exp_pts.reshape((2,3,nd)) assert_array_almost_equal(res, exp_res) def test_matrix_vector(): for M, N in ((4,4), (5,4), (4, 5)): xform = np.zeros((M, N)) xform[:-1,:] = np.random.normal(size=(M-1, N)) xform[-1,-1] = 1 newmat, newvec = to_matvec(xform) mat = xform[:-1, :-1] vec = xform[:-1, -1] assert_array_equal(newmat, mat) assert_array_equal(newvec, vec) assert_equal(newvec.shape, (M-1,)) assert_array_equal(from_matvec(mat, vec), xform) # Check default translation works xform_not = xform[:] xform_not[:-1,:] = 0 assert_array_equal(from_matvec(mat), xform) assert_array_equal(from_matvec(mat, None), xform) # Check array-like works newmat, newvec = to_matvec(xform.tolist()) assert_array_equal(newmat, mat) assert_array_equal(newvec, vec) assert_array_equal(from_matvec(mat.tolist(), vec.tolist()), xform) def test_append_diag(): # Routine for appending diagonal elements assert_array_equal(append_diag(np.diag([2,3,1]), [1]), np.diag([2,3,1,1])) assert_array_equal(append_diag(np.diag([2,3,1]), [1,1]), np.diag([2,3,1,1,1])) aff = np.array([[2,0,0], [0,3,0], [0,0,1], [0,0,1]]) assert_array_equal(append_diag(aff, [5], [9]), [[2,0,0,0], [0,3,0,0], [0,0,0,1], [0,0,5,9], [0,0,0,1]]) assert_array_equal(append_diag(aff, [5,6], [9,10]), [[2,0,0,0,0], [0,3,0,0,0], [0,0,0,0,1], [0,0,5,0,9], [0,0,0,6,10], [0,0,0,0,1]]) aff = np.array([[2,0,0,0], [0,3,0,0], [0,0,0,1]]) assert_array_equal(append_diag(aff, [5], [9]), [[2,0,0,0,0], [0,3,0,0,0], [0,0,0,5,9], [0,0,0,0,1]]) # Length of starts has to match length of steps assert_raises(ValueError, append_diag, aff, [5,6], [9]) def test_dot_reduce(): # Chaining numpy dot # Error for no arguments assert_raises(TypeError, dot_reduce) # Anything at all on its own, passes through assert_equal(dot_reduce(1), 1) assert_equal(dot_reduce(None), None) assert_equal(dot_reduce([1, 2, 3]), [1, 2, 3]) # Two or more -> dot product vec = [1, 2, 3] mat = np.arange(4, 13).reshape((3, 3)) assert_array_equal(dot_reduce(vec, mat), np.dot(vec, mat)) assert_array_equal(dot_reduce(mat, vec), np.dot(mat, vec)) mat2 = np.arange(13, 22).reshape((3, 3)) assert_array_equal(dot_reduce(mat2, vec, mat), np.dot(mat2, np.dot(vec, mat))) assert_array_equal(dot_reduce(mat, vec, mat2, ), np.dot(mat, np.dot(vec, mat2)))