示例#1
0
        /*************************************************************************
        Optimum of A subject to:
        a) active boundary constraints (given by ActiveSet[] and corresponding
           elements of XC)
        b) active linear constraints (given by C, R, LagrangeC)

        INPUT PARAMETERS:
            A       -   main quadratic term of the model;
                        although structure may  store  linear  and  rank-K  terms,
                        these terms are ignored and rewritten  by  this  function.
            ANorm   -   estimate of ||A|| (2-norm is used)
            B       -   array[N], linear term of the model
            XN      -   possibly preallocated buffer
            Tmp     -   temporary buffer (automatically resized)
            Tmp1    -   temporary buffer (automatically resized)

        OUTPUT PARAMETERS:
            A       -   modified quadratic model (this function changes rank-K
                        term and linear term of the model)
            LagrangeC-  current estimate of the Lagrange coefficients
            XN      -   solution

        RESULT:
            True on success, False on failure (non-SPD model)

          -- ALGLIB --
             Copyright 20.06.2012 by Bochkanov Sergey
        *************************************************************************/
        private static bool constrainedoptimum(sactivesets.sactiveset sas,
            cqmodels.convexquadraticmodel a,
            double anorm,
            double[] b,
            ref double[] xn,
            int n,
            ref double[] tmp,
            ref bool[] tmpb,
            ref double[] lagrangec)
        {
            bool result = new bool();
            int itidx = 0;
            int i = 0;
            double v = 0;
            double feaserrold = 0;
            double feaserrnew = 0;
            double theta = 0;
            int i_ = 0;

            
            //
            // Rebuild basis accroding to current active set.
            // We call SASRebuildBasis() to make sure that fields of SAS
            // store up to date values.
            //
            sactivesets.sasrebuildbasis(sas);
            
            //
            // Allocate temporaries.
            //
            apserv.rvectorsetlengthatleast(ref tmp, Math.Max(n, sas.basissize));
            apserv.bvectorsetlengthatleast(ref tmpb, n);
            apserv.rvectorsetlengthatleast(ref lagrangec, sas.basissize);
            
            //
            // Prepare model
            //
            for(i=0; i<=sas.basissize-1; i++)
            {
                tmp[i] = sas.pbasis[i,n];
            }
            theta = 100.0*anorm;
            for(i=0; i<=n-1; i++)
            {
                if( sas.activeset[i]>0 )
                {
                    tmpb[i] = true;
                }
                else
                {
                    tmpb[i] = false;
                }
            }
            cqmodels.cqmsetactiveset(a, sas.xc, tmpb);
            cqmodels.cqmsetq(a, sas.pbasis, tmp, sas.basissize, theta);
            
            //
            // Iterate until optimal values of Lagrange multipliers are found
            //
            for(i=0; i<=sas.basissize-1; i++)
            {
                lagrangec[i] = 0;
            }
            feaserrnew = math.maxrealnumber;
            result = true;
            for(itidx=1; itidx<=maxlagrangeits; itidx++)
            {
                
                //
                // Generate right part B using linear term and current
                // estimate of the Lagrange multipliers.
                //
                for(i_=0; i_<=n-1;i_++)
                {
                    tmp[i_] = b[i_];
                }
                for(i=0; i<=sas.basissize-1; i++)
                {
                    v = lagrangec[i];
                    for(i_=0; i_<=n-1;i_++)
                    {
                        tmp[i_] = tmp[i_] - v*sas.pbasis[i,i_];
                    }
                }
                cqmodels.cqmsetb(a, tmp);
                
                //
                // Solve
                //
                result = cqmodels.cqmconstrainedoptimum(a, ref xn);
                if( !result )
                {
                    return result;
                }
                
                //
                // Compare feasibility errors.
                // Terminate if error decreased too slowly.
                //
                feaserrold = feaserrnew;
                feaserrnew = 0;
                for(i=0; i<=sas.basissize-1; i++)
                {
                    v = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v += sas.pbasis[i,i_]*xn[i_];
                    }
                    feaserrnew = feaserrnew+math.sqr(v-sas.pbasis[i,n]);
                }
                feaserrnew = Math.Sqrt(feaserrnew);
                if( (double)(feaserrnew)>=(double)(0.2*feaserrold) )
                {
                    break;
                }
                
                //
                // Update Lagrange multipliers
                //
                for(i=0; i<=sas.basissize-1; i++)
                {
                    v = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v += sas.pbasis[i,i_]*xn[i_];
                    }
                    lagrangec[i] = lagrangec[i]-theta*(v-sas.pbasis[i,n]);
                }
            }
            return result;
        }
