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

mboehm7 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/systemds.git


The following commit(s) were added to refs/heads/master by this push:
     new 0bf27ea  [SYSTEMDS-2802] Fix parfor handling of negative loop 
increments
0bf27ea is described below

commit 0bf27eaad3ffb40da8e6bf87d42721f0a333ba19
Author: Matthias Boehm <[email protected]>
AuthorDate: Sat Jan 23 18:13:32 2021 +0100

    [SYSTEMDS-2802] Fix parfor handling of negative loop increments
    
    * Fix parfor dependency analysis for negative increments (via
    normalization)
    * Fix parfor runtime program block (determine number of iterations
    correctly, to prevent invalid early-abort)
    * Fix removed local debug flag for parfor dependency analysis
    * Tests for parfor dependency analysis and runtime predicates
---
 .../apache/sysds/parser/ParForStatementBlock.java  | 26 ++++++-
 .../runtime/controlprogram/ParForProgramBlock.java |  7 +-
 .../parfor/ParForDependencyAnalysisTest.java       |  9 ++-
 .../parfor/misc/ForLoopPredicateTest.java          | 90 +++++++++++-----------
 src/test/scripts/component/parfor/parfor55a.dml    | 29 +++++++
 src/test/scripts/component/parfor/parfor55b.dml    | 29 +++++++
 .../scripts/functions/parfor/parfor_pred1_neg.dml  | 25 ++++++
 .../scripts/functions/parfor/parfor_pred2_neg.dml  | 27 +++++++
 8 files changed, 189 insertions(+), 53 deletions(-)

diff --git a/src/main/java/org/apache/sysds/parser/ParForStatementBlock.java 
b/src/main/java/org/apache/sysds/parser/ParForStatementBlock.java
index b88d8c3..af88d60 100644
--- a/src/main/java/org/apache/sysds/parser/ParForStatementBlock.java
+++ b/src/main/java/org/apache/sysds/parser/ParForStatementBlock.java
@@ -33,6 +33,10 @@ import org.apache.sysds.hops.IndexingOp;
 import org.apache.sysds.hops.LiteralOp;
 import org.apache.sysds.hops.OptimizerUtils;
 import org.apache.sysds.hops.rewrite.HopRewriteUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
 import org.apache.sysds.common.Builtins;
 import org.apache.sysds.common.Types.DataType;
 import org.apache.sysds.common.Types.OpOp1;
