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