1919
2020package org .apache .sysds .runtime .instructions .spark ;
2121
22-
2322import org .apache .spark .api .java .JavaPairRDD ;
2423import org .apache .spark .api .java .function .PairFunction ;
2524import org .apache .sysds .runtime .controlprogram .context .ExecutionContext ;
2625import org .apache .sysds .runtime .controlprogram .context .SparkExecutionContext ;
2726import org .apache .sysds .runtime .functionobjects .Builtin ;
28- import org .apache .sysds .runtime .functionobjects .KahanPlus ;
2927import org .apache .sysds .runtime .functionobjects .PlusMultiply ;
3028import org .apache .sysds .runtime .instructions .InstructionUtils ;
3129import org .apache .sysds .runtime .instructions .cp .CPOperand ;
32- import org .apache .sysds .runtime .instructions .cp .KahanObject ;
3330import org .apache .sysds .runtime .instructions .spark .utils .RDDAggregateUtils ;
3431import org .apache .sysds .runtime .instructions .spark .utils .SparkUtils ;
3532import 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