Пример #1
0
        internal void ReconstructGradient()
        {
            // reconstruct inactive elements of G from G_bar and free variables
            if (activeSize == l)
            {
                return;
            }
            int nrFree = 0;

            for (int j = activeSize; j < l; j++)
            {
                g[j] = gBar[j] + p[j];
            }
            for (int j = 0; j < activeSize; j++)
            {
                if (IsFree(j))
                {
                    nrFree++;
                }
            }
            if (2 * nrFree < activeSize)
            {
                SvmMain.Info("\nWARNING: using -h 0 may be faster\n");
            }
            if (nrFree * l > 2 * activeSize * (l - activeSize))
            {
                for (int i = activeSize; i < l; i++)
                {
                    float[] qI = q.GetQ(i, activeSize);
                    for (int j = 0; j < activeSize; j++)
                    {
                        if (IsFree(j))
                        {
                            g[i] += alpha[j] * qI[j];
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < activeSize; i++)
                {
                    if (IsFree(i))
                    {
                        float[] qI     = q.GetQ(i, l);
                        double  alphaI = alpha[i];
                        for (int j = activeSize; j < l; j++)
                        {
                            g[j] += alphaI * qI[j];
                        }
                    }
                }
            }
        }
Пример #2
0
        internal virtual void Solve(int l1, SvmMatrix q1, double[] p1, short[] y1, double[] alpha1, double cp1, double cn1,
                                    double eps1, SolutionInfo si, bool shrinking)
        {
            l        = l1;
            q        = q1;
            qd       = q1.GetQd();
            p        = (double[])p1.Clone();
            y        = (short[])y1.Clone();
            alpha    = (double[])alpha1.Clone();
            cp       = cp1;
            cn       = cn1;
            eps      = eps1;
            unshrink = false;
            // initialize alpha_status
            {
                alphaStatus = new byte[l1];
                for (int i = 0; i < l1; i++)
                {
                    UpdateAlphaStatus(i);
                }
            }
            // initialize active set (for shrinking)
            {
                activeSet = new int[l1];
                for (int i = 0; i < l1; i++)
                {
                    activeSet[i] = i;
                }
                activeSize = l1;
            }
            // initialize gradient
            {
                g    = new double[l1];
                gBar = new double[l1];
                int i;
                for (i = 0; i < l1; i++)
                {
                    g[i]    = p[i];
                    gBar[i] = 0;
                }
                for (i = 0; i < l1; i++)
                {
                    if (!IsLowerBound(i))
                    {
                        float[] qI     = q1.GetQ(i, l1);
                        double  alphaI = alpha[i];
                        int     j;
                        for (j = 0; j < l1; j++)
                        {
                            g[j] += alphaI * qI[j];
                        }
                        if (IsUpperBound(i))
                        {
                            for (j = 0; j < l1; j++)
                            {
                                gBar[j] += GetC(i) * qI[j];
                            }
                        }
                    }
                }
            }
            // optimization step
            int iter    = 0;
            int maxIter = Math.Max(10000000, l1 > int.MaxValue / 100 ? int.MaxValue : 100 * l1);
            int counter = Math.Min(l1, 1000) + 1;

            int[] workingSet = new int[2];
            while (iter < maxIter)
            {
                // show progress and do shrinking
                if (--counter == 0)
                {
                    counter = Math.Min(l1, 1000);
                    if (shrinking)
                    {
                        DoShrinking();
                    }
                    SvmMain.Info(".");
                }
                if (SelectWorkingSet(workingSet) != 0)
                {
                    // reconstruct the whole gradient
                    ReconstructGradient();
                    // reset active set size and check
                    activeSize = l1;
                    SvmMain.Info("*");
                    if (SelectWorkingSet(workingSet) != 0)
                    {
                        break;
                    }
                    counter = 1;                     // do shrinking next iteration
                }
                int i = workingSet[0];
                int j = workingSet[1];
                ++iter;
                // update alpha[i] and alpha[j], handle bounds carefully
                float[] qI        = q1.GetQ(i, activeSize);
                float[] qJ        = q1.GetQ(j, activeSize);
                double  cI        = GetC(i);
                double  cJ        = GetC(j);
                double  oldAlphaI = alpha[i];
                double  oldAlphaJ = alpha[j];
                if (y[i] != y[j])
                {
                    double quadCoef = qd[i] + qd[j] + 2 * qI[j];
                    if (quadCoef <= 0)
                    {
                        quadCoef = 1e-12;
                    }
                    double delta = (-g[i] - g[j]) / quadCoef;
                    double diff  = alpha[i] - alpha[j];
                    alpha[i] += delta;
                    alpha[j] += delta;
                    if (diff > 0)
                    {
                        if (alpha[j] < 0)
                        {
                            alpha[j] = 0;
                            alpha[i] = diff;
                        }
                    }
                    else
                    {
                        if (alpha[i] < 0)
                        {
                            alpha[i] = 0;
                            alpha[j] = -diff;
                        }
                    }
                    if (diff > cI - cJ)
                    {
                        if (alpha[i] > cI)
                        {
                            alpha[i] = cI;
                            alpha[j] = cI - diff;
                        }
                    }
                    else
                    {
                        if (alpha[j] > cJ)
                        {
                            alpha[j] = cJ;
                            alpha[i] = cJ + diff;
                        }
                    }
                }
                else
                {
                    double quadCoef = qd[i] + qd[j] - 2 * qI[j];
                    if (quadCoef <= 0)
                    {
                        quadCoef = 1e-12;
                    }
                    double delta = (g[i] - g[j]) / quadCoef;
                    double sum   = alpha[i] + alpha[j];
                    alpha[i] -= delta;
                    alpha[j] += delta;
                    if (sum > cI)
                    {
                        if (alpha[i] > cI)
                        {
                            alpha[i] = cI;
                            alpha[j] = sum - cI;
                        }
                    }
                    else
                    {
                        if (alpha[j] < 0)
                        {
                            alpha[j] = 0;
                            alpha[i] = sum;
                        }
                    }
                    if (sum > cJ)
                    {
                        if (alpha[j] > cJ)
                        {
                            alpha[j] = cJ;
                            alpha[i] = sum - cJ;
                        }
                    }
                    else
                    {
                        if (alpha[i] < 0)
                        {
                            alpha[i] = 0;
                            alpha[j] = sum;
                        }
                    }
                }
                // update G
                double deltaAlphaI = alpha[i] - oldAlphaI;
                double deltaAlphaJ = alpha[j] - oldAlphaJ;
                for (int k = 0; k < activeSize; k++)
                {
                    g[k] += qI[k] * deltaAlphaI + qJ[k] * deltaAlphaJ;
                }
                // update alpha_status and G_bar
                {
                    bool ui = IsUpperBound(i);
                    bool uj = IsUpperBound(j);
                    UpdateAlphaStatus(i);
                    UpdateAlphaStatus(j);
                    int k;
                    if (ui != IsUpperBound(i))
                    {
                        qI = q1.GetQ(i, l1);
                        if (ui)
                        {
                            for (k = 0; k < l1; k++)
                            {
                                gBar[k] -= cI * qI[k];
                            }
                        }
                        else
                        {
                            for (k = 0; k < l1; k++)
                            {
                                gBar[k] += cI * qI[k];
                            }
                        }
                    }
                    if (uj != IsUpperBound(j))
                    {
                        qJ = q1.GetQ(j, l1);
                        if (uj)
                        {
                            for (k = 0; k < l1; k++)
                            {
                                gBar[k] -= cJ * qJ[k];
                            }
                        }
                        else
                        {
                            for (k = 0; k < l1; k++)
                            {
                                gBar[k] += cJ * qJ[k];
                            }
                        }
                    }
                }
            }
            if (iter >= maxIter)
            {
                if (activeSize < l1)
                {
                    // reconstruct the whole gradient to calculate objective value
                    ReconstructGradient();
                    activeSize = l1;
                    SvmMain.Info("*");
                }
                SvmMain.Info("\nWARNING: reaching max number of iterations");
            }
            // calculate rho
            si.rho = CalculateRho();
            // calculate objective value
            {
                double v = 0;
                int    i;
                for (i = 0; i < l1; i++)
                {
                    v += alpha[i] * (g[i] + p[i]);
                }
                si.obj = v / 2;
            }
            // put back the solution
            {
                for (int i = 0; i < l1; i++)
                {
                    alpha1[activeSet[i]] = alpha[i];
                }
            }
            si.upperBoundP = cp1;
            si.upperBoundN = cn1;
            SvmMain.Info("\noptimization finished, #iter = " + iter + "\n");
        }