Пример #1
0
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;
}
Пример #2
0
/**
 * 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;
}
Пример #3
0
/*************************************************************************
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;
    }
}
Пример #4
0
/*************************************************************************
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);
        }
    }
}
Пример #5
0
/*************************************************************************
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;
}
Пример #6
0
/*************************************************************************
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);
    }
}
Пример #7
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;
}