You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemml.apache.org by mb...@apache.org on 2018/06/08 06:37:35 UTC

[1/2] systemml git commit: [SYSTEMML-2374] New simplification rewrite 'fold nary min/max ops'

Repository: systemml
Updated Branches:
  refs/heads/master 5f580f02e -> 4d370a8a6


[SYSTEMML-2374] New simplification rewrite 'fold nary min/max ops'

This patch adds a new dynamic rewrite for folding nested binary or nary
min/max operations into a single nary min/max operation. Due to limited
support for broadcasting this is a dynamic rewrite that is only applied
if the dimensions of all involved matrix inputs match.


Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/8d320791
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/8d320791
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/8d320791

Branch: refs/heads/master
Commit: 8d320791265321de38050e741308e3243ce89a7b
Parents: 5f580f0
Author: Matthias Boehm <mb...@gmail.com>
Authored: Thu Jun 7 22:23:05 2018 -0700
Committer: Matthias Boehm <mb...@gmail.com>
Committed: Thu Jun 7 22:23:05 2018 -0700

----------------------------------------------------------------------
 .../RewriteAlgebraicSimplificationDynamic.java  |  57 ++++++++-
 .../functions/misc/RewriteFoldMinMaxTest.java   | 118 +++++++++++++++++++
 .../scripts/functions/misc/RewriteFoldMax.dml   |  28 +++++
 .../scripts/functions/misc/RewriteFoldMin.dml   |  28 +++++
 .../functions/misc/ZPackageSuite.java           |   1 +
 5 files changed, 231 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/systemml/blob/8d320791/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java b/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java
index 81c20e0..062da2f 100644
--- a/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java
+++ b/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java
@@ -22,6 +22,7 @@ package org.apache.sysml.hops.rewrite;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -37,11 +38,13 @@ import org.apache.sysml.hops.Hop.OpOp1;
 import org.apache.sysml.hops.Hop.OpOp2;
 import org.apache.sysml.hops.Hop.OpOp3;
 import org.apache.sysml.hops.Hop.OpOp4;
+import org.apache.sysml.hops.Hop.OpOpN;
 import org.apache.sysml.hops.Hop.ParamBuiltinOp;
 import org.apache.sysml.hops.Hop.ReOrgOp;
 import org.apache.sysml.hops.IndexingOp;
 import org.apache.sysml.hops.LeftIndexingOp;
 import org.apache.sysml.hops.LiteralOp;
+import org.apache.sysml.hops.NaryOp;
 import org.apache.sysml.hops.OptimizerUtils;
 import org.apache.sysml.hops.ParameterizedBuiltinOp;
 import org.apache.sysml.hops.QuaternaryOp;
@@ -182,7 +185,7 @@ public class RewriteAlgebraicSimplificationDynamic extends HopRewriteRule
 				hi = simplifyWeightedUnaryMM(hop, hi, i);         //e.g., X*exp(U%*%t(V)) -> wumm(X, U, t(V), exp)
 				hi = simplifyDotProductSum(hop, hi, i);           //e.g., sum(v^2) -> t(v)%*%v if ncol(v)==1 
 				hi = fuseSumSquared(hop, hi, i);                  //e.g., sum(X^2) -> sumSq(X), if ncol(X)>1
-				hi = fuseAxpyBinaryOperationChain(hop, hi, i);    //e.g., (X+s*Y) -> (X+*s Y), (X-s*Y) -> (X-*s Y) 	
+				hi = fuseAxpyBinaryOperationChain(hop, hi, i);    //e.g., (X+s*Y) -> (X+*s Y), (X-s*Y) -> (X-*s Y)
 			}
 			hi = reorderMinusMatrixMult(hop, hi, i);          //e.g., (-t(X))%*%y->-(t(X)%*%y), TODO size
 			hi = simplifySumMatrixMult(hop, hi, i);           //e.g., sum(A%*%B) -> sum(t(colSums(A))*rowSums(B)), if not dot product / wsloss
@@ -191,6 +194,8 @@ public class RewriteAlgebraicSimplificationDynamic extends HopRewriteRule
 			hi = simplifyNnzComputation(hop, hi, i);          //e.g., sum(ppred(X,0,"!=")) -> literal(nnz(X)), if nnz known
 			hi = simplifyNrowNcolComputation(hop, hi, i);     //e.g., nrow(X) -> literal(nrow(X)), if nrow known to remove data dependency
 			hi = simplifyTableSeqExpand(hop, hi, i);          //e.g., table(seq(1,nrow(v)), v, nrow(v), m) -> rexpand(v, max=m, dir=row, ignore=false, cast=true)
