Esempio n. 1
0
        /*************************************************************************
        This subroutine is used to solve NNLS problem.

        INPUT PARAMETERS:
            S   -   SNNLS solver, must be initialized with SNNLSInit() call and
                    problem must be set up with SNNLSSetProblem() call.
            X   -   possibly preallocated buffer, automatically resized if needed

        OUTPUT PARAMETERS:
            X   -   array[NS+ND], solution
            
        NOTE:
            1. You can have NS+ND=0, solver will correctly accept such combination
               and return empty array as problem solution.
            
            2. Internal field S.DebugFLOPS contains rough estimate of  FLOPs  used
               to solve problem. It can be used for debugging purposes. This field
               is real-valued.
            
          -- ALGLIB --
             Copyright 10.10.2012 by Bochkanov Sergey
        *************************************************************************/
        public static void snnlssolve(snnlssolver s,
            ref double[] x)
        {
            int i = 0;
            int j = 0;
            int ns = 0;
            int nd = 0;
            int nr = 0;
            int nsc = 0;
            int ndc = 0;
            int newtoncnt = 0;
            bool terminationneeded = new bool();
            double eps = 0;
            double fcur = 0;
            double fprev = 0;
            double fcand = 0;
            double noiselevel = 0;
            double noisetolerance = 0;
            double stplen = 0;
            double d2 = 0;
            double d1 = 0;
            double d0 = 0;
            bool wasactivation = new bool();
            int rfsits = 0;
            double lambdav = 0;
            double v0 = 0;
            double v1 = 0;
            double v = 0;
            int i_ = 0;
            int i1_ = 0;

            
            //
            // Prepare
            //
            ns = s.ns;
            nd = s.nd;
            nr = s.nr;
            s.debugflops = 0.0;
            
            //
            // Handle special cases:
            // * NS+ND=0
            // * ND=0
            //
            if( ns+nd==0 )
            {
                return;
            }
            if( nd==0 )
            {
                apserv.rvectorsetlengthatleast(ref x, ns);
                for(i=0; i<=ns-1; i++)
                {
                    x[i] = s.b[i];
                    if( s.nnc[i] )
                    {
                        x[i] = Math.Max(x[i], 0.0);
                    }
                }
                return;
            }
            
            //
            // Main cycle of BLEIC-SNNLS algorithm.
            // Below we assume that ND>0.
            //
            apserv.rvectorsetlengthatleast(ref x, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.xn, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.g, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.d, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.r, nr);
            apserv.rvectorsetlengthatleast(ref s.diagaa, nd);
            apserv.rvectorsetlengthatleast(ref s.dx, ns+nd);
            for(i=0; i<=ns+nd-1; i++)
            {
                x[i] = 0.0;
            }
            eps = 2*math.machineepsilon;
            noisetolerance = 10.0;
            lambdav = 1.0E6*math.machineepsilon;
            newtoncnt = 0;
            while( true )
            {
                
                //
                // Phase 1: perform steepest descent step.
                //
                // TerminationNeeded control variable is set on exit from this loop:
                // * TerminationNeeded=False in case we have to proceed to Phase 2 (Newton step)
                // * TerminationNeeded=True in case we found solution (step along projected gradient is small enough)
                //
                // Temporaries used:
                // * R      (I|A)*x-b
                //
                // NOTE 1. It is assumed that initial point X is feasible. This feasibility
                //         is retained during all iterations.
                //
                terminationneeded = false;
                while( true )
                {
                    
                    //
                    // Calculate gradient G and constrained descent direction D
                    //
                    for(i=0; i<=nr-1; i++)
                    {
                        i1_ = (ns)-(0);
                        v = 0.0;
                        for(i_=0; i_<=nd-1;i_++)
                        {
                            v += s.densea[i,i_]*x[i_+i1_];
                        }
                        if( i<ns )
                        {
                            v = v+x[i];
                        }
                        s.r[i] = v-s.b[i];
                    }
                    for(i=0; i<=ns-1; i++)
                    {
                        s.g[i] = s.r[i];
                    }
                    for(i=ns; i<=ns+nd-1; i++)
                    {
                        s.g[i] = 0.0;
                    }
                    for(i=0; i<=nr-1; i++)
                    {
                        v = s.r[i];
                        i1_ = (0) - (ns);
                        for(i_=ns; i_<=ns+nd-1;i_++)
                        {
                            s.g[i_] = s.g[i_] + v*s.densea[i,i_+i1_];
                        }
                    }
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        if( (s.nnc[i] && (double)(x[i])<=(double)(0)) && (double)(s.g[i])>(double)(0) )
                        {
                            s.d[i] = 0.0;
                        }
                        else
                        {
                            s.d[i] = -s.g[i];
                        }
                    }
                    s.debugflops = s.debugflops+2*2*nr*nd;
                    
                    //
                    // Build quadratic model of F along descent direction:
                    //     F(x+alpha*d) = D2*alpha^2 + D1*alpha + D0
                    //
                    // Estimate numerical noise in the X (noise level is used
                    // to classify step as singificant or insignificant). Noise
                    // comes from two sources:
                    // * noise when calculating rows of (I|A)*x
                    // * noise when calculating norm of residual
                    //
                    // In case function curvature is negative or product of descent
                    // direction and gradient is non-negative, iterations are terminated.
                    //
                    // NOTE: D0 is not actually used, but we prefer to maintain it.
                    //
                    fprev = 0.0;
                    for(i_=0; i_<=nr-1;i_++)
                    {
                        fprev += s.r[i_]*s.r[i_];
                    }
                    fprev = fprev/2;
                    noiselevel = 0.0;
                    for(i=0; i<=nr-1; i++)
                    {
                        
                        //
                        // Estimate noise introduced by I-th row of (I|A)*x
                        //
                        v = 0.0;
                        if( i<ns )
                        {
                            v = eps*x[i];
                        }
                        for(j=0; j<=nd-1; j++)
                        {
                            v = Math.Max(v, eps*Math.Abs(s.densea[i,j]*x[ns+j]));
                        }
                        v = 2*Math.Abs(s.r[i]*v)+v*v;
                        
                        //
                        // Add to summary noise in the model
                        //
                        noiselevel = noiselevel+v;
                    }
                    noiselevel = Math.Max(noiselevel, eps*fprev);
                    d2 = 0.0;
                    for(i=0; i<=nr-1; i++)
                    {
                        i1_ = (ns)-(0);
                        v = 0.0;
                        for(i_=0; i_<=nd-1;i_++)
                        {
                            v += s.densea[i,i_]*s.d[i_+i1_];
                        }
                        if( i<ns )
                        {
                            v = v+s.d[i];
                        }
                        d2 = d2+0.5*math.sqr(v);
                    }
                    v = 0.0;
                    for(i_=0; i_<=ns+nd-1;i_++)
                    {
                        v += s.d[i_]*s.g[i_];
                    }
                    d1 = v;
                    d0 = fprev;
                    if( (double)(d2)<=(double)(0) || (double)(d1)>=(double)(0) )
                    {
                        terminationneeded = true;
                        break;
                    }
                    s.debugflops = s.debugflops+2*nr*nd;
                    apserv.touchreal(ref d0);
                    
                    //
                    // Perform full (unconstrained) step with length StpLen in direction D.
                    //
                    // We can terminate iterations in case one of two criteria is met:
                    // 1. function change is dominated by noise (or function actually increased
                    //    instead of decreasing)
                    // 2. relative change in X is small enough
                    //
                    // First condition is not enough to guarantee algorithm termination because
                    // sometimes our noise estimate is too optimistic (say, in situations when
                    // function value at solition is zero).
                    //
                    stplen = -(d1/(2*d2));
                    for(i_=0; i_<=ns+nd-1;i_++)
                    {
                        s.xn[i_] = x[i_];
                    }
                    for(i_=0; i_<=ns+nd-1;i_++)
                    {
                        s.xn[i_] = s.xn[i_] + stplen*s.d[i_];
                    }
                    fcand = 0.0;
                    for(i=0; i<=nr-1; i++)
                    {
                        i1_ = (ns)-(0);
                        v = 0.0;
                        for(i_=0; i_<=nd-1;i_++)
                        {
                            v += s.densea[i,i_]*s.xn[i_+i1_];
                        }
                        if( i<ns )
                        {
                            v = v+s.xn[i];
                        }
                        fcand = fcand+0.5*math.sqr(v-s.b[i]);
                    }
                    s.debugflops = s.debugflops+2*nr*nd;
                    if( (double)(fcand)>=(double)(fprev-noiselevel*noisetolerance) )
                    {
                        terminationneeded = true;
                        break;
                    }
                    v = 0;
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        v0 = Math.Abs(x[i]);
                        v1 = Math.Abs(s.xn[i]);
                        if( (double)(v0)!=(double)(0) || (double)(v1)!=(double)(0) )
                        {
                            v = Math.Max(v, Math.Abs(x[i]-s.xn[i])/Math.Max(v0, v1));
                        }
                    }
                    if( (double)(v)<=(double)(eps*noisetolerance) )
                    {
                        terminationneeded = true;
                        break;
                    }
                    
                    //
                    // Perform step one more time, now with non-negativity constraints.
                    //
                    // NOTE: complicated code below which deals with VarIdx temporary makes
                    //       sure that in case unconstrained step leads us outside of feasible
                    //       area, we activate at least one constraint.
                    //
                    wasactivation = boundedstepandactivation(x, s.xn, s.nnc, ns+nd);
                    fcur = 0.0;
                    for(i=0; i<=nr-1; i++)
                    {
                        i1_ = (ns)-(0);
                        v = 0.0;
                        for(i_=0; i_<=nd-1;i_++)
                        {
                            v += s.densea[i,i_]*x[i_+i1_];
                        }
                        if( i<ns )
                        {
                            v = v+x[i];
                        }
                        fcur = fcur+0.5*math.sqr(v-s.b[i]);
                    }
                    s.debugflops = s.debugflops+2*nr*nd;
                    
                    //
                    // Depending on results, decide what to do:
                    // 1. In case step was performed without activation of constraints,
                    //    we proceed to Newton method
                    // 2. In case there was activated at least one constraint, we repeat
                    //    steepest descent step.
                    //
                    if( !wasactivation )
                    {
                        
                        //
                        // Step without activation, proceed to Newton
                        //
                        break;
                    }
                }
                if( terminationneeded )
                {
                    break;
                }
                
                //
                // Phase 2: Newton method.
                //
                apserv.rvectorsetlengthatleast(ref s.cx, ns+nd);
                apserv.ivectorsetlengthatleast(ref s.columnmap, ns+nd);
                apserv.ivectorsetlengthatleast(ref s.rowmap, nr);
                apserv.rmatrixsetlengthatleast(ref s.tmpca, nr, nd);
                apserv.rmatrixsetlengthatleast(ref s.tmpz, nd, nd);
                apserv.rvectorsetlengthatleast(ref s.cborg, nr);
                apserv.rvectorsetlengthatleast(ref s.cb, nr);
                terminationneeded = false;
                while( true )
                {
                    
                    //
                    // Prepare equality constrained subproblem with NSC<=NS "sparse"
                    // variables and NDC<=ND "dense" variables.
                    //
                    // First, we reorder variables (columns) and move all unconstrained
                    // variables "to the left", ColumnMap stores this permutation.
                    //
                    // Then, we reorder first NS rows of A and first NS elements of B in
                    // such way that we still have identity matrix in first NSC columns
                    // of problem. This permutation is stored in RowMap.
                    //
                    nsc = 0;
                    ndc = 0;
                    for(i=0; i<=ns-1; i++)
                    {
                        if( !(s.nnc[i] && (double)(x[i])==(double)(0)) )
                        {
                            s.columnmap[nsc] = i;
                            nsc = nsc+1;
                        }
                    }
                    for(i=ns; i<=ns+nd-1; i++)
                    {
                        if( !(s.nnc[i] && (double)(x[i])==(double)(0)) )
                        {
                            s.columnmap[nsc+ndc] = i;
                            ndc = ndc+1;
                        }
                    }
                    for(i=0; i<=nsc-1; i++)
                    {
                        s.rowmap[i] = s.columnmap[i];
                    }
                    j = nsc;
                    for(i=0; i<=ns-1; i++)
                    {
                        if( s.nnc[i] && (double)(x[i])==(double)(0) )
                        {
                            s.rowmap[j] = i;
                            j = j+1;
                        }
                    }
                    for(i=ns; i<=nr-1; i++)
                    {
                        s.rowmap[i] = i;
                    }
                    
                    //
                    // Now, permutations are ready, and we can copy/reorder
                    // A, B and X to CA, CB and CX.
                    //
                    for(i=0; i<=nsc+ndc-1; i++)
                    {
                        s.cx[i] = x[s.columnmap[i]];
                    }
                    for(i=0; i<=nr-1; i++)
                    {
                        for(j=0; j<=ndc-1; j++)
                        {
                            s.tmpca[i,j] = s.densea[s.rowmap[i],s.columnmap[nsc+j]-ns];
                        }
                        s.cb[i] = s.b[s.rowmap[i]];
                    }
                    
                    //
                    // Solve equality constrained subproblem.
                    //
                    if( ndc>0 )
                    {
                        
                        //
                        // NDC>0.
                        //
                        // Solve subproblem using Newton-type algorithm. We have a
                        // NR*(NSC+NDC) linear least squares subproblem
                        //
                        //         | ( I  AU )   ( XU )   ( BU ) |^2
                        //     min | (       ) * (    ) - (    ) |
                        //         | ( 0  AL )   ( XL )   ( BL ) |
                        //
                        // where:
                        // * I is a NSC*NSC identity matrix
                        // * AU is NSC*NDC dense matrix (first NSC rows of CA)
                        // * AL is (NR-NSC)*NDC dense matrix (next NR-NSC rows of CA)
                        // * BU and BL are correspondingly sized parts of CB
                        //
                        // After conversion to normal equations and small regularization,
                        // we get:
                        //
                        //     ( I   AU ) (  XU )   ( BU            )
                        //     (        )*(     ) = (               )
                        //     ( AU' Y  ) (  XL )   ( AU'*BU+AL'*BL )
                        //
                        // where Y = AU'*AU + AL'*AL + lambda*diag(AU'*AU+AL'*AL).
                        //
                        // With Schur Complement Method this system can be solved in
                        // O(NR*NDC^2+NDC^3) operations. In order to solve it we multiply
                        // first row by AU' and subtract it from the second one. As result,
                        // we get system
                        //
                        //     Z*XL = AL'*BL, where Z=AL'*AL+lambda*diag(AU'*AU+AL'*AL)
                        //
                        // We can easily solve it for XL, and we can get XU as XU = BU-AU*XL.
                        //
                        // We will start solution from calculating Cholesky decomposition of Z.
                        //
                        for(i=0; i<=nr-1; i++)
                        {
                            s.cborg[i] = s.cb[i];
                        }
                        for(i=0; i<=ndc-1; i++)
                        {
                            s.diagaa[i] = 0;
                        }
                        for(i=0; i<=nr-1; i++)
                        {
                            for(j=0; j<=ndc-1; j++)
                            {
                                s.diagaa[j] = s.diagaa[j]+math.sqr(s.tmpca[i,j]);
                            }
                        }
                        for(j=0; j<=ndc-1; j++)
                        {
                            if( (double)(s.diagaa[j])==(double)(0) )
                            {
                                s.diagaa[j] = 1;
                            }
                        }
                        while( true )
                        {
                            
                            //
                            // NOTE: we try to factorize Z. In case of failure we increase
                            //       regularization parameter and try again.
                            //
                            s.debugflops = s.debugflops+2*(nr-nsc)*math.sqr(ndc)+Math.Pow(ndc, 3)/3;
                            for(i=0; i<=ndc-1; i++)
                            {
                                for(j=0; j<=ndc-1; j++)
                                {
                                    s.tmpz[i,j] = 0.0;
                                }
                            }
                            ablas.rmatrixsyrk(ndc, nr-nsc, 1.0, s.tmpca, nsc, 0, 2, 0.0, s.tmpz, 0, 0, true);
                            for(i=0; i<=ndc-1; i++)
                            {
                                s.tmpz[i,i] = s.tmpz[i,i]+lambdav*s.diagaa[i];
                            }
                            if( trfac.spdmatrixcholeskyrec(ref s.tmpz, 0, ndc, true, ref s.tmpcholesky) )
                            {
                                break;
                            }
                            lambdav = lambdav*10;
                        }
                        
                        //
                        // We have Cholesky decomposition of Z, now we can solve system:
                        // * we start from initial point CX
                        // * we perform several iterations of refinement:
                        //   * BU_new := BU_orig - XU_cur - AU*XL_cur
                        //   * BL_new := BL_orig - AL*XL_cur
                        //   * solve for BU_new/BL_new, obtain solution dx
                        //   * XU_cur := XU_cur + dx_u
                        //   * XL_cur := XL_cur + dx_l
                        // * BU_new/BL_new are stored in CB, original right part is
                        //   stored in CBOrg, correction to X is stored in DX, current
                        //   X is stored in CX
                        //
                        for(rfsits=1; rfsits<=s.refinementits; rfsits++)
                        {
                            for(i=0; i<=nr-1; i++)
                            {
                                i1_ = (nsc)-(0);
                                v = 0.0;
                                for(i_=0; i_<=ndc-1;i_++)
                                {
                                    v += s.tmpca[i,i_]*s.cx[i_+i1_];
                                }
                                s.cb[i] = s.cborg[i]-v;
                                if( i<nsc )
                                {
                                    s.cb[i] = s.cb[i]-s.cx[i];
                                }
                            }
                            s.debugflops = s.debugflops+2*nr*ndc;
                            for(i=0; i<=ndc-1; i++)
                            {
                                s.dx[i] = 0.0;
                            }
                            for(i=nsc; i<=nr-1; i++)
                            {
                                v = s.cb[i];
                                for(i_=0; i_<=ndc-1;i_++)
                                {
                                    s.dx[i_] = s.dx[i_] + v*s.tmpca[i,i_];
                                }
                            }
                            fbls.fblscholeskysolve(s.tmpz, 1.0, ndc, true, s.dx, ref s.tmpcholesky);
                            s.debugflops = s.debugflops+2*ndc*ndc;
                            i1_ = (0) - (nsc);
                            for(i_=nsc; i_<=nsc+ndc-1;i_++)
                            {
                                s.cx[i_] = s.cx[i_] + s.dx[i_+i1_];
                            }
                            for(i=0; i<=nsc-1; i++)
                            {
                                v = 0.0;
                                for(i_=0; i_<=ndc-1;i_++)
                                {
                                    v += s.tmpca[i,i_]*s.dx[i_];
                                }
                                s.cx[i] = s.cx[i]+s.cb[i]-v;
                            }
                            s.debugflops = s.debugflops+2*nsc*ndc;
                        }
                    }
                    else
                    {
                        
                        //
                        // NDC=0.
                        //
                        // We have a NR*NSC linear least squares subproblem
                        //
                        //     min |XU-BU|^2
                        //
                        // solution is easy to find - it is XU=BU!
                        //
                        for(i=0; i<=nsc-1; i++)
                        {
                            s.cx[i] = s.cb[i];
                        }
                    }
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        s.xn[i] = x[i];
                    }
                    for(i=0; i<=nsc+ndc-1; i++)
                    {
                        s.xn[s.columnmap[i]] = s.cx[i];
                    }
                    newtoncnt = newtoncnt+1;
                    
                    //
                    // Step to candidate point.
                    // If no constraints was added, accept candidate point XN and move to next phase.
                    // Terminate, if number of Newton iterations exceeded DebugMaxNewton counter.
                    //
                    terminationneeded = s.debugmaxnewton>0 && newtoncnt>=s.debugmaxnewton;
                    if( !boundedstepandactivation(x, s.xn, s.nnc, ns+nd) )
                    {
                        break;
                    }
                    if( terminationneeded )
                    {
                        break;
                    }
                }
                if( terminationneeded )
                {
                    break;
                }
            }
        }
