/* Author: G. Jungman * RCS: $Id: jacobi.c,v 1.1 1999/10/19 11:15:05 bjg Exp $ */ /* Simple linear algebra operations, operating directly * on the gsl_vector and gsl_matrix objects. These are * meant for "generic" and "small" systems. Anyone * interested in large systems will want to use more * sophisticated methods, presumably involving native * BLAS operations, specialized data representations, * or other optimizations. */ #include #include #include #include #include #include #include "gsl_eigen.h" #define REAL double inline static void jac_rotate(gsl_matrix * a, int i, int j, int k, int l, double * g, double * h, double s, double tau) { *g = gsl_matrix_get(a, i, j); *h = gsl_matrix_get(a, k, l); gsl_matrix_set(a, i, j, (*g) - s*((*h) + (*g)*tau)); gsl_matrix_set(a, k, l, (*h) + s*((*g) - (*h)*tau)); } int gsl_eigen_jacobi_impl(gsl_matrix * a, gsl_vector * eval, gsl_matrix * evec, unsigned int max_rot, unsigned int * nrot) { if(a == 0 || eval == 0 || evec == 0) { return GSL_EFAULT; } else if(a->size1 != a->size2) { return GSL_ENOTSQR; } else if(a->size1 != evec->size1 || a->size1 != evec->size2) { return GSL_EBADLEN; } else if(a->size1 != eval->size) { return GSL_EBADLEN; } else { const int n = a->size1; unsigned int i; int j, iq, ip; double t, s; REAL * b = (REAL *) malloc(n * sizeof(REAL)); REAL * z = (REAL *) malloc(n * sizeof(REAL)); if(b == 0 || z == 0) { if(b != 0) free(b); if(z != 0) free(z); return GSL_ENOMEM; } /* Set eigenvectors to coordinate basis. */ for(ip=0; ip 4 && fabs(d_ip)+g == fabs(d_ip) && fabs(d_iq)+g == fabs(d_iq) ) { gsl_matrix_set(a, ip, iq, 0.0); } else if(fabs(a_ipiq) > thresh) { h = d_iq - d_ip; if(fabs(h) + g == fabs(h)) { t = a_ipiq/h; } else { REAL theta = 0.5*h/a_ipiq; t = 1.0/(fabs(theta) + sqrt(1.0 + theta*theta)); if(theta < 0.0) t = -t; } c = 1.0/sqrt(1.0+t*t); s = t*c; tau = s/(1.0+c); h = t * a_ipiq; z[ip] -= h; z[iq] += h; gsl_vector_set(eval, ip, d_ip - h); gsl_vector_set(eval, iq, d_iq + h); gsl_matrix_set(a, ip, iq, 0.0); for(j=0; j<=ip-1; j++){ jac_rotate(a, j, ip, j, iq, &g, &h, s, tau); } for(j=ip+1; j<=iq-1; j++){ jac_rotate(a, ip, j, j, iq, &g, &h, s, tau); } for(j=iq+1; jsize1 != a->size2 || ainv->size1 != ainv->size2) { return GSL_ENOTSQR; } else if(a->size1 != ainv->size2) { return GSL_EBADLEN; } else { const int n = a->size1; unsigned int nrot; int i,j,k,l; /* This is annoying because I do not want * the error handling in these functions. * But there are no "impl"-like versions * of these allocators... sigh. */ gsl_vector * eval = gsl_vector_alloc(n); gsl_matrix * evec = gsl_matrix_alloc(n, n); gsl_matrix * inv_diag = gsl_matrix_alloc(n, n); if(eval == 0 || evec == 0 || inv_diag == 0) { if(eval != 0) gsl_vector_free(eval); if(evec != 0) gsl_matrix_free(evec); if(inv_diag != 0) gsl_matrix_free(inv_diag); return GSL_ENOMEM; } memcpy(ainv->data, a->data, n*n*sizeof(REAL)); gsl_eigen_jacobi_impl(ainv, eval, evec, max_rot, &nrot); for(i=0; i