bool testblas(bool silent) { bool result; int pass; int passcount; int n; int i; int i1; int i2; int j; int j1; int j2; int l; int k; int r; int i3; int j3; int col1; int col2; int row1; int row2; ap::real_1d_array x1; ap::real_1d_array x2; ap::real_2d_array a; ap::real_2d_array b; ap::real_2d_array c1; ap::real_2d_array c2; double err; double e1; double e2; double e3; double v; double scl1; double scl2; double scl3; bool was1; bool was2; bool trans1; bool trans2; double threshold; bool n2errors; bool hsnerrors; bool amaxerrors; bool mverrors; bool iterrors; bool cterrors; bool mmerrors; bool waserrors; n2errors = false; amaxerrors = false; hsnerrors = false; mverrors = false; iterrors = false; cterrors = false; mmerrors = false; waserrors = false; threshold = 10000*ap::machineepsilon; // // Test Norm2 // passcount = 1000; e1 = 0; e2 = 0; e3 = 0; scl2 = 0.5*ap::maxrealnumber; scl3 = 2*ap::minrealnumber; for(pass = 1; pass <= passcount; pass++) { n = 1+ap::randominteger(1000); i1 = ap::randominteger(10); i2 = n+i1-1; x1.setbounds(i1, i2); x2.setbounds(i1, i2); for(i = i1; i <= i2; i++) { x1(i) = 2*ap::randomreal()-1; } v = 0; for(i = i1; i <= i2; i++) { v = v+ap::sqr(x1(i)); } v = sqrt(v); e1 = ap::maxreal(e1, fabs(v-vectornorm2(x1, i1, i2))); for(i = i1; i <= i2; i++) { x2(i) = scl2*x1(i); } e2 = ap::maxreal(e2, fabs(v*scl2-vectornorm2(x2, i1, i2))); for(i = i1; i <= i2; i++) { x2(i) = scl3*x1(i); } e3 = ap::maxreal(e3, fabs(v*scl3-vectornorm2(x2, i1, i2))); } e2 = e2/scl2; e3 = e3/scl3; n2errors = ap::fp_greater_eq(e1,threshold)||ap::fp_greater_eq(e2,threshold)||ap::fp_greater_eq(e3,threshold); // // Testing VectorAbsMax, Column/Row AbsMax // x1.setbounds(1, 5); x1(1) = 2.0; x1(2) = 0.2; x1(3) = -1.3; x1(4) = 0.7; x1(5) = -3.0; amaxerrors = vectoridxabsmax(x1, 1, 5)!=5||vectoridxabsmax(x1, 1, 4)!=1||vectoridxabsmax(x1, 2, 4)!=3; n = 30; x1.setbounds(1, n); a.setbounds(1, n, 1, n); for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { a(i,j) = 2*ap::randomreal()-1; } } was1 = false; was2 = false; for(pass = 1; pass <= 1000; pass++) { j = 1+ap::randominteger(n); i1 = 1+ap::randominteger(n); i2 = i1+ap::randominteger(n+1-i1); ap::vmove(x1.getvector(i1, i2), a.getcolumn(j, i1, i2)); if( vectoridxabsmax(x1, i1, i2)!=columnidxabsmax(a, i1, i2, j) ) { was1 = true; } i = 1+ap::randominteger(n); j1 = 1+ap::randominteger(n); j2 = j1+ap::randominteger(n+1-j1); ap::vmove(&x1(j1), &a(i, j1), ap::vlen(j1,j2)); if( vectoridxabsmax(x1, j1, j2)!=rowidxabsmax(a, j1, j2, i) ) { was2 = true; } } amaxerrors = amaxerrors||was1||was2; // // Testing upper Hessenberg 1-norm // a.setbounds(1, 3, 1, 3); x1.setbounds(1, 3); a(1,1) = 2; a(1,2) = 3; a(1,3) = 1; a(2,1) = 4; a(2,2) = -5; a(2,3) = 8; a(3,1) = 99; a(3,2) = 3; a(3,3) = 1; hsnerrors = ap::fp_greater(fabs(upperhessenberg1norm(a, 1, 3, 1, 3, x1)-11),threshold); // // Testing MatrixVectorMultiply // a.setbounds(2, 3, 3, 5); x1.setbounds(1, 3); x2.setbounds(1, 2); a(2,3) = 2; a(2,4) = -1; a(2,5) = -1; a(3,3) = 1; a(3,4) = -2; a(3,5) = 2; x1(1) = 1; x1(2) = 2; x1(3) = 1; x2(1) = -1; x2(2) = -1; matrixvectormultiply(a, 2, 3, 3, 5, false, x1, 1, 3, 1.0, x2, 1, 2, 1.0); matrixvectormultiply(a, 2, 3, 3, 5, true, x2, 1, 2, 1.0, x1, 1, 3, 1.0); e1 = fabs(x1(1)+5)+fabs(x1(2)-8)+fabs(x1(3)+1)+fabs(x2(1)+2)+fabs(x2(2)+2); x1(1) = 1; x1(2) = 2; x1(3) = 1; x2(1) = -1; x2(2) = -1; matrixvectormultiply(a, 2, 3, 3, 5, false, x1, 1, 3, 1.0, x2, 1, 2, 0.0); matrixvectormultiply(a, 2, 3, 3, 5, true, x2, 1, 2, 1.0, x1, 1, 3, 0.0); e2 = fabs(x1(1)+3)+fabs(x1(2)-3)+fabs(x1(3)+1)+fabs(x2(1)+1)+fabs(x2(2)+1); mverrors = ap::fp_greater_eq(e1+e2,threshold); // // testing inplace transpose // n = 10; a.setbounds(1, n, 1, n); b.setbounds(1, n, 1, n); x1.setbounds(1, n-1); for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { a(i,j) = ap::randomreal(); } } passcount = 10000; was1 = false; for(pass = 1; pass <= passcount; pass++) { i1 = 1+ap::randominteger(n); i2 = i1+ap::randominteger(n-i1+1); j1 = 1+ap::randominteger(n-(i2-i1)); j2 = j1+(i2-i1); copymatrix(a, i1, i2, j1, j2, b, i1, i2, j1, j2); inplacetranspose(b, i1, i2, j1, j2, x1); for(i = i1; i <= i2; i++) { for(j = j1; j <= j2; j++) { if( ap::fp_neq(a(i,j),b(i1+(j-j1),j1+(i-i1))) ) { was1 = true; } } } } iterrors = was1; // // testing copy and transpose // n = 10; a.setbounds(1, n, 1, n); b.setbounds(1, n, 1, n); for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { a(i,j) = ap::randomreal(); } } passcount = 10000; was1 = false; for(pass = 1; pass <= passcount; pass++) { i1 = 1+ap::randominteger(n); i2 = i1+ap::randominteger(n-i1+1); j1 = 1+ap::randominteger(n); j2 = j1+ap::randominteger(n-j1+1); copyandtranspose(a, i1, i2, j1, j2, b, j1, j2, i1, i2); for(i = i1; i <= i2; i++) { for(j = j1; j <= j2; j++) { if( ap::fp_neq(a(i,j),b(j,i)) ) { was1 = true; } } } } cterrors = was1; // // Testing MatrixMatrixMultiply // n = 10; a.setbounds(1, 2*n, 1, 2*n); b.setbounds(1, 2*n, 1, 2*n); c1.setbounds(1, 2*n, 1, 2*n); c2.setbounds(1, 2*n, 1, 2*n); x1.setbounds(1, n); x2.setbounds(1, n); for(i = 1; i <= 2*n; i++) { for(j = 1; j <= 2*n; j++) { a(i,j) = ap::randomreal(); b(i,j) = ap::randomreal(); } } passcount = 1000; was1 = false; for(pass = 1; pass <= passcount; pass++) { for(i = 1; i <= 2*n; i++) { for(j = 1; j <= 2*n; j++) { c1(i,j) = 2.1*i+3.1*j; c2(i,j) = c1(i,j); } } l = 1+ap::randominteger(n); k = 1+ap::randominteger(n); r = 1+ap::randominteger(n); i1 = 1+ap::randominteger(n); j1 = 1+ap::randominteger(n); i2 = 1+ap::randominteger(n); j2 = 1+ap::randominteger(n); i3 = 1+ap::randominteger(n); j3 = 1+ap::randominteger(n); trans1 = ap::fp_greater(ap::randomreal(),0.5); trans2 = ap::fp_greater(ap::randomreal(),0.5); if( trans1 ) { col1 = l; row1 = k; } else { col1 = k; row1 = l; } if( trans2 ) { col2 = k; row2 = r; } else { col2 = r; row2 = k; } scl1 = ap::randomreal(); scl2 = ap::randomreal(); matrixmatrixmultiply(a, i1, i1+row1-1, j1, j1+col1-1, trans1, b, i2, i2+row2-1, j2, j2+col2-1, trans2, scl1, c1, i3, i3+l-1, j3, j3+r-1, scl2, x1); naivematrixmatrixmultiply(a, i1, i1+row1-1, j1, j1+col1-1, trans1, b, i2, i2+row2-1, j2, j2+col2-1, trans2, scl1, c2, i3, i3+l-1, j3, j3+r-1, scl2); err = 0; for(i = 1; i <= l; i++) { for(j = 1; j <= r; j++) { err = ap::maxreal(err, fabs(c1(i3+i-1,j3+j-1)-c2(i3+i-1,j3+j-1))); } } if( ap::fp_greater(err,threshold) ) { was1 = true; break; } } mmerrors = was1; // // report // waserrors = n2errors||amaxerrors||hsnerrors||mverrors||iterrors||cterrors||mmerrors; if( !silent ) { printf("TESTING BLAS\n"); printf("VectorNorm2: "); if( n2errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("AbsMax (vector/row/column): "); if( amaxerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("UpperHessenberg1Norm: "); if( hsnerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MatrixVectorMultiply: "); if( mverrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("InplaceTranspose: "); if( iterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CopyAndTranspose: "); if( cterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MatrixMatrixMultiply: "); if( mmerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; }
/** * Compute the ordinary least squares estimation of the solution to a linear regression * * @param data The regression input. Each inner vector should be a single variable (so column maj order) * @param response The response variable. * @return betas The estimate of regression coefficients */ vector<double> LinearRegression::leastSquares(const vector<vector<double> > &data, const vector<double> &response){ int sz = data.size(); if(sz < 0) throw LinearRegressionException(); int indivSz = response.size(); vector<double> betas; alglib::real_1d_array vecResp; alglib::real_1d_array vecBetas; alglib::real_2d_array vecData; alglib::real_2d_array tempSquare; alglib::real_1d_array tempWork; vecResp.setlength(indivSz); vecBetas.setlength(sz); vecData.setlength(indivSz,sz); tempSquare.setlength(sz,sz); tempWork.setlength(indivSz+1); // Transfer into the matrices. for(unsigned int i=0;i<data.size();i++){ for(unsigned int j=0;j < data.at(0).size();j++){ vecData(j,i) = data.at(i).at(j); } } for(unsigned int i=0;i<response.size();i++) vecResp(i) = response.at(i); /// X'*X matrixmatrixmultiply(vecData,0,indivSz-1,0,sz-1,true, vecData,0,indivSz-1,0,sz-1,false,1.0, tempSquare,0,sz-1,0,sz-1,0.0,tempWork); alglib::matinvreport report; alglib::ae_int_t reportInfo ; rmatrixinverse(tempSquare, reportInfo, report); if(reportInfo != 1){ throw LinearRegressionException(); } if (report.r1 > LINEAR_REGRESSION_CONDITION_NUMBER_LIMIT){ throw ConditionNumberEx(1.0/report.r1); } /// X'*beta matrixvectormultiply(vecData,0,indivSz-1,0,sz-1,true, vecResp,0,indivSz-1,1.0, tempWork,0,sz-1,0.0); /// tempSquare * tempWork matrixvectormultiply(tempSquare,0,sz-1,0,sz-1,false, tempWork,0,sz-1,1.0, vecBetas,0,sz-1,0.0); for(int i=0;i<sz;i++) betas.push_back(vecBetas(i)); return betas; }
/************************************************************************* Internal linear regression subroutine *************************************************************************/ static void lrinternal(const ap::real_2d_array& xy, const ap::real_1d_array& s, int npoints, int nvars, int& info, linearmodel& lm, lrreport& ar) { ap::real_2d_array a; ap::real_2d_array u; ap::real_2d_array vt; ap::real_2d_array vm; ap::real_2d_array xym; ap::real_1d_array b; ap::real_1d_array sv; ap::real_1d_array t; ap::real_1d_array svi; ap::real_1d_array work; int i; int j; int k; int ncv; int na; int nacv; double r; double p; double epstol; lrreport ar2; int offs; linearmodel tlm; epstol = 1000; // // Check for errors in data // if( npoints<nvars||nvars<1 ) { info = -1; return; } for(i = 0; i <= npoints-1; i++) { if( ap::fp_less_eq(s(i),0) ) { info = -2; return; } } info = 1; // // Create design matrix // a.setbounds(0, npoints-1, 0, nvars-1); b.setbounds(0, npoints-1); for(i = 0; i <= npoints-1; i++) { r = 1/s(i); ap::vmove(&a(i, 0), &xy(i, 0), ap::vlen(0,nvars-1), r); b(i) = xy(i,nvars)/s(i); } // // Allocate W: // W[0] array size // W[1] version number, 0 // W[2] NVars (minus 1, to be compatible with external representation) // W[3] coefficients offset // lm.w.setbounds(0, 4+nvars-1); offs = 4; lm.w(0) = 4+nvars; lm.w(1) = lrvnum; lm.w(2) = nvars-1; lm.w(3) = offs; // // Solve problem using SVD: // // 0. check for degeneracy (different types) // 1. A = U*diag(sv)*V' // 2. T = b'*U // 3. w = SUM((T[i]/sv[i])*V[..,i]) // 4. cov(wi,wj) = SUM(Vji*Vjk/sv[i]^2,K=1..M) // // see $15.4 of "Numerical Recipes in C" for more information // t.setbounds(0, nvars-1); svi.setbounds(0, nvars-1); ar.c.setbounds(0, nvars-1, 0, nvars-1); vm.setbounds(0, nvars-1, 0, nvars-1); if( !rmatrixsvd(a, npoints, nvars, 1, 1, 2, sv, u, vt) ) { info = -4; return; } if( ap::fp_less_eq(sv(0),0) ) { // // Degenerate case: zero design matrix. // for(i = offs; i <= offs+nvars-1; i++) { lm.w(i) = 0; } ar.rmserror = lrrmserror(lm, xy, npoints); ar.avgerror = lravgerror(lm, xy, npoints); ar.avgrelerror = lravgrelerror(lm, xy, npoints); ar.cvrmserror = ar.rmserror; ar.cvavgerror = ar.avgerror; ar.cvavgrelerror = ar.avgrelerror; ar.ncvdefects = 0; ar.cvdefects.setbounds(0, nvars-1); ar.c.setbounds(0, nvars-1, 0, nvars-1); for(i = 0; i <= nvars-1; i++) { for(j = 0; j <= nvars-1; j++) { ar.c(i,j) = 0; } } return; } if( ap::fp_less_eq(sv(nvars-1),epstol*ap::machineepsilon*sv(0)) ) { // // Degenerate case, non-zero design matrix. // // We can leave it and solve task in SVD least squares fashion. // Solution and covariance matrix will be obtained correctly, // but CV error estimates - will not. It is better to reduce // it to non-degenerate task and to obtain correct CV estimates. // for(k = nvars; k >= 1; k--) { if( ap::fp_greater(sv(k-1),epstol*ap::machineepsilon*sv(0)) ) { // // Reduce // xym.setbounds(0, npoints-1, 0, k); for(i = 0; i <= npoints-1; i++) { for(j = 0; j <= k-1; j++) { r = ap::vdotproduct(&xy(i, 0), &vt(j, 0), ap::vlen(0,nvars-1)); xym(i,j) = r; } xym(i,k) = xy(i,nvars); } // // Solve // lrinternal(xym, s, npoints, k, info, tlm, ar2); if( info!=1 ) { return; } // // Convert back to un-reduced format // for(j = 0; j <= nvars-1; j++) { lm.w(offs+j) = 0; } for(j = 0; j <= k-1; j++) { r = tlm.w(offs+j); ap::vadd(&lm.w(offs), &vt(j, 0), ap::vlen(offs,offs+nvars-1), r); } ar.rmserror = ar2.rmserror; ar.avgerror = ar2.avgerror; ar.avgrelerror = ar2.avgrelerror; ar.cvrmserror = ar2.cvrmserror; ar.cvavgerror = ar2.cvavgerror; ar.cvavgrelerror = ar2.cvavgrelerror; ar.ncvdefects = ar2.ncvdefects; ar.cvdefects.setbounds(0, nvars-1); for(j = 0; j <= ar.ncvdefects-1; j++) { ar.cvdefects(j) = ar2.cvdefects(j); } ar.c.setbounds(0, nvars-1, 0, nvars-1); work.setbounds(1, nvars); matrixmatrixmultiply(ar2.c, 0, k-1, 0, k-1, false, vt, 0, k-1, 0, nvars-1, false, 1.0, vm, 0, k-1, 0, nvars-1, 0.0, work); matrixmatrixmultiply(vt, 0, k-1, 0, nvars-1, true, vm, 0, k-1, 0, nvars-1, false, 1.0, ar.c, 0, nvars-1, 0, nvars-1, 0.0, work); return; } } info = -255; return; } for(i = 0; i <= nvars-1; i++) { if( ap::fp_greater(sv(i),epstol*ap::machineepsilon*sv(0)) ) { svi(i) = 1/sv(i); } else { svi(i) = 0; } } for(i = 0; i <= nvars-1; i++) { t(i) = 0; } for(i = 0; i <= npoints-1; i++) { r = b(i); ap::vadd(&t(0), &u(i, 0), ap::vlen(0,nvars-1), r); } for(i = 0; i <= nvars-1; i++) { lm.w(offs+i) = 0; } for(i = 0; i <= nvars-1; i++) { r = t(i)*svi(i); ap::vadd(&lm.w(offs), &vt(i, 0), ap::vlen(offs,offs+nvars-1), r); } for(j = 0; j <= nvars-1; j++) { r = svi(j); ap::vmove(vm.getcolumn(j, 0, nvars-1), vt.getrow(j, 0, nvars-1), r); } for(i = 0; i <= nvars-1; i++) { for(j = i; j <= nvars-1; j++) { r = ap::vdotproduct(&vm(i, 0), &vm(j, 0), ap::vlen(0,nvars-1)); ar.c(i,j) = r; ar.c(j,i) = r; } } // // Leave-1-out cross-validation error. // // NOTATIONS: // A design matrix // A*x = b original linear least squares task // U*S*V' SVD of A // ai i-th row of the A // bi i-th element of the b // xf solution of the original LLS task // // Cross-validation error of i-th element from a sample is // calculated using following formula: // // ERRi = ai*xf - (ai*xf-bi*(ui*ui'))/(1-ui*ui') (1) // // This formula can be derived from normal equations of the // original task // // (A'*A)x = A'*b (2) // // by applying modification (zeroing out i-th row of A) to (2): // // (A-ai)'*(A-ai) = (A-ai)'*b // // and using Sherman-Morrison formula for updating matrix inverse // // NOTE 1: b is not zeroed out since it is much simpler and // does not influence final result. // // NOTE 2: some design matrices A have such ui that 1-ui*ui'=0. // Formula (1) can't be applied for such cases and they are skipped // from CV calculation (which distorts resulting CV estimate). // But from the properties of U we can conclude that there can // be no more than NVars such vectors. Usually // NVars << NPoints, so in a normal case it only slightly // influences result. // ncv = 0; na = 0; nacv = 0; ar.rmserror = 0; ar.avgerror = 0; ar.avgrelerror = 0; ar.cvrmserror = 0; ar.cvavgerror = 0; ar.cvavgrelerror = 0; ar.ncvdefects = 0; ar.cvdefects.setbounds(0, nvars-1); for(i = 0; i <= npoints-1; i++) { // // Error on a training set // r = ap::vdotproduct(&xy(i, 0), &lm.w(offs), ap::vlen(0,nvars-1)); ar.rmserror = ar.rmserror+ap::sqr(r-xy(i,nvars)); ar.avgerror = ar.avgerror+fabs(r-xy(i,nvars)); if( ap::fp_neq(xy(i,nvars),0) ) { ar.avgrelerror = ar.avgrelerror+fabs((r-xy(i,nvars))/xy(i,nvars)); na = na+1; } // // Error using fast leave-one-out cross-validation // p = ap::vdotproduct(&u(i, 0), &u(i, 0), ap::vlen(0,nvars-1)); if( ap::fp_greater(p,1-epstol*ap::machineepsilon) ) { ar.cvdefects(ar.ncvdefects) = i; ar.ncvdefects = ar.ncvdefects+1; continue; } r = s(i)*(r/s(i)-b(i)*p)/(1-p); ar.cvrmserror = ar.cvrmserror+ap::sqr(r-xy(i,nvars)); ar.cvavgerror = ar.cvavgerror+fabs(r-xy(i,nvars)); if( ap::fp_neq(xy(i,nvars),0) ) { ar.cvavgrelerror = ar.cvavgrelerror+fabs((r-xy(i,nvars))/xy(i,nvars)); nacv = nacv+1; } ncv = ncv+1; } if( ncv==0 ) { // // Something strange: ALL ui are degenerate. // Unexpected... // info = -255; return; } ar.rmserror = sqrt(ar.rmserror/npoints); ar.avgerror = ar.avgerror/npoints; if( na!=0 ) { ar.avgrelerror = ar.avgrelerror/na; } ar.cvrmserror = sqrt(ar.cvrmserror/ncv); ar.cvavgerror = ar.cvavgerror/ncv; if( nacv!=0 ) { ar.cvavgrelerror = ar.cvavgrelerror/nacv; } }
/************************************************************************* N-dimensional multiclass Fisher LDA Subroutine finds coefficients of linear combinations which optimally separates training set on classes. It returns N-dimensional basis whose vector are sorted by quality of training set separation (in descending order). INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - basis, array[0..NVars-1,0..NVars-1] columns of matrix stores basis vectors, sorted by quality of training set separation (in descending order) -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/ void fisherldan(const ap::real_2d_array& xy, int npoints, int nvars, int nclasses, int& info, ap::real_2d_array& w) { int i; int j; int k; int m; double v; ap::integer_1d_array c; ap::real_1d_array mu; ap::real_2d_array muc; ap::integer_1d_array nc; ap::real_2d_array sw; ap::real_2d_array st; ap::real_2d_array z; ap::real_2d_array z2; ap::real_2d_array tm; ap::real_2d_array sbroot; ap::real_2d_array a; ap::real_2d_array xyproj; ap::real_2d_array wproj; ap::real_1d_array tf; ap::real_1d_array d; ap::real_1d_array d2; ap::real_1d_array work; // // Test data // if( npoints<0||nvars<1||nclasses<2 ) { info = -1; return; } for(i = 0; i <= npoints-1; i++) { if( ap::round(xy(i,nvars))<0||ap::round(xy(i,nvars))>=nclasses ) { info = -2; return; } } info = 1; // // Special case: NPoints<=1 // Degenerate task. // if( npoints<=1 ) { info = 2; w.setbounds(0, nvars-1, 0, nvars-1); for(i = 0; i <= nvars-1; i++) { for(j = 0; j <= nvars-1; j++) { if( i==j ) { w(i,j) = 1; } else { w(i,j) = 0; } } } return; } // // Prepare temporaries // tf.setbounds(0, nvars-1); work.setbounds(1, ap::maxint(nvars, npoints)); // // Convert class labels from reals to integers (just for convenience) // c.setbounds(0, npoints-1); for(i = 0; i <= npoints-1; i++) { c(i) = ap::round(xy(i,nvars)); } // // Calculate class sizes and means // mu.setbounds(0, nvars-1); muc.setbounds(0, nclasses-1, 0, nvars-1); nc.setbounds(0, nclasses-1); for(j = 0; j <= nvars-1; j++) { mu(j) = 0; } for(i = 0; i <= nclasses-1; i++) { nc(i) = 0; for(j = 0; j <= nvars-1; j++) { muc(i,j) = 0; } } for(i = 0; i <= npoints-1; i++) { ap::vadd(&mu(0), 1, &xy(i, 0), 1, ap::vlen(0,nvars-1)); ap::vadd(&muc(c(i), 0), 1, &xy(i, 0), 1, ap::vlen(0,nvars-1)); nc(c(i)) = nc(c(i))+1; } for(i = 0; i <= nclasses-1; i++) { v = double(1)/double(nc(i)); ap::vmul(&muc(i, 0), 1, ap::vlen(0,nvars-1), v); } v = double(1)/double(npoints); ap::vmul(&mu(0), 1, ap::vlen(0,nvars-1), v); // // Create ST matrix // st.setbounds(0, nvars-1, 0, nvars-1); for(i = 0; i <= nvars-1; i++) { for(j = 0; j <= nvars-1; j++) { st(i,j) = 0; } } for(k = 0; k <= npoints-1; k++) { ap::vmove(&tf(0), 1, &xy(k, 0), 1, ap::vlen(0,nvars-1)); ap::vsub(&tf(0), 1, &mu(0), 1, ap::vlen(0,nvars-1)); for(i = 0; i <= nvars-1; i++) { v = tf(i); ap::vadd(&st(i, 0), 1, &tf(0), 1, ap::vlen(0,nvars-1), v); } } // // Create SW matrix // sw.setbounds(0, nvars-1, 0, nvars-1); for(i = 0; i <= nvars-1; i++) { for(j = 0; j <= nvars-1; j++) { sw(i,j) = 0; } } for(k = 0; k <= npoints-1; k++) { ap::vmove(&tf(0), 1, &xy(k, 0), 1, ap::vlen(0,nvars-1)); ap::vsub(&tf(0), 1, &muc(c(k), 0), 1, ap::vlen(0,nvars-1)); for(i = 0; i <= nvars-1; i++) { v = tf(i); ap::vadd(&sw(i, 0), 1, &tf(0), 1, ap::vlen(0,nvars-1), v); } } // // Maximize ratio J=(w'*ST*w)/(w'*SW*w). // // First, make transition from w to v such that w'*ST*w becomes v'*v: // v = root(ST)*w = R*w // R = root(D)*Z' // w = (root(ST)^-1)*v = RI*v // RI = Z*inv(root(D)) // J = (v'*v)/(v'*(RI'*SW*RI)*v) // ST = Z*D*Z' // // so we have // // J = (v'*v) / (v'*(inv(root(D))*Z'*SW*Z*inv(root(D)))*v) = // = (v'*v) / (v'*A*v) // if( !smatrixevd(st, nvars, 1, true, d, z) ) { info = -4; return; } w.setbounds(0, nvars-1, 0, nvars-1); if( ap::fp_less_eq(d(nvars-1),0)||ap::fp_less_eq(d(0),1000*ap::machineepsilon*d(nvars-1)) ) { // // Special case: D[NVars-1]<=0 // Degenerate task (all variables takes the same value). // if( ap::fp_less_eq(d(nvars-1),0) ) { info = 2; for(i = 0; i <= nvars-1; i++) { for(j = 0; j <= nvars-1; j++) { if( i==j ) { w(i,j) = 1; } else { w(i,j) = 0; } } } return; } // // Special case: degenerate ST matrix, multicollinearity found. // Since we know ST eigenvalues/vectors we can translate task to // non-degenerate form. // // Let WG is orthogonal basis of the non zero variance subspace // of the ST and let WZ is orthogonal basis of the zero variance // subspace. // // Projection on WG allows us to use LDA on reduced M-dimensional // subspace, N-M vectors of WZ allows us to update reduced LDA // factors to full N-dimensional subspace. // m = 0; for(k = 0; k <= nvars-1; k++) { if( ap::fp_less_eq(d(k),1000*ap::machineepsilon*d(nvars-1)) ) { m = k+1; } } ap::ap_error::make_assertion(m!=0, "FisherLDAN: internal error #1"); xyproj.setbounds(0, npoints-1, 0, nvars-m); matrixmatrixmultiply(xy, 0, npoints-1, 0, nvars-1, false, z, 0, nvars-1, m, nvars-1, false, 1.0, xyproj, 0, npoints-1, 0, nvars-m-1, 0.0, work); for(i = 0; i <= npoints-1; i++) { xyproj(i,nvars-m) = xy(i,nvars); } fisherldan(xyproj, npoints, nvars-m, nclasses, info, wproj); if( info<0 ) { return; } matrixmatrixmultiply(z, 0, nvars-1, m, nvars-1, false, wproj, 0, nvars-m-1, 0, nvars-m-1, false, 1.0, w, 0, nvars-1, 0, nvars-m-1, 0.0, work); for(k = nvars-m; k <= nvars-1; k++) { ap::vmove(&w(0, k), w.getstride(), &z(0, k-(nvars-m)), z.getstride(), ap::vlen(0,nvars-1)); } info = 2; } else { // // General case: no multicollinearity // tm.setbounds(0, nvars-1, 0, nvars-1); a.setbounds(0, nvars-1, 0, nvars-1); matrixmatrixmultiply(sw, 0, nvars-1, 0, nvars-1, false, z, 0, nvars-1, 0, nvars-1, false, 1.0, tm, 0, nvars-1, 0, nvars-1, 0.0, work); matrixmatrixmultiply(z, 0, nvars-1, 0, nvars-1, true, tm, 0, nvars-1, 0, nvars-1, false, 1.0, a, 0, nvars-1, 0, nvars-1, 0.0, work); for(i = 0; i <= nvars-1; i++) { for(j = 0; j <= nvars-1; j++) { a(i,j) = a(i,j)/sqrt(d(i)*d(j)); } } if( !smatrixevd(a, nvars, 1, true, d2, z2) ) { info = -4; return; } for(k = 0; k <= nvars-1; k++) { for(i = 0; i <= nvars-1; i++) { tf(i) = z2(i,k)/sqrt(d(i)); } for(i = 0; i <= nvars-1; i++) { v = ap::vdotproduct(&z(i, 0), 1, &tf(0), 1, ap::vlen(0,nvars-1)); w(i,k) = v; } } } // // Post-processing: // * normalization // * converting to non-negative form, if possible // for(k = 0; k <= nvars-1; k++) { v = ap::vdotproduct(&w(0, k), w.getstride(), &w(0, k), w.getstride(), ap::vlen(0,nvars-1)); v = 1/sqrt(v); ap::vmul(&w(0, k), w.getstride(), ap::vlen(0,nvars-1), v); v = 0; for(i = 0; i <= nvars-1; i++) { v = v+w(i,k); } if( ap::fp_less(v,0) ) { ap::vmul(&w(0, k), w.getstride(), ap::vlen(0,nvars-1), -1); } } }
/************************************************************************* Singular value decomposition of a rectangular matrix. The algorithm calculates the singular value decomposition of a matrix of size MxN: A = U * S * V^T The algorithm finds the singular values and, optionally, matrices U and V^T. The algorithm can find both first min(M,N) columns of matrix U and rows of matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM and NxN respectively). Take into account that the subroutine does not return matrix V but V^T. Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. UNeeded - 0, 1 or 2. See the description of the parameter U. VTNeeded - 0, 1 or 2. See the description of the parameter VT. AdditionalMemory - If the parameter: * equals 0, the algorithm doesn’t use additional memory (lower requirements, lower performance). * equals 1, the algorithm uses additional memory of size min(M,N)*min(M,N) of real numbers. It often speeds up the algorithm. * equals 2, the algorithm uses additional memory of size M*min(M,N) of real numbers. It allows to get a maximum performance. The recommended value of the parameter is 2. Output parameters: W - contains singular values in descending order. U - if UNeeded=0, U isn't changed, the left singular vectors are not calculated. if Uneeded=1, U contains left singular vectors (first min(M,N) columns of matrix U). Array whose indexes range within [0..M-1, 0..Min(M,N)-1]. if UNeeded=2, U contains matrix U wholly. Array whose indexes range within [0..M-1, 0..M-1]. VT - if VTNeeded=0, VT isn’t changed, the right singular vectors are not calculated. if VTNeeded=1, VT contains right singular vectors (first min(M,N) rows of matrix V^T). Array whose indexes range within [0..min(M,N)-1, 0..N-1]. if VTNeeded=2, VT contains matrix V^T wholly. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ bool rmatrixsvd(ap::real_2d_array a, int m, int n, int uneeded, int vtneeded, int additionalmemory, ap::real_1d_array& w, ap::real_2d_array& u, ap::real_2d_array& vt) { bool result; ap::real_1d_array tauq; ap::real_1d_array taup; ap::real_1d_array tau; ap::real_1d_array e; ap::real_1d_array work; ap::real_2d_array t2; bool isupper; int minmn; int ncu; int nrvt; int nru; int ncvt; int i; int j; result = true; if( m==0||n==0 ) { return result; } ap::ap_error::make_assertion(uneeded>=0&&uneeded<=2, "SVDDecomposition: wrong parameters!"); ap::ap_error::make_assertion(vtneeded>=0&&vtneeded<=2, "SVDDecomposition: wrong parameters!"); ap::ap_error::make_assertion(additionalmemory>=0&&additionalmemory<=2, "SVDDecomposition: wrong parameters!"); // // initialize // minmn = ap::minint(m, n); w.setbounds(1, minmn); ncu = 0; nru = 0; if( uneeded==1 ) { nru = m; ncu = minmn; u.setbounds(0, nru-1, 0, ncu-1); } if( uneeded==2 ) { nru = m; ncu = m; u.setbounds(0, nru-1, 0, ncu-1); } nrvt = 0; ncvt = 0; if( vtneeded==1 ) { nrvt = minmn; ncvt = n; vt.setbounds(0, nrvt-1, 0, ncvt-1); } if( vtneeded==2 ) { nrvt = n; ncvt = n; vt.setbounds(0, nrvt-1, 0, ncvt-1); } // // M much larger than N // Use bidiagonal reduction with QR-decomposition // if( ap::fp_greater(m,1.6*n) ) { if( uneeded==0 ) { // // No left singular vectors to be computed // rmatrixqr(a, m, n, tau); for(i = 0; i <= n-1; i++) { for(j = 0; j <= i-1; j++) { a(i,j) = 0; } } rmatrixbd(a, n, n, tauq, taup); rmatrixbdunpackpt(a, n, n, taup, nrvt, vt); rmatrixbdunpackdiagonals(a, n, n, isupper, w, e); result = rmatrixbdsvd(w, e, n, isupper, false, u, 0, a, 0, vt, ncvt); return result; } else { // // Left singular vectors (may be full matrix U) to be computed // rmatrixqr(a, m, n, tau); rmatrixqrunpackq(a, m, n, tau, ncu, u); for(i = 0; i <= n-1; i++) { for(j = 0; j <= i-1; j++) { a(i,j) = 0; } } rmatrixbd(a, n, n, tauq, taup); rmatrixbdunpackpt(a, n, n, taup, nrvt, vt); rmatrixbdunpackdiagonals(a, n, n, isupper, w, e); if( additionalmemory<1 ) { // // No additional memory can be used // rmatrixbdmultiplybyq(a, n, n, tauq, u, m, n, true, false); result = rmatrixbdsvd(w, e, n, isupper, false, u, m, a, 0, vt, ncvt); } else { // // Large U. Transforming intermediate matrix T2 // work.setbounds(1, ap::maxint(m, n)); rmatrixbdunpackq(a, n, n, tauq, n, t2); copymatrix(u, 0, m-1, 0, n-1, a, 0, m-1, 0, n-1); inplacetranspose(t2, 0, n-1, 0, n-1, work); result = rmatrixbdsvd(w, e, n, isupper, false, u, 0, t2, n, vt, ncvt); matrixmatrixmultiply(a, 0, m-1, 0, n-1, false, t2, 0, n-1, 0, n-1, true, 1.0, u, 0, m-1, 0, n-1, 0.0, work); } return result; } } // // N much larger than M // Use bidiagonal reduction with LQ-decomposition // if( ap::fp_greater(n,1.6*m) ) { if( vtneeded==0 ) { // // No right singular vectors to be computed // rmatrixlq(a, m, n, tau); for(i = 0; i <= m-1; i++) { for(j = i+1; j <= m-1; j++) { a(i,j) = 0; } } rmatrixbd(a, m, m, tauq, taup); rmatrixbdunpackq(a, m, m, tauq, ncu, u); rmatrixbdunpackdiagonals(a, m, m, isupper, w, e); work.setbounds(1, m); inplacetranspose(u, 0, nru-1, 0, ncu-1, work); result = rmatrixbdsvd(w, e, m, isupper, false, a, 0, u, nru, vt, 0); inplacetranspose(u, 0, nru-1, 0, ncu-1, work); return result; } else { // // Right singular vectors (may be full matrix VT) to be computed // rmatrixlq(a, m, n, tau); rmatrixlqunpackq(a, m, n, tau, nrvt, vt); for(i = 0; i <= m-1; i++) { for(j = i+1; j <= m-1; j++) { a(i,j) = 0; } } rmatrixbd(a, m, m, tauq, taup); rmatrixbdunpackq(a, m, m, tauq, ncu, u); rmatrixbdunpackdiagonals(a, m, m, isupper, w, e); work.setbounds(1, ap::maxint(m, n)); inplacetranspose(u, 0, nru-1, 0, ncu-1, work); if( additionalmemory<1 ) { // // No additional memory available // rmatrixbdmultiplybyp(a, m, m, taup, vt, m, n, false, true); result = rmatrixbdsvd(w, e, m, isupper, false, a, 0, u, nru, vt, n); } else { // // Large VT. Transforming intermediate matrix T2 // rmatrixbdunpackpt(a, m, m, taup, m, t2); result = rmatrixbdsvd(w, e, m, isupper, false, a, 0, u, nru, t2, m); copymatrix(vt, 0, m-1, 0, n-1, a, 0, m-1, 0, n-1); matrixmatrixmultiply(t2, 0, m-1, 0, m-1, false, a, 0, m-1, 0, n-1, false, 1.0, vt, 0, m-1, 0, n-1, 0.0, work); } inplacetranspose(u, 0, nru-1, 0, ncu-1, work); return result; } } // // M<=N // We can use inplace transposition of U to get rid of columnwise operations // if( m<=n ) { rmatrixbd(a, m, n, tauq, taup); rmatrixbdunpackq(a, m, n, tauq, ncu, u); rmatrixbdunpackpt(a, m, n, taup, nrvt, vt); rmatrixbdunpackdiagonals(a, m, n, isupper, w, e); work.setbounds(1, m); inplacetranspose(u, 0, nru-1, 0, ncu-1, work); result = rmatrixbdsvd(w, e, minmn, isupper, false, a, 0, u, nru, vt, ncvt); inplacetranspose(u, 0, nru-1, 0, ncu-1, work); return result; } // // Simple bidiagonal reduction // rmatrixbd(a, m, n, tauq, taup); rmatrixbdunpackq(a, m, n, tauq, ncu, u); rmatrixbdunpackpt(a, m, n, taup, nrvt, vt); rmatrixbdunpackdiagonals(a, m, n, isupper, w, e); if( additionalmemory<2||uneeded==0 ) { // // We cant use additional memory or there is no need in such operations // result = rmatrixbdsvd(w, e, minmn, isupper, false, u, nru, a, 0, vt, ncvt); } else { // // We can use additional memory // t2.setbounds(0, minmn-1, 0, m-1); copyandtranspose(u, 0, m-1, 0, minmn-1, t2, 0, minmn-1, 0, m-1); result = rmatrixbdsvd(w, e, minmn, isupper, false, u, 0, t2, m, vt, ncvt); copyandtranspose(t2, 0, minmn-1, 0, m-1, u, 0, m-1, 0, minmn-1); } return result; }
/************************************************************************* Weighted constained linear least squares fitting. This is variation of LSFitLinearW(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() is called. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * -1 incorrect N/M/K were specified * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. SEE ALSO LSFitLinear LSFitLinearC LSFitLinearWC -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearwc(ap::real_1d_array y, const ap::real_1d_array& w, const ap::real_2d_array& fmatrix, ap::real_2d_array cmatrix, int n, int m, int k, int& info, ap::real_1d_array& c, lsfitreport& rep) { int i; int j; ap::real_1d_array tau; ap::real_2d_array q; ap::real_2d_array f2; ap::real_1d_array tmp; ap::real_1d_array c0; double v; if( n<1||m<1||k<0 ) { info = -1; return; } if( k>=m ) { info = -3; return; } // // Solve // if( k==0 ) { // // no constraints // lsfitlinearinternal(y, w, fmatrix, n, m, info, c, rep); } else { // // First, find general form solution of constraints system: // * factorize C = L*Q // * unpack Q // * fill upper part of C with zeros (for RCond) // // We got C=C0+Q2'*y where Q2 is lower M-K rows of Q. // rmatrixlq(cmatrix, k, m, tau); rmatrixlqunpackq(cmatrix, k, m, tau, m, q); for(i = 0; i <= k-1; i++) { for(j = i+1; j <= m-1; j++) { cmatrix(i,j) = 0.0; } } if( ap::fp_less(rmatrixlurcondinf(cmatrix, k),1000*ap::machineepsilon) ) { info = -3; return; } tmp.setlength(k); for(i = 0; i <= k-1; i++) { if( i>0 ) { v = ap::vdotproduct(&cmatrix(i, 0), 1, &tmp(0), 1, ap::vlen(0,i-1)); } else { v = 0; } tmp(i) = (cmatrix(i,m)-v)/cmatrix(i,i); } c0.setlength(m); for(i = 0; i <= m-1; i++) { c0(i) = 0; } for(i = 0; i <= k-1; i++) { v = tmp(i); ap::vadd(&c0(0), 1, &q(i, 0), 1, ap::vlen(0,m-1), v); } // // Second, prepare modified matrix F2 = F*Q2' and solve modified task // tmp.setlength(ap::maxint(n, m)+1); f2.setlength(n, m-k); matrixvectormultiply(fmatrix, 0, n-1, 0, m-1, false, c0, 0, m-1, -1.0, y, 0, n-1, 1.0); matrixmatrixmultiply(fmatrix, 0, n-1, 0, m-1, false, q, k, m-1, 0, m-1, true, 1.0, f2, 0, n-1, 0, m-k-1, 0.0, tmp); lsfitlinearinternal(y, w, f2, n, m-k, info, tmp, rep); rep.taskrcond = -1; if( info<=0 ) { return; } // // then, convert back to original answer: C = C0 + Q2'*Y0 // c.setlength(m); ap::vmove(&c(0), 1, &c0(0), 1, ap::vlen(0,m-1)); matrixvectormultiply(q, k, m-1, 0, m-1, true, tmp, 0, m-k-1, 1.0, c, 0, m-1, 1.0); } }
/* * @depricated * * NR implementation by RTG. * * Note on matrix vector multiplication: * void matrixmatrixmultiply(const alglib::real_2d_array& a, * int ai1, * int ai2, * int aj1, * int aj2, * bool transa, * const alglib::real_2d_array& b, * int bi1, * int bi2, * int bj1, * int bj2, * bool transb, * double alpha, * alglib::real_2d_array& c, * int ci1, * int ci2, * int cj1, * int cj2, * double beta, * alglib::real_1d_array& work); * * transa is true if transposed. * Operation is: c = A * alpha * b + beta * C * * * @input const vector<vector<double>> data holds explantory variables. each inner vector is a variable. * @input const vector<double> response holds response variable. * @input vector<double> Place to return the information matrix inverse. Column major order. * Expects correct size. */ vector<double> LogisticRegression::newtonRaphsonFast(const vector<vector<double> > &data, const vector<double> &response , vector<vector<double> > &invInfMatrix, double startVal) { vector<double> betas; // Variables used in the computation: alglib::real_1d_array tempBetas; alglib::real_2d_array tempData; alglib::real_1d_array oldExpY; alglib::real_2d_array tempDeriv; // holds data' * w * data. Returned in last input param. alglib::real_1d_array expY; alglib::real_1d_array adjy; double stop_var = 1e-10; int iter = 0; int maxIter = 200; int numVars = data.size(); if(numVars < 1){ throw NewtonRaphsonFailureEx(); } int numSamples = data.at(0).size(); if(numSamples < 1){ throw NewtonRaphsonFailureEx(); } tempBetas.setlength(numVars); tempData.setlength(numSamples,numVars); oldExpY.setlength(numSamples); expY.setlength(numSamples); tempDeriv.setlength(numVars,numVars); adjy.setlength(numSamples); for(int i=0;i < numVars; i++){ for(int j=0;j < numSamples; j++){ tempData(j,i) = data.at(i).at(j); } tempBetas(i) = startVal; } for(int i=0;i < numSamples;i++){ oldExpY(i) = -1; adjy(i) = 0; // makes valgrind happier. } while(iter < maxIter){ //data * tempBetas matrixvectormultiply(tempData, 0, numSamples-1,0,numVars-1,false, tempBetas, 0, numVars-1, 1.0, adjy, 0, numSamples-1, 0.0); for(int i=0;i < numSamples; i++){ expY(i) = 1 / (1 + exp(-adjy(i))); } // build deriv. double deriv = -100000; for(int i=0;i < numSamples; i++){ if(expY(i) * (1 - expY(i)) > deriv) deriv = expY(i) * (1 - expY(i)); } if(stop_var * 0.001 > deriv) deriv = stop_var * 0.001; // adjy = adjy + (y-expy) ./ deriv for(int i=0;i<numSamples;i++){ adjy(i) = adjy(i) + (response.at(i) - expY(i)) / deriv; } // build data' * w * data alglib::real_1d_array work; work.setlength(numSamples); // This temporary workspace must be one larger than the longest // row or column that will be seen. Otherwise, the program // crashes or - worse! - corrupts data. matrixmatrixmultiply(tempData,0,numSamples-1,0,numVars-1,true, tempData,0,numSamples-1,0,numVars-1,false,deriv, tempDeriv,0,numVars-1,0,numVars-1,0.0,work); #if DEBUG_NR cout << "A' * w * A " << endl; cout << tempDeriv(0,0) << " " << tempDeriv(0,1) << endl; cout << tempDeriv(1,0) << " " << tempDeriv(1,1) << endl; cout << endl; #endif alglib::matinvreport report; alglib::ae_int_t reportInfo; rmatrixinverse(tempDeriv, reportInfo, report); if( reportInfo != 1 ){ throw SingularMatrixEx(); } #if DEBUG_NR cout << "inv(A' * w * A) " << endl; cout << tempDeriv(0,0) << " " << tempDeriv(0,1) << endl; cout << tempDeriv(1,0) << " " << tempDeriv(1,1) << endl; cout << endl; #endif matrixvectormultiply(tempData,0,numSamples-1,0,numVars-1,true, adjy,0,numSamples-1,deriv, work,0,numVars-1,0.0); matrixvectormultiply(tempDeriv,0,numVars-1,0,numVars-1,false, work,0,numVars-1,1.0, tempBetas,0,numVars-1,0.0); #if DEBUG_NR cout << "Betas "; for(int i=0;i < numVars;i++) cout << tempBetas(i) << " " ; cout << endl; #endif double stop = 0.0; for(int i=0;i < numSamples;i++){ stop += abs(expY(i) - oldExpY(i)); } if (stop < numSamples*stop_var){ break; } oldExpY = expY; iter++; } if(iter == maxIter){ throw NewtonRaphsonIterationEx(); } betas.clear(); for(int i=0;i<numVars;i++){ betas.push_back(tempBetas(i)); } for(int i=0;i<numVars;i++){ for(int j=0;j<numVars;j++){ invInfMatrix.at(i).at(j) = tempDeriv(i,j); } } return betas; }