This is an automated email from the ASF dual-hosted git repository.
baunsgaard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/systemds.git
The following commit(s) were added to refs/heads/main by this push:
new dd7bfe6cb1 [SYSTEMDS-3718] Improve reshaping of Sparse MatrixBlock
dd7bfe6cb1 is described below
commit dd7bfe6cb1a025a2903994e43066632a3eb37d44
Author: Sebastian Baunsgaard <[email protected]>
AuthorDate: Wed Aug 14 12:11:44 2024 +0200
[SYSTEMDS-3718] Improve reshaping of Sparse MatrixBlock
This commit adds minor refinements to some of the reshaping instructions
Mainly for the MCSR to MCSR case where for instance
1/3 on 10k by 10k matrices of 0.1 sparsity improve by 1/3.
While CSR to CSR improve by 5-15%.
See the PR for performance details
Closes #2064
---
.../instructions/cp/ReshapeCPInstruction.java | 2 +-
.../sysds/runtime/matrix/data/LibMatrixReorg.java | 441 +++++++++++++------
.../java/org/apache/sysds/performance/Main.java | 4 +
.../java/org/apache/sysds/performance/README.md | 6 +
.../sysds/performance/matrix/ReshapePerf.java | 86 ++++
src/test/java/org/apache/sysds/test/TestUtils.java | 21 +-
.../matrix/libMatrixReorg/ReshapeTest.java | 476 +++++++++++++++++++++
.../{ => libMatrixReorg}/TransposeCSRTest.java | 2 +-
.../{ => libMatrixReorg}/TransposeInplaceTest.java | 2 +-
.../{ => libMatrixReorg}/TransposeTwiceTest.java | 2 +-
10 files changed, 882 insertions(+), 160 deletions(-)
diff --git
a/src/main/java/org/apache/sysds/runtime/instructions/cp/ReshapeCPInstruction.java
b/src/main/java/org/apache/sysds/runtime/instructions/cp/ReshapeCPInstruction.java
index 9cf30acb37..96fcc20a3f 100644
---
a/src/main/java/org/apache/sysds/runtime/instructions/cp/ReshapeCPInstruction.java
+++
b/src/main/java/org/apache/sysds/runtime/instructions/cp/ReshapeCPInstruction.java
@@ -100,7 +100,7 @@ public class ReshapeCPInstruction extends
UnaryCPInstruction {
//execute operations
MatrixBlock out = new MatrixBlock();
- LibMatrixReorg.reshape(in, out, rows, cols,
byRow.getBooleanValue());
+ LibMatrixReorg.reshape(in, out, rows, cols,
byRow.getBooleanValue(), -1);
//set output and release inputs
ec.releaseMatrixInput(input1.getName());
diff --git
a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixReorg.java
b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixReorg.java
index 1ebd73da4d..17a3ae1a4f 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixReorg.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixReorg.java
@@ -41,6 +41,7 @@ import org.apache.sysds.runtime.DMLRuntimeException;
import org.apache.sysds.runtime.compress.CompressedMatrixBlock;
import org.apache.sysds.runtime.compress.DMLCompressionException;
import org.apache.sysds.runtime.controlprogram.caching.MatrixObject.UpdateType;
+import
org.apache.sysds.runtime.controlprogram.parfor.stat.InfrastructureAnalyzer;
import org.apache.sysds.runtime.data.DenseBlock;
import org.apache.sysds.runtime.data.DenseBlockFactory;
import org.apache.sysds.runtime.data.SparseBlock;
@@ -282,16 +283,23 @@ public class LibMatrixReorg {
for(int i = 0; i < k & i * blklen < len; i++)
tasks.add(new TransposeTask(in, out, row, i *
blklen, Math.min((i + 1) * blklen, len), cnt, allowReturnBlock));
- List<MatrixBlock> blocks = allowReturnBlock ? new
ArrayList<>(): null;
- // List<Future<Object>> taskret =
pool.invokeAll(tasks);
- for(Future<MatrixBlock> task : pool.invokeAll(tasks)){
- MatrixBlock m = task.get();
- if(allowReturnBlock && m != null)
- blocks.add(m);
- }
+
+ if(allowReturnBlock) {
+ List<MatrixBlock> blocks = new ArrayList<>();
+ for(Future<MatrixBlock> task :
pool.invokeAll(tasks)) {
+ MatrixBlock m = task.get();
+ if(allowReturnBlock && m != null)
+ blocks.add(m);
+ }
- if(allowReturnBlock)
- combine(blocks, out, row, k);
+ if(allowReturnBlock)
+ combine(blocks, out, row, k);
+ }
+ else {
+ for(Future<MatrixBlock> task :
pool.invokeAll(tasks)) {
+ task.get();
+ }
+ }
}
catch(Exception ex) {
throw new DMLRuntimeException(ex);
@@ -548,13 +556,22 @@ public class LibMatrixReorg {
if( !ixret ) {
out.allocateBlock();
//copy input data in sorted order into result
- ExecutorService pool = CommonThreadPool.get(k);
- ArrayList<CopyTask> tasks = new ArrayList<>();
- ArrayList<Integer> blklen = UtilFunctions
+ if(k > 1){
+
+ ExecutorService pool = CommonThreadPool.get(k);
+ ArrayList<CopyTask> tasks = new ArrayList<>();
+ ArrayList<Integer> blklen = UtilFunctions
+ .getBalancedBlockSizesDefault(rlen, k,
false);
+ for( int i=0, lb=0; i<blklen.size();
lb+=blklen.get(i), i++ )
+ tasks.add( new CopyTask(in, out, vix,
lb, lb+blklen.get(i)));
+ CommonThreadPool.invokeAndShutdown(pool, tasks);
+ }
+ else{
+ ArrayList<Integer> blklen = UtilFunctions
.getBalancedBlockSizesDefault(rlen, k, false);
- for( int i=0, lb=0; i<blklen.size(); lb+=blklen.get(i),
i++ )
- tasks.add( new CopyTask(in, out, vix, lb,
lb+blklen.get(i)));
- CommonThreadPool.invokeAndShutdown(pool, tasks);
+ for( int i=0, lb=0; i<blklen.size();
lb+=blklen.get(i), i++ )
+ new CopyTask(in, out, vix, lb,
lb+blklen.get(i)).call();
+ }
}
else {
//copy sorted index vector into result
@@ -568,57 +585,101 @@ public class LibMatrixReorg {
}
/**
- * CP reshape operation (single input, single output matrix)
+ * CP reshape operation (single input, single output matrix)
*
- * NOTE: In contrast to R, the rowwise parameter specifies both
- * the read and write order, with row-wise being the default, while
- * R uses always a column-wise read, rowwise specifying the write
- * order and column-wise being the default.
+ * NOTE: In contrast to R, the rowwise parameter specifies both the
read and write order, with row-wise being the
+ * default, while R uses always a column-wise read, rowwise specifying
the write order and column-wise being the
+ * default.
*
- * @param in input matrix
- * @param out output matrix
- * @param rows number of rows
- * @param cols number of columns
+ * @param in input matrix
+ * @param rows number of rows
+ * @param cols number of columns
* @param rowwise if true, reshape by row
* @return output matrix
*/
- public static MatrixBlock reshape( MatrixBlock in, MatrixBlock out, int
rows, int cols, boolean rowwise ) {
- int rlen = in.rlen;
- int clen = in.clen;
-
- //check validity
- if( ((long)rlen)*clen != ((long)rows)*cols )
- throw new DMLRuntimeException("Reshape matrix requires
consistent numbers of input/output cells ("+rlen+":"+clen+",
"+rows+":"+cols+").");
+ public static MatrixBlock reshape(MatrixBlock in, int rows, int cols,
boolean rowwise) {
+ return reshape(in, null, rows,cols, rowwise, 1);
+ }
+
+ /**
+ * CP reshape operation (single input, single output matrix)
+ *
+ * NOTE: In contrast to R, the rowwise parameter specifies both the
read and write order, with row-wise being the
+ * default, while R uses always a column-wise read, rowwise specifying
the write order and column-wise being the
+ * default.
+ *
+ * @param in input matrix
+ * @param out output matrix
+ * @param rows number of rows
+ * @param cols number of columns
+ * @param rowwise if true, reshape by row
+ * @return output matrix
+ */
+ public static MatrixBlock reshape(MatrixBlock in, MatrixBlock out, int
rows, int cols, boolean rowwise) {
+ return reshape(in, out, rows,cols, rowwise, 1);
+ }
+
+ /**
+ * CP reshape operation (single input, single output matrix)
+ *
+ * NOTE: In contrast to R, the rowwise parameter specifies both the
read and write order, with row-wise being the
+ * default, while R uses always a column-wise read, rowwise specifying
the write order and column-wise being the
+ * default.
+ *
+ * @param in input matrix
+ * @param out output matrix
+ * @param rows number of rows
+ * @param cols number of columns
+ * @param rowwise if true, reshape by row
+ * @param k The parallelization degree
+ * @return output matrix
+ */
+ public static MatrixBlock reshape(MatrixBlock in, MatrixBlock out, int
rows, int cols, boolean rowwise, int k) {
+ try{
+ final int rlen = in.rlen;
+ final int clen = in.clen;
+
+ if(out == null)
+ out = new MatrixBlock();
+
+ //check for same dimensions
+ if(rlen == rows && clen == cols) {
+ // copy incl dims, nnz
+ if(SHALLOW_COPY_REORG)
+ out.copyShallow(in);
+ else
+ out.copy(in);
+ return out;
+ }
+
+ //check validity
+ if(((long) rlen) * clen != ((long) rows) * cols)
+ throw new DMLRuntimeException("Reshape matrix
requires consistent numbers of input/output cells (" + rlen + ":"
+ + clen + ", " + rows + ":" + cols +
").");
- //check for same dimensions
- if( rlen==rows && clen == cols ) {
- //copy incl dims, nnz
- if( SHALLOW_COPY_REORG )
- out.copyShallow(in);
+ //determine output representation
+ out.sparse = MatrixBlock.evalSparseFormatInMemory(rows,
cols, in.nonZeros);
+
+ //set output dimensions
+ out.rlen = rows;
+ out.clen = cols;
+ out.nonZeros = in.nonZeros;
+
+ //core reshape (sparse or dense)
+ if(!in.sparse && !out.sparse)
+ reshapeDense(in, out, rows, cols, rowwise);
+ else if(in.sparse && out.sparse)
+ reshapeSparse(in, out, rows, cols, rowwise, k);
+ else if(in.sparse)
+ reshapeSparseToDense(in, out, rows, cols,
rowwise);
else
- out.copy(in);
+ reshapeDenseToSparse(in, out, rows, cols,
rowwise);
+
return out;
}
-
- //determine output representation
- out.sparse = MatrixBlock.evalSparseFormatInMemory(rows, cols,
in.nonZeros);
-
- //set output dimensions
- out.rlen = rows;
- out.clen = cols;
- out.nonZeros = in.nonZeros;
-
- //core reshape (sparse or dense)
- if(!in.sparse && !out.sparse)
- reshapeDense(in, out, rows, cols, rowwise);
- else if(in.sparse && out.sparse)
- reshapeSparse(in, out, rows, cols, rowwise);
- else if(in.sparse)
- reshapeSparseToDense(in, out, rows, cols, rowwise);
- else
- reshapeDenseToSparse(in, out, rows, cols, rowwise);
-
- return out;
+ catch(Exception e) {
+ throw new RuntimeException("Failed to reshape Matrix",
e);
+ }
}
@@ -2277,7 +2338,7 @@ public class LibMatrixReorg {
//reshape empty block
if( in.denseBlock == null )
return;
-
+
//shallow dense by-row reshape (w/o result allocation)
if( SHALLOW_COPY_REORG && rowwise &&
in.denseBlock.numBlocks()==1 ) {
//since the physical representation of dense matrices
is always the same,
@@ -2336,8 +2397,8 @@ public class LibMatrixReorg {
}
}
- private static void reshapeSparse( MatrixBlock in, MatrixBlock out, int
rows, int cols, boolean rowwise )
- {
+ private static void reshapeSparse(MatrixBlock in, MatrixBlock out, int
rows, int cols, boolean rowwise, int k)
+ throws Exception {
int rlen = in.rlen;
int clen = in.clen;
@@ -2373,89 +2434,12 @@ public class LibMatrixReorg {
c.append(0, cix+aix[j],
avals[j]);
}
}
- else if( cols%clen==0 //SPECIAL CSR N:1 MATRIX->MATRIX
- && SHALLOW_COPY_REORG && SPARSE_OUTPUTS_IN_CSR
- && in.nonZeros < Integer.MAX_VALUE ) { //int nnz
- int n = cols/clen, pos = 0;
- int[] rptr = new int[rows+1];
- int[] indexes = new int[(int)a.size()];
- double[] values = null;
- rptr[0] = 0;
-
- if(a instanceof SparseBlockCSR) {
- int[] aix =
((SparseBlockCSR)a).indexes();
- for(int bi=0, ci=0; bi<rlen; bi+=n,
ci++) {
- for( int i=bi, cix=0; i<bi+n;
i++, cix+=clen ) {
- if(a.isEmpty(i))
continue;
- int apos = a.pos(i);
- int alen = a.size(i);
- for( int j=apos;
j<apos+alen; j++ )
- indexes[pos++]
= cix+aix[j];
- }
- rptr[ci+1] = pos;
- }
- //shallow copy of CSR values
- values = ((SparseBlockCSR)a).values();
- }
- else {
- values = new double[indexes.length];
- for(int bi=0, ci=0; bi<rlen; bi+=n,
ci++) { //output rows
- for( int i=bi, cix=0; i<bi+n;
i++, cix+=clen ) { // N input rows
- if(a.isEmpty(i))
continue;
- int apos = a.pos(i);
- int alen = a.size(i);
- int[] aix =
a.indexes(i);
-
System.arraycopy(a.values(i), apos, values, pos, alen);
- for( int j=apos;
j<apos+alen; j++ )
- indexes[pos++]
= cix+aix[j];
- }
- rptr[ci+1] = pos;
- }
- }
-
- //create CSR block from constructed or
shallow-copy arrays
- out.sparseBlock = new SparseBlockCSR(rptr,
indexes, values, pos);
- }
- else if( cols%clen==0 ) { //SPECIAL N:1 MATRIX->MATRIX
- int n = cols/clen;
- for(int bi=0, ci=0; bi<rlen; bi+=n, ci++) {
- //allocate output row once (w/o
re-allocations)
- long lnnz = a.size(bi, bi+n);
- c.allocate(ci, (int)lnnz);
- //copy N input rows into output row
- for( int i=bi, cix=0; i<bi+n; i++,
cix+=clen ) {
- if(a.isEmpty(i)) continue;
- 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++ )
- c.append(ci,
cix+aix[j], avals[j]);
- }
- }
- }
- else //GENERAL CASE: MATRIX->MATRIX
- {
- //note: cache-friendly on a but not c;
append-only
- //long cix because total cells in sparse can be
larger than int
- long cix = 0;
- for( int i=0; i<rlen; 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 ci =
(int)((cix+aix[j])/cols);
- int cj =
(int)((cix+aix[j])%cols);
- c.allocate(ci, estnnz,
cols);
- c.append(ci, cj,
avals[j]);
- }
- }
-
- cix += clen;
- }
+ else if( cols%clen==0 // SPECIAL CSR N:1 MATRIX->MATRIX
+ && SHALLOW_COPY_REORG && SPARSE_OUTPUTS_IN_CSR
&& in.getNonZeros() < Integer.MAX_VALUE) { // int nnz
+ reshapeSparseToCSR(in, out, rows, cols);
}
+ else
+ reshapeSparseToMCSR(in, out, rows, cols, k);
}
else //colwise
{
@@ -2501,6 +2485,179 @@ public class LibMatrixReorg {
}
}
+ private static void reshapeSparseToMCSR(MatrixBlock in, MatrixBlock
out, int rows, int cols, int k) throws Exception{
+ int rlen = in.rlen;
+ int clen = in.clen;
+
+ // allocate block
+ out.allocateSparseRowsBlock(false);
+ int estnnz = (int) (in.nonZeros / rows);
+
+ // sparse reshape
+ SparseBlock a = in.sparseBlock;
+ SparseBlock c = out.sparseBlock;
+ if(cols % clen == 0)
+ reshapeSparseToMCSR_Nto1(in, out, rows, cols, k);
+ else // GENERAL CASE: MATRIX->MATRIX
+ {
+ // note: cache-friendly on a but not c; append-only
+ // long cix because total cells in sparse can be larger
than int
+ long cix = 0;
+ for(int i = 0; i < rlen; 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 ci = (int) ((cix + aix[j])
/ cols);
+ int cj = (int) ((cix + aix[j])
% cols);
+ c.allocate(ci, estnnz, cols);
+ c.append(ci, cj, avals[j]);
+ }
+ }
+
+ cix += clen;
+ }
+ }
+ }
+
+ private static void reshapeSparseToMCSR_Nto1(MatrixBlock in,
MatrixBlock out, int rows, int cols, int k) throws Exception{
+ // SPECIAL N:1 MATRIX->MATRIX
+ final int rlen = in.rlen;
+ final int clen = in.clen;
+
+ final SparseBlock a = in.sparseBlock;
+ final SparseBlock c = out.sparseBlock;
+ final int n = cols / clen;
+ // safe now since we fixed the parfor threading.
+ if((k > 1 || k == -1) && ((double) rows / k) > 16) {
+ final ExecutorService pool = CommonThreadPool.get(k ==
-1 ? InfrastructureAnalyzer.getLocalParallelism() : k);
+ try {
+ final int blkz = Math.max((int)
Math.ceil((double) rows / k), 16);
+ ArrayList<Future<?>> tasks = new ArrayList<>();
+ for(int i = 0; i < rows; i += blkz) {
+ final int start = i;
+ final int end = Math.min(i + blkz,
rows);
+ tasks.add(pool.submit(() -> {
+ for(int bi = start * n, ci =
start; ci < end; bi += n, ci++) {
+
reshapeSparseToMCSR_Nto1_row(a, c, clen, bi, n, ci);
+ }
+ }));
+ }
+ for(Future<?> f : tasks)
+ f.get();
+ }
+ finally {
+ pool.shutdown();
+ }
+ }
+ else {
+ for(int bi = 0, ci = 0; bi < rlen; bi += n, ci++) {
+ reshapeSparseToMCSR_Nto1_row(a, c, clen, bi, n,
ci);
+ }
+ }
+
+ out.setNonZeros(in.nonZeros);
+ }
+
+ private static void reshapeSparseToMCSR_Nto1_row(SparseBlock a,
SparseBlock c, int clen, int bi, int n, int ci){
+ // allocate output row once (w/o re-allocations)
+ final int s = (int) a.size(bi, bi + n); // get exact size of
row output
+ final int[] cix = new int[s];
+ final double[] cvals = new double[s];
+
+ int pos = 0;
+ // copy N input rows into output row
+ for(int i = bi, colOffset = 0; i < bi + n; i++, colOffset +=
clen) {
+ pos = reshapeSparseToMCSR_Nto1_row_one(a,i, pos,cix,
colOffset, cvals);
+ }
+ c.set(ci, new SparseRowVector(cvals, cix), false);
+ }
+
+ private static int reshapeSparseToMCSR_Nto1_row_one(SparseBlock a, int
i, int pos, int[] cix, int colOffset,
+ double[] cvals) {
+ if(a.isEmpty(i))
+ return pos;
+ final int apos = a.pos(i);
+ final int alen = a.size(i);
+ final int[] aix = a.indexes(i);
+ final double[] avals = a.values(i);
+ for(int j = apos; j < apos + alen; j++, pos++) {
+ cix[pos] = colOffset + aix[j];
+ cvals[pos] = avals[j];
+ }
+ return pos;
+ }
+
+ private static void reshapeSparseToCSR(MatrixBlock in, MatrixBlock out,
int rows, int cols) {
+ if(in.sparseBlock instanceof SparseBlockCSR)
+ reshapeSparseToCSRFromCSR(in, out, rows, cols);
+ else
+ reshapeSparseToCSRFromMCSR(in, out, rows, cols);
+ }
+
+ private static void reshapeSparseToCSRFromMCSR(MatrixBlock in,
MatrixBlock out, int rows, int cols) {
+ final SparseBlock a = in.sparseBlock;
+ final int rlen = in.rlen;
+ final int clen = in.clen;
+
+ final int n = cols / clen;
+ final int[] rptr = new int[rows + 1];
+ final int[] indexes = new int[(int) a.size()];
+ final double[] values = new double[indexes.length];
+
+ int pos = 0;
+
+ for(int bi = 0, ci = 0; bi < rlen; bi += n, ci++) { // output
rows
+ for(int i = bi, cix = 0; i < bi + n; i++, cix += clen)
{ // N input rows
+ if(a.isEmpty(i))
+ continue;
+ final int apos = a.pos(i);
+ final int alen = a.size(i);
+ final int[] aix = a.indexes(i);
+ System.arraycopy(a.values(i), apos, values,
pos, alen);
+ for(int j = apos; j < apos + alen; j++)
+ indexes[pos++] = cix + aix[j];
+ }
+ rptr[ci + 1] = pos;
+ }
+
+ // create CSR block from constructed or shallow-copy arrays
+ out.sparseBlock = new SparseBlockCSR(rptr, indexes, values,
pos);
+ }
+
+
+ private static void reshapeSparseToCSRFromCSR(MatrixBlock in,
MatrixBlock out, int rows, int cols) {
+ final SparseBlock a = in.sparseBlock;
+ int rlen = in.rlen;
+ int clen = in.clen;
+
+ int n = cols / clen, pos = 0;
+ int[] rptr = new int[rows + 1];
+ int[] indexes = new int[(int) a.size()];
+ double[] values = null;
+ rptr[0] = 0;
+
+ int[] aix = ((SparseBlockCSR) a).indexes();
+ for(int bi = 0, ci = 0; bi < rlen; bi += n, ci++) {
+ for(int i = bi, cix = 0; i < bi + n; i++, cix += clen) {
+ if(a.isEmpty(i))
+ continue;
+ int apos = a.pos(i);
+ int alen = a.size(i);
+ for(int j = apos; j < apos + alen; j++)
+ indexes[pos++] = cix + aix[j];
+ }
+ rptr[ci + 1] = pos;
+ }
+ // shallow copy of CSR values
+ values = ((SparseBlockCSR) a).values();
+
+ // create CSR block from constructed or shallow-copy arrays
+ out.sparseBlock = new SparseBlockCSR(rptr, indexes, values,
pos);
+ }
+
private static void reshapeDenseToSparse( MatrixBlock in, MatrixBlock
out, int rows, int cols, boolean rowwise )
{
int rlen = in.rlen;
diff --git a/src/test/java/org/apache/sysds/performance/Main.java
b/src/test/java/org/apache/sysds/performance/Main.java
index a281dd2cf0..e161ca0187 100644
--- a/src/test/java/org/apache/sysds/performance/Main.java
+++ b/src/test/java/org/apache/sysds/performance/Main.java
@@ -33,6 +33,7 @@ import org.apache.sysds.performance.generators.MatrixFile;
import org.apache.sysds.performance.matrix.MatrixMulPerformance;
import org.apache.sysds.performance.matrix.MatrixReplacePerf;
import org.apache.sysds.performance.matrix.MatrixStorage;
+import org.apache.sysds.performance.matrix.ReshapePerf;
import org.apache.sysds.performance.matrix.SparseAppend;
import org.apache.sysds.runtime.data.SparseBlock;
import org.apache.sysds.runtime.frame.data.FrameBlock;
@@ -123,6 +124,9 @@ public class Main {
case 1004:
run1004(args);
break;
+ case 1005:
+ ReshapePerf.main(args);
+ break;
default:
break;
}
diff --git a/src/test/java/org/apache/sysds/performance/README.md
b/src/test/java/org/apache/sysds/performance/README.md
index 7129757f34..751e5e3cf9 100644
--- a/src/test/java/org/apache/sysds/performance/README.md
+++ b/src/test/java/org/apache/sysds/performance/README.md
@@ -70,3 +70,9 @@ Frame Operation timings
java -jar
-agentpath:$HOME/Programs/profiler/lib/libasyncProfiler.so=start,event=cpu,file=temp/log.html
target/systemds-3.3.0-SNAPSHOT-perf.jar 15 16 10
"src/test/resources/datasets/titanic/titanic.csv"
"src/test/resources/datasets/titanic/tfspec.json"
```
+Reshape Sparse
+
+```bash
+java -cp "target/systemds-3.3.0-SNAPSHOT-perf.jar:target/lib/*"
-agentpath:$HOME/Programs/profiler/lib/libasyncProfiler.so=start,event=cpu,file=temp/log.html
org.apache.sysds.performance.Main 1005
+```
+
diff --git a/src/test/java/org/apache/sysds/performance/matrix/ReshapePerf.java
b/src/test/java/org/apache/sysds/performance/matrix/ReshapePerf.java
new file mode 100644
index 0000000000..246598bcf8
--- /dev/null
+++ b/src/test/java/org/apache/sysds/performance/matrix/ReshapePerf.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.performance.matrix;
+
+import org.apache.sysds.performance.compression.APerfTest;
+import org.apache.sysds.performance.generators.ConstMatrix;
+import org.apache.sysds.performance.generators.IGenerate;
+import org.apache.sysds.runtime.data.SparseBlockCSR;
+import org.apache.sysds.runtime.matrix.data.LibMatrixReorg;
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.test.TestUtils;
+
+public class ReshapePerf extends APerfTest<Object, MatrixBlock> {
+
+ private final int k;
+
+ public ReshapePerf(int N, IGenerate<MatrixBlock> gen, int k) {
+ super(N, gen);
+ this.k = k;
+ }
+
+ public void run() throws Exception {
+ MatrixBlock mb = gen.take();
+ System.out.println(
+ String.format("Input Size: %d x %d , sparsity: %f ",
mb.getNumRows(), mb.getNumColumns(), mb.getSparsity()));
+ warmup(() -> reshape_Div(k, 2), 1000);
+
+ execute(() -> reshape_Div(k, 1), "same");
+ for(int i = 2; i < 51; i++) {
+ double d = ((double) mb.getNumRows() / i);
+ final int ii = i;
+ if((int) d == d) {
+ execute(() -> reshape_Div(k, ii), "replace_div
" + i + " Parallel: " + k);
+ }
+
+ }
+ }
+
+ private void reshape_Div(int k, int div) {
+ MatrixBlock mb = gen.take();
+ LibMatrixReorg.reshape(mb, null, mb.getNumRows() / div,
mb.getNumColumns() * div, true, k);
+ ret.add(null);
+ }
+
+ @Override
+ protected String makeResString() {
+ return "";
+ }
+
+ public static void main(String[] args) throws Exception {
+ MatrixBlock a =
TestUtils.ceil(TestUtils.generateTestMatrixBlock(10000, 10000, 0, 100, 0.1,
42));
+ // to CSR
+ // System.out.println("MCSR to CSR");
+ // new ReshapePerf(100, new ConstMatrix(a), 1).run();
+ // new ReshapePerf(1000, new ConstMatrix(a), 16).run();
+
+ // System.out.println("MCSR to MCSR parallel");
+ // MatrixBlock spy = spy(a);
+ // when(spy.getNonZeros()).thenReturn((long)Integer.MAX_VALUE +
42L);
+ // new ReshapePerf(100, new ConstMatrix(spy), 1).run();
+ // new ReshapePerf(100, new ConstMatrix(spy), 16).run();
+
+ System.out.println("CSR to CSR");
+ a.setSparseBlock(new SparseBlockCSR(a.getSparseBlock()));
+ new ReshapePerf(100, new ConstMatrix(a), 1).run();
+
+ }
+
+}
diff --git a/src/test/java/org/apache/sysds/test/TestUtils.java
b/src/test/java/org/apache/sysds/test/TestUtils.java
index ca6a3b2bf5..3a78a3780b 100644
--- a/src/test/java/org/apache/sysds/test/TestUtils.java
+++ b/src/test/java/org/apache/sysds/test/TestUtils.java
@@ -2056,25 +2056,18 @@ public class TestUtils {
/**
* <p>
- * Generates a test matrix with the specified parameters as a two
- * dimensional array.
+ * Generates a test matrix with the specified parameters as a two
dimensional array.
* </p>
* <p>
* Set seed to -1 to use the current time as seed.
* </p>
*
- * @param rows
- * number of rows
- * @param cols
- * number of columns
- * @param min
- * minimum value
- * @param max
- * maximum value
- * @param sparsity
- * sparsity
- * @param seed
- * seed
+ * @param rows number of rows
+ * @param cols number of columns
+ * @param min minimum value
+ * @param max maximum value
+ * @param sparsity sparsity
+ * @param seed seed
* @return random matrix
*/
public static double[][] generateTestMatrix(int rows, int cols, double
min, double max, double sparsity, long seed) {
diff --git
a/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/ReshapeTest.java
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/ReshapeTest.java
new file mode 100644
index 0000000000..379128e0d4
--- /dev/null
+++
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/ReshapeTest.java
@@ -0,0 +1,476 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.test.component.matrix.libMatrixReorg;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.sysds.runtime.data.DenseBlock;
+import org.apache.sysds.runtime.data.SparseBlockCSR;
+import org.apache.sysds.runtime.matrix.data.LibMatrixReorg;
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.test.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(value = Parameterized.class)
+
+public class ReshapeTest {
+ protected static final Log LOG =
LogFactory.getLog(ReshapeTest.class.getName());
+
+ @Parameterized.Parameter
+ public int k;
+ @Parameterized.Parameter(1)
+ public boolean rowWise;
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ ArrayList<Object[]> tests = new ArrayList<>();
+ tests.add(new Object[] {1, true});
+ tests.add(new Object[] {10, true});
+ tests.add(new Object[] {-1, true});
+ tests.add(new Object[] {1, false});
+ tests.add(new Object[] {10, false});
+ tests.add(new Object[] {-1, false});
+
+ return tests;
+ }
+
+ @Test
+ public void reshapeDense1() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(10, 5, 0, 10,
1.0, 132);
+ MatrixBlock b = runReshape(a, 5, 10);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense2() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 5, 0,
10, 1.0, 132);
+ MatrixBlock b = runReshape(a, 5, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense3() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 24, 0,
10, 1.0, 132);
+ MatrixBlock b = runReshape(a, 24, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense4() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(2, 2, 0, 10,
1.0, 132);
+ MatrixBlock b = runReshape(a, 1, 4);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense5() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 50, 0,
10, 1.0, 132);
+ MatrixBlock b = runReshape(a, 25, 200);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense6() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 1, 0,
10, 1.0, 132);
+ MatrixBlock b = runReshape(a, 25, 4);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense7() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 100, 0,
10, 1.0, 132);
+ MatrixBlock b = runReshape(a, 25, 4);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense8() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 50, 0,
10, 1.0, 132);
+ DenseBlock db = a.getDenseBlock();
+ DenseBlock spy = spy(db);
+ when(spy.numBlocks()).thenReturn(2);
+ a.setDenseBlock(spy);
+ MatrixBlock b = runReshape(a, 25, 200);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense9() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(25, 4, 0, 10,
1.0, 132);
+ MatrixBlock b = runReshape(a, 100, 1);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense10() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(25, 4, 0, 10,
1.0, 132);
+ MatrixBlock b = runReshape(a, 1, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense11() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(25, 4, 0, 10,
1.0, 132);
+ a.setDenseBlock(null);
+ MatrixBlock b = runReshape(a, 1, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense4OtherInterface() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 50, 0,
10, 1.0, 132);
+ MatrixBlock b = LibMatrixReorg.reshape(a, null, 25, 200,
rowWise);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDense4OtherInterfaceObject() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 50, 0,
10, 1.0, 132);
+ MatrixBlock b = LibMatrixReorg.reshape(a, new MatrixBlock(),
25, 200, rowWise);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSameSize1() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 50, 0,
10, 1.0, 132);
+ MatrixBlock b = runReshape(a, 100, 50);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSameSize2() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(10, 5, 0, 10,
1.0, 132);
+ MatrixBlock b = runReshape(a, 10, 5);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test(expected = Exception.class)
+ public void invalid1() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(10, 5, 0, 10,
1.0, 132);
+ runReshape(a, 10, 10);
+ }
+
+ @Test(expected = Exception.class)
+ public void invalid2() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(10, 5, 0, 10,
1.0, 132);
+ runReshape(a, 5, 5);
+ }
+
+ @Test(expected = Exception.class)
+ public void invalid3() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(10, 5, 0, 10,
1.0, 132);
+ runReshape(a, 12, 12);
+ }
+
+ @Test
+ public void reshapeSparseToDense() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 100, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 100, 1);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToDense2() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 100, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 50, 2);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToDense3() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 100, 0,
10, 0.9, 132);
+
+ a.denseToSparse(true);
+ MatrixBlock b = runReshape(a, 200, 50);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToDense4() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 100, 0,
10, 0.9, 132);
+ a.denseToSparse(true);
+ MatrixBlock b = runReshape(a, 50, 200);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToDense5() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 100, 0,
10, 0.9, 132);
+ a.getDenseBlock().fillRow(3, 0);
+ a.denseToSparse(true);
+ MatrixBlock b = runReshape(a, 50, 200);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToDense6() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(3, 100, 0,
10, 1.0, 132);
+ a.getDenseBlock().fillRow(1, 0);
+ a.denseToSparse(true);
+ MatrixBlock b = runReshape(a, 1, 300);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToDense7() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 100, 0,
10, 1.0, 132);
+ a.getDenseBlock().fillRow(0, 0);
+ a.denseToSparse(false);
+ MatrixBlock b = runReshape(a, 2, 50);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDenseToSparse1() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 1, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 1, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDenseToSparse2() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 1, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 2, 50);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDenseToSparse3() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 2, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 2, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDenseToSparse4() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 2, 0,
10, 0.1, 132);
+ a.setDenseBlock(null);
+ MatrixBlock b = runReshape(a, 2, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeDenseToSparse5() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(50, 2, 0, 10,
0.1, 132);
+ MatrixBlock b = runReshape(a, 1, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+
+ @Test
+ public void reshapeDenseToSparse6() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 100, 0,
10, 0.1, 132);
+ a.sparseToDense();
+ MatrixBlock b = runReshape(a, 2, 50);
+ verifyEqualReshaped(a, b);
+ }
+
+
+ @Test
+ public void reshapeSparseToSparse() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 100, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 50, 200);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse2() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 100, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 25, 400);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse3() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 125, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 25, 500);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse4() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 125, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 1, 100 * 125);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse5() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 1, 0,
10, 0.1, 132);
+ MatrixBlock b = runReshape(a, 1, 100);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse6() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 100, 0,
10, 0.001, 132);
+ MatrixBlock b = runReshape(a, 50, 200);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse7() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(10, 100, 0,
10, 0.0001, 132);
+ MatrixBlock b = runReshape(a, 1, 1000);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse8() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 1000, 0,
10, 0.0001, 132);
+ MatrixBlock b = runReshape(a, 2, 500);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse9() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 1000, 0,
10, 0.001, 132);
+ MatrixBlock b = runReshape(a, 2, 500);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse10() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(4, 250, 0,
10, 0.001, 132);
+ a.setSparseBlock(new SparseBlockCSR(a.getSparseBlock()));
+ MatrixBlock b = runReshape(a, 2, 500);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse11() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(4, 250, 0,
10, 0.001, 132);
+ MatrixBlock spy = spy(a);
+ when(spy.getNonZeros()).thenReturn((long) Integer.MAX_VALUE +
45L);
+ MatrixBlock b = runReshape(spy, 2, 500);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse12() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(4, 125, 0,
10, (double)1 / (125*2), 132);
+ MatrixBlock b = runReshape(a, 1, 500);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeSparseToSparse13() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(1, 100, 0,
10, 0.1, 132);
+ a.getSparseBlock().reset(0, 10, 100);
+ MatrixBlock b = runReshape(a, 2, 50);
+ verifyEqualReshaped(a, b);
+ }
+
+
+ @Test
+ public void reshapeEmpty1() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(100, 125, 0,
10, 0.0, 132);
+ MatrixBlock b = runReshape(a, 25, 500);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeEmpty2() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(10, 10, 0,
10, 0.0, 132);
+ MatrixBlock b = runReshape(a, 5, 20);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeEmpty3() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(5, 5, 0, 10,
0.0, 132);
+ MatrixBlock b = runReshape(a, 1, 25);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeEmpty4() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(5, 5, 0, 10,
0.0, 132);
+ MatrixBlock b = runReshape(a, 25, 1);
+ verifyEqualReshaped(a, b);
+ }
+
+ @Test
+ public void reshapeEmpty5() {
+ MatrixBlock a = TestUtils.generateTestMatrixBlock(6, 6, 0, 10,
0.0, 132);
+ MatrixBlock b = runReshape(a, 3, 12);
+ verifyEqualReshaped(a, b);
+ }
+
+ private MatrixBlock runReshape(MatrixBlock a, int r, int c) {
+ return LibMatrixReorg.reshape(a, null, r, c, rowWise, k);
+ }
+
+ private void verifyEqualReshaped(MatrixBlock expected, MatrixBlock
actual) {
+ final long expectedCells = (long) expected.getNumRows() *
expected.getNumColumns();
+ final long actualCells = (long) actual.getNumRows() *
actual.getNumColumns();
+
+ assertEquals(expectedCells, actualCells);
+ final long eCols = expected.getNumColumns();
+ final long eRows = expected.getNumRows();
+ final long aCols = actual.getNumColumns();
+ final long aRows = actual.getNumRows();
+
+ if(rowWise) {
+
+ for(long c = 0; c < expectedCells; c++) {
+ int r1 = (int) (c / eCols);
+ int c1 = (int) (c % eCols);
+
+ int r2 = (int) (c / aCols);
+ int c2 = (int) (c % aCols);
+ if(expected.get(r1, c1) != actual.get(r2, c2)) {
+ double v1 = expected.get(r1, c1);
+ double v2 = actual.get(r2, c2);
+ String err = String.format("%d,%d vs
%d,%d not equal with values: %f vs %f", r1, c1, r2, c2, v1, v2);
+ assertEquals(err, v1, v2, 0.0);
+ }
+ }
+ }
+ else {
+
+ for(long c = 0; c < expectedCells; c++) {
+ int r2 = (int) (c / aCols);
+ int c2 = (int) (c % aCols);
+
+ int r1 = (int) ((aRows * c2 + r2) % eRows);
+ int c1 = (int) ((aRows * c2 + r2) / eRows);
+
+ if(expected.get(r1, c1) != actual.get(r2, c2)) {
+ double v1 = expected.get(r1, c1);
+ double v2 = actual.get(r2, c2);
+ String err = String.format("%d,%d vs
%d,%d not equal with values: %f vs %f", r1, c1, r2, c2, v1, v2);
+ assertEquals(err, v1, v2, 0.0);
+ }
+ }
+ }
+
+ }
+}
diff --git
a/src/test/java/org/apache/sysds/test/component/matrix/TransposeCSRTest.java
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeCSRTest.java
similarity index 98%
rename from
src/test/java/org/apache/sysds/test/component/matrix/TransposeCSRTest.java
rename to
src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeCSRTest.java
index 9f4ff33719..35d4d0546d 100644
--- a/src/test/java/org/apache/sysds/test/component/matrix/TransposeCSRTest.java
+++
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeCSRTest.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.apache.sysds.test.component.matrix;
+package org.apache.sysds.test.component.matrix.libMatrixReorg;
import static org.junit.Assert.fail;
diff --git
a/src/test/java/org/apache/sysds/test/component/matrix/TransposeInplaceTest.java
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeInplaceTest.java
similarity index 97%
rename from
src/test/java/org/apache/sysds/test/component/matrix/TransposeInplaceTest.java
rename to
src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeInplaceTest.java
index 7b23bdadb9..4490136cd6 100644
---
a/src/test/java/org/apache/sysds/test/component/matrix/TransposeInplaceTest.java
+++
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeInplaceTest.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.apache.sysds.test.component.matrix;
+package org.apache.sysds.test.component.matrix.libMatrixReorg;
import java.util.ArrayList;
import java.util.Collection;
diff --git
a/src/test/java/org/apache/sysds/test/component/matrix/TransposeTwiceTest.java
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeTwiceTest.java
similarity index 98%
rename from
src/test/java/org/apache/sysds/test/component/matrix/TransposeTwiceTest.java
rename to
src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeTwiceTest.java
index c8fcb7abb1..eb38914f1e 100644
---
a/src/test/java/org/apache/sysds/test/component/matrix/TransposeTwiceTest.java
+++
b/src/test/java/org/apache/sysds/test/component/matrix/libMatrixReorg/TransposeTwiceTest.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.apache.sysds.test.component.matrix;
+package org.apache.sysds.test.component.matrix.libMatrixReorg;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;