You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemds.apache.org by mb...@apache.org on 2025/03/22 17:43:08 UTC

(systemds) branch main updated: [SYSTEMDS-3844] Extended codegen templates w/ row/colProd Agg

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

mboehm7 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 0ec4dcd36e [SYSTEMDS-3844] Extended codegen templates w/ row/colProd Agg
0ec4dcd36e is described below

commit 0ec4dcd36e5cce81467ffac5cabc7a8c87acb46b
Author: Frxms <to...@gmail.com>
AuthorDate: Sat Mar 22 18:41:41 2025 +0100

    [SYSTEMDS-3844] Extended codegen templates w/ row/colProd Agg
    
    Closes #2234.
---
 .../sysds/hops/codegen/template/TemplateCell.java  |   2 +-
 .../sysds/hops/codegen/template/TemplateRow.java   |   2 +-
 .../sysds/runtime/codegen/SpoofCellwise.java       | 219 ++++++++++++++++++++-
 .../test/functions/codegen/CellwiseTmplTest.java   |  73 ++++++-
 .../scripts/functions/codegen/cellwisetmpl28.R     |  39 ++++
 .../scripts/functions/codegen/cellwisetmpl28.dml   |  32 +++
 .../scripts/functions/codegen/cellwisetmpl29.R     |  40 ++++
 .../scripts/functions/codegen/cellwisetmpl29.dml   |  33 ++++
 .../scripts/functions/codegen/cellwisetmpl30.R     |  39 ++++
 .../scripts/functions/codegen/cellwisetmpl30.dml   |  32 +++
 .../scripts/functions/codegen/cellwisetmpl31.R     |  38 ++++
 .../scripts/functions/codegen/cellwisetmpl31.dml   |  31 +++
 12 files changed, 573 insertions(+), 7 deletions(-)

