package water.rapids.ast.prims.timeseries;
import water.MRTask;
import water.fvec.Chunk;
import water.fvec.Frame;
import water.fvec.NewChunk;
import water.fvec.Vec;
import water.rapids.Env;
import water.rapids.Val;
import water.rapids.vals.ValFrame;
import water.rapids.ast.AstPrimitive;
import water.rapids.ast.AstRoot;
import water.util.ArrayUtils;
/**
* Compute a difference of a time series where lag = 1
*/
public class AstDiffLag1 extends AstPrimitive {
@Override
public String[] args() {
return new String[]{"ary"};
}
@Override
public int nargs() {
return 1 + 1;
}
@Override
public String str() {
return "difflag1";
}
@Override
public ValFrame apply(Env env, Env.StackHelp stk, AstRoot asts[]) {
Frame fr = stk.track(asts[1].exec(env).getFrame());
if (fr.numCols() != 1)
throw new IllegalArgumentException("Expected a single column for diff. Got: " + fr.numCols() + " columns.");
if (!fr.anyVec().isNumeric())
throw new IllegalArgumentException("Expected a numeric column for diff. Got: " + fr.anyVec().get_type_str());
final double[] lastElemPerChk = GetLastElemPerChunkTask.get(fr.anyVec());
return new ValFrame(new MRTask() {
@Override
public void map(Chunk c, NewChunk nc) {
if (c.cidx() == 0) nc.addNA();
else nc.addNum(c.atd(0) - lastElemPerChk[c.cidx() - 1]);
for (int row = 1; row < c._len; ++row)
nc.addNum(c.atd(row) - c.atd(row - 1));
}
}.doAll(fr.types(), fr).outputFrame(fr.names(), fr.domains()));
}
private static class GetLastElemPerChunkTask extends MRTask<GetLastElemPerChunkTask> {
double[] _res;
GetLastElemPerChunkTask(Vec v) {
_res = new double[v.espc().length];
}
static double[] get(Vec v) {
GetLastElemPerChunkTask t = new GetLastElemPerChunkTask(v);
t.doAll(v);
return t._res;
}
@Override
public void map(Chunk c) {
_res[c.cidx()] = c.atd(c._len - 1);
}
@Override
public void reduce(GetLastElemPerChunkTask t) {
ArrayUtils.add(_res, t._res);
}
}
}