+			if( OptimizerUtils.ALLOW_OPERATOR_FUSION )
+				foldMultipleMinMaxOperations(hi);             //e.g., min(X,min(min(3,7),Y)) -> min(X,3,7,Y)
 			
 			//process childs recursively after rewrites (to investigate pattern newly created by rewrites)
 			if( !descendFirst )
@@ -2584,4 +2589,54 @@ public class RewriteAlgebraicSimplificationDynamic extends HopRewriteRule
 	
 		return hi;
 	}
+	
+	private static Hop foldMultipleMinMaxOperations(Hop hi) 
+	{
+		if( (HopRewriteUtils.isBinary(hi, OpOp2.MIN, OpOp2.MAX) 
+			|| HopRewriteUtils.isNary(hi, OpOpN.MIN, OpOpN.MAX))
+			&& !OptimizerUtils.isHadoopExecutionMode() )
+		{
+			OpOp2 bop = (hi instanceof BinaryOp) ? ((BinaryOp)hi).getOp() :
+				OpOp2.valueOf(((NaryOp)hi).getOp().name());
+			OpOpN nop = (hi instanceof NaryOp) ? ((NaryOp)hi).getOp() :
+				OpOpN.valueOf(((BinaryOp)hi).getOp().name());
+			
+			boolean converged = false;
+			while( !converged ) {
+				//get first matching min/max
+				Hop first = hi.getInput().stream()
+					.filter(h -> HopRewriteUtils.isBinary(h, bop) || HopRewriteUtils.isNary(h, nop))
+					.findFirst().orElse(null);
+				
+				//replace current op with new nary min/max
+				final Hop lhi = hi;
+				if( first != null && first.getParent().size()==1
+					&& first.getInput().stream().allMatch(c -> c.getDataType()==DataType.SCALAR 
+						|| HopRewriteUtils.isEqualSize(lhi, c))) {
+					//construct new list of inputs (in original order)
+					ArrayList<Hop> linputs = new ArrayList<>();
+					for(Hop in : hi.getInput())
+						if( in == first )
+							linputs.addAll(first.getInput());
+						else
+							linputs.add(in);
+					Hop hnew = HopRewriteUtils.createNary(nop, linputs.toArray(new Hop[0]));
+					//clear dangling references
+					HopRewriteUtils.removeAllChildReferences(hi);
+					HopRewriteUtils.removeAllChildReferences(first);
+					//rewire all parents (avoid anomalies with refs to hi)
+					List<Hop> parents = new ArrayList<>(hi.getParent());
+					for( Hop p : parents )
+						HopRewriteUtils.replaceChildReference(p, hi, hnew);
+					hi = hnew;
+					LOG.debug("Applied foldMultipleMinMaxOperations (line "+hi.getBeginLine()+").");
+				}
+				else {
+					converged = true;
+				}
+			}
+		}
+		
+		return hi;
+	}
 }

