code: public double negHalfGradient(double y, double f) {
      switch (distribution) {
        case AUTO:
        case gaussian:
        case bernoulli:
        case poisson:
          return y - linkInv(f);
        case quasibinomial:
          double ff = linkInv(f);
          if (ff==y)
            return 0;
          else if (ff > 1)
            return y/ff;
          else if (ff < 0)
            return (1-y)/(ff-1);
          else
            return y - ff;
        case gamma:
          return y * exp(-f) - 1;
        case tweedie:
          assert (tweediePower > 1 && tweediePower < 2);
          return y * exp(f * (1 - tweediePower)) - exp(f * (2 - tweediePower));
        case huber:
          if (Math.abs(y-f) <= huberDelta) {
            return y - f;
          } else {
            return f >= y ? -huberDelta : huberDelta;
          }
        case laplace:
          return f > y ? -0.5 : 0.5;
        case quantile:
          return y > f ? 0.5*quantileAlpha : 0.5*(quantileAlpha-1);
  //        return y > f ? quantileAlpha : quantileAlpha-1;
        case modified_huber:
          double yf = (2*y-1)*f;
          if (yf < -1)
            return 2*(2*y-1);
          else if (yf > 1)
            return 0;
          else
            return -f*(2*y-1)*(2*y-1);
        default:
          throw H2O.unimpl();
      }
    }
docs: (Negative half) Gradient of deviance function at predicted value f, for actual response y
  This assumes that the deviance(w,y,f) is w*deviance(y,f), so the gradient is w * d/df deviance(y,f)
  @param y (actual) response
  @param f (predicted) response in link space (including offset)
  @return -1/2 * d/df deviance(w=1,y,f)