protected double[] evaluateGradient(double[] x){
      double[] grad = new double[x.length];
      for(int i=0; i<m_Classes.length; i++){ // ith bag
        int nI = m_Data[i][0].length; // numInstances in ith bag 

        double denom=0.0;
        double[] numrt = new double[x.length];

        for(int j=0; j<nI; j++){
          double exp=0.0;
          for(int k=0; k<m_Data[i].length; k++)
            exp += (m_Data[i][k][j]-x[k*2])*(m_Data[i][k][j]-x[k*2])/
              (x[k*2+1]*x[k*2+1]);			
          exp = Math.exp(-exp);
          if(m_Classes[i]==1)
            denom += exp;
          else
            denom += (1.0-exp);		   

          // Instance-wise update
          for(int p=0; p<m_Data[i].length; p++){  // pth variable
            numrt[2*p] += exp*2.0*(x[2*p]-m_Data[i][p][j])/
              (x[2*p+1]*x[2*p+1]);
            numrt[2*p+1] += 
              exp*(x[2*p]-m_Data[i][p][j])*(x[2*p]-m_Data[i][p][j])/
              (x[2*p+1]*x[2*p+1]*x[2*p+1]);
          }			
        }

        if(denom <= m_Zero){
          denom = m_Zero;
        }

        // Bag-wise update 
        for(int q=0; q<m_Data[i].length; q++){
          if(m_Classes[i]==1){
            grad[2*q] += numrt[2*q]/denom;
            grad[2*q+1] -= numrt[2*q+1]/denom;
          }else{
            grad[2*q] -= numrt[2*q]/denom;
            grad[2*q+1] += numrt[2*q+1]/denom;
          }
        }
      }

      return grad;
    }