http://git-wip-us.apache.org/repos/asf/systemml/blob/8d320791/src/test/java/org/apache/sysml/test/integration/functions/misc/RewriteFoldMinMaxTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/sysml/test/integration/functions/misc/RewriteFoldMinMaxTest.java b/src/test/java/org/apache/sysml/test/integration/functions/misc/RewriteFoldMinMaxTest.java
new file mode 100644
index 0000000..65c2a3e
--- /dev/null
+++ b/src/test/java/org/apache/sysml/test/integration/functions/misc/RewriteFoldMinMaxTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.sysml.test.integration.functions.misc;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.apache.sysml.api.DMLScript;
+import org.apache.sysml.api.DMLScript.RUNTIME_PLATFORM;
+import org.apache.sysml.hops.OptimizerUtils;
+import org.apache.sysml.lops.LopProperties.ExecType;
+import org.apache.sysml.runtime.matrix.data.MatrixValue.CellIndex;
+import org.apache.sysml.test.integration.AutomatedTestBase;
+import org.apache.sysml.test.integration.TestConfiguration;
+import org.apache.sysml.test.utils.TestUtils;
+import org.apache.sysml.utils.Statistics;
+
+public class RewriteFoldMinMaxTest extends AutomatedTestBase 
+{
+	private static final String TEST_NAME1 = "RewriteFoldMin";
+	private static final String TEST_NAME2 = "RewriteFoldMax";
+	
+	private static final String TEST_DIR = "functions/misc/";
+	private static final String TEST_CLASS_DIR = TEST_DIR + RewriteFoldMinMaxTest.class.getSimpleName() + "/";
+	
+	private static final int rows = 1932;
+	private static final int cols = 14;
+	
+	@Override
+	public void setUp() {
+		TestUtils.clearAssertionInformation();
+		addTestConfiguration( TEST_NAME1, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME1, new String[] { "R" }) );
+		addTestConfiguration( TEST_NAME2, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME2, new String[] { "R" }) );
+	}
+
+	@Test
+	public void testRewriteFoldMinNoRewrite() {
+		testRewriteFoldMinMax( TEST_NAME1, false, ExecType.CP );
+	}
+	
+	@Test
+	public void testRewriteFoldMinRewrite() {
+		testRewriteFoldMinMax( TEST_NAME1, true, ExecType.CP );
+	}
+	
+	@Test
+	public void testRewriteFoldMaxNoRewrite() {
+		testRewriteFoldMinMax( TEST_NAME2, false, ExecType.CP );
+	}
+	
+	@Test
+	public void testRewriteFoldMaxRewrite() {
+		testRewriteFoldMinMax( TEST_NAME2, true, ExecType.CP );
+	}
+
+	private void testRewriteFoldMinMax( String testname, boolean rewrites, ExecType et )
+	{
+		RUNTIME_PLATFORM platformOld = rtplatform;
+		switch( et ){
+			case MR: rtplatform = RUNTIME_PLATFORM.HADOOP; break;
+			case SPARK: rtplatform = RUNTIME_PLATFORM.SPARK; break;
+			default: rtplatform = RUNTIME_PLATFORM.HYBRID_SPARK; break;
+		}
+		
+		boolean sparkConfigOld = DMLScript.USE_LOCAL_SPARK_CONFIG;
+		if( rtplatform == RUNTIME_PLATFORM.SPARK || rtplatform == RUNTIME_PLATFORM.HYBRID_SPARK )
+			DMLScript.USE_LOCAL_SPARK_CONFIG = true;
+		
+		boolean oldFlag = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION;
+		
+		try {
+			TestConfiguration config = getTestConfiguration(testname);
+			loadTestConfiguration(config);
+			
+			String HOME = SCRIPT_DIR + TEST_DIR;
+			fullDMLScriptName = HOME + testname + ".dml";
+			programArgs = new String[]{ "-stats", "-args", String.valueOf(rows), 
+					String.valueOf(cols), output("R") };
+			OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION = rewrites;
+
+			//run performance tests
+			runTest(true, false, null, -1); 
+			
+			//compare matrices 
+			Double ret = readDMLMatrixFromHDFS("R").get(new CellIndex(1,1));
+			Assert.assertEquals("Wrong result", new Double(5*rows*cols), ret);
+			
+			//check for applied rewrites
+			if( rewrites ) {
+				Assert.assertTrue(!heavyHittersContainsString("min") && !heavyHittersContainsString("max")
+					&& (!testname.equals(TEST_NAME1) || Statistics.getCPHeavyHitterCount("nmin") == 1)
+					&& (!testname.equals(TEST_NAME2) || Statistics.getCPHeavyHitterCount("nmax") == 1));
+			}
+		}
+		finally {
+			OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION = oldFlag;
+			DMLScript.USE_LOCAL_SPARK_CONFIG = sparkConfigOld;
+			rtplatform = platformOld;
+		}
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/systemml/blob/8d320791/src/test/scripts/functions/misc/RewriteFoldMax.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/misc/RewriteFoldMax.dml b/src/test/scripts/functions/misc/RewriteFoldMax.dml
new file mode 100644
index 0000000..c5117c8
--- /dev/null
+++ b/src/test/scripts/functions/misc/RewriteFoldMax.dml
@@ -0,0 +1,28 @@
+#-------------------------------------------------------------
+#
+# 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(1, $1, $2)
+while(FALSE){}
+Y = max(X-7,max(max(X-5,-7),5))
+while(FALSE){}
+R = as.matrix(sum(Y))
+
+write(R, $3);

http://git-wip-us.apache.org/repos/asf/systemml/blob/8d320791/src/test/scripts/functions/misc/RewriteFoldMin.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/misc/RewriteFoldMin.dml b/src/test/scripts/functions/misc/RewriteFoldMin.dml
new file mode 100644
index 0000000..7919d9b
--- /dev/null
+++ b/src/test/scripts/functions/misc/RewriteFoldMin.dml
@@ -0,0 +1,28 @@
+#-------------------------------------------------------------
+#
+# 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(1, $1, $2)
+while(FALSE){}
+Y = min(X+7,min(min(X+5,7),5))
+while(FALSE){}
+R = as.matrix(sum(Y))
+
+write(R, $3);

http://git-wip-us.apache.org/repos/asf/systemml/blob/8d320791/src/test_suites/java/org/apache/sysml/test/integration/functions/misc/ZPackageSuite.java
----------------------------------------------------------------------
diff --git a/src/test_suites/java/org/apache/sysml/test/integration/functions/misc/ZPackageSuite.java b/src/test_suites/java/org/apache/sysml/test/integration/functions/misc/ZPackageSuite.java
index e2c7bf1..75e9970 100644
--- a/src/test_suites/java/org/apache/sysml/test/integration/functions/misc/ZPackageSuite.java
+++ b/src/test_suites/java/org/apache/sysml/test/integration/functions/misc/ZPackageSuite.java
@@ -61,6 +61,7 @@ import org.junit.runners.Suite;
 	RewriteCTableToRExpandTest.class,
 	RewriteElementwiseMultChainOptimizationTest.class,
 	RewriteEliminateAggregatesTest.class,
+	RewriteFoldMinMaxTest.class,
 	RewriteFoldRCBindTest.class,
 	RewriteFuseBinaryOpChainTest.class,
 	RewriteFusedRandTest.class,


[2/2] systemml git commit: [SYSTEMML-2273] Codegen support for nary min/max in cell/row templates

Posted by mb...@apache.org.
[SYSTEMML-2273] Codegen support for nary min/max in cell/row templates

This patch adds operator fusion and code generation support for the new
nary min/max operator in cell and row templates. For both scenarios, we
map the nary operator to binary codegen operations which are anyway
fused on a cell or row level without additional overhead and thus no
need for additional template or runtime primitives.


Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/4d370a8a
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/4d370a8a
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/4d370a8a

Branch: refs/heads/master
Commit: 4d370a8a6fb73329c46f12a3b6775d0b7817dad4
Parents: 8d32079
Author: Matthias Boehm <mb...@gmail.com>
Authored: Thu Jun 7 23:37:33 2018 -0700
Committer: Matthias Boehm <mb...@gmail.com>
Committed: Thu Jun 7 23:37:33 2018 -0700

----------------------------------------------------------------------
 .../hops/codegen/template/TemplateCell.java     | 19 +++++++--
 .../hops/codegen/template/TemplateRow.java      | 43 +++++++++++++-------
 .../functions/codegen/CellwiseTmplTest.java     | 24 +++++++++--
 .../functions/codegen/RowAggTmplTest.java       | 21 +++++++++-
 .../scripts/functions/codegen/cellwisetmpl23.R  | 31 ++++++++++++++
 .../functions/codegen/cellwisetmpl23.dml        | 30 ++++++++++++++
 .../scripts/functions/codegen/rowAggPattern42.R | 31 ++++++++++++++
 .../functions/codegen/rowAggPattern42.dml       | 30 ++++++++++++++
 8 files changed, 207 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java
index 0ce35c6..0106a59 100644
--- a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java
@@ -37,9 +37,11 @@ import org.apache.sysml.hops.Hop.AggOp;
 import org.apache.sysml.hops.Hop.DataGenMethod;
 import org.apache.sysml.hops.Hop.OpOp2;
 import org.apache.sysml.hops.Hop.OpOp3;
+import org.apache.sysml.hops.Hop.OpOpN;
 import org.apache.sysml.hops.Hop.ParamBuiltinOp;
 import org.apache.sysml.hops.IndexingOp;
 import org.apache.sysml.hops.LiteralOp;
+import org.apache.sysml.hops.NaryOp;
 import org.apache.sysml.hops.ParameterizedBuiltinOp;
 import org.apache.sysml.hops.TernaryOp;
 import org.apache.sysml.hops.codegen.cplan.CNode;
@@ -82,7 +84,8 @@ public class TemplateCell extends TemplateBase
 			|| (hop instanceof IndexingOp && hop.getInput().get(0).getDim2() >= 0
 				&& (((IndexingOp)hop).isColLowerEqualsUpper() || hop.getDim2()==1))
 			|| (HopRewriteUtils.isDataGenOpWithLiteralInputs(hop, DataGenMethod.SEQ)
-				&& HopRewriteUtils.hasOnlyUnaryBinaryParents(hop, true));
+				&& HopRewriteUtils.hasOnlyUnaryBinaryParents(hop, true))
+			|| (HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX) && hop.isMatrix());
 	}
 
 	@Override