Esempio n. 2
0
        /*************************************************************************
        This subroutine is used to set NNLS problem:

                ( [ 1     |      ]   [   ]   [   ] )^2
                ( [   1   |      ]   [   ]   [   ] )
            min ( [     1 |  Ad  ] * [ x ] - [ b ] )    s.t. x>=0
                ( [       |      ]   [   ]   [   ] )
                ( [       |      ]   [   ]   [   ] )

        where:
        * identity matrix has NS*NS size (NS<=NR, NS can be zero)
        * dense matrix Ad has NR*ND size
        * b is NR*1 vector
        * x is (NS+ND)*1 vector
        * all elements of x are non-negative (this constraint can be removed later
          by calling SNNLSDropNNC() function)

        Previously allocated buffer variables are reused as much as possible.
        After you set problem, you can solve it with SNNLSSolve().

        INPUT PARAMETERS:
            S   -   SNNLS solver, must be initialized with SNNLSInit() call
            A   -   array[NR,ND], dense part of the system
            B   -   array[NR], right part
            NS  -   size of the sparse part of the system, 0<=NS<=NR
            ND  -   size of the dense part of the system, ND>=0
            NR  -   rows count, NR>0

        NOTE:
            1. You can have NS+ND=0, solver will correctly accept such combination
               and return empty array as problem solution.
            
          -- ALGLIB --
             Copyright 10.10.2012 by Bochkanov Sergey
        *************************************************************************/
        public static void snnlssetproblem(snnlssolver s,
            double[,] a,
            double[] b,
            int ns,
            int nd,
            int nr)
        {
            int i = 0;
            int i_ = 0;

            alglib.ap.assert(nd>=0, "SNNLSSetProblem: ND<0");
            alglib.ap.assert(ns>=0, "SNNLSSetProblem: NS<0");
            alglib.ap.assert(nr>0, "SNNLSSetProblem: NR<=0");
            alglib.ap.assert(ns<=nr, "SNNLSSetProblem: NS>NR");
            alglib.ap.assert(alglib.ap.rows(a)>=nr || nd==0, "SNNLSSetProblem: rows(A)<NR");
            alglib.ap.assert(alglib.ap.cols(a)>=nd, "SNNLSSetProblem: cols(A)<ND");
            alglib.ap.assert(alglib.ap.len(b)>=nr, "SNNLSSetProblem: length(B)<NR");
            alglib.ap.assert(apserv.apservisfinitematrix(a, nr, nd), "SNNLSSetProblem: A contains INF/NAN");
            alglib.ap.assert(apserv.isfinitevector(b, nr), "SNNLSSetProblem: B contains INF/NAN");
            
            //
            // Copy problem
            //
            s.ns = ns;
            s.nd = nd;
            s.nr = nr;
            if( nd>0 )
            {
                apserv.rmatrixsetlengthatleast(ref s.densea, nr, nd);
                for(i=0; i<=nr-1; i++)
                {
                    for(i_=0; i_<=nd-1;i_++)
                    {
                        s.densea[i,i_] = a[i,i_];
                    }
                }
            }
            apserv.rvectorsetlengthatleast(ref s.b, nr);
            for(i_=0; i_<=nr-1;i_++)
            {
                s.b[i_] = b[i_];
            }
            apserv.bvectorsetlengthatleast(ref s.nnc, ns+nd);
            for(i=0; i<=ns+nd-1; i++)
            {
                s.nnc[i] = true;
            }
        }
