use of org.apache.sysml.runtime.instructions.cp.KahanObject in project incubator-systemml by apache.
the class LibMatrixAgg method aggregateTernaryGeneric.
private static void aggregateTernaryGeneric(MatrixBlock in1, MatrixBlock in2, MatrixBlock in3, MatrixBlock ret, IndexFunction ixFn, int rl, int ru) {
// compute block operations
KahanObject kbuff = new KahanObject(0, 0);
KahanPlus kplus = KahanPlus.getKahanPlusFnObject();
// guaranteed to have at least one sparse input, sort by nnz, assume num cells if
// (potentially incorrect) in dense representation, keep null at end via stable sort
MatrixBlock[] blocks = new MatrixBlock[] { in1, in2, in3 };
Arrays.sort(blocks, new Comparator<MatrixBlock>() {
@Override
public int compare(MatrixBlock o1, MatrixBlock o2) {
long nnz1 = (o1 != null && o1.sparse) ? o1.nonZeros : Long.MAX_VALUE;
long nnz2 = (o2 != null && o2.sparse) ? o2.nonZeros : Long.MAX_VALUE;
return Long.compare(nnz1, nnz2);
}
});
MatrixBlock lin1 = blocks[0];
MatrixBlock lin2 = blocks[1];
MatrixBlock lin3 = blocks[2];
SparseBlock a = lin1.sparseBlock;
final int n = in1.clen;
if (// tak+*
ixFn instanceof ReduceAll) {
for (int i = rl; i < ru; i++) if (!a.isEmpty(i)) {
int apos = a.pos(i);
int alen = a.size(i);
int[] aix = a.indexes(i);
double[] avals = a.values(i);
for (int j = apos; j < apos + alen; j++) {
double val1 = avals[j];
double val2 = lin2.quickGetValue(i, aix[j]);
double val = val1 * val2;
if (val != 0 && lin3 != null)
val *= lin3.quickGetValue(i, aix[j]);
kplus.execute2(kbuff, val);
}
}
ret.quickSetValue(0, 0, kbuff._sum);
ret.quickSetValue(0, 1, kbuff._correction);
} else // tack+*
{
double[] c = ret.getDenseBlockValues();
for (int i = rl; i < ru; i++) if (!a.isEmpty(i)) {
int apos = a.pos(i);
int alen = a.size(i);
int[] aix = a.indexes(i);
double[] avals = a.values(i);
for (int j = apos; j < apos + alen; j++) {
int colIx = aix[j];
double val1 = avals[j];
double val2 = lin2.quickGetValue(i, colIx);
double val = val1 * val2;
if (val != 0 && lin3 != null)
val *= lin3.quickGetValue(i, colIx);
kbuff._sum = c[colIx];
kbuff._correction = c[colIx + n];
kplus.execute2(kbuff, val);
c[colIx] = kbuff._sum;
c[colIx + n] = kbuff._correction;
}
}
}
}
use of org.apache.sysml.runtime.instructions.cp.KahanObject in project incubator-systemml by apache.
the class LibMatrixAgg method groupedAggregateKahanPlus.
/**
* This is a specific implementation for aggregate(fn="sum"), where we use KahanPlus for numerical
* stability. In contrast to other functions of aggregate, this implementation supports row and column
* vectors for target and exploits sparse representations since KahanPlus is sparse-safe.
*
* @param groups matrix block groups
* @param target matrix block target
* @param weights matrix block weights
* @param result matrix block result
* @param numGroups number of groups
* @param aggop aggregate operator
* @param cl column lower index
* @param cu column upper index
*/
private static void groupedAggregateKahanPlus(MatrixBlock groups, MatrixBlock target, MatrixBlock weights, MatrixBlock result, int numGroups, AggregateOperator aggop, int cl, int cu) {
boolean rowVector = (target.getNumRows() == 1 && target.getNumColumns() > 1);
// default weight
double w = 1;
// skip empty blocks (sparse-safe operation)
if (target.isEmptyBlock(false))
return;
// init group buffers
int numCols2 = cu - cl;
KahanObject[][] buffer = new KahanObject[numGroups][numCols2];
for (int i = 0; i < numGroups; i++) for (int j = 0; j < numCols2; j++) buffer[i][j] = new KahanObject(aggop.initialValue, 0);
if (// target is rowvector
rowVector) {
if (// SPARSE target
target.sparse) {
if (!target.sparseBlock.isEmpty(0)) {
int pos = target.sparseBlock.pos(0);
int len = target.sparseBlock.size(0);
int[] aix = target.sparseBlock.indexes(0);
double[] avals = target.sparseBlock.values(0);
for (// for each nnz
int j = pos; // for each nnz
j < pos + len; // for each nnz
j++) {
int g = (int) groups.quickGetValue(aix[j], 0);
if (g > numGroups)
continue;
if (weights != null)
w = weights.quickGetValue(aix[j], 0);
aggop.increOp.fn.execute(buffer[g - 1][0], avals[j] * w);
}
}
} else // DENSE target
{
double[] a = target.getDenseBlockValues();
for (int i = 0; i < target.getNumColumns(); i++) {
double d = a[i];
if (// sparse-safe
d != 0) {
int g = (int) groups.quickGetValue(i, 0);
if (g > numGroups)
continue;
if (weights != null)
w = weights.quickGetValue(i, 0);
// buffer is 0-indexed, whereas range of values for g = [1,numGroups]
aggop.increOp.fn.execute(buffer[g - 1][0], d * w);
}
}
}
} else // column vector or matrix
{
if (// SPARSE target
target.sparse) {
SparseBlock a = target.sparseBlock;
for (int i = 0; i < groups.getNumRows(); i++) {
int g = (int) groups.quickGetValue(i, 0);
if (g > numGroups)
continue;
if (!a.isEmpty(i)) {
int pos = a.pos(i);
int len = a.size(i);
int[] aix = a.indexes(i);
double[] avals = a.values(i);
int j = (cl == 0) ? 0 : a.posFIndexGTE(i, cl);
j = (j >= 0) ? pos + j : pos + len;
for (; // for each nnz
j < pos + len && aix[j] < cu; // for each nnz
j++) {
if (weights != null)
w = weights.quickGetValue(aix[j], 0);
aggop.increOp.fn.execute(buffer[g - 1][aix[j] - cl], avals[j] * w);
}
}
}
} else // DENSE target
{
DenseBlock a = target.getDenseBlock();
for (int i = 0; i < groups.getNumRows(); i++) {
int g = (int) groups.quickGetValue(i, 0);
if (g > numGroups)
continue;
double[] avals = a.values(i);
int aix = a.pos(i);
for (int j = cl; j < cu; j++) {
double d = avals[aix + j];
if (d != 0) {
// sparse-safe
if (weights != null)
w = weights.quickGetValue(i, 0);
// buffer is 0-indexed, whereas range of values for g = [1,numGroups]
aggop.increOp.fn.execute(buffer[g - 1][j - cl], d * w);
}
}
}
}
}
// extract the results from group buffers
for (int i = 0; i < numGroups; i++) for (int j = 0; j < numCols2; j++) result.appendValue(i, j + cl, buffer[i][j]._sum);
}
use of org.apache.sysml.runtime.instructions.cp.KahanObject in project incubator-systemml by apache.
the class LibMatrixAgg method aggregateBinaryMatrixLastColDenseGeneric.
private static void aggregateBinaryMatrixLastColDenseGeneric(MatrixBlock in, MatrixBlock aggVal) {
if (in.denseBlock == null || in.isEmptyBlock(false))
return;
final int m = in.rlen;
final int n = in.clen;
double[] a = in.getDenseBlockValues();
KahanObject buffer = new KahanObject(0, 0);
KahanPlus akplus = KahanPlus.getKahanPlusFnObject();
// incl implicit nnz maintenance
for (int i = 0, ix = 0; i < m; i++, ix += n) for (int j = 0; j < n - 1; j++) {
buffer._sum = aggVal.quickGetValue(i, j);
buffer._correction = aggVal.quickGetValue(i, n - 1);
akplus.execute(buffer, a[ix + j], a[ix + j + 1]);
aggVal.quickSetValue(i, j, buffer._sum);
aggVal.quickSetValue(i, n - 1, buffer._correction);
}
// note: nnz of aggVal maintained internally
aggVal.examSparsity();
}
use of org.apache.sysml.runtime.instructions.cp.KahanObject in project incubator-systemml by apache.
the class LibMatrixAgg method aggregateBinaryMatrixSparseDense.
private static void aggregateBinaryMatrixSparseDense(MatrixBlock in, MatrixBlock aggVal, MatrixBlock aggCorr) {
if (in.isEmptyBlock(false))
return;
// allocate output arrays (if required)
// should always stay in dense
aggVal.allocateDenseBlock();
// should always stay in dense
aggCorr.allocateDenseBlock();
SparseBlock a = in.getSparseBlock();
double[] c = aggVal.getDenseBlockValues();
double[] cc = aggCorr.getDenseBlockValues();
KahanObject buffer1 = new KahanObject(0, 0);
KahanPlus akplus = KahanPlus.getKahanPlusFnObject();
final int m = in.rlen;
final int n = in.clen;
final int rlen = Math.min(a.numRows(), m);
for (int i = 0, cix = 0; i < rlen; i++, cix += n) {
if (!a.isEmpty(i)) {
int apos = a.pos(i);
int alen = a.size(i);
int[] aix = a.indexes(i);
double[] avals = a.values(i);
for (int j = apos; j < apos + alen; j++) {
int ix = cix + aix[j];
buffer1._sum = c[ix];
buffer1._correction = cc[ix];
akplus.execute2(buffer1, avals[j]);
c[ix] = buffer1._sum;
cc[ix] = buffer1._correction;
}
}
}
aggVal.recomputeNonZeros();
aggCorr.recomputeNonZeros();
}
use of org.apache.sysml.runtime.instructions.cp.KahanObject in project incubator-systemml by apache.
the class KahanPlus method execute.
// in1, in2 is the sum, in3 is the correction
@Override
public Data execute(Data in1, double in2, double in3) {
KahanObject kahanObj = (KahanObject) in1;
// (computing corrections otherwise incorrectly computes NaN)
if (Double.isInfinite(kahanObj._sum) || Double.isInfinite(in2)) {
kahanObj.set(Double.isInfinite(in2) ? in2 : kahanObj._sum, 0);
return kahanObj;
}
// default path for any other value
double correction = in2 + (kahanObj._correction + in3);
double sum = kahanObj._sum + correction;
// prevent eager JIT opt
kahanObj.set(sum, correction - (sum - kahanObj._sum));
return kahanObj;
}
Aggregations