public void solve(double[] w) { int i, m, s; int iter = 0; double[] alpha = new double[l * nr_class]; double[] alpha_new = new double[nr_class]; int[] index = new int[l]; double[] QD = new double[l]; int[] d_ind = new int[nr_class]; double[] d_val = new double[nr_class]; int[] alpha_index = new int[nr_class * l]; int[] y_index = new int[l]; int active_size = l; int[] active_size_i = new int[l]; double eps_shrink = Math.Max(10.0 * eps, 1.0); // stopping tolerance for shrinking bool start_from_all = true; // Initial alpha can be set here. Note that // sum_m alpha[i*nr_class+m] = 0, for all i=1,...,l-1 // alpha[i*nr_class+m] <= C[GETI(i)] if prob->y[i] == m // alpha[i*nr_class+m] <= 0 if prob->y[i] != m // If initial alpha isn't zero, uncomment the for loop below to initialize w for (i = 0; i < l * nr_class; i++) alpha[i] = 0; for (i = 0; i < w_size * nr_class; i++) w[i] = 0; for (i = 0; i < l; i++) { for (m = 0; m < nr_class; m++) alpha_index[i * nr_class + m] = m; QD[i] = 0; foreach (Feature xi in prob.x[i]) { double val = xi.Value; QD[i] += val * val; // Uncomment the for loop if initial alpha isn't zero // for(m=0; m<nr_class; m++) // w[(xi->index-1)*nr_class+m] += alpha[i*nr_class+m]*val; } active_size_i[i] = nr_class; y_index[i] = (int)prob.y[i]; index[i] = i; } ArrayPointer<double> alpha_i = new ArrayPointer<double>(alpha, 0); ArrayPointer<int> alpha_index_i = new ArrayPointer<int>(alpha_index, 0); while (iter < max_iter) { double stopping = Double.NegativeInfinity; for (i = 0; i < active_size; i++) { // int j = i+rand()%(active_size-i); int j = i + Linear.random.Next(active_size - i); Linear.swap(index, i, j); } for (s = 0; s < active_size; s++) { i = index[s]; double Ai = QD[i]; // double *alpha_i = &alpha[i*nr_class]; alpha_i.setOffset(i * nr_class); // int *alpha_index_i = &alpha_index[i*nr_class]; alpha_index_i.setOffset(i * nr_class); if (Ai > 0) { for (m = 0; m < active_size_i[i]; m++) G[m] = 1; if (y_index[i] < active_size_i[i]) G[y_index[i]] = 0; foreach (Feature xi in prob.x[i]) { // double *w_i = &w[(xi.index-1)*nr_class]; int w_offset = (xi.Index - 1) * nr_class; for (m = 0; m < active_size_i[i]; m++) // G[m] += w_i[alpha_index_i[m]]*(xi.value); G[m] += w[w_offset + alpha_index_i[m]] * (xi.Value); } double minG = Double.PositiveInfinity; double maxG = Double.NegativeInfinity; for (m = 0; m < active_size_i[i]; m++) { if (alpha_i[alpha_index_i[m]] < 0 && G[m] < minG) minG = G[m]; if (G[m] > maxG) maxG = G[m]; } if (y_index[i] < active_size_i[i]) { if (alpha_i[(int)prob.y[i]] < C[GETI(i)] && G[y_index[i]] < minG) { minG = G[y_index[i]]; } } for (m = 0; m < active_size_i[i]; m++) { if (be_shrunk(i, m, y_index[i], alpha_i[alpha_index_i[m]], minG)) { active_size_i[i]--; while (active_size_i[i] > m) { if (!be_shrunk(i, active_size_i[i], y_index[i], alpha_i[alpha_index_i[active_size_i[i]]], minG)) { Linear.swap(alpha_index_i, m, active_size_i[i]); Linear.swap(G, m, active_size_i[i]); if (y_index[i] == active_size_i[i]) y_index[i] = m; else if (y_index[i] == m) y_index[i] = active_size_i[i]; break; } active_size_i[i]--; } } } if (active_size_i[i] <= 1) { active_size--; Linear.swap(index, s, active_size); s--; continue; } if (maxG - minG <= 1e-12) continue; else stopping = Math.Max(maxG - minG, stopping); for (m = 0; m < active_size_i[i]; m++) B[m] = G[m] - Ai * alpha_i[alpha_index_i[m]]; solve_sub_problem(Ai, y_index[i], C[GETI(i)], active_size_i[i], alpha_new); int nz_d = 0; for (m = 0; m < active_size_i[i]; m++) { double d = alpha_new[m] - alpha_i[alpha_index_i[m]]; alpha_i[alpha_index_i[m]] = alpha_new[m]; if (Math.Abs(d) >= 1e-12) { d_ind[nz_d] = alpha_index_i[m]; d_val[nz_d] = d; nz_d++; } } foreach (Feature xi in prob.x[i]) { // double *w_i = &w[(xi->index-1)*nr_class]; int w_offset = (xi.Index - 1) * nr_class; for (m = 0; m < nz_d; m++) { w[w_offset + d_ind[m]] += d_val[m] * xi.Value; } } } } iter++; if (iter % 10 == 0) { Linear.info("."); } if (stopping < eps_shrink) { if (stopping < eps && start_from_all == true) break; else { active_size = l; for (i = 0; i < l; i++) active_size_i[i] = nr_class; Linear.info("*"); eps_shrink = Math.Max(eps_shrink / 2, eps); start_from_all = true; } } else start_from_all = false; } Linear.info("\noptimization finished, #iter = {0}", iter); if (iter >= max_iter) Linear.info("\nWARNING: reaching max number of iterations"); // calculate objective value double v = 0; int nSV = 0; for (i = 0; i < w_size * nr_class; i++) v += w[i] * w[i]; v = 0.5 * v; for (i = 0; i < l * nr_class; i++) { v += alpha[i]; if (Math.Abs(alpha[i]) > 0) nSV++; } for (i = 0; i < l; i++) v -= alpha[i * nr_class + (int)prob.y[i]]; Linear.info("Objective value = {0}", v); Linear.info("nSV = {0}", nSV); }