Skip to content

Commit 092eede

Browse files
committed
Add large rowCumsum tests and update Spark cumulative instructions
1 parent 09e6fd0 commit 092eede

14 files changed

Lines changed: 661 additions & 214 deletions

src/main/java/org/apache/sysds/runtime/functionobjects/Builtin.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public enum BuiltinCode { AUTODIFF, SIN, COS, TAN, SINH, COSH, TANH, ASIN, ACOS,
9696
String2BuiltinCode.put( "floor" , BuiltinCode.FLOOR);
9797
String2BuiltinCode.put( "ucumk+" , BuiltinCode.CUMSUM);
9898
String2BuiltinCode.put( "urowcumk+" , BuiltinCode.ROWCUMSUM);
99+
String2BuiltinCode.put("rowCumsum", BuiltinCode.ROWCUMSUM);
99100
String2BuiltinCode.put( "ucum*" , BuiltinCode.CUMPROD);
100101
String2BuiltinCode.put( "ucumk+*", BuiltinCode.CUMSUMPROD);
101102
String2BuiltinCode.put( "ucummin", BuiltinCode.CUMMIN);

src/main/java/org/apache/sysds/runtime/instructions/spark/CumulativeAggregateSPInstruction.java

Lines changed: 91 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,14 @@
1919

2020
package org.apache.sysds.runtime.instructions.spark;
2121

22-
2322
import org.apache.spark.api.java.JavaPairRDD;
2423
import org.apache.spark.api.java.function.PairFunction;
2524
import org.apache.sysds.runtime.controlprogram.context.ExecutionContext;
2625
import org.apache.sysds.runtime.controlprogram.context.SparkExecutionContext;
2726
import org.apache.sysds.runtime.functionobjects.Builtin;
28-
import org.apache.sysds.runtime.functionobjects.KahanPlus;
2927
import org.apache.sysds.runtime.functionobjects.PlusMultiply;
3028
import org.apache.sysds.runtime.instructions.InstructionUtils;
3129
import org.apache.sysds.runtime.instructions.cp.CPOperand;
32-
import org.apache.sysds.runtime.instructions.cp.KahanObject;
3330
import org.apache.sysds.runtime.instructions.spark.utils.RDDAggregateUtils;
3431
import org.apache.sysds.runtime.instructions.spark.utils.SparkUtils;
3532
import org.apache.sysds.runtime.matrix.data.MatrixBlock;
@@ -47,42 +44,60 @@ private CumulativeAggregateSPInstruction(AggregateUnaryOperator op, CPOperand in
4744
super(SPType.CumsumAggregate, op, null, in1, out, null, opcode, istr);
4845
}
4946

50-
public static CumulativeAggregateSPInstruction parseInstruction( String str ) {
51-
String[] parts = InstructionUtils.getInstructionPartsWithValueType( str );
52-
InstructionUtils.checkNumFields ( parts, 2 );
47+
public static CumulativeAggregateSPInstruction parseInstruction(String str) {
48+
String[] parts = InstructionUtils.getInstructionPartsWithValueType(str);
49+
// parts: opcode, in, out => 3 fields
50+
InstructionUtils.checkNumFields(parts, 3);
51+
5352
String opcode = parts[0];
5453
CPOperand in1 = new CPOperand(parts[1]);
5554
CPOperand out = new CPOperand(parts[2]);
55+
5656
AggregateUnaryOperator aggun = InstructionUtils.parseCumulativeAggregateUnaryOperator(opcode);
5757
return new CumulativeAggregateSPInstruction(aggun, in1, out, opcode, str);
5858
}
5959

6060
@Override
6161
public void processInstruction(ExecutionContext ec) {
62-
SparkExecutionContext sec = (SparkExecutionContext)ec;
62+
SparkExecutionContext sec = (SparkExecutionContext) ec;
6363
DataCharacteristics mc = sec.getDataCharacteristics(input1.getName());
6464

65-
//get input
66-
JavaPairRDD<MatrixIndexes,MatrixBlock> in = sec.getBinaryMatrixBlockRDDHandleForVariable( input1.getName() );
65+
// get input
66+
JavaPairRDD<MatrixIndexes, MatrixBlock> in =
67+
sec.getBinaryMatrixBlockRDDHandleForVariable(input1.getName());
6768

6869
if ("urowcumk+".equals(getOpcode())) {
69-
processRowCumsum(sec, in, mc);
70-
} else {
70+
// rowcumsum: aggregate phase should output carry/end-values per block
71+
processRowCumsumAggregate(sec, in, mc);
72+
}
73+
else {
74+
// regular cumsum aggregate phase
7175
processCumsum(sec, in, mc);
7276
}
7377
}
7478

75-
private void processRowCumsum(SparkExecutionContext sec, JavaPairRDD<MatrixIndexes,MatrixBlock> in, DataCharacteristics mc) {
76-
JavaPairRDD<MatrixIndexes, MatrixBlock> localRowCumsum =
77-
in.mapToPair(new LocalRowCumsumFunction());
79+
private void processRowCumsumAggregate(SparkExecutionContext sec, JavaPairRDD<MatrixIndexes, MatrixBlock> in, DataCharacteristics mc) {
80+
Tuple2<JavaPairRDD<MatrixIndexes, MatrixBlock>, JavaPairRDD<MatrixIndexes, MatrixBlock>> res =
81+
processRowCumsumWithEndValues(in);
7882

79-
sec.setRDDHandleForVariable(output.getName(), localRowCumsum);
83+
JavaPairRDD<MatrixIndexes, MatrixBlock> endValues = res._2;
84+
85+
sec.setRDDHandleForVariable(output.getName(), endValues);
8086
sec.addLineageRDD(output.getName(), input1.getName());
81-
sec.getDataCharacteristics(output.getName()).set(mc);
87+
88+
// output characteristics: same rows as input, but 1 column (per-row carry)
89+
MatrixCharacteristics mcOut = new MatrixCharacteristics(mc);
90+
mcOut.setCols(1);
91+
sec.getDataCharacteristics(output.getName()).set(mcOut);
8292
}
8393

94+
/**
95+
* Helper for rowcumsum:
96+
* returns (localRowCumsumBlocks, endValuesBlocks).
97+
*/
8498
public static Tuple2<JavaPairRDD<MatrixIndexes, MatrixBlock>, JavaPairRDD<MatrixIndexes, MatrixBlock>>
85-
processRowCumsumWithEndValues(JavaPairRDD<MatrixIndexes,MatrixBlock> in) {
99+
processRowCumsumWithEndValues(JavaPairRDD<MatrixIndexes, MatrixBlock> in) {
100+
86101
JavaPairRDD<MatrixIndexes, MatrixBlock> localRowCumsum =
87102
in.mapToPair(new LocalRowCumsumFunction());
88103

@@ -92,128 +107,136 @@ private void processRowCumsum(SparkExecutionContext sec, JavaPairRDD<MatrixIndex
92107
return new Tuple2<>(localRowCumsum, endValues);
93108
}
94109

95-
private void processCumsum(SparkExecutionContext sec, JavaPairRDD<MatrixIndexes,MatrixBlock> in, DataCharacteristics mc) {
110+
/**
111+
* Original cumsum aggregate phase (keep intact).
112+
*/
113+
private void processCumsum(SparkExecutionContext sec, JavaPairRDD<MatrixIndexes, MatrixBlock> in, DataCharacteristics mc) {
96114
DataCharacteristics mcOut = new MatrixCharacteristics(mc);
97115
long rlen = mc.getRows();
98116
int blen = mc.getBlocksize();
99-
mcOut.setRows((long)(Math.ceil((double)rlen/blen)));
117+
mcOut.setRows((long) (Math.ceil((double) rlen / blen)));
100118

101-
//execute unary aggregate (w/ implicit drop correction)
119+
// execute unary aggregate (w/ implicit drop correction)
102120
AggregateUnaryOperator auop = (AggregateUnaryOperator) _optr;
103-
JavaPairRDD<MatrixIndexes,MatrixBlock> out =
121+
JavaPairRDD<MatrixIndexes, MatrixBlock> out =
104122
in.mapToPair(new RDDCumAggFunction(auop, rlen, blen));
105-
//merge partial aggregates, adjusting for correct number of partitions
106-
//as size can significant shrink (1K) but also grow (sparse-dense)
123+
124+
// merge partial aggregates, adjusting for correct number of partitions
107125
int numParts = SparkUtils.getNumPreferredPartitions(mcOut);
108-
int minPar = (int)Math.min(SparkExecutionContext.getDefaultParallelism(true), mcOut.getNumBlocks());
126+
int minPar = (int) Math.min(SparkExecutionContext.getDefaultParallelism(true), mcOut.getNumBlocks());
109127
out = RDDAggregateUtils.mergeByKey(out, Math.max(numParts, minPar), false);
110128

111-
//put output handle in symbol table
129+
// put output handle in symbol table
112130
sec.setRDDHandleForVariable(output.getName(), out);
113131
sec.addLineageRDD(output.getName(), input1.getName());
114132
sec.getDataCharacteristics(output.getName()).set(mcOut);
115133
}
116134

117-
private static class LocalRowCumsumFunction implements PairFunction<Tuple2<MatrixIndexes, MatrixBlock>, MatrixIndexes, MatrixBlock> {
135+
136+
private static class LocalRowCumsumFunction
137+
implements PairFunction<Tuple2<MatrixIndexes, MatrixBlock>, MatrixIndexes, MatrixBlock> {
138+
118139
private static final long serialVersionUID = 123L;
119140

141+
private static final UnaryOperator ROWCUMSUM_OP =
142+
new UnaryOperator(Builtin.getBuiltinFnObject("urowcumk+"));
143+
120144
@Override
121-
public Tuple2<MatrixIndexes, MatrixBlock> call(Tuple2<MatrixIndexes, MatrixBlock> kv) throws Exception {
145+
public Tuple2<MatrixIndexes, MatrixBlock> call(Tuple2<MatrixIndexes, MatrixBlock> kv) {
122146
MatrixIndexes idx = kv._1;
123147
MatrixBlock inputBlock = kv._2;
124-
MatrixBlock outBlock = new MatrixBlock(inputBlock.getNumRows(), inputBlock.getNumColumns(), false);
125-
126-
for (int i = 0; i < inputBlock.getNumRows(); i++) {
127-
KahanObject kbuff = new KahanObject(0, 0);
128-
KahanPlus kplus = KahanPlus.getKahanPlusFnObject();
129148

130-
for (int j = 0; j < inputBlock.getNumColumns(); j++) {
131-
double val = inputBlock.get(i, j);
132-
kplus.execute2(kbuff, val);
133-
outBlock.set(i, j, kbuff._sum);
134-
}
135-
}
136-
// original index, original matrix and local cumsum block
149+
MatrixBlock outBlock = inputBlock.unaryOperations(ROWCUMSUM_OP, new MatrixBlock());
137150
return new Tuple2<>(idx, outBlock);
138151
}
139152
}
140153

141-
private static class ExtractEndValuesFunction implements PairFunction<Tuple2<MatrixIndexes, MatrixBlock>, MatrixIndexes, MatrixBlock> {
154+
155+
private static class ExtractEndValuesFunction
156+
implements PairFunction<Tuple2<MatrixIndexes, MatrixBlock>, MatrixIndexes, MatrixBlock> {
157+
142158
private static final long serialVersionUID = 123L;
143159

144160
@Override
145-
public Tuple2<MatrixIndexes, MatrixBlock> call(Tuple2<MatrixIndexes, MatrixBlock> kv) throws Exception {
161+
public Tuple2<MatrixIndexes, MatrixBlock> call(Tuple2<MatrixIndexes, MatrixBlock> kv) {
146162
MatrixIndexes idx = kv._1;
147163
MatrixBlock cumsumBlock = kv._2;
148164

149-
MatrixBlock endValuesBlock = new MatrixBlock(cumsumBlock.getNumRows(), 1, false);
150-
for (int i = 0; i < cumsumBlock.getNumRows(); i++) {
151-
if (cumsumBlock.getNumColumns() > 0) {
152-
endValuesBlock.set(i, 0, cumsumBlock.get(i, cumsumBlock.getNumColumns() - 1));
153-
} else {
165+
int r = cumsumBlock.getNumRows();
166+
int c = cumsumBlock.getNumColumns();
167+
MatrixBlock endValuesBlock = new MatrixBlock(r, 1, false);
168+
169+
if (c > 0) {
170+
int lastCol = c - 1;
171+
for (int i = 0; i < r; i++) {
172+
endValuesBlock.set(i, 0, cumsumBlock.get(i, lastCol));
173+
}
174+
}
175+
else {
176+
// degenerate case: empty block
177+
for (int i = 0; i < r; i++) {
154178
endValuesBlock.set(i, 0, 0.0);
155179
}
156180
}
181+
157182
return new Tuple2<>(idx, endValuesBlock);
158183
}
159184
}
160185

161-
private static class RDDCumAggFunction implements PairFunction<Tuple2<MatrixIndexes, MatrixBlock>, MatrixIndexes, MatrixBlock>
162-
{
186+
private static class RDDCumAggFunction
187+
implements PairFunction<Tuple2<MatrixIndexes, MatrixBlock>, MatrixIndexes, MatrixBlock> {
188+
163189
private static final long serialVersionUID = 11324676268945117L;
164190

165191
private final AggregateUnaryOperator _op;
166192
private UnaryOperator _uop = null;
167193
private final long _rlen;
168194
private final int _blen;
169195

170-
public RDDCumAggFunction( AggregateUnaryOperator op, long rlen, int blen ) {
196+
public RDDCumAggFunction(AggregateUnaryOperator op, long rlen, int blen) {
171197
_op = op;
172198
_rlen = rlen;
173199
_blen = blen;
174200
}
175201

176202
@Override
177-
public Tuple2<MatrixIndexes, MatrixBlock> call( Tuple2<MatrixIndexes, MatrixBlock> arg0 )
178-
throws Exception
179-
{
203+
public Tuple2<MatrixIndexes, MatrixBlock> call(Tuple2<MatrixIndexes, MatrixBlock> arg0) throws Exception {
180204
MatrixIndexes ixIn = arg0._1();
181205
MatrixBlock blkIn = arg0._2();
182206

183207
MatrixIndexes ixOut = new MatrixIndexes();
184208
MatrixBlock blkOut = new MatrixBlock();
185209

186-
//process instruction
210+
// process instruction
187211
AggregateUnaryOperator aop = _op;
188-
if( aop.aggOp.increOp.fn instanceof PlusMultiply ) { //cumsumprod
212+
if (aop.aggOp.increOp.fn instanceof PlusMultiply) { // cumsumprod
189213
aop.indexFn.execute(ixIn, ixOut);
190-
if( _uop == null )
214+
if (_uop == null)
191215
_uop = new UnaryOperator(Builtin.getBuiltinFnObject("ucumk+*"));
192216
MatrixBlock t1 = blkIn.unaryOperations(_uop, new MatrixBlock());
193-
MatrixBlock t2 = blkIn.slice(0, blkIn.getNumRows()-1, 1, 1, new MatrixBlock());
217+
MatrixBlock t2 = blkIn.slice(0, blkIn.getNumRows() - 1, 1, 1, new MatrixBlock());
194218
blkOut.reset(1, 2);
195-
blkOut.set(0, 0, t1.get(t1.getNumRows()-1, 0));
219+
blkOut.set(0, 0, t1.get(t1.getNumRows() - 1, 0));
196220
blkOut.set(0, 1, t2.prod());
197221
}
198-
else { //general case
199-
OperationsOnMatrixValues.performAggregateUnary( ixIn, blkIn, ixOut, blkOut, aop, _blen);
200-
if( aop.aggOp.existsCorrection() )
222+
else { // general case
223+
OperationsOnMatrixValues.performAggregateUnary(ixIn, blkIn, ixOut, blkOut, aop, _blen);
224+
if (aop.aggOp.existsCorrection())
201225
blkOut.dropLastRowsOrColumns(aop.aggOp.correction);
202226
}
203227

204-
//cumsum expand partial aggregates
205-
long rlenOut = (long)Math.ceil((double)_rlen/_blen);
206-
long rixOut = (long)Math.ceil((double)ixIn.getRowIndex()/_blen);
207-
int rlenBlk = (int) Math.min(rlenOut-(rixOut-1)*_blen, _blen);
228+
// cumsum expand partial aggregates
229+
long rlenOut = (long) Math.ceil((double) _rlen / _blen);
230+
long rixOut = (long) Math.ceil((double) ixIn.getRowIndex() / _blen);
231+
int rlenBlk = (int) Math.min(rlenOut - (rixOut - 1) * _blen, _blen);
208232
int clenBlk = blkOut.getNumColumns();
209-
int posBlk = (int) ((ixIn.getRowIndex()-1) % _blen);
233+
int posBlk = (int) ((ixIn.getRowIndex() - 1) % _blen);
210234

211-
//construct sparse output blocks (single row in target block size)
235+
// construct sparse output blocks (single row in target block size)
212236
MatrixBlock blkOut2 = new MatrixBlock(rlenBlk, clenBlk, true);
213-
blkOut2.copy(posBlk, posBlk, 0, clenBlk-1, blkOut, true);
237+
blkOut2.copy(posBlk, posBlk, 0, clenBlk - 1, blkOut, true);
214238
ixOut.setIndexes(rixOut, ixOut.getColumnIndex());
215239

216-
//output new tuple
217240
return new Tuple2<>(ixOut, blkOut2);
218241
}
219242
}

0 commit comments

Comments
 (0)