Esempio n. 3
0
        /*************************************************************************
        This subroutine drops non-negativity constraint from the  problem  set  by
        SNNLSSetProblem() call. This function must be called AFTER problem is set,
        because each SetProblem() call resets constraints to their  default  state
        (all constraints are present).

        INPUT PARAMETERS:
            S   -   SNNLS solver, must be initialized with SNNLSInit() call,
                    problem must be set with SNNLSSetProblem() call.
            Idx -   constraint index, 0<=IDX<NS+ND
            
          -- ALGLIB --
             Copyright 10.10.2012 by Bochkanov Sergey
        *************************************************************************/
        public static void snnlsdropnnc(snnlssolver s,
            int idx)
        {
            alglib.ap.assert(idx>=0, "SNNLSDropNNC: Idx<0");
            alglib.ap.assert(idx<s.ns+s.nd, "SNNLSDropNNC: Idx>=NS+ND");
            s.nnc[idx] = false;
        }
Esempio n. 4
0
 public override alglib.apobject make_copy()
 {
     snnlssolver _result = new snnlssolver();
     _result.ns = ns;
     _result.nd = nd;
     _result.nr = nr;
     _result.densea = (double[,])densea.Clone();
     _result.b = (double[])b.Clone();
     _result.nnc = (bool[])nnc.Clone();
     _result.refinementits = refinementits;
     _result.debugflops = debugflops;
     _result.debugmaxnewton = debugmaxnewton;
     _result.xn = (double[])xn.Clone();
     _result.tmpz = (double[,])tmpz.Clone();
     _result.tmpca = (double[,])tmpca.Clone();
     _result.g = (double[])g.Clone();
     _result.d = (double[])d.Clone();
     _result.dx = (double[])dx.Clone();
     _result.diagaa = (double[])diagaa.Clone();
     _result.cb = (double[])cb.Clone();
     _result.cx = (double[])cx.Clone();
     _result.cborg = (double[])cborg.Clone();
     _result.columnmap = (int[])columnmap.Clone();
     _result.rowmap = (int[])rowmap.Clone();
     _result.tmpcholesky = (double[])tmpcholesky.Clone();
     _result.r = (double[])r.Clone();
     return _result;
 }
