package water.rapids.ast.prims.math;
import water.H2O;
import water.MRTask;
import water.fvec.Chunk;
import water.fvec.Frame;
import water.fvec.NewChunk;
import water.fvec.Vec;
import water.rapids.Val;
import water.rapids.ast.AstBuiltin;
import water.rapids.vals.ValFrame;
import water.rapids.vals.ValNum;
import water.rapids.vals.ValRow;
/**
* Subclasses auto-widen between scalars and Frames, and have exactly one argument
*/
public abstract class AstUniOp<T extends AstUniOp<T>> extends AstBuiltin<T> {
@Override
public String[] args() {
return new String[]{"ary"};
}
@Override
public int nargs() {
return 1 + 1;
}
@Override
public Val exec(Val... args) {
Val val = args[1];
switch (val.type()) {
case Val.NUM:
return new ValNum(op(val.getNum()));
case Val.FRM:
Frame fr = val.getFrame();
for (int i = 0; i < fr.numCols(); i++)
if (!fr.vec(i).isNumeric())
throw new IllegalArgumentException(
"Operator " + str() + "() cannot be applied to non-numeric column " + fr.name(i));
// Get length of columns in fr and append `op(colName)`. For example, a column named "income" that had
// a log transformation would now be changed to `log(income)`.
String[] newNames = new String[fr.numCols()];
for (int i = 0; i < newNames.length; i++) {
newNames[i] = str() + "(" + fr.name(i) + ")";
}
return new ValFrame(new MRTask() {
@Override
public void map(Chunk cs[], NewChunk ncs[]) {
for (int col = 0; col < cs.length; col++) {
Chunk c = cs[col];
NewChunk nc = ncs[col];
for (int i = 0; i < c._len; i++)
nc.addNum(op(c.atd(i)));
}
}
}.doAll(fr.numCols(), Vec.T_NUM, fr).outputFrame(newNames, null));
case Val.ROW:
double[] ds = new double[val.getRow().length];
for (int i = 0; i < ds.length; ++i)
ds[i] = op(val.getRow()[i]);
String[] names = ((ValRow) val).getNames().clone();
return new ValRow(ds, names);
default:
throw H2O.unimpl("unop unimpl: " + val.getClass());
}
}
public abstract double op(double d);
}