/* * highly inefficient computation of the imaginary part of complex * conjugate eigenvalues of a 3x3 non-symmetric matrix */ double gage_imaginary_part_eigenvalues( gage_t *M ) { double A, B, C, scale, frob, m[9], _eval[3]; double beta, gamma; int roots; frob = ELL_3M_FROB(M); scale = frob > 10 ? 10.0/frob : 1.0; ELL_3M_SCALE(m, scale, M); /* ** from gordon with mathematica; these are the coefficients of the ** cubic polynomial in x: det(x*I - M). The full cubic is ** x^3 + A*x^2 + B*x + C. */ A = -m[0] - m[4] - m[8]; B = m[0]*m[4] - m[3]*m[1] + m[0]*m[8] - m[6]*m[2] + m[4]*m[8] - m[7]*m[5]; C = (m[6]*m[4] - m[3]*m[7])*m[2] + (m[0]*m[7] - m[6]*m[1])*m[5] + (m[3]*m[1] - m[0]*m[4])*m[8]; roots = ell_cubic(_eval, A, B, C, AIR_TRUE); if ( roots != ell_cubic_root_single ) return 0.; /* 2 complex conjuguate eigenvalues */ beta = A + _eval[0]; gamma = -C/_eval[0]; return sqrt( 4.*gamma - beta*beta ); }
/* ******** ell_3m_eigenvalues_d() ** ** finds eigenvalues of given matrix. ** ** returns information about the roots according to ellCubeRoot enum, ** see header for ellCubic for details. ** ** given matrix is NOT modified ** ** This does NOT use biff ** ** Doing the frobenius normalization proved successfull in avoiding the ** the creating of NaN eigenvalues when the coefficients of the matrix ** were really large (> 50000). Also, when the matrix norm was really ** small, the comparison to "epsilon" in ell_cubic mistook three separate ** roots for a single and a double, with this matrix in particular: ** 1.7421892 0.0137642 0.0152975 ** 0.0137642 1.7565432 -0.0062296 ** 0.0152975 -0.0062296 1.7700019 ** (actually, this is prior to tenEigensolve's isotropic removal) ** ** HEY: tenEigensolve_d and tenEigensolve_f start by removing the ** isotropic part of the tensor. It may be that that smarts should ** be migrated here, but GLK is uncertain how it would change the ** handling of non-symmetric matrices. */ int ell_3m_eigenvalues_d(double _eval[3], const double _m[9], const int newton) { double A, B, C, scale, frob, m[9], eval[3]; int roots; frob = ELL_3M_FROB(_m); scale = frob ? 1.0/frob : 1.0; ELL_3M_SCALE(m, scale, _m); /* printf("!%s: m = %g %g %g; %g %g %g; %g %g %g\n", "ell_3m_eigenvalues_d", m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); */ /* ** from gordon with mathematica; these are the coefficients of the ** cubic polynomial in x: det(x*I - M). The full cubic is ** x^3 + A*x^2 + B*x + C. */ A = -m[0] - m[4] - m[8]; B = m[0]*m[4] - m[3]*m[1] + m[0]*m[8] - m[6]*m[2] + m[4]*m[8] - m[7]*m[5]; C = (m[6]*m[4] - m[3]*m[7])*m[2] + (m[0]*m[7] - m[6]*m[1])*m[5] + (m[3]*m[1] - m[0]*m[4])*m[8]; /* printf("!%s: A B C = %g %g %g\n", "ell_3m_eigenvalues_d", A, B, C); */ roots = ell_cubic(eval, A, B, C, newton); /* no longer need to sort here */ ELL_3V_SCALE(_eval, 1.0/scale, eval); return roots; }
int main(int argc, char **argv) { char buf[512]; double ans0, ans1, ans2, A, B, C; int ret; double r[3]; me = argv[0]; if (argc != 4) { usage(); } sprintf(buf, "%s %s %s", argv[1], argv[2], argv[3]); if (3 != sscanf(buf, "%lf %lf %lf", &A, &B, &C)) { fprintf(stderr, "%s: couldn't parse 3 floats from command line\n", me); exit(1); } ell_debug = AIR_TRUE; ret = ell_cubic(r, A, B, C, AIR_TRUE); ans0 = C + r[0]*(B + r[0]*(A + r[0])); switch(ret) { case ell_cubic_root_single: printf("1 single root: %f -> %f\n", r[0], ans0); break; case ell_cubic_root_triple: printf("1 triple root: %f -> %f\n", r[0], ans0); break; case ell_cubic_root_single_double: ans1 = C + r[1]*(B + r[1]*(A + r[1])); printf("1 single root %f -> %f, 1 double root %f -> %f\n", r[0], ans0, r[1], ans1); break; case ell_cubic_root_three: ans1 = C + r[1]*(B + r[1]*(A + r[1])); ans2 = C + r[2]*(B + r[2]*(A + r[2])); printf("3 distinct roots:\n %f -> %f\n %f -> %f\n %f -> %f\n", r[0], ans0, r[1], ans1, r[2], ans2); break; default: printf("%s: something fatally wacky happened\n", me); exit(1); } exit(0); }