@@ -93,7 +96,8 @@ public class TemplateCell extends TemplateBase
 				&& hop.getDim1()==1 && hop.getDim2()==1)
 				&& HopRewriteUtils.isTransposeOperation(hop.getInput().get(0))
 			|| (HopRewriteUtils.isTransposeOperation(hop) 
-				&& hop.getDim1()==1 && hop.getDim2()>1));
+				&& hop.getDim1()==1 && hop.getDim2()>1))
+			|| (HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX) && hop.isMatrix());
 	}
 
 	@Override
@@ -103,7 +107,8 @@ public class TemplateCell extends TemplateBase
 			|| (hop instanceof AggBinaryOp && hop.getInput().indexOf(input)==0 
 				&& HopRewriteUtils.isTransposeOperation(input))))
 			|| (HopRewriteUtils.isDataGenOpWithLiteralInputs(input, DataGenMethod.SEQ)
-				&& HopRewriteUtils.hasOnlyUnaryBinaryParents(input, false));
+				&& HopRewriteUtils.hasOnlyUnaryBinaryParents(input, false))
+			|| (HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX) && hop.isMatrix());
 	}
 
 	@Override
@@ -221,6 +226,14 @@ public class TemplateCell extends TemplateBase
 			out = new CNodeTernary(cdata1, cdata2, cdata3, 
 				TernaryType.valueOf(top.getOp().name()));
 		}
