#pragma once #include "functions.h" #include "mat.h" #include "diag_mat.h" #include #include #include "vec.h" #include namespace cgv { namespace math { //if x is an eigen vector of A the rayleigh quotient returns the corresponding eigenvalue template T rayleigh_quotient(mat& A,vec&x) { return dot(x,A*x)/dot(x,x); } template void rot(mat &a, const T s, const T tau, const int i, const int j, const int k, const int l) { T g=a(i,j); T h=a(k,l); a(i,j)=g-s*(h+g*tau); a(k,l)=h+s*(g-h*tau); } template void eigsrt(diag_mat &d, mat &v) { unsigned k; unsigned n=d.size(); for (unsigned i=0;i= p) p=d(k=j); if (k != i) { d(k)=d(i); d(i)=p; for (unsigned j=0;j bool eig_sym(const mat &a, mat &v, diag_mat &d,bool ordering=true, unsigned maxiter=50) { mataa = a; unsigned n =aa.nrows(); v.identity(n); d.resize(n); unsigned nrot=0; const T eps = std::numeric_limits::epsilon(); T tresh,theta,tau,t,sm,s,h,g,c; vec b(n),z; z.zeros(n); unsigned ip,iq; for(unsigned i = 0; i < n; i++) d(i)=b(i)=aa(i,i); for (unsigned i=1;i<=maxiter;i++) { sm=(T)0.0; for (ip=0;ip 4 && g <= eps*std::abs(d(ip)) && g <= eps*std::abs(d(iq))) aa(ip,iq)=(T)0.0; else if (std::abs(aa(ip,iq)) > tresh) { h=d(iq)-d(ip); if (g <= eps*std::abs(h)) t=(aa(ip,iq))/h; else { theta=(T)(0.5*h/(aa(ip,iq))); t=(T)(1.0/(std::abs(theta)+sqrt(1.0+theta*theta))); if (theta < 0.0) t = -t; } c=(T)(1.0/sqrt(1+t*t)); s=t*c; tau=(T)(s/(1.0+c)); h=t*aa(ip,iq); z(ip) -= h; z(iq) += h; d(ip) -= h; d(iq) += h; aa(ip,iq)=(T)0.0; for (unsigned j=0;j struct Unsymmeig { int n; cgv::math::mat a,zz; cgv::math::diag_mat > wri; cgv::math::vec scale; cgv::math::vec perm; bool yesvecs,hessen; Unsymmeig(const cgv::math::mat&aa, bool yesvec=true, bool hessenb=false) : n(aa.nrows()), a(aa), zz(n,n,0.0), wri(n), scale(n), perm(n), yesvecs(yesvec), hessen(hessenb) { scale.ones(); balance(); if (!hessen) elmhes(); if (yesvecs) { for (int i=0;i T SIGN(const T &a, const T &b) {return (T)(b >= 0 ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a));} template void Unsymmeig::balance() { const T RADIX = std::numeric_limits::radix; bool done=false; T sqrdx=RADIX*RADIX; while (!done) { done=true; for (int i=0;ig) { f /= RADIX; c /= sqrdx; } if ((c+r)/f < 0.95*s) { done=false; g=1.0/f; scale[i] *= f; for (int j=0;j void Unsymmeig::balbak() { for (int i=0;i void Unsymmeig::elmhes() { for (int m=1;m std::abs(x)) { x=a(j,m-1); i=j; } } perm[m]=i; if (i != m) { for (int j=m-1;j void Unsymmeig::eltran() { for (int mp=n-2;mp>0;mp--) { for (int k=mp+1;k void Unsymmeig::hqr() { int nn,m,l,k,j,its,i,mmin; T z,y,x,w,v,u,t,s,r,q,p,anorm=0.0; const T EPS=std::numeric_limits::epsilon(); for (i=0;i= 0) { its=0; do { for (l=nn;l>0;l--) { s=std::abs(a(l-1,l-1))+std::abs(a(l,l)); if (s == 0.0) s=anorm; if (std::abs(a(l,l-1)) <= EPS*s) { a(l,l-1) = 0.0; break; } } x=a(nn,nn); if (l == nn) { wri[nn--]=x+t; } else { y=a(nn-1,nn-1); w=a(nn,nn-1)*a(nn-1,nn); if (l == nn-1) { p=0.5*(y-x); q=p*p+w; z=sqrt(std::abs(q)); x += t; if (q >= 0.0) { z=p+SIGN(z,p); wri[nn-1]=wri[nn]=x+z; if (z != 0.0) wri[nn]=x-w/z; } else { wri[nn]=std::complex(x+p,-z); wri[nn-1]=conj(wri[nn]); } nn -= 2; } else { if (its == 30) throw("Too many iterations in hqr"); if (its == 10 || its == 20) { t += x; for (i=0;i=l;m--) { z=a(m,m); r=x-z; s=y-z; p=(r*s-w)/a(m+1,m)+a(m,m+1); q=a(m+1,m+1)-z-r-s; r=a(m+2,m+1); s=std::abs(p)+std::abs(q)+std::abs(r); p /= s; q /= s; r /= s; if (m == l) break; u=std::abs(a(m,m-1))*(std::abs(q)+std::abs(r)); v=std::abs(p)*(std::abs(a(m-1,m-1))+std::abs(z)+std::abs(a(m+1,m+1))); if (u <= EPS*v) break; } for (i=m;i void Unsymmeig::hqr2() { int nn,m,l,k,j,its,i,mmin,na; T z,y,x,w,v,u,t,s,r,q,p,anorm=0.0,ra,sa,vr,vi; const T EPS=std::numeric_limits::epsilon(); for (i=0;i= 0) { its=0; do { for (l=nn;l>0;l--) { s=std::abs(a(l-1,l-1))+std::abs(a(l,l)); if (s == 0.0) s=anorm; if (std::abs(a(l,l-1)) <= EPS*s) { a(l,l-1) = 0.0; break; } } x=a(nn,nn); if (l == nn) { wri(nn)=a(nn,nn)=x+t; nn--; } else { y=a(nn-1,nn-1); w=a(nn,nn-1)*a(nn-1,nn); if (l == nn-1) { p=0.5*(y-x); q=p*p+w; z=sqrt(std::abs(q)); x += t; a(nn,nn)=x; a(nn-1,nn-1)=y+t; if (q >= 0.0) { z=p+SIGN(z,p); wri[nn-1]=wri[nn]=x+z; if (z != 0.0) wri[nn]=x-w/z; x=a(nn,nn-1); s=std::abs(x)+std::abs(z); p=x/s; q=z/s; r=sqrt(p*p+q*q); p /= r; q /= r; for (j=nn-1;j(x+p,-z); wri[nn-1]=std::conj(wri[nn]); } nn -= 2; } else { if (its == 30) throw("Too many iterations in hqr"); if (its == 10 || its == 20) { t += x; for (i=0;i=l;m--) { z=a(m,m); r=x-z; s=y-z; p=(r*s-w)/a(m+1,m)+a(m,m+1); q=a(m+1,m+1)-z-r-s; r=a(m+2,m+1); s=std::abs(p)+std::abs(q)+std::abs(r); p /= s; q /= s; r /= s; if (m == l) break; u=std::abs(a(m,m-1))*(std::abs(q)+std::abs(r)); v=std::abs(p)*(std::abs(a(m-1,m-1))+std::abs(z)+std::abs(a(m+1,m+1))); if (u <= EPS*v) break; } for (i=m;i=0;nn--) { p=real(wri[nn]); q=imag(wri[nn]); na=nn-1; if (q == 0.0) { m=nn; a(nn,nn)=1.0; for (i=nn-1;i>=0;i--) { w=a(i,i)-p; r=0.0; for (j=m;j<=nn;j++) r += a(i,j)*a(j,nn); if (imag(wri[i]) < 0.0) { z=w; s=r; } else { m=i; if (imag(wri[i]) == 0.0) { t=w; if (t == 0.0) t=EPS*anorm; a(i,nn)=-r/t; } else { x=a(i,i+1); y=a(i+1,i); q=cgv::math::sqr(real(wri[i])-p)+cgv::math::sqr(imag(wri[i])); t=(x*s-z*r)/q; a(i,nn)=t; if (std::abs(x) > std::abs(z)) a(i+1,nn)=(-r-w*t)/x; else a(i+1,nn)=(-s-y*t)/z; } t=std::abs(a(i,nn)); if (EPS*t*t > 1) for (j=i;j<=nn;j++) a(j,nn) /= t; } } } else if (q < 0.0) { m=na; if (std::abs(a(nn,na)) > std::abs(a(na,nn))) { a(na,na)=q/a(nn,na); a(na,nn)=-(a(nn,nn)-p)/a(nn,na); } else { std::complex temp=std::complex(0.0,-a(na,nn))/std::complex(a(na,na)-p,q); a(na,na)=real(temp); a(na,nn)=imag(temp); } a(nn,na)=0.0; a(nn,nn)=1.0; for (i=nn-2;i>=0;i--) { w=a(i,i)-p; ra=sa=0.0; for (j=m;j<=nn;j++) { ra += a(i,j)*a(j,na); sa += a(i,j)*a(j,nn); } if (imag(wri[i]) < 0.0) { z=w; r=ra; s=sa; } else { m=i; if (imag(wri[i]) == 0.0) { std::complex temp = std::complex(-ra,-sa)/std::complex(w,q); a(i,na)=real(temp); a(i,nn)=imag(temp); } else { x=a(i,i+1); y=a(i+1,i); vr=cgv::math::sqr(real(wri(i))-p)+cgv::math::sqr(imag(wri(i)))-q*q; vi=2.0*q*(real(wri(i))-p); if (vr == 0.0 && vi == 0.0) vr=EPS*anorm*(std::abs(w)+std::abs(q)+std::abs(x)+std::abs(y)+std::abs(z)); std::complex temp=std::complex(x*r-z*ra+q*sa,x*s-z*sa-q*ra)/ std::complex(vr,vi); a(i,na)=real(temp); a(i,nn)=imag(temp); if (std::abs(x) > std::abs(z)+std::abs(q)) { a(i+1,na)=(-ra-w*a(i,na)+q*a(i,nn))/x; a(i+1,nn)=(-sa-w*a(i,nn)-q*a(i,na))/x; } else { std::complex temp=std::complex(-r-y*a(i,na),-s-y*a(i,nn))/ std::complex(z,q); a(i+1,na)=real(temp); a(i+1,nn)=imag(temp); } } } t=std::max(std::abs(a(i,na)),std::abs(a(i,nn))); if (EPS*t*t > 1) for (j=i;j<=nn;j++) { a(j,na) /= t; a(j,nn) /= t; } } } } for (j=n-1;j>=0;j--) for (i=0;i void Unsymmeig::sort() { int i; for (int j=1;j x=wri[j]; for (i=j-1;i>=0;i--) { if (std::real(wri[i]) >= real(x)) break; wri[i+1]=wri[i]; } wri[i+1]=x; } } template void Unsymmeig::sortvecs() { int i; cgv::math::vec temp(n); for (int j=1;j x=wri[j]; for (int k=0;k=0;i--) { if (real(wri[i]) >= std::real(x)) break; wri[i+1]=wri[i]; for (int k=0;k void eig_unsym(const cgv::math::mat &a,cgv::math::diag_mat >& eigvals, bool hessenb=false) { Unsymmeig eigsolver((cgv::math::mat)a,false,hessenb); eigvals = eigsolver.wri; } //compute eigenvectors and eigenvalues of matrix a which is a real unsymmetric matrix //if a is still in hessenberg form set hessenb to true (default is false) //eigenvectors are not normalized template void eig_unsym(const cgv::math::mat& a,cgv::math::mat& eigvecs,cgv::math::diag_mat >& eigvals,bool normalize=true, bool hessenb=false) { cgv::math::mat A=a; Unsymmeig eigsolver(A,true,hessenb); eigvals = eigsolver.wri; if(normalize) { for(unsigned i = 0; i < eigsolver.zz.ncols();i++) eigsolver.zz.set_col(i,cgv::math::normalize(eigsolver.zz.col(i))); } eigvecs=eigsolver.zz; } }}