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 4a07cac  [SYSTEMDS-2577,2824] Fix sparse cumsumprod operations, 
functions tests
4a07cac is described below

commit 4a07cacffad03f2b31b3c650a609bb40997c6cd3
Author: Matthias Boehm <[email protected]>
AuthorDate: Wed Jun 2 23:52:52 2021 +0200

    [SYSTEMDS-2577,2824] Fix sparse cumsumprod operations, functions tests
    
    This patch fixes the missing support for sparse cumsumprod operations.
    The input is always a two-column matrix and hence was assumed dense.
    However, with ultra-sparse matrices and optimizations that use CSR as a
    more space-efficient data structure, sparse inputs can occur.
    
    Furthermore, this patch also adds dedicated tests for function
    precendence checks (user functions, dml-bodied builtins, namespace
    functions, native builtins) but these did not reveal additional issues.
---
 .../apache/sysds/runtime/data/SparseBlockMCSR.java |  3 +-
 .../sysds/runtime/matrix/data/LibMatrixAgg.java    | 33 +++++++++++
 .../test/component/matrix/CumsumprodTest.java      | 65 +++++++++++++++++++++
 .../sysds/test/component/matrix/SliceTest.java     | 68 +++++++++++-----------
 .../test/functions/misc/FunctionPotpourriTest.java |  6 ++
 .../misc/FunPotpourriBuiltinPrecedence.dml         | 38 ++++++++++++
 .../misc/FunPotpourriBuiltinPrecedence2.dml        | 26 +++++++++
 7 files changed, 204 insertions(+), 35 deletions(-)

diff --git a/src/main/java/org/apache/sysds/runtime/data/SparseBlockMCSR.java 
b/src/main/java/org/apache/sysds/runtime/data/SparseBlockMCSR.java
index 77caaec..159e581 100644
--- a/src/main/java/org/apache/sysds/runtime/data/SparseBlockMCSR.java
+++ b/src/main/java/org/apache/sysds/runtime/data/SparseBlockMCSR.java
@@ -48,7 +48,8 @@ public class SparseBlockMCSR extends SparseBlock
                        SparseRow[] orows = ((SparseBlockMCSR)sblock)._rows;
                        _rows = new SparseRow[orows.length];
                        for( int i=0; i<_rows.length; i++ )
-                               _rows[i] = new SparseRowVector(orows[i]);
+                               if( orows[i] != null )
+                                       _rows[i] = new 
SparseRowVector(orows[i]);
                }
                //general case SparseBlock
                else { 
diff --git 
a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixAgg.java 
b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixAgg.java
index 389700b..d9578ae 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixAgg.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixAgg.java
@@ -1549,6 +1549,12 @@ public class LibMatrixAgg
                                s_ucumkp(a, agg, dc, m, n, kbuff, kplus, rl, 
ru);
                                break;
                        }
+                       case CUM_SUM_PROD: { //CUMSUMPROD
+                               if( n != 2 )
+                                       throw new 
DMLRuntimeException("Cumsumprod expects two-column input (n="+n+").");
+                               s_ucumkpp(a, agg, dc, rl, ru);
+                               break;
+                       }
                        case CUM_PROD: { //CUMPROD
                                s_ucumm(a, agg, c, n, rl, ru);
                                break;
@@ -2365,6 +2371,33 @@ public class LibMatrixAgg
                }
        }
        
