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 2022/04/23 21:48:24 UTC

[systemds] branch main updated: [SYSTEMDS-3358] New rewrite cumsum of constant vector to sequence

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 37bf83d705 [SYSTEMDS-3358] New rewrite cumsum of constant vector to sequence
37bf83d705 is described below

commit 37bf83d705676ddc4f15ccb2575d424577bc36a2
Author: Matthias Boehm <mb...@gmail.com>
AuthorDate: Sat Apr 23 23:47:50 2022 +0200

    [SYSTEMDS-3358] New rewrite cumsum of constant vector to sequence
    
    There are a few scripts that compute a sequence via cumsum on a constant
    vector. We now automatically rewrite these patterns as follows:
    
    weight = matrix(1/s_max, rows=s_max, cols=1)
    weight = cumsum(weight)
    --> (new rewrite)
    weight = seq(1/s_max, s_max * 1/s_max, 1/s_max)
    --> (constant folding)
    weight = seq(1/s_max, 1, 1/s_max)
    
    Furthermore, this patch includes the cleanup of a few warnings, and
    the fix of a corrupted test that ran into null pointer exceptions on
    probing the buffered std-output (which only exists if ran through mvn).
---
 .../apache/sysds/hops/rewrite/HopRewriteUtils.java | 25 ++++---
 .../RewriteAlgebraicSimplificationDynamic.java     | 18 +++++
 .../compress/colgroup/offset/OffsetSingle.java     |  1 +
 .../compress/colgroup/offset/OffsetTwo.java        |  1 +
 .../readers/ReadersTestCompareReaders.java         |  1 +
 .../pipelines/BuiltinTopkEvaluateTest.java         |  1 -
 ...MaxTest.java => RewriteCumsumConstantTest.java} | 83 ++++++++++++----------
 .../functions/rewrite/RewriteFoldMinMaxTest.java   | 15 +---
 .../functions/rewrite/RewriteFoldRCBindTest.java   | 15 +---
 .../rewrite/RewriteMMCBindZeroVector.java          |  1 +
 .../functions/rewrite/RewriteCumsumConstant1.dml   | 28 ++++++++
 .../functions/rewrite/RewriteCumsumConstant2.dml   | 28 ++++++++
 12 files changed, 139 insertions(+), 78 deletions(-)

