This is an automated email from the ASF dual-hosted git repository.

ywcb00 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 c50c769153 [SYSTEMDS-3948] Implement Row-wise Sparsity Estimator
c50c769153 is described below

commit c50c769153de7a7ed4aa36a9c9fa86d3bd3c569e
Author: ywcb00 <[email protected]>
AuthorDate: Thu May 21 09:28:37 2026 +0200

    [SYSTEMDS-3948] Implement Row-wise Sparsity Estimator
    
    This commit implements the row-wise sparsity estimator and adds respective 
test cases.
    
    Closes #2466.
---
 .../apache/sysds/hops/estim/EstimatorRowWise.java  | 356 +++++++++++++++++++++
 .../test/component/estim/OpBindChainTest.java      | 116 ++++---
 .../sysds/test/component/estim/OpBindTest.java     | 105 +++---
 .../test/component/estim/OpElemWChainTest.java     |  98 +++---
 .../sysds/test/component/estim/OpElemWTest.java    |  96 +++---
 .../sysds/test/component/estim/OpSingleTest.java   | 166 ++++++----
 .../test/component/estim/OuterProductTest.java     | 107 +++----
 .../test/component/estim/SelfProductTest.java      | 146 ++++-----
 .../component/estim/SquaredProductChainTest.java   | 132 ++++----
 .../test/component/estim/SquaredProductTest.java   | 138 ++++----
 10 files changed, 917 insertions(+), 543 deletions(-)

