Пример #1
0
 public override void Solve(int l, QMatrix Q, double[] p, short[] y,
      double[] alpha, double Cp, double Cn, double eps,
      SolutionInfo si, int shrinking) {
   this.si = si;
   base.Solve(l, Q, p, y, alpha, Cp, Cn, eps, si, shrinking);
 }
Пример #2
0
    public virtual void Solve(int l, QMatrix Q, double[] p_, short[] y_,
         double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, int shrinking) {
      this.l = l;
      this.Q = Q;
      QD = Q.get_QD();
      p = (double[])p_.Clone();
      y = (short[])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.get_Q(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 max_iter = Math.Max(10000000, l > int.MaxValue / 100 ? int.MaxValue : 100 * l);
      int counter = Math.Min(l, 1000) + 1;
      int[] working_set = new int[2];

      while (iter < max_iter) {
        // show progress and do shrinking

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

        if (select_working_set(working_set) != 0) {
          // reconstruct the whole gradient
          reconstruct_gradient();
          // reset active set size and check
          active_size = l;
          svm.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.get_Q(i, active_size);
        float[] Q_j = Q.get_Q(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 = QD[i] + QD[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 = QD[i] + QD[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.get_Q(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.get_Q(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];
          }
        }

      }

      if (iter >= max_iter) {
        if (active_size < l) {
          // reconstruct the whole gradient to calculate objective value
          reconstruct_gradient();
          active_size = l;
          svm.info("*");
        }
        svm.info("WARNING: reaching max number of iterations" + Environment.NewLine);
      }

      // 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;

      svm.info("optimization finished, #iter = " + iter + Environment.NewLine);
    }