Ejemplo n.º 1
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);
            }
        }
Ejemplo n.º 2
0
 public override alglib.apobject make_copy()
 {
     qpbleicbuffers _result = new qpbleicbuffers();
     _result.solver = (minbleic.minbleicstate)solver.make_copy();
     _result.solverrep = (minbleic.minbleicreport)solverrep.make_copy();
     _result.tmp0 = (double[])tmp0.Clone();
     _result.tmp1 = (double[])tmp1.Clone();
     _result.tmpi = (int[])tmpi.Clone();
     _result.repinneriterationscount = repinneriterationscount;
     _result.repouteriterationscount = repouteriterationscount;
     return _result;
 }