@@ -60,6 +64,9 @@ import org.apache.sysds.runtime.util.UtilFunctions;
  */
 public class ParForStatementBlock extends ForStatementBlock 
 {
+       private static final boolean LDEBUG = false; //internal local debug 
level
+       protected static final Log LOG = 
LogFactory.getLog(ParForStatementBlock.class.getName());
+       
        //external parameter names 
        private static HashSet<String> _paramNames;
        public static final String CHECK            = "check";       //run loop 
dependency analysis
@@ -140,6 +147,13 @@ public class ParForStatementBlock extends ForStatementBlock
                if( USE_FN_CACHE ) {
                        _fncache = new HashMap<>();
                }
+               
+               // for internal debugging only
+               if( LDEBUG ) {
+                       
Logger.getLogger("org.apache.sysds.parser.ParForStatementBlock")
+                               .setLevel(Level.TRACE);
+                       System.out.println();
+               }
        }
        
        public ParForStatementBlock() {
@@ -908,7 +922,15 @@ public class ParForStatementBlock extends ForStatementBlock
                                                incr = 
((IntIdentifier)ip.getIncrementExpr()).getValue();
                                        else 
                                                incr = ( low <= up ) ? 1 : -1;
-
+                                       
+                                       //normalize bounds to positive 
increment (for dependency analysis only)
+                                       if( incr < 0 ) {
+                                               long tmp = low;
+                                               low = up;
+                                               up = tmp;
+                                               incr *= -1; //positive increment
+                                       }
+                                       
                                        
_bounds._lower.put(ip.getIterVar()._name, low);
                                        
_bounds._upper.put(ip.getIterVar()._name, up);
                                        
_bounds._increment.put(ip.getIterVar()._name, incr);
@@ -1093,7 +1115,7 @@ public class ParForStatementBlock extends 
ForStatementBlock
                        //min/max bound 
                        int len = Math.max(f1._b.length, f2._b.length);
                        boolean invalid = false;
-                       for( int i=0; i<len; i++ ) 
+                       for( int i=0; i<len; i++ )
                        {
                                String var=(f1._b.length>i) ? f1._vars[i] : 
f2._vars[i];
                                if( !_bounds._lower.containsKey(var) || 
!_bounds._upper.containsKey(var) ) {
diff --git 
a/src/main/java/org/apache/sysds/runtime/controlprogram/ParForProgramBlock.java 
b/src/main/java/org/apache/sysds/runtime/controlprogram/ParForProgramBlock.java
index 1e4281c..d95512f 100644
--- 
a/src/main/java/org/apache/sysds/runtime/controlprogram/ParForProgramBlock.java
+++ 
b/src/main/java/org/apache/sysds/runtime/controlprogram/ParForProgramBlock.java
@@ -569,7 +569,8 @@ public class ParForProgramBlock extends ForProgramBlock
                                + "of variable '" + _iterPredVar + "' must 
evaluate to a non-zero value.");
                
                //early exit on num iterations = zero
-               _numIterations = computeNumIterations(from, to, incr);
+               _numIterations = UtilFunctions.getSeqLength(
+                       from.getDoubleValue(), to.getDoubleValue(), 
incr.getDoubleValue());
                if( _numIterations <= 0 )
                        return; //avoid unnecessary optimization/initialization
                
@@ -1519,10 +1520,6 @@ public class ParForProgramBlock extends ForProgramBlock
                                StatisticMonitor.putPfPwMapping(_ID, _pwIDs[i]);
                }
        }
-
-       private static long computeNumIterations( IntObject from, IntObject to, 
IntObject incr ) {
-               return (long)Math.ceil(((double)(to.getLongValue() - 
from.getLongValue() + 1)) / incr.getLongValue()); 
-       }
        
        /**
         * NOTE: Only required for remote parfor. Hence, there is no need to 
transfer DMLConfig to
diff --git 
a/src/test/java/org/apache/sysds/test/component/parfor/ParForDependencyAnalysisTest.java
 
b/src/test/java/org/apache/sysds/test/component/parfor/ParForDependencyAnalysisTest.java
index e8dac4e..04f575a 100644
--- 
a/src/test/java/org/apache/sysds/test/component/parfor/ParForDependencyAnalysisTest.java
+++ 
b/src/test/java/org/apache/sysds/test/component/parfor/ParForDependencyAnalysisTest.java
@@ -68,6 +68,8 @@ import org.apache.sysds.test.TestConfiguration;
  *    53a: no, 53b dep, 53c dep, 53d dep, 53e dep
  * * lists
  *    54a: no, 54b: no, 54c: dep, 54d: dep
+ * * negative loop increment
+ *    55a: no, 55b: yes
  */
 public class ParForDependencyAnalysisTest extends AutomatedTestBase
 {
@@ -325,6 +327,12 @@ public class ParForDependencyAnalysisTest extends 
AutomatedTestBase
        @Test
        public void testDependencyAnalysis54d() { runTest("parfor54d.dml", 
true); }
        
+       @Test
+       public void testDependencyAnalysis55a() { runTest("parfor55a.dml", 
false); }
+       
+       @Test
+       public void testDependencyAnalysis55b() { runTest("parfor55b.dml", 
true); }
+       
        private void runTest( String scriptFilename, boolean expectedException 
) {
                boolean raisedException = false;
                try
@@ -371,5 +379,4 @@ public class ParForDependencyAnalysisTest extends 
AutomatedTestBase
                //check correctness
                Assert.assertEquals(expectedException, raisedException);
        }
-       
 }
diff --git 
a/src/test/java/org/apache/sysds/test/functions/parfor/misc/ForLoopPredicateTest.java
 
b/src/test/java/org/apache/sysds/test/functions/parfor/misc/ForLoopPredicateTest.java
index aea2a15..c2ecb9e 100644
--- 
a/src/test/java/org/apache/sysds/test/functions/parfor/misc/ForLoopPredicateTest.java
+++ 
b/src/test/java/org/apache/sysds/test/functions/parfor/misc/ForLoopPredicateTest.java
@@ -29,7 +29,6 @@ import org.apache.sysds.test.TestConfiguration;
 
 public class ForLoopPredicateTest extends AutomatedTestBase 
 {
-       
        private final static String TEST_NAME1 = "for_pred1a"; //const
        private final static String TEST_NAME2 = "for_pred1b"; //const seq
        private final static String TEST_NAME3 = "for_pred2a"; //var
@@ -37,6 +36,8 @@ public class ForLoopPredicateTest extends AutomatedTestBase
        private final static String TEST_NAME5 = "for_pred3a"; //expression
        private final static String TEST_NAME6 = "for_pred3b"; //expression seq
        private final static String TEST_NAME7 = "for_pred1a_seq"; //const seq 
two parameters (this tests is only for parser)
+       private final static String TEST_NAME8 = "parfor_pred1_neg"; //to:from 
(negative increment)
+       private final static String TEST_NAME9 = "parfor_pred2_neg"; //2:1 
(negative increment, two steps)
        private final static String TEST_DIR = "functions/parfor/";
        private final static String TEST_CLASS_DIR = TEST_DIR + 
ForLoopPredicateTest.class.getSimpleName() + "/";
        
@@ -45,8 +46,7 @@ public class ForLoopPredicateTest extends AutomatedTestBase
        private final static int increment = 1;
        
        @Override
-       public void setUp() 
-       {
+       public void setUp() {
                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"}));
                addTestConfiguration(TEST_NAME3, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME3, new String[]{"R"}));
@@ -54,102 +54,103 @@ public class ForLoopPredicateTest extends 
AutomatedTestBase
                addTestConfiguration(TEST_NAME5, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME5, new String[]{"R"}));
                addTestConfiguration(TEST_NAME6, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME6, new String[]{"R"}));
                addTestConfiguration(TEST_NAME7, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME7, new String[]{"R"}));