diff --git a/src/main/java/org/apache/sysds/hops/estim/EstimatorRowWise.java 
b/src/main/java/org/apache/sysds/hops/estim/EstimatorRowWise.java
new file mode 100644
index 0000000000..0cee03c8df
--- /dev/null
+++ b/src/main/java/org/apache/sysds/hops/estim/EstimatorRowWise.java
@@ -0,0 +1,356 @@
+/*
+ * 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.hops.estim;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.NotImplementedException;
+import org.apache.sysds.hops.OptimizerUtils;
+import org.apache.sysds.runtime.data.SparseRow;
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.runtime.meta.DataCharacteristics;
+import org.apache.sysds.runtime.meta.MatrixCharacteristics;
+
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+
+/**
+ * This estimator implements an approach based on row-wise sparsity estimation,
+ * introduced in
+ * Lin, Chunxu, Wensheng Luo, Yixiang Fang, Chenhao Ma, Xilin Liu and Yuchi Ma:
+ * On Efficient Large Sparse Matrix Chain Multiplication.
+ * Proceedings of the ACM on Management of Data 2 (2024): 1 - 27.
+ */
+public class EstimatorRowWise extends SparsityEstimator {
+       @Override
+       public DataCharacteristics estim(MMNode root) {
+               estimInternChain(root);
+               double sparsity = 
DoubleStream.of((double[])root.getSynopsis()).average().orElse(0);
+
+               DataCharacteristics outputCharacteristics = 
deriveOutputCharacteristics(root, sparsity);
+               return root.setDataCharacteristics(outputCharacteristics);
+       }
+
+       @Override
+       public double estim(MatrixBlock m1, MatrixBlock m2) {
+               return estim(m1, m2, OpCode.MM);
+       }
+       
+       @Override
+       public double estim(MatrixBlock m1, MatrixBlock m2, OpCode op) {
+               if( isExactMetadataOp(op, m1.getNumColumns()) ) {
+                       return estimExactMetaData(m1.getDataCharacteristics(),
+                               m2.getDataCharacteristics(), op).getSparsity();
+               }
+
+               double[] rsOut = estimIntern(m1, m2, op);
+               return DoubleStream.of(rsOut).average().orElse(0);
+       }
+
+       @Override
+       public double estim(MatrixBlock m1, OpCode op) {
+               if( isExactMetadataOp(op, m1.getNumColumns()) )
+                       return estimExactMetaData(m1.getDataCharacteristics(), 
null, op).getSparsity();
+
+               double[] rsOut = estimIntern(m1, op);
+               return DoubleStream.of(rsOut).average().orElse(0);
+       }
+
+       private double[] estimInternChain(MMNode node) {
+               return estimInternChain(node, null, null);
+       }
+
+       private double[] estimInternChain(MMNode node, double[] 
rsRightNeighbor, OpCode opRightNeighbor) {
+               double[] rsOut;
+               if(node.isLeaf()) {
+                       MatrixBlock mb = node.getData();
+                       if(rsRightNeighbor != null)
+                               rsOut = estimIntern(mb, rsRightNeighbor, 
opRightNeighbor);
+                       else
+                               rsOut = getRowWiseSparsityVector(mb);
+               }
+               else {
+                       MMNode nodeLeft = node.getLeft();
+                       MMNode nodeRight = node.getRight();
+                       switch(node.getOp()) {
+                               case MM:
+                                       double[] rsRightMM = 
estimInternChain(nodeRight, rsRightNeighbor, opRightNeighbor);
+                                       rsOut = estimInternChain(nodeLeft, 
rsRightMM, node.getOp());
+                                       break;
+                               case CBIND:
+                                       /**
+                                        * NOTE: considering the current node 
as new DAG for estimation (cut), since the row sparsity of
+                                        * the right neighbor cannot be 
aggregated into a cbind operation when having only row sparsity vectors
+                                        */
+                                       double[] rsLeftCBind = 
estimInternChain(nodeLeft);
+                                       double[] rsRightCBind = 
estimInternChain(nodeRight);
+                                       double[] rsCBind = 
estimInternCBind(rsLeftCBind, rsRightCBind);
+                                       if(rsRightNeighbor != null) {
+                                               rsOut = 
estimInternMMFallback(rsCBind, rsRightNeighbor);
+                                               if(opRightNeighbor != OpCode.MM)
+                                                       throw new 
NotImplementedException("Fallback sparsity estimation has only been " +
+                                                               "considered for 
MM operation w/ right neighbor yet.");
+                                       }
+                                       else
+                                               rsOut = rsCBind;
+                                       break;
+                               case RBIND:
+                                       /**
+                                        * NOTE: considering the current node 
as new DAG for estimation (cut), since the row sparsity of
+                                        * the right neighbor cannot be 
aggregated into an rbind operation when having only row sparsity vectors
+                                        */
+                                       double[] rsLeftRBind = 
estimInternChain(nodeLeft);
+                                       double[] rsRightRBind = 
estimInternChain(nodeRight);
+                                       double[] rsRBind = 
estimInternRBind(rsLeftRBind, rsRightRBind);
+                                       if(rsRightNeighbor != null) {
+                                               rsOut = 
estimInternMMFallback(rsRBind, rsRightNeighbor);
+                                               if(opRightNeighbor != OpCode.MM)
+                                                       throw new 
NotImplementedException("Fallback sparsity estimation has only been " +
+                                                               "considered for 
MM operation w/ right neighbor yet.");
+                                       }
+                                       else
+                                               rsOut = rsRBind;
+                                       break;
+                               case PLUS:
+                                       /**
+                                        * NOTE: considering the current node 
as new DAG for estimation (cut), since the row sparsity of
+                                        * the right neighbor cannot be 
aggregated into an element-wise operation when having only row sparsity vectors
+                                        */
+                                       double[] rsLeftPlus = 
estimInternChain(nodeLeft);
+                                       double[] rsRightPlus = 
estimInternChain(nodeRight);
+                                       double[] rsPlus = 
estimInternPlus(rsLeftPlus, rsRightPlus);
+                                       if(rsRightNeighbor != null) {
+                                               rsOut = 
estimInternMMFallback(rsPlus, rsRightNeighbor);
+                                               if(opRightNeighbor != OpCode.MM)
+                                                       throw new 
NotImplementedException("Fallback sparsity estimation has only been " +
+                                                               "considered for 
MM operation w/ right neighbor yet.");
+                                       }
+                                       else
+                                               rsOut = rsPlus;
+                                       break;
+                               case MULT:
+                                       /**
+                                        * NOTE: considering the current node 
as new DAG for estimation (cut), since the row sparsity of
+                                        * the right neighbor cannot be 
aggregated into an element-wise operation when having only row sparsity vectors
+                                        */
+                                       double[] rsLeftMult = 
estimInternChain(nodeLeft);
+                                       double[] rsRightMult = 
estimInternChain(nodeRight);
+                                       double[] rsMult = 
estimInternMult(rsLeftMult, rsRightMult);
+                                       if(rsRightNeighbor != null) {
+                                               rsOut = 
estimInternMMFallback(rsMult, rsRightNeighbor);
+                                               if(opRightNeighbor != OpCode.MM)
+                                                       throw new 
NotImplementedException("Fallback sparsity estimation has only been " +
+                                                               "considered for 
MM operation w/ right neighbor yet.");
+                                       }
+                                       else
+                                               rsOut = rsMult;
+                                       break;
+                               default:
+                                       throw new 
NotImplementedException("Chain estimation for operator " + 
node.getOp().toString() +
+                                       " is not supported yet.");
+                       }
+               }
+               node.setSynopsis(rsOut);
+               node.setDataCharacteristics(deriveOutputCharacteristics(node, 
DoubleStream.of(rsOut).average().orElse(0)));
+               return rsOut;
+       }
+
+       private double[] estimIntern(MatrixBlock m1, MatrixBlock m2, OpCode op) 
{
+               double[] rsM2 = getRowWiseSparsityVector(m2);
+               return estimIntern(m1, rsM2, op);
+       }
+
+       private double[] estimIntern(MatrixBlock m1, double[] rsM2, OpCode op) {
+               switch(op) {
+                       case MM:
+                               return estimInternMM(m1, rsM2);
+                       case CBIND:
+                               return 
estimInternCBind(getRowWiseSparsityVector(m1), rsM2);
+                       case RBIND:
+                               return 
estimInternRBind(getRowWiseSparsityVector(m1), rsM2);
+                       case PLUS:
+                               return 
estimInternPlus(getRowWiseSparsityVector(m1), rsM2);
+                       case MULT:
+                               return 
estimInternMult(getRowWiseSparsityVector(m1), rsM2);
+                       default:
+                               throw new NotImplementedException("Sparsity 
estimation for operation " + op.toString() + " not supported yet.");
+               }
+       }
+
+       private double[] estimIntern(MatrixBlock mb, OpCode op) {
+               switch(op) {
+                       case DIAG:
+                               return estimInternDiag(mb);
+                       default:
+                               throw new NotImplementedException("Sparsity 
estimation for operation " + op.toString() + " not supported yet.");
+               }
+       }
+
+       /**
+        * Corresponds to Algorithm 1 in the publication
+        */
+       private double[] estimInternMM(MatrixBlock m1, double[] rsM2) {
+               double[] rsOut = new double[m1.getNumRows()];
+               for(int rIdx = 0; rIdx < m1.getNumRows(); rIdx++) {
+                       double currentVal = 1;
+                       for(int cIdx : getNonZeroColumnIndices(m1, rIdx)) {
+                               currentVal *= 1.0 - rsM2[cIdx];
+                       }
+                       rsOut[rIdx] = 1 - currentVal;
+               }
+               return rsOut;
+       }
+
+       /**
+        * NOTE: fallback estimate using the uniform estimator (aka 
average-case estimator, Naive Bayes estimator) for
+        * the case when we are limited to the row sparsity vectors of both 
inputs
+        * NOTE: Considering the average of the second matrix would probably 
not be far off while saving computing time
+        */
+       private double[] estimInternMMFallback(double[] rsM1, double[] rsM2) {
+               double[] rsOut = new double[rsM1.length];
+               for(int i = 0; i < rsM1.length; i++) {
+                       double rsM1i = rsM1[i];
+                       if(rsM1i == 0) {
+                               rsOut[i] = 0;
+                       }
+                       else {
+                               double currentVal = 1;
+                               for(int j = 0; j < rsM2.length; j++) {
+                                       currentVal *= 1.0 - (rsM1i * rsM2[j]);
+                               }
+                               rsOut[i] = 1.0 - currentVal;
+                       }
+               }
+               return rsOut;
+       }
+
+       private double[] estimInternCBind(double[] rsM1, double[] rsM2) {
+               // FIXME: this estimate assumes that the number of columns is 
equivalent for both inputs
+               double[] rsOut = new double[rsM1.length];
+               for(int idx = 0; idx < rsM1.length; idx++) {
+                       rsOut[idx] = (rsM1[idx] + rsM2[idx]) / 2.0;
+               }
+               return rsOut;
+       }
+
+       private double[] estimInternRBind(double[] rsM1, double[] rsM2) {
+               return ArrayUtils.addAll(rsM1, rsM2);
+       }
+
+       private double[] estimInternPlus(double[] rsM1, double[] rsM2) {
+               // row-wise average case estimates
+               // rsM1 + rsM2 - (rsM1 * rsM2)
+               double[] rsOut = new double[rsM1.length];
+               for(int idx = 0; idx < rsM1.length; idx++) {
+                       rsOut[idx] = rsM1[idx] + rsM2[idx] - (rsM1[idx] * 
rsM2[idx]);
+               }
+               return rsOut;
+       }
+
+       private double[] estimInternMult(double[] rsM1, double[] rsM2) {
+               // row-wise average case estimates
+               // rsM1 * rsM2
+               double[] rsOut = new double[rsM1.length];
+               for(int idx = 0; idx < rsM1.length; idx++) {
+                       rsOut[idx] = rsM1[idx] * rsM2[idx];
+               }
+               return rsOut;
+       }
+
+       private double[] estimInternDiag(MatrixBlock mb) {
+               double[] rsOut = new double[mb.getNumRows()];
+               for(int rIdx = 0; rIdx < mb.getNumRows(); rIdx++) {
+                       rsOut[rIdx] = (mb.get(rIdx, rIdx) == 0) ? 0 : 1;
+               }
+               return rsOut;
+       }
+
+       private double[] getRowWiseSparsityVector(MatrixBlock mb) {
+               int numRows = mb.getNumRows();
+               double[] rsOut = new double[numRows];
+               if(mb.isInSparseFormat()) {
+                       for(int rIdx = 0; rIdx < numRows; rIdx++) {
+                               SparseRow sparseRow = 
mb.getSparseBlock().get(rIdx);
+                               rsOut[rIdx] = (sparseRow == null) ? 0 : 
(double) sparseRow.size() / mb.getNumColumns();
+                       }
+               }
+               else {
+                       for(int rIdx = 0; rIdx < numRows; rIdx++) {
+                               rsOut[rIdx] = (double) 
mb.getDenseBlock().countNonZeros(rIdx) / mb.getNumColumns();
+                       }
+               }
+               return rsOut;
+       }
+
+       private int[] getNonZeroColumnIndices(MatrixBlock mb, final int rIdx) {
+               int[] nonZeroCols;
+               if(mb.isInSparseFormat()) {
+                       SparseRow sparseRow = mb.getSparseBlock().get(rIdx);
+                       nonZeroCols = (sparseRow == null) ? new int[0] : 
sparseRow.indexes();
+               }
+               else {
+                       nonZeroCols = IntStream.range(0, mb.getNumColumns())
+                               .filter(cIdx -> mb.get(rIdx, cIdx) != 
0).toArray();
+               }
+               return nonZeroCols;
+       }
+
+       public static DataCharacteristics deriveOutputCharacteristics(MMNode 
node, double spOut) {
+               if(node.isLeaf() ||
+                       (node.getDataCharacteristics() != null && 
node.getDataCharacteristics().getNonZeros() != -1)) {
+                       return node.getDataCharacteristics();
+               }
+
+               MMNode nodeLeft = node.getLeft();
+               MMNode nodeRight = node.getRight();
+               int leftNRow = nodeLeft.getRows();
+               int leftNCol = nodeLeft.getCols();
+               int rightNRow = nodeRight.getRows();
+               int rightNCol = nodeRight.getCols();
+               switch(node.getOp()) {
+                       case MM:
+                               return new MatrixCharacteristics(leftNRow, 
rightNCol,
+                                       OptimizerUtils.getNnz(leftNRow, 
rightNCol, spOut));
+                       case MULT:
+                       case PLUS:
+                       case NEQZERO:
+                       case EQZERO:
+                               return new MatrixCharacteristics(leftNRow, 
leftNCol,
+                                       OptimizerUtils.getNnz(leftNRow, 
leftNCol, spOut));
+                       case RBIND:
+                               return new 
MatrixCharacteristics(leftNRow+rightNRow, leftNCol,
+                                       
OptimizerUtils.getNnz(leftNRow+rightNRow, leftNCol, spOut));
+                       case CBIND:
+                               return new MatrixCharacteristics(leftNRow, 
leftNCol+rightNCol,
+                                       OptimizerUtils.getNnz(leftNRow, 
leftNCol+rightNCol, spOut));
+                       case DIAG:
+                               int ncol = (leftNCol == 1) ? leftNRow : 1;
+                               return new MatrixCharacteristics(leftNRow, ncol,
+                                       OptimizerUtils.getNnz(leftNRow, ncol, 
spOut));
+                       case TRANS:
+                               return new MatrixCharacteristics(leftNCol, 
leftNRow,
+                                       OptimizerUtils.getNnz(leftNCol, 
leftNRow, spOut));
+                       case RESHAPE:
+                               throw new 
NotImplementedException("Characteristics derivation for " + node.getOp() +" has 
not been " +
+                                       "implemented yet, but could be 
implemented similar to EstimatorMatrixHistogram.java");
+                       default:
+                               throw new NotImplementedException();
+               }
+       }
+};
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/OpBindChainTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/OpBindChainTest.java
index 35efedaf62..9626f9eb74 100644
--- a/src/test/java/org/apache/sysds/test/component/estim/OpBindChainTest.java
+++ b/src/test/java/org/apache/sysds/test/component/estim/OpBindChainTest.java
@@ -19,11 +19,11 @@
 
 package org.apache.sysds.test.component.estim;
 
-import org.junit.Test;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
 import org.apache.sysds.hops.estim.MMNode;
 import org.apache.sysds.hops.estim.SparsityEstimator;
@@ -32,136 +32,146 @@ import 
org.apache.sysds.runtime.instructions.InstructionUtils;
 import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 import org.apache.commons.lang3.NotImplementedException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 /**
- * this is the basic operation check for all estimators with single operations
+ * this is the basic operation check for all estimators with chains of 
operations including binding operations
  */
-public class OpBindChainTest extends AutomatedTestBase 
+@RunWith(value = Parameterized.class)
+public class OpBindChainTest extends AutomatedTestBase
 {
-       private final static int m = 600;
-       private final static int k = 300;
-       private final static int n = 100;
-       private final static double[] sparsity = new double[]{0.2, 0.4};
-//     private final static OpCode mult = OpCode.MULT;
-//     private final static OpCode plus = OpCode.PLUS;
-       private final static OpCode rbind = OpCode.RBIND;
-       private final static OpCode cbind = OpCode.CBIND;
-//     private final static OpCode eqzero = OpCode.EQZERO;
-//     private final static OpCode diag = OpCode.DIAG;
-//     private final static OpCode neqzero = OpCode.NEQZERO;
-//     private final static OpCode trans = OpCode.TRANS;
-//     private final static OpCode reshape = OpCode.RESHAPE;
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int k;
+       @Parameterized.Parameter(2)
+       public int n;
+       @Parameterized.Parameter(3)
+       public double[] sparsity;
 
        @Override
        public void setUp() {
                //do  nothing
        }
-       
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, k, n, sparsity}
+                       {600, 300, 100, new double[]{0.2, 0.4}},
+                       {600, 200, 300, new double[]{0.1, 0.15}},
+               });
+       }
+
        //Average Case
        @Test
        public void testAvgRbind() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.RBIND);
        }
        
        @Test
        public void testAvgCbind() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.CBIND);
        }
        
        //Worst Case
        @Test
        public void testWorstRbind() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), 