示例#2
0
        /*************************************************************************
        Model value: f = 0.5*x'*A*x + b'*x

        INPUT PARAMETERS:
            A       -   convex quadratic model; only main quadratic term is used,
                        other parts of the model (D/Q/linear term) are ignored.
                        This function does not modify model state.
            B       -   right part
            XC      -   evaluation point
            Tmp     -   temporary buffer, automatically resized if needed

          -- ALGLIB --
             Copyright 20.06.2012 by Bochkanov Sergey
        *************************************************************************/
        private static double modelvalue(cqmodels.convexquadraticmodel a,
            double[] b,
            double[] xc,
            int n,
            ref double[] tmp)
        {
            double result = 0;
            double v0 = 0;
            double v1 = 0;
            int i_ = 0;

            apserv.rvectorsetlengthatleast(ref tmp, n);
            cqmodels.cqmadx(a, xc, ref tmp);
            v0 = 0.0;
            for(i_=0; i_<=n-1;i_++)
            {
                v0 += xc[i_]*tmp[i_];
            }
            v1 = 0.0;
            for(i_=0; i_<=n-1;i_++)
            {
                v1 += xc[i_]*b[i_];
            }
            result = 0.5*v0+v1;
            return result;
        }
示例#3
0
        /*************************************************************************
        This function runs QPCholesky 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.

        INPUT PARAMETERS:
            AC          -   for dense problems (AKind=0) contains system matrix in
                            the A-term of CQM object.  OTHER  TERMS  ARE  ACTIVELY
                            USED AND MODIFIED BY THE SOLVER!
            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    -   QPCholeskySettings object initialized by one of the initialization
                            functions.
            SState      -   object which stores temporaries:
                            * if uninitialized object was passed, FirstCall parameter MUST
                              be set to True; object will be automatically initialized by the
                              function, and FirstCall will be set to False.
                            * if FirstCall=False, it is assumed that this parameter was already
                              initialized by previous call to this function with same
                              problem dimensions (variable count N).
            XS          -   initial point, array[NC]
            
            
        OUTPUT PARAMETERS:
            XS          -   last point
            TerminationType-termination type:
                            *
                            *
                            *

          -- ALGLIB --
             Copyright 14.05.2011 by Bochkanov Sergey
        *************************************************************************/
        public static void qpcholeskyoptimize(cqmodels.convexquadraticmodel a,
            double anorm,
            double[] b,
            double[] bndl,
            double[] bndu,
            double[] s,
            double[] xorigin,
            int n,
            double[,] cleic,
            int nec,
            int nic,
            qpcholeskybuffers sstate,
            ref double[] xsc,
            ref int terminationtype)
        {
            int i = 0;
            double noisetolerance = 0;
            bool havebc = new bool();
            double v = 0;
            int badnewtonits = 0;
            double maxscaledgrad = 0;
            double v0 = 0;
            double v1 = 0;
            int nextaction = 0;
            double fprev = 0;
            double fcur = 0;
            double fcand = 0;
            double noiselevel = 0;
            double d0 = 0;
            double d1 = 0;
            double d2 = 0;
            int actstatus = 0;
            int i_ = 0;

            terminationtype = 0;

            
            //
            // Allocate storage and prepare fields
            //
            apserv.rvectorsetlengthatleast(ref sstate.rctmpg, n);
            apserv.rvectorsetlengthatleast(ref sstate.tmp0, n);
            apserv.rvectorsetlengthatleast(ref sstate.tmp1, n);
            apserv.rvectorsetlengthatleast(ref sstate.gc, n);
            apserv.rvectorsetlengthatleast(ref sstate.pg, n);
            apserv.rvectorsetlengthatleast(ref sstate.xs, n);
            apserv.rvectorsetlengthatleast(ref sstate.xn, n);
            apserv.rvectorsetlengthatleast(ref sstate.workbndl, n);
            apserv.rvectorsetlengthatleast(ref sstate.workbndu, n);
            apserv.bvectorsetlengthatleast(ref sstate.havebndl, n);
            apserv.bvectorsetlengthatleast(ref sstate.havebndu, n);
            sstate.repinneriterationscount = 0;
            sstate.repouteriterationscount = 0;
            sstate.repncholesky = 0;
            noisetolerance = 10;
            
            //
            // Our formulation of quadratic problem includes origin point,
            // i.e. we have F(x-x_origin) which is minimized subject to
            // constraints on x, instead of having simply F(x).
            //
            // Here we make transition from non-zero origin to zero one.
            // In order to make such transition we have to:
            // 1. subtract x_origin from x_start
            // 2. modify constraints
            // 3. solve problem
            // 4. add x_origin to solution
            //
            // There is alternate solution - to modify quadratic function
            // by expansion of multipliers containing (x-x_origin), but
            // we prefer to modify constraints, because it is a) more precise
            // and b) easier to to.
            //
            // Parts (1)-(2) are done here. After this block is over,
            // we have:
            // * XS, which stores shifted XStart (if we don't have XStart,
            //   value of XS will be ignored later)
            // * WorkBndL, WorkBndU, which store modified boundary constraints.
            //
            havebc = false;
            for(i=0; i<=n-1; i++)
            {
                sstate.havebndl[i] = math.isfinite(bndl[i]);
                sstate.havebndu[i] = math.isfinite(bndu[i]);
                havebc = (havebc || sstate.havebndl[i]) || sstate.havebndu[i];
                if( sstate.havebndl[i] )
                {
                    sstate.workbndl[i] = bndl[i]-xorigin[i];
                }
                else
                {
                    sstate.workbndl[i] = Double.NegativeInfinity;
                }
                if( sstate.havebndu[i] )
                {
                    sstate.workbndu[i] = bndu[i]-xorigin[i];
                }
                else
                {
                    sstate.workbndu[i] = Double.PositiveInfinity;
                }
            }
            apserv.rmatrixsetlengthatleast(ref sstate.workcleic, nec+nic, n+1);
            for(i=0; i<=nec+nic-1; i++)
            {
                v = 0.0;
                for(i_=0; i_<=n-1;i_++)
                {
                    v += cleic[i,i_]*xorigin[i_];
                }
                for(i_=0; i_<=n-1;i_++)
                {
                    sstate.workcleic[i,i_] = cleic[i,i_];
                }
                sstate.workcleic[i,n] = cleic[i,n]-v;
            }
            
            //
            // We have starting point in StartX, so we just have to shift and bound it
            //
            for(i=0; i<=n-1; i++)
            {
                sstate.xs[i] = xsc[i]-xorigin[i];
                if( sstate.havebndl[i] )
                {
                    if( (double)(sstate.xs[i])<(double)(sstate.workbndl[i]) )
                    {
                        sstate.xs[i] = sstate.workbndl[i];
                    }
                }
                if( sstate.havebndu[i] )
                {
                    if( (double)(sstate.xs[i])>(double)(sstate.workbndu[i]) )
                    {
                        sstate.xs[i] = sstate.workbndu[i];
                    }
                }
            }
            
            //
            // Handle special case - no constraints
            //
            if( !havebc && nec+nic==0 )
            {
                
                //
                // "Simple" unconstrained Cholesky
                //
                apserv.bvectorsetlengthatleast(ref sstate.tmpb, n);
                for(i=0; i<=n-1; i++)
                {
                    sstate.tmpb[i] = false;
                }
                sstate.repncholesky = sstate.repncholesky+1;
                cqmodels.cqmsetb(a, b);
                cqmodels.cqmsetactiveset(a, sstate.xs, sstate.tmpb);
                if( !cqmodels.cqmconstrainedoptimum(a, ref sstate.xn) )
                {
                    terminationtype = -5;
                    return;
                }
                for(i_=0; i_<=n-1;i_++)
                {
                    xsc[i_] = sstate.xn[i_];
                }
                for(i_=0; i_<=n-1;i_++)
                {
                    xsc[i_] = xsc[i_] + xorigin[i_];
                }
                sstate.repinneriterationscount = 1;
                sstate.repouteriterationscount = 1;
                terminationtype = 4;
                return;
            }
            
            //
            // Prepare "active set" structure
            //
            sactivesets.sasinit(n, sstate.sas);
            sactivesets.sassetbc(sstate.sas, sstate.workbndl, sstate.workbndu);
            sactivesets.sassetlcx(sstate.sas, sstate.workcleic, nec, nic);
            sactivesets.sassetscale(sstate.sas, s);
            if( !sactivesets.sasstartoptimization(sstate.sas, sstate.xs) )
            {
                terminationtype = -3;
                return;
            }
            
            //
            // Main cycle of CQP algorithm
            //
            terminationtype = 4;
            badnewtonits = 0;
            maxscaledgrad = 0.0;
            while( true )
            {
                
                //
                // Update iterations count
                //
                apserv.inc(ref sstate.repouteriterationscount);
                apserv.inc(ref sstate.repinneriterationscount);
                
                //
                // Phase 1.
                //
                // Determine active set.
                // Update MaxScaledGrad.
                //
                cqmodels.cqmadx(a, sstate.sas.xc, ref sstate.rctmpg);
                for(i_=0; i_<=n-1;i_++)
                {
                    sstate.rctmpg[i_] = sstate.rctmpg[i_] + b[i_];
                }
                sactivesets.sasreactivateconstraints(sstate.sas, sstate.rctmpg);
                v = 0.0;
                for(i=0; i<=n-1; i++)
                {
                    v = v+math.sqr(sstate.rctmpg[i]*s[i]);
                }
                maxscaledgrad = Math.Max(maxscaledgrad, Math.Sqrt(v));
                
                //
                // Phase 2: perform penalized steepest descent step.
                //
                // NextAction control variable is set on exit from this loop:
                // * NextAction>0 in case we have to proceed to Phase 3 (Newton step)
                // * NextAction<0 in case we have to proceed to Phase 1 (recalculate active set)
                // * NextAction=0 in case we found solution (step along projected gradient is small enough)
                //
                while( true )
                {
                    
                    //
                    // Calculate constrained descent direction, store to PG.
                    // Successful termination if PG is zero.
                    //
                    cqmodels.cqmadx(a, sstate.sas.xc, ref sstate.gc);
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.gc[i_] = sstate.gc[i_] + b[i_];
                    }
                    sactivesets.sasconstraineddescent(sstate.sas, sstate.gc, ref sstate.pg);
                    v0 = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v0 += sstate.pg[i_]*sstate.pg[i_];
                    }
                    if( (double)(v0)==(double)(0) )
                    {
                        
                        //
                        // Constrained derivative is zero.
                        // Solution found.
                        //
                        nextaction = 0;
                        break;
                    }
                    
                    //
                    // Build quadratic model of F along descent direction:
                    //     F(xc+alpha*pg) = D2*alpha^2 + D1*alpha + D0
                    // Store noise level in the XC (noise level is used to classify
                    // step as singificant or insignificant).
                    //
                    // 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 = modelvalue(a, b, sstate.sas.xc, n, ref sstate.tmp0);
                    fprev = fprev+penaltyfactor*maxscaledgrad*sactivesets.sasactivelcpenalty1(sstate.sas, sstate.sas.xc);
                    cqmodels.cqmevalx(a, sstate.sas.xc, ref v, ref noiselevel);
                    v0 = cqmodels.cqmxtadx2(a, sstate.pg);
                    d2 = v0;
                    v1 = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v1 += sstate.pg[i_]*sstate.gc[i_];
                    }
                    d1 = v1;
                    d0 = fprev;
                    if( (double)(d2)<=(double)(0) )
                    {
                        
                        //
                        // Second derivative is non-positive, function is non-convex.
                        //
                        terminationtype = -5;
                        nextaction = 0;
                        break;
                    }
                    if( (double)(d1)>=(double)(0) )
                    {
                        
                        //
                        // Second derivative is positive, first derivative is non-negative.
                        // Solution found.
                        //
                        nextaction = 0;
                        break;
                    }
                    
                    //
                    // Modify quadratic model - add penalty for violation of the active
                    // constraints.
                    //
                    // Boundary constraints are always satisfied exactly, so we do not
                    // add penalty term for them. General equality constraint of the
                    // form a'*(xc+alpha*d)=b adds penalty term:
                    //     P(alpha) = (a'*(xc+alpha*d)-b)^2
                    //              = (alpha*(a'*d) + (a'*xc-b))^2
                    //              = alpha^2*(a'*d)^2 + alpha*2*(a'*d)*(a'*xc-b) + (a'*xc-b)^2
                    // Each penalty term is multiplied by 100*Anorm before adding it to
                    // the 1-dimensional quadratic model.
                    //
                    // Penalization of the quadratic model improves behavior of the
                    // algorithm in the presense of the multiple degenerate constraints.
                    // In particular, it prevents algorithm from making large steps in
                    // directions which violate equality constraints.
                    //
                    for(i=0; i<=nec+nic-1; i++)
                    {
                        if( sstate.sas.activeset[n+i]>0 )
                        {
                            v0 = 0.0;
                            for(i_=0; i_<=n-1;i_++)
                            {
                                v0 += sstate.workcleic[i,i_]*sstate.pg[i_];
                            }
                            v1 = 0.0;
                            for(i_=0; i_<=n-1;i_++)
                            {
                                v1 += sstate.workcleic[i,i_]*sstate.sas.xc[i_];
                            }
                            v1 = v1-sstate.workcleic[i,n];
                            v = 100*anorm;
                            d2 = d2+v*math.sqr(v0);
                            d1 = d1+v*2*v0*v1;
                            d0 = d0+v*math.sqr(v1);
                        }
                    }
                    
                    //
                    // Try unbounded step.
                    // In case function change is dominated by noise or function actually increased
                    // instead of decreasing, we terminate iterations.
                    //
                    v = -(d1/(2*d2));
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.xn[i_] = sstate.sas.xc[i_];
                    }
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.xn[i_] = sstate.xn[i_] + v*sstate.pg[i_];
                    }
                    fcand = modelvalue(a, b, sstate.xn, n, ref sstate.tmp0);
                    fcand = fcand+penaltyfactor*maxscaledgrad*sactivesets.sasactivelcpenalty1(sstate.sas, sstate.xn);
                    if( (double)(fcand)>=(double)(fprev-noiselevel*noisetolerance) )
                    {
                        nextaction = 0;
                        break;
                    }
                    
                    //
                    // Save active set
                    // Perform bounded step with (possible) activation
                    //
                    actstatus = boundedstepandactivation(sstate.sas, sstate.xn, n, ref sstate.tmp0);
                    fcur = modelvalue(a, b, sstate.sas.xc, n, ref sstate.tmp0);
                    
                    //
                    // 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 with ActiveSet[I]<0,
                    //    we proceed to Phase 1 and re-evaluate active set.
                    // 3. Otherwise (activation of the constraints with ActiveSet[I]=0)
                    //    we try Phase 2 one more time.
                    //
                    if( actstatus<0 )
                    {
                        
                        //
                        // Step without activation, proceed to Newton
                        //
                        nextaction = 1;
                        break;
                    }
                    if( actstatus==0 )
                    {
                        
                        //
                        // No new constraints added during last activation - only
                        // ones which were at the boundary (ActiveSet[I]=0), but
                        // inactive due to numerical noise.
                        //
                        // Now, these constraints are added to the active set, and
                        // we try to perform steepest descent (Phase 2) one more time.
                        //
                        continue;
                    }
                    else
                    {
                        
                        //
                        // Last step activated at least one significantly new
                        // constraint (ActiveSet[I]<0), we have to re-evaluate
                        // active set (Phase 1).
                        //
                        nextaction = -1;
                        break;
                    }
                }
                if( nextaction<0 )
                {
                    continue;
                }
                if( nextaction==0 )
                {
                    break;
                }
                
                //
                // Phase 3: fast equality-constrained solver
                //
                // NOTE: this solver uses Augmented Lagrangian algorithm to solve
                //       equality-constrained subproblems. This algorithm may
                //       perform steps which increase function values instead of
                //       decreasing it (in hard cases, like overconstrained problems).
                //
                //       Such non-monononic steps may create a loop, when Augmented
                //       Lagrangian algorithm performs uphill step, and steepest
                //       descent algorithm (Phase 2) performs downhill step in the
                //       opposite direction.
                //
                //       In order to prevent iterations to continue forever we
                //       count iterations when AL algorithm increased function
                //       value instead of decreasing it. When number of such "bad"
                //       iterations will increase beyong MaxBadNewtonIts, we will
                //       terminate algorithm.
                //
                fprev = modelvalue(a, b, sstate.sas.xc, n, ref sstate.tmp0);
                while( true )
                {
                    
                    //
                    // Calculate optimum subject to presently active constraints
                    //
                    sstate.repncholesky = sstate.repncholesky+1;
                    if( !constrainedoptimum(sstate.sas, a, anorm, b, ref sstate.xn, n, ref sstate.tmp0, ref sstate.tmpb, ref sstate.tmp1) )
                    {
                        terminationtype = -5;
                        sactivesets.sasstopoptimization(sstate.sas);
                        return;
                    }
                    
                    //
                    // Add constraints.
                    // If no constraints was added, accept candidate point XN and move to next phase.
                    //
                    if( boundedstepandactivation(sstate.sas, sstate.xn, n, ref sstate.tmp0)<0 )
                    {
                        break;
                    }
                }
                fcur = modelvalue(a, b, sstate.sas.xc, n, ref sstate.tmp0);
                if( (double)(fcur)>=(double)(fprev) )
                {
                    badnewtonits = badnewtonits+1;
                }
                if( badnewtonits>=maxbadnewtonits )
                {
                    
                    //
                    // Algorithm found solution, but keeps iterating because Newton
                    // algorithm performs uphill steps (noise in the Augmented Lagrangian
                    // algorithm). We terminate algorithm; it is considered normal
                    // termination.
                    //
                    break;
                }
            }
            sactivesets.sasstopoptimization(sstate.sas);
            
            //
            // Post-process: add XOrigin to XC
            //
            for(i=0; i<=n-1; i++)
            {
                if( sstate.havebndl[i] && (double)(sstate.sas.xc[i])==(double)(sstate.workbndl[i]) )
                {
                    xsc[i] = bndl[i];
                    continue;
                }
                if( sstate.havebndu[i] && (double)(sstate.sas.xc[i])==(double)(sstate.workbndu[i]) )
                {
                    xsc[i] = bndu[i];
                    continue;
                }
                xsc[i] = apserv.boundval(sstate.sas.xc[i]+xorigin[i], bndl[i], bndu[i]);
            }
        }