Esempio n. 5
0
        /*************************************************************************
        This subroutine is used to initialize SNNLS solver.

        By default, empty NNLS problem is produced, but we allocated enough  space
        to store problems with NSMax+NDMax columns and  NRMax  rows.  It  is  good
        place to provide algorithm with initial estimate of the space requirements,
        although you may underestimate problem size or even pass zero estimates  -
        in this case buffer variables will be resized automatically  when  you set
        NNLS problem.

        Previously allocated buffer variables are reused as much as possible. This
        function does not clear structure completely, it tries to preserve as much
        dynamically allocated memory as possible.

          -- ALGLIB --
             Copyright 10.10.2012 by Bochkanov Sergey
        *************************************************************************/
        public static void snnlsinit(int nsmax,
            int ndmax,
            int nrmax,
            snnlssolver s)
        {
            s.ns = 0;
            s.nd = 0;
            s.nr = 0;
            apserv.rmatrixsetlengthatleast(ref s.densea, nrmax, ndmax);
            apserv.rmatrixsetlengthatleast(ref s.tmpca, nrmax, ndmax);
            apserv.rmatrixsetlengthatleast(ref s.tmpz, ndmax, ndmax);
            apserv.rvectorsetlengthatleast(ref s.b, nrmax);
            apserv.bvectorsetlengthatleast(ref s.nnc, nsmax+ndmax);
            s.debugflops = 0.0;
            s.debugmaxnewton = 0;
            s.refinementits = iterativerefinementits;
        }
