/* miscmaths.cc Mark Jenkinson, Mark Woolrich, Christian Beckmann, Tim Behrens and Matthew Webster, FMRIB Image Analysis Group Copyright (C) 1999-2009 University of Oxford */ /* CCOPYRIGHT */ // Miscellaneous maths functions #define NOMINMAX #include #include #include #include "miscmaths.h" #include "miscprob.h" #include "stdlib.h" #include "newmatio.h" using namespace std; namespace MISCMATHS { // The following lines are ignored by the current SGI compiler // (version egcs-2.91.57) // A temporary fix of including the std:: in front of all abs() etc // has been done for now using std::abs; using std::sqrt; using std::exp; using std::log; // using std::pow; using std::atan2; string size(const Matrix& mat) { string str = num2str(mat.Nrows())+"*"+num2str(mat.Ncols()); return str; } float Sinc(const float x) { if (fabs(x)<1e-9) { return 1-x*x*M_PI*M_PI/6.0; } else { return sin(M_PI*x)/(M_PI*x); } } double Sinc(const double x) { if (fabs(x)<1e-9) { return 1-x*x*M_PI*M_PI/6.0; } else { return sin(M_PI*x)/(M_PI*x); } } // General string/IO functions bool isNumber( const string& input) { if (input.size()==0) return false; char *pend; strtod(input.c_str(),&pend); if (*pend!='\0') return false; return true; } string skip_alpha(ifstream& fs) { string cline; while (!fs.eof()) { streampos curpos = fs.tellg(); getline(fs,cline); cline += " "; // force extra entry in parsing istringstream ss(cline.c_str()); string firstToken=""; ss >> firstToken; //Put first non-whitespace sequence into cc if (isNumber(firstToken)) { if (!fs.eof()) { fs.seekg(curpos); } else { fs.clear(); fs.seekg(0,ios::beg); } return cline; } } return ""; } ReturnMatrix read_ascii_matrix(int nrows, int ncols, const string& filename) { return read_ascii_matrix(filename,nrows,ncols); } ReturnMatrix read_ascii_matrix(const string& filename, int nrows, int ncols) { Matrix mat(nrows,ncols); mat = 0.0; if ( filename.size()<1 ) return mat; ifstream fs(filename.c_str()); if (!fs) { cerr << "Could not open matrix file " << filename << endl; return mat; } mat = read_ascii_matrix(fs,nrows,ncols); fs.close(); mat.Release(); return mat; } ReturnMatrix read_ascii_matrix(int nrows, int ncols, ifstream& fs) { return read_ascii_matrix(fs, nrows, ncols); } ReturnMatrix read_ascii_matrix(ifstream& fs, int nrows, int ncols) { Matrix mat(nrows,ncols); mat = 0.0; string ss=""; ss = skip_alpha(fs); for (int r=1; r<=nrows; r++) { for (int c=1; c<=ncols; c++) { if (!fs.eof()) { fs >> ss; while ( !isNumber(ss) && !fs.eof() ) { fs >> ss; } mat(r,c) = atof(ss.c_str()); } } } mat.Release(); return mat; } ReturnMatrix read_ascii_matrix(const string& filename) { Matrix mat; if ( filename.size()<1 ) return mat; ifstream fs(filename.c_str()); if (!fs) { cerr << "Could not open matrix file " << filename << endl; mat.Release(); return mat; } mat = read_ascii_matrix(fs); fs.close(); mat.Release(); return mat; } ReturnMatrix read_ascii_matrix(ifstream& fs) { int nRows(0), nColumns(0); string currentLine; // skip initial non-numeric lines // and count the number of columns in the first numeric line currentLine = skip_alpha(fs); currentLine += " "; { istringstream ss(currentLine.c_str()); string dummyToken=""; while (!ss.eof()) { nColumns++; ss >> dummyToken; } } nColumns--; do { getline(fs,currentLine); currentLine += " "; // force extra entry in parsing istringstream ss(currentLine.c_str()); string firstToken(""); ss >> firstToken; //Put first non-whitespace sequence into cc if (!isNumber(firstToken)) break; // stop processing when non-numeric line found nRows++; // add new row to matrix } while (!fs.eof()); // now know the size of matrix fs.clear(); fs.seekg(0,ios::beg); return read_ascii_matrix(fs,nRows,nColumns); } #define BINFLAG 42 ReturnMatrix read_binary_matrix(const string& filename) { Matrix mres; read_binary_matrix(mres,filename); mres.Release(); return mres; } int read_binary_matrix(Matrix& mres, const string& filename) { if ( filename.size()<1 ) return 1; ifstream fs(filename.c_str(), ios::in | ios::binary); if (!fs) { cerr << "Could not open matrix file " << filename << endl; return 2; } read_binary_matrix(mres,fs); fs.close(); return 0; } ReturnMatrix read_binary_matrix(ifstream& fs) { Matrix mres; read_binary_matrix(mres,fs); mres.Release(); return mres; } int read_binary_matrix(Matrix& mres, ifstream& fs) { bool swapbytes = false; unsigned int testval; // test for byte swapping fs.read((char*)&testval,sizeof(testval)); if (testval!=BINFLAG) { swapbytes = true; Swap_Nbytes(1,sizeof(testval),&testval); if (testval!=BINFLAG) { cerr << "Unrecognised binary matrix file format" << endl; return 2; } } // read matrix dimensions (num rows x num cols) unsigned int ival,nx,ny; fs.read((char*)&ival,sizeof(ival)); // ignore the padding (reserved for future use) fs.read((char*)&ival,sizeof(ival)); if (swapbytes) Swap_Nbytes(1,sizeof(ival),&ival); nx = ival; fs.read((char*)&ival,sizeof(ival)); if (swapbytes) Swap_Nbytes(1,sizeof(ival),&ival); ny = ival; // set up and read matrix (rows fast, cols slow) double val; if ( (((unsigned int) mres.Ncols())0) { fs.precision(precision); } else { fs.precision(10); // default precision } #ifdef PPC64 int n=0; #endif for (int i=1; i<=mat.Nrows(); i++) { for (int j=1; j<=mat.Ncols(); j++) { fs << mat(i,j) << " "; #ifdef PPC64 if ((n++ % 50) == 0) fs.flush(); #endif } fs << endl; } return 0; } int write_vest(string p_fname, const Matrix& x, int precision) { return write_vest(x,p_fname,precision); } int write_vest(const Matrix& x, string p_fname, int precision) { ofstream out; out.open(p_fname.c_str(), ios::out); if(!out) { cerr << "Unable to open " << p_fname << endl; return -1; } out << "! VEST-Waveform File" << endl; out << "/NumWaves\t" << x.Ncols() << endl; out << "/NumPoints\t" << x.Nrows() << endl; out << "/Skip" << endl; out << endl << "/Matrix" << endl; int retval = write_ascii_matrix(x, out, precision); out.close(); return retval; } int write_binary_matrix(const Matrix& mat, const string& filename) { Tracer tr("write_binary_matrix"); if ( (filename.size()<1) ) return -1; ofstream fs(filename.c_str(), ios::out | ios::binary); if (!fs) { cerr << "Could not open file " << filename << " for writing" << endl; return -1; } int retval = write_binary_matrix(mat,fs); fs.close(); return retval; } int write_binary_matrix(const Matrix& mat, ofstream& fs) { unsigned int ival, nx, ny; ival = BINFLAG; fs.write((char*)&ival,sizeof(ival)); ival = 0; // padding (reserved for future use) fs.write((char*)&ival,sizeof(ival)); ival = mat.Nrows(); fs.write((char*)&ival,sizeof(ival)); ival = mat.Ncols(); fs.write((char*)&ival,sizeof(ival)); nx = mat.Nrows(); ny = mat.Ncols(); double val; #ifdef PPC64 int n=0; #endif for (unsigned int y=1; y<=ny; y++) { for (unsigned int x=1; x<=nx; x++) { val = mat(x,y); fs.write((char*)&val,sizeof(val)); #ifdef PPC64 if ((n++ % 50) == 0) fs.flush(); #endif } } return 0; } // General mathematical functions int round(int x) { return x; } int round(float x) { if (x>0.0) return ((int) (x+0.5)); else return ((int) (x-0.5)); } int round(double x) { if (x>0.0) return ((int) (x+0.5)); else return ((int) (x-0.5)); } double rounddouble(double x){ return ( floor(x+0.5)); } int periodicclamp(int x, int x1, int x2) { if (x2=0) { return (xp % d) + x1; } else { xp = xp + d + std::abs(xp/d)*d; assert(xp>0); return periodicclamp(xp + d + std::abs(xp/d)*d,x1,x2); } } ColumnVector cross(const ColumnVector& a, const ColumnVector& b) { Tracer tr("cross"); ColumnVector ans(3); ans(1) = a(2)*b(3) - a(3)*b(2); ans(2) = a(3)*b(1) - a(1)*b(3); ans(3) = a(1)*b(2) - a(2)*b(1); return ans; } ColumnVector cross(const Real *a, const Real *b) { Tracer tr("cross"); ColumnVector a1(3), b1(3); a1 << a; b1 << b; return cross(a1,b1); } double norm2(const ColumnVector& x) { return std::sqrt(x.SumSquare()); } double norm2sq(double a, double b, double c) { return a*a + b*b + c*c; } float norm2sq(float a, float b, float c) { return a*a + b*b + c*c; } int diag(Matrix& m, const float diagvals[]) { Tracer tr("diag"); m=0.0; for (int j=1; j<=m.Nrows(); j++) m(j,j)=diagvals[j-1]; return 0; } int diag(DiagonalMatrix& m, const ColumnVector& diagvals) { Tracer tr("diag"); m.ReSize(diagvals.Nrows()); m=0.0; for (int j=1; j<=diagvals.Nrows(); j++) m(j)=diagvals(j); return 0; } int diag(Matrix& m, const ColumnVector& diagvals) { Tracer tr("diag"); m.ReSize(diagvals.Nrows(),diagvals.Nrows()); m=0.0; for (int j=1; j<=diagvals.Nrows(); j++) m(j,j)=diagvals(j); return 0; } ReturnMatrix diag(const Matrix& Mat) { Tracer tr("diag"); if(Mat.Ncols()==1){ Matrix retmat(Mat.Nrows(),Mat.Nrows()); diag(retmat,Mat); retmat.Release(); return retmat;} else{ int mindim = Min(Mat.Ncols(),Mat.Nrows()); Matrix retmat(mindim,1); for(int ctr=1; ctr<=mindim;ctr++){ retmat(ctr,1)=Mat(ctr,ctr); } retmat.Release(); return retmat; } } ReturnMatrix pinv(const Matrix& mat2) { // calculates the psuedo-inverse using SVD // note that the right-pinv(x') = pinv(x).t() Matrix mat(mat2); if ( mat2.Ncols() > mat2.Nrows() ) mat=mat.t(); Tracer tr("pinv"); DiagonalMatrix D; Matrix U, V; SVD(mat,D,U,V); float tol; tol = MaximumAbsoluteValue(D) * Max(mat.Nrows(),mat.Ncols()) * 1e-16; for (int n=1; n<=D.Nrows(); n++) { if (fabs(D(n,n))>tol) D(n,n) = 1.0/D(n,n); else D(n,n) = 0.0; // reduce the number of columns because too close to singular } Matrix pinv = V * D * U.t(); if ( mat2.Ncols() > mat2.Nrows() ) pinv=pinv.t(); pinv.Release(); return pinv; } int rank(const Matrix& X) { // calculates the rank of matrix X Tracer tr("rank"); DiagonalMatrix eigenvals; SVD(X,eigenvals); double tolerance = Max(X.Nrows(),X.Ncols()) * eigenvals.Maximum() * 1e-16; int therank=0; for(int i=0; itolerance) therank++; // cout << "tolerance = " << tolerance << "\n" << "eigenvalues = " << eigenvals << "\n" << "rank = " << therank << endl; return therank; } ReturnMatrix sqrtaff(const Matrix& mat) { Tracer tr("sqrtaff"); Matrix matnew(4,4), rot, id4; rot=IdentityMatrix(4); id4=IdentityMatrix(4); ColumnVector params(12), centre(3), trans(4); centre = 0.0; // Quaternion decomposition -> params(1..3) = sin(theta/2)*(unit_axis_vec) // Want a new quaternion : q = sin(theta/4)*(unit_axis_vec) // Therefore factor of conversion is: factor = sin(theta/4)/sin(theta/2) // = 1/(2 * cos(theta/4)) which is calculated below // NB: t = theta/2 decompose_aff(params,mat,centre,rotmat2quat); double sint; sint = std::sqrt(params(1)*params(1) + params(2)*params(2) + params(3)*params(3)); double t = asin(sint); double factor = 1.0/(2.0*cos(0.5*t)); params(1) = factor * params(1); params(2) = factor * params(2); params(3) = factor * params(3); params(7) = std::sqrt(params(7)); params(8) = std::sqrt(params(8)); params(9) = std::sqrt(params(9)); params(10) = 0.5*params(10); params(11) = 0.5*params(11); params(12) = 0.5*params(12); construct_rotmat_quat(params,3,rot,centre); rot(1,4) = 0.0; rot(2,4) = 0.0; rot(3,4) = 0.0; Matrix scale=IdentityMatrix(4); scale(1,1)=params(7); scale(2,2)=params(8); scale(3,3)=params(9); Matrix skew=IdentityMatrix(4); skew(1,2)=params(10); skew(1,3)=params(11); skew(2,3)=params(12); trans(1) = params(4); trans(2) = params(5); trans(3) = params(6); trans(4) = 1.0; // The translation, being independent of the 3x3 submatrix, is // calculated so that it will be equal for each of the two // halves of the approximate square root // (i.e. matnew and mat*matnew.i() have exactly the same translation) ColumnVector th(4); th = (mat*scale.i()*skew.i()*rot.i() + id4).SubMatrix(1,3,1,3).i() * trans.SubMatrix(1,3,1,1); matnew = rot*skew*scale; matnew(1,4) = th(1); matnew(2,4) = th(2); matnew(3,4) = th(3); matnew.Release(); return matnew; } vector get_sortindex(const Matrix& vals, const string& mode, int col) { // mode is either "new2old" or "old2new" // return the mapping of old and new indices in the *ascending* sort of vals (from column=col) int length=vals.Nrows(); vector > sortlist(length); for (int n=0; n((double) vals(n+1,col),n+1); } sort(sortlist.begin(),sortlist.end()); // O(N.log(N)) vector idx(length); for (int n=0; nnrows) { rc++; rr=1; } } } } ReturnMatrix reshape(const Matrix& m, int nrows, int ncols) { Tracer tr("reshape"); Matrix r; reshape(r,m,nrows,ncols); r.Release(); return r; } int addrow(Matrix& m, int ncols) { if (m.Nrows()==0) { Matrix mm(1,ncols); mm=0; m = mm; } else { Matrix mm(m.Nrows()+1,ncols); mm = 0; mm.SubMatrix(1,m.Nrows(),1,ncols) = m; m = mm; } return 0; } //------------------------------------------------------------------------// // Spatial transformation functions (rotations and affine transforms) int construct_rotmat_euler(const ColumnVector& params, int n, Matrix& aff, const ColumnVector& centre) { Tracer tr("construct_rotmat_euler"); ColumnVector angl(3); Matrix newaff(4,4); aff=IdentityMatrix(4); if (n<=0) return 0; // order of parameters is 3 rotation + 3 translation // angles are in radians // order of parameters is (Rx,Ry,Rz) and R = Rx.Ry.Rz angl=0.0; angl(1)=params(1); make_rot(angl,centre,newaff); aff = aff * newaff; if (n==1) return 0; angl=0.0; angl(2)=params(2); make_rot(angl,centre,newaff); aff = aff * newaff; if (n==2) return 0; angl=0.0; angl(3)=params(3); make_rot(angl,centre,newaff); aff = aff * newaff; if (n==3) return 0; aff(1,4)+=params(4); if (n==4) return 0; aff(2,4)+=params(5); if (n==5) return 0; aff(3,4)+=params(6); if (n==6) return 0; return 1; } int construct_rotmat_euler(const ColumnVector& params, int n, Matrix& aff) { Tracer tr("construct_rotmat_euler"); ColumnVector centre(3); centre = 0.0; return construct_rotmat_euler(params,n,aff,centre); } int construct_rotmat_quat(const ColumnVector& params, int n, Matrix& aff, const ColumnVector& centre) { Tracer tr("construct_rotmat_quat"); aff=IdentityMatrix(4); if (n<=0) return 0; // order of parameters is 3 rotation (last 3 quaternion components) // + 3 translation if ((n>=1) && (n<3)) { cerr<<"Can only do 3 or more, not "<< n < 1e-4) { cerr << "Failed orthogonality check!" << endl; return -1; } Matrix u(3,3), v(3,3); DiagonalMatrix d(3); SVD(rotmat-IdentityMatrix(3),d,u,v); // return column of V corresponding to minimum value of |S| for (int i=1; i<=3; i++) { if (fabs(d(i))<1e-4) axis = v.SubMatrix(1,3,i,i); } return 0; } int rotmat2euler(ColumnVector& angles, const Matrix& rotmat) { // uses the convention that R = Rx.Ry.Rz Tracer tr("rotmat2euler"); float cz, sz, cy, sy, cx, sx; cy = std::sqrt(Sqr(rotmat(1,1)) + Sqr(rotmat(1,2))); if (cy < 1e-4) { //cerr << "Cos y is too small - Gimbal lock condition..." << endl; cx = rotmat(2,2); sx = -rotmat(3,2); sy = -rotmat(1,3); angles(1) = atan2(sx,cx); angles(2) = atan2(sy,(float)0.0); angles(3) = 0.0; } else { // choose by convention that cy > 0 // get the same rotation if: sy stays same & all other values swap sign cz = rotmat(1,1)/cy; sz = rotmat(1,2)/cy; cx = rotmat(3,3)/cy; sx = rotmat(2,3)/cy; sy = -rotmat(1,3); //atan2(sin,cos) (defined as atan2(y,x)) angles(1) = atan2(sx,cx); angles(2) = atan2(sy,cy); angles(3) = atan2(sz,cz); } return 0; } int rotmat2quat(ColumnVector& quaternion, const Matrix& rotmat) { Tracer tr("rotmat2quat"); float trace = rotmat.SubMatrix(1,3,1,3).Trace(); if (trace > 0) { float w = std::sqrt((trace + 1.0)/4.0); quaternion(1) = (rotmat(3,2) - rotmat(2,3))/(4.0*w); quaternion(2) = (rotmat(1,3) - rotmat(3,1))/(4.0*w); quaternion(3) = (rotmat(2,1) - rotmat(1,2))/(4.0*w); } else if ((rotmat(1,1) > rotmat(2,2)) && (rotmat(1,1) > rotmat(3,3))) { // first col case float s = std::sqrt(1.0 + rotmat(1,1) - rotmat(2,2) - rotmat(3,3)) * 2.0; quaternion(1) = 0.5 / s; quaternion(2) = (-rotmat(1,2) - rotmat(1,2)) / s; quaternion(3) = (-rotmat(1,3) - rotmat(3,1)) / s; } else if ((rotmat(2,2) > rotmat(1,1)) && (rotmat(2,2) > rotmat(3,3))) { // 2nd col case float s = std::sqrt(1.0 + rotmat(2,2) - rotmat(1,1) - rotmat(3,3)) * 2.0; quaternion(1) = (-rotmat(1,2) - rotmat(2,1)) / s; quaternion(2) = 0.5 / s; quaternion(3) = (-rotmat(2,3) - rotmat(3,2)) / s; } else if ((rotmat(3,3) > rotmat(1,1)) && (rotmat(3,3) > rotmat(2,2))) { // 3rd col case float s = std::sqrt(1.0 + rotmat(3,3) - rotmat(1,1) - rotmat(2,2)) * 2.0; quaternion(1) = (-rotmat(1,3) - rotmat(3,1)) / s; quaternion(2) = (-rotmat(2,3) - rotmat(3,2)) / s; quaternion(3) = 0.5 / s; } return 0; } int decompose_aff(ColumnVector& params, const Matrix& affmat, const ColumnVector& centre, int (*rotmat2params)(ColumnVector& , const Matrix& )) { // decomposes using the convention: mat = rotmat * skew * scale // order of parameters is 3 rotation + 3 translation + 3 scales + 3 skews // angles are in radians Tracer tr("decompose_aff"); if (params. Nrows() < 12) params.ReSize(12); if (rotmat2params==0) { cerr << "No rotmat2params function specified" << endl; return -1; } ColumnVector x(3), y(3), z(3); Matrix aff3(3,3); aff3 = affmat.SubMatrix(1,3,1,3); x = affmat.SubMatrix(1,3,1,1); y = affmat.SubMatrix(1,3,2,2); z = affmat.SubMatrix(1,3,3,3); float sx, sy, sz, a, b, c; sx = norm2(x); sy = std::sqrt( dot(y,y) - (Sqr(dot(x,y)) / Sqr(sx)) ); a = dot(x,y)/(sx*sy); ColumnVector x0(3), y0(3); x0 = x/sx; y0 = y/sy - a*x0; sz = std::sqrt(dot(z,z) - Sqr(dot(x0,z)) - Sqr(dot(y0,z))); b = dot(x0,z)/sz; c = dot(y0,z)/sz; params(7) = sx; params(8) = sy; params(9) = sz; Matrix scales(3,3); float diagvals[] = {sx,sy,sz}; diag(scales,diagvals); Real skewvals[] = {1,a,b,0 , 0,1,c,0 , 0,0,1,0 , 0,0,0,1}; Matrix skew(4,4); skew << skewvals; params(10) = a; params(11) = b; params(12) = c; Matrix rotmat(3,3); rotmat = aff3 * scales.i() * (skew.SubMatrix(1,3,1,3)).i(); ColumnVector transl(3); transl = affmat.SubMatrix(1,3,1,3)*centre + affmat.SubMatrix(1,3,4,4) - centre; for (int i=1; i<=3; i++) { params(i+3) = transl(i); } ColumnVector rotparams(3); (*rotmat2params)(rotparams,rotmat); for (int i=1; i<=3; i++) { params(i) = rotparams(i); } return 0; } int decompose_aff(ColumnVector& params, const Matrix& affmat, int (*rotmat2params)(ColumnVector& , const Matrix& )) { Tracer tr("decompose_aff"); ColumnVector centre(3); centre = 0.0; return decompose_aff(params,affmat,centre,rotmat2params); } int compose_aff(const ColumnVector& params, int n, const ColumnVector& centre, Matrix& aff, int (*params2rotmat)(const ColumnVector& , int , Matrix& , const ColumnVector& ) ) { Tracer tr("compose_aff"); if (n<=0) return 0; // order of parameters is 3 rotation + 3 translation + 3 scales + 3 skews // angles are in radians (*params2rotmat)(params,n,aff,centre); if (n<=6) return 0; Matrix scale=IdentityMatrix(4); if (n>=7) { scale(1,1)=params(7); if (n>=8) scale(2,2)=params(8); else scale(2,2)=params(7); if (n>=9) scale(3,3)=params(9); else scale(3,3)=params(7); } // fix the translation so that the centre is not moved ColumnVector strans(3); strans = centre - scale.SubMatrix(1,3,1,3)*centre; scale.SubMatrix(1,3,4,4) = strans; Matrix skew=IdentityMatrix(4); if (n>=10) { if (n>=10) skew(1,2)=params(10); if (n>=11) skew(1,3)=params(11); if (n>=12) skew(2,3)=params(12); } // fix the translation so that the centre is not moved ColumnVector ktrans(3); ktrans = centre - skew.SubMatrix(1,3,1,3)*centre; skew.SubMatrix(1,3,4,4) = ktrans; aff = aff * skew * scale; return 0; } float rms_deviation(const Matrix& affmat1, const Matrix& affmat2, const ColumnVector& centre, const float rmax) { Tracer trcr("rms_deviation"); Matrix isodiff(4,4), a1(4,4), a2(4,4); if ((affmat1.Nrows()==4) && (affmat1.Ncols()==4)) { a1=affmat1; } else if ((affmat1.Nrows()==3) && (affmat1.Ncols()==3)) { a1=IdentityMatrix(4); a1.SubMatrix(1,3,1,3)=affmat1; } else { cerr << "ERROR:: Can only calculate RMS deviation for 4x4 or 3x3 matrices" << endl; exit(-5); } if ((affmat2.Nrows()==4) && (affmat2.Ncols()==4)) { a2=affmat2; } else if ((affmat2.Nrows()==3) && (affmat2.Ncols()==3)) { a2=IdentityMatrix(4); a2.SubMatrix(1,3,1,3)=affmat2; } else { cerr << "ERROR:: Can only calculate RMS deviation for 4x4 or 3x3 matrices" << endl; exit(-5); } try { isodiff = a1*a2.i() - IdentityMatrix(4); } catch(...) { cerr << "RMS_DEVIATION ERROR:: Could not invert matrix" << endl; exit(-5); } Matrix adiff(3,3); adiff = isodiff.SubMatrix(1,3,1,3); ColumnVector tr(3); tr = isodiff.SubMatrix(1,3,4,4) + adiff*centre; float rms = std::sqrt( (tr.t() * tr).AsScalar() + (rmax*rmax/5.0)*Trace(adiff.t()*adiff) ); return rms; } float rms_deviation(const Matrix& affmat1, const Matrix& affmat2, const float rmax) { ColumnVector centre(3); centre = 0; return rms_deviation(affmat1,affmat2,centre,rmax); } // helper function - calls nifti, but with FSL default case Matrix Mat44ToNewmat(mat44 m) { Matrix r(4,4); for(unsigned short i = 0; i < 4; ++i) for(unsigned short j = 0; j < 4; ++j) r(i+1, j+1) = m.m[i][j]; return r; } mat44 NewmatToMat44(const Matrix& m) { mat44 r; for(unsigned short i = 0; i < 4; ++i) for(unsigned short j = 0; j < 4; ++j) r.m[i][j] = m(i+1, j+1); return r; } void get_axis_orientations(const Matrix& sform_mat, int sform_code, const Matrix& qform_mat, int qform_code, int& icode, int& jcode, int& kcode) { Matrix vox2mm(4,4); if (sform_code!=NIFTI_XFORM_UNKNOWN) { vox2mm = sform_mat; } else if (qform_code!=NIFTI_XFORM_UNKNOWN) { vox2mm = qform_mat; } else { // ideally should be sampling_mat(), but for orientation it doesn't matter vox2mm = IdentityMatrix(4); vox2mm(1,1) = -vox2mm(1,1); } mat44 v2mm; for (int ii=0; ii<4; ii++) { for (int jj=0; jj<4; jj++) { v2mm.m[ii][jj] = vox2mm(ii+1,jj+1); } } nifti_mat44_to_orientation(v2mm,&icode,&jcode,&kcode); } Matrix mat44_to_newmat(mat44 inmat) { Matrix retmat(4,4); for (int ii=0; ii<4; ii++) { for (int jj=0; jj<4; jj++) { retmat(ii+1,jj+1) = inmat.m[ii][jj]; } } return retmat; } mat44 newmat_to_mat44(const Matrix& inmat) { mat44 retmat; for (int ii=0; ii<4; ii++) { for (int jj=0; jj<4; jj++) { retmat.m[ii][jj] = inmat(ii+1,jj+1); } } return retmat; } // Matlab style functions for percentiles, quantiles and median // AUG 06 CB ColumnVector seq(const int size) { ColumnVector outputVector(size); for(int i=1; i<=size; i++) outputVector(i) = i; return outputVector; } float interp1(const ColumnVector& x, const ColumnVector& y, float xi) // Look-up function for data table defined by x, y // Returns the values yi at xi using linear interpolation // Assumes that x is sorted in ascending order { float ans; if(xi >= x.Maximum()) ans = y(x.Nrows()); else if(xi <= x.Minimum()) ans = y(1); else{ int ind=2; while(xi >= x(ind)) { ind++; } float xa = x(ind-1), xb = x(ind), ya = y(ind-1), yb = y(ind); ans = ya + (xi - xa)/(xb - xa) * (yb - ya); } return ans; } float quantile(const ColumnVector& in, int which) { float p; switch (which) { case 0 : p = 0.0; break; case 1 : p = 25.0; break; case 2 : p = 50.0; break; case 3 : p = 75.0; break; case 4 : p =100.0; break; default: p = 0.0; } return percentile(in,p); } float percentile(const ColumnVector& in, float p) { ColumnVector y = in; SortAscending(y); int num = y.Nrows(); ColumnVector xx,yy,sequence,a(1),b(1),c(1),d(1); sequence = 100*(seq(num)-0.5)/num; a << y(1); b << y(num); c = 0; d = 100; xx = (c & sequence & d); yy = (a & y & b); return interp1(xx,yy,p); } ReturnMatrix quantile(const Matrix& in, int which) { int num = in.Ncols(); Matrix res(1,num); for (int ctr=1; ctr<=num; ctr++){ ColumnVector tmp = in.Column(ctr); res(1,ctr) = quantile(tmp,which); } res.Release(); return res; } ReturnMatrix percentile(const Matrix& in, float p) { int num = in.Ncols(); Matrix res(1,num); for (int ctr=1; ctr<=num; ctr++){ ColumnVector tmp = in.Column(ctr); res(1,ctr) = percentile(tmp,p); } res.Release(); return res; } void cart2sph(const ColumnVector& dir, float& th, float& ph) { float mag=sqrt(dir(1)*dir(1)+dir(2)*dir(2)+dir(3)*dir(3)); if(mag==0){ ph=M_PI/2; th=M_PI/2; } else{ if(dir(1)==0 && dir(2)>=0) ph=M_PI/2; else if(dir(1)==0 && dir(2)<0) ph=-M_PI/2; else if(dir(1)>0) ph=atan(dir(2)/dir(1)); else if(dir(2)>0) ph=atan(dir(2)/dir(1))+M_PI; else ph=atan(dir(2)/dir(1))-M_PI; if(dir(3)==0) th=M_PI/2; else if(dir(3)>0) th=atan(sqrt(dir(1)*dir(1)+dir(2)*dir(2))/dir(3)); else th=atan(sqrt(dir(1)*dir(1)+dir(2)*dir(2))/dir(3))+M_PI; } } void cart2sph(const Matrix& dir,ColumnVector& th,ColumnVector& ph) { if(th.Nrows()!=dir.Ncols()){ th.ReSize(dir.Ncols()); } if(ph.Nrows()!=dir.Ncols()){ ph.ReSize(dir.Ncols()); } for (int i=1;i<=dir.Ncols();i++) { float mag=sqrt(dir(1,i)*dir(1,i)+dir(2,i)*dir(2,i)+dir(3,i)*dir(3,i)); if(mag==0){ ph(i)=M_PI/2; th(i)=M_PI/2; } else{ if(dir(1,i)==0 && dir(2,i)>=0) ph(i)=M_PI/2; else if(dir(1,i)==0 && dir(2,i)<0) ph(i)=-M_PI/2; else if(dir(1,i)>0) ph(i)=atan(dir(2,i)/dir(1,i)); else if(dir(2,i)>0) ph(i)=atan(dir(2,i)/dir(1,i))+M_PI; else ph(i)=atan(dir(2,i)/dir(1,i))-M_PI; if(dir(3,i)==0) th(i)=M_PI/2; else if(dir(3,i)>0) th(i)=atan(sqrt(dir(1,i)*dir(1,i)+dir(2,i)*dir(2,i))/dir(3,i)); else th(i)=atan(sqrt(dir(1,i)*dir(1,i)+dir(2,i)*dir(2,i))/dir(3,i))+M_PI; } } } // added by SJ void cart2sph(const vector& dir,ColumnVector& th,ColumnVector& ph) { if(th.Nrows()!=(int)dir.size()){ th.ReSize(dir.size()); } if(ph.Nrows()!=(int)dir.size()){ ph.ReSize(dir.size()); } //double _2pi=2*M_PI; double _pi2=M_PI/2; int j=1; for (unsigned int i=0;i=0) ph(j)=_pi2; else if(dir[i](1)==0 && dir[i](2)<0) ph(j)=-_pi2; else if(dir[i](1)>0) ph(j)=std::atan(dir[i](2)/dir[i](1)); else if(dir[i](2)>0) ph(j)=std::atan(dir[i](2)/dir[i](1))+M_PI; else ph(j)=std::atan(dir[i](2)/dir[i](1))-M_PI; //ph(j)=fmod(ph(j),_2pi); if(dir[i](3)==0) th(j)=_pi2; else if(dir[i](3)>0) th(j)=std::atan(std::sqrt(dir[i](1)*dir[i](1)+dir[i](2)*dir[i](2))/dir[i](3)); else th(j)=std::atan(std::sqrt(dir[i](1)*dir[i](1)+dir[i](2)*dir[i](2))/dir[i](3))+M_PI; //th(j)=fmod(th(j),M_PI); } j++; } } // Added by CFB --- Matlab style Matrix functions ReturnMatrix ones(const int dim1, const int dim2) { int tdim = dim2; if(tdim<0){tdim=dim1;} Matrix res(dim1,tdim); res = 1.0; res.Release(); return res; } ReturnMatrix zeros(const int dim1, const int dim2) { int tdim = dim2; if(tdim<0){tdim=dim1;} Matrix res(dim1,tdim); res = 0.0; res.Release(); return res; } ReturnMatrix repmat(const Matrix &mat, const int rows, const int cols) { Matrix res = mat; for(int ctr = 1; ctr < cols; ctr++){res |= mat;} Matrix tmpres = res; for(int ctr = 1; ctr < rows; ctr++){res &= tmpres;} res.Release(); return res; } ReturnMatrix dist2(const Matrix &mat1, const Matrix &mat2) { Matrix res(mat1.Ncols(),mat2.Ncols()); for(int ctr1 = 1; ctr1 <= mat1.Ncols(); ctr1++) for(int ctr2 =1; ctr2 <= mat2.Ncols(); ctr2++) { ColumnVector tmp; tmp=mat1.Column(ctr1)-mat2.Column(ctr2); res(ctr1,ctr2) = std::sqrt(tmp.SumSquare()); } res.Release(); return res; } ReturnMatrix abs(const Matrix& mat) { Matrix res = mat; for (int mc=1; mc<=mat.Ncols(); mc++) { for (int mr=1; mr<=mat.Nrows(); mr++) { res(mr,mc)=std::abs(res(mr,mc)); } } res.Release(); return res; } ReturnMatrix sqrt(const Matrix& mat) { Matrix res = mat; bool neg_flag = false; for (int mc=1; mc<=mat.Ncols(); mc++) { for (int mr=1; mr<=mat.Nrows(); mr++) { if(res(mr,mc)<0){ neg_flag = true; } res(mr,mc)=std::sqrt(std::abs(res(mr,mc))); } } if(neg_flag){ //cerr << " Matrix contained negative elements" << endl; //cerr << " return sqrt(abs(X)) instead" << endl; } res.Release(); return res; } ReturnMatrix sqrtm(const Matrix& mat) { Matrix res, tmpU, tmpV; DiagonalMatrix tmpD; SVD(mat, tmpD, tmpU, tmpV); res = tmpU*sqrt(tmpD)*tmpV.t(); res.Release(); return res; } ReturnMatrix log(const Matrix& mat) { Matrix res = mat; bool neg_flag = false; for (int mc=1; mc<=mat.Ncols(); mc++) { for (int mr=1; mr<=mat.Nrows(); mr++) { if(res(mr,mc)<0){ neg_flag = true; } res(mr,mc)=std::log(std::abs(res(mr,mc))); } } if(neg_flag){ // cerr << " Matrix contained negative elements" << endl; // cerr << " return log(abs(X)) instead" << endl; } res.Release(); return res; } ReturnMatrix exp(const Matrix& mat) { Matrix res = mat; for (int mc=1; mc<=mat.Ncols(); mc++) { for (int mr=1; mr<=mat.Nrows(); mr++) { res(mr,mc)=std::exp(res(mr,mc)); } } res.Release(); return res; } // optimised code for calculating matrix exponential ReturnMatrix expm(const Matrix& mat){ float nmat = sum(mat).Maximum(); int nc=mat.Ncols(),nr=mat.Nrows(); Matrix res(nr,nc); IdentityMatrix id(nr); Matrix U(nr,nc),V(nr,nc); if(nmat <= 1.495585217958292e-002){ // m=3 Matrix mat2(nr,nc); mat2=mat*mat; U = mat*(mat2+60.0*id); V = 12.0*mat2+120.0*id; res = (-U+V).i()*(U+V); } else if(nmat <= 2.539398330063230e-001){ // m=5 Matrix mat2(nr,nc),mat4(nr,nc); mat2=mat*mat;mat4=mat2*mat2; U = mat*(mat4+420.0*mat2+15120.0*id); V = 30.0*mat4+3360.0*mat2+30240.0*id; res = (-U+V).i()*(U+V); } else if(nmat <= 9.504178996162932e-001){ // m=7 Matrix mat2(nr,nc),mat4(nr,nc),mat6(nr,nc); mat2=mat*mat;mat4=mat2*mat2,mat6=mat4*mat2; U = mat*(mat6+1512.0*mat4+277200.0*mat2+8648640.0*id); V = 56.0*mat6+25200.0*mat4+1995840.0*mat2+17297280.0*id; res = (-U+V).i()*(U+V); } else if(nmat <= 2.097847961257068e+000){ Matrix mat2(nr,nc),mat4(nr,nc),mat6(nr,nc),mat8(nr,nc); mat2=mat*mat;mat4=mat2*mat2,mat6=mat4*mat2,mat8=mat6*mat2; U = mat*(mat8+3960.0*mat6+2162160.0*mat4+302702400.0*mat2+8821612800.0*id); V = 90.0*mat8+110880.0*mat6+30270240.0*mat4+2075673600.0*mat2+17643225600.0*id; res = (-U+V).i()*(U+V); } else if(nmat <= 5.371920351148152e+000){ Matrix mat2(nr,nc),mat4(nr,nc),mat6(nr,nc); mat2=mat*mat;mat4=mat2*mat2,mat6=mat4*mat2; U = mat*(mat6*(mat6+16380.0*mat4+40840800.0*mat2)+ +33522128640.0*mat6+10559470521600.0*mat4+1187353796428800.0*mat2+32382376266240000.0*id); V = mat6*(182.0*mat6+960960.0*mat4+1323241920.0*mat2) + 670442572800.0*mat6+129060195264000.0*mat4+7771770303897600.0*mat2+64764752532480000.0*id; res = (-U+V).i()*(U+V); } else{ double t;int s; t = frexp(nmat/5.371920351148152,&s); if(t==0.5) s--; t = std::pow(2.0,s); res = (mat/t); Matrix mat2(nr,nc),mat4(nr,nc),mat6(nr,nc); mat2=res*res;mat4=mat2*mat2,mat6=mat4*mat2; U = res*(mat6*(mat6+16380*mat4+40840800*mat2)+ +33522128640.0*mat6+10559470521600.0*mat4+1187353796428800.0*mat2+32382376266240000.0*id); V = mat6*(182.0*mat6+960960.0*mat4+1323241920.0*mat2) + 670442572800.0*mat6+129060195264000.0*mat4+7771770303897600.0*mat2+64764752532480000.0*id; res = (-U+V).i()*(U+V); for(int i=1;i<=s;i++) res = res*res; } res.Release(); return res; } ReturnMatrix tanh(const Matrix& mat) { Matrix res = mat; for (int mc=1; mc<=mat.Ncols(); mc++) { for (int mr=1; mr<=mat.Nrows(); mr++) { res(mr,mc)=std::tanh(res(mr,mc)); } } res.Release(); return res; } ReturnMatrix pow(const Matrix& mat, const double exp) { Matrix res = mat; for (int mc=1; mc<=mat.Ncols(); mc++) { for (int mr=1; mr<=mat.Nrows(); mr++) { res(mr,mc)=std::pow(res(mr,mc),exp); } } res.Release(); return res; } ReturnMatrix max(const Matrix& mat) { Matrix res; if(mat.Nrows()>1){ res=zeros(1,mat.Ncols()); res=mat.Row(1); for(int mc=1; mc<=mat.Ncols();mc++){ for(int mr=2; mr<=mat.Nrows();mr++){ if(mat(mr,mc)>res(1,mc)){res(1,mc)=mat(mr,mc);} } } } else{ res=zeros(1); res=mat(1,1); for(int mc=2; mc<=mat.Ncols(); mc++){ if(mat(1,mc)>res(1,1)){res(1,1)=mat(1,mc);} } } res.Release(); return res; } ReturnMatrix max(const Matrix& mat,ColumnVector& index) { index.ReSize(mat.Nrows()); index=1; Matrix res; if(mat.Nrows()>1){ res=zeros(1,mat.Ncols()); res=mat.Row(1); for(int mc=1; mc<=mat.Ncols();mc++){ for(int mr=2; mr<=mat.Nrows();mr++){ if(mat(mr,mc)>res(1,mc)) { res(1,mc)=mat(mr,mc); index(mr)=mc; } } } } else{ res=zeros(1); res=mat(1,1); for(int mc=2; mc<=mat.Ncols(); mc++){ if(mat(1,mc)>res(1,1)) { res(1,1)=mat(1,mc); index(1)=mc; } } } res.Release(); return res; } ReturnMatrix min(const Matrix& mat) { Matrix res; if(mat.Nrows()>1){ res=zeros(1,mat.Ncols()); res=mat.Row(1); for(int mc=1; mc<=mat.Ncols();mc++){ for(int mr=2; mr<=mat.Nrows();mr++){ if(mat(mr,mc)1){ tmp -= ones(tmp.Nrows(),1)*mean(tmp,1); for (int mc=1; mc<=tmp.Ncols(); mc++) for (int mr=1; mr<=tmp.Nrows(); mr++) res(1,mc) += tmp(mr,mc) / (N-1) * tmp(mr,mc); } if (!(dim == 1)) {res=res.t();} res.Release(); return res; } ReturnMatrix stdev(const Matrix& mat, const int dim) { return sqrt(var(mat,dim)); } ReturnMatrix gt(const Matrix& mat1,const Matrix& mat2) { int ctrcol = std::min(mat1.Ncols(),mat2.Ncols()); int ctrrow = std::min(mat1.Nrows(),mat2.Nrows()); Matrix res(ctrrow,ctrcol); res=0.0; for (int ctr1 = 1; ctr1 <= ctrrow; ctr1++) { for (int ctr2 =1; ctr2 <= ctrcol; ctr2++) { if( mat1(ctr1,ctr2) > mat2(ctr1,ctr2)){ res(ctr1,ctr2) = 1.0; } } } res.Release(); return res; } ReturnMatrix lt(const Matrix& mat1,const Matrix& mat2) { int ctrcol = std::min(mat1.Ncols(),mat2.Ncols()); int ctrrow = std::min(mat1.Nrows(),mat2.Nrows()); Matrix res(ctrrow,ctrcol); res=0.0; for (int ctr1 = 1; ctr1 <= ctrrow; ctr1++) { for (int ctr2 =1; ctr2 <= ctrcol; ctr2++) { if( mat1(ctr1,ctr2) < mat2(ctr1,ctr2)){ res(ctr1,ctr2) = 1.0; } } } res.Release(); return res; } ReturnMatrix geqt(const Matrix& mat1,const Matrix& mat2) { int ctrcol = std::min(mat1.Ncols(),mat2.Ncols()); int ctrrow = std::min(mat1.Nrows(),mat2.Nrows()); Matrix res(ctrrow,ctrcol); res=0.0; for (int ctr1 = 1; ctr1 <= ctrrow; ctr1++) { for (int ctr2 =1; ctr2 <= ctrcol; ctr2++) { if( mat1(ctr1,ctr2) >= mat2(ctr1,ctr2)){ res(ctr1,ctr2) = 1.0; } } } res.Release(); return res; } ReturnMatrix geqt(const Matrix& mat,const float a) { int ncols = mat.Ncols(); int nrows = mat.Nrows(); Matrix res(nrows,ncols); res=0.0; for (int ctr1 = 1; ctr1 <= nrows; ctr1++) { for (int ctr2 =1; ctr2 <= ncols; ctr2++) { if( mat(ctr1,ctr2) >= a){ res(ctr1,ctr2) = 1.0; } } } res.Release(); return res; } ReturnMatrix leqt(const Matrix& mat1,const Matrix& mat2) { int ctrcol = std::min(mat1.Ncols(),mat2.Ncols()); int ctrrow = std::min(mat1.Nrows(),mat2.Nrows()); Matrix res(ctrrow,ctrcol); res=0.0; for (int ctr1 = 1; ctr1 <= ctrrow; ctr1++) { for (int ctr2 =1; ctr2 <= ctrcol; ctr2++) { if( mat1(ctr1,ctr2) <= mat2(ctr1,ctr2)){ res(ctr1,ctr2) = 1.0; } } } res.Release(); return res; } ReturnMatrix eq(const Matrix& mat1,const Matrix& mat2) { int ctrcol = std::min(mat1.Ncols(),mat2.Ncols()); int ctrrow = std::min(mat1.Nrows(),mat2.Nrows()); Matrix res(ctrrow,ctrcol); res=0.0; for (int ctr1 = 1; ctr1 <= ctrrow; ctr1++) { for (int ctr2 =1; ctr2 <= ctrcol; ctr2++) { if( mat1(ctr1,ctr2) == mat2(ctr1,ctr2)){ res(ctr1,ctr2) = 1.0; } } } res.Release(); return res; } ReturnMatrix neq(const Matrix& mat1,const Matrix& mat2) { int ctrcol = std::min(mat1.Ncols(),mat2.Ncols()); int ctrrow = std::min(mat1.Nrows(),mat2.Nrows()); Matrix res(ctrrow,ctrcol); res=0.0; for (int ctr1 = 1; ctr1 <= ctrrow; ctr1++) { for (int ctr2 =1; ctr2 <= ctrcol; ctr2++) { if( mat1(ctr1,ctr2) != mat2(ctr1,ctr2)){ res(ctr1,ctr2) = 1.0; } } } res.Release(); return res; } ReturnMatrix SD(const Matrix& mat1,const Matrix& mat2) { if((mat1.Nrows() != mat2.Nrows()) || (mat1.Ncols() != mat2.Ncols()) ){ cerr <<"MISCMATHS::SD - matrices are of different dimensions"<0) && (Mat(i,j) 0 ? tmp : tmp + n; } } } } int nextpow2(int n) { return (int)pow(2,ceil(log(float(n))/log(float(2)))); } void xcorr(const Matrix& p_ts, Matrix& ret, int lag, int p_zeropad) { Tracer tr("MISCMATHS::xcorr"); int sizeTS = p_ts.Nrows(); int numTS = p_ts.Ncols(); if(p_zeropad == 0) p_zeropad = sizeTS; if(lag == 0) lag = sizeTS; ColumnVector x(p_zeropad); x = 0; ColumnVector fft_real; ColumnVector fft_im; ColumnVector dummy(p_zeropad); ColumnVector dummy2; dummy = 0; ColumnVector realifft(p_zeropad); ret.ReSize(lag,numTS); ret = 0; for(int i = 1; i <= numTS; i++) { x.Rows(1,sizeTS) = p_ts.Column(i); FFT(x, dummy, fft_real, fft_im); for(int j = 1; j <= p_zeropad; j++) { // (x+iy)(x-iy) = x^2 + y^2 fft_real(j) = fft_real(j)*fft_real(j) + fft_im(j)*fft_im(j); fft_im(j) = 0; } FFTI(fft_real, fft_im, realifft, dummy2); float varx = var(x.Rows(1,sizeTS)).AsScalar(); ret.Column(i) = realifft.Rows(1,lag); for(int j = 1; j <= lag-1; j++) { // Correction to make autocorr unbiased and normalised ret(j,i) = ret(j,i)/((sizeTS-j)*varx); } } } ReturnMatrix xcorr(const Matrix& p_ts, int lag, int p_zeropad ) { Matrix r; xcorr(p_ts,r,lag,p_zeropad); r.Release(); return r; } void detrend(Matrix& p_ts, int p_level) { Tracer trace("MISCMATHS::detrend"); int sizeTS = p_ts.Nrows(); // p_ts = b*a + e (OLS regression) // e is detrended data Matrix a(sizeTS, p_level+1); // Create a for(int t = 1; t <= sizeTS; t++) { for(int l = 0; l <= p_level; l++) a(t,l+1) = pow((float)t/sizeTS,l); } // Form residual forming matrix R: Matrix R = IdentityMatrix(sizeTS)-a*pinv(a); for(int t = 1; t <= sizeTS; t++) { p_ts.Column(t) = R*p_ts.Column(t); } } ReturnMatrix read_vest(string p_fname) { ifstream in; in.open(p_fname.c_str(), ios::in); if(!in) throw Exception(string("Unable to open "+p_fname).c_str()); int numWaves = 0; int numPoints = 0; string str; while(true) { if(!in.good()) throw Exception(string(p_fname+" is not a valid vest file").c_str()); in >> str; if(str == "/Matrix") break; else if(str == "/NumWaves") { in >> numWaves; } else if(str == "/NumPoints" || str == "/NumContrasts") { in >> numPoints; } } Matrix p_mat(numPoints, numWaves); for(int i = 1; i <= numPoints; i++) { for(int j = 1; j <= numWaves; j++) { if (!in.eof()) in >> ws >> p_mat(i,j) >> ws; else throw Exception(string(p_fname+" has insufficient data points").c_str()); } } in.close(); p_mat.Release(); return p_mat; } void ols(const Matrix& data,const Matrix& des,const Matrix& tc, Matrix& cope,Matrix& varcope){ // ols // data is t x v // des is t x ev (design matrix) // tc is cons x ev (contrast matrix) // cope and varcope will be cons x v // but will be resized if they are wrong // hence may be passed in uninitialised // TB 2004 if(data.Nrows() != des.Nrows()){ cerr <<"MISCMATHS::ols - data and design have different number of time points"< 4000 ) //Use the simple version as huge designs require too much RAM in the full calculation return des.Nrows() - des.Ncols(); try { Matrix pdes = pinv(des); Matrix R=IdentityMatrix(des.Nrows())-des*pdes; return R.Trace();} catch (...) { cerr << "ols_dof: Error in determining the trace, resorting to basic calculation" << endl; } return des.Nrows() - des.Ncols(); } int conjgrad(ColumnVector& x, const Matrix& A, const ColumnVector& b, int maxit, float reltol) { // solves: A * x = b (for x) // implementation of algorithm in Golub and Van Loan (3rd ed, page 527) ColumnVector rk1, rk2, pk, apk; double betak, alphak, rk1rk1=0, rk2rk2, r00=0; int k=0; rk1 = b - A*x; // a *big* calculation for (int n=1; n<=maxit; n++) { k++; if (k==1) { pk = rk1; rk1rk1 = (rk1.t() * rk1).AsScalar(); r00=rk1rk1; } else { rk2rk2 = rk1rk1; // from before rk1rk1 = (rk1.t() * rk1).AsScalar(); if (rk2rk2<1e-10*rk1rk1) { cerr << "WARNING:: Conj Grad - low demoninator (rk2rk2)" << endl; if (rk2rk2<=0) { cerr << "Aborting conj grad ..." << endl; return 1; } } betak = rk1rk1 / rk2rk2; pk = rk1 + betak * pk; // note RHS pk is p(k-1) in algorithm } // stop if sufficient accuracy is achieved if (rk1rk1 ColumnVector2vector(const ColumnVector& col) { vector vec(col.Nrows()); for(int c = 0; c < col.Nrows(); c++) vec[c] = col(c+1); return vec; } ///////////////////////////////////////////////////////////////////////////////////////////////////// // Uninteresting byte swapping functions typedef struct { unsigned char a,b ; } TWObytes ; void Swap_2bytes( int n , void *ar ) /* 2 bytes at a time */ { register int ii ; register TWObytes *tb = (TWObytes *)ar ; register unsigned char tt ; for( ii=0 ; ii < n ; ii++ ){ tt = tb[ii].a ; tb[ii].a = tb[ii].b ; tb[ii].b = tt ; } return ; } /*---------------------------------------------------------------------------*/ typedef struct { unsigned char a,b,c,d ; } FOURbytes ; void Swap_4bytes( int n , void *ar ) /* 4 bytes at a time */ { register int ii ; register FOURbytes *tb = (FOURbytes *)ar ; register unsigned char tt ; for( ii=0 ; ii < n ; ii++ ){ tt = tb[ii].a ; tb[ii].a = tb[ii].d ; tb[ii].d = tt ; tt = tb[ii].b ; tb[ii].b = tb[ii].c ; tb[ii].c = tt ; } return ; } /*---------------------------------------------------------------------------*/ typedef struct { unsigned char a,b,c,d , D,C,B,A ; } EIGHTbytes ; void Swap_8bytes( int n , void *ar ) /* 8 bytes at a time */ { register int ii ; register EIGHTbytes *tb = (EIGHTbytes *)ar ; register unsigned char tt ; for( ii=0 ; ii < n ; ii++ ){ tt = tb[ii].a ; tb[ii].a = tb[ii].A ; tb[ii].A = tt ; tt = tb[ii].b ; tb[ii].b = tb[ii].B ; tb[ii].B = tt ; tt = tb[ii].c ; tb[ii].c = tb[ii].C ; tb[ii].C = tt ; tt = tb[ii].d ; tb[ii].d = tb[ii].D ; tb[ii].D = tt ; } return ; } /*---------------------------------------------------------------------------*/ typedef struct { unsigned char a,b,c,d,e,f,g,h , H,G,F,E,D,C,B,A ; } SIXTEENbytes ; void Swap_16bytes( int n , void *ar ) /* 16 bytes at a time */ { register int ii ; register SIXTEENbytes *tb = (SIXTEENbytes *)ar ; register unsigned char tt ; for( ii=0 ; ii < n ; ii++ ){ tt = tb[ii].a ; tb[ii].a = tb[ii].A ; tb[ii].A = tt ; tt = tb[ii].b ; tb[ii].b = tb[ii].B ; tb[ii].B = tt ; tt = tb[ii].c ; tb[ii].c = tb[ii].C ; tb[ii].C = tt ; tt = tb[ii].d ; tb[ii].d = tb[ii].D ; tb[ii].D = tt ; tt = tb[ii].e ; tb[ii].e = tb[ii].E ; tb[ii].E = tt ; tt = tb[ii].f ; tb[ii].f = tb[ii].F ; tb[ii].F = tt ; tt = tb[ii].g ; tb[ii].g = tb[ii].G ; tb[ii].G = tt ; tt = tb[ii].h ; tb[ii].h = tb[ii].H ; tb[ii].H = tt ; } return ; } /*---------------------------------------------------------------------------*/ void Swap_Nbytes( int n , int siz , void *ar ) /* subsuming case */ { switch( siz ){ case 2: Swap_2bytes ( n , ar ) ; break ; case 4: Swap_4bytes ( n , ar ) ; break ; case 8: Swap_8bytes ( n , ar ) ; break ; case 16: Swap_16bytes( n , ar ) ; break ; } return ; } // end namespace MISCMATHS }