示例#1
0
        private void InitializeGradient(int totalProblems, IQMatrix qMatrix)
        {
            gradient    = new double[totalProblems];
            gradientBar = new double[totalProblems];
            int i;

            for (i = 0; i < totalProblems; i++)
            {
                gradient[i]    = p[i];
                gradientBar[i] = 0;
            }
            for (i = 0; i < totalProblems; i++)
            {
                if (!IsLowerBound(i))
                {
                    float[] Q_i     = qMatrix.GetQ(i, totalProblems);
                    double  alpha_i = alpha[i];
                    int     j;
                    for (j = 0; j < totalProblems; j++)
                    {
                        gradient[j] += alpha_i * Q_i[j];
                    }
                    if (IsUpperBound(i))
                    {
                        for (j = 0; j < totalProblems; j++)
                        {
                            gradientBar[j] += GetC(i) * Q_i[j];
                        }
                    }
                }
            }
        }
示例#2
0
文件: Solver.cs 项目: wendelad/RecSys
        public virtual void Solve(int l, IQMatrix Q, double[] p_, sbyte[] y_, double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, bool shrinking)
        {
            this.l = l;
            this.Q = Q;
            QD = Q.GetQD();
            p = (double[])p_.Clone();
            y = (sbyte[])y_.Clone();
            alpha = (double[])alpha_.Clone();
            this.Cp = Cp;
            this.Cn = Cn;
            this.EPS = eps;
            this.unshrink = false;

            // initialize alpha_status
            {
                alpha_status = new byte[l];
                for (int i = 0; i < l; i++)
                    update_alpha_status(i);
            }

            // initialize active set (for shrinking)
            {
                active_set = new int[l];
                for (int i = 0; i < l; i++)
                    active_set[i] = i;
                active_size = l;
            }

            // initialize gradient
            {
                G = new double[l];
                G_bar = new double[l];
                int i;
                for (i = 0; i < l; i++)
                {
                    G[i] = p[i];
                    G_bar[i] = 0;
                }
                for (i = 0; i < l; i++)
                    if (!is_lower_bound(i))
                    {
                        float[] Q_i = Q.GetQ(i, l);
                        double alpha_i = alpha[i];
                        int j;
                        for (j = 0; j < l; j++)
                            G[j] += alpha_i * Q_i[j];
                        if (is_upper_bound(i))
                            for (j = 0; j < l; j++)
                                G_bar[j] += get_C(i) * Q_i[j];
                    }
            }

            // optimization step

            int iter = 0;
            int counter = Math.Min(l, 1000) + 1;
            int[] working_set = new int[2];

            while (true)
            {
                // show progress and do shrinking

                if (--counter == 0)
                {
                    counter = Math.Min(l, 1000);
                    if (shrinking) do_shrinking();
                    Procedures.info(".");
                }

                if (select_working_set(working_set) != 0)
                {
                    // reconstruct the whole gradient
                    reconstruct_gradient();
                    // reset active set size and check
                    active_size = l;
                    Procedures.info("*");
                    if (select_working_set(working_set) != 0)
                        break;
                    else
                        counter = 1;	// do shrinking next iteration
                }

                int i = working_set[0];
                int j = working_set[1];

                ++iter;

                // update alpha[i] and alpha[j], handle bounds carefully

                float[] Q_i = Q.GetQ(i, active_size);
                float[] Q_j = Q.GetQ(j, active_size);

                double C_i = get_C(i);
                double C_j = get_C(j);

                double old_alpha_i = alpha[i];
                double old_alpha_j = alpha[j];

                if (y[i] != y[j])
                {
                    double quad_coef = Q_i[i] + Q_j[j] + 2 * Q_i[j];
                    if (quad_coef <= 0)
                        quad_coef = 1e-12;
                    double delta = (-G[i] - G[j]) / quad_coef;
                    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 > C_i - C_j)
                    {
                        if (alpha[i] > C_i)
                        {
                            alpha[i] = C_i;
                            alpha[j] = C_i - diff;
                        }
                    }
                    else
                    {
                        if (alpha[j] > C_j)
                        {
                            alpha[j] = C_j;
                            alpha[i] = C_j + diff;
                        }
                    }
                }
                else
                {
                    double quad_coef = Q_i[i] + Q_j[j] - 2 * Q_i[j];
                    if (quad_coef <= 0)
                        quad_coef = 1e-12;
                    double delta = (G[i] - G[j]) / quad_coef;
                    double sum = alpha[i] + alpha[j];
                    alpha[i] -= delta;
                    alpha[j] += delta;

                    if (sum > C_i)
                    {
                        if (alpha[i] > C_i)
                        {
                            alpha[i] = C_i;
                            alpha[j] = sum - C_i;
                        }
                    }
                    else
                    {
                        if (alpha[j] < 0)
                        {
                            alpha[j] = 0;
                            alpha[i] = sum;
                        }
                    }
                    if (sum > C_j)
                    {
                        if (alpha[j] > C_j)
                        {
                            alpha[j] = C_j;
                            alpha[i] = sum - C_j;
                        }
                    }
                    else
                    {
                        if (alpha[i] < 0)
                        {
                            alpha[i] = 0;
                            alpha[j] = sum;
                        }
                    }
                }

                // update G

                double delta_alpha_i = alpha[i] - old_alpha_i;
                double delta_alpha_j = alpha[j] - old_alpha_j;

                for (int k = 0; k < active_size; k++)
                {
                    G[k] += Q_i[k] * delta_alpha_i + Q_j[k] * delta_alpha_j;
                }

                // update alpha_status and G_bar

                {
                    bool ui = is_upper_bound(i);
                    bool uj = is_upper_bound(j);
                    update_alpha_status(i);
                    update_alpha_status(j);
                    int k;
                    if (ui != is_upper_bound(i))
                    {
                        Q_i = Q.GetQ(i, l);
                        if (ui)
                            for (k = 0; k < l; k++)
                                G_bar[k] -= C_i * Q_i[k];
                        else
                            for (k = 0; k < l; k++)
                                G_bar[k] += C_i * Q_i[k];
                    }

                    if (uj != is_upper_bound(j))
                    {
                        Q_j = Q.GetQ(j, l);
                        if (uj)
                            for (k = 0; k < l; k++)
                                G_bar[k] -= C_j * Q_j[k];
                        else
                            for (k = 0; k < l; k++)
                                G_bar[k] += C_j * Q_j[k];
                    }
                }

            }

            // calculate rho

            si.rho = calculate_rho();

            // calculate objective value
            {
                double v = 0;
                int i;
                for (i = 0; i < l; i++)
                    v += alpha[i] * (G[i] + p[i]);

                si.obj = v / 2;
            }

            // put back the solution
            {
                for (int i = 0; i < l; i++)
                    alpha_[active_set[i]] = alpha[i];
            }

            si.upper_bound_p = Cp;
            si.upper_bound_n = Cn;

            Procedures.info("\noptimization finished, #iter = " + iter + "\n");
        }
