Exemplo n.º 1
0
        /*************************************************************************
        This   function prepares equality-constrained Newton step using previously
        calculated constrained Cholesky matrix of the problem

            f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b)
            
        where A can be dense or sparse.

        As  input,  this  function  accepts  gradient  at the current location. As
        output, it returns step vector (replaces gradient).

        This function works as black box. It uses fields of SState which are marked
        as "Variables for constrained Newton phase", and only  this  function  and
        its friends know about these variables. Everyone else should use:
        * CNewtonBuild() to prepare initial Cholesky decomposition for step
        * CNewtonStep() to perform constrained Newton step
        * CNewtonUpdate() to update Cholesky matrix  after  point  was  moved  and
          constraints were updated. In some cases it  is  possible to  efficiently
          re-calculate Cholesky decomposition if you know which  constraints  were
          activated. If efficient  re-calculation  is  impossible,  this  function
          returns False.

        INPUT PARAMETERS:
            SState  -   structure which stores model and temporaries for CN phase;
                        in particular, SAS.XC stores current point.
            Settings -  QQPSettings object which was  initialized  by  appropriate
                        construction function.
            GC       -  array[NMain+NSlack], gradient of the target function
            
        OUTPUT PARAMETERS:
            GC       -  array[NMain+NSlack], step vector (on success)
            
        RESULT:
            True, if step was successfully calculated.
            False, if step calculation failed:
            a) gradient was exactly zero,
            b) gradient norm was smaller than EpsG (stopping condition)
            c) all variables were equality-constrained
            
        NOTE: this function may routinely return False.
              You should be able to handle such situations.
                    
          -- ALGLIB --
             Copyright 14.05.2014 by Bochkanov Sergey
        *************************************************************************/
        private static bool cnewtonstep(qqpbuffers sstate,
            qqpsettings settings,
            double[] gc)
        {
            bool result = new bool();
            int i = 0;
            int n = 0;
            int nfree = 0;
            double v = 0;
            int i_ = 0;

            result = false;
            n = sstate.n;
            nfree = sstate.nfree;
            for(i=nfree; i<=n-1; i++)
            {
                gc[sstate.yidx[i]] = 0.0;
            }
            v = 0.0;
            for(i_=0; i_<=n-1;i_++)
            {
                v += gc[i_]*gc[i_];
            }
            if( (double)(Math.Sqrt(v))<=(double)(settings.epsg) )
            {
                return result;
            }
            for(i=0; i<=n-1; i++)
            {
                gc[i] = -gc[i];
            }
            if( sstate.akind==0 )
            {
                
                //
                // Dense Newton step.
                // Use straightforward Cholesky solver.
                //
                fbls.fblscholeskysolve(sstate.densez, 1.0, n, true, gc, ref sstate.tmpcn);
                result = true;
                return result;
            }
            if( sstate.akind==1 )
            {
                
                //
                // Sparse Newton step.
                //
                // We have T*T' = L*L' = U'*U (depending on specific triangle stored in SparseCCA).
                //
                if( sstate.sparseupper )
                {
                    sparse.sparsetrsv(sstate.sparsecca, sstate.sparseupper, false, 1, gc);
                    sparse.sparsetrsv(sstate.sparsecca, sstate.sparseupper, false, 0, gc);
                }
                else
                {
                    sparse.sparsetrsv(sstate.sparsecca, sstate.sparseupper, false, 0, gc);
                    sparse.sparsetrsv(sstate.sparsecca, sstate.sparseupper, false, 1, gc);
                }
                result = true;
                return result;
            }
            alglib.ap.assert(false, "CNewtonStep: internal error");
            return result;
        }