Esempio n. 6
0
        private static void trdprepare(snnlssolver s,
            double[] x,
            double[] diag,
            double lambdav,
            ref double[] trdd,
            ref double[,] trda,
            ref double[] tmp0,
            ref double[] tmp1,
            ref double[] tmp2,
            ref double[,] tmplq)
        {
            int i = 0;
            int j = 0;
            int ns = 0;
            int nd = 0;
            int nr = 0;
            double v = 0;
            double cs = 0;
            double sn = 0;
            double r = 0;

            
            //
            // Prepare
            //
            ns = s.ns;
            nd = s.nd;
            nr = s.nr;
            
            //
            // Triangular reduction
            //
            apserv.rvectorsetlengthatleast(ref trdd, ns);
            apserv.rmatrixsetlengthatleast(ref trda, ns+nd, nd);
            apserv.rmatrixsetlengthatleast(ref tmplq, nd, nr+nd);
            for(i=0; i<=ns-1; i++)
            {
                
                //
                // Apply rotation to I-th row and corresponding row of
                // regularizer. Here V is diagonal element of I-th row,
                // which is set to 1.0 or 0.0 depending on variable
                // status (constrained or not).
                //
                v = 1.0;
                if( s.nnc[i] && (double)(x[i])==(double)(0.0) )
                {
                    v = 0.0;
                }
                rotations.generaterotation(v, lambdav, ref cs, ref sn, ref r);
                trdd[i] = cs*v+sn*lambdav;
                for(j=0; j<=nd-1; j++)
                {
                    v = s.densea[i,j];
                    trda[i,j] = cs*v;
                    tmplq[j,i] = -(sn*v);
                }
            }
            for(j=0; j<=nd-1; j++)
            {
                for(i=ns; i<=nr-1; i++)
                {
                    tmplq[j,i] = s.densea[i,j];
                }
            }
            for(j=0; j<=nd-1; j++)
            {
                if( s.nnc[ns+j] && (double)(x[ns+j])==(double)(0.0) )
                {
                    
                    //
                    // Variable is constrained, entire row is set to zero.
                    //
                    for(i=0; i<=nr-1; i++)
                    {
                        tmplq[j,i] = 0.0;
                    }
                    for(i=0; i<=ns-1; i++)
                    {
                        trda[i,j] = 0.0;
                    }
                }
            }
            for(i=0; i<=nd-1; i++)
            {
                for(j=0; j<=nd-1; j++)
                {
                    tmplq[j,nr+i] = 0.0;
                }
                tmplq[i,nr+i] = lambdav*diag[i];
            }
            apserv.rvectorsetlengthatleast(ref tmp0, nr+nd+1);
            apserv.rvectorsetlengthatleast(ref tmp1, nr+nd+1);
            apserv.rvectorsetlengthatleast(ref tmp2, nr+nd+1);
            ortfac.rmatrixlqbasecase(ref tmplq, nd, nr+nd, ref tmp0, ref tmp1, ref tmp2);
            for(i=0; i<=nd-1; i++)
            {
                if( (double)(tmplq[i,i])<(double)(0.0) )
                {
                    for(j=i; j<=nd-1; j++)
                    {
                        tmplq[j,i] = -tmplq[j,i];
                    }
                }
            }
            for(i=0; i<=nd-1; i++)
            {
                for(j=0; j<=i; j++)
                {
                    trda[ns+j,i] = tmplq[i,j];
                }
            }
        }