示例#3
0
        // return 1 if already optimal, return 0 otherwise
        protected virtual int SelectWorkingSet(int[] workingSet)
        {
            // return i,j such that
            // i: Maximizes -y_i * grad(f)_i, i in I_up(\Alpha)
            // j: mimimizes the decrease of obj value
            //    (if quadratic coefficeint <= 0, replace it with tau)
            //    -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\Alpha)

            double gMax       = -INF;
            double gMax2      = -INF;
            int    gMaxIdx    = -1;
            int    gMinIdx    = -1;
            double objDiffMin = INF;

            for (int t = 0; t < activeSize; t++)
            {
                if (y[t] == +1)
                {
                    if (!IsUpperBound(t))
                    {
                        if (-gradient[t] >= gMax)
                        {
                            gMax    = -gradient[t];
                            gMaxIdx = t;
                        }
                    }
                }
                else
                {
                    if (!IsLowerBound(t))
                    {
                        if (gradient[t] >= gMax)
                        {
                            gMax    = gradient[t];
                            gMaxIdx = t;
                        }
                    }
                }
            }
            int i = gMaxIdx;

            float[] qI = null;
            if (i != -1) // null Q_i not accessed: GMax=-INF if i=-1
            {
                qI = qMatrix.GetQ(i, activeSize);
            }

            for (int j = 0; j < activeSize; j++)
            {
                if (y[j] == +1)
                {
                    if (!IsLowerBound(j))
                    {
                        double gradDiff = gMax + gradient[j];
                        if (gradient[j] >= gMax2)
                        {
                            gMax2 = gradient[j];
                        }
                        if (gradDiff > 0)
                        {
                            double objDiff;
                            double quadCoef = qI[i] + qd[j] - 2.0 * y[i] * qI[j];
                            if (quadCoef > 0)
                            {
                                objDiff = -(gradDiff * gradDiff) / quadCoef;
                            }
                            else
                            {
                                objDiff = -(gradDiff * gradDiff) / 1e-12;
                            }
                            if (objDiff <= objDiffMin)
                            {
                                gMinIdx    = j;
                                objDiffMin = objDiff;
                            }
                        }
                    }
                }
                else
                {
                    if (!IsUpperBound(j))
                    {
                        double gradDiff = gMax - gradient[j];
                        if (-gradient[j] >= gMax2)
                        {
                            gMax2 = -gradient[j];
                        }
                        if (gradDiff > 0)
                        {
                            double objDiff;
                            double quadCoef = qI[i] + qd[j] + 2.0 * y[i] * qI[j];
                            if (quadCoef > 0)
                            {
                                objDiff = -(gradDiff * gradDiff) / quadCoef;
                            }
                            else
                            {
                                objDiff = -(gradDiff * gradDiff) / 1e-12;
                            }

                            if (objDiff <= objDiffMin)
                            {
                                gMinIdx    = j;
                                objDiffMin = objDiff;
                            }
                        }
                    }
                }
            }

            if (gMax + gMax2 < eps)
            {
                return(1);
            }

            workingSet[0] = gMaxIdx;
            workingSet[1] = gMinIdx;
            return(0);
        }
示例#4
0
        public virtual void Solve(
            int totalProblemsInSolver,
            IQMatrix matrix,
            double[] pValue,
            sbyte[] yValue,
            double[] alphaValue,
            double cpValue,
            double cnValue,
            double epsValue,
            SolutionInfo solutionInfo,
            bool shrinking)
        {
            totalProblems = totalProblemsInSolver;
            qMatrix       = matrix;
            qd            = matrix.GetQD();
            p             = (double[])pValue.Clone();
            y             = (sbyte[])yValue.Clone();
            alpha         = (double[])alphaValue.Clone();
            this.cp       = cpValue;
            this.cn       = cnValue;
            eps           = epsValue;
            unshrink      = false;

            // initialize alpha_status
            InitializeAlphaStatus(totalProblemsInSolver);

            // initialize active set (for shrinking)
            InitializeActiveSet(totalProblemsInSolver);

            // initialize gradient
            InitializeGradient(totalProblemsInSolver, matrix);

            // optimization step

            int maxIterations = Math.Max(10000000, totalProblemsInSolver > int.MaxValue / 100 ? int.MaxValue : 100 * totalProblemsInSolver);
            int iter          = 0;
            int counter       = Math.Min(totalProblemsInSolver, 1000) + 1;

            int[] workingSet = new int[2];

            while (iter < maxIterations)
            {
                // show progress and do shrinking
                Token.ThrowIfCancellationRequested();
                if (--counter == 0)
                {
                    counter = Math.Min(totalProblemsInSolver, 1000);
                    if (shrinking)
                    {
                        DoShrinking();
                    }

                    log.Debug(".");
                }

                if (SelectWorkingSet(workingSet) != 0)
                {
                    // reconstruct the whole gradient
                    ReconstructGradient();

                    // reset active set size and check
                    activeSize = totalProblemsInSolver;
                    log.Debug("*");
                    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 = matrix.GetQ(i, activeSize);
                float[] qJ = matrix.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 = qI[i] + qJ[j] + 2 * qI[j];
                    if (quadCoef <= 0)
                    {
                        quadCoef = 1e-12;
                    }

                    double delta = (-gradient[i] - gradient[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 = qI[i] + qJ[j] - 2 * qI[j];
                    if (quadCoef <= 0)
                    {
                        quadCoef = 1e-12;
                    }

                    double delta = (gradient[i] - gradient[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++)
                {
                    gradient[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 = matrix.GetQ(i, totalProblemsInSolver);
                        if (ui)
                        {
                            for (k = 0; k < totalProblemsInSolver; k++)
                            {
                                gradientBar[k] -= cI * qI[k];
                            }
                        }
                        else
                        {
                            for (k = 0; k < totalProblemsInSolver; k++)
                            {
                                gradientBar[k] += cI * qI[k];
                            }
                        }
                    }

                    if (uj != IsUpperBound(j))
                    {
                        qJ = matrix.GetQ(j, totalProblemsInSolver);
                        if (uj)
                        {
                            for (k = 0; k < totalProblemsInSolver; k++)
                            {
                                gradientBar[k] -= cJ * qJ[k];
                            }
                        }
                        else
                        {
                            for (k = 0; k < totalProblemsInSolver; k++)
                            {
                                gradientBar[k] += cJ * qJ[k];
                            }
                        }
                    }
                }
            }

            if (iter >= maxIterations)
            {
                if (activeSize < totalProblemsInSolver)
                {
                    // reconstruct the whole gradient to calculate objective value
                    ReconstructGradient();
                    activeSize = totalProblemsInSolver;
                    log.Debug("*");
                }

                log.Warn("WARNING: reaching max number of iterations");
            }

            // calculate rho
            solutionInfo.Rho = CalculateRho();

            // calculate objective value
            CalculateObjectiveValue(totalProblemsInSolver, solutionInfo);

            // put back the solution
            for (int i = 0; i < totalProblemsInSolver; i++)
            {
                alphaValue[activeSet[i]] = alpha[i];
            }

            solutionInfo.UpperBoundP = cpValue;
            solutionInfo.UpperBoundN = cnValue;
            log.Debug("optimization finished, #iter = " + iter);
        }
示例#5
0
        public virtual void Solve(int l, IQMatrix Q, double[] p_, sbyte[] y_, double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, bool shrinking)
        {
            this.l            = l;
            this.Q            = Q;
            this.QD           = Q.GetQD();
            this.p            = (double[])p_.Clone();
            this.y            = (sbyte[])y_.Clone();
            this.alpha        = (double[])alpha_.Clone();
            this.Cp           = Cp;
            this.Cn           = Cn;
            this.EPS          = eps;
            this.unshrink     = false;
            this.alpha_status = new byte[l];
            for (int i = 0; i < l; i++)
            {
                this.update_alpha_status(i);
            }
            this.active_set = new int[l];
            for (int j = 0; j < l; j++)
            {
                this.active_set[j] = j;
            }
            this.active_size = l;
            this.G           = new double[l];
            this.G_bar       = new double[l];
            for (int k = 0; k < l; k++)
            {
                this.G[k]     = this.p[k];
                this.G_bar[k] = 0.0;
            }
            for (int k = 0; k < l; k++)
            {
                if (!this.is_lower_bound(k))
                {
                    float[] q   = Q.GetQ(k, l);
                    double  num = this.alpha[k];
                    for (int m = 0; m < l; m++)
                    {
                        this.G[m] += num * (double)q[m];
                    }
                    if (this.is_upper_bound(k))
                    {
                        for (int m = 0; m < l; m++)
                        {
                            this.G_bar[m] += this.get_C(k) * (double)q[m];
                        }
                    }
                }
            }
            int num2 = 0;
            int num3 = Math.Min(l, 1000) + 1;

            int[] array = new int[2];
            while (true)
            {
                if (--num3 == 0)
                {
                    num3 = Math.Min(l, 1000);
                    if (shrinking)
                    {
                        this.do_shrinking();
                    }
                    Procedures.info(".");
                }
                if (this.select_working_set(array) != 0)
                {
                    this.reconstruct_gradient();
                    this.active_size = l;
                    Procedures.info("*");
                    if (this.select_working_set(array) != 0)
                    {
                        break;
                    }
                    num3 = 1;
                }
                int num4 = array[0];
                int num5 = array[1];
                num2++;
                float[] q2   = Q.GetQ(num4, this.active_size);
                float[] q3   = Q.GetQ(num5, this.active_size);
                double  num6 = this.get_C(num4);
                double  num7 = this.get_C(num5);
                double  num8 = this.alpha[num4];
                double  num9 = this.alpha[num5];
                if (this.y[num4] != this.y[num5])
                {
                    double num10 = (double)(q2[num4] + q3[num5] + 2f * q2[num5]);
                    if (num10 <= 0.0)
                    {
                        num10 = 1E-12;
                    }
                    double num11 = (0.0 - this.G[num4] - this.G[num5]) / num10;
                    double num12 = this.alpha[num4] - this.alpha[num5];
                    this.alpha[num4] += num11;
                    this.alpha[num5] += num11;
                    if (num12 > 0.0)
                    {
                        if (this.alpha[num5] < 0.0)
                        {
                            this.alpha[num5] = 0.0;
                            this.alpha[num4] = num12;
                        }
                    }
                    else if (this.alpha[num4] < 0.0)
                    {
                        this.alpha[num4] = 0.0;
                        this.alpha[num5] = 0.0 - num12;
                    }
                    if (num12 > num6 - num7)
                    {
                        if (this.alpha[num4] > num6)
                        {
                            this.alpha[num4] = num6;
                            this.alpha[num5] = num6 - num12;
                        }
                    }
                    else if (this.alpha[num5] > num7)
                    {
                        this.alpha[num5] = num7;
                        this.alpha[num4] = num7 + num12;
                    }
                }
                else
                {
                    double num13 = (double)(q2[num4] + q3[num5] - 2f * q2[num5]);
                    if (num13 <= 0.0)
                    {
                        num13 = 1E-12;
                    }
                    double num14 = (this.G[num4] - this.G[num5]) / num13;
                    double num15 = this.alpha[num4] + this.alpha[num5];
                    this.alpha[num4] -= num14;
                    this.alpha[num5] += num14;
                    if (num15 > num6)
                    {
                        if (this.alpha[num4] > num6)
                        {
                            this.alpha[num4] = num6;
                            this.alpha[num5] = num15 - num6;
                        }
                    }
                    else if (this.alpha[num5] < 0.0)
                    {
                        this.alpha[num5] = 0.0;
                        this.alpha[num4] = num15;
                    }
                    if (num15 > num7)
                    {
                        if (this.alpha[num5] > num7)
                        {
                            this.alpha[num5] = num7;
                            this.alpha[num4] = num15 - num7;
                        }
                    }
                    else if (this.alpha[num4] < 0.0)
                    {
                        this.alpha[num4] = 0.0;
                        this.alpha[num5] = num15;
                    }
                }
                double num16 = this.alpha[num4] - num8;
                double num17 = this.alpha[num5] - num9;
                for (int n = 0; n < this.active_size; n++)
                {
                    this.G[n] += (double)q2[n] * num16 + (double)q3[n] * num17;
                }
                bool flag  = this.is_upper_bound(num4);
                bool flag2 = this.is_upper_bound(num5);
                this.update_alpha_status(num4);
                this.update_alpha_status(num5);
                if (flag != this.is_upper_bound(num4))
                {
                    q2 = Q.GetQ(num4, l);
                    if (flag)
                    {
                        for (int num18 = 0; num18 < l; num18++)
                        {
                            this.G_bar[num18] -= num6 * (double)q2[num18];
                        }
                    }
                    else
                    {
                        for (int num18 = 0; num18 < l; num18++)
                        {
                            this.G_bar[num18] += num6 * (double)q2[num18];
                        }
                    }
                }
                if (flag2 != this.is_upper_bound(num5))
                {
                    q3 = Q.GetQ(num5, l);
                    if (flag2)
                    {
                        for (int num18 = 0; num18 < l; num18++)
                        {
                            this.G_bar[num18] -= num7 * (double)q3[num18];
                        }
                    }
                    else
                    {
                        for (int num18 = 0; num18 < l; num18++)
                        {
                            this.G_bar[num18] += num7 * (double)q3[num18];
                        }
                    }
                }
            }
            si.rho = this.calculate_rho();
            double num19 = 0.0;

            for (int num20 = 0; num20 < l; num20++)
            {
                num19 += this.alpha[num20] * (this.G[num20] + this.p[num20]);
            }
            si.obj = num19 / 2.0;
            for (int num21 = 0; num21 < l; num21++)
            {
                alpha_[this.active_set[num21]] = this.alpha[num21];
            }
            si.upper_bound_p = Cp;
            si.upper_bound_n = Cn;
            Procedures.info("\noptimization finished, #iter = " + num2 + "\n");
        }