diff --git a/src/main/java/org/apache/sysds/hops/rewrite/HopRewriteUtils.java b/src/main/java/org/apache/sysds/hops/rewrite/HopRewriteUtils.java
index 25201ccc86..6dbc5e35b6 100644
--- a/src/main/java/org/apache/sysds/hops/rewrite/HopRewriteUtils.java
+++ b/src/main/java/org/apache/sysds/hops/rewrite/HopRewriteUtils.java
@@ -775,23 +775,22 @@ public class HopRewriteUtils {
 	public static DataGenOp createSeqDataGenOp( Hop input, boolean asc ) {
 		Hop to = input.rowsKnown() ? new LiteralOp(input.getDim1()) : 
 			new UnaryOp("tmprows", DataType.SCALAR, ValueType.INT64, OpOp1.NROW, input);
-		
+		if( asc )
+			return createSeqDataGenOp(input, new LiteralOp(1), to, new LiteralOp(1));
+		else
+			return createSeqDataGenOp(input, to, new LiteralOp(1), new LiteralOp(-1));
+	}
+	
+	public static DataGenOp createSeqDataGenOp(Hop proxy, Hop from, Hop to, Hop incr) {
 		HashMap<String, Hop> params = new HashMap<>();
-		if( asc ) {
-			params.put(Statement.SEQ_FROM, new LiteralOp(1));
-			params.put(Statement.SEQ_TO, to);
-			params.put(Statement.SEQ_INCR, new LiteralOp(1));
-		}
-		else {
-			params.put(Statement.SEQ_FROM, to);
-			params.put(Statement.SEQ_TO, new LiteralOp(1));
-			params.put(Statement.SEQ_INCR, new LiteralOp(-1));	
-		}
+		params.put(Statement.SEQ_FROM, from);
+		params.put(Statement.SEQ_TO, to);
+		params.put(Statement.SEQ_INCR, incr);
 		
 		//note internal refresh size information
 		DataGenOp datagen = new DataGenOp(OpOpDG.SEQ, new DataIdentifier("tmp"), params);
-		datagen.setBlocksize(input.getBlocksize());
-		copyLineNumbers(input, datagen);
+		datagen.setBlocksize(proxy.getBlocksize());
+		copyLineNumbers(proxy, datagen);
 		
 		return datagen;
 	}
diff --git a/src/main/java/org/apache/sysds/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java b/src/main/java/org/apache/sysds/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java
index d0b1ac58d1..c142dab12f 100644
--- a/src/main/java/org/apache/sysds/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java
+++ b/src/main/java/org/apache/sysds/hops/rewrite/RewriteAlgebraicSimplificationDynamic.java
@@ -177,6 +177,7 @@ public class RewriteAlgebraicSimplificationDynamic extends HopRewriteRule
 			hi = simplifyDiagMatrixMult(hop, hi, i);          //e.g., diag(X%*%Y)->rowSums(X*t(Y)); if col vector
 			hi = simplifySumDiagToTrace(hi);                  //e.g., sum(diag(X)) -> trace(X); if col vector
 			hi = simplifyLowerTriExtraction(hop, hi, i);      //e.g., X * cumsum(diag(matrix(1,nrow(X),1))) -> lower.tri
+			hi = simplifyConstantCumsum(hop, hi, i);          //e.g., cumsum(matrix(1/n,n,1)) -> seq(1/n, 1, 1/n)
 			hi = pushdownBinaryOperationOnDiag(hop, hi, i);   //e.g., diag(X)*7 -> diag(X*7); if col vector
 			hi = pushdownSumOnAdditiveBinary(hop, hi, i);     //e.g., sum(A+B) -> sum(A)+sum(B); if dims(A)==dims(B)
 			if(OptimizerUtils.ALLOW_OPERATOR_FUSION) {
@@ -1217,6 +1218,23 @@ public class RewriteAlgebraicSimplificationDynamic extends HopRewriteRule
 		return hi;
 	}
 	
+	private static Hop simplifyConstantCumsum(Hop parent, Hop hi, int pos) {
+		//pattern: cumsum(matrix(1/n,n,1)) -> seq(1/n, 1, 1/n)
+		if( HopRewriteUtils.isUnary(hi, OpOp1.CUMSUM)
+			&& HopRewriteUtils.isDataGenOpWithConstantValue(hi.getInput(0))
+			&& hi.getInput(0).getParent().size() == 1 //cumsum only consumer
+			&& hi.dimsKnown() && hi.getDim2() == 1 )
+		{
+			Hop constVal = ((DataGenOp) hi.getInput(0)).getConstantValue();
+			Hop to = HopRewriteUtils.createBinary(new LiteralOp(hi.getDim1()), constVal, OpOp2.MULT);
+			Hop hnew = HopRewriteUtils.createSeqDataGenOp(hi, constVal, to, constVal);
+			HopRewriteUtils.replaceChildReference(parent, hi, hnew, pos);
+			hi = hnew;
+			LOG.debug("Applied simplifyConstantCumsum (line "+hi.getBeginLine()+").");
+		}
+		return hi;
+	}
+	
 	@SuppressWarnings("unchecked")
 	private static Hop pushdownBinaryOperationOnDiag(Hop parent, Hop hi, int pos) 
 	{
diff --git a/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetSingle.java b/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetSingle.java
index b01bbb0e4c..38ffc8b34a 100644
--- a/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetSingle.java
+++ b/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetSingle.java
@@ -24,6 +24,7 @@ import java.io.DataOutput;
 import java.io.IOException;
 
 public class OffsetSingle extends AOffset {
+	private static final long serialVersionUID = -614636669776415032L;
 
 	private final int off;
 
diff --git a/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetTwo.java b/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetTwo.java
index ac2f6338f0..fbb447f4b7 100644
--- a/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetTwo.java
+++ b/src/main/java/org/apache/sysds/runtime/compress/colgroup/offset/OffsetTwo.java
@@ -24,6 +24,7 @@ import java.io.DataOutput;
 import java.io.IOException;
 
 public class OffsetTwo extends AOffset {
+	private static final long serialVersionUID = -3756723021239389269L;
 
 	private final int first;
 	private final int last;
diff --git a/src/test/java/org/apache/sysds/test/component/compress/readers/ReadersTestCompareReaders.java b/src/test/java/org/apache/sysds/test/component/compress/readers/ReadersTestCompareReaders.java
index 9ae2ad780e..480b147000 100644
--- a/src/test/java/org/apache/sysds/test/component/compress/readers/ReadersTestCompareReaders.java
+++ b/src/test/java/org/apache/sysds/test/component/compress/readers/ReadersTestCompareReaders.java
@@ -548,6 +548,7 @@ public class ReadersTestCompareReaders {
 	}
 
 	private class DenseBlockFP64Mock extends DenseBlockFP64 {
+		private static final long serialVersionUID = -3601232958390554672L;
 
 		public DenseBlockFP64Mock(int[] dims, double[] data) {
 			super(dims, data);
diff --git a/src/test/java/org/apache/sysds/test/functions/pipelines/BuiltinTopkEvaluateTest.java b/src/test/java/org/apache/sysds/test/functions/pipelines/BuiltinTopkEvaluateTest.java
index b46dba2903..d1e7ba472d 100644
--- a/src/test/java/org/apache/sysds/test/functions/pipelines/BuiltinTopkEvaluateTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/pipelines/BuiltinTopkEvaluateTest.java
@@ -24,7 +24,6 @@ import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestConfiguration;
 import org.apache.sysds.test.TestUtils;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class BuiltinTopkEvaluateTest extends AutomatedTestBase {
diff --git a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldMinMaxTest.java b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteCumsumConstantTest.java
similarity index 55%
copy from src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldMinMaxTest.java
copy to src/test/java/org/apache/sysds/test/functions/rewrite/RewriteCumsumConstantTest.java
index cf8b4be365..e5a8625325 100644
--- a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldMinMaxTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteCumsumConstantTest.java
@@ -21,7 +21,6 @@ package org.apache.sysds.test.functions.rewrite;
 
 import org.junit.Assert;
 import org.junit.Test;
-import org.apache.sysds.api.DMLScript;
 import org.apache.sysds.common.Types.ExecMode;
 import org.apache.sysds.hops.OptimizerUtils;
 import org.apache.sysds.common.Types.ExecType;
@@ -29,18 +28,16 @@ import org.apache.sysds.runtime.matrix.data.MatrixValue.CellIndex;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestConfiguration;
 import org.apache.sysds.test.TestUtils;
-import org.apache.sysds.utils.Statistics;
 
-public class RewriteFoldMinMaxTest extends AutomatedTestBase 
+public class RewriteCumsumConstantTest extends AutomatedTestBase 
 {
-	private static final String TEST_NAME1 = "RewriteFoldMin";
-	private static final String TEST_NAME2 = "RewriteFoldMax";
+	private static final String TEST_NAME1 = "RewriteCumsumConstant1";
+	private static final String TEST_NAME2 = "RewriteCumsumConstant2";
 	
 	private static final String TEST_DIR = "functions/rewrite/";
-	private static final String TEST_CLASS_DIR = TEST_DIR + RewriteFoldMinMaxTest.class.getSimpleName() + "/";
+	private static final String TEST_CLASS_DIR = TEST_DIR + RewriteCumsumConstantTest.class.getSimpleName() + "/";
 	
-	private static final int rows = 1932;
-	private static final int cols = 14;
+	private static final int rows = 4;
 	
 	@Override
 	public void setUp() {
@@ -50,37 +47,48 @@ public class RewriteFoldMinMaxTest extends AutomatedTestBase
 	}
 
 	@Test
-	public void testRewriteFoldMinNoRewrite() {
-		testRewriteFoldMinMax( TEST_NAME1, false, ExecType.CP );
+	public void testRewriteCumsumPosNoRewrite() {
+		testRewriteCumsumConst( TEST_NAME1, false, 1, ExecType.CP );
 	}
 	
 	@Test
-	public void testRewriteFoldMinRewrite() {
-		testRewriteFoldMinMax( TEST_NAME1, true, ExecType.CP );
+	public void testRewriteCumsumPosRewrite() {
+		testRewriteCumsumConst( TEST_NAME1, true, 1, ExecType.CP );
 	}
 	
 	@Test
-	public void testRewriteFoldMaxNoRewrite() {
-		testRewriteFoldMinMax( TEST_NAME2, false, ExecType.CP );
+	public void testRewriteCumsumNegNoRewrite() {
+		testRewriteCumsumConst( TEST_NAME2, false, 1, ExecType.CP );
 	}
 	
 	@Test
-	public void testRewriteFoldMaxRewrite() {
-		testRewriteFoldMinMax( TEST_NAME2, true, ExecType.CP );
+	public void testRewriteCumsumNegRewrite() {
+		testRewriteCumsumConst( TEST_NAME2, true, 1, ExecType.CP );
+	}
+	
+	@Test
+	public void testRewriteCumsumPos2NoRewrite() {
+		testRewriteCumsumConst( TEST_NAME1, false, 2, ExecType.CP );
+	}
+	
+	@Test
+	public void testRewriteCumsumPos2Rewrite() {
+		testRewriteCumsumConst( TEST_NAME1, true, 2, ExecType.CP );
+	}
+	
+	@Test
+	public void testRewriteCumsumNeg2NoRewrite() {
+		testRewriteCumsumConst( TEST_NAME2, false, 2, ExecType.CP );
+	}
+	
+	@Test
+	public void testRewriteCumsumNeg2Rewrite() {
+		testRewriteCumsumConst( TEST_NAME2, true, 2, ExecType.CP );
 	}
 
-	private void testRewriteFoldMinMax( String testname, boolean rewrites, ExecType et )
+	private void testRewriteCumsumConst( String testname, boolean rewrites, int cols, ExecType et )
 	{
-		ExecMode platformOld = rtplatform;
-		switch( et ){
-			case SPARK: rtplatform = ExecMode.SPARK; break;
-			default: rtplatform = ExecMode.HYBRID; break;
-		}
-		
-		boolean sparkConfigOld = DMLScript.USE_LOCAL_SPARK_CONFIG;
-		if( rtplatform == ExecMode.SPARK || rtplatform == ExecMode.HYBRID )
-			DMLScript.USE_LOCAL_SPARK_CONFIG = true;
-		
+		ExecMode platformOld = setExecMode(et);
 		boolean oldFlag = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION;
 		
 		try {
@@ -89,29 +97,28 @@ public class RewriteFoldMinMaxTest extends AutomatedTestBase
 			
 			String HOME = SCRIPT_DIR + TEST_DIR;
 			fullDMLScriptName = HOME + testname + ".dml";
-			programArgs = new String[]{ "-stats", "-args", String.valueOf(rows), 
-					String.valueOf(cols), output("R") };
+			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); 
+			runTest(true, false, null, -1);
 			
 			//compare matrices 
 			Double ret = readDMLMatrixFromOutputDir("R").get(new CellIndex(1,1));
-			Assert.assertEquals("Wrong result", Double.valueOf(5*rows*cols), ret);
+			double expected = cols * ((double)rows*(rows+1)/2)/rows
+				* (testname.equals(TEST_NAME1) ? 1 : -1);
+			Assert.assertEquals("Wrong result", Double.valueOf(expected), 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));
+			if( rewrites && cols==1 ) { //sequence only for col vectors
+				Assert.assertTrue(!heavyHittersContainsString("rand")
+					&& !heavyHittersContainsString("ucumk+"));
 			}
 		}
 		finally {
 			OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION = oldFlag;
-			DMLScript.USE_LOCAL_SPARK_CONFIG = sparkConfigOld;
-			rtplatform = platformOld;
+			resetExecMode(platformOld);
 		}
 	}
 }
-
diff --git a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldMinMaxTest.java b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldMinMaxTest.java
index cf8b4be365..bcae201717 100644
--- a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldMinMaxTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldMinMaxTest.java
@@ -21,7 +21,6 @@ package org.apache.sysds.test.functions.rewrite;
 
 import org.junit.Assert;
 import org.junit.Test;
-import org.apache.sysds.api.DMLScript;
 import org.apache.sysds.common.Types.ExecMode;
 import org.apache.sysds.hops.OptimizerUtils;
 import org.apache.sysds.common.Types.ExecType;
@@ -71,16 +70,7 @@ public class RewriteFoldMinMaxTest extends AutomatedTestBase
 
 	private void testRewriteFoldMinMax( String testname, boolean rewrites, ExecType et )
 	{
-		ExecMode platformOld = rtplatform;
-		switch( et ){
-			case SPARK: rtplatform = ExecMode.SPARK; break;
-			default: rtplatform = ExecMode.HYBRID; break;
-		}
-		
-		boolean sparkConfigOld = DMLScript.USE_LOCAL_SPARK_CONFIG;
-		if( rtplatform == ExecMode.SPARK || rtplatform == ExecMode.HYBRID )
-			DMLScript.USE_LOCAL_SPARK_CONFIG = true;
-		
+		ExecMode platformOld = setExecMode(et);
 		boolean oldFlag = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION;
 		
 		try {
@@ -109,8 +99,7 @@ public class RewriteFoldMinMaxTest extends AutomatedTestBase
 		}
 		finally {
 			OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION = oldFlag;
-			DMLScript.USE_LOCAL_SPARK_CONFIG = sparkConfigOld;
-			rtplatform = platformOld;
+			resetExecMode(platformOld);
 		}
 	}
 }
diff --git a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldRCBindTest.java b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldRCBindTest.java
index ca09e23326..f25ce672f3 100644
--- a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldRCBindTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteFoldRCBindTest.java
@@ -21,7 +21,6 @@ package org.apache.sysds.test.functions.rewrite;
 
 import org.junit.Assert;
 import org.junit.Test;
-import org.apache.sysds.api.DMLScript;
 import org.apache.sysds.common.Types.ExecMode;
 import org.apache.sysds.hops.OptimizerUtils;
 import org.apache.sysds.common.Types.ExecType;
@@ -71,16 +70,7 @@ public class RewriteFoldRCBindTest extends AutomatedTestBase
 
 	private void testRewriteFoldRCBind( String testname, boolean rewrites, ExecType et )
 	{
-		ExecMode platformOld = rtplatform;
-		switch( et ){
-			case SPARK: rtplatform = ExecMode.SPARK; break;
-			default: rtplatform = ExecMode.HYBRID; break;
-		}
-		
-		boolean sparkConfigOld = DMLScript.USE_LOCAL_SPARK_CONFIG;
-		if( rtplatform == ExecMode.SPARK || rtplatform == ExecMode.HYBRID )
-			DMLScript.USE_LOCAL_SPARK_CONFIG = true;
-		
+		ExecMode platformOld = setExecMode(et);
 		boolean oldFlag = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION;
 		
 		try {
@@ -109,8 +99,7 @@ public class RewriteFoldRCBindTest extends AutomatedTestBase
 		}
 		finally {
 			OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION = oldFlag;
-			DMLScript.USE_LOCAL_SPARK_CONFIG = sparkConfigOld;
-			rtplatform = platformOld;
+			resetExecMode(platformOld);
 		}
 	}
 }
diff --git a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteMMCBindZeroVector.java b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteMMCBindZeroVector.java
index 6a8bfd77ae..d344d7eee3 100644
--- a/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteMMCBindZeroVector.java
+++ b/src/test/java/org/apache/sysds/test/functions/rewrite/RewriteMMCBindZeroVector.java
@@ -121,6 +121,7 @@ public class RewriteMMCBindZeroVector extends AutomatedTestBase {
 			writeInputMatrixWithMTD("Y", Y, false);
 
 			// execute tests
+			setOutputBuffering(true);
 			String out = runTest(null).toString();
 
 			for(String line : out.split("\n")) {
diff --git a/src/test/scripts/functions/rewrite/RewriteCumsumConstant1.dml b/src/test/scripts/functions/rewrite/RewriteCumsumConstant1.dml
new file mode 100644
index 0000000000..445f0e4c7a
--- /dev/null
+++ b/src/test/scripts/functions/rewrite/RewriteCumsumConstant1.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, $1, $2)
+Y = cumsum(X);
+
+while(FALSE){}
+R = as.matrix(sum(Y))
+
+write(R, $3);
diff --git a/src/test/scripts/functions/rewrite/RewriteCumsumConstant2.dml b/src/test/scripts/functions/rewrite/RewriteCumsumConstant2.dml
new file mode 100644
index 0000000000..fd1982eae1
--- /dev/null
+++ b/src/test/scripts/functions/rewrite/RewriteCumsumConstant2.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, $1, $2)
+Y = cumsum(X);
+
+while(FALSE){}
+R = as.matrix(sum(Y))
+
+write(R, $3);