Esempio n. 7
0
        /*************************************************************************
        This function calculates function value F = 0.5*|R|^2 at X.

          -- ALGLIB --
             Copyright 15.07.2015 by Bochkanov Sergey
        *************************************************************************/
        private static void func(snnlssolver s,
            double[] x,
            ref double f)
        {
            int i = 0;
            int nr = 0;
            int nd = 0;
            int ns = 0;
            double v = 0;
            int i_ = 0;
            int i1_ = 0;

            f = 0;

            nr = s.nr;
            nd = s.nd;
            ns = s.ns;
            f = 0.0;
            for(i=0; i<=nr-1; i++)
            {
                i1_ = (ns)-(0);
                v = 0.0;
                for(i_=0; i_<=nd-1;i_++)
                {
                    v += s.densea[i,i_]*x[i_+i1_];
                }
                if( i<ns )
                {
                    v = v+x[i];
                }
                v = v-s.b[i];
                f = f+0.5*v*v;
            }
        }
Esempio n. 8
0
        /*************************************************************************
        This function calculates:
        * residual vector R = A*x-b
        * unconstrained gradient vector G
        * function value F = 0.5*|R|^2

        R and G must have at least N elements.

          -- ALGLIB --
             Copyright 15.07.2015 by Bochkanov Sergey
        *************************************************************************/
        private static void funcgradu(snnlssolver s,
            double[] x,
            double[] r,
            double[] g,
            ref double f)
        {
            int i = 0;
            int nr = 0;
            int nd = 0;
            int ns = 0;
            double v = 0;
            int i_ = 0;
            int i1_ = 0;

            f = 0;

            nr = s.nr;
            nd = s.nd;
            ns = s.ns;
            f = 0.0;
            for(i=0; i<=nr-1; i++)
            {
                i1_ = (ns)-(0);
                v = 0.0;
                for(i_=0; i_<=nd-1;i_++)
                {
                    v += s.densea[i,i_]*x[i_+i1_];
                }
                if( i<ns )
                {
                    v = v+x[i];
                }
                v = v-s.b[i];
                r[i] = v;
                f = f+0.5*v*v;
            }
            for(i=0; i<=ns-1; i++)
            {
                g[i] = r[i];
            }
            for(i=ns; i<=ns+nd-1; i++)
            {
                g[i] = 0.0;
            }
            for(i=0; i<=nr-1; i++)
            {
                v = r[i];
                i1_ = (0) - (ns);
                for(i_=ns; i_<=ns+nd-1;i_++)
                {
                    g[i_] = g[i_] + v*s.densea[i,i_+i1_];
                }
            }
        }
Esempio n. 9
0
        /*************************************************************************
        This subroutine is used to solve NNLS problem.

        INPUT PARAMETERS:
            S   -   SNNLS solver, must be initialized with SNNLSInit() call and
                    problem must be set up with SNNLSSetProblem() call.
            X   -   possibly preallocated buffer, automatically resized if needed

        OUTPUT PARAMETERS:
            X   -   array[NS+ND], solution
            
        NOTE:
            1. You can have NS+ND=0, solver will correctly accept such combination
               and return empty array as problem solution.
            
            2. Internal field S.DebugFLOPS contains rough estimate of  FLOPs  used
               to solve problem. It can be used for debugging purposes. This field
               is real-valued.
            
          -- ALGLIB --
             Copyright 10.10.2012 by Bochkanov Sergey
        *************************************************************************/
        public static void snnlssolve(snnlssolver s,
            ref double[] x)
        {
            int i = 0;
            int ns = 0;
            int nd = 0;
            int nr = 0;
            bool wasactivation = new bool();
            double lambdav = 0;
            double v0 = 0;
            double v1 = 0;
            double v = 0;
            int outerits = 0;
            int innerits = 0;
            int maxouterits = 0;
            double xtol = 0;
            double kicklength = 0;
            bool kickneeded = new bool();
            double f0 = 0;
            double f1 = 0;
            double dnrm = 0;
            int actidx = 0;
            double stp = 0;
            double stpmax = 0;

            
            //
            // Prepare
            //
            ns = s.ns;
            nd = s.nd;
            nr = s.nr;
            s.debugflops = 0.0;
            
            //
            // Handle special cases:
            // * NS+ND=0
            // * ND=0
            //
            if( ns+nd==0 )
            {
                return;
            }
            if( nd==0 )
            {
                apserv.rvectorsetlengthatleast(ref x, ns);
                for(i=0; i<=ns-1; i++)
                {
                    x[i] = s.b[i];
                    if( s.nnc[i] )
                    {
                        x[i] = Math.Max(x[i], 0.0);
                    }
                }
                return;
            }
            
            //
            // Main cycle of BLEIC-SNNLS algorithm.
            // Below we assume that ND>0.
            //
            apserv.rvectorsetlengthatleast(ref x, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.xn, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.xp, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.g, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.d, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.r, nr);
            apserv.rvectorsetlengthatleast(ref s.diagaa, nd);
            apserv.rvectorsetlengthatleast(ref s.regdiag, ns+nd);
            apserv.rvectorsetlengthatleast(ref s.dx, ns+nd);
            for(i=0; i<=ns+nd-1; i++)
            {
                x[i] = 0.0;
                s.regdiag[i] = 1.0;
            }
            lambdav = 1.0E6*math.machineepsilon;
            maxouterits = 10;
            outerits = 0;
            innerits = 0;
            xtol = 1.0E3*math.machineepsilon;
            kicklength = Math.Sqrt(math.minrealnumber);
            while( true )
            {
                
                //
                // Initial check for correctness of X
                //
                for(i=0; i<=ns+nd-1; i++)
                {
                    alglib.ap.assert(!s.nnc[i] || (double)(x[i])>=(double)(0), "SNNLS: integrity check failed");
                }
                
                //
                // Calculate gradient G and constrained descent direction D
                //
                funcgradu(s, x, s.r, s.g, ref f0);
                for(i=0; i<=ns+nd-1; i++)
                {
                    if( (s.nnc[i] && (double)(x[i])==(double)(0)) && (double)(s.g[i])>(double)(0) )
                    {
                        s.d[i] = 0.0;
                    }
                    else
                    {
                        s.d[i] = -s.g[i];
                    }
                }
                
                //
                // Decide whether we need "kick" stage: special stage
                // that moves us away from boundary constraints which are
                // not strictly active (i.e. such constraints that x[i]=0.0 and d[i]>0).
                //
                // If we need kick stage, we make a kick - and restart iteration.
                // If not, after this block we can rely on the fact that
                // for all x[i]=0.0 we have d[i]=0.0
                //
                // NOTE: we do not increase outer iterations counter here
                //
                kickneeded = false;
                for(i=0; i<=ns+nd-1; i++)
                {
                    if( (s.nnc[i] && (double)(x[i])==(double)(0.0)) && (double)(s.d[i])>(double)(0.0) )
                    {
                        kickneeded = true;
                    }
                }
                if( kickneeded )
                {
                    
                    //
                    // Perform kick.
                    // Restart.
                    // Do not increase iterations counter.
                    //
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        if( (double)(x[i])==(double)(0.0) && (double)(s.d[i])>(double)(0.0) )
                        {
                            x[i] = x[i]+kicklength;
                        }
                    }
                    continue;
                }
                
                //
                // Newton phase
                // Reduce problem to constrained triangular form and perform Newton
                // steps with quick activation of constrants  (triangular  form  is
                // updated in order to handle changed constraints).
                //
                for(i=0; i<=ns+nd-1; i++)
                {
                    s.xp[i] = x[i];
                }
                trdprepare(s, x, s.regdiag, lambdav, ref s.trdd, ref s.trda, ref s.tmp0, ref s.tmp1, ref s.tmp2, ref s.tmplq);
                while( true )
                {
                    
                    //
                    // Skip if debug limit on inner iterations count is turned on.
                    //
                    if( s.debugmaxinnerits>0 && innerits>=s.debugmaxinnerits )
                    {
                        break;
                    }
                    
                    //
                    // Prepare step vector.
                    //
                    funcgradu(s, x, s.r, s.g, ref f0);
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        s.d[i] = -s.g[i];
                        if( s.nnc[i] && (double)(x[i])==(double)(0.0) )
                        {
                            s.d[i] = 0.0;
                        }
                    }
                    trdsolve(s.trdd, s.trda, ns, nd, s.d);
                    
                    //
                    // Perform unconstrained trial step and compare function values.
                    //
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        s.xn[i] = x[i]+s.d[i];
                    }
                    func(s, s.xn, ref f1);
                    if( (double)(f1)>=(double)(f0) )
                    {
                        break;
                    }
                    
                    //
                    // Calculate length of D, maximum step and component which is
                    // activated by this step. Break if D is exactly zero.
                    //
                    dnrm = 0.0;
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        dnrm = dnrm+math.sqr(s.d[i]);
                    }
                    dnrm = Math.Sqrt(dnrm);
                    actidx = -1;
                    stpmax = 1.0E50;
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        if( s.nnc[i] && (double)(s.d[i])<(double)(0.0) )
                        {
                            v = stpmax;
                            stpmax = apserv.safeminposrv(x[i], -s.d[i], stpmax);
                            if( (double)(stpmax)<(double)(v) )
                            {
                                actidx = i;
                            }
                        }
                    }
                    if( (double)(dnrm)==(double)(0.0) )
                    {
                        break;
                    }
                    
                    //
                    // Perform constrained step and update X
                    // and triangular model.
                    //
                    stp = Math.Min(1.0, stpmax);
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        v = x[i]+stp*s.d[i];
                        if( s.nnc[i] )
                        {
                            v = Math.Max(v, 0.0);
                        }
                        s.xn[i] = v;
                    }
                    if( (double)(stp)==(double)(stpmax) && actidx>=0 )
                    {
                        s.xn[actidx] = 0.0;
                    }
                    wasactivation = false;
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        if( (double)(s.xn[i])==(double)(0.0) && (double)(x[i])!=(double)(0.0) )
                        {
                            wasactivation = true;
                            trdfixvariable(s.trdd, s.trda, ns, nd, i, ref s.tmpcholesky);
                        }
                    }
                    for(i=0; i<=ns+nd-1; i++)
                    {
                        x[i] = s.xn[i];
                    }
                    
                    //
                    // Increment iterations counter.
                    // Terminate if no constraint was activated.
                    //
                    apserv.inc(ref innerits);
                    if( !wasactivation )
                    {
                        break;
                    }
                }
                
                //
                // Update outer iterations counter.
                //
                // Break if necessary:
                // * maximum number of outer iterations performed
                // * relative change in X is small enough
                //
                apserv.inc(ref outerits);
                if( outerits>=maxouterits )
                {
                    break;
                }
                v = 0;
                for(i=0; i<=ns+nd-1; i++)
                {
                    v0 = Math.Abs(s.xp[i]);
                    v1 = Math.Abs(x[i]);
                    if( (double)(v0)!=(double)(0) || (double)(v1)!=(double)(0) )
                    {
                        v = Math.Max(v, Math.Abs(x[i]-s.xp[i])/Math.Max(v0, v1));
                    }
                }
                if( (double)(v)<=(double)(xtol) )
                {
                    break;
                }
            }
        }
Esempio n. 10
0
 public override alglib.apobject make_copy()
 {
     snnlssolver _result = new snnlssolver();
     _result.ns = ns;
     _result.nd = nd;
     _result.nr = nr;
     _result.densea = (double[,])densea.Clone();
     _result.b = (double[])b.Clone();
     _result.nnc = (bool[])nnc.Clone();
     _result.debugflops = debugflops;
     _result.debugmaxinnerits = debugmaxinnerits;
     _result.xn = (double[])xn.Clone();
     _result.xp = (double[])xp.Clone();
     _result.tmpz = (double[,])tmpz.Clone();
     _result.tmpca = (double[,])tmpca.Clone();
     _result.tmplq = (double[,])tmplq.Clone();
     _result.trda = (double[,])trda.Clone();
     _result.trdd = (double[])trdd.Clone();
     _result.crb = (double[])crb.Clone();
     _result.g = (double[])g.Clone();
     _result.d = (double[])d.Clone();
     _result.dx = (double[])dx.Clone();
     _result.diagaa = (double[])diagaa.Clone();
     _result.cb = (double[])cb.Clone();
     _result.cx = (double[])cx.Clone();
     _result.cborg = (double[])cborg.Clone();
     _result.tmpcholesky = (double[])tmpcholesky.Clone();
     _result.r = (double[])r.Clone();
     _result.regdiag = (double[])regdiag.Clone();
     _result.tmp0 = (double[])tmp0.Clone();
     _result.tmp1 = (double[])tmp1.Clone();
     _result.tmp2 = (double[])tmp2.Clone();
     _result.rdtmprowmap = (int[])rdtmprowmap.Clone();
     return _result;
 }