/**
   * wrap up various variables to save memeory and do some housekeeping after optimization has
   * finished.
   *
   * @throws Exception if something goes wrong
   */
  protected void wrapUp() throws Exception {
    m_target = null;

    m_nEvals = m_kernel.numEvals();
    m_nCacheHits = m_kernel.numCacheHits();

    if ((m_SVM.getKernel() instanceof PolyKernel)
        && ((PolyKernel) m_SVM.getKernel()).getExponent() == 1.0) {
      // convert alpha's to weights
      double[] weights = new double[m_data.numAttributes()];
      for (int k = m_supportVectors.getNext(-1); k != -1; k = m_supportVectors.getNext(k)) {
        for (int j = 0; j < weights.length; j++) {
          if (j != m_classIndex) {
            weights[j] += (m_alpha[k] - m_alphaStar[k]) * m_data.instance(k).value(j);
          }
        }
      }
      m_weights = weights;

      // release memory
      m_alpha = null;
      m_alphaStar = null;
      m_kernel = null;
    }
    m_bModelBuilt = true;
  }
  /**
   * initializes the algorithm
   *
   * @param data the data to work with
   * @throws Exception if m_SVM is null
   */
  protected void init(Instances data) throws Exception {
    if (m_SVM == null) {
      throw new Exception("SVM not initialized in optimizer. Use RegOptimizer.setSVMReg()");
    }
    m_C = m_SVM.getC();
    m_data = data;
    m_classIndex = data.classIndex();
    m_nInstances = data.numInstances();

    // Initialize kernel
    m_kernel = Kernel.makeCopy(m_SVM.getKernel());
    m_kernel.buildKernel(data);

    // init m_target
    m_target = new double[m_nInstances];
    for (int i = 0; i < m_nInstances; i++) {
      m_target[i] = data.instance(i).classValue();
    }

    m_random = new Random(m_nSeed);

    //		initialize alpha and alpha* array to all zero
    m_alpha = new double[m_target.length];
    m_alphaStar = new double[m_target.length];

    m_supportVectors = new SMOset(m_nInstances);

    m_b = 0.0;
    m_nEvals = 0;
    m_nCacheHits = -1;
  }
 /**
  * SVMOutput of an instance in the training set, m_data This uses the cache, unlike
  * SVMOutput(Instance)
  *
  * @param index index of the training instance in m_data
  * @return the SVM output
  * @throws Exception if something goes wrong
  */
 protected double SVMOutput(int index) throws Exception {
   double result = -m_b;
   for (int i = m_supportVectors.getNext(-1); i != -1; i = m_supportVectors.getNext(i)) {
     result += (m_alpha[i] - m_alphaStar[i]) * m_kernel.eval(index, i, m_data.instance(index));
   }
   return result;
 }
 /**
  * Compute the value of the objective function.
  *
  * @return the score
  * @throws Exception if something goes wrong
  */
 protected double getScore() throws Exception {
   double res = 0;
   double t = 0, t2 = 0;
   double sumAlpha = 0.0;
   for (int i = 0; i < m_nInstances; i++) {
     sumAlpha += (m_alpha[i] - m_alphaStar[i]);
     for (int j = 0; j < m_nInstances; j++) {
       t +=
           (m_alpha[i] - m_alphaStar[i])
               * (m_alpha[j] - m_alphaStar[j])
               * m_kernel.eval(i, j, m_data.instance(i));
     }
     //    switch(m_nLossType) {
     //    case L1:
     //    t2 += m_data.instance(i).classValue() * (m_alpha[i] - m_alpha_[i]);
     //    break;
     //    case L2:
     //    t2 += m_data.instance(i).classValue() * (m_alpha[i] - m_alpha_[i]) - (0.5/m_SVM.getC())
     // * (m_alpha[i]*m_alpha[i] + m_alpha_[i]*m_alpha_[i]);
     //    break;
     //    case HUBER:
     //    t2 += m_data.instance(i).classValue() * (m_alpha[i] - m_alpha_[i]) -
     // (0.5*m_SVM.getEpsilon()/m_SVM.getC()) * (m_alpha[i]*m_alpha[i] + m_alpha_[i]*m_alpha_[i]);
     //    break;
     //    case EPSILON:
     // t2 += m_data.instance(i).classValue() * (m_alpha[i] - m_alphaStar[i]) - m_epsilon *
     // (m_alpha[i] + m_alphaStar[i]);
     t2 += m_target[i] * (m_alpha[i] - m_alphaStar[i]) - m_epsilon * (m_alpha[i] + m_alphaStar[i]);
     //    break;
     //    }
   }
   res += -0.5 * t + t2;
   return res;
 }
  /**
   * @param inst
   * @return
   * @throws Exception
   */
  public double SVMOutput(Instance inst) throws Exception {

    double result = -m_b;
    // Is the machine linear?
    if (m_weights != null) {
      // Is weight vector stored in sparse format?
      for (int i = 0; i < inst.numValues(); i++) {
        if (inst.index(i) != m_classIndex) {
          result += m_weights[inst.index(i)] * inst.valueSparse(i);
        }
      }
    } else {
      for (int i = m_supportVectors.getNext(-1); i != -1; i = m_supportVectors.getNext(i)) {
        result += (m_alpha[i] - m_alphaStar[i]) * m_kernel.eval(-1, i, inst);
      }
    }
    return result;
  }