+		else if(HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX)) {
+			String op = ((NaryOp)hop).getOp().name();
+			CNode[] inputs = hop.getInput().stream().map(c -> 
+				TemplateUtils.wrapLookupIfNecessary(tmp.get(c.getHopID()), c)).toArray(CNode[]::new);
+			out = new CNodeBinary(inputs[0], inputs[1], BinType.valueOf(op));
+			for( int i=2; i<hop.getInput().size(); i++ )
+				out = new CNodeBinary(out, inputs[i], BinType.valueOf(op));
+		}
 		else if( hop instanceof ParameterizedBuiltinOp ) {
 			CNode cdata1 = tmp.get(((ParameterizedBuiltinOp)hop).getTargetHop().getHopID());
 			cdata1 = TemplateUtils.wrapLookupIfNecessary(cdata1, hop.getInput().get(0));

http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
index 737b30d..55b62ba 100644
--- a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
@@ -31,6 +31,7 @@ import org.apache.sysml.hops.DataGenOp;
 import org.apache.sysml.hops.Hop;
 import org.apache.sysml.hops.IndexingOp;
 import org.apache.sysml.hops.LiteralOp;
+import org.apache.sysml.hops.NaryOp;
 import org.apache.sysml.hops.ParameterizedBuiltinOp;
 import org.apache.sysml.hops.TernaryOp;
 import org.apache.sysml.hops.UnaryOp;
@@ -92,6 +93,7 @@ public class TemplateRow extends TemplateBase
 			|| (HopRewriteUtils.isBinary(hop, OpOp2.CBIND) && hop.getInput().get(0).isMatrix() && hop.dimsKnown())
 			|| HopRewriteUtils.isTernary(hop, OpOp3.PLUS_MULT, OpOp3.MINUS_MULT)
 			|| (HopRewriteUtils.isNary(hop, OpOpN.CBIND) && hop.getInput().get(0).isMatrix() && hop.dimsKnown())
+			|| (HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX) && hop.isMatrix())
 			|| (hop instanceof AggBinaryOp && hop.dimsKnown() && hop.getDim2()==1 //MV
 				&& hop.getInput().get(0).getDim1()>1 && hop.getInput().get(0).getDim2()>1)
 			|| (hop instanceof AggBinaryOp && hop.dimsKnown() && LibMatrixMult.isSkinnyRightHandSide(
@@ -117,6 +119,7 @@ public class TemplateRow extends TemplateBase
 			(  (hop instanceof BinaryOp && isValidBinaryOperation(hop)) 
 			|| (HopRewriteUtils.isBinary(hop, OpOp2.CBIND) && hop.getInput().get(0).isMatrix() && hop.dimsKnown())
 			|| (HopRewriteUtils.isNary(hop, OpOpN.CBIND) && hop.getInput().get(0).isMatrix() && hop.dimsKnown())
+			|| (HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX) && hop.isMatrix())
 			|| ((hop instanceof UnaryOp || hop instanceof ParameterizedBuiltinOp) 
 				&& TemplateCell.isValidOperation(hop))
 			|| HopRewriteUtils.isTernary(hop, OpOp3.PLUS_MULT, OpOp3.MINUS_MULT)
@@ -141,6 +144,7 @@ public class TemplateRow extends TemplateBase
 				&& hop.getDim1() > 1 && input.getDim1()>1)
 			|| (HopRewriteUtils.isBinary(hop, OpOp2.CBIND) && hop.getInput().get(0).isMatrix() && hop.dimsKnown())
 			|| (HopRewriteUtils.isNary(hop, OpOpN.CBIND) && hop.getInput().get(0).isMatrix() && hop.dimsKnown())
+			|| (HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX) && hop.isMatrix())
 			|| (HopRewriteUtils.isDataGenOpWithLiteralInputs(input, DataGenMethod.SEQ)
 				&& HopRewriteUtils.hasOnlyUnaryBinaryParents(input, false))
 			|| (hop instanceof AggBinaryOp
@@ -408,19 +412,11 @@ public class TemplateRow extends TemplateBase
 					&& (cdata1.getDataType().isMatrix() || cdata2.getDataType().isMatrix())))
 			{
 				if( HopRewriteUtils.isBinary(hop, SUPPORTED_VECT_BINARY) ) {
-					if( TemplateUtils.isMatrix(cdata1) && (TemplateUtils.isMatrix(cdata2) 
-							|| TemplateUtils.isRowVector(cdata2)) ) {
-						String opname = "VECT_"+((BinaryOp)hop).getOp().name();
-						out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(opname));
-					}
-					else {
-						String opname = "VECT_"+((BinaryOp)hop).getOp().name()+"_SCALAR";
-						if( TemplateUtils.isColVector(cdata1) )
-							cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
-						if( TemplateUtils.isColVector(cdata2) )
-							cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
-						out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(opname));
-					}
+					if( TemplateUtils.isColVector(cdata1) )
+						cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
+					if( TemplateUtils.isColVector(cdata2) )
+						cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
+					out = getVectorBinary(cdata1, cdata2, ((BinaryOp)hop).getOp().name());
 					if( cdata1 instanceof CNodeData && !inHops2.containsKey("X")
 						&& !(cdata1.getDataType()==DataType.SCALAR) ) {
 						inHops2.put("X", hop.getInput().get(0));
@@ -463,7 +459,7 @@ public class TemplateRow extends TemplateBase
 					TernaryType.valueOf(top.getOp().name()));
 			}
 		}