+               addTestConfiguration(TEST_NAME8, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME8, new String[]{"R"}));
+               addTestConfiguration(TEST_NAME9, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME9, new String[]{"R"}));
        }
 
        @Test
-       public void testForConstIntegerPredicate() 
-       {
+       public void testForConstIntegerPredicate() {
                runForPredicateTest(1, true);
        }
        
        @Test
-       public void testForConstIntegerSeq2ParametersPredicate() 
-       {
+       public void testForConstIntegerSeq2ParametersPredicate() {
                runForPredicateTest(7, true);
        }
        
        @Test
-       public void testForConstIntegerSeqPredicate() 
-       {
+       public void testForConstIntegerSeqPredicate() {
                runForPredicateTest(2, true);
        }
        
        @Test
-       public void testForVariableIntegerPredicate() 
-       {
+       public void testForVariableIntegerPredicate() {
                runForPredicateTest(3, true);
        }
        
        @Test
-       public void testForVariableIntegerSeqPredicate() 
-       {
+       public void testForVariableIntegerSeqPredicate() {
                runForPredicateTest(4, true);
        }
        
        @Test
-       public void testForExpressionIntegerPredicate() 
-       {
+       public void testForExpressionIntegerPredicate() {
                runForPredicateTest(5, true);
        }
        
        @Test
-       public void testForExpressionIntegerSeqPredicate() 
-       {
+       public void testForExpressionIntegerSeqPredicate() {
                runForPredicateTest(6, true);
        }
 
        @Test
-       public void testForConstDoublePredicate() 
-       {
+       public void testForConstDoublePredicate() {
                runForPredicateTest(1, false);
        }
        
        @Test
-       public void testForConstDoubleSeq2ParametersPredicate() 
-       {
+       public void testForConstDoubleSeq2ParametersPredicate() {
                runForPredicateTest(7, false);
        }
        
        @Test
-       public void testForConstDoubleSeqPredicate() 
-       {
+       public void testForConstDoubleSeqPredicate() {
                runForPredicateTest(2, false);
        }
        
        @Test
-       public void testForVariableDoublePredicate() 
-       {
+       public void testForVariableDoublePredicate() {
                runForPredicateTest(3, false);
        }
        
        @Test
-       public void testForVariableDoubleSeqPredicate() 
-       {
+       public void testForVariableDoubleSeqPredicate() {
                runForPredicateTest(4, false);
        }
        
        @Test
-       public void testForExpressionDoublePredicate() 
-       {
+       public void testForExpressionDoublePredicate() {
                runForPredicateTest(5, false);
        }
        
        @Test
-       public void testForExpressionDoubleSeqPredicate() 
-       {
+       public void testForExpressionDoubleSeqPredicate() {
                runForPredicateTest(6, false);
        }
        
-       /**
-        * 
-        * @param testNum
-        * @param intScalar
-        */
-       private void runForPredicateTest( int testNum, boolean intScalar )
+       @Test
+       public void testParFor1IntNegativeIncrement() {
+               runForPredicateTest(8, true, true);
+       }
+       
+       @Test
+       public void testParFor1DoubleNegativeIncrement() {
+               runForPredicateTest(8, false, true);
+       }
+       
+       @Test
+       public void testParFor2IntNegativeIncrement() {
+               runForPredicateTest(9, true, true);
+       }
+       
+       private void runForPredicateTest( int testNum, boolean intScalar ) {
+               runForPredicateTest(testNum, intScalar, false);
+       }
+       
+       private void runForPredicateTest( int testNum, boolean intScalar, 
boolean negative )
        {
                String TEST_NAME = null;
-               switch( testNum )
-               {
+               switch( testNum ) {
                        case 1: TEST_NAME = TEST_NAME1; break;
                        case 2: TEST_NAME = TEST_NAME2; break;
                        case 3: TEST_NAME = TEST_NAME3; break;
@@ -157,6 +158,8 @@ public class ForLoopPredicateTest extends AutomatedTestBase
                        case 5: TEST_NAME = TEST_NAME5; break;
                        case 6: TEST_NAME = TEST_NAME6; break;
                        case 7: TEST_NAME = TEST_NAME7; break;
+                       case 8: TEST_NAME = TEST_NAME8; break;
+                       case 9: TEST_NAME = TEST_NAME9; break;
                }
                
                getAndLoadTestConfiguration(TEST_NAME);
@@ -164,14 +167,12 @@ public class ForLoopPredicateTest extends 
AutomatedTestBase
                Object valFrom = null;
                Object valTo = null;
                Object valIncrement = null;
-               if( intScalar )
-               {
+               if( intScalar ) {
                        valFrom = Integer.valueOf((int)Math.round(from));
                        valTo = Integer.valueOf((int)Math.round(to));
                        valIncrement = Integer.valueOf(increment);
                }
-               else
-               {
+               else {
                        valFrom = new Double(from);
                        valTo = new Double(to);
                        valIncrement = new Double(increment);
@@ -196,5 +197,4 @@ public class ForLoopPredicateTest extends AutomatedTestBase
                Assert.assertEquals( 
Double.valueOf(Math.ceil((Math.round(to)-Math.round(from)+1)/increment)),
                                             dmlfile.get(new CellIndex(1,1)));
        }
-       
-}
\ No newline at end of file
+}
diff --git a/src/test/scripts/component/parfor/parfor55a.dml 
b/src/test/scripts/component/parfor/parfor55a.dml
new file mode 100644
index 0000000..21a8c48
--- /dev/null
+++ b/src/test/scripts/component/parfor/parfor55a.dml
@@ -0,0 +1,29 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+
+A = matrix(0, rows=10,cols=1);
+B = Rand(rows=10,cols=1);
+
+parfor( i in 10:1 ) 
+  A[i,1] = B[i,1];
+
+#print(A);
diff --git a/src/test/scripts/component/parfor/parfor55b.dml 
b/src/test/scripts/component/parfor/parfor55b.dml
new file mode 100644
index 0000000..fbc8fff4
--- /dev/null
+++ b/src/test/scripts/component/parfor/parfor55b.dml
@@ -0,0 +1,29 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+
+A = matrix(0,rows=10,cols=1);
+B = Rand(rows=10,cols=1);
+
+parfor( i in 10:2 )
+  A[i,1] = B[i,1] + A[i-1,1];
+
+#print(A);
diff --git a/src/test/scripts/functions/parfor/parfor_pred1_neg.dml 
b/src/test/scripts/functions/parfor/parfor_pred1_neg.dml
new file mode 100644
index 0000000..bb1d8db
--- /dev/null
+++ b/src/test/scripts/functions/parfor/parfor_pred1_neg.dml
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+R = matrix(0, rows=1, cols=1);
+parfor( i in $2:$1 )
+  R += matrix(1,1,1);
+write(R, $4); 
diff --git a/src/test/scripts/functions/parfor/parfor_pred2_neg.dml 
b/src/test/scripts/functions/parfor/parfor_pred2_neg.dml
new file mode 100644
index 0000000..fb6c022
--- /dev/null
+++ b/src/test/scripts/functions/parfor/parfor_pred2_neg.dml
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+R = matrix(0, rows=1, cols=1);
+parfor( i in 2:1 )
+  R += matrix(1,1,1);
+off = ceil(round($2)-round($1)+1)-2;
+R += matrix(off,1,1);
+write(R, $4); 

Reply via email to