OpCode.RBIND);
        }
        
        @Test
        public void testWorstCbind() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), 
OpCode.CBIND);
        }
        
        //DensityMap
        /*@Test
        public void testDMCaserbind() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorDensityMap(), 
OpCode.RBIND);
        }
        
        @Test
        public void testDMCasecbind() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorDensityMap(), 
OpCode.CBIND);
        }*/
        
        //MNC
        @Test
        public void testMNCRbind() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, k, 
n, sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.RBIND);
        }
                
        @Test
        public void testMNCCbind() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, k, 
n, sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.CBIND);
        }
 
        //Bitset
        @Test
        public void testBitsetCaserbind() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.RBIND);
        }
        
         @Test
        public void testBitsetCasecbind() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.CBIND);
         }
                
        //Layered Graph
        @Test
        public void testLGCaserbind() {
                runSparsityEstimateTest(
-                       new EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 
7), 
-                       m, k, n, sparsity, rbind);
+                       new EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 
7), OpCode.RBIND);
        }
                        
        @Test
        public void testLGCasecbind() {
                runSparsityEstimateTest(
-                       new EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 
3), 
-                       m, k, n, sparsity, cbind);
+                       new EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 
3), OpCode.CBIND);
        }
-       
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int k, int n, double[] sp, OpCode op) {
-               MatrixBlock m1;
+
+       // Row Wise Sparsity Estimator
+       @Test
+       public void testRowWiseRbind() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.RBIND);
+       }
+
+       @Test
+       public void testRowWiseCbind() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.CBIND);
+       }
+
+
+       private void runSparsityEstimateTest(SparsityEstimator estim, OpCode 
op) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sparsity[0], 
1, 1, "uniform", 3);
                MatrixBlock m2;
                MatrixBlock m3 = new MatrixBlock();
                MatrixBlock m4;
-               MatrixBlock m5 = new MatrixBlock();
-               double est = 0;
                switch(op) {
                        case RBIND:
-                               m1 = MatrixBlock.randOperations(m, k, sp[0], 1, 
1, "uniform", 3);
-                               m2 = MatrixBlock.randOperations(n, k, sp[1], 1, 
1, "uniform", 7);
+                               m2 = MatrixBlock.randOperations(n, k, 
sparsity[1], 1, 1, "uniform", 7);
                                m1.append(m2, m3, false);
-                               m4 = MatrixBlock.randOperations(k, m, sp[1], 1, 
1, "uniform", 5);
-                               m5 = m3.aggregateBinaryOperations(m3, m4, 
-                                               new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
-                               est = estim.estim(new MMNode(new MMNode(new 
MMNode(m1), new MMNode(m2), op), new MMNode(m4), OpCode.MM)).getSparsity();
-                               //System.out.println(est);
-                               //System.out.println(m5.getSparsity());
+                               m4 = MatrixBlock.randOperations(k, m, 
sparsity[1], 1, 1, "uniform", 5);
                                break;
                        case CBIND:
-                               m1 = MatrixBlock.randOperations(m, k, sp[0], 1, 
1, "uniform", 3);
-                               m2 = MatrixBlock.randOperations(m, n, sp[1], 1, 
1, "uniform", 7);
+                               m2 = MatrixBlock.randOperations(m, n, 
sparsity[1], 1, 1, "uniform", 7);
                                m1.append(m2, m3, true);
-                               m4 = MatrixBlock.randOperations(k+n, m, sp[1], 
1, 1, "uniform", 5);
-                               m5 = m3.aggregateBinaryOperations(m3, m4, 
-                                               new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
-                               est = estim.estim(new MMNode(new MMNode(new 
MMNode(m1), new MMNode(m2), op), new MMNode(m4), OpCode.MM)).getSparsity();
-                               //System.out.println(est);
-                               //System.out.println(m5.getSparsity());
+                               m4 = MatrixBlock.randOperations(k+n, m, 
sparsity[1], 1, 1, "uniform", 5);
                                break;
                        default:
                                throw new NotImplementedException();
                }
+               MatrixBlock m5 = m3.aggregateBinaryOperations(m3, m4,
+                               new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
+               double est = estim.estim(new MMNode(new MMNode(new MMNode(m1), 
new MMNode(m2), op), new MMNode(m4), OpCode.MM)).getSparsity();
                //compare estimated and real sparsity
                TestUtils.compareScalars(est, m5.getSparsity(),
                        (estim instanceof EstimatorBasicWorst) ? 5e-1 :
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/OpBindTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/OpBindTest.java
index 3e7ad24fe8..c943a06be1 100644
--- a/src/test/java/org/apache/sysds/test/component/estim/OpBindTest.java
+++ b/src/test/java/org/apache/sysds/test/component/estim/OpBindTest.java
@@ -19,146 +19,163 @@
 
 package org.apache.sysds.test.component.estim;
 
-import org.junit.Test;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
 import org.apache.sysds.hops.estim.SparsityEstimator;
 import org.apache.sysds.hops.estim.SparsityEstimator.OpCode;
 import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 import org.apache.commons.lang3.NotImplementedException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 /**
- * this is the basic operation check for all estimators with single operations
+ * this is the basic operation check for all estimators with binding operations
  */
-public class OpBindTest extends AutomatedTestBase 
+@RunWith(value = Parameterized.class)
+public class OpBindTest extends AutomatedTestBase
 {
-       private final static int m = 600;
-       private final static int k = 300;
-       private final static int n = 100;
-       private final static double[] sparsity = new double[]{0.2, 0.4};
-//     private final static OpCode mult = OpCode.MULT;
-//     private final static OpCode plus = OpCode.PLUS;
-       private final static OpCode rbind = OpCode.RBIND;
-       private final static OpCode cbind = OpCode.CBIND;
-//     private final static OpCode eqzero = OpCode.EQZERO;
-//     private final static OpCode diag = OpCode.DIAG;
-//     private final static OpCode neqzero = OpCode.NEQZERO;
-//     private final static OpCode trans = OpCode.TRANS;
-//     private final static OpCode reshape = OpCode.RESHAPE;
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int k;
+       @Parameterized.Parameter(2)
+       public int n;
+       @Parameterized.Parameter(3)
+       public double[] sparsity;
 
        @Override
        public void setUp() {
                //do  nothing
        }
-       
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, k, n, sparsity}
+                       {600, 300, 100, new double[]{0.2, 0.4}},
+                       {600, 200, 300, new double[]{0.1, 0.15}},
+               });
+       }
+
        //Average Case
        @Test
        public void testAvgRbind() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.RBIND);
        }
        
        @Test
        public void testAvgCbind() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.CBIND);
        }
        
        //Worst Case
        @Test
        public void testWorstRbind() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), 
OpCode.RBIND);
        }
        
        @Test
        public void testWorstCbind() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), 
OpCode.CBIND);
        }
        
        //DensityMap
        /*@Test
        public void testDMCaserbind() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorDensityMap(), 
OpCode.RBIND);
        }
        
        @Test
        public void testDMCasecbind() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorDensityMap(), 
OpCode.CBIND);
        }*/
        
        //MNC
        @Test
        public void testMNCRbind() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, k, 
n, sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.RBIND);
        }
                
        @Test
        public void testMNCCbind() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, k, 
n, sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.CBIND);
        }
 
        //Bitset
        @Test
        public void testBitsetCasecbind() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.CBIND);
        }
        
        @Test
        public void testBitsetCaserbind() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.RBIND);
        }
        
        //Layered Graph
        @Test
        public void testLGCaserbind() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorLayeredGraph(), 
OpCode.RBIND);
        }
        
        @Test
        public void testLGCasecbind() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorLayeredGraph(), 
OpCode.CBIND);
        }
                
        //Sample
        /*@Test
        public void testSampleCaserbind() {
-               runSparsityEstimateTest(new EstimatorSample(), m, k, n, 
sparsity, rbind);
+               runSparsityEstimateTest(new EstimatorSample(), OpCode.RBIND);
        }
        
        @Test
        public void testSampleCasecbind() {
-               runSparsityEstimateTest(new EstimatorSample(), m, k, n, 
sparsity, cbind);
+               runSparsityEstimateTest(new EstimatorSample(), OpCode.CBIND);
        }*/