-		else if(HopRewriteUtils.isNary(hop, OpOpN.CBIND)) {
+		else if( hop instanceof NaryOp ) {
 			CNode[] inputs = new CNode[hop.getInput().size()];
 			for( int i=0; i<hop.getInput().size(); i++ ) {
 				Hop c = hop.getInput().get(i);
@@ -474,7 +470,14 @@ public class TemplateRow extends TemplateBase
 				if( i==0 && cdata instanceof CNodeData && !inHops2.containsKey("X") )
 					inHops2.put("X", c);
 			}
-			out = new CNodeNary(inputs, NaryType.VECT_CBIND);
+			if( HopRewriteUtils.isNary(hop, OpOpN.CBIND) ) {
+				out = new CNodeNary(inputs, NaryType.VECT_CBIND);
+			}
+			else if( HopRewriteUtils.isNary(hop, OpOpN.MIN, OpOpN.MAX) ) {
+				out = getVectorBinary(inputs[0], inputs[1], ((NaryOp)hop).getOp().name());
+				for( int i=2; i<hop.getInput().size(); i++ )
+					out = getVectorBinary(out, inputs[i], ((NaryOp)hop).getOp().name());
+			}
 		}
 		else if( hop instanceof ParameterizedBuiltinOp ) {
 			CNode cdata1 = tmp.get(((ParameterizedBuiltinOp)hop).getTargetHop().getHopID());
@@ -505,6 +508,16 @@ public class TemplateRow extends TemplateBase
 		tmp.put(hop.getHopID(), out);
 	}
 	
+	private CNodeBinary getVectorBinary(CNode cdata1, CNode cdata2, String name) {
+		if( TemplateUtils.isMatrix(cdata1) && (TemplateUtils.isMatrix(cdata2) 
+				|| TemplateUtils.isRowVector(cdata2)) ) {
+			return new CNodeBinary(cdata1, cdata2, BinType.valueOf("VECT_"+name));
+		}
+		else {
+			return new CNodeBinary(cdata1, cdata2, BinType.valueOf("VECT_"+name+"_SCALAR"));
+		}
+	}
+	
 	/**
 	 * Comparator to order input hops of the row aggregate template. We try 
 	 * to order matrices-vectors-scalars via sorting by number of cells but 

http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/test/java/org/apache/sysml/test/integration/functions/codegen/CellwiseTmplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/sysml/test/integration/functions/codegen/CellwiseTmplTest.java b/src/test/java/org/apache/sysml/test/integration/functions/codegen/CellwiseTmplTest.java
index 76469de..cfcabde 100644
--- a/src/test/java/org/apache/sysml/test/integration/functions/codegen/CellwiseTmplTest.java
+++ b/src/test/java/org/apache/sysml/test/integration/functions/codegen/CellwiseTmplTest.java
@@ -58,6 +58,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 	private static final String TEST_NAME20 = TEST_NAME+20; //bitwAnd() operation
 	private static final String TEST_NAME21 = TEST_NAME+21; //relu operation, (X>0)*dout
 	private static final String TEST_NAME22 = TEST_NAME+22; //sum(X * seq(1,N) + t(seq(M,1)))
+	private static final String TEST_NAME23 = TEST_NAME+23; //sum(min(X,Y,Z))
 	
 	private static final String TEST_DIR = "functions/codegen/";
 	private static final String TEST_CLASS_DIR = TEST_DIR + CellwiseTmplTest.class.getSimpleName() + "/";
@@ -70,7 +71,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 	@Override
 	public void setUp() {
 		TestUtils.clearAssertionInformation();
-		for( int i=1; i<=22; i++ ) {
+		for( int i=1; i<=23; i++ ) {
 			addTestConfiguration( TEST_NAME+i, new TestConfiguration(
 					TEST_CLASS_DIR, TEST_NAME+i, new String[] {String.valueOf(i)}) );
 		}
@@ -382,6 +383,21 @@ public class CellwiseTmplTest extends AutomatedTestBase
 	public void testCodegenCellwiseRewrite22_sp() {
 		testCodegenIntegration( TEST_NAME22, true, ExecType.SPARK );
 	}
+	
+	@Test
+	public void testCodegenCellwiseRewrite23() {
+		testCodegenIntegration( TEST_NAME23, true, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwise23() {
+		testCodegenIntegration( TEST_NAME23, false, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenCellwiseRewrite23_sp() {
+		testCodegenIntegration( TEST_NAME23, true, ExecType.SPARK );
+	}
 
 	private void testCodegenIntegration( String testname, boolean rewrites, ExecType instType )
 	{
@@ -409,7 +425,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 			
 			String HOME = SCRIPT_DIR + TEST_DIR;
 			fullDMLScriptName = HOME + testname + ".dml";
-			programArgs = new String[]{"-explain", "hops", "-stats", "-args", output("S") };
+			programArgs = new String[]{"-explain", "-stats", "-args", output("S") };
 			
 			fullRScriptName = HOME + testname + ".R";
 			rCmd = getRCmd(inputDir(), expectedDir());
@@ -420,7 +436,7 @@ public class CellwiseTmplTest extends AutomatedTestBase
 			runRScript(true); 
 			
 			if(testname.equals(TEST_NAME6) || testname.equals(TEST_NAME7) 
-				|| testname.equals(TEST_NAME9) || testname.equals(TEST_NAME10) ) {
+				|| testname.equals(TEST_NAME9) || testname.equals(TEST_NAME10)) {
 				//compare scalars 
 				HashMap<CellIndex, Double> dmlfile = readDMLScalarFromHDFS("S");
 				HashMap<CellIndex, Double> rfile  = readRScalarFromFS("S");
@@ -451,6 +467,8 @@ public class CellwiseTmplTest extends AutomatedTestBase
 				Assert.assertTrue(!heavyHittersContainsSubString("xor"));
 			else if( testname.equals(TEST_NAME22) )
 				Assert.assertTrue(!heavyHittersContainsSubString("seq"));
+			else if( testname.equals(TEST_NAME23) )
+				Assert.assertTrue(!heavyHittersContainsSubString("min","nmin"));
 		}
 		finally {
 			rtplatform = platformOld;

http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java b/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
index e07c543..203e9b1 100644
--- a/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
+++ b/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
@@ -78,6 +78,7 @@ public class RowAggTmplTest extends AutomatedTestBase
 	private static final String TEST_NAME39 = TEST_NAME+"39"; //BitwAnd operation
 	private static final String TEST_NAME40 = TEST_NAME+"40"; //relu operation -> (X>0)* dout
 	private static final String TEST_NAME41 = TEST_NAME+"41"; //X*rowSums(X/seq(1,N)+t(seq(M,1)))
+	private static final String TEST_NAME42 = TEST_NAME+"42"; //X/rowSums(min(X, Y, Z))
 	
 	private static final String TEST_DIR = "functions/codegen/";
 	private static final String TEST_CLASS_DIR = TEST_DIR + RowAggTmplTest.class.getSimpleName() + "/";
@@ -89,7 +90,7 @@ public class RowAggTmplTest extends AutomatedTestBase
 	@Override
 	public void setUp() {
 		TestUtils.clearAssertionInformation();
-		for(int i=1; i<=41; i++)
+		for(int i=1; i<=42; i++)
 			addTestConfiguration( TEST_NAME+i, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME+i, new String[] { String.valueOf(i) }) );
 	}
 	
@@ -707,6 +708,21 @@ public class RowAggTmplTest extends AutomatedTestBase
 	public void testCodegenRowAgg41SP() {
 		testCodegenIntegration( TEST_NAME41, false, ExecType.SPARK );
 	}
+	
+	@Test
+	public void testCodegenRowAggRewrite42CP() {
+		testCodegenIntegration( TEST_NAME42, true, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenRowAgg42CP() {
+		testCodegenIntegration( TEST_NAME42, false, ExecType.CP );
+	}
+
+	@Test
+	public void testCodegenRowAgg42SP() {
+		testCodegenIntegration( TEST_NAME42, false, ExecType.SPARK );
+	}
 
 	private void testCodegenIntegration( String testname, boolean rewrites, ExecType instType )
 	{
@@ -766,6 +782,9 @@ public class RowAggTmplTest extends AutomatedTestBase
 				Assert.assertTrue(!heavyHittersContainsSubString("xor"));
 			if( testname.equals(TEST_NAME41) )
 				Assert.assertTrue(!heavyHittersContainsSubString("seq"));
+			if( testname.equals(TEST_NAME42) )
+				Assert.assertTrue(!heavyHittersContainsSubString("min","nmin") 
+					&& !heavyHittersContainsSubString("spoof", 2));
 		}
 		finally {
 			rtplatform = platformOld;

http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/test/scripts/functions/codegen/cellwisetmpl23.R
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl23.R b/src/test/scripts/functions/codegen/cellwisetmpl23.R
new file mode 100644
index 0000000..9dffe0a
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl23.R
@@ -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.
+#
+#-------------------------------------------------------------
+
+args<-commandArgs(TRUE)
+options(digits=22)
+library("Matrix")
+
+X = matrix(6, 500, 2);
+Y = matrix(7, 500, 2);
+Z = matrix(8, 500, 2);
+R = as.matrix(sum(pmin(X,Y,Z)));
+
+writeMM(as(R,"CsparseMatrix"), paste(args[2], "S", sep=""));

http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/test/scripts/functions/codegen/cellwisetmpl23.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/codegen/cellwisetmpl23.dml b/src/test/scripts/functions/codegen/cellwisetmpl23.dml
new file mode 100644
index 0000000..8e53d27
--- /dev/null
+++ b/src/test/scripts/functions/codegen/cellwisetmpl23.dml
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------
+#
+# 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(6, 500, 2);
+Y = matrix(7, 500, 2);
+Z = matrix(8, 500, 2);
+
+while(FALSE){}
+
+R = as.matrix(sum(min(X,Y,Z)));
+
+write(R, $1)

http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/test/scripts/functions/codegen/rowAggPattern42.R
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/codegen/rowAggPattern42.R b/src/test/scripts/functions/codegen/rowAggPattern42.R
new file mode 100644
index 0000000..2214a46
--- /dev/null
+++ b/src/test/scripts/functions/codegen/rowAggPattern42.R
@@ -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.
+#
+#-------------------------------------------------------------
+
+args<-commandArgs(TRUE)
+options(digits=22)
+library("Matrix")
+
+X = matrix(6, 500, 2);
+Y = matrix(7, 500, 2);
+Z = matrix(8, 500, 2);
+R = X / (rowSums(pmin(X, Y, Z)) %*% matrix(1,1,2));
+
+writeMM(as(R,"CsparseMatrix"), paste(args[2], "S", sep=""));

http://git-wip-us.apache.org/repos/asf/systemml/blob/4d370a8a/src/test/scripts/functions/codegen/rowAggPattern42.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/codegen/rowAggPattern42.dml b/src/test/scripts/functions/codegen/rowAggPattern42.dml
new file mode 100644
index 0000000..78647c7
--- /dev/null
+++ b/src/test/scripts/functions/codegen/rowAggPattern42.dml
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------
+#
+# 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(6, 500, 2);
+Y = matrix(7, 500, 2);
+Z = matrix(8, 500, 2);
+
+while(FALSE){}
+
+R = X / rowSums(min(X, Y, Z));
+
+write(R, $1)