diff --git a/src/main/java/org/apache/sysds/hops/codegen/template/TemplateCell.java b/src/main/java/org/apache/sysds/hops/codegen/template/TemplateCell.java
index 8d0dc273eb..c909d86cd1 100644
--- a/src/main/java/org/apache/sysds/hops/codegen/template/TemplateCell.java
+++ b/src/main/java/org/apache/sysds/hops/codegen/template/TemplateCell.java
@@ -66,7 +66,7 @@ import org.apache.sysds.runtime.matrix.data.Pair;
 public class TemplateCell extends TemplateBase 
 {	
 	private static final AggOp[] SUPPORTED_AGG = 
-			new AggOp[]{AggOp.SUM, AggOp.SUM_SQ, AggOp.MIN, AggOp.MAX};
+			new AggOp[]{AggOp.SUM, AggOp.SUM_SQ, AggOp.MIN, AggOp.MAX, AggOp.PROD};
 	
 	public TemplateCell() {
 		super(TemplateType.CELL);
diff --git a/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java b/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java
index 4ac38b1487..c42ea6c858 100644
--- a/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java
+++ b/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java
@@ -67,7 +67,7 @@ import org.apache.sysds.runtime.matrix.data.Pair;
 
 public class TemplateRow extends TemplateBase 
 {
-	private static final AggOp[] SUPPORTED_ROW_AGG = new AggOp[]{AggOp.SUM, AggOp.MIN, AggOp.MAX, AggOp.MEAN};
+	private static final AggOp[] SUPPORTED_ROW_AGG = new AggOp[]{AggOp.SUM, AggOp.MIN, AggOp.MAX, AggOp.MEAN, AggOp.PROD};
 	private static final OpOp1[] SUPPORTED_VECT_UNARY = new OpOp1[]{
 		OpOp1.EXP, OpOp1.SQRT, OpOp1.LOG, OpOp1.ABS, OpOp1.ROUND, OpOp1.CEIL, OpOp1.FLOOR, OpOp1.SIGN,
 		OpOp1.SIN, OpOp1.COS, OpOp1.TAN, OpOp1.ASIN, OpOp1.ACOS, OpOp1.ATAN, OpOp1.SINH, OpOp1.COSH, OpOp1.TANH,
diff --git a/src/main/java/org/apache/sysds/runtime/codegen/SpoofCellwise.java b/src/main/java/org/apache/sysds/runtime/codegen/SpoofCellwise.java
index 6c3986bd93..d59f50a0e8 100644
--- a/src/main/java/org/apache/sysds/runtime/codegen/SpoofCellwise.java
+++ b/src/main/java/org/apache/sysds/runtime/codegen/SpoofCellwise.java
@@ -84,6 +84,7 @@ public abstract class SpoofCellwise extends SpoofOperator {
 		SUM_SQ,
 		MIN,
 		MAX,
+		PROD
 	}
 	
 	protected final CellType _type;
@@ -332,12 +333,16 @@ public abstract class SpoofCellwise extends SpoofOperator {
 		else if( _type == CellType.ROW_AGG ) {
 			if( _aggOp == AggOp.SUM || _aggOp == AggOp.SUM_SQ )
 				return executeDenseRowAggSum(a, lb, scalars, c, m, n, sparseSafe, rl, ru, rix);
+			else if(_aggOp == AggOp.PROD)
+				return executeDenseRowProd(a, lb, scalars, c, m, n, sparseSafe, rl, ru, rix);
 			else
 				return executeDenseRowAggMxx(a, lb, scalars, c, m, n, sparseSafe, rl, ru, rix);
 		}
 		else if( _type == CellType.COL_AGG ) {
 			if( _aggOp == AggOp.SUM || _aggOp == AggOp.SUM_SQ )
 				return executeDenseColAggSum(a, lb, scalars, c, m, n, sparseSafe, rl, ru, rix);
+			else if(_aggOp == AggOp.PROD)
+				return executeDenseColProd(a, lb, scalars, c, m, n, sparseSafe, rl, ru, rix);
 			else
 				return executeDenseColAggMxx(a, lb, scalars, c, m, n, sparseSafe, rl, ru, rix);
 		}
@@ -372,12 +377,16 @@ public abstract class SpoofCellwise extends SpoofOperator {
 		else if( _type == CellType.ROW_AGG ) {
 			if( _aggOp == AggOp.SUM || _aggOp == AggOp.SUM_SQ )
 				return executeSparseRowAggSum(sblock, lb, scalars, out, m, n, sparseSafe, rl, ru, rix);
+			else if( _aggOp == AggOp.PROD)
+				return executeSparseRowProd(sblock, lb, scalars, out, m, n, sparseSafe, rl, ru, rix);
 			else
 				return executeSparseRowAggMxx(sblock, lb, scalars, out, m, n, sparseSafe, rl, ru, rix);
 		}
 		else if( _type == CellType.COL_AGG ) {
 			if( _aggOp == AggOp.SUM || _aggOp == AggOp.SUM_SQ )
 				return executeSparseColAggSum(sblock, lb, scalars, out, m, n, sparseSafe, rl, ru, rix);
+			else if( _aggOp == AggOp.PROD)
+				return executeSparseColProd(sblock, lb, scalars, out, m, n, sparseSafe, rl, ru, rix);
 			else
 				return executeSparseColAggMxx(sblock, lb, scalars, out, m, n, sparseSafe, rl, ru, rix);
 		}
@@ -930,7 +939,215 @@ public abstract class SpoofCellwise extends SpoofOperator {
 		}
 		return ret;
 	}
-	
+
+	private long executeDenseRowProd(DenseBlock a, SideInput[] b, double[] scalars,
+		DenseBlock c, int m, int n, boolean sparseSafe, int rl, int ru, long rix)
+	{
+		// single block output
+		double[] lc = c.valuesAt(0);
+		long lnnz = 0;
+		if(a == null && !sparseSafe) {
+			for(int i = rl; i < ru; i++) {
+				for(int j = 0; j < n; j++) {
+					if(j == 0) {
+						lc[i] = genexec(0, b, scalars, m, n, rix+i, i, j);
+					} else if(lc[i] != 0) {
+						lc[i] *= genexec(0, b, scalars, m, n, rix+i, i, j);
+					} else {
+						break;
+					}
+				}
+				lnnz += (lc[i]!=0) ? 1 : 0;
+			}
+		}
+		else if( a != null ) {
+			for(int i = rl; i < ru; i++) {
+				double[] avals = a.values(i);
+				int aix = a.pos(i);
+				for(int j = 0; j < n; j++) {
+					double aval = avals[aix + j];
+					if(aval != 0 || !sparseSafe) {
+						if(j == 0) {
+							lc[i] = genexec(aval, b, scalars, m, n, rix+i, i, j);
+						} else if(lc[i] != 0) {
+							lc[i] *= genexec(aval, b, scalars, m, n, rix+i, i, j);
+						} else {
+							break;
+						}
+					} else {
+						break;
+					}
+				}
+				lnnz += (lc[i] != 0) ? 1 : 0;
+			}
+		}
+		return lnnz;
+	}
+
+	private long executeDenseColProd(DenseBlock a, SideInput[] b, double[] scalars,
+		DenseBlock c, int m, int n, boolean sparseSafe, int rl, int ru, long rix)
+	{
+		double[] lc = c.valuesAt(0);
+		//track the cols that have a zero
+		boolean[] zeroFlag = new boolean[n];
+		if(a == null && !sparseSafe) {
+			for(int i = rl; i < ru; i++) {
+				for(int j = 0; j < n; j++) {
+					if(!zeroFlag[j]) {
+						if(i == 0) {
+							lc[j] = genexec(0, b, scalars, m, n, rix+i, i, j);
+						} else if(lc[j] != 0) {
+							lc[j] *= genexec(0, b, scalars, m, n, rix+i, i, j);
+						} else {
+							zeroFlag[j] = true;
+						}
+					}
+				}
+			}
+		}
+		else if(a != null) {
+			for(int i = rl; i < ru; i++) {
+				double[] avals = a.values(i);
+				int aix = a.pos(i);
+				for(int j = 0; j < n; j++) {
+					if(!zeroFlag[j]) {
+						double aval = avals[aix + j];
+						if(aval != 0 || !sparseSafe) {
+							if(i == 0) {
+								lc[j] = genexec(aval, b, scalars, m, n, rix + i, i, j);
+							} else if(lc[j] != 0) {
+								lc[j] *= genexec(aval, b, scalars, m, n, rix + i, i, j);
+							} else {
+								zeroFlag[j] = true;
+							}
+						}
+					} else {
+						zeroFlag[j] = true;
+					}
+				}
+			}
+		}
+		return -1;
+	}
+
+	private long executeSparseRowProd(SparseBlock sblock, SideInput[] b, double[] scalars,
+		MatrixBlock out, int m, int n, boolean sparseSafe, int rl, int ru, long rix)
+	{
+		double[] c = out.getDenseBlockValues();
+		long lnnz = 0;
+		for(int i = rl; i < ru; i++) {
+			int lastj = -1;
+			if(sblock != null && !sblock.isEmpty(i)) {
+				int apos = sblock.pos(i);
+				int alen = sblock.size(i);
+				int[] aix = sblock.indexes(i);
+				double[] avals = sblock.values(i);
+				for(int k = apos; k < apos+alen; k++) {
+					if(!sparseSafe) {
+						for(int j=lastj+1; j<aix[k]; j++) {
+							if(j == 0) {
+								c[i] = genexec(0, b, scalars, m, n, rix+i, i, j);
+							} else if(c[i] != 0){
+								c[i] *= genexec(0, b, scalars, m, n, rix+i, i, j);
+							} else {
+								break;
+							}
+						}
+					}
+					if(aix.length == n || !sparseSafe) {
+						if(aix[k] == 0) {
+							lastj = aix[k];
+							c[i] = genexec(avals[k], b, scalars, m, n, rix+i, i, k);
+						} else if(c[i] != 0){
+							lastj = aix[k];
+							c[i] *= genexec(avals[k], b, scalars, m, n, rix+i, i, k);
+						} else {
+							break;
+						}
+					} else {
+						break;
+					}
+				}
+			}
+			//process remaining zeros
+			if(!sparseSafe)
+				for(int j=lastj+1; j<n; j++) {
+					if(j == 0) {
+						c[i] = genexec(0, b, scalars, m, n, rix+i, i, j);
+					} else if(c[i] != 0){
+						c[i] *= genexec(0, b, scalars, m, n, rix+i, i, j);
+					} else {
+						break;
+					}
+				}
+			lnnz += (c[i] != 0) ? 1 : 0;
+		}
+		return lnnz;
+	}
+
+	private long executeSparseColProd(SparseBlock sblock, SideInput[] b, double[] scalars,
+		MatrixBlock out, int m, int n, boolean sparseSafe, int rl, int ru, long rix)
+	{
+		double[] c = out.getDenseBlockValues();
+		boolean[] zeroFlag = new boolean[n];
+
+		for(int i=rl; i<ru; i++) {
+			int lastj = -1;
+			//handle non-empty rows
+			if(sblock != null && !sblock.isEmpty(i)) {
+				int apos = sblock.pos(i);
+				int alen = sblock.size(i);
+				int[] aix = sblock.indexes(i);
+				double[] avals = sblock.values(i);
+				long nnzCount = sblock.size(rl, ru);
+				//process every column, to not miss any 0's
+				for(int k=apos; k<apos+alen; k++) {
+					//process zeros before current non-zero
+					if( !sparseSafe )
+						for(int j=lastj+1; j<aix[k]; j++) {
+							if(!zeroFlag[j]) {
+								if(i == 0) {
+									c[j] = genexec(0, b, scalars, m, n, rix+i, i, j);
+								} else if(c[j] != 0){
+									c[j] *= genexec(0, b, scalars, m, n, rix+i, i, j);
+								} else {
+									zeroFlag[j] = true;
+								}
+							}
+						}
+					//process current non-zero
+					if((nnzCount == m || !sparseSafe) && !zeroFlag[aix[k]]) {
+						if(i == 0) {
+							lastj = aix[k];
+							c[aix[k]] = genexec(avals[k], b, scalars, m, n, rix+i, i, lastj);
+						} else if(c[aix[k]] != 0){
+							lastj = aix[k];
+							c[aix[k]] *= genexec(avals[k], b, scalars, m, n, rix+i, i, lastj);
+						} else {
+							zeroFlag[aix[k]] = true;
+						}
+					} else {
+						zeroFlag[aix[k]] = true;
+					}
+				}
+			}
+			//process empty rows or remaining zeros
+			if(!sparseSafe)
+				for(int j=lastj+1; j<n; j++) {
+					if(!zeroFlag[j]) {
+						if(i == 0) {
+							c[j] = genexec(0, b, scalars, m, n, rix+i, i, j);
+						} else if(c[j] != 0){
+							c[j] *= genexec(0, b, scalars, m, n, rix+i, i, j);
+						} else {
+							zeroFlag[j] = true;
+						}
+					}
+				}
+		}
+		return -1;
+	}
+
 	//local execution where grix==rix
 	protected final double genexec( double a, SideInput[] b,
 		double[] scalars, int m, int n, int rix, int cix) {
diff --git a/src/test/java/org/apache/sysds/test/functions/codegen/CellwiseTmplTest.java b/src/test/java/org/apache/sysds/test/functions/codegen/CellwiseTmplTest.java
index e9a1fc0d40..62ab375f2a 100644
--- a/src/test/java/org/apache/sysds/test/functions/codegen/CellwiseTmplTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/codegen/CellwiseTmplTest.java
@@ -67,6 +67,10 @@ public class CellwiseTmplTest extends AutomatedTestBase
 	private static final String TEST_NAME25 = TEST_NAME+25; //bias_add
 	private static final String TEST_NAME26 = TEST_NAME+26; //bias_mult
 	private static final String TEST_NAME27 = TEST_NAME+27; //outer < +7 negative
+	private static final String TEST_NAME28 = TEST_NAME+28; //colProds(X^2 + 1)
+	private static final String TEST_NAME29 = TEST_NAME+29; //colProds(2*log(X))
+	private static final String TEST_NAME30 = TEST_NAME+30;	//rowProds(X^2 + 1)
+	private static final String TEST_NAME31 = TEST_NAME+31;	//rowProds(2*log(X))
 
 	private static final String TEST_DIR = "functions/codegen/";
 	private static final String TEST_CLASS_DIR = TEST_DIR + CellwiseTmplTest.class.getSimpleName() + "/";
@@ -79,7 +83,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 	@Override
 	public void setUp() {
 		TestUtils.clearAssertionInformation();
-		for( int i=1; i<=27; i++ ) {
+		for( int i=1; i<=31; i++ ) {
 			addTestConfiguration( TEST_NAME+i, new TestConfiguration(
 				TEST_CLASS_DIR, TEST_NAME+i, new String[] {String.valueOf(i)}) );
 		}
@@ -444,7 +448,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 	public void testCodegenCellwiseRewrite26_sp() {
 		testCodegenIntegration( TEST_NAME26, true, ExecType.SPARK );
 	}
-	
+
 	@Test
 	public void testCodegenCellwiseRewrite27() {
 		testCodegenIntegration( TEST_NAME27, true, ExecType.CP );
@@ -455,10 +459,71 @@ public class CellwiseTmplTest extends AutomatedTestBase
 		testCodegenIntegration( TEST_NAME27, false, ExecType.CP );
 	}
 
+	@Test
 	public void testCodegenCellwiseRewrite27_sp() {
 		testCodegenIntegration( TEST_NAME27, true, ExecType.SPARK );
 	}
 
+	@Test
+	public void testCodegenCellwiseRewrite28() {
+		testCodegenIntegration( TEST_NAME28, true, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwise28() {
+		testCodegenIntegration( TEST_NAME28, false, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite28_sp() {
+		testCodegenIntegration( TEST_NAME28, true, ExecType.SPARK );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite29() {
+		testCodegenIntegration( TEST_NAME29, true, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwise29() {
+		testCodegenIntegration( TEST_NAME29, false, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite29_sp() {
+		testCodegenIntegration( TEST_NAME29, true, ExecType.SPARK );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite30() {
+		testCodegenIntegration( TEST_NAME30, true, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwise30() {
+		testCodegenIntegration( TEST_NAME30, false, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite30_sp() {
+		testCodegenIntegration( TEST_NAME30, true, ExecType.SPARK );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite31() {
+		testCodegenIntegration( TEST_NAME31, true, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwise31() {
+		testCodegenIntegration( TEST_NAME31, false, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite31_sp() {
+		testCodegenIntegration( TEST_NAME31, true, ExecType.SPARK );
+	}
+
 	private void testCodegenIntegration( String testname, boolean rewrites, ExecType instType )
 	{
 		boolean oldRewrites = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION;
@@ -467,7 +532,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 		
 		if( testname.equals(TEST_NAME9) )
 			TEST_CONF = TEST_CONF6;
-		
+		  
 		try
 		{
 			TestConfiguration config = getTestConfiguration(testname);
@@ -475,7 +540,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 			
 			String HOME = SCRIPT_DIR + TEST_DIR;
 			fullDMLScriptName = HOME + testname + ".dml";
-			programArgs = new String[]{"-stats", "-args", output("S") };
+			programArgs = new String[]{"-explain", "codegen", "-stats", "-args", output("S") };
 			
 			fullRScriptName = HOME + testname + ".R";
 			rCmd = getRCmd(inputDir(), expectedDir());
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl28.R b/src/test/scripts/functions/codegen/cellwisetmpl28.R
new file mode 100644
index 0000000000..05e31d0f19
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl28.R
@@ -0,0 +1,39 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+args<-commandArgs(TRUE)
+options(digits=22)
+library("Matrix")
+library("matrixStats")
+
+# colProds <- function(X) {
+#   apply(X, 2, prod)
+# }
+
+Z = matrix(0, 5, 1)
+Y = matrix(2, 5, 1)
+A = rbind(Y, Z)
+B = matrix(0, 10, 10)
+X = cbind(B, A, B)
+
+R = t(colProds(X^2 + 1));
+
+writeMM(as(R,"CsparseMatrix"), paste(args[2], "S", sep=""));
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl28.dml b/src/test/scripts/functions/codegen/cellwisetmpl28.dml
new file mode 100644
index 0000000000..ea06eafe26
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl28.dml
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+Z = matrix(0, 5, 1)
+Y = matrix(2, 5, 1)
+A = rbind(Y, Z)
+B = matrix(0, 10, 10)
+X = cbind(B, A, B)
+
+while(FALSE){}
+
+R = colProds(X^2 + 1)
+
+write(R, $1)
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl29.R b/src/test/scripts/functions/codegen/cellwisetmpl29.R
new file mode 100644
index 0000000000..08c255f617
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl29.R
@@ -0,0 +1,40 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+args<-commandArgs(TRUE)
+options(digits=22)
+library("Matrix")
+library("matrixStats")
+
+# colProds <- function(X) {
+#   apply(X, 2, prod)
+# }
+
+X = matrix(3, 10, 10)
+# X = matrix(seq(9, 100*100+8), 100, 100, byrow=TRUE);
+# F = matrix(0.1, 10, 10)
+# X = matrix(seq(from = 1, to = 10, by = 2), 10, 20)
+# X = matrix(1.3109348721, 10, 10)
+
+R = t(colProds(2*log(X)))
+# R = t(colProds(X*min(F)));
+
+writeMM(as(R,"CsparseMatrix"), paste(args[2], "S", sep=""));
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl29.dml b/src/test/scripts/functions/codegen/cellwisetmpl29.dml
new file mode 100644
index 0000000000..72a38870a3
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl29.dml
@@ -0,0 +1,33 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+X = matrix(3, 10, 10)
+#X = matrix(seq(9, 100*100+8), 100, 100);
+#F = matrix(0.1, 10, 10)
+#X = matrix(seq(2, 10*20+1), 10, 20)
+#X = matrix(1.3109348721, 10, 10)
+
+while(FALSE){}
+
+R = colProds(2*log(X))
+#R = colProds(X*min(F))
+
+write(R, $1)
\ No newline at end of file
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl30.R b/src/test/scripts/functions/codegen/cellwisetmpl30.R
new file mode 100644
index 0000000000..7ef7086009
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl30.R
@@ -0,0 +1,39 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+args<-commandArgs(TRUE)
+options(digits=22)
+library("Matrix")
+library("matrixStats")
+
+# rowProds <- function(X) {
+#   apply(X, 1, prod)
+# }
+
+Z = matrix(0, 1, 5)
+Y = matrix(2, 1, 5)
+A = cbind(Y, Z)
+B = matrix(0, 10, 10)
+X = rbind(B, A, B)
+
+R = rowProds(X^2 + 1)
+
+writeMM(as(R,"CsparseMatrix"), paste(args[2], "S", sep=""));
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl30.dml b/src/test/scripts/functions/codegen/cellwisetmpl30.dml
new file mode 100644
index 0000000000..ed023ce669
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl30.dml
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+Z = matrix(0, 1, 5)
+Y = matrix(2, 1, 5)
+A = cbind(Y, Z)
+B = matrix(0, 10, 10)
+X = rbind(B, A, B)
+
+while(FALSE){}
+
+R = rowProds(X^2 + 1)
+
+write(R, $1)
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl31.R b/src/test/scripts/functions/codegen/cellwisetmpl31.R
new file mode 100644
index 0000000000..24a7ed759f
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl31.R
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+args<-commandArgs(TRUE)
+options(digits=22)
+library("Matrix")
+library("matrixStats")
+
+# rowProds <- function(X) {
+#   apply(X, 1, prod)
+# }
+
+X = matrix(3, 10, 10)
+# X = matrix(seq(9, 100*100+8), 100, 100, byrow=TRUE);
+# F = matrix(0.1, 10, 10)
+
+R = rowProds(2*log(X));
+# R = rowProds(X*min(F))
+
+writeMM(as(R,"CsparseMatrix"), paste(args[2], "S", sep=""));
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl31.dml b/src/test/scripts/functions/codegen/cellwisetmpl31.dml
new file mode 100644
index 0000000000..77f2e84ebe
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl31.dml
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+X = matrix(3, 10, 10)
+#X = matrix(seq(9, 100*100+8), 100, 100);
+#F = matrix(0.1, 10, 10)
+
+while(FALSE){}
+
+R = rowProds(2*log(X))
+#R = rowProds(X*min(F))
+
+write(R, $1)
\ No newline at end of file