+
+       // Row Wise Sparsity Estimator
+       @Test
+       public void testRowWiseRbind() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.RBIND);
+       }
+
+       @Test
+       public void testRowWiseCbind() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.CBIND);
+       }
+
        
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int k, int n, double[] sp, OpCode op) {
+       private void runSparsityEstimateTest(SparsityEstimator estim, OpCode 
op) {
                MatrixBlock m1;
                MatrixBlock m2;
                MatrixBlock m3 = new MatrixBlock();
-               double est = 0;
                switch(op) {
                        case RBIND:
-                               m1 = MatrixBlock.randOperations(m, k, sp[0], 1, 
1, "uniform", 3);
-                               m2 = MatrixBlock.randOperations(n, k, sp[1], 1, 
1, "uniform", 3);
+                               m1 = MatrixBlock.randOperations(m, k, 
sparsity[0], 1, 1, "uniform", 3);
+                               m2 = MatrixBlock.randOperations(n, k, 
sparsity[1], 1, 1, "uniform", 3);
                                m1.append(m2, m3, false);
-                               est = estim.estim(m1, m2, op);
-                               // System.out.println(est);
-                               // System.out.println(m3.getSparsity());
                                break;
                        case CBIND:
-                               m1 = MatrixBlock.randOperations(10, 130, sp[0], 
1, 1, "uniform", 3);
-                               m2 = MatrixBlock.randOperations(10, 70, sp[1], 
1, 1, "uniform", 3);
+                               m1 = MatrixBlock.randOperations(10, 130, 
sparsity[0], 1, 1, "uniform", 3);
+                               m2 = MatrixBlock.randOperations(10, 70, 
sparsity[1], 1, 1, "uniform", 3);
                                m1.append(m2, m3);
-                               est = estim.estim(m1, m2, op);
-                               // System.out.println(est);
-                               // System.out.println(m3.getSparsity());
                                break;
                        default:
                                throw new NotImplementedException();
                }
+               double est = estim.estim(m1, m2, op);
                //compare estimated and real sparsity
                TestUtils.compareScalars(est, m3.getSparsity(),
                        (estim instanceof EstimatorBasicWorst) ? 5e-1 :
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/OpElemWChainTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/OpElemWChainTest.java
index a1b6594a92..da18067867 100644
--- a/src/test/java/org/apache/sysds/test/component/estim/OpElemWChainTest.java
+++ b/src/test/java/org/apache/sysds/test/component/estim/OpElemWChainTest.java
@@ -19,12 +19,12 @@
 
 package org.apache.sysds.test.component.estim;
 
-import org.junit.Test;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.EstimatorDensityMap;
 import org.apache.sysds.hops.estim.MMNode;
 import org.apache.sysds.hops.estim.SparsityEstimator;
@@ -36,120 +36,140 @@ import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.runtime.matrix.operators.BinaryOperator;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 import org.apache.commons.lang3.NotImplementedException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 /**
- * this is the basic operation check for all estimators with single operations
+ * this is the basic operation check for all estimators with chains of 
operations including element-wise operations
  */
+@RunWith(value = Parameterized.class)
 public class OpElemWChainTest extends AutomatedTestBase 
 {
-       private final static int m = 1600;
-       private final static int n = 700;
-       private final static double[] sparsity = new double[]{0.1, 0.04};
-       private final static OpCode mult = OpCode.MULT;
-       private final static OpCode plus = OpCode.PLUS;
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int n;
+       @Parameterized.Parameter(2)
+       public double[] sparsity;
 
        @Override
        public void setUp() {
                //do  nothing
        }
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, n, sparsity}
+                       {1600, 700, new double[]{0.1, 0.04}},
+                       {900, 1200, new double[]{0.01, 0.125}},
+               });
+       }
+
        //Average Case
        @Test
        public void testAvgMult() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.MULT);
        }
        
        @Test
        public void testAvgPlus() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.PLUS);
        }
        
        //Worst Case
        @Test
        public void testWorstMult() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), OpCode.MULT);
        }
        
        @Test
        public void testWorstPlus() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), OpCode.PLUS);
        }
        
        //DensityMap
        @Test
        public void testDMMult() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorDensityMap(), OpCode.MULT);
        }
        
        @Test
        public void testDMPlus() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorDensityMap(), OpCode.PLUS);
        }
        
        //MNC
        @Test
        public void testMNCMult() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.MULT);
        }
        
        @Test
        public void testMNCPlus() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.PLUS);
        }
        
        //Bitset
        @Test
        public void testBitsetMult() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.MULT);
        }
        
        @Test
        public void testBitsetPlus() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.PLUS);
        }
        
        //Layered Graph
        @Test
        public void testLGCasemult() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), OpCode.MULT);
        }
                
        @Test
        public void testLGCaseplus() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), OpCode.PLUS);
        }
-       
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int n, double[] sp, OpCode op) {
-               MatrixBlock m1 = MatrixBlock.randOperations(m, n, sp[0], 1, 1, 
"uniform", 3);
-               MatrixBlock m2 = MatrixBlock.randOperations(m, n, sp[1], 1, 1, 
"uniform", 5);
-               MatrixBlock m3 = MatrixBlock.randOperations(n, m, sp[1], 1, 1, 
"uniform", 7);
+
+       // Row Wise Sparsity Estimator
+       @Test
+       public void testRowWiseCaseMult() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.MULT);
+       }
+
+       @Test
+       public void testRowWiseCasePlus() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.PLUS);
+       }
+
+       private void runSparsityEstimateTest(SparsityEstimator estim, OpCode 
op) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, n, sparsity[0], 
1, 1, "uniform", 3);
+               MatrixBlock m2 = MatrixBlock.randOperations(m, n, sparsity[1], 
1, 1, "uniform", 5);
+               MatrixBlock m3 = MatrixBlock.randOperations(n, m, sparsity[1], 
1, 1, "uniform", 7);
                MatrixBlock m4 = new MatrixBlock();
-               MatrixBlock m5 = new MatrixBlock();
                BinaryOperator bOp;
-               double est = 0;
                switch(op) {
                        case MULT:
                                bOp = new 
BinaryOperator(Multiply.getMultiplyFnObject());
-                               m1.binaryOperations(bOp, m2, m4);
-                               m5 = m4.aggregateBinaryOperations(m4, m3, 
-                                               new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
-                               est = estim.estim(new MMNode(new MMNode(new 
MMNode(m1), new MMNode(m2), op), new MMNode(m3), OpCode.MM)).getSparsity();
-                               // System.out.println(m5.getSparsity());
-                               // System.out.println(est);
                                break;
                        case PLUS:
                                bOp = new 
BinaryOperator(Plus.getPlusFnObject());
-                               m1.binaryOperations(bOp, m2, m4);
-                               m5 = m4.aggregateBinaryOperations(m4, m3, 
-                                               new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
-                               est = estim.estim(new MMNode(new MMNode(new 
MMNode(m1), new MMNode(m2), op), new MMNode(m3), OpCode.MM)).getSparsity();
-                               // System.out.println(m5.getSparsity());
-                               // System.out.println(est);
                                break;
                        default:
                                throw new NotImplementedException();
                }
+               m1.binaryOperations(bOp, m2, m4);
+               MatrixBlock m5 = m4.aggregateBinaryOperations(m4, m3,
+                               new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
+               double est = estim.estim(new MMNode(new MMNode(new MMNode(m1), 
new MMNode(m2), op), new MMNode(m3), OpCode.MM)).getSparsity();
+
                //compare estimated and real sparsity
                TestUtils.compareScalars(est, m5.getSparsity(), (estim 
instanceof EstimatorBasicWorst) ? 9e-1 :
                        (estim instanceof EstimatorLayeredGraph) ? 7e-2 : 1e-2);
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/OpElemWTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/OpElemWTest.java
index f8ddb91bce..311ae50cb5 100644
--- a/src/test/java/org/apache/sysds/test/component/estim/OpElemWTest.java
+++ b/src/test/java/org/apache/sysds/test/component/estim/OpElemWTest.java
@@ -19,12 +19,12 @@
 
 package org.apache.sysds.test.component.estim;
 
-import org.junit.Test;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorDensityMap;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
 import org.apache.sysds.hops.estim.EstimatorSample;
 import org.apache.sysds.hops.estim.SparsityEstimator;
@@ -35,124 +35,148 @@ import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.runtime.matrix.operators.BinaryOperator;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 import org.apache.commons.lang3.NotImplementedException;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 /**
- * this is the basic operation check for all estimators with single operations
+ * this is the basic operation check for all estimators with element-wise 
operations
  */
+@RunWith(value = Parameterized.class)
 public class OpElemWTest extends AutomatedTestBase 
 {
-       private final static int m = 1600;
-       private final static int n = 700;
-       private final static double[] sparsity = new double[]{0.2, 0.4};
-       private final static OpCode mult = OpCode.MULT;
-       private final static OpCode plus = OpCode.PLUS;
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int n;
+       @Parameterized.Parameter(2)
+       public double[] sparsity;
 
        @Override
        public void setUp() {
                //do  nothing
        }
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, n, sparsity}
+                       {1600, 700, new double[]{0.2, 0.4}},
+                       {900, 1200, new double[]{0.01, 0.125}},
+               });
+       }
+
        //Average Case
        @Test
        public void testAvgMult() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.MULT);
        }
        
        @Test
        public void testAvgPlus() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), OpCode.PLUS);
        }
        
        //Worst Case
        @Test
        public void testWorstMult() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), OpCode.MULT);
        }
        
        @Test
        public void testWorstPlus() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), OpCode.PLUS);
        }
        
        //DensityMap
        @Test
        public void testDMMult() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorDensityMap(), OpCode.MULT);
        }
        
        @Test
        public void testDMPlus() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorDensityMap(), OpCode.PLUS);
        }
        
        //MNC
        @Test
        public void testMNCMult() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.MULT);
        }
        
        @Test
        public void testMNCPlus() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(), 
OpCode.PLUS);
        }
        
        //Bitset
        @Test
        public void testBitsetMult() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.MULT);
        }
        
        @Test
        public void testBitsetPlus() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), OpCode.PLUS);
        }
 
        //Layered Graph
        @Test
        public void testLGCasemult() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, n, 
sparsity, mult);
+               runSparsityEstimateTest(new EstimatorLayeredGraph(), 
OpCode.MULT);
        }
        
        @Test
        public void testLGCaseplus() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, n, 
sparsity, plus);
+               runSparsityEstimateTest(new EstimatorLayeredGraph(), 
OpCode.PLUS);
        }
        
        //Sample
        @Test
        public void testSampleMult() {
-               runSparsityEstimateTest(new EstimatorSample(), m, n, sparsity, 
mult);
+               runSparsityEstimateTest(new EstimatorSample(), OpCode.MULT);
        }
        
        @Test
        public void testSamplePlus() {
-               runSparsityEstimateTest(new EstimatorSample(), m, n, sparsity, 
plus);
+               runSparsityEstimateTest(new EstimatorSample(), OpCode.PLUS);
        }
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int n, double[] sp, OpCode op) {
-               MatrixBlock m1 = MatrixBlock.randOperations(m, n, sp[0], 1, 1, 
"uniform", 3);
-               MatrixBlock m2 = MatrixBlock.randOperations(m, n, sp[1], 1, 1, 
"uniform", 7);
+
+       // Row Wise Sparsity Estimator
+       @Test
+       public void testRowWiseMult() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.MULT);
+       }
+
+       @Test
+       public void testRowWisePlus() {
+               runSparsityEstimateTest(new EstimatorRowWise(), OpCode.PLUS);
+       }
+
+       private void runSparsityEstimateTest(SparsityEstimator estim, OpCode 
op) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, n, sparsity[0], 
1, 1, "uniform", 3);
+               MatrixBlock m2 = MatrixBlock.randOperations(m, n, sparsity[1], 
1, 1, "uniform", 7);
                MatrixBlock m3 = new MatrixBlock();
                BinaryOperator bOp;