+       
+       /**
+        * CUMSUMPROD, opcode: ucumk+*, dense input.
+        * 
+        * @param a sparse block
+        * @param agg ?
+        * @param c ?
+        * @param rl row lower index
+        * @param ru row upper index
+        */
+       private static void s_ucumkpp( SparseBlock a, double[] agg, DenseBlock 
c, int rl, int ru ) {
+               //init current row sum/correction arrays w/ neutral 0
+               double sum = (agg != null) ? agg[0] : 0;
+               //scan once and compute prefix sums
+               double[] cvals = c.values(0);
+               for( int i=rl; i<ru; i++ ) {
+                       if( a.isEmpty(i) )
+                               sum = cvals[i] = 0;
+                       else if( a.size(i) == 2 ) {
+                               double[] avals = a.values(i); int apos = 
a.pos(i);
+                               sum = cvals[i] = avals[apos] + avals[apos+1] * 
sum;
+                       }
+                       else //fallback
+                               sum = cvals[i] = a.get(i,0) + a.get(i,1) * sum;
+               }
+       }
+       
        /**
         * CUMPROD, opcode: ucum*, sparse input.
         * 
diff --git 
a/src/test/java/org/apache/sysds/test/component/matrix/CumsumprodTest.java 
b/src/test/java/org/apache/sysds/test/component/matrix/CumsumprodTest.java
new file mode 100644
index 0000000..3ad96fe
--- /dev/null
+++ b/src/test/java/org/apache/sysds/test/component/matrix/CumsumprodTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.test.component.matrix;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.sysds.runtime.data.SparseBlock;
+import org.apache.sysds.runtime.functionobjects.Builtin;
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.runtime.matrix.operators.UnaryOperator;
+import org.junit.Test;
+
+public class CumsumprodTest {
+       @Test
+       public void testCumsumprodDense() {
+               MatrixBlock A = MatrixBlock.randOperations(100, 2, 0.9, 0, 10, 
"uniform", 7);
+               UnaryOperator uop = new 
UnaryOperator(Builtin.getBuiltinFnObject("ucumk+*"), 1, false);
+               MatrixBlock B = A.unaryOperations(uop, new MatrixBlock());
+               assertEquals(100, B.getNumRows());
+       }
+       
+       @Test
+       public void testCumsumprodSparseMCSR() {
+               MatrixBlock A = MatrixBlock.randOperations(1000, 2, 0.05, 0, 
10, "uniform", 7);
+               A = new MatrixBlock(A, SparseBlock.Type.MCSR, true);
+               UnaryOperator uop = new 
UnaryOperator(Builtin.getBuiltinFnObject("ucumk+*"), 1, false);
+               MatrixBlock B = A.unaryOperations(uop, new MatrixBlock());
+               assertEquals(1000, B.getNumRows());
+       }
+       
+       @Test
+       public void testCumsumprodSparseCSR() {
+               MatrixBlock A = MatrixBlock.randOperations(1000, 2, 0.05, 0, 
10, "uniform", 7);
+               A = new MatrixBlock(A, SparseBlock.Type.CSR, true);
+               UnaryOperator uop = new 
UnaryOperator(Builtin.getBuiltinFnObject("ucumk+*"), 1, false);
+               MatrixBlock B = A.unaryOperations(uop, new MatrixBlock());
+               assertEquals(1000, B.getNumRows());
+       }
+       
+       @Test
+       public void testCumsumprodSparseCOO() {
+               MatrixBlock A = MatrixBlock.randOperations(1000, 2, 0.05, 0, 
10, "uniform", 7);
+               A = new MatrixBlock(A, SparseBlock.Type.COO, true);
+               UnaryOperator uop = new 
UnaryOperator(Builtin.getBuiltinFnObject("ucumk+*"), 1, false);
+               MatrixBlock B = A.unaryOperations(uop, new MatrixBlock());
+               assertEquals(1000, B.getNumRows());
+       }
+}
diff --git 
a/src/test/java/org/apache/sysds/test/component/matrix/SliceTest.java 
b/src/test/java/org/apache/sysds/test/component/matrix/SliceTest.java
index f69df13..0fc0d7b 100644
--- a/src/test/java/org/apache/sysds/test/component/matrix/SliceTest.java
+++ b/src/test/java/org/apache/sysds/test/component/matrix/SliceTest.java
@@ -26,38 +26,38 @@ import org.apache.sysds.runtime.util.DataConverter;
 import org.junit.Test;
 
 public class SliceTest {
-    MatrixBlock a = genIncMatrix(10, 10);
-
-    @Test
-    public void sliceTest_01() {
-        MatrixBlock b = a.slice(0, 4);
-        assertEquals(5, b.getNumRows());
-    }
-
-    @Test
-    public void sliceTest_02() {
-        MatrixBlock b = a.slice(0, 9);
-        assertEquals(10, b.getNumRows());
-    }
-
-    @Test
-    public void sliceTest_03() {
-        MatrixBlock b = a.slice(9, 9);
-        assertEquals(1, b.getNumRows());
-    }
-
-    private static MatrixBlock gen(int[][] v) {
-        return DataConverter.convertToMatrixBlock(v);
-    }
-
-    private static MatrixBlock genIncMatrix(int rows, int cols) {
-        int[][] ret = new int[rows][cols];
-        int x = 0;
-        for(int i = 0; i < rows; i++) {
-            for(int j = 0; j < cols; j++) {
-                ret[i][j] = x++;
-            }
-        }
-        return gen(ret);
-    }
+       MatrixBlock a = genIncMatrix(10, 10);
+
+       @Test
+       public void sliceTest_01() {
+               MatrixBlock b = a.slice(0, 4);
+               assertEquals(5, b.getNumRows());
+       }
+
+       @Test
+       public void sliceTest_02() {
+               MatrixBlock b = a.slice(0, 9);
+               assertEquals(10, b.getNumRows());
+       }
+
+       @Test
+       public void sliceTest_03() {
+               MatrixBlock b = a.slice(9, 9);
+               assertEquals(1, b.getNumRows());
+       }
+
+       private static MatrixBlock gen(int[][] v) {
+               return DataConverter.convertToMatrixBlock(v);
+       }
+
+       private static MatrixBlock genIncMatrix(int rows, int cols) {
+               int[][] ret = new int[rows][cols];
+               int x = 0;
+               for(int i = 0; i < rows; i++) {
+                       for(int j = 0; j < cols; j++) {
+                               ret[i][j] = x++;
+                       }
+               }
+               return gen(ret);
+       }
 }
diff --git 
a/src/test/java/org/apache/sysds/test/functions/misc/FunctionPotpourriTest.java 
b/src/test/java/org/apache/sysds/test/functions/misc/FunctionPotpourriTest.java
index b174dbb..6756272 100644
--- 
a/src/test/java/org/apache/sysds/test/functions/misc/FunctionPotpourriTest.java
+++ 
b/src/test/java/org/apache/sysds/test/functions/misc/FunctionPotpourriTest.java
@@ -55,6 +55,7 @@ public class FunctionPotpourriTest extends AutomatedTestBase
                "FunPotpourriEvalList1Arg",
                "FunPotpourriEvalList2Arg",
                "FunPotpourriEvalNamespace",
+               "FunPotpourriBuiltinPrecedence",
        };
        
        private final static String TEST_DIR = "functions/misc/";
@@ -192,6 +193,11 @@ public class FunctionPotpourriTest extends 
AutomatedTestBase
                runFunctionTest( TEST_NAMES[24], null );
        }
        
+       @Test
+       public void testFunctionBuiltinPrecedence() {
+               runFunctionTest( TEST_NAMES[25], null );
+       }
+       
        private void runFunctionTest(String testName, Class<?> error) {
                TestConfiguration config = getTestConfiguration(testName);
                loadTestConfiguration(config);
diff --git a/src/test/scripts/functions/misc/FunPotpourriBuiltinPrecedence.dml 
b/src/test/scripts/functions/misc/FunPotpourriBuiltinPrecedence.dml
new file mode 100644
index 0000000..3e557a0
--- /dev/null
+++ b/src/test/scripts/functions/misc/FunPotpourriBuiltinPrecedence.dml
@@ -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.
+#
+#-------------------------------------------------------------
+
+source("./src/test/scripts/functions/misc/FunPotpourriBuiltinPrecedence2.dml") 
as NS
+
+sigmoid = function(Matrix[Double] X) return (Matrix[Double] Y) {
+  while(FALSE){} # no inlining
+  #Y = 1 / (1 + exp(-X));
+  Y = 1 / (1 + exp(-X)) * 2; # corrupted result
+}
+
+X = rand(rows=10, cols=10, seed=7)
+R1 = 1 / (1 + exp(-X)); # sigmoid
+R2 = sigmoid(X); #must not call builtin
+R3 = NS::sigmoid(X); #must not call builtin or local 
+
+if( sum(abs(R1*2 - R2) > 1e-8) != 0 )
+   print(R2[-sum(R1),-sum(R2)]) #crash test
+if( sum(abs(R1*3 - R3) > 1e-8) != 0 )
+   print(R3[-sum(R1),-sum(R3)]) #crash test
diff --git a/src/test/scripts/functions/misc/FunPotpourriBuiltinPrecedence2.dml 
b/src/test/scripts/functions/misc/FunPotpourriBuiltinPrecedence2.dml
new file mode 100644
index 0000000..a8e21a2
--- /dev/null
+++ b/src/test/scripts/functions/misc/FunPotpourriBuiltinPrecedence2.dml
@@ -0,0 +1,26 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+sigmoid = function(Matrix[Double] X) return (Matrix[Double] Y) {
+  while(FALSE){} # no inlining
+  #Y = 1 / (1 + exp(-X));
+  Y = 1 / (1 + exp(-X)) * 3; # corrupted result
+}

Reply via email to