package water.fvec;
import org.junit.Test;
import water.Futures;
import water.Key;
import water.TestUtil;
import water.UKV;
import java.util.Iterator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Created by tomasnykodym on 3/28/14.
*/
public class SparseTest extends TestUtil {
protected Chunk makeChunk(double [] vals){
int nzs = 0;
int [] nonzeros = new int[vals.length];
int j = 0;
for(double d:vals)if(d != 0)nonzeros[nzs++] = j++;
Key key = Vec.newKey();
AppendableVec av = new AppendableVec(key);
NewChunk nv = new NewChunk(av,0);
for(double d:vals){
if(Double.isNaN(d))nv.addNA();
else if((long)d == d) nv.addNum((long)d,0);
else nv.addNum(d);
}
nv.close(0,null);
Futures fs = new Futures();
Vec vec = av.close(fs);
fs.blockForPending();
return vec.chunkForChunkIdx(0);
}
protected Chunk setAndClose(double val, int id, Chunk c){return setAndClose(new double[]{val},new int[]{id},c);}
protected Chunk setAndClose(double [] vals, int [] ids, Chunk c){
final int cidx = c.cidx();
final Vec vec = c._vec;
for(int i = 0; i < vals.length; ++i)
c.set0(ids[i],vals[i]);
Futures fs = new Futures();
c.close(cidx,fs);
return vec.chunkForChunkIdx(cidx);
}
public void runTest(double [] vs, double v1, double v2, Class class0, Class class1, Class class2){
int nzeros = 3;
int length = 4*NewChunk.MIN_SPARSE_RATIO + 1;
double [] vals = new double[length];
int [] nzs = new int[]{length/4,length/2,(3*length)/4};
// test sparse double
vals[nzs[0]] = vs[0];
vals[nzs[1]] = vs[1];
vals[nzs[2]] = vs[2];
Chunk c0 = makeChunk(vals);
assertTrue(class0.isAssignableFrom(c0.getClass()));
try{
assertTrue(class0.isAssignableFrom(c0.getClass()));
assertEquals(3,c0.sparseLen());
for(int i = 0; i < vals.length; ++i){
assertEquals(Double.isNaN(vals[i]), c0.isNA0(i));
assertTrue(Double.isNaN(vals[i]) || vals[i] == c0.at0(i));
}
int j = c0.nextNZ(-1);
// test skip cnt iteration
for(int nz:nzs){
assertEquals(nz,j);
assertEquals(Double.isNaN(vals[nz]),c0.isNA0(j));
assertTrue(Double.isNaN(vals[nz]) || vals[nz] == c0.at0(j));
j = c0.nextNZ(j);
}
Iterator<CXIChunk.Value> it = ((CXIChunk)c0).values();
// test iterator
for(int nz:nzs){
CXIChunk.Value v = it.next();
assertEquals(nz,v.rowInChunk());
assertEquals(Double.isNaN(vals[nz]), v.isNA());
assertTrue(Double.isNaN(vals[nz]) || vals[nz] == v.asDouble());
}
Chunk c1 = setAndClose(vals[length-1] = v1,length-1,c0);
assertTrue(class1.isAssignableFrom(c1.getClass()));
// test sparse set
assertEquals(4,c1.sparseLen());
assertEquals(Double.isNaN(v1),c1.isNA0(length-1));
assertTrue(Double.isNaN(v1) || v1 == c1.at0(length-1));
Chunk c2 = setAndClose(vals[0] = v2,0,c1);
assertTrue(class2.isAssignableFrom(c2.getClass()));
assertTrue(c2.nextNZ(-1) == 0);
assertEquals(vals.length,c2.sparseLen());
for(int i = 0; i < vals.length; ++i){
assertEquals(Double.isNaN(vals[i]),c2.isNA0(i));
assertTrue(Double.isNaN(vals[i]) || vals[i] == c2.at0(i));
assertTrue(c2.nextNZ(i) == i+1);
}
}finally{
UKV.remove(c0._vec._key);
}
}
@Test
public void testDouble() {runTest(new double [] {2.7182,3.14,42},Double.NaN,123.45,CXDChunk.class,CXDChunk.class,C8DChunk.class);}
@Test
public void testBinary() {
runTest(new double [] {1,1,1},1,1,CX0Chunk.class,CX0Chunk.class,CBSChunk.class);
runTest(new double [] {1,1,1},Double.NaN,1,CX0Chunk.class,CXIChunk.class,CBSChunk.class);
}
@Test public void testInt() {
runTest(new double [] {1,2,Double.NaN},4,5,CXIChunk.class,CXIChunk.class,C1Chunk.class);
runTest(new double [] {1,2000,Double.NaN,3},4,5,CXIChunk.class,CXIChunk.class,C2Chunk.class);
runTest(new double [] {Double.NaN,2000,3},400000,5,CXIChunk.class,CXIChunk.class,C4Chunk.class);
runTest(new double [] {1,Double.NaN,2000,3},Double.NaN,1e10,CXIChunk.class,CXIChunk.class,C8Chunk.class);
}
}