def test_matrix(self): dofs = spin.ExponentialMap.random() rot = spin.ExponentialMap(dofs) rot2 = spin.ExponentialMap.from_rotation(rot) rot3 = ExponentialMap(dofs) print(make_title('Cython (from dofs)')) print(rot) print(make_title('Cython (from matrix)')) print(rot2) print(make_title('Python (from dofs)')) print(rot3) axis, angle = rot.axis_angle r, theta, phi = csb.polar3d(axis) axisangle = spin.AxisAngle([theta, phi, angle]) rot4 = spin.Rotation(csb.rotation_matrix(axis, -angle)) self.assertTrue(spin.distance(rot, rot2) < self.tol) self.assertTrue(spin.distance(rot, rot4) < self.tol) self.assertTrue(spin.distance(rot3, rot4) < self.tol) self.assertTrue(spin.distance(rot2, axisangle) < self.tol)
def test_analytical(self): """ Test analytical calculation of the upper bound using SVD and eigenvalue decomposition. """ tol = 1e-10 n = int(1e3) X, Y = load_coords(['1ake', '4ake']) A = np.dot(X.T, Y) R = fit(X, Y)[0] func = spin.NearestRotation(A) func2 = spin.NearestUnitQuaternion(A) self.assertTrue(spin.distance(func.optimum(), R) < tol) self.assertTrue(np.linalg.norm(func2.optimum().dofs-spin.Quaternion(R).dofs) < tol) rotations = spin.random_rotation(n) vals = np.array(list(map(func, rotations))) vals2 = np.dot(rotations.reshape(n,-1), A.flatten()) self.assertTrue(np.fabs(vals-vals2).max() < tol) self.assertTrue(np.all(vals <= func(func.optimum().matrix))) self.assertTrue(np.all(vals <= func2(func2.optimum())))
def test_lsq(self): rotation, score = self.lsq['svd'].optimum() rmsd_ = [ np.sqrt(score / len(self.coords[0])), self.lsq['svd'].rmsd(rotation.matrix), rmsd(*self.coords) ] lsq_ = [0.5 * score, self.lsq['svd'](rotation.matrix)] for name in ('euler', 'axisangle', 'expmap', 'axisangle'): dofs = self.lsq[name].trafo.from_rotation(rotation).dofs lsq_.append(self.lsq[name](dofs)) rmsd_ = np.round(rmsd_, 5) lsq_ = np.round(lsq_, 2) print(make_title('checking LSQ optimization using SVD')) print('RMSD: {0}'.format(rmsd_)) print(' LSQ: {0}'.format(lsq_)) tol = 1e-10 self.assertTrue(np.all(np.fabs(rmsd_ - rmsd_[0]) < tol)) self.assertTrue(np.all(np.fabs(lsq_ - lsq_[0]) < tol)) self.assertAlmostEqual(spin.distance( fit(*self.coords)[0], rotation.matrix), 0., delta=tol)
def test_opt(self): print(make_title('test optimization of least-squares residual')) out = '{0:>14}: #steps={1:3d}, RMSD: {5:.2f}->{2:.2f}, ' + \ 'accuracy: {3:.3e} (rot), {4:.3e} (trans)' start = spin.random_rotation(), np.random.standard_normal(3) * 10 R, t = fit(*self.coords) rot = [] trans = [] rmsds = [] for trafo in self.trafos[1:]: trafo.matrix_vector = start f = spin.LeastSquares(*self.coords, trafo=trafo) x = trafo.dofs.copy() y = opt.fmin_bfgs(f, x, f.gradient, disp=False) rot.append(spin.distance(R, trafo.rotation)) trans.append(np.linalg.norm(t - trafo.translation.vector)) rmsds.append(np.sqrt(2 * f(y) / len(self.coords[0]))) print( out.format(trafo.rotation.name, len(f.values), rmsds[-1], rot[-1], trans[-1], np.sqrt(2 * f(x) / len(self.coords[0])))) self.assertAlmostEqual(rot[-1], 0., delta=1e-5) self.assertAlmostEqual(trans[-1], 0., delta=1e-5) self.assertAlmostEqual(np.std(rmsds), 0., delta=1e-5)
def test_matrix(self): angles = np.random.random(3) euler = spin.EulerAngles(angles) euler2 = spin.EulerAngles.from_rotation(euler) euler3 = compose_euler(*angles) a, b, c = angles euler4 = spin.compose(R_z(c), R_y(b), R_z(a)) R = np.zeros((3, 3)) eulerlib.matrix(angles, R) self.assertTrue(spin.distance(euler, euler2) < self.tol) self.assertTrue(spin.distance(euler, euler3) < self.tol) self.assertTrue(spin.distance(euler, euler4) < self.tol) self.assertTrue(spin.distance(euler, R) < self.tol)
def test_compose(self): n = 10 R = [spin.EulerAngles() for _ in range(n)] M = np.eye(3) for R_ in R: M = M.dot(R_.matrix) R_tot = spin.compose(*R) self.assertTrue(spin.distance(M, R_tot) < self.tol)
def test_optimizers(self): """ Test various optimizers for finding the optimal rotation in Euler parameterization """ optimizers = OrderedDict() optimizers['nedler-mead'] = opt.fmin optimizers['powell'] = opt.fmin_powell optimizers['bfgs'] = opt.fmin_bfgs print(make_title('Testing different optimizers')) rotation, _ = self.lsq['svd'].optimum() lsq_opt = self.lsq['svd'](rotation.matrix) output = '{0:11s} : min.score={1:.2f}, dist={2:.3e}, nsteps={3:d}' for name, lsq in self.lsq.items(): if name == 'svd': continue print(make_title(lsq.trafo.name)) start = lsq.trafo.random() results = OrderedDict() for method, run in optimizers.items(): lsq.values = [] args = [lsq, start.copy() ] + ([lsq.gradient] if method == 'bfgs' else []) best = run(*args, disp=False) results[method] = np.array(lsq.values) summary = lsq(best), spin.distance(rotation, lsq.trafo), len(lsq.values) print(output.format(*((method, ) + summary))) fig, ax = plt.subplots(1, 1, figsize=(10, 6)) fig.suptitle(lsq.trafo.name) for method, values in results.items(): ax.plot(values, lw=5, alpha=0.7, label=method) ax.axhline(lsq_opt, lw=3, ls='--', color='r') ax.legend()
def test_params(self): rigid = self.trafos[0] print(make_title('comparing matrix and vector')) out = '{0:14s} : distance rotation={1:.3e}, translation={2:.3e}' for other in self.trafos[1:]: dist_rot = spin.distance(rigid.rotation, other.rotation) dist_trans = np.linalg.norm(rigid.translation.vector - other.translation.vector) print(out.format(other.rotation.name, dist_rot, dist_trans)) self.assertAlmostEqual(dist_rot, 0., delta=1e-10) self.assertAlmostEqual(dist_trans, 0., delta=1e-10)
Compare least-squares fitting with unit quaternions (Kearsley's algorithm) with fitting using singular value decomposition (Kabsch's algorithm). """ from __future__ import print_function import spin import time import numpy as np from littlehelpers import load_coords from csb.bio.utils import fit X, Y = load_coords(['1ake', '4ake']) n = 1000 X = np.repeat(X, n, axis=0) Y = np.repeat(Y, n, axis=0) t = time.clock() A = spin.qfit(X, Y) t = time.clock() - t t2 = time.clock() B = fit(X, Y) t2 = time.clock() - t2 print('dist(R_quat,R_svd) = {0:.3f}'.format(spin.distance(A[0], B[0]))) print('dist(t_quat,t_svd) = {0:.3f}'.format(np.linalg.norm(A[1] - B[1]))) print('times: {0:.3f} vs {1:.3f} (quat vs svd)'.format(t, t2))
import spin import numpy as np from scipy.spatial.distance import squareform, cdist, pdist n = 1000 rot = (spin.EulerAngles(), spin.ExponentialMap(), spin.AxisAngle(), spin.Quaternion())[-1] dofs = rot.random(n).T R = [] for x in dofs: rot.dofs = np.ascontiguousarray(x) R.append(rot.matrix.copy()) R = np.array(R) a = pdist(dofs) if isinstance(rot, spin.Quaternion): ## see Mitchell et al: Generating Uniform Incremental Grids on SO(3) Using the Hopf Fibration a = squareform(np.dot(dofs,dofs.T),checks=False) a = np.arccos(np.fabs(a)) b = [spin.distance(R1,R2) for i, R1 in enumerate(R) for R2 in R[i+1:]] figure() title(rot.__class__.__name__) scatter(a,b,alpha=0.1,s=1)