package hex;

import water.exceptions.H2OIllegalArgumentException;
import water.fvec.Frame;
import water.util.ArrayUtils;

public class ModelMetricsRegression extends ModelMetricsSupervised {
  public final double _mean_residual_deviance;
  public ModelMetricsRegression(Model model, Frame frame, double mse, double sigma, double meanResidualDeviance) {
    super(model, frame, mse, null, sigma);
    _mean_residual_deviance = meanResidualDeviance;
  }

  public static ModelMetricsRegression getFromDKV(Model model, Frame frame) {
    ModelMetrics mm = ModelMetrics.getFromDKV(model, frame);

    if (! (mm instanceof ModelMetricsRegression))
      throw new H2OIllegalArgumentException("Expected to find a Regression ModelMetrics for model: " + model._key.toString() + " and frame: " + frame._key.toString(),
              "Expected to find a ModelMetricsRegression for model: " + model._key.toString() + " and frame: " + frame._key.toString() + " but found a: " + mm.getClass());

    return (ModelMetricsRegression) mm;
  }


  public static class MetricBuilderRegression extends MetricBuilderSupervised {
    double _sumdeviance;
    public MetricBuilderRegression() {
      super(1,null); //this will make _work = new float[2];
    }

    // ds[0] has the prediction and ds[1] is ignored
    @Override public double[] perRow(double ds[], float[] yact, Model m) {return perRow(ds, yact, 1, 0, m);}
    @Override public double[] perRow(double ds[], float[] yact, double w, double o,  Model m) {
      if( Float.isNaN(yact[0]) ) return ds; // No errors if   actual   is missing
      if(ArrayUtils.hasNaNs(ds)) return ds;  // No errors if prediction has missing values (can happen for GLM)
      if(w == 0 || Double.isNaN(w)) return ds;
      // Compute error
      double err = yact[0] - ds[0]; // Error: distance from the actual
      _sumsqe += w*err*err;       // Squared error
      assert !Double.isNaN(_sumsqe);
      if (m!=null) _sumdeviance += m.deviance(w, yact[0], ds[0]);
      _count++;
      _wcount += w;
      _wY += w*yact[0];
      _wYY += w*yact[0]*yact[0];
      return ds;                // Flow coding
    }

    public void reduce( MetricBuilderRegression mb ) {
      super.reduce(mb);
      _sumdeviance += mb._sumdeviance;
    }

    // Having computed a MetricBuilder, this method fills in a ModelMetrics
    public ModelMetrics makeModelMetrics( Model m, Frame f) {
      double mse = _sumsqe / _wcount;
      double meanResDeviance = _sumdeviance / _wcount; //mean residual deviance
      return m._output.addModelMetrics(new ModelMetricsRegression( m, f, mse, weightedSigma(), meanResDeviance));
    }

    public String toString() {return " mse = " + _sumsqe / _wcount;}
  }
}

@@ -1060,32 +1060,70 @@
 uilderRegression
+%3CT extends MetricBuilderRegression%3CT%3E%3E
  extends MetricB
@@ -1134,24 +1134,27 @@
 erSupervised
+%3CT%3E
  %7B%0A    doubl
@@ -2169,24 +2169,34 @@
 %0A    %7D%0A%0A    
+@Override 
 public void 
@@ -2203,39 +2203,17 @@
 reduce( 
-MetricBuilderRegression
+T
  mb ) %7B%0A

Fix ModelMetricsRegression - needs to have template parameter for reduce() to be @Override'able.