package water.rapids.ast.prims.reducers;
import water.MRTask;
import water.fvec.Chunk;
import water.rapids.Env;
import water.rapids.Val;
import water.rapids.vals.ValNum;
import water.rapids.ast.AstPrimitive;
import water.rapids.ast.AstRoot;
/**
* Subclasses take a Frame and produces a scalar. NAs -> NAs
*/
public abstract class AstReducerOp extends AstPrimitive {
@Override
public int nargs() {
return -1;
}
@Override
public Val apply(Env env, Env.StackHelp stk, AstRoot asts[]) {
// NOTE: no *initial* value needed for the reduction. Instead, the
// reduction op is used between pairs of actual values, and never against
// the empty list. NaN is returned if there are *no* values in the
// reduction.
double d = Double.NaN;
for (int i = 1; i < asts.length; i++) {
Val val = asts[i].exec(env);
double d2 = val.isFrame() ? new AstReducerOp.RedOp().doAll(stk.track(val).getFrame())._d : val.getNum();
if (i == 1) d = d2;
else d = op(d, d2);
}
return new ValNum(d);
}
/**
* Override to express a basic math primitive
*/
public abstract double op(double l, double r);
class RedOp extends MRTask<AstReducerOp.RedOp> {
double _d;
@Override
public void map(Chunk chks[]) {
int rows = chks[0]._len;
for (Chunk C : chks) {
if (!C.vec().isNumeric()) throw new IllegalArgumentException("Numeric columns only");
double sum = _d;
for (int r = 0; r < rows; r++)
sum = op(sum, C.atd(r));
_d = sum;
if (Double.isNaN(sum)) break; // Shortcut if the reduction is already NaN
}
}
@Override
public void reduce(AstReducerOp.RedOp s) {
_d = op(_d, s._d);
}
}
// class NaRmRedOp extends MRTask<NaRmRedOp> {
// double _d;
// @Override public void map( Chunk chks[] ) {
// int rows = chks[0]._len;
// for( Chunk C : chks ) {
// if( !C.vec().isNumeric() ) throw new IllegalArgumentException("Numeric columns only");
// double sum = _d;
// for( int r = 0; r < rows; r++ ) {
// double d = C.atd(r);
// if( !Double.isNaN(d) )
// sum = op(sum, d);
// }
// _d = sum;
// if( Double.isNaN(sum) ) break; // Shortcut if the reduction is already NaN
// }
// }
// @Override public void reduce( NaRmRedOp s ) { _d = op(_d, s._d); }
// }
}