package hex;

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import water.TestUtil;
import water.fvec.Vec;
import water.util.Log;

import java.util.Random;

public class GainsLiftTest extends TestUtil {
  @BeforeClass public static void stall() { stall_till_cloudsize(1); }

  @Test public void good() {
    int len = 100000;
    double[] p = new double[len];
    long[] a = new long[len];
    Random rng = new Random(0xDECAF);
    for (int i=0; i<len; ++i) {
      a[i] = rng.nextDouble() > 0.8 ? 1 : 0;
      p[i] = a[i] == 0 ? 0.5*rng.nextDouble() : 0.5 + rng.nextDouble() * 0.5;
    }
    Vec actual = Vec.makeVec(a, new String[]{"N","Y"}, Vec.newKey());
    Vec predict = Vec.makeVec(p, Vec.newKey());

    GainsLift gl = new GainsLift(predict, actual);
    gl.exec();
    Log.info(gl);
    for (int i=0;i<2;++i)
      Assert.assertTrue(gl.response_rates[i] > 0.9);
    for (int i=2;i<gl.response_rates.length;++i)
      Assert.assertTrue(gl.response_rates[i] < 0.1);

    actual.remove();
    predict.remove();
  }

  @Test public void bad() {
    int len = 100000;
    double[] p = new double[len];
    long[] a = new long[len];
    Random rng = new Random(0xDECAF);
    for (int i=0; i<len; ++i) {
      a[i] = rng.nextDouble() > 0.8 ? 1 : 0;
      p[i] = a[i] == 0 ? 0.5 + 0.5*rng.nextDouble() : 0.5*rng.nextDouble();
    }
    Vec actual = Vec.makeVec(a, new String[]{"N","Y"}, Vec.newKey());
    Vec predict = Vec.makeVec(p, Vec.newKey());

    GainsLift gl = new GainsLift(predict, actual);
    gl.exec();
    Log.info(gl);
    for (int i=gl.response_rates.length-2;i<gl.response_rates.length;++i)
      Assert.assertTrue(gl.response_rates[i] > 0.9);
    for (int i=0;i<gl.response_rates.length-2;++i)
      Assert.assertTrue(gl.response_rates[i] < 0.1);

    actual.remove();
    predict.remove();
  }

  @Test public void random() {
    int len = 100000;
    double[] p = new double[len];
    long[] a = new long[len];
    Random rng = new Random(0xDECAF);
    for (int i=0; i<len; ++i) {
      a[i] = rng.nextDouble() > 0.8 ? 1 : 0;
      p[i] = rng.nextDouble();
    }
    Vec actual = Vec.makeVec(a, new String[]{"N","Y"}, Vec.newKey());
    Vec predict = Vec.makeVec(p, Vec.newKey());

    GainsLift gl = new GainsLift(predict, actual);
    gl.exec();
    Log.info(gl);
    for (int i=0;i<gl.response_rates.length;++i)
      Assert.assertTrue(gl.response_rates[i] > 0.19 && gl.response_rates[i] < 0.21);

    actual.remove();
    predict.remove();
  }
}

@@ -2443,24 +2443,854 @@
 %5D %3C 0.21);%0A%0A
+    actual.remove();%0A    predict.remove();%0A  %7D%0A%0A  @Test public void imbalanced() %7B%0A    int len = 50000;%0A    double thresh = 1e-7;%0A    double%5B%5D p = new double%5B2*len%5D;%0A    long%5B%5D a = new long%5B2*len%5D;%0A    Random rng = new Random(0xDECAF);%0A    int i;%0A    for (i=0; i%3Clen; ++i) %7B%0A      a%5Bi%5D = rng.nextDouble() %3E 0.8 ? 1 : 0;%0A      p%5Bi%5D = rng.nextDouble()*thresh;%0A    %7D%0A    for (i=len; i%3C2*len; ++i) %7B%0A      a%5Bi%5D = rng.nextDouble() %3E 0.8 ? 1 : 0;%0A      p%5Bi%5D = (1-thresh)+thresh*rng.nextDouble();%0A    %7D%0A    Vec actual = Vec.makeVec(a, new String%5B%5D%7B%22N%22,%22Y%22%7D, Vec.newKey());%0A    Vec predict = Vec.makeVec(p, Vec.newKey());%0A%0A    GainsLift gl = new GainsLift(predict, actual);%0A    gl.exec();%0A    Log.info(gl);%0A    for (i=0;i%3Cgl.response_rates.length;++i)%0A      Assert.assertTrue(gl.response_rates%5Bi%5D %3E 0.19 && gl.response_rates%5Bi%5D %3C 0.21);%0A%0A
     actual.r

Add another JUnit for gains/list for extremely imbalanced predictions. Requires the multi-pass quantiles (on by default for Gains/Lift).