/// <summary> /// Solves the optimization problem /// </summary> /// <param name="minusOnes"></param> /// <param name="y_"></param> /// <param name="alpha_"></param> /// <param name="si"></param> /// <param name="shrinking"></param> private void Solve(float[] minusOnes, sbyte[] y_, float[] alpha_, SolutionInfo si, bool shrinking) { #region initialization //this.l = l; //this.Q = Q; p = (float[])minusOnes.Clone(); y = (sbyte[])y_.Clone(); alpha = (float[])alpha_.Clone(); //this.Cp = Cp; //this.Cn = Cn; this.unshrink = false; // initialize alpha_status { alpha_status = new byte[problemSize]; for (int i = 0; i < problemSize; i++) { update_alpha_status(i); } } // initialize active set (for shrinking) { active_set = new int[problemSize]; for (int i = 0; i < problemSize; i++) { active_set[i] = i; } active_size = problemSize; } // initialize gradient { G = new float[problemSize]; G_bar = new float[problemSize]; int i; for (i = 0; i < problemSize; i++) { G[i] = p[i]; G_bar[i] = 0; } for (i = 0; i < problemSize; i++) { if (!is_lower_bound(i)) { float[] Q_i = Q.GetQ(i, problemSize); float alpha_i = alpha[i]; int j; for (j = 0; j < problemSize; j++) { G[j] += alpha_i * Q_i[j]; } if (is_upper_bound(i)) { for (j = 0; j < problemSize; j++) { G_bar[j] += get_C(i) * Q_i[j]; } } } } } #endregion // optimization step int iter = 0; int counter = Math.Min(problemSize, 1000) + 1; int[] working_set = new int[2]; int processors = Environment.ProcessorCount; while (iter < IterMaX) { if (--counter == 0) { counter = Math.Min(problemSize, 1000); if (shrinking) { do_shrinking(); } //Procedures.info("."); } if (select_working_set(working_set, processors) != 0) { // reconstruct the whole gradient reconstruct_gradient(); // reset active set size and check active_size = problemSize; // Procedures.info("*"); if (select_working_set(working_set, processors) != 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); float C_i = get_C(i); float C_j = get_C(j); float old_alpha_i = alpha[i]; float old_alpha_j = alpha[j]; if (y[i] != y[j]) { float quad_coef = Q_i[i] + Q_j[j] + 2 * Q_i[j]; if (quad_coef <= 0) { quad_coef = 1e-12f; } float delta = (-G[i] - G[j]) / quad_coef; float 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 { float quad_coef = Q_i[i] + Q_j[j] - 2 * Q_i[j]; if (quad_coef <= 0) { quad_coef = 1e-12f; } float delta = (G[i] - G[j]) / quad_coef; float 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 float delta_alpha_i = alpha[i] - old_alpha_i; float delta_alpha_j = alpha[j] - old_alpha_j; UpdateGradients(Q_i, Q_j, delta_alpha_i, delta_alpha_j); // Parallel.ForEach(partition, UpdateGradient); // 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, problemSize); if (ui) { for (k = 0; k < problemSize; k++) { G_bar[k] -= C_i * Q_i[k]; } } else { for (k = 0; k < problemSize; k++) { G_bar[k] += C_i * Q_i[k]; } } } if (uj != is_upper_bound(j)) { Q_j = Q.GetQ(j, problemSize); if (uj) { for (k = 0; k < problemSize; k++) { G_bar[k] -= C_j * Q_j[k]; } } else { for (k = 0; k < problemSize; k++) { G_bar[k] += C_j * Q_j[k]; } } } } }//end while // calculate rho si.rho = calculate_rho(); si.iter = iter; // calculate objective value { double v = ObjVal(); si.obj = (float)v; } // put back the solution { for (int i = 0; i < problemSize; i++) { //alpha_[active_set[i]] = alpha[i]; //we don't set indexes to previous order alpha_[i] = alpha[i]; } } si.upper_bound_p = Cp; si.upper_bound_n = Cn; }
/// <summary> /// Solves the optimization problem /// </summary> /// <param name="minusOnes"></param> /// <param name="y_"></param> /// <param name="alpha_"></param> /// <param name="si"></param> /// <param name="shrinking"></param> private void Solve(float[] minusOnes, sbyte[] y_, float[] alpha_, SolutionInfo si, bool shrinking) { //this.l = l; //this.Q = Q; p = (float[])minusOnes.Clone(); y = (sbyte[])y_.Clone(); alpha = (float[])alpha_.Clone(); //this.Cp = Cp; //this.Cn = Cn; this.unshrink = false; // initialize alpha_status { alpha_status = new byte[problemSize]; for (int i = 0; i < problemSize; i++) { update_alpha_status(i); } } // initialize active set (for shrinking) { active_set = new int[problemSize]; for (int i = 0; i < problemSize; i++) { active_set[i] = i; } active_size = problemSize; } // initialize gradient { G = new float[problemSize]; G_bar = new float[problemSize]; int i; for (i = 0; i < problemSize; i++) { G[i] = p[i]; G_bar[i] = 0; } for (i = 0; i < problemSize; i++) { if (!is_lower_bound(i)) { float[] Q_i = Q.GetQ(i, problemSize); float alpha_i = alpha[i]; int j; for (j = 0; j < problemSize; j++) { G[j] += alpha_i * Q_i[j]; } if (is_upper_bound(i)) { for (j = 0; j < problemSize; j++) { G_bar[j] += get_C(i) * Q_i[j]; } } } } } // optimization step int iter = 0; int counter = Math.Min(problemSize, 1000) + 1; int[] working_set = new int[2]; Random rand = new Random(); while (true) { // show progress and do shrinking int i = rand.Next(active_size); int j = i; while (j == i) { j = rand.Next(active_size); } ++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); float C_i = get_C(i); float C_j = get_C(j); float old_alpha_i = alpha[i]; float old_alpha_j = alpha[j]; if (y[i] != y[j]) { float quad_coef = Q_i[i] + Q_j[j] + 2 * Q_i[j]; if (quad_coef <= 0) { quad_coef = 1e-12f; } float delta = (-G[i] - G[j]) / quad_coef; float 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 { float quad_coef = Q_i[i] + Q_j[j] - 2 * Q_i[j]; if (quad_coef <= 0) { quad_coef = 1e-12f; } float delta = (G[i] - G[j]) / quad_coef; float 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 float delta_alpha_i = alpha[i] - old_alpha_i; float delta_alpha_j = alpha[j] - old_alpha_j; update_alpha_status(i); update_alpha_status(j); double nG = 0; double nL1G = 0; double nMaxG = double.NegativeInfinity; float GMax = -INF; float GMax2 = -INF; for (int k = 0; k < active_size; k++) { G[k] += Q_i[k] * delta_alpha_i + Q_j[k] * delta_alpha_j; //nG += G[k] * G[k]; //nL1G += Math.Abs( G[k]); //nMaxG = Math.Max(nMaxG, Math.Abs(G[k])); if (y[k] == +1) { if (!is_upper_bound(k)) { if (-G[k] >= GMax) { GMax = -G[k]; } } if (!is_lower_bound(k)) { if (G[k] >= GMax2) { GMax2 = G[k]; } } } else { if (!is_lower_bound(k)) { if (G[k] >= GMax) { GMax = G[k]; } } if (!is_upper_bound(k)) { if (-G[k] >= GMax2) { GMax2 = -G[k]; } } } } if (GMax + GMax2 < EPS) { break; } } // calculate rho si.rho = calculate_rho(); si.iter = iter; // calculate objective value { float v = 0; int i; for (i = 0; i < problemSize; i++) { v += alpha[i] * (G[i] + p[i]); } si.obj = v / 2; } // put back the solution { for (int i = 0; i < problemSize; i++) { alpha_[i] = alpha[i]; //alpha_[active_set[i]] = alpha[i]; //kernel.SwapIndex(i, active_set[i]); } } si.upper_bound_p = Cp; si.upper_bound_n = Cn; // Procedures.info("\noptimization finished, #iter = " + iter + "\n"); }
/// <summary> /// Solves the optimization problem /// </summary> /// <param name="minusOnes"></param> /// <param name="y_"></param> /// <param name="alpha_"></param> /// <param name="si"></param> /// <param name="shrinking"></param> private void Solve(float[] minusOnes, sbyte[] y_, float[] alpha_, SolutionInfo si, bool shrinking) { //this.l = l; //this.Q = Q; p = (float[])minusOnes.Clone(); y = (sbyte[])y_.Clone(); alpha = (float[])alpha_.Clone(); //this.Cp = Cp; //this.Cn = Cn; this.unshrink = false; // initialize alpha_status { alpha_status = new byte[problemSize]; for (int i = 0; i < problemSize; i++) { update_alpha_status(i); } } // initialize active set (for shrinking) { active_set = new int[problemSize]; for (int i = 0; i < problemSize; i++) { active_set[i] = i; } active_size = problemSize; } // initialize gradient { G = new float[problemSize]; G_bar = new float[problemSize]; int i; for (i = 0; i < problemSize; i++) { G[i] = p[i]; G_bar[i] = 0; } for (i = 0; i < problemSize; i++) { if (!is_lower_bound(i)) { float[] Q_i = Q.GetQ(i, problemSize); float alpha_i = alpha[i]; int j; for (j = 0; j < problemSize; j++) { G[j] += alpha_i * Q_i[j]; } if (is_upper_bound(i)) { for (j = 0; j < problemSize; j++) { G_bar[j] += get_C(i) * Q_i[j]; } } } } } // optimization step int iter = 0; int counter = Math.Min(problemSize, 1000) + 1; int[] working_set = new int[2]; float[][] ker2Cols = new float[2][]; ker2Cols[0] = new float[problem.ElementsCount]; ker2Cols[1] = new float[problem.ElementsCount]; while (true) { // show progress and do shrinking if (--counter == 0) { counter = Math.Min(problemSize, 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 = problemSize; // 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 kernel.AllProducts(i, j, ker2Cols); float[] Q_i = ker2Cols[0]; float[] Q_j = ker2Cols[1]; //float[] Q_i = Q.GetQ(i, active_size); //float[] Q_j = Q.GetQ(j, active_size); float C_i = get_C(i); float C_j = get_C(j); float old_alpha_i = alpha[i]; float old_alpha_j = alpha[j]; if (y[i] != y[j]) { float quad_coef = Q_i[i] + Q_j[j] + 2 * Q_i[j]; if (quad_coef <= 0) { quad_coef = 1e-12f; } float delta = (-G[i] - G[j]) / quad_coef; float 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 { float quad_coef = Q_i[i] + Q_j[j] - 2 * Q_i[j]; if (quad_coef <= 0) { quad_coef = 1e-12f; } float delta = (G[i] - G[j]) / quad_coef; float 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 float delta_alpha_i = alpha[i] - old_alpha_i; float 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, problemSize); if (ui) { for (k = 0; k < problemSize; k++) { G_bar[k] -= C_i * Q_i[k]; } } else { for (k = 0; k < problemSize; k++) { G_bar[k] += C_i * Q_i[k]; } } } if (uj != is_upper_bound(j)) { // Q_j = Q.GetQ(j, problemSize); if (uj) { for (k = 0; k < problemSize; k++) { G_bar[k] -= C_j * Q_j[k]; } } else { for (k = 0; k < problemSize; k++) { G_bar[k] += C_j * Q_j[k]; } } } } } // calculate rho si.rho = calculate_rho(); si.iter = iter; // calculate objective value { float v = 0; int i; for (i = 0; i < problemSize; i++) { v += alpha[i] * (G[i] + p[i]); } si.obj = v / 2; } // put back the solution { for (int i = 0; i < problemSize; i++) { alpha_[i] = alpha[i]; //alpha_[active_set[i]] = alpha[i]; //kernel.SwapIndex(i, active_set[i]); } } si.upper_bound_p = Cp; si.upper_bound_n = Cn; }