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]; } } } } }
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"); }
// 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); }
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); }
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"); }