/************************************************************************* Determinant calculation of the symmetric positive definite matrix. Input parameters: A - matrix. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper = True, then the symmetric matrix A is given by its upper triangle, and the lower triangle isn’t used by subroutine. Similarly, if IsUpper = False, then A is given by its lower triangle. Result: determinant of matrix A. If matrix A is not positive definite, then subroutine returns -1. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixdet(ap::real_2d_array a, int n, bool isupper) { double result; if( !spdmatrixcholesky(a, n, isupper) ) { result = -1; } else { result = spdmatrixcholeskydet(a, n); } return result; }
/************************************************************************* Solving a system of linear equations with a symmetric positive-definite matrix by using the Cholesky decomposition. The algorithm solves a system of linear equations whose matrix is symmetric and positive-definite. Input parameters: A - upper or lower triangle part of a symmetric system matrix. Array whose indexes range within [0..N-1, 0..N-1]. B - right side of a system. Array whose index ranges within [0..N-1]. N - size of matrix A. IsUpper - points to the triangle of matrix A in which the matrix is stored. Output parameters: X - solution of a system. Array whose index ranges within [0..N-1]. Result: True, if the system is not singular. False, if the system is singular. In this case, X doesn't contain a solution. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ bool spdmatrixsolve(ap::real_2d_array a, ap::real_1d_array b, int n, bool isupper, ap::real_1d_array& x) { bool result; result = spdmatrixcholesky(a, n, isupper); if( !result ) { return result; } result = spdmatrixcholeskysolve(a, b, n, isupper, x); return result; }
/************************************************************************* Algorithm for reduction of the following generalized symmetric positive- definite eigenvalue problem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3) to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and the given problems are the same, and the eigenvectors of the given problem could be obtained by multiplying the obtained eigenvectors by the transformation matrix x = R*y). Here A is a symmetric matrix, B - symmetric positive-definite matrix. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: A - symmetric matrix which is given by its upper or lower triangle depending on IsUpperA. Contains matrix C. Array whose indexes range within [0..N-1, 0..N-1]. R - upper triangular or low triangular transformation matrix which is used to obtain the eigenvectors of a given problem as the product of eigenvectors of C (from the right) and matrix R (from the left). If the matrix is upper triangular, the elements below the main diagonal are equal to 0 (and vice versa). Thus, we can perform the multiplication without taking into account the internal structure (which is an easier though less effective way). Array whose indexes range within [0..N-1, 0..N-1]. IsUpperR - type of matrix R (upper or lower triangular). Result: True, if the problem was reduced successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix is not positive-definite). -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixgevdreduce(ap::real_2d_array& a, int n, bool isuppera, const ap::real_2d_array& b, bool isupperb, int problemtype, ap::real_2d_array& r, bool& isupperr) { bool result; ap::real_2d_array t; ap::real_1d_array w1; ap::real_1d_array w2; ap::real_1d_array w3; int i; int j; double v; ap::ap_error::make_assertion(n>0, "SMatrixGEVDReduce: N<=0!"); ap::ap_error::make_assertion(problemtype==1||problemtype==2||problemtype==3, "SMatrixGEVDReduce: incorrect ProblemType!"); result = true; // // Problem 1: A*x = lambda*B*x // // Reducing to: // C*y = lambda*y // C = L^(-1) * A * L^(-T) // x = L^(-T) * y // if( problemtype==1 ) { // // Factorize B in T: B = LL' // t.setbounds(0, n-1, 0, n-1); if( isupperb ) { for(i = 0; i <= n-1; i++) { ap::vmove(t.getcolumn(i, i, n-1), b.getrow(i, i, n-1)); } } else { for(i = 0; i <= n-1; i++) { ap::vmove(&t(i, 0), &b(i, 0), ap::vlen(0,i)); } } if( !spdmatrixcholesky(t, n, false) ) { result = false; return result; } // // Invert L in T // if( !rmatrixtrinverse(t, n, false, false) ) { result = false; return result; } // // Build L^(-1) * A * L^(-T) in R // w1.setbounds(1, n); w2.setbounds(1, n); r.setbounds(0, n-1, 0, n-1); for(j = 1; j <= n; j++) { // // Form w2 = A * l'(j) (here l'(j) is j-th column of L^(-T)) // ap::vmove(&w1(1), &t(j-1, 0), ap::vlen(1,j)); symmetricmatrixvectormultiply(a, isuppera, 0, j-1, w1, 1.0, w2); if( isuppera ) { matrixvectormultiply(a, 0, j-1, j, n-1, true, w1, 1, j, 1.0, w2, j+1, n, 0.0); } else { matrixvectormultiply(a, j, n-1, 0, j-1, false, w1, 1, j, 1.0, w2, j+1, n, 0.0); } // // Form l(i)*w2 (here l(i) is i-th row of L^(-1)) // for(i = 1; i <= n; i++) { v = ap::vdotproduct(&t(i-1, 0), &w2(1), ap::vlen(0,i-1)); r(i-1,j-1) = v; } } // // Copy R to A // for(i = 0; i <= n-1; i++) { ap::vmove(&a(i, 0), &r(i, 0), ap::vlen(0,n-1)); } // // Copy L^(-1) from T to R and transpose // isupperr = true; for(i = 0; i <= n-1; i++) { for(j = 0; j <= i-1; j++) { r(i,j) = 0; } } for(i = 0; i <= n-1; i++) { ap::vmove(r.getrow(i, i, n-1), t.getcolumn(i, i, n-1)); } return result; } // // Problem 2: A*B*x = lambda*x // or // problem 3: B*A*x = lambda*x // // Reducing to: // C*y = lambda*y // C = U * A * U' // B = U'* U // if( problemtype==2||problemtype==3 ) { // // Factorize B in T: B = U'*U // t.setbounds(0, n-1, 0, n-1); if( isupperb ) { for(i = 0; i <= n-1; i++) { ap::vmove(&t(i, i), &b(i, i), ap::vlen(i,n-1)); } } else { for(i = 0; i <= n-1; i++) { ap::vmove(t.getrow(i, i, n-1), b.getcolumn(i, i, n-1)); } } if( !spdmatrixcholesky(t, n, true) ) { result = false; return result; } // // Build U * A * U' in R // w1.setbounds(1, n); w2.setbounds(1, n); w3.setbounds(1, n); r.setbounds(0, n-1, 0, n-1); for(j = 1; j <= n; j++) { // // Form w2 = A * u'(j) (here u'(j) is j-th column of U') // ap::vmove(&w1(1), &t(j-1, j-1), ap::vlen(1,n-j+1)); symmetricmatrixvectormultiply(a, isuppera, j-1, n-1, w1, 1.0, w3); ap::vmove(&w2(j), &w3(1), ap::vlen(j,n)); ap::vmove(&w1(j), &t(j-1, j-1), ap::vlen(j,n)); if( isuppera ) { matrixvectormultiply(a, 0, j-2, j-1, n-1, false, w1, j, n, 1.0, w2, 1, j-1, 0.0); } else { matrixvectormultiply(a, j-1, n-1, 0, j-2, true, w1, j, n, 1.0, w2, 1, j-1, 0.0); } // // Form u(i)*w2 (here u(i) is i-th row of U) // for(i = 1; i <= n; i++) { v = ap::vdotproduct(&t(i-1, i-1), &w2(i), ap::vlen(i-1,n-1)); r(i-1,j-1) = v; } } // // Copy R to A // for(i = 0; i <= n-1; i++) { ap::vmove(&a(i, 0), &r(i, 0), ap::vlen(0,n-1)); } if( problemtype==2 ) { // // Invert U in T // if( !rmatrixtrinverse(t, n, true, false) ) { result = false; return result; } // // Copy U^-1 from T to R // isupperr = true; for(i = 0; i <= n-1; i++) { for(j = 0; j <= i-1; j++) { r(i,j) = 0; } } for(i = 0; i <= n-1; i++) { ap::vmove(&r(i, i), &t(i, i), ap::vlen(i,n-1)); } } else { // // Copy U from T to R and transpose // isupperr = false; for(i = 0; i <= n-1; i++) { for(j = i+1; j <= n-1; j++) { r(i,j) = 0; } } for(i = 0; i <= n-1; i++) { ap::vmove(r.getcolumn(i, i, n-1), t.getrow(i, i, n-1)); } } } return result; }
/************************************************************************* Neural network training using modified Levenberg-Marquardt with exact Hessian calculation and regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for small and medium scale problems (hundreds of weights). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -9, if internal matrix inverse subroutine failed * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlptrainlm(multilayerperceptron& network, const ap::real_2d_array& xy, int npoints, double decay, int restarts, int& info, mlpreport& rep) { int nin; int nout; int wcount; double lmftol; double lmsteptol; int i; int j; int k; int mx; double v; double e; double enew; double xnorm2; double stepnorm; ap::real_1d_array g; ap::real_1d_array d; ap::real_2d_array h; ap::real_2d_array hmod; ap::real_2d_array z; bool spd; double nu; double lambda; double lambdaup; double lambdadown; int cvcnt; double cvrelcnt; lbfgsreport internalrep; lbfgsstate state; ap::real_1d_array x; ap::real_1d_array y; ap::real_1d_array wbase; double wstep; ap::real_1d_array wdir; ap::real_1d_array wt; ap::real_1d_array wx; int pass; ap::real_1d_array wbest; double ebest; mlpproperties(network, nin, nout, wcount); lambdaup = 10; lambdadown = 0.3; lmftol = 0.001; lmsteptol = 0.001; // // Test for inputs // if( npoints<=0||restarts<1 ) { info = -1; return; } if( mlpissoftmax(network) ) { for(i = 0; i <= npoints-1; i++) { if( ap::round(xy(i,nin))<0||ap::round(xy(i,nin))>=nout ) { info = -2; return; } } } decay = ap::maxreal(decay, mindecay); info = 2; // // Initialize data // rep.ngrad = 0; rep.nhess = 0; rep.ncholesky = 0; // // General case. // Prepare task and network. Allocate space. // mlpinitpreprocessor(network, xy, npoints); g.setbounds(0, wcount-1); h.setbounds(0, wcount-1, 0, wcount-1); hmod.setbounds(0, wcount-1, 0, wcount-1); wbase.setbounds(0, wcount-1); wdir.setbounds(0, wcount-1); wbest.setbounds(0, wcount-1); wt.setbounds(0, wcount-1); wx.setbounds(0, wcount-1); ebest = ap::maxrealnumber; // // Multiple passes // for(pass = 1; pass <= restarts; pass++) { // // Initialize weights // mlprandomize(network); // // First stage of the hybrid algorithm: LBFGS // ap::vmove(&wbase(0), &network.weights(0), ap::vlen(0,wcount-1)); minlbfgs(wcount, ap::minint(wcount, 5), wbase, 0.0, 0.0, 0.0, ap::maxint(25, wcount), 0, state); while(minlbfgsiteration(state)) { // // gradient // ap::vmove(&network.weights(0), &state.x(0), ap::vlen(0,wcount-1)); mlpgradbatch(network, xy, npoints, state.f, state.g); // // weight decay // v = ap::vdotproduct(&network.weights(0), &network.weights(0), ap::vlen(0,wcount-1)); state.f = state.f+0.5*decay*v; ap::vadd(&state.g(0), &network.weights(0), ap::vlen(0,wcount-1), decay); // // next iteration // rep.ngrad = rep.ngrad+1; } minlbfgsresults(state, wbase, internalrep); ap::vmove(&network.weights(0), &wbase(0), ap::vlen(0,wcount-1)); // // Second stage of the hybrid algorithm: LM // // Initialize H with identity matrix, // G with gradient, // E with regularized error. // mlphessianbatch(network, xy, npoints, e, g, h); v = ap::vdotproduct(&network.weights(0), &network.weights(0), ap::vlen(0,wcount-1)); e = e+0.5*decay*v; ap::vadd(&g(0), &network.weights(0), ap::vlen(0,wcount-1), decay); for(k = 0; k <= wcount-1; k++) { h(k,k) = h(k,k)+decay; } rep.nhess = rep.nhess+1; lambda = 0.001; nu = 2; while(true) { // // 1. HMod = H+lambda*I // 2. Try to solve (H+Lambda*I)*dx = -g. // Increase lambda if left part is not positive definite. // for(i = 0; i <= wcount-1; i++) { ap::vmove(&hmod(i, 0), &h(i, 0), ap::vlen(0,wcount-1)); hmod(i,i) = hmod(i,i)+lambda; } spd = spdmatrixcholesky(hmod, wcount, true); rep.ncholesky = rep.ncholesky+1; if( !spd ) { lambda = lambda*lambdaup*nu; nu = nu*2; continue; } if( !spdmatrixcholeskysolve(hmod, g, wcount, true, wdir) ) { lambda = lambda*lambdaup*nu; nu = nu*2; continue; } ap::vmul(&wdir(0), ap::vlen(0,wcount-1), -1); // // Lambda found. // 1. Save old w in WBase // 1. Test some stopping criterions // 2. If error(w+wdir)>error(w), increase lambda // ap::vadd(&network.weights(0), &wdir(0), ap::vlen(0,wcount-1)); xnorm2 = ap::vdotproduct(&network.weights(0), &network.weights(0), ap::vlen(0,wcount-1)); stepnorm = ap::vdotproduct(&wdir(0), &wdir(0), ap::vlen(0,wcount-1)); stepnorm = sqrt(stepnorm); enew = mlperror(network, xy, npoints)+0.5*decay*xnorm2; if( ap::fp_less(stepnorm,lmsteptol*(1+sqrt(xnorm2))) ) { break; } if( ap::fp_greater(enew,e) ) { lambda = lambda*lambdaup*nu; nu = nu*2; continue; } // // Optimize using inv(cholesky(H)) as preconditioner // if( !rmatrixtrinverse(hmod, wcount, true, false) ) { // // if matrix can't be inverted then exit with errors // TODO: make WCount steps in direction suggested by HMod // info = -9; return; } ap::vmove(&wbase(0), &network.weights(0), ap::vlen(0,wcount-1)); for(i = 0; i <= wcount-1; i++) { wt(i) = 0; } minlbfgs(wcount, wcount, wt, 0.0, 0.0, 0.0, 5, 0, state); while(minlbfgsiteration(state)) { // // gradient // for(i = 0; i <= wcount-1; i++) { v = ap::vdotproduct(&state.x(i), &hmod(i, i), ap::vlen(i,wcount-1)); network.weights(i) = wbase(i)+v; } mlpgradbatch(network, xy, npoints, state.f, g); for(i = 0; i <= wcount-1; i++) { state.g(i) = 0; } for(i = 0; i <= wcount-1; i++) { v = g(i); ap::vadd(&state.g(i), &hmod(i, i), ap::vlen(i,wcount-1), v); } // // weight decay // grad(x'*x) = A'*(x0+A*t) // v = ap::vdotproduct(&network.weights(0), &network.weights(0), ap::vlen(0,wcount-1)); state.f = state.f+0.5*decay*v; for(i = 0; i <= wcount-1; i++) { v = decay*network.weights(i); ap::vadd(&state.g(i), &hmod(i, i), ap::vlen(i,wcount-1), v); } // // next iteration // rep.ngrad = rep.ngrad+1; } minlbfgsresults(state, wt, internalrep); // // Accept new position. // Calculate Hessian // for(i = 0; i <= wcount-1; i++) { v = ap::vdotproduct(&wt(i), &hmod(i, i), ap::vlen(i,wcount-1)); network.weights(i) = wbase(i)+v; } mlphessianbatch(network, xy, npoints, e, g, h); v = ap::vdotproduct(&network.weights(0), &network.weights(0), ap::vlen(0,wcount-1)); e = e+0.5*decay*v; ap::vadd(&g(0), &network.weights(0), ap::vlen(0,wcount-1), decay); for(k = 0; k <= wcount-1; k++) { h(k,k) = h(k,k)+decay; } rep.nhess = rep.nhess+1; // // Update lambda // lambda = lambda*lambdadown; nu = 2; } // // update WBest // v = ap::vdotproduct(&network.weights(0), &network.weights(0), ap::vlen(0,wcount-1)); e = 0.5*decay*v+mlperror(network, xy, npoints); if( ap::fp_less(e,ebest) ) { ebest = e; ap::vmove(&wbest(0), &network.weights(0), ap::vlen(0,wcount-1)); } } // // copy WBest to output // ap::vmove(&network.weights(0), &wbest(0), ap::vlen(0,wcount-1)); }
void spline1dfitpenalizedw(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _w; ae_int_t i; ae_int_t j; ae_int_t b; double v; double relcnt; double xa; double xb; double sa; double sb; ae_vector xoriginal; ae_vector yoriginal; double pdecay; double tdecay; ae_matrix fmatrix; ae_vector fcolumn; ae_vector y2; ae_vector w2; ae_vector xc; ae_vector yc; ae_vector dc; double fdmax; double admax; ae_matrix amatrix; ae_matrix d2matrix; double fa; double ga; double fb; double gb; double lambdav; ae_vector bx; ae_vector by; ae_vector bd1; ae_vector bd2; ae_vector tx; ae_vector ty; ae_vector td; spline1dinterpolant bs; ae_matrix nmatrix; ae_vector rightpart; fblslincgstate cgstate; ae_vector c; ae_vector tmp0; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state, ae_true); x = &_x; ae_vector_init_copy(&_y, y, _state, ae_true); y = &_y; ae_vector_init_copy(&_w, w, _state, ae_true); w = &_w; *info = 0; _spline1dinterpolant_clear(s); _spline1dfitreport_clear(rep); ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); ae_vector_init(&fcolumn, 0, DT_REAL, _state, ae_true); ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); ae_vector_init(&dc, 0, DT_INT, _state, ae_true); ae_matrix_init(&amatrix, 0, 0, DT_REAL, _state, ae_true); ae_matrix_init(&d2matrix, 0, 0, DT_REAL, _state, ae_true); ae_vector_init(&bx, 0, DT_REAL, _state, ae_true); ae_vector_init(&by, 0, DT_REAL, _state, ae_true); ae_vector_init(&bd1, 0, DT_REAL, _state, ae_true); ae_vector_init(&bd2, 0, DT_REAL, _state, ae_true); ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); ae_vector_init(&ty, 0, DT_REAL, _state, ae_true); ae_vector_init(&td, 0, DT_REAL, _state, ae_true); _spline1dinterpolant_init(&bs, _state, ae_true); ae_matrix_init(&nmatrix, 0, 0, DT_REAL, _state, ae_true); ae_vector_init(&rightpart, 0, DT_REAL, _state, ae_true); _fblslincgstate_init(&cgstate, _state, ae_true); ae_vector_init(&c, 0, DT_REAL, _state, ae_true); ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); ae_assert(n>=1, "Spline1DFitPenalizedW: N<1!", _state); ae_assert(m>=4, "Spline1DFitPenalizedW: M<4!", _state); ae_assert(x->cnt>=n, "Spline1DFitPenalizedW: Length(X)<N!", _state); ae_assert(y->cnt>=n, "Spline1DFitPenalizedW: Length(Y)<N!", _state); ae_assert(w->cnt>=n, "Spline1DFitPenalizedW: Length(W)<N!", _state); ae_assert(isfinitevector(x, n, _state), "Spline1DFitPenalizedW: X contains infinite or NAN values!", _state); ae_assert(isfinitevector(y, n, _state), "Spline1DFitPenalizedW: Y contains infinite or NAN values!", _state); ae_assert(isfinitevector(w, n, _state), "Spline1DFitPenalizedW: Y contains infinite or NAN values!", _state); ae_assert(ae_isfinite(rho, _state), "Spline1DFitPenalizedW: Rho is infinite!", _state); /* * Prepare LambdaV */ v = -ae_log(ae_machineepsilon, _state)/ae_log(10, _state); if( ae_fp_less(rho,-v) ) { rho = -v; } if( ae_fp_greater(rho,v) ) { rho = v; } lambdav = ae_pow(10, rho, _state); /* * Sort X, Y, W */ heapsortdpoints(x, y, w, n, _state); /* * Scale X, Y, XC, YC */ lsfitscalexy(x, y, w, n, &xc, &yc, &dc, 0, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); /* * Allocate space */ ae_matrix_set_length(&fmatrix, n, m, _state); ae_matrix_set_length(&amatrix, m, m, _state); ae_matrix_set_length(&d2matrix, m, m, _state); ae_vector_set_length(&bx, m, _state); ae_vector_set_length(&by, m, _state); ae_vector_set_length(&fcolumn, n, _state); ae_matrix_set_length(&nmatrix, m, m, _state); ae_vector_set_length(&rightpart, m, _state); ae_vector_set_length(&tmp0, ae_maxint(m, n, _state), _state); ae_vector_set_length(&c, m, _state); /* * Fill: * * FMatrix by values of basis functions * * TmpAMatrix by second derivatives of I-th function at J-th point * * CMatrix by constraints */ fdmax = 0; for (b=0; b<=m-1; b++) { /* * Prepare I-th basis function */ for(j=0; j<=m-1; j++) { bx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-1; by.ptr.p_double[j] = 0; } by.ptr.p_double[b] = 1; //spline1dgriddiff2cubic(&bx, &by, m, 2, 0.0, 2, 0.0, &bd1, &bd2, _state); test_gridDiff2Cubic(&bx, &by, m, &bd1, &bd2, _state); // spline1dbuildcubic(&bx, &by, m, 2, 0.0, 2, 0.0, &bs, _state); test_buildCubic(&bx, &by, m, &bs, _state); /* * Calculate B-th column of FMatrix * Update FDMax (maximum column norm) */ spline1dconvcubic(&bx, &by, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state); ae_v_move(&fmatrix.ptr.pp_double[0][b], fmatrix.stride, &fcolumn.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = 0; for(i=0; i<=n-1; i++) { //fprintf(stderr, "fcoll %d %f\n", i, fcolumn.ptr.p_double[i]); v = v+ae_sqr(w->ptr.p_double[i]*fcolumn.ptr.p_double[i], _state); } fdmax = ae_maxreal(fdmax, v, _state); /* * Fill temporary with second derivatives of basis function */ ae_v_move(&d2matrix.ptr.pp_double[b][0], 1, &bd2.ptr.p_double[0], 1, ae_v_len(0,m-1)); } /* * * calculate penalty matrix A * * calculate max of diagonal elements of A * * calculate PDecay - coefficient before penalty matrix */ for(i=0; i<=m-1; i++) { for(j=i; j<=m-1; j++) { /* * calculate integral(B_i''*B_j'') where B_i and B_j are * i-th and j-th basis splines. * B_i and B_j are piecewise linear functions. */ v = 0; for(b=0; b<=m-2; b++) { fa = d2matrix.ptr.pp_double[i][b]; fb = d2matrix.ptr.pp_double[i][b+1]; ga = d2matrix.ptr.pp_double[j][b]; gb = d2matrix.ptr.pp_double[j][b+1]; v = v+(bx.ptr.p_double[b+1]-bx.ptr.p_double[b])*(fa*ga+(fa*(gb-ga)+ga*(fb-fa))/2+(fb-fa)*(gb-ga)/3); } amatrix.ptr.pp_double[i][j] = v; amatrix.ptr.pp_double[j][i] = v; } } admax = 0; for(i=0; i<=m-1; i++) { admax = ae_maxreal(admax, ae_fabs(amatrix.ptr.pp_double[i][i], _state), _state); } pdecay = lambdav*fdmax/admax; /* * Calculate TDecay for Tikhonov regularization */ tdecay = fdmax*(1+pdecay)*10*ae_machineepsilon; /* * Prepare system * * NOTE: FMatrix is spoiled during this process */ for(i=0; i<=n-1; i++) { v = w->ptr.p_double[i]; ae_v_muld(&fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } rmatrixgemm(m, m, n, 1.0, &fmatrix, 0, 0, 1, &fmatrix, 0, 0, 0, 0.0, &nmatrix, 0, 0, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { nmatrix.ptr.pp_double[i][j] = nmatrix.ptr.pp_double[i][j]+pdecay*amatrix.ptr.pp_double[i][j]; } } for(i=0; i<=m-1; i++) { nmatrix.ptr.pp_double[i][i] = nmatrix.ptr.pp_double[i][i]+tdecay; } for(i=0; i<=m-1; i++) { rightpart.ptr.p_double[i] = 0; } for(i=0; i<=n-1; i++) { v = y->ptr.p_double[i]*w->ptr.p_double[i]; ae_v_addd(&rightpart.ptr.p_double[0], 1, &fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } /* * Solve system */ if( !spdmatrixcholesky(&nmatrix, m, ae_true, _state) ) { *info = -4; ae_frame_leave(_state); return; } fblscholeskysolve(&nmatrix, 1.0, m, ae_true, &rightpart, &tmp0, _state); ae_v_move(&c.ptr.p_double[0], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(0,m-1)); /* * add nodes to force linearity outside of the fitting interval */ spline1dgriddiffcubic(&bx, &c, m, 2, 0.0, 2, 0.0, &bd1, _state); ae_vector_set_length(&tx, m+2, _state); ae_vector_set_length(&ty, m+2, _state); ae_vector_set_length(&td, m+2, _state); ae_v_move(&tx.ptr.p_double[1], 1, &bx.ptr.p_double[0], 1, ae_v_len(1,m)); ae_v_move(&ty.ptr.p_double[1], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(1,m)); ae_v_move(&td.ptr.p_double[1], 1, &bd1.ptr.p_double[0], 1, ae_v_len(1,m)); tx.ptr.p_double[0] = tx.ptr.p_double[1]-(tx.ptr.p_double[2]-tx.ptr.p_double[1]); ty.ptr.p_double[0] = ty.ptr.p_double[1]-td.ptr.p_double[1]*(tx.ptr.p_double[2]-tx.ptr.p_double[1]); td.ptr.p_double[0] = td.ptr.p_double[1]; tx.ptr.p_double[m+1] = tx.ptr.p_double[m]+(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]); ty.ptr.p_double[m+1] = ty.ptr.p_double[m]+td.ptr.p_double[m]*(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]); td.ptr.p_double[m+1] = td.ptr.p_double[m]; spline1dbuildhermite(&tx, &ty, &td, m+2, s, _state); spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); spline1dlintransy(s, sb-sa, sa, _state); *info = 1; /* * Fill report */ rep->rmserror = 0; rep->avgerror = 0; rep->avgrelerror = 0; rep->maxerror = 0; relcnt = 0; spline1dconvcubic(&bx, &rightpart, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state); for(i=0; i<=n-1; i++) { v = (sb-sa)*fcolumn.ptr.p_double[i]+sa; rep->rmserror = rep->rmserror+ae_sqr(v-yoriginal.ptr.p_double[i], _state); rep->avgerror = rep->avgerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state); if( ae_fp_neq(yoriginal.ptr.p_double[i],0) ) { rep->avgrelerror = rep->avgrelerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); relcnt = relcnt+1; } rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-yoriginal.ptr.p_double[i], _state), _state); } rep->rmserror = ae_sqrt(rep->rmserror/n, _state); rep->avgerror = rep->avgerror/n; if( ae_fp_neq(relcnt,0) ) { rep->avgrelerror = rep->avgrelerror/relcnt; } ae_frame_leave(_state); }
/************************************************************************* Returns True for successful test, False - for failed test *************************************************************************/ static bool testspdmatrixrcond(int maxn, int passcount) { bool result; ap::real_2d_array a; ap::real_2d_array cha; ap::integer_1d_array p; int n; int i; int j; int pass; bool err50; bool err90; bool errspec; bool errless; bool isupper; double erc1; double ercinf; ap::real_1d_array q50; ap::real_1d_array q90; double v; err50 = false; err90 = false; errless = false; errspec = false; q50.setlength(2); q90.setlength(2); for(n = 1; n <= maxn; n++) { isupper = ap::fp_greater(ap::randomreal(),0.5); // // general test // a.setlength(n, n); for(i = 0; i <= 1; i++) { q50(i) = 0; q90(i) = 0; } for(pass = 1; pass <= passcount; pass++) { spdmatrixrndcond(n, exp(ap::randomreal()*log(double(1000))), a); rmatrixrefrcond(a, n, erc1, ercinf); rmatrixdrophalf(a, n, isupper); rmatrixmakeacopy(a, n, n, cha); spdmatrixcholesky(cha, n, isupper); // // normal // v = 1/spdmatrixrcond(a, n, isupper); if( ap::fp_greater_eq(v,threshold50*erc1) ) { q50(0) = q50(0)+double(1)/double(passcount); } if( ap::fp_greater_eq(v,threshold90*erc1) ) { q90(0) = q90(0)+double(1)/double(passcount); } errless = errless||ap::fp_greater(v,erc1*1.001); // // Cholesky // v = 1/spdmatrixcholeskyrcond(cha, n, isupper); if( ap::fp_greater_eq(v,threshold50*erc1) ) { q50(1) = q50(1)+double(1)/double(passcount); } if( ap::fp_greater_eq(v,threshold90*erc1) ) { q90(1) = q90(1)+double(1)/double(passcount); } errless = errless||ap::fp_greater(v,erc1*1.001); } for(i = 0; i <= 1; i++) { err50 = err50||ap::fp_less(q50(i),0.50); err90 = err90||ap::fp_less(q90(i),0.90); } // // degenerate matrix test // if( n>=3 ) { a.setlength(n, n); for(i = 0; i <= n-1; i++) { for(j = 0; j <= n-1; j++) { a(i,j) = 0.0; } } a(0,0) = 1; a(n-1,n-1) = 1; errspec = errspec||ap::fp_neq(spdmatrixrcond(a, n, isupper),-1); errspec = errspec||ap::fp_neq(spdmatrixcholeskyrcond(a, n, isupper),0); } // // near-degenerate matrix test // if( n>=2 ) { a.setlength(n, n); for(i = 0; i <= n-1; i++) { for(j = 0; j <= n-1; j++) { a(i,j) = 0.0; } } for(i = 0; i <= n-1; i++) { a(i,i) = 1; } i = ap::randominteger(n); a(i,i) = 0.1*ap::maxrealnumber; errspec = errspec||ap::fp_neq(spdmatrixrcond(a, n, isupper),0); errspec = errspec||ap::fp_neq(spdmatrixcholeskyrcond(a, n, isupper),0); } } // // report // result = !(err50||err90||errless||errspec); return result; }