示例#4
0
        /*************************************************************************
        This function runs QPBLEIC 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.

        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).
            AbsASum     -   SUM(|A[i,j]|)
            AbsASum2    -   SUM(A[i,j]^2)
            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    -   QPBLEICSettings object initialized by one of the initialization
                            functions.
            SState      -   object which stores temporaries:
                            * if uninitialized object was passed, FirstCall parameter MUST
                              be set to True; object will be automatically initialized by the
                              function, and FirstCall will be set to False.
                            * if FirstCall=False, it is assumed that this parameter was already
                              initialized by previous call to this function with same
                              problem dimensions (variable count N).
            FirstCall   -   whether it is first call of this function for this specific
                            instance of SState, with this number of variables N specified.
            XS          -   initial point, array[NC]
            
            
        OUTPUT PARAMETERS:
            XS          -   last point
            FirstCall   -   uncondtionally set to False
            TerminationType-termination type:
                            *
                            *
                            *

          -- ALGLIB --
             Copyright 14.05.2011 by Bochkanov Sergey
        *************************************************************************/
        public static void qpbleicoptimize(cqmodels.convexquadraticmodel a,
            sparse.sparsematrix sparsea,
            int akind,
            bool sparseaupper,
            double absasum,
            double absasum2,
            double[] b,
            double[] bndl,
            double[] bndu,
            double[] s,
            double[] xorigin,
            int n,
            double[,] cleic,
            int nec,
            int nic,
            qpbleicsettings settings,
            qpbleicbuffers sstate,
            ref bool firstcall,
            ref double[] xs,
            ref int terminationtype)
        {
            int i = 0;
            double d2 = 0;
            double d1 = 0;
            double d0 = 0;
            double v = 0;
            double v0 = 0;
            double v1 = 0;
            double md = 0;
            double mx = 0;
            double mb = 0;
            int d1est = 0;
            int d2est = 0;
            int i_ = 0;

            terminationtype = 0;

            alglib.ap.assert(akind==0 || akind==1, "QPBLEICOptimize: unexpected AKind");
            sstate.repinneriterationscount = 0;
            sstate.repouteriterationscount = 0;
            terminationtype = 0;
            
            //
            // Prepare solver object, if needed
            //
            if( firstcall )
            {
                minbleic.minbleiccreate(n, xs, sstate.solver);
                firstcall = false;
            }
            
            //
            // Prepare max(|B|)
            //
            mb = 0.0;
            for(i=0; i<=n-1; i++)
            {
                mb = Math.Max(mb, Math.Abs(b[i]));
            }
            
            //
            // Temporaries
            //
            apserv.ivectorsetlengthatleast(ref sstate.tmpi, nec+nic);
            apserv.rvectorsetlengthatleast(ref sstate.tmp0, n);
            apserv.rvectorsetlengthatleast(ref sstate.tmp1, n);
            for(i=0; i<=nec-1; i++)
            {
                sstate.tmpi[i] = 0;
            }
            for(i=0; i<=nic-1; i++)
            {
                sstate.tmpi[nec+i] = -1;
            }
            minbleic.minbleicsetlc(sstate.solver, cleic, sstate.tmpi, nec+nic);
            minbleic.minbleicsetbc(sstate.solver, bndl, bndu);
            minbleic.minbleicsetdrep(sstate.solver, true);
            minbleic.minbleicsetcond(sstate.solver, math.minrealnumber, 0.0, 0.0, settings.maxits);
            minbleic.minbleicsetscale(sstate.solver, s);
            minbleic.minbleicsetprecscale(sstate.solver);
            minbleic.minbleicrestartfrom(sstate.solver, xs);
            while( minbleic.minbleiciteration(sstate.solver) )
            {
                
                //
                // Line search started
                //
                if( sstate.solver.lsstart )
                {
                    
                    //
                    // Iteration counters:
                    // * inner iterations count is increased on every line search
                    // * outer iterations count is increased only at steepest descent line search
                    //
                    apserv.inc(ref sstate.repinneriterationscount);
                    if( sstate.solver.steepestdescentstep )
                    {
                        apserv.inc(ref sstate.repouteriterationscount);
                    }
                    
                    //
                    // Build quadratic model of F along descent direction:
                    //
                    //     F(x+alpha*d) = D2*alpha^2 + D1*alpha + D0
                    //
                    // Calculate estimates of linear and quadratic term
                    // (term magnitude is compared with magnitude of numerical errors)
                    //
                    d0 = sstate.solver.f;
                    d1 = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        d1 += sstate.solver.d[i_]*sstate.solver.g[i_];
                    }
                    d2 = 0;
                    if( akind==0 )
                    {
                        d2 = cqmodels.cqmxtadx2(a, sstate.solver.d);
                    }
                    if( akind==1 )
                    {
                        sparse.sparsesmv(sparsea, sparseaupper, sstate.solver.d, ref sstate.tmp0);
                        d2 = 0.0;
                        for(i=0; i<=n-1; i++)
                        {
                            d2 = d2+sstate.solver.d[i]*sstate.tmp0[i];
                        }
                        d2 = 0.5*d2;
                    }
                    mx = 0.0;
                    md = 0.0;
                    for(i=0; i<=n-1; i++)
                    {
                        mx = Math.Max(mx, Math.Abs(sstate.solver.x[i]));
                        md = Math.Max(md, Math.Abs(sstate.solver.d[i]));
                    }
                    optserv.estimateparabolicmodel(absasum, absasum2, mx, mb, md, d1, d2, ref d1est, ref d2est);
                    
                    //
                    // Tests for "normal" convergence.
                    //
                    // This line search may be started from steepest descent
                    // stage (stage 2) or from L-BFGS stage (stage 3) of the
                    // BLEIC algorithm. Depending on stage type, different
                    // checks are performed.
                    //
                    // Say, L-BFGS stage is an equality-constrained refinement
                    // stage of BLEIC. This stage refines current iterate
                    // under "frozen" equality constraints. We can terminate
                    // iterations at this stage only when we encounter
                    // unconstrained direction of negative curvature. In all
                    // other cases (say, when constrained gradient is zero)
                    // we should not terminate algorithm because everything may
                    // change after de-activating presently active constraints.
                    //
                    // Tests for convergence are performed only at "steepest descent" stage
                    // of the BLEIC algorithm, and only when function is non-concave
                    // (D2 is positive or approximately zero) along direction D.
                    //
                    // NOTE: we do not test iteration count (MaxIts) here, because
                    //       this stopping condition is tested by BLEIC itself.
                    //
                    if( sstate.solver.steepestdescentstep && d2est>=0 )
                    {
                        if( d1est>=0 )
                        {
                            
                            //
                            // "Emergency" stopping condition: D is non-descent direction.
                            // Sometimes it is possible because of numerical noise in the
                            // target function.
                            //
                            terminationtype = 4;
                            for(i=0; i<=n-1; i++)
                            {
                                xs[i] = sstate.solver.x[i];
                            }
                            break;
                        }
                        if( d2est>0 )
                        {
                            
                            //
                            // Stopping condition #4 - gradient norm is small:
                            //
                            // 1. rescale State.Solver.D and State.Solver.G according to
                            //    current scaling, store results to Tmp0 and Tmp1.
                            // 2. Normalize Tmp0 (scaled direction vector).
                            // 3. compute directional derivative (in scaled variables),
                            //    which is equal to DOTPRODUCT(Tmp0,Tmp1).
                            //
                            v = 0;
                            for(i=0; i<=n-1; i++)
                            {
                                sstate.tmp0[i] = sstate.solver.d[i]/s[i];
                                sstate.tmp1[i] = sstate.solver.g[i]*s[i];
                                v = v+math.sqr(sstate.tmp0[i]);
                            }
                            alglib.ap.assert((double)(v)>(double)(0), "QPBLEICOptimize: inernal errror (scaled direction is zero)");
                            v = 1/Math.Sqrt(v);
                            for(i_=0; i_<=n-1;i_++)
                            {
                                sstate.tmp0[i_] = v*sstate.tmp0[i_];
                            }
                            v = 0.0;
                            for(i_=0; i_<=n-1;i_++)
                            {
                                v += sstate.tmp0[i_]*sstate.tmp1[i_];
                            }
                            if( (double)(Math.Abs(v))<=(double)(settings.epsg) )
                            {
                                terminationtype = 4;
                                for(i=0; i<=n-1; i++)
                                {
                                    xs[i] = sstate.solver.x[i];
                                }
                                break;
                            }
                            
                            //
                            // Stopping condition #1 - relative function improvement is small:
                            //
                            // 1. calculate steepest descent step:   V = -D1/(2*D2)
                            // 2. calculate function change:         V1= D2*V^2 + D1*V
                            // 3. stop if function change is small enough
                            //
                            v = -(d1/(2*d2));
                            v1 = d2*v*v+d1*v;
                            if( (double)(Math.Abs(v1))<=(double)(settings.epsf*Math.Max(d0, 1.0)) )
                            {
                                terminationtype = 1;
                                for(i=0; i<=n-1; i++)
                                {
                                    xs[i] = sstate.solver.x[i];
                                }
                                break;
                            }
                            
                            //
                            // Stopping condition #2 - scaled step is small:
                            //
                            // 1. calculate step multiplier V0 (step itself is D*V0)
                            // 2. calculate scaled step length V
                            // 3. stop if step is small enough
                            //
                            v0 = -(d1/(2*d2));
                            v = 0;
                            for(i=0; i<=n-1; i++)
                            {
                                v = v+math.sqr(v0*sstate.solver.d[i]/s[i]);
                            }
                            if( (double)(Math.Sqrt(v))<=(double)(settings.epsx) )
                            {
                                terminationtype = 2;
                                for(i=0; i<=n-1; i++)
                                {
                                    xs[i] = sstate.solver.x[i];
                                }
                                break;
                            }
                        }
                    }
                    
                    //
                    // Test for unconstrained direction of negative curvature
                    //
                    if( (d2est<0 || (d2est==0 && d1est<0)) && !sstate.solver.boundedstep )
                    {
                        
                        //
                        // Function is unbounded from below:
                        // * function will decrease along D, i.e. either:
                        //   * D2<0
                        //   * D2=0 and D1<0
                        // * step is unconstrained
                        //
                        // If these conditions are true, we abnormally terminate QP
                        // algorithm with return code -4 (we can do so at any stage
                        // of BLEIC - whether it is L-BFGS or steepest descent one).
                        //
                        terminationtype = -4;
                        for(i=0; i<=n-1; i++)
                        {
                            xs[i] = sstate.solver.x[i];
                        }
                        break;
                    }
                    
                    //
                    // Suggest new step (only if D1 is negative far away from zero,
                    // D2 is positive far away from zero).
                    //
                    if( d1est<0 && d2est>0 )
                    {
                        sstate.solver.stp = apserv.safeminposrv(-d1, 2*d2, sstate.solver.curstpmax);
                    }
                }
                
                //
                // Gradient evaluation
                //
                if( sstate.solver.needfg )
                {
                    for(i=0; i<=n-1; i++)
                    {
                        sstate.tmp0[i] = sstate.solver.x[i]-xorigin[i];
                    }
                    if( akind==0 )
                    {
                        cqmodels.cqmadx(a, sstate.tmp0, ref sstate.tmp1);
                    }
                    if( akind==1 )
                    {
                        sparse.sparsesmv(sparsea, sparseaupper, sstate.tmp0, ref sstate.tmp1);
                    }
                    v0 = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v0 += sstate.tmp0[i_]*sstate.tmp1[i_];
                    }
                    v1 = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v1 += sstate.tmp0[i_]*b[i_];
                    }
                    sstate.solver.f = 0.5*v0+v1;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.solver.g[i_] = sstate.tmp1[i_];
                    }
                    for(i_=0; i_<=n-1;i_++)
                    {
                        sstate.solver.g[i_] = sstate.solver.g[i_] + b[i_];
                    }
                }
            }
            if( terminationtype==0 )
            {
                
                //
                // BLEIC optimizer was terminated by one of its inner stopping
                // conditions. Usually it is iteration counter (if such
                // stopping condition was specified by user).
                //
                minbleic.minbleicresultsbuf(sstate.solver, ref xs, sstate.solverrep);
                terminationtype = sstate.solverrep.terminationtype;
            }
            else
            {
                
                //
                // BLEIC optimizer was terminated in "emergency" mode by QP
                // solver.
                //
                // NOTE: such termination is "emergency" only when viewed from
                //       BLEIC's position. QP solver sees such termination as
                //       routine one, triggered by QP's stopping criteria.
                //
                minbleic.minbleicemergencytermination(sstate.solver);
            }
        }