-               double est = 0;
                switch(op) {
                        case MULT:
                                bOp = new 
BinaryOperator(Multiply.getMultiplyFnObject());
-                               m1.binaryOperations(bOp, m2, m3);
-                               est = estim.estim(m1, m2, op);
-                               // System.out.println(est);
-                               // System.out.println(m3.getSparsity());
                                break;
                        case PLUS:
                                bOp = new 
BinaryOperator(Plus.getPlusFnObject());
-                               m1.binaryOperations(bOp, m2, m3);
-                               est = estim.estim(m1, m2, op);
-                               // System.out.println(est);
-                               // System.out.println(m3.getSparsity());
                                break;
-                       default:
-                               throw new NotImplementedException();
+                               default:
+                                       throw new NotImplementedException();
                }
+               m1.binaryOperations(bOp, m2, m3);
+               double est = estim.estim(m1, m2, op);
                //compare estimated and real sparsity
                TestUtils.compareScalars(est, m3.getSparsity(), (estim 
instanceof EstimatorBasicWorst) ? 5e-1 :
                        (estim instanceof EstimatorLayeredGraph) ? 3e-2 : 5e-3);
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/OpSingleTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/OpSingleTest.java
index d40f84c4fb..14696fa572 100644
--- a/src/test/java/org/apache/sysds/test/component/estim/OpSingleTest.java
+++ b/src/test/java/org/apache/sysds/test/component/estim/OpSingleTest.java
@@ -19,255 +19,297 @@
 
 package org.apache.sysds.test.component.estim;
 
-import org.apache.sysds.runtime.matrix.data.LibMatrixReorg;
-import org.junit.Test;
 import org.apache.commons.lang3.NotImplementedException;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.SparsityEstimator;
 import org.apache.sysds.hops.estim.SparsityEstimator.OpCode;
 import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
 
+import org.apache.sysds.runtime.matrix.data.LibMatrixReorg;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 /**
  * this is the basic operation check for all estimators with single operations
  */
+@RunWith(value = Parameterized.class)
 public class OpSingleTest extends AutomatedTestBase 
 {
-       private final static int m = 600;
-       private final static int k = 300;
-       private final static double sparsity = 0.2;
-//     private final static OpCode eqzero = OpCode.EQZERO;
-       private final static OpCode diag = OpCode.DIAG;
-       private final static OpCode neqzero = OpCode.NEQZERO;
-       private final static OpCode trans = OpCode.TRANS;
-       private final static OpCode reshape = OpCode.RESHAPE;
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int k_param;
+       @Parameterized.Parameter(2)
+       public double sparsity;
 
        @Override
        public void setUp() {
                //do  nothing
        }
-       
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, k_param, sparsity}
+                       {600, 300, 0.2},
+                       {200, 1200, 0.6},
+               });
+       }
+
        //Average Case
 //     @Test
 //     public void testAvgEqzero() {
-//             runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, 
sparsity, eqzero);
+//             runSparsityEstimateTest(new EstimatorBasicAvg(), k_param, 
OpCode.EQZERO);
 //     }
        
 //     @Test
 //     public void testAvgDiag() {
-//             runSparsityEstimateTest(new EstimatorBasicAvg(), m, m, 
sparsity, diag);
+//             runSparsityEstimateTest(new EstimatorBasicAvg(), m, 
OpCode.DIAG);
 //     }
        
        @Test
        public void testAvgNeqzero() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, 
sparsity, neqzero);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), k_param, 
OpCode.NEQZERO);
        }
        
        @Test
        public void testAvgTrans() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, 
sparsity, trans);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), k_param, 
OpCode.TRANS);
        }
        
        @Test
        public void testAvgReshape() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, 
sparsity, reshape);
+               runSparsityEstimateTest(new EstimatorBasicAvg(), k_param, 
OpCode.RESHAPE);
        }
        
        //Worst Case
 //     @Test
 //     public void testWorstEqzero() {
-//             runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, 
sparsity, eqzero);
+//             runSparsityEstimateTest(new EstimatorBasicWorst(), k_param, 
OpCode.EQZERO);
 //     }
        
 //     @Test
 //     public void testWCasediag() {
-//             runSparsityEstimateTest(new EstimatorBasicWorst(), m, m, 
sparsity, diag);
+//             runSparsityEstimateTest(new EstimatorBasicWorst(), m, 
OpCode.DIAG);
 //     }
        
        @Test
        public void testWorstNeqzero() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, 
sparsity, neqzero);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), k_param, 
OpCode.NEQZERO);
        }
        
        @Test
        public void testWoestTrans() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, 
sparsity, trans);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), k_param, 
OpCode.TRANS);
        }
        
        @Test
        public void testWorstReshape() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, 
sparsity, reshape);
+               runSparsityEstimateTest(new EstimatorBasicWorst(), k_param, 
OpCode.RESHAPE);
        } 
        
 //     //DensityMap
 //     @Test
 //     public void testDMCaseeqzero() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, eqzero);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.EQZERO);
 //     }
 //     
 //     @Test
 //     public void testDMCasediag() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, m, 
sparsity, diag);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), m, 
OpCode.DIAG);
 //     }
 //     
 //     @Test
 //     public void testDMCaseneqzero() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, neqzero);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.NEQZERO);
 //     }
 //     
 //     @Test
 //     public void testDMCasetrans() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, trans);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.TRANS);
 //     }
 //             
 //     @Test
 //     public void testDMCasereshape() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, reshape);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.RESHAPE);
 //     }
 //     
 //     //MNC
 //     @Test
 //     public void testMNCCaseeqzero() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, eqzero);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.EQZERO);
 //     }
 //     
 //     @Test
 //     public void testMNCCasediag() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, m, 
sparsity, diag);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), m, 
OpCode.DIAG);
 //     }
 //     
 //     @Test
 //     public void testMNCCaseneqzero() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, neqzero);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.NEQZERO);
 //     }
 //     
 //     @Test
 //     public void testMNCCasetrans() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, trans);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.TRANS);
 //     }
 //     
 //     @Test
 //     public void testMNCCasereshape() {
-//             runSparsityEstimateTest(new EstimatorDensityMap(), m, k, 
sparsity, reshape);
+//             runSparsityEstimateTest(new EstimatorDensityMap(), k_param, 
OpCode.RESHAPE);
 //     }
 //     
        //Bitset
 //     @Test
 //     public void testBitsetCaseeqzero() {
-//             runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, 
sparsity, eqzero);
+//             runSparsityEstimateTest(new EstimatorBitsetMM(), k_param, 
OpCode.EQZERO);
 //     }
        
 //     @Test
 //     public void testBitsetCasediag() {
-//             runSparsityEstimateTest(new EstimatorBitsetMM(), m, m, 
sparsity, diag);
+//             runSparsityEstimateTest(new EstimatorBitsetMM(), m, 
OpCode.DIAG);
 //     }
        
        @Test
        public void testBitsetNeqzero() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, 
sparsity, neqzero);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), k_param, 
OpCode.NEQZERO);
        }
        
        @Test
        public void testBitsetTrans() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, 
sparsity, trans);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), k_param, 
OpCode.TRANS);
        }
        
        @Test
        public void testBitsetReshape() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, 
sparsity, reshape);
+               runSparsityEstimateTest(new EstimatorBitsetMM(), k_param, 
OpCode.RESHAPE);
        }
        
 //     //Layered Graph
 //     @Test
 //     public void testLGCaseeqzero() {
-//             runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, 
sparsity, eqzero);
+//             runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), k_param, 
OpCode.EQZERO);
 //     }
 //     
        @Test
        public void testLGCasediagM() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, m, 
sparsity, diag);
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), m, OpCode.DIAG);
        }
 
        @Test
        public void testLGCasediagV() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, 1, 
sparsity, diag);
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), 1, OpCode.DIAG);
        }
 //     
 //     @Test
 //     public void testLGCaseneqzero() {
-//             runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, 
sparsity, neqzero);
+//             runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), k_param, 
OpCode.NEQZERO);
 //     }
 //     
        @Test
        public void testLGCasetrans() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, 
sparsity, trans);
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), k_param, OpCode.TRANS);
        }
 
 //     @Test
 //     public void testLGCasereshape() {
-//             runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, 
sparsity, reshape);
+//             runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13), k_param, 
OpCode.RESHAPE);
 //     }
 //     
 //     //Sample
 //     @Test
 //     public void testSampleCaseeqzero() {
-//             runSparsityEstimateTest(new EstimatorSample(), m, k, sparsity, 
eqzero);
+//             runSparsityEstimateTest(new EstimatorSample(), k_param, 
OpCode.EQZERO);
 //     }
 //     
 //     @Test
 //     public void testSampleCasediag() {
-//             runSparsityEstimateTest(new EstimatorSample(), m, m, sparsity, 
diag);
+//             runSparsityEstimateTest(new EstimatorSample(), m, OpCode.DIAG);
 //     }
 //     
 //     @Test
 //     public void testSampleCaseneqzero() {
-//             runSparsityEstimateTest(new EstimatorSample(), m, k, sparsity, 
neqzero);
+//             runSparsityEstimateTest(new EstimatorSample(), k_param, 
OpCode.NEQZERO);
 //     }
 //     
 //     @Test
 //     public void testSampleCasetrans() {
-//             runSparsityEstimateTest(new EstimatorSample(), m, k, sparsity, 
trans);
+//             runSparsityEstimateTest(new EstimatorSample(), k_param, 
OpCode.TRANS);
 //     }
 //     
 //     @Test
 //     public void testSampleCasereshape() {
-//             runSparsityEstimateTest(new EstimatorSample(), m, k, sparsity, 
reshape);
+//             runSparsityEstimateTest(new EstimatorSample(), k_param, 
OpCode.RESHAPE);
 //     }
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int k, double sp, OpCode op) {
-               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sp, 1, 1, 
"uniform", 3);
-               MatrixBlock m2 = new MatrixBlock();
-               double est = 0;
+
+       // Row Wise Sparsity Estimator
+       @Test
+       public void testRowWiseEqzero() {
+               runSparsityEstimateTest(new EstimatorRowWise(), k_param, 
OpCode.EQZERO);
+       }
+
+       @Test
+       public void testRowWiseDiagM() {
+               runSparsityEstimateTest(new EstimatorRowWise(), m, OpCode.DIAG);
+       }
+
+       @Test
+       public void testRowWiseDiagV() {
+               runSparsityEstimateTest(new EstimatorRowWise(), 1, OpCode.DIAG);
+       }
+
+       @Test
+       public void testRowWiseNeqzero() {
+               runSparsityEstimateTest(new EstimatorRowWise(), k_param, 
OpCode.NEQZERO);
+       }
+
+       @Test
+       public void testRowWiseTrans() {
+               runSparsityEstimateTest(new EstimatorRowWise(), k_param, 
OpCode.TRANS);
+       }
+
+       @Test
+       public void testRowWiseReshape() {
+               runSparsityEstimateTest(new EstimatorRowWise(), k_param, 
OpCode.RESHAPE);
+       }
+
+       private void runSparsityEstimateTest(SparsityEstimator estim, int k, 
OpCode op) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sparsity, 1, 
1, "uniform", 3);
+               MatrixBlock m2;
+               double ref = -1;
                switch(op) {
                        case EQZERO:
-                               //TODO find out how to do eqzero
+                               ref = 1 - m1.getSparsity();
+                               break;
                        case DIAG:
                                m2 = m1.getNumColumns() == 1
                                                ? LibMatrixReorg.diag(m1, new 
MatrixBlock(m1.getNumRows(), m1.getNumRows(), false))
                                                : LibMatrixReorg.diag(m1, new 
MatrixBlock(m1.getNumRows(), 1, false));
-                               est = estim.estim(m1, op);
+                               ref = m2.getSparsity();
                                break;
                        case NEQZERO:
-                               m2 = m1;
-                               est = estim.estim(m1, op);
-                               break;
                        case TRANS:
-                               m2 = m1;
-                               est = estim.estim(m1, op);
-                               break;
                        case RESHAPE:
                                m2 = m1;
-                               est = estim.estim(m1, op);
+                               ref = m2.getSparsity();
                                break;
                        default:
                                throw new NotImplementedException();
                }
+               double est = estim.estim(m1, op);
                //compare estimated and real sparsity
-               TestUtils.compareScalars(est, m2.getSparsity(),
+               TestUtils.compareScalars(est, ref,
                        (estim instanceof EstimatorBasicWorst) ? 5e-1 :
                        (estim instanceof EstimatorLayeredGraph) ? 3e-2 : 2e-2);
        }
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/OuterProductTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/OuterProductTest.java
index fdc33d878d..f0486a58ca 100644
--- a/src/test/java/org/apache/sysds/test/component/estim/OuterProductTest.java
+++ b/src/test/java/org/apache/sysds/test/component/estim/OuterProductTest.java
@@ -20,12 +20,19 @@
 package org.apache.sysds.test.component.estim;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorDensityMap;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.EstimatorSample;
 import org.apache.sysds.hops.estim.SparsityEstimator;
 import org.apache.sysds.runtime.instructions.InstructionUtils;
@@ -37,122 +44,90 @@ import org.apache.sysds.test.TestUtils;
  * This is a basic sanity check for all estimator, which need
  * to compute the exact sparsity for the special case of outer products.
  */
-public class OuterProductTest extends AutomatedTestBase 
+@RunWith(value = Parameterized.class)
+public class OuterProductTest extends AutomatedTestBase
 {
-       private final static int m = 1154;
-       private final static int k = 1;
-       private final static int n = 900;
-       private final static double[] case1 = new double[]{0.1, 0.7};
-       private final static double[] case2 = new double[]{0.6, 0.7};
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int k;
+       @Parameterized.Parameter(2)
+       public int n;
+       @Parameterized.Parameter(3)
+       public double[] sparsity;
 
        @Override
        public void setUp() {
                //do  nothing
        }
        
-       @Test
-       public void testBasicAvgCase1() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
case1);
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, k, n, sparsity}
+                       {1154, 1, 900, new double[]{0.1, 0.7}},
+                       {1154, 1, 900, new double[]{0.6, 0.7}},
+               });
        }
-       
+
        @Test
-       public void testBasicAvgCase2() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
case2);
+       public void testBasicAvgCase1() {
+               runSparsityEstimateTest(new EstimatorBasicAvg());
        }
        
        @Test
        public void testBasicWorstCase1() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testBasicWorstCase2() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
case2);
+               runSparsityEstimateTest(new EstimatorBasicWorst());
        }
        
        @Test
        public void testDensityMapCase1() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testDensityMapCase2() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
case2);
+               runSparsityEstimateTest(new EstimatorDensityMap());
        }
        
        @Test
        public void testDensityMap7Case1() {
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testDensityMap7Case2() {
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, k, n, 
case2);
+               runSparsityEstimateTest(new EstimatorDensityMap(7));
        }
        
        @Test
        public void testBitsetMatrixCase1() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testBitsetMatrixCase2() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
case2);
+               runSparsityEstimateTest(new EstimatorBitsetMM());
        }
        
        @Test
        public void testMatrixHistogramCase1() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
k, n, case1);
-       }
-       
-       @Test
-       public void testMatrixHistogramCase2() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
k, n, case2);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(false));
        }
        
        @Test
        public void testMatrixHistogramExceptCase1() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
k, n, case1);
-       }
-       
-       @Test
-       public void testMatrixHistogramExceptCase2() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
k, n, case2);
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(true));
        }
        
        @Test
        public void testSamplingDefCase1() {
-               runSparsityEstimateTest(new EstimatorSample(), m, k, n, case1);
-       }
-       
-       @Test
-       public void testSamplingDefCase2() {
-               runSparsityEstimateTest(new EstimatorSample(), m, k, n, case2);
+               runSparsityEstimateTest(new EstimatorSample());
        }
        
        @Test
        public void testSampling20Case1() {
-               runSparsityEstimateTest(new EstimatorSample(0.2), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testSampling20Case2() {
-               runSparsityEstimateTest(new EstimatorSample(0.2), m, k, n, 
case2);
+               runSparsityEstimateTest(new EstimatorSample(0.2));
        }
 
        @Test
        public void testLayeredGraphCase1() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
case1);
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13));
        }
 
        @Test
-       public void testLayeredGraphCase2() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
case2);
+       public void testRowWiseCase1() {
+               runSparsityEstimateTest(new EstimatorRowWise());
        }
 
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int k, int n, double[] sp) {
-               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sp[0], 1, 1, 
"uniform", 3);
-               MatrixBlock m2 = MatrixBlock.randOperations(k, n, sp[1], 1, 1, 
"uniform", 3);
+       private void runSparsityEstimateTest(SparsityEstimator estim) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sparsity[0], 
1, 1, "uniform", 3);
+               MatrixBlock m2 = MatrixBlock.randOperations(k, n, sparsity[1], 
1, 1, "uniform", 3);
                MatrixBlock m3 = m1.aggregateBinaryOperations(m1, m2, 
                        new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
                
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/SelfProductTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/SelfProductTest.java
index d99f38d939..58e7f2195c 100644
--- a/src/test/java/org/apache/sysds/test/component/estim/SelfProductTest.java
+++ b/src/test/java/org/apache/sysds/test/component/estim/SelfProductTest.java
@@ -19,7 +19,14 @@
 
 package org.apache.sysds.test.component.estim;
 
+import org.junit.Assume;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 import org.apache.sysds.hops.OptimizerUtils;
 import org.apache.sysds.hops.estim.EstimationUtils;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
@@ -28,6 +35,7 @@ import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorDensityMap;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.EstimatorSample;
 import org.apache.sysds.hops.estim.EstimatorSampleRa;
 import org.apache.sysds.hops.estim.SparsityEstimator;
@@ -36,142 +44,118 @@ import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
 
-public class SelfProductTest extends AutomatedTestBase 
+@RunWith(value = Parameterized.class)
+public class SelfProductTest extends AutomatedTestBase
 {
-       private final static int m = 2500;
-       private final static double sparsity0 = 0.5;
-       private final static double sparsity1 = 0.1;
-       private final static double sparsity2 = 0.0001;
-       private final static double sparsity3 = 0.000001;
-       private final static double eps1 = 0.05;
-       private final static double eps2 = 1e-4;
-       private final static double eps3 = 0;
-       
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public double sparsity;
        
        @Override
        public void setUp() {
                //do  nothing
        }
-       
-       @Test
-       public void testBasicAvgCase() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m/4, 
sparsity0);
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m/2, 
sparsity1);
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, sparsity2);
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, sparsity3);
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, sparsity}
+                       {625, 0.5},
+                       {1250, 0.1},
+                       {2500, 0.0001},
+                       {2500, 0.000001},
+               });
        }
-       
+
        @Test
-       public void testDensityMapCase() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m/4, 
sparsity0);
-               runSparsityEstimateTest(new EstimatorDensityMap(), m/2, 
sparsity1);
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, 
sparsity2);
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, 
sparsity3);
+       public void testBasicAvg() {
+               runSparsityEstimateTest(new EstimatorBasicAvg());
        }
        
        @Test
-       public void testDensityMap7Case() {
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m/4, 
sparsity0);
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m/2, 
sparsity1);
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, 
sparsity2);
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, 
sparsity3);
+       public void testDensityMap() {
+               runSparsityEstimateTest(new EstimatorDensityMap());
        }
        
        @Test
-       public void testBitsetMatrixCase() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m/4, 
sparsity0);
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m/2, 
sparsity1);
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, sparsity2);
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, sparsity3);
+       public void testDensityMapBlocksize7() {
+               runSparsityEstimateTest(new EstimatorDensityMap(7));
        }
        
        @Test
-       public void testBitset2MatrixCase() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(2), m/4, 
sparsity0);
-               runSparsityEstimateTest(new EstimatorBitsetMM(2), m/2, 
sparsity1);
-               runSparsityEstimateTest(new EstimatorBitsetMM(2), m, sparsity2);
-               runSparsityEstimateTest(new EstimatorBitsetMM(2), m, sparsity3);
+       public void testBitsetMatrix() {
+               runSparsityEstimateTest(new EstimatorBitsetMM());
        }
        
        @Test
-       public void testMatrixHistogramCase() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), 
m/4, sparsity0);
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), 
m/2, sparsity1);
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
sparsity2);
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
sparsity3);
+       public void testBitsetMatrixType2() {
+               runSparsityEstimateTest(new EstimatorBitsetMM(2));
        }
        
        @Test
-       public void testMatrixHistogramExceptCase() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), 
m/4, sparsity0);
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), 
m/2, sparsity1);
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
sparsity2);
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
sparsity3);
+       public void testMatrixHistogram() {
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(false));
        }
        
        @Test
-       public void testSamplingDefCase() {
-               runSparsityEstimateTest(new EstimatorSample(), m, sparsity2);
-               runSparsityEstimateTest(new EstimatorSample(), m, sparsity3);
+       public void testMatrixHistogramExtended() {
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(true));
        }
        
        @Test
-       public void testSampling20Case() {
-               runSparsityEstimateTest(new EstimatorSample(0.2), m, sparsity2);
-               runSparsityEstimateTest(new EstimatorSample(0.2), m, sparsity3);
+       public void testSampling() {
+               Assume.assumeTrue(sparsity < 0.1);
+               runSparsityEstimateTest(new EstimatorSample());
        }
        
        @Test
-       public void testSamplingRaDefCase() {
-               runSparsityEstimateTest(new EstimatorSampleRa(), m/4, 
sparsity0);
-               runSparsityEstimateTest(new EstimatorSampleRa(), m, sparsity2);
-               runSparsityEstimateTest(new EstimatorSampleRa(), m, sparsity3);
+       public void testSamplingFrac20() {
+               Assume.assumeTrue(sparsity < 0.1);
+               runSparsityEstimateTest(new EstimatorSample(0.2));
        }
        
        @Test
-       public void testSamplingRa20Case() {
-               runSparsityEstimateTest(new EstimatorSampleRa(0.2), m/4, 
sparsity0);
-               runSparsityEstimateTest(new EstimatorSampleRa(0.2), m, 
sparsity2);
-               runSparsityEstimateTest(new EstimatorSampleRa(0.2), m, 
sparsity3);
+       public void testSamplingRa() {
+               runSparsityEstimateTest(new EstimatorSampleRa());
        }
        
        @Test
-       public void testLayeredGraphDefCase() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, 
sparsity2);
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, 
sparsity3);
+       public void testSamplingRaFrac20() {
+               runSparsityEstimateTest(new EstimatorSampleRa(0.2));
        }
        
        @Test
-       public void testLayeredGraph64Case() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(64), m, 
sparsity2);
-               runSparsityEstimateTest(new EstimatorLayeredGraph(64), m, 
sparsity3);
+       public void testLayeredGraph() {
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13));
        }
 
        @Test
-       public void testLayeredGraphCase1() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, 
sparsity1);
+       public void testLayeredGraph64Rounds() {
+               runSparsityEstimateTest(new EstimatorLayeredGraph(64, 13));
        }
 
        @Test
-       public void testLayeredGraphCase2() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, 
sparsity2);
+       public void testRowWise() {
+               runSparsityEstimateTest(new EstimatorRowWise());
        }
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int n, double sp) {
-               MatrixBlock m1 = MatrixBlock.randOperations(n, n, sp, 1, 1, 
"uniform", 3);
+
+       private void runSparsityEstimateTest(SparsityEstimator estim) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, m, sparsity, 1, 
1, "uniform", 3);
                MatrixBlock m3 = m1.aggregateBinaryOperations(m1, m1, 
                        new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
-               double spExact1 = OptimizerUtils.getSparsity(n, n,
+               double spExact1 = OptimizerUtils.getSparsity(m, m,
                        EstimationUtils.getSelfProductOutputNnz(m1));
-               double spExact2 = sp<0.4 ? OptimizerUtils.getSparsity(n, n,
+               double spExact2 = sparsity<0.4 ? OptimizerUtils.getSparsity(m, 
m,
                        EstimationUtils.getSparseProductOutputNnz(m1, m1)) : 
spExact1;
                
                //compare estimated and real sparsity
                double est = estim.estim(m1, m1);
                TestUtils.compareScalars(est, m3.getSparsity(),
-                       (estim instanceof EstimatorBitsetMM) ? eps3 : //exact
-                       (estim instanceof EstimatorBasicWorst || estim 
instanceof EstimatorLayeredGraph) ? eps1 : eps2);
-               TestUtils.compareScalars(m3.getSparsity(), spExact1, eps3);
-               TestUtils.compareScalars(m3.getSparsity(), spExact2, eps3);
+                       (estim instanceof EstimatorBitsetMM) ? 0 : //exact
+                       (estim instanceof EstimatorBasicWorst || estim 
instanceof EstimatorLayeredGraph) ? 0.05 :
+                       (sparsity == 0.1 && estim instanceof EstimatorSampleRa) 
? 0.12 : 1e-4);
+               TestUtils.compareScalars(m3.getSparsity(), spExact1, 0);
+               TestUtils.compareScalars(m3.getSparsity(), spExact2, 0);
        }
 }
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/SquaredProductChainTest.java
 
b/src/test/java/org/apache/sysds/test/component/estim/SquaredProductChainTest.java
index f799b02c96..a2b04b34df 100644
--- 
a/src/test/java/org/apache/sysds/test/component/estim/SquaredProductChainTest.java
+++ 
b/src/test/java/org/apache/sysds/test/component/estim/SquaredProductChainTest.java
@@ -19,13 +19,13 @@
 
 package org.apache.sysds.test.component.estim;
 
-import org.junit.Test;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorDensityMap;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.MMNode;
 import org.apache.sysds.hops.estim.SparsityEstimator;
 import org.apache.sysds.hops.estim.SparsityEstimator.OpCode;
@@ -34,123 +34,99 @@ import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 /**
  * This is a basic sanity check for all estimator, which need
  * to compute a reasonable estimate for uniform data.
  */
-public class SquaredProductChainTest extends AutomatedTestBase 
+@RunWith(value = Parameterized.class)
+public class SquaredProductChainTest extends AutomatedTestBase
 {
-       private final static int m = 1000;
-       private final static int k = 1000;
-       private final static int n = 1000;
-       private final static int n2 = 1000;
-       private final static double[] case1 = new double[]{0.0001, 0.00007, 
0.001};
-       private final static double[] case2 = new double[]{0.0006, 0.00007, 
0.001};
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int k;
+       @Parameterized.Parameter(2)
+       public int n;
+       @Parameterized.Parameter(3)
+       public int n2;
+       @Parameterized.Parameter(4)
+       public double[] sparsity;
 
-       private final static double eps1 = 1.0;
-       private final static double eps2 = 1e-4;
-       private final static double eps3 = 0;
-       
-       
        @Override
        public void setUp() {
                //do  nothing
        }
-       
-       @Test
-       public void testBasicAvgCase1() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, n2, 
case1);
-       }
-       
-       @Test
-       public void testBasicAvgCase2() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, n2, 
case2);
-       }
-       
-       @Test
-       public void testBasicWorstCase1() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, n2, 
case1);
-       }
-       
-       @Test
-       public void testBasicWorstCase2() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, n2, 
case2);
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, k, n, n2, sparsity}
+                       {1000, 1000, 1000, 1000, new double[]{0.0001, 0.00007, 
0.001}},
+                       {1000, 1000, 1000, 1000, new double[]{0.0006, 0.00007, 
0.001}},
+               });
        }
        
        @Test
-       public void testDensityMapCase1() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, n2, 
case1);
+       public void testBasicAvg() {
+               runSparsityEstimateTest(new EstimatorBasicAvg());
        }
        
        @Test
-       public void testDensityMapCase2() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, n2, 
case2);
+       public void testBasicWorst() {
+               runSparsityEstimateTest(new EstimatorBasicWorst());
        }
        
        @Test
-       public void testDensityMap7Case1() {
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, k, n, 
n2, case1);
+       public void testDensityMap() {
+               runSparsityEstimateTest(new EstimatorDensityMap());
        }
        
        @Test
-       public void testDensityMap7Case2() {
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, k, n, 
n2, case2);
+       public void testDensityMapBlocksize7() {
+               runSparsityEstimateTest(new EstimatorDensityMap(7));
        }
        
        @Test
-       public void testBitsetMatrixCase1() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, n2, 
case1);
+       public void testBitsetMatrix() {
+               runSparsityEstimateTest(new EstimatorBitsetMM());
        }
        
        @Test
-       public void testBitsetMatrixCase2() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, n2, 
case2);
+       public void testMatrixHistogram() {
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(false));
        }
        
        @Test
-       public void testMatrixHistogramCase1() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
k, n, n2, case1);
+       public void testMatrixHistogramExcept() {
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(true));
        }
        
        @Test
-       public void testMatrixHistogramCase2() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
k, n, n2, case2);
+       public void testLayeredGraph() {
+               runSparsityEstimateTest(new 
EstimatorLayeredGraph(EstimatorLayeredGraph.ROUNDS, 13));
        }
        
        @Test
-       public void testMatrixHistogramExceptCase1() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
k, n, n2, case1);
+       public void testLayeredGraph32Rounds() {
+               runSparsityEstimateTest(new EstimatorLayeredGraph(32, 13));
        }
        
        @Test
-       public void testMatrixHistogramExceptCase2() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
k, n, n2, case2);
-       }
-
-       @Test
-       public void testLayeredGraphCase1() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
n2, case1);
+       public void testRowWise() {
+               runSparsityEstimateTest(new EstimatorRowWise());
        }
 
-       @Test
-       public void testLayeredGraphCase2() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
n2, case2);
-       }
-       
-       @Test
-       public void testLayeredGraph32Case1() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(32), m, k, n, 
n2, case1);
-       }
-       
-       @Test
-       public void testLayeredGraph32Case2() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(32), m, k, n, 
n2, case2);
-       }
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int k, int n, int n2, double[] sp) {
-               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sp[0], 1, 1, 
"uniform", 1);
-               MatrixBlock m2 = MatrixBlock.randOperations(k, n, sp[1], 1, 1, 
"uniform", 2);
-               MatrixBlock m3 = MatrixBlock.randOperations(n, n2, sp[2], 1, 1, 
"uniform", 3);
+       private void runSparsityEstimateTest(SparsityEstimator estim) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sparsity[0], 
1, 1, "uniform", 1);
+               MatrixBlock m2 = MatrixBlock.randOperations(k, n, sparsity[1], 
1, 1, "uniform", 2);
+               MatrixBlock m3 = MatrixBlock.randOperations(n, n2, sparsity[2], 
1, 1, "uniform", 3);
                MatrixBlock m4 = m1.aggregateBinaryOperations(m1, m2, 
                        new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
                MatrixBlock m5 = m4.aggregateBinaryOperations(m4, m3, 
@@ -160,7 +136,7 @@ public class SquaredProductChainTest extends 
AutomatedTestBase
                double est = estim.estim(new MMNode(new MMNode(new MMNode(m1), 
new MMNode(m2),
                        OpCode.MM), new MMNode(m3), OpCode.MM)).getSparsity();
                TestUtils.compareScalars(est, m5.getSparsity(),
-                       (estim instanceof EstimatorBitsetMM) ? eps3 : //exact
-                       (estim instanceof EstimatorBasicWorst) ? eps1 : eps2);
+                       (estim instanceof EstimatorBitsetMM) ? 0 : //exact
+                       (estim instanceof EstimatorBasicWorst) ? 1.0 : 1e-4);
        }
 }
diff --git 
a/src/test/java/org/apache/sysds/test/component/estim/SquaredProductTest.java 
b/src/test/java/org/apache/sysds/test/component/estim/SquaredProductTest.java
index 2a898f9c39..d117b98c1c 100644
--- 
a/src/test/java/org/apache/sysds/test/component/estim/SquaredProductTest.java
+++ 
b/src/test/java/org/apache/sysds/test/component/estim/SquaredProductTest.java
@@ -19,12 +19,12 @@
 
 package org.apache.sysds.test.component.estim;
 
-import org.junit.Test;
 import org.apache.sysds.hops.estim.EstimatorBasicAvg;
 import org.apache.sysds.hops.estim.EstimatorBasicWorst;
 import org.apache.sysds.hops.estim.EstimatorBitsetMM;
 import org.apache.sysds.hops.estim.EstimatorDensityMap;
 import org.apache.sysds.hops.estim.EstimatorMatrixHistogram;
+import org.apache.sysds.hops.estim.EstimatorRowWise;
 import org.apache.sysds.hops.estim.EstimatorLayeredGraph;
 import org.apache.sysds.hops.estim.EstimatorSample;
 import org.apache.sysds.hops.estim.SparsityEstimator;
@@ -33,138 +33,108 @@ import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestUtils;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
 /**
  * This is a basic sanity check for all estimator, which need
  * to compute a reasonable estimate for uniform data.
  */
-public class SquaredProductTest extends AutomatedTestBase 
+@RunWith(value = Parameterized.class)
+public class SquaredProductTest extends AutomatedTestBase
 {
-       private final static int m = 1000;
-       private final static int k = 1000;
-       private final static int n = 1000;
-       private final static double[] case1 = new double[]{0.0001, 0.00007};
-       private final static double[] case2 = new double[]{0.0006, 0.00007};
-
-       private final static double eps1 = 0.05;
-       private final static double eps2 = 1e-4;
-       private final static double eps3 = 0;
-       
+       @Parameterized.Parameter(0)
+       public int m;
+       @Parameterized.Parameter(1)
+       public int k;
+       @Parameterized.Parameter(2)
+       public int n;
+       @Parameterized.Parameter(3)
+       public double[] sparsity;
        
        @Override
        public void setUp() {
                //do  nothing
        }
-       
-       @Test
-       public void testBasicAvgCase1() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testBasicAvgCase2() {
-               runSparsityEstimateTest(new EstimatorBasicAvg(), m, k, n, 
case2);
-       }
-       
-       @Test
-       public void testBasicWorstCase1() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testBasicWorstCase2() {
-               runSparsityEstimateTest(new EstimatorBasicWorst(), m, k, n, 
case2);
-       }
-       
-       @Test
-       public void testDensityMapCase1() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testDensityMapCase2() {
-               runSparsityEstimateTest(new EstimatorDensityMap(), m, k, n, 
case2);
-       }
-       
-       @Test
-       public void testDensityMap7Case1() {
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, k, n, 
case1);
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] {
+                       // {m, k, n, sparsity}
+                       {1000, 1000, 1000, new double[]{0.0001, 0.00007}},
+                       {1000, 1000, 1000, new double[]{0.0006, 0.00007}},
+               });
        }
        
        @Test
-       public void testDensityMap7Case2() {
-               runSparsityEstimateTest(new EstimatorDensityMap(7), m, k, n, 
case2);
+       public void testBasicAvg() {
+               runSparsityEstimateTest(new EstimatorBasicAvg());
        }
        
        @Test
-       public void testBitsetMatrixCase1() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
case1);
+       public void testBasicWorst() {
+               runSparsityEstimateTest(new EstimatorBasicWorst());
        }
        
        @Test
-       public void testBitsetMatrixCase2() {
-               runSparsityEstimateTest(new EstimatorBitsetMM(), m, k, n, 
case2);
+       public void testDensityMap() {
+               runSparsityEstimateTest(new EstimatorDensityMap());
        }
        
        @Test
-       public void testMatrixHistogramCase1() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
k, n, case1);
+       public void testDensityMapBlocksize7() {
+               runSparsityEstimateTest(new EstimatorDensityMap(7));
        }
        
        @Test
-       public void testMatrixHistogramCase2() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(false), m, 
k, n, case2);
+       public void testBitsetMatrix() {
+               runSparsityEstimateTest(new EstimatorBitsetMM());
        }
        
        @Test
-       public void testMatrixHistogramExceptCase1() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
k, n, case1);
+       public void testMatrixHistogram() {
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(false));
        }
        
        @Test
-       public void testMatrixHistogramExceptCase2() {
-               runSparsityEstimateTest(new EstimatorMatrixHistogram(true), m, 
k, n, case2);
+       public void testMatrixHistogramExcept() {
+               runSparsityEstimateTest(new EstimatorMatrixHistogram(true));
        }
 
        @Test
-       public void testSamplingDefCase1() {
-               runSparsityEstimateTest(new EstimatorSample(), m, k, n, case1);
+       public void testSampling() {
+               runSparsityEstimateTest(new EstimatorSample());
        }
        
        @Test
-       public void testSamplingDefCase2() {
-               runSparsityEstimateTest(new EstimatorSample(), m, k, n, case2);
-       }
-       
-       @Test
-       public void testSampling20Case1() {
-               runSparsityEstimateTest(new EstimatorSample(0.2), m, k, n, 
case1);
-       }
-       
-       @Test
-       public void testSampling20Case2() {
-               runSparsityEstimateTest(new EstimatorSample(0.2), m, k, n, 
case2);
+       public void testSamplingFrac20() {
+               runSparsityEstimateTest(new EstimatorSample(0.2));
        }
 
        @Test
-       public void testLayeredGraphCase1() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
case1);
+       public void testLayeredGraph() {
+               runSparsityEstimateTest(new EstimatorLayeredGraph());
        }
 
        @Test
-       public void testLayeredGraphCase2() {
-               runSparsityEstimateTest(new EstimatorLayeredGraph(), m, k, n, 
case2);
+       public void testRowWise() {
+               runSparsityEstimateTest(new EstimatorRowWise());
        }
-       
-       private static void runSparsityEstimateTest(SparsityEstimator estim, 
int m, int k, int n, double[] sp) {
-               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sp[0], 1, 1, 
"uniform", 3);
-               MatrixBlock m2 = MatrixBlock.randOperations(k, n, sp[1], 1, 1, 
"uniform", 7);
+
+       private void runSparsityEstimateTest(SparsityEstimator estim) {
+               MatrixBlock m1 = MatrixBlock.randOperations(m, k, sparsity[0], 
1, 1, "uniform", 3);
+               MatrixBlock m2 = MatrixBlock.randOperations(k, n, sparsity[1], 
1, 1, "uniform", 7);
                MatrixBlock m3 = m1.aggregateBinaryOperations(m1, m2, 
                        new MatrixBlock(), 
InstructionUtils.getMatMultOperator(1));
                
                //compare estimated and real sparsity
                double est = estim.estim(m1, m2);
                TestUtils.compareScalars(est, m3.getSparsity(),
-                       (estim instanceof EstimatorBitsetMM) ? eps3 : //exact
-                       (estim instanceof EstimatorBasicWorst) ? eps1 : eps2);
+                       (estim instanceof EstimatorBitsetMM) ? 0 : //exact
+                       (estim instanceof EstimatorBasicWorst) ? 0.05 : 1e-4);
        }
 }

Reply via email to