Пример #1
0
        /**
         * Main algorithm.  Descriptions see "Practical Optimization"
         *
         * @param initX initial point of x, assuMing no value's on the bound!
         * @param constraints the bound constraints of each variable
         *                    constraints[0] is the lower bounds and 
         *                    constraints[1] is the upper bounds
         * @return the solution of x, null if number of iterations not enough
         * @throws Exception if an error occurs
         */
        public double[] findArgMin(double[] initX, double[,] constraints)
        {
            int l = initX.Length;

            // Initially all variables are free, all bounds are constraints of
            // non-working-set constraints
            bool[] isFixed = new bool[l];
            double[,] nwsBounds = new double[2, l];
            // Record indice of fixed variables, simply for efficiency
            DynamicIntArray wsBdsIndx = new DynamicIntArray(constraints.Length);
            // Vectors used to record the variable indices to be freed 	
            DynamicIntArray toFree = null, oldToFree = null;

            // Initial value of obj. function, gradient and inverse of the Hessian
            m_f = objectiveFunction(initX);

            double sum = 0;
            double[] grad = evaluateGradient(initX), oldGrad, oldX,
                     deltaGrad = new double[l], deltaX = new double[l],
                     direct = new double[l], x = new double[l];
            Matrix L = new Matrix(l, l);  // Lower triangle of Cholesky factor 
            double[] D = new double[l];   // Diagonal of Cholesky factor
            for (int i = 0; i < l; i++)
            {
                L.setRow(i, new double[l]);
                L.setElement(i, i, 1.0);
                D[i] = 1.0;
                direct[i] = -grad[i];
                sum += grad[i] * grad[i];
                x[i] = initX[i];
                nwsBounds[0, i] = constraints[0, i];
                nwsBounds[1, i] = constraints[1, i];
                isFixed[i] = false;
            }
            double stpMax = m_STPMX * Math.Max(Math.Sqrt(sum), l);

        iterates:
            for (int step = 0; step < m_MaxITS; step++)
            {

                // Try at most one feasible newton step, i.e. 0<lamda<=alpha
                oldX = x;
                oldGrad = grad;

                // Also update grad
                m_IsZeroStep = false;
                x = lnsrch(x, grad, direct, stpMax,
                     isFixed, nwsBounds, wsBdsIndx);


                if (m_IsZeroStep)
                { // Zero step, simply delete rows/cols of D and L
                    for (int f = 0; f < wsBdsIndx.msize(); f++)
                    {
                        int idx = wsBdsIndx.elementAt(f);
                        L.setRow(idx, new double[l]);
                        L.setColumn(idx, new double[l]);
                        D[idx] = 0.0;
                    }
                    grad = evaluateGradient(x);
                    step--;
                }
                else
                {
                    // Check converge on x
                    bool finish = false;
                    double test = 0.0;
                    for (int h = 0; h < l; h++)
                    {
                        deltaX[h] = x[h] - oldX[h];
                        double tmp = Math.Abs(deltaX[h]) /
                        Math.Max(Math.Abs(x[h]), 1.0);
                        if (tmp > test) test = tmp;
                    }
                    if (test < m_Zero)
                    {

                        finish = true;
                    }

                    // Check zero gradient	    
                    grad = evaluateGradient(x);
                    test = 0.0;
                    double denom = 0.0, dxSq = 0.0, dgSq = 0.0, newlyBounded = 0.0;
                    for (int g = 0; g < l; g++)
                    {
                        if (!isFixed[g])
                        {
                            deltaGrad[g] = grad[g] - oldGrad[g];
                            // Calculate the denoMinators			    
                            denom += deltaX[g] * deltaGrad[g];
                            dxSq += deltaX[g] * deltaX[g];
                            dgSq += deltaGrad[g] * deltaGrad[g];
                        }
                        else // Only newly bounded variables will be non-zero
                            newlyBounded += deltaX[g] * (grad[g] - oldGrad[g]);

                        // Note: CANNOT use projected gradient for testing 
                        // convergence because of newly bounded variables
                        double tmp = Math.Abs(grad[g]) *
                        Math.Max(Math.Abs(direct[g]), 1.0) /
                        Math.Max(Math.Abs(m_f), 1.0);
                        if (tmp > test) test = tmp;
                    }

                    if (test < m_Zero)
                    {
                        finish = true;
                    }

                    // dg'*dx could be < 0 using inexact lnsrch
                    // dg'*dx = 0
                    if (Math.Abs(denom + newlyBounded) < m_Zero)
                        finish = true;

                    int size = wsBdsIndx.msize();
                    bool isUpdate = true;  // Whether to update BFGS formula	    
                    // Converge: check whether release any current constraints
                    if (finish)
                    {

                        if (toFree != null)
                            oldToFree = (DynamicIntArray)toFree.copy();
                        toFree = new DynamicIntArray(wsBdsIndx.msize());

                        for (int m = size - 1; m >= 0; m--)
                        {
                            int index = wsBdsIndx.elementAt(m);
                            double[] hessian = evaluateHessian(x, index);
                            double deltaL = 0.0;
                            if (hessian != null)
                            {
                                for (int mm = 0; mm < hessian.Length; mm++)
                                    if (!isFixed[mm]) // Free variable
                                        deltaL += hessian[mm] * direct[mm];
                            }

                            // First and second order Lagrangian multiplier estimate
                            // If user didn't provide Hessian, use first-order only
                            double L1 = 0, L2 = 0;
                            if (x[index] >= constraints[1, index]) // Upper bound
                            {
                                L1 = -grad[index];
                            }
                            else
                            {
                                if (x[index] <= constraints[0, index])// Lower bound
                                {
                                    L1 = grad[index];
                                }
                            }

                            // L2 = L1 + deltaL
                            L2 = L1 + deltaL;

                            //Check validity of Lagrangian multiplier estimate
                            bool isConverge =
                                (2.0 * Math.Abs(deltaL)) < Math.Min(Math.Abs(L1),
                                                  Math.Abs(L2));
                            if ((L1 * L2 > 0.0) && isConverge)
                            { //Same sign and converge: valid
                                if (L2 < 0.0)
                                {// Negative Lagrangian: feasible
                                    toFree.addElement(index);
                                    wsBdsIndx.removeElementAt(m);
                                    finish = false; // Not optimal, cannot finish
                                }
                            }

                            // Although hardly happen, better check it
                            // If the first-order Lagrangian multiplier estimate is wrong,
                            // avoid zigzagging
                            if ((hessian == null) && (toFree != null) && toFree.Equal(oldToFree))
                                finish = true;
                        }

                        if (finish)
                        {// Min. found

                            m_f = objectiveFunction(x);

                            return x;
                        }

                        // Free some variables
                        for (int mmm = 0; mmm < toFree.msize(); mmm++)
                        {
                            int freeIndx = toFree.elementAt(mmm);
                            isFixed[freeIndx] = false; // Free this variable
                            if (x[freeIndx] <= constraints[0, freeIndx])
                            {// Lower bound
                                nwsBounds[0, freeIndx] = constraints[0, freeIndx];

                            }
                            else
                            { // Upper bound
                                nwsBounds[1, freeIndx] = constraints[1, freeIndx];

                            }
                            L.setElement(freeIndx, freeIndx, 1.0);
                            D[freeIndx] = 1.0;
                            isUpdate = false;
                        }
                    }

                    if (denom < Math.Max(m_Zero * Math.Sqrt(dxSq) * Math.Sqrt(dgSq), m_Zero))
                    {

                        isUpdate = false; // Do not update		    
                    }
                    // If Hessian will be positive definite, update it
                    if (isUpdate)
                    {

                        // modify once: dg*dg'/(dg'*dx)	
                        double coeff = 1.0 / denom; // 1/(dg'*dx)	
                        updateCholeskyFactor(L, D, deltaGrad, coeff, isFixed);

                        // modify twice: g*g'/(g'*p)	
                        coeff = 1.0 / m_Slope; // 1/(g'*p)
                        updateCholeskyFactor(L, D, oldGrad, coeff, isFixed);
                    }
                }

                // Find new direction 
                Matrix LD = new Matrix(l, l); // L*D
                double[] b = new double[l];

                for (int k = 0; k < l; k++)
                {
                    if (!isFixed[k]) b[k] = -grad[k];
                    else b[k] = 0.0;

                    for (int j = k; j < l; j++)
                    { // Lower triangle	
                        if (!isFixed[j] && !isFixed[k])
                            LD.setElement(j, k, L.getElement(j, k) * D[k]);
                    }
                }

                // Solve (LD)*y = -g, where y=L'*direct
                double[] LDIR = solveTriangle(LD, b, true, isFixed);
                LD = null;

                // Solve L'*direct = y
                direct = solveTriangle(L, LDIR, false, isFixed);

                //System.gc();
            }

            m_X = x;
            return null;
        }