示例#5
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];
                }
            }
        }
示例#6
0
        /*************************************************************************
        Optimum of A subject to:
        a) active boundary constraints (given by ActiveB[] and corresponding
           elements of XC)
        b) active linear constraints (given by C, R, LagrangeC)

        INPUT PARAMETERS:
            A       -   main quadratic term of the model;
                        although structure may  store  linear  and  rank-K  terms,
                        these terms are ignored and rewritten  by  this  function.
            ANorm   -   estimate of ||A|| (2-norm is used)
            B       -   array[N], linear term of the model
            ActiveB -   array[N], active boundary constraints
            XC      -   array[N], constrained values
            C       -   equality constraints, array[K,N]
            R       -   array[K], right part of the equality constraints
            K       -   number of equality constraints
            XN      -   possibly preallocated buffer
            Tmp     -   temporary buffer (automatically resized)
            Tmp1    -   temporary buffer (automatically resized)

        OUTPUT PARAMETERS:
            A       -   modified quadratic model (this function changes rank-K
                        term and linear term of the model)
            LagrangeC-  current estimate of the Lagrange coefficients
            XN      -   solution

        RESULT:
            True on success, False on failure (non-SPD model)

          -- ALGLIB --
             Copyright 20.06.2012 by Bochkanov Sergey
        *************************************************************************/
        private static bool minqpconstrainedoptimum(cqmodels.convexquadraticmodel a,
            double anorm,
            double[] b,
            bool[] activeb,
            double[] xc,
            int n,
            double[,] c,
            double[] r,
            int k,
            ref double[] xn,
            ref double[] tmp,
            ref double[] lagrangec)
        {
            bool result = new bool();
            int itidx = 0;
            int i = 0;
            double v = 0;
            double feaserrold = 0;
            double feaserrnew = 0;
            double theta = 0;
            int i_ = 0;

            
            //
            // Prepare model
            //
            theta = 100.0*anorm;
            apserv.rvectorsetlengthatleast(ref tmp, n);
            apserv.rvectorsetlengthatleast(ref lagrangec, k);
            cqmodels.cqmsetactiveset(a, xc, activeb);
            cqmodels.cqmsetq(a, c, r, k, theta);
            
            //
            // Iterate until optimal values of Lagrange multipliers are found
            //
            for(i=0; i<=k-1; i++)
            {
                lagrangec[i] = 0;
            }
            feaserrnew = math.maxrealnumber;
            result = true;
            for(itidx=1; itidx<=maxlagrangeits; itidx++)
            {
                
                //
                // Generate right part B using linear term and current
                // estimate of the Lagrange multipliers.
                //
                for(i_=0; i_<=n-1;i_++)
                {
                    tmp[i_] = b[i_];
                }
                for(i=0; i<=k-1; i++)
                {
                    v = lagrangec[i];
                    for(i_=0; i_<=n-1;i_++)
                    {
                        tmp[i_] = tmp[i_] - v*c[i,i_];
                    }
                }
                cqmodels.cqmsetb(a, tmp);
                
                //
                // Solve
                //
                result = cqmodels.cqmconstrainedoptimum(a, ref xn);
                if( !result )
                {
                    return result;
                }
                
                //
                // Compare feasibility errors.
                // Terminate if error decreased too slowly.
                //
                feaserrold = feaserrnew;
                feaserrnew = 0;
                for(i=0; i<=k-1; i++)
                {
                    v = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v += c[i,i_]*xn[i_];
                    }
                    feaserrnew = feaserrnew+math.sqr(v-r[i]);
                }
                feaserrnew = Math.Sqrt(feaserrnew);
                if( (double)(feaserrnew)>=(double)(0.2*feaserrold) )
                {
                    break;
                }
                
                //
                // Update Lagrange multipliers
                //
                for(i=0; i<=k-1; i++)
                {
                    v = 0.0;
                    for(i_=0; i_<=n-1;i_++)
                    {
                        v += c[i,i_]*xn[i_];
                    }
                    lagrangec[i] = lagrangec[i]-theta*(v-r[i]);
                }
            }
            return result;
        }