Exemplo n.º 2
0
        /*************************************************************************
        This   function  updates  equality-constrained   Cholesky   matrix   after
        activation of the  new  equality  constraints.  Matrix  being  updated  is
        quadratic term of the function below

            f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b)
            
        where A can be dense or sparse.

        This  function  uses  YIdx[]  array  (set by CNewtonBuild()  function)  to
        distinguish between active and inactive constraints.

        This function works as black box. It uses fields of SState which are marked
        as "Variables for constrained Newton phase", and only  this  function  and
        its friends know about these variables. Everyone else should use:
        * CNewtonBuild() to prepare initial Cholesky decomposition for step
        * CNewtonStep() to perform constrained Newton step
        * CNewtonUpdate() to update Cholesky matrix  after  point  was  moved  and
          constraints were updated. In some cases it  is  possible to  efficiently
          re-calculate Cholesky decomposition if you know which  constraints  were
          activated. If efficient  re-calculation  is  impossible,  this  function
          returns False.

        INPUT PARAMETERS:
            SState  -   structure which stores model and temporaries for CN phase;
                        in particular, SAS.XC stores current point.
            Settings -  QQPSettings object which was  initialized  by  appropriate
                        construction function.
            NCUpdates-  counter which is incremented after each update (one update
                        means one variable being fixed)
            
        OUTPUT PARAMETERS:
            NCUpdates-  possibly updated counter
            
        RESULT:
            True, if Cholesky decomposition was successfully performed.
            False, if a) model age was too high, or b) particular  combination  of
            matrix type (sparse) and constraints (general linear) is not supported
            
        NOTE: this function may routinely return False.
              You should be able to handle such situations.
                    
          -- ALGLIB --
             Copyright 14.05.2014 by Bochkanov Sergey
        *************************************************************************/
        private static bool cnewtonupdate(qqpbuffers sstate,
            qqpsettings settings,
            ref int ncupdates)
        {
            bool result = new bool();
            int n = 0;
            int nfree = 0;
            int ntofix = 0;
            bool b = new bool();
            int ridx0 = 0;
            int ridx1 = 0;
            int i = 0;
            int k = 0;

            result = false;
            
            //
            // Cholesky updates for sparse problems are not supported
            //
            if( sstate.akind==1 )
            {
                return result;
            }
            
            //
            // Fetch often used fields
            //
            n = sstate.n;
            nfree = sstate.nfree;
            
            //
            // Determine variables to fix and move them to YIdx[NFree-NToFix:NFree-1]
            // Exit if CNModelAge increased too much.
            //
            apserv.ivectorsetlengthatleast(ref sstate.tmpcni, n);
            ridx0 = 0;
            ridx1 = nfree-1;
            for(i=0; i<=nfree-1; i++)
            {
                sstate.tmpcni[i] = -1;
            }
            for(k=0; k<=nfree-1; k++)
            {
                i = sstate.yidx[k];
                alglib.ap.assert(!sstate.havebndl[i] || (double)(sstate.sas.xc[i])>=(double)(sstate.bndl[i]), "CNewtonUpdate: internal error");
                alglib.ap.assert(!sstate.havebndu[i] || (double)(sstate.sas.xc[i])<=(double)(sstate.bndu[i]), "CNewtonUpdate: internal error");
                b = false;
                b = b || (sstate.havebndl[i] && (double)(sstate.sas.xc[i])==(double)(sstate.bndl[i]));
                b = b || (sstate.havebndu[i] && (double)(sstate.sas.xc[i])==(double)(sstate.bndu[i]));
                if( b )
                {
                    sstate.tmpcni[ridx1] = i;
                    ridx1 = ridx1-1;
                }
                else
                {
                    sstate.tmpcni[ridx0] = i;
                    ridx0 = ridx0+1;
                }
            }
            alglib.ap.assert(ridx0==ridx1+1, "CNewtonUpdate: internal error");
            ntofix = nfree-ridx0;
            if( ntofix==0 || ntofix==nfree )
            {
                return result;
            }
            if( sstate.cnmodelage+ntofix>settings.cnmaxupdates )
            {
                return result;
            }
            for(i=0; i<=nfree-1; i++)
            {
                sstate.yidx[i] = sstate.tmpcni[i];
            }
            
            //
            // Constrained Newton matrix: dense version.
            //
            if( sstate.akind==0 )
            {
                
                //
                // Update Cholesky matrix with SPDMatrixCholeskyUpdateFixBuf()
                //
                apserv.bvectorsetlengthatleast(ref sstate.tmpcnb, n);
                for(i=0; i<=n-1; i++)
                {
                    sstate.tmpcnb[i] = false;
                }
                for(i=nfree-ntofix; i<=nfree-1; i++)
                {
                    sstate.tmpcnb[sstate.yidx[i]] = true;
                }
                trfac.spdmatrixcholeskyupdatefixbuf(sstate.densez, n, true, sstate.tmpcnb, ref sstate.tmpcn);
                
                //
                // Update information stored in State and exit
                //
                sstate.nfree = nfree-ntofix;
                sstate.cnmodelage = sstate.cnmodelage+ntofix;
                ncupdates = ncupdates+ntofix;
                result = true;
                return result;
            }
            
            //
            // Unexpected :)
            //
            alglib.ap.assert(false, "CNewtonUpdate: internal error");
            return result;
        }
Exemplo n.º 3
0
        /*************************************************************************
        This function runs QQP solver; it returns after optimization  process  was
        completed. Following QP problem is solved:

            min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin))
            
        subject to boundary constraints.

        IMPORTANT: UNLIKE MANY OTHER SOLVERS, THIS FUNCTION DOES NOT  REQUIRE  YOU
                   TO INITIALIZE STATE OBJECT. IT CAN BE AUTOMATICALLY INITIALIZED
                   DURING SOLUTION PROCESS.

        INPUT PARAMETERS:
            AC          -   for dense problems (AKind=0) A-term of CQM object
                            contains system matrix. Other terms are unspecified
                            and should not be referenced.
            SparseAC    -   for sparse problems (AKind=1
            AKind       -   sparse matrix format:
                            * 0 for dense matrix
                            * 1 for sparse matrix
            SparseUpper -   which triangle of SparseAC stores matrix  -  upper  or
                            lower one (for dense matrices this  parameter  is  not
                            actual).
            BC          -   linear term, array[NC]
            BndLC       -   lower bound, array[NC]
            BndUC       -   upper bound, array[NC]
            SC          -   scale vector, array[NC]:
                            * I-th element contains scale of I-th variable,
                            * SC[I]>0
            XOriginC    -   origin term, array[NC]. Can be zero.
            NC          -   number of variables in the  original  formulation  (no
                            slack variables).
            CLEICC      -   linear equality/inequality constraints. Present version
                            of this function does NOT provide  publicly  available
                            support for linear constraints. This feature  will  be
                            introduced in the future versions of the function.
            NEC, NIC    -   number of equality/inequality constraints.
                            MUST BE ZERO IN THE CURRENT VERSION!!!
            Settings    -   QQPSettings object initialized by one of the initialization
                            functions.
            SState      -   object which stores temporaries:
                            * uninitialized object is automatically initialized
                            * previously allocated memory is reused as much
                              as possible
            XS          -   initial point, array[NC]
            
            
        OUTPUT PARAMETERS:
            XS          -   last point
            TerminationType-termination type:
                            *
                            *
                            *

          -- ALGLIB --
             Copyright 14.05.2011 by Bochkanov Sergey
        *************************************************************************/
        public static void qqpoptimize(cqmodels.convexquadraticmodel ac,
            sparse.sparsematrix sparseac,
            int akind,
            bool sparseupper,
            double[] bc,
            double[] bndlc,
            double[] bnduc,
            double[] sc,
            double[] xoriginc,
            int nc,
            double[,] cleicc,
            int nec,
            int nic,
            qqpsettings settings,
            qqpbuffers sstate,
            double[] xs,
            ref int terminationtype)
        {
            int n = 0;
            int nmain = 0;
            int i = 0;
            int j = 0;
            int k = 0;
            double v = 0;
            double vv = 0;
            double d2 = 0;
            double d1 = 0;
            int d1est = 0;
            int d2est = 0;
            bool needact = new bool();
            double reststp = 0;
            double fullstp = 0;
            double stpmax = 0;
            double stp = 0;
            int stpcnt = 0;
            int cidx = 0;
            double cval = 0;
            int cgcnt = 0;
            int cgmax = 0;
            int newtcnt = 0;
            int sparsesolver = 0;
            double beta = 0;
            bool b = new bool();
            double fprev = 0;
            double fcur = 0;
            int i_ = 0;

            terminationtype = 0;

            
            //
            // Primary checks
            //
            alglib.ap.assert(akind==0 || akind==1, "QQPOptimize: incorrect AKind");
            sstate.nmain = nc;
            sstate.nslack = nic;
            sstate.n = nc+nic;
            sstate.nec = nec;
            sstate.nic = nic;
            sstate.akind = akind;
            n = sstate.n;
            nmain = sstate.nmain;
            terminationtype = 0;
            sstate.repinneriterationscount = 0;
            sstate.repouteriterationscount = 0;
            sstate.repncholesky = 0;
            sstate.repncupdates = 0;
            
            //
            // Several checks
            // * matrix size
            // * scale vector
            // * consistency of bound constraints
            // * consistency of settings
            //
            if( akind==1 )
            {
                alglib.ap.assert(sparse.sparsegetnrows(sparseac)==nmain, "QQPOptimize: rows(SparseAC)<>NMain");
                alglib.ap.assert(sparse.sparsegetncols(sparseac)==nmain, "QQPOptimize: cols(SparseAC)<>NMain");
            }
            for(i=0; i<=nmain-1; i++)
            {
                alglib.ap.assert(math.isfinite(sc[i]) && (double)(sc[i])>(double)(0), "QQPOptimize: incorrect scale");
            }
            for(i=0; i<=nmain-1; i++)
            {
                if( math.isfinite(bndlc[i]) && math.isfinite(bnduc[i]) )
                {
                    if( (double)(bndlc[i])>(double)(bnduc[i]) )
                    {
                        terminationtype = -3;
                        return;
                    }
                }
            }
            alglib.ap.assert(settings.cgphase || settings.cnphase, "QQPOptimize: both phases (CG and Newton) are inactive");
            
            //
            // Allocate data structures
            //
            apserv.rvectorsetlengthatleast(ref sstate.bndl, n);
            apserv.rvectorsetlengthatleast(ref sstate.bndu, n);
            apserv.bvectorsetlengthatleast(ref sstate.havebndl, n);
            apserv.bvectorsetlengthatleast(ref sstate.havebndu, n);
            apserv.rvectorsetlengthatleast(ref sstate.xs, n);
            apserv.rvectorsetlengthatleast(ref sstate.xp, n);
            apserv.rvectorsetlengthatleast(ref sstate.gc, n);
            apserv.rvectorsetlengthatleast(ref sstate.cgc, n);
            apserv.rvectorsetlengthatleast(ref sstate.cgp, n);
            apserv.rvectorsetlengthatleast(ref sstate.dc, n);
            apserv.rvectorsetlengthatleast(ref sstate.dp, n);
            apserv.rvectorsetlengthatleast(ref sstate.tmp0, n);
            apserv.rvectorsetlengthatleast(ref sstate.stpbuf, 15);
            sactivesets.sasinit(n, sstate.sas);
            
            //
            // Scale/shift problem coefficients:
            //
            //     min { 0.5*(x-x0)'*A*(x-x0) + b'*(x-x0) }
            //
            // becomes (after transformation "x = S*y+x0")
            //
            //     min { 0.5*y'*(S*A*S)*y + (S*b)'*y
            //
            // Modified A_mod=S*A*S and b_mod=S*(b+A*x0) are
            // stored into SState.DenseA and SState.B.
            //
            // NOTE: DenseA/DenseB are arrays whose lengths are
            //       NMain, not N=NMain+NSlack! We store reduced 
            //       matrix and vector because extend parts (last
            //       NSlack rows/columns) are exactly zero.
            //       
            //
            apserv.rvectorsetlengthatleast(ref sstate.b, nmain);
            for(i=0; i<=nmain-1; i++)
            {
                sstate.b[i] = sc[i]*bc[i];
            }
            if( akind==0 )
            {
                
                //
                // Dense QP problem - just copy and scale.
                //
                apserv.rmatrixsetlengthatleast(ref sstate.densea, nmain, nmain);
                cqmodels.cqmgeta(ac, ref sstate.densea);
                sstate.absamax = 0;
                sstate.absasum = 0;
                sstate.absasum2 = 0;
                for(i=0; i<=nmain-1; i++)
                {
                    for(j=0; j<=nmain-1; j++)
                    {
                        v = sc[i]*sstate.densea[i,j]*sc[j];
                        sstate.densea[i,j] = v;
                        sstate.absamax = Math.Max(sstate.absamax, v);
                        sstate.absasum = sstate.absasum+v;
                        sstate.absasum2 = sstate.absasum2+v*v;
                    }
                }
            }
            else
            {
                
                //
                // Sparse QP problem - a bit tricky. Depending on format of the
                // input we use different strategies for copying matrix:
                // * SKS matrices are copied to SKS format
                // * anything else is copied to CRS format
                //
                alglib.ap.assert(akind==1, "QQPOptimize: unexpected AKind (internal error)");
                sparse.sparsecopytosksbuf(sparseac, sstate.sparsea);
                if( sparseupper )
                {
                    sparse.sparsetransposesks(sstate.sparsea);
                }
                sstate.sparseupper = false;
                sstate.absamax = 0;
                sstate.absasum = 0;
                sstate.absasum2 = 0;
                for(i=0; i<=n-1; i++)
                {
                    k = sstate.sparsea.ridx[i];
                    for(j=i-sstate.sparsea.didx[i]; j<=i; j++)
                    {
                        v = sc[i]*sstate.sparsea.vals[k]*sc[j];
                        sstate.sparsea.vals[k] = v;
                        if( i==j )
                        {
                            
                            //
                            // Diagonal terms are counted only once
                            //
                            sstate.absamax = Math.Max(sstate.absamax, v);
                            sstate.absasum = sstate.absasum+v;
                            sstate.absasum2 = sstate.absasum2+v*v;
                        }
                        else
                        {
                            
                            //
                            // Offdiagonal terms are counted twice
                            //
                            sstate.absamax = Math.Max(sstate.absamax, v);
                            sstate.absasum = sstate.absasum+2*v;
                            sstate.absasum2 = sstate.absasum2+2*v*v;
                        }
                        k = k+1;
                    }
                }
            }
            
            //
            // Load box constraints into State structure.
            //
            // We apply transformation to variables: y=(x-x_origin)/s,
            // each of the constraints is appropriately shifted/scaled.
            //
            for(i=0; i<=nmain-1; i++)
            {
                sstate.havebndl[i] = math.isfinite(bndlc[i]);
                if( sstate.havebndl[i] )
                {
                    sstate.bndl[i] = (bndlc[i]-xoriginc[i])/sc[i];
                }
                else
                {
                    alglib.ap.assert(Double.IsNegativeInfinity(bndlc[i]), "QQPOptimize: incorrect lower bound");
                    sstate.bndl[i] = Double.NegativeInfinity;
                }
                sstate.havebndu[i] = math.isfinite(bnduc[i]);
                if( sstate.havebndu[i] )
                {
                    sstate.bndu[i] = (bnduc[i]-xoriginc[i])/sc[i];
                }
                else
                {
                    alglib.ap.assert(Double.IsPositiveInfinity(bnduc[i]), "QQPOptimize: incorrect upper bound");
                    sstate.bndu[i] = Double.PositiveInfinity;
                }
            }
            for(i=nmain; i<=n-1; i++)
            {
                sstate.havebndl[i] = true;
                sstate.bndl[i] = 0.0;
                sstate.havebndu[i] = false;
                sstate.bndu[i] = Double.PositiveInfinity;
            }
            
            //
            // Shift/scale linear constraints with transformation y=(x-x_origin)/s:
            // * constraint "c[i]'*x = b[i]" becomes "(s[i]*c[i])'*x = b[i]-c[i]'*x_origin".
            // * after constraint is loaded into SState.CLEIC, it is additionally normalized
            //
            apserv.rmatrixsetlengthatleast(ref sstate.cleic, nec+nic, n+1);
            for(i=0; i<=nec+nic-1; i++)
            {
                v = 0;
                vv = 0;
                for(j=0; j<=nmain-1; j++)
                {
                    sstate.cleic[i,j] = cleicc[i,j]*sc[j];
                    vv = vv+math.sqr(sstate.cleic[i,j]);
                    v = v+cleicc[i,j]*xoriginc[j];
                }
                vv = Math.Sqrt(vv);
                for(j=nmain; j<=n-1; j++)
                {
                    sstate.cleic[i,j] = 0.0;
                }
                sstate.cleic[i,n] = cleicc[i,nmain]-v;
                if( i>=nec )
                {
                    sstate.cleic[i,nmain+i-nec] = 1.0;
                }
                if( (double)(vv)>(double)(0) )
                {
                    for(j=0; j<=n; j++)
                    {
                        sstate.cleic[i,j] = sstate.cleic[i,j]/vv;
                    }
                }
            }
            
            //
            // Process initial point:
            // * first NMain components are equal to XS-XOriginC
            // * last NIC components are deduced from linear constraints
            // * make sure that boundary constraints are preserved by transformation
            //
            for(i=0; i<=nmain-1; i++)
            {
                sstate.xs[i] = (xs[i]-xoriginc[i])/sc[i];
                if( sstate.havebndl[i] && (double)(sstate.xs[i])<(double)(sstate.bndl[i]) )
                {
                    sstate.xs[i] = sstate.bndl[i];
                }
                if( sstate.havebndu[i] && (double)(sstate.xs[i])>(double)(sstate.bndu[i]) )
                {
                    sstate.xs[i] = sstate.bndu[i];
                }
                if( sstate.havebndl[i] && (double)(xs[i])==(double)(bndlc[i]) )
                {
                    sstate.xs[i] = sstate.bndl[i];
                }
                if( sstate.havebndu[i] && (double)(xs[i])==(double)(bnduc[i]) )
                {
                    sstate.xs[i] = sstate.bndu[i];
                }
            }
            for(i=0; i<=nic-1; i++)
            {
                v = 0.0;
                for(i_=0; i_<=nmain-1;i_++)
                {
                    v += sstate.xs[i_]*sstate.cleic[nec+i,i_];
                }
                sstate.xs[nmain+i] = Math.Max(sstate.cleic[nec+i,n]-v, 0.0);
            }
            
            //
            // Prepare "active set" structure
            //
            sactivesets.sassetbc(sstate.sas, sstate.bndl, sstate.bndu);
            sactivesets.sassetlcx(sstate.sas, sstate.cleic, 0, 0);
            if( !sactivesets.sasstartoptimization(sstate.sas, sstate.xs) )
            {
                terminationtype = -3;
                return;
            }
            
            //
            // Select sparse direct solver
            //
            if( akind==1 )
            {
                sparsesolver = settings.sparsesolver;
                if( sparsesolver==0 )
                {
                    sparsesolver = 1;
                }
                if( sparse.sparseissks(sstate.sparsea) )
                {
                    sparsesolver = 2;
                }
                sparsesolver = 2;
                alglib.ap.assert(sparsesolver==1 || sparsesolver==2, "QQPOptimize: incorrect SparseSolver");
            }
            else
            {
                sparsesolver = 0;
            }
            
            //
            // Main loop.
            //
            // Following variables are used:
            // * GC stores current gradient (unconstrained)
            // * CGC stores current gradient (constrained)
            // * DC stores current search direction
            // * CGP stores constrained gradient at previous point
            //   (zero on initial entry)
            // * DP stores previous search direction
            //   (zero on initial entry)
            //
            cgmax = settings.cgminits;
            sstate.repinneriterationscount = 0;
            sstate.repouteriterationscount = 0;
            while( true )
            {
                if( settings.maxouterits>0 && sstate.repouteriterationscount>=settings.maxouterits )
                {
                    terminationtype = 5;
                    break;
                }
                if( sstate.repouteriterationscount>0 )
                {
                    
                    //
                    // Check EpsF- and EpsX-based stopping criteria.
                    // Because problem was already scaled, we do not scale step before checking its length.
                    // NOTE: these checks are performed only after at least one outer iteration was made.
                    //
                    if( (double)(settings.epsf)>(double)(0) )
                    {
                        
                        //
                        // NOTE 1: here we rely on the fact that ProjectedTargetFunction() ignore D when Stp=0
                        // NOTE 2: code below handles situation when update increases function value instead
                        //         of decreasing it.
                        //
                        fprev = projectedtargetfunction(sstate, sstate.xp, sstate.dc, 0.0, ref sstate.tmp0);
                        fcur = projectedtargetfunction(sstate, sstate.sas.xc, sstate.dc, 0.0, ref sstate.tmp0);
                        if( (double)(fprev-fcur)<=(double)(settings.epsf*Math.Max(Math.Abs(fprev), Math.Max(Math.Abs(fcur), 1.0))) )
                        {
                            terminationtype = 1;
                            break;
                        }
                    }
                    if( (double)(settings.epsx)>(double)(0) )
                    {
                        v = 0.0;
                        for(i=0; i<=n-1; i++)
                        {
                            v = v+math.sqr(sstate.xp[i]-sstate.sas.xc[i]);
                        }
                        if( (double)(Math.Sqrt(v))<=(double)(settings.epsx) )
                        {
                            terminationtype = 2;
                            break;
                        }
                    }
                }
                apserv.inc(ref sstate.repouteriterationscount);
                for(i_=0; i_<=n-1;i_++)
                {
                    sstate.xp[i_] = sstate.sas.xc[i_];
                }
                if( !settings.cgphase )
                {
                    cgmax = 0;
                }
                for(i=0; i<=n-1; i++)
                {
                    sstate.cgp[i] = 0.0;
                    sstate.dp[i] = 0.0;
                }
                for(cgcnt=0; cgcnt<=cgmax-1; cgcnt++)
                {
                    
                    //
                    // Calculate unconstrained gradient GC for "extended" QP problem
                    // Determine active set, current constrained gradient CGC.
                    // Check gradient-based stopping condition.
                    //
                    // NOTE: because problem was scaled, we do not have to apply scaling
                    //       to gradient before checking stopping condition.
                    //
                    targetgradient(sstate, sstate.sas.xc, ref sstate.gc);
                    sactivesets.sasreactivateconstraints(sstate.sas, sstate.gc);
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.cgc[i_] = sstate.gc[i_];
                    }
                    sactivesets.sasconstraineddirection(sstate.sas, ref sstate.cgc);
                    v = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v += sstate.cgc[i_]*sstate.cgc[i_];
                    }
                    if( (double)(Math.Sqrt(v))<=(double)(settings.epsg) )
                    {
                        terminationtype = 4;
                        break;
                    }
                    
                    //
                    // Prepare search direction DC and explore it.
                    //
                    // We try to use CGP/DP to prepare conjugate gradient step,
                    // but we resort to steepest descent step (Beta=0) in case
                    // we are at I-th boundary, but DP[I]<>0.
                    //
                    // Such approach allows us to ALWAYS have feasible DC, with
                    // guaranteed compatibility with both feasible area and current
                    // active set.
                    //
                    // Automatic CG reset performed every time DP is incompatible
                    // with current active set and/or feasible area. We also
                    // perform reset every QuickQPRestartCG iterations.
                    //
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.dc[i_] = -sstate.cgc[i_];
                    }
                    v = 0.0;
                    vv = 0.0;
                    b = false;
                    for(i=0; i<=n-1; i++)
                    {
                        v = v+sstate.cgc[i]*sstate.cgc[i];
                        vv = vv+sstate.cgp[i]*sstate.cgp[i];
                        b = b || ((sstate.havebndl[i] && (double)(sstate.sas.xc[i])==(double)(sstate.bndl[i])) && (double)(sstate.dp[i])!=(double)(0));
                        b = b || ((sstate.havebndu[i] && (double)(sstate.sas.xc[i])==(double)(sstate.bndu[i])) && (double)(sstate.dp[i])!=(double)(0));
                    }
                    b = b || (double)(vv)==(double)(0);
                    b = b || cgcnt%quickqprestartcg==0;
                    if( !b )
                    {
                        beta = v/vv;
                    }
                    else
                    {
                        beta = 0.0;
                    }
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.dc[i_] = sstate.dc[i_] + beta*sstate.dp[i_];
                    }
                    sactivesets.sasconstraineddirection(sstate.sas, ref sstate.dc);
                    sactivesets.sasexploredirection(sstate.sas, sstate.dc, ref stpmax, ref cidx, ref cval);
                    
                    //
                    // Build quadratic model of F along descent direction:
                    //
                    //     F(xc+alpha*D) = D2*alpha^2 + D1*alpha
                    //
                    // Terminate algorithm if needed.
                    //
                    // NOTE: we do not maintain constant term D0
                    //
                    quadraticmodel(sstate, sstate.sas.xc, sstate.dc, sstate.gc, ref d1, ref d1est, ref d2, ref d2est);
                    if( (double)(d1)==(double)(0) && (double)(d2)==(double)(0) )
                    {
                        
                        //
                        // D1 and D2 are exactly zero, success.
                        // After this if-then we assume that D is non-zero.
                        //
                        terminationtype = 4;
                        break;
                    }
                    if( d1est>=0 )
                    {
                        
                        //
                        // Numerical noise is too large, it means that we are close
                        // to minimum - and that further improvement is impossible.
                        //
                        // After this if-then we assume that D1 is definitely negative
                        // (even under presence of numerical errors).
                        //
                        terminationtype = 7;
                        break;
                    }
                    if( d2est<=0 && cidx<0 )
                    {
                        
                        //
                        // Function is unbounded from below:
                        // * D1<0 (verified by previous block)
                        // * D2Est<=0, which means that either D2<0 - or it can not
                        //   be reliably distinguished from zero.
                        // * step is unconstrained
                        //
                        // If these conditions are true, we abnormally terminate QP
                        // algorithm with return code -4
                        //
                        terminationtype = -4;
                        break;
                    }
                    
                    //
                    // Perform step along DC.
                    //
                    // In this block of code we maintain two step length:
                    // * RestStp -  restricted step, maximum step length along DC which does
                    //              not violate constraints
                    // * FullStp -  step length along DC which minimizes quadratic function
                    //              without taking constraints into account. If problem is
                    //              unbounded from below without constraints, FullStp is
                    //              forced to be RestStp.
                    //
                    // So, if function is convex (D2>0):
                    // * FullStp = -D1/(2*D2)
                    // * RestStp = restricted FullStp
                    // * 0<=RestStp<=FullStp
                    //
                    // If function is non-convex, but bounded from below under constraints:
                    // * RestStp = step length subject to constraints
                    // * FullStp = RestStp
                    //
                    // After RestStp and FullStp are initialized, we generate several trial
                    // steps which are different multiples of RestStp and FullStp.
                    //
                    if( d2est>0 )
                    {
                        alglib.ap.assert((double)(d1)<(double)(0), "QQPOptimize: internal error");
                        fullstp = -(d1/(2*d2));
                        needact = (double)(fullstp)>=(double)(stpmax);
                        if( needact )
                        {
                            alglib.ap.assert(alglib.ap.len(sstate.stpbuf)>=3, "QQPOptimize: StpBuf overflow");
                            reststp = stpmax;
                            stp = reststp;
                            sstate.stpbuf[0] = reststp*4;
                            sstate.stpbuf[1] = fullstp;
                            sstate.stpbuf[2] = fullstp/4;
                            stpcnt = 3;
                        }
                        else
                        {
                            reststp = fullstp;
                            stp = fullstp;
                            stpcnt = 0;
                        }
                    }
                    else
                    {
                        alglib.ap.assert(cidx>=0, "QQPOptimize: internal error");
                        alglib.ap.assert(alglib.ap.len(sstate.stpbuf)>=2, "QQPOptimize: StpBuf overflow");
                        reststp = stpmax;
                        fullstp = stpmax;
                        stp = reststp;
                        needact = true;
                        sstate.stpbuf[0] = 4*reststp;
                        stpcnt = 1;
                    }
                    findbeststepandmove(sstate, sstate.sas, sstate.dc, stp, needact, cidx, cval, sstate.stpbuf, stpcnt, ref sstate.activated, ref sstate.tmp0);
                    
                    //
                    // Update CG information.
                    //
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.dp[i_] = sstate.dc[i_];
                    }
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.cgp[i_] = sstate.cgc[i_];
                    }
                    
                    //
                    // Update iterations counter
                    //
                    sstate.repinneriterationscount = sstate.repinneriterationscount+1;
                }
                if( terminationtype!=0 )
                {
                    break;
                }
                cgmax = settings.cgmaxits;
                
                //
                // Generate YIdx - reordering of variables for constrained Newton phase.
                // Free variables come first, fixed are last ones.
                //
                newtcnt = 0;
                while( true )
                {
                    
                    //
                    // Skip iteration if constrained Newton is turned off.
                    //
                    if( !settings.cnphase )
                    {
                        break;
                    }
                    
                    //
                    // At the first iteration   - build Cholesky decomposition of Hessian.
                    // At subsequent iterations - refine Hessian by adding new constraints.
                    //
                    // Loop is terminated in following cases:
                    // * Hessian is not positive definite subject to current constraints
                    //   (termination during initial decomposition)
                    // * there were no new constraints being activated
                    //   (termination during update)
                    // * all constraints were activated during last step
                    //   (termination during update)
                    // * CNMaxUpdates were performed on matrix
                    //   (termination during update)
                    //
                    if( newtcnt==0 )
                    {
                        
                        //
                        // Perform initial Newton step. If Cholesky decomposition fails,
                        // increase number of CG iterations to CGMaxIts - it should help
                        // us to find set of constraints which will make matrix positive
                        // definite.
                        //
                        b = cnewtonbuild(sstate, sparsesolver, ref sstate.repncholesky);
                        if( b )
                        {
                            cgmax = settings.cgminits;
                        }
                    }
                    else
                    {
                        b = cnewtonupdate(sstate, settings, ref sstate.repncupdates);
                    }
                    if( !b )
                    {
                        break;
                    }
                    apserv.inc(ref newtcnt);
                    
                    //
                    // Calculate gradient GC.
                    //
                    targetgradient(sstate, sstate.sas.xc, ref sstate.gc);
                    
                    //
                    // Bound-constrained Newton step
                    //
                    for(i=0; i<=n-1; i++)
                    {
                        sstate.dc[i] = sstate.gc[i];
                    }
                    if( !cnewtonstep(sstate, settings, sstate.dc) )
                    {
                        break;
                    }
                    quadraticmodel(sstate, sstate.sas.xc, sstate.dc, sstate.gc, ref d1, ref d1est, ref d2, ref d2est);
                    if( d1est>=0 || d2est<=0 )
                    {
                        break;
                    }
                    alglib.ap.assert((double)(d1)<(double)(0), "QQPOptimize: internal error");
                    fullstp = -(d1/(2*d2));
                    sactivesets.sasexploredirection(sstate.sas, sstate.dc, ref stpmax, ref cidx, ref cval);
                    needact = (double)(fullstp)>=(double)(stpmax);
                    if( needact )
                    {
                        alglib.ap.assert(alglib.ap.len(sstate.stpbuf)>=3, "QQPOptimize: StpBuf overflow");
                        reststp = stpmax;
                        stp = reststp;
                        sstate.stpbuf[0] = reststp*4;
                        sstate.stpbuf[1] = fullstp;
                        sstate.stpbuf[2] = fullstp/4;
                        stpcnt = 3;
                    }
                    else
                    {
                        reststp = fullstp;
                        stp = fullstp;
                        stpcnt = 0;
                    }
                    findbeststepandmove(sstate, sstate.sas, sstate.dc, stp, needact, cidx, cval, sstate.stpbuf, stpcnt, ref sstate.activated, ref sstate.tmp0);
                }
                if( terminationtype!=0 )
                {
                    break;
                }
            }
            
            //
            // Stop optimization and unpack results.
            //
            // Add XOriginC to XS and make sure that boundary constraints are
            // both (a) satisfied, (b) preserved. Former means that "shifted"
            // point is feasible, while latter means that point which was exactly
            // at the boundary before shift will be exactly at the boundary
            // after shift.
            //
            sactivesets.sasstopoptimization(sstate.sas);
            for(i=0; i<=nmain-1; i++)
            {
                xs[i] = sc[i]*sstate.sas.xc[i]+xoriginc[i];
                if( sstate.havebndl[i] && (double)(xs[i])<(double)(bndlc[i]) )
                {
                    xs[i] = bndlc[i];
                }
                if( sstate.havebndu[i] && (double)(xs[i])>(double)(bnduc[i]) )
                {
                    xs[i] = bnduc[i];
                }
                if( sstate.havebndl[i] && (double)(sstate.sas.xc[i])==(double)(sstate.bndl[i]) )
                {
                    xs[i] = bndlc[i];
                }
                if( sstate.havebndu[i] && (double)(sstate.sas.xc[i])==(double)(sstate.bndu[i]) )
                {
                    xs[i] = bnduc[i];
                }
            }
        }
Exemplo n.º 4
0
        /*************************************************************************
        This function initializes QQPSettings  structure  with  copy  of  another,
        already initialized structure.

          -- ALGLIB --
             Copyright 14.05.2011 by Bochkanov Sergey
        *************************************************************************/
        public static void qqpcopysettings(qqpsettings src,
            qqpsettings dst)
        {
            dst.epsg = src.epsg;
            dst.epsf = src.epsf;
            dst.epsx = src.epsx;
            dst.maxouterits = src.maxouterits;
            dst.cgphase = src.cgphase;
            dst.cnphase = src.cnphase;
            dst.cgminits = src.cgminits;
            dst.cgmaxits = src.cgmaxits;
            dst.sparsesolver = src.sparsesolver;
            dst.cnmaxupdates = src.cnmaxupdates;
        }
Exemplo n.º 5
0
        /*************************************************************************
        This function initializes QQPSettings structure with default settings.

        Newly created structure MUST be initialized by default settings  -  or  by
        copy of the already initialized structure.

          -- ALGLIB --
             Copyright 14.05.2011 by Bochkanov Sergey
        *************************************************************************/
        public static void qqploaddefaults(int nmain,
            qqpsettings s)
        {
            s.epsg = 0.0;
            s.epsf = 0.0;
            s.epsx = 1.0E-6;
            s.maxouterits = 0;
            s.cgphase = true;
            s.cnphase = true;
            s.cgminits = 5;
            s.cgmaxits = Math.Max(s.cgminits, (int)Math.Round(1+0.33*nmain));
            s.sparsesolver = 0;
            s.cnmaxupdates = (int)Math.Round(1+0.1*nmain);
        }
Exemplo n.º 6
0
 public override alglib.apobject make_copy()
 {
     qqpsettings _result = new qqpsettings();
     _result.epsg = epsg;
     _result.epsf = epsf;
     _result.epsx = epsx;
     _result.maxouterits = maxouterits;
     _result.cgphase = cgphase;
     _result.cnphase = cnphase;
     _result.cgminits = cgminits;
     _result.cgmaxits = cgmaxits;
     _result.cnmaxupdates = cnmaxupdates;
     _result.sparsesolver = sparsesolver;
     return _result;
 }