You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemds.apache.org by ba...@apache.org on 2022/04/21 10:17:40 UTC

[systemds] branch main updated: [SYSTEMDS-3353] Sparse TSMM dense row block CSR

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

baunsgaard 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 ef6651095c [SYSTEMDS-3353] Sparse TSMM dense row block CSR
ef6651095c is described below

commit ef6651095cbf871128289cf04f5ea16c4e3532f9
Author: baunsgaard <ba...@tugraz.at>
AuthorDate: Wed Apr 20 15:11:28 2022 +0200

    [SYSTEMDS-3353] Sparse TSMM dense row block CSR
    
    This commit fixes a bug where CSR is not supported if it contains
    filled dense rows in Sparse TSMM Left.
    
    Closes #1592
---
 .../org/apache/sysds/runtime/data/SparseBlock.java |   2 +
 .../runtime/matrix/data/LibMatrixBincell.java      |   2 +
 .../sysds/runtime/matrix/data/LibMatrixMult.java   |  12 ++-
 .../sysds/runtime/matrix/data/MatrixBlock.java     |   3 +
 src/test/java/org/apache/sysds/test/TestUtils.java |   2 +-
 .../sysds/test/component/matrix/TSMMTest.java      | 101 +++++++++++++++++++++
 6 files changed, 118 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/sysds/runtime/data/SparseBlock.java b/src/main/java/org/apache/sysds/runtime/data/SparseBlock.java
index d876946be6..60b34b9e78 100644
--- a/src/main/java/org/apache/sysds/runtime/data/SparseBlock.java
+++ b/src/main/java/org/apache/sysds/runtime/data/SparseBlock.java
@@ -447,6 +447,8 @@ public abstract class SparseBlock implements Serializable
 	 * returned by indexes(r) and values(r). If no such value exists, 
 	 * this call returns -1.
 	 * 
+	 * Note if CSR the pos(r) is subtracted from the result.
+	 * 
 	 * @param r row index starting at 0
 	 * @param c column index starting at 0
 	 * @return position of the first column index greater than or equal to column c in row r
diff --git a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java
index 4651165f2b..43ba3791a4 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java
@@ -1638,6 +1638,8 @@ public class LibMatrixBincell {
 		if( op.fn instanceof Multiply ) { //skip empty
 			//skip empty: merge-join (with inner join semantics)
 			//similar to sorted list intersection
+			if(result.getSparseBlock() == null)
+				result.allocateSparseRowsBlock();
 			SparseBlock sblock = result.getSparseBlock();
 			sblock.allocate(resultRow, Math.min(size1, size2), result.clen);
 			while( p1 < size1 && p2 < size2 ) {
diff --git a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixMult.java b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixMult.java
index 0e003cad5f..674bb35b1d 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixMult.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixMult.java
@@ -2043,9 +2043,15 @@ public class LibMatrixMult
 					int alen = a.size(r);
 					double[] avals = a.values(r);
 					if( alen == n ) { //dense row
-						for( int i=rl; i<ru; i++ ) {
-							vectMultiplyAdd(avals[i], avals,
-								c.values(i), i, c.pos(i) + i, n-i);
+						final int apos = a.pos(r);
+						for (int i = rl; i < ru; i++){
+							double[] cvals = c.values(i);
+							int cix = c.pos(i);
+							double val = avals[i + apos];
+							for(int j = i ; j < ru; j++){
+								double d = val * avals[j + apos];
+								cvals[cix + j] +=d;
+							}
 						}
 					}
 					else { //non-full sparse row
diff --git a/src/main/java/org/apache/sysds/runtime/matrix/data/MatrixBlock.java b/src/main/java/org/apache/sysds/runtime/matrix/data/MatrixBlock.java
index 5df5d62e72..d65a6d548b 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/MatrixBlock.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/MatrixBlock.java
@@ -1279,6 +1279,8 @@ public class MatrixBlock extends MatrixValue implements CacheBlock, Externalizab
 				rptr, indexes, values, lnnz);
 		}
 		else {
+			// remember number non zeros.
+			long nnzTemp = getNonZeros();
 			//fallback to less-memory efficient MCSR format,
 			//which however allows much larger sparse matrices
 			if( !allocateSparseRowsBlock() )
@@ -1295,6 +1297,7 @@ public class MatrixBlock extends MatrixValue implements CacheBlock, Externalizab
 				for( int j=0; j<n; j++ )
 					sblock.append(i, j, avals[aix+j]);
 			}
+			nonZeros = nnzTemp;
 		}
 		
 		//update nnz and cleanup dense block
diff --git a/src/test/java/org/apache/sysds/test/TestUtils.java b/src/test/java/org/apache/sysds/test/TestUtils.java
index ace1c10726..f367032467 100644
--- a/src/test/java/org/apache/sysds/test/TestUtils.java
+++ b/src/test/java/org/apache/sysds/test/TestUtils.java
@@ -870,7 +870,7 @@ public class TestUtils
 		}
 		else if(actualMatrix.isEmpty()) {
 			if(expectedMatrix.getNumRows() < 10)
-				fail(message + "\nThe expected output is empty while the actual matrix is not\n" + expectedMatrix + "\n\n"
+				fail(message + "\nThe actual output is empty while the expected matrix is not\nexpected:" + expectedMatrix + "\n\n"
 					+ "actual:" + actualMatrix);
 			fail(message + "\nThe actual output is empty while the expected matrix is not");
 		}
diff --git a/src/test/java/org/apache/sysds/test/component/matrix/TSMMTest.java b/src/test/java/org/apache/sysds/test/component/matrix/TSMMTest.java
new file mode 100644
index 0000000000..d195ea952b
--- /dev/null
+++ b/src/test/java/org/apache/sysds/test/component/matrix/TSMMTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.sysds.lops.MMTSJ.MMTSJType;
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.test.TestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(value = Parameterized.class)
+public class TSMMTest {
+
+	protected static final Log LOG = LogFactory.getLog(TSMMTest.class.getName());
+
+	@Parameterized.Parameter
+	public MatrixBlock in;
+	@Parameterized.Parameter(1)
+	public int k;
+
+	@Parameters
+	public static Collection<Object[]> data() {
+		ArrayList<Object[]> tests = new ArrayList<>();
+		MatrixBlock mb;
+		final double[] spar = new double[] {0.3, 0.1, 0.01};
+		final int[] cols = new int[] {10, 6, 4, 3, 2, 1};
+		final int[] threads = new int[] {1, 10};
+		final int[] rows = new int[] {10};
+		for(int i = 0; i < 3; i++) { // seeds
+			for(int s = 0; s < spar.length; s++) {
+				for(int c = 0; c < cols.length; c++) {
+					for(int r = 0; r < rows.length; r++) {
+
+						mb = TestUtils.round(TestUtils.generateTestMatrixBlock(rows[r], cols[c], 1, 10, spar[s], i));
+						for(int t = 0; t < threads.length; t++)
+							tests.add(new Object[] {mb, threads[t]});
+					}
+				}
+
+			}
+		}
+		return tests;
+	}
+
+	@Test
+	public void testTSMMLeftSparseVSDense() {
+		final MMTSJType mType = MMTSJType.LEFT;
+		final MatrixBlock expected = in.transposeSelfMatrixMultOperations(null, mType, k);
+		final boolean isSparse = in.isInSparseFormat();
+
+		if(isSparse) {
+			MatrixBlock m2 = new MatrixBlock();
+			m2.copy(in);
+			m2.sparseToDense();
+			testCompare(expected, m2);
+		}
+		else {
+			MatrixBlock m2 = new MatrixBlock();
+			m2.copy(in);
+			m2.denseToSparse(true);
+			testCompare(expected, m2);
+
+			MatrixBlock m3 = new MatrixBlock();
+			m3.copy(in);
+			m3.copy(in);
+			m3.denseToSparse(false);
+			testCompare(expected, m3);
+		}
+	}
+
+	private void testCompare(MatrixBlock expected, MatrixBlock m2) {
+		final MMTSJType mType = MMTSJType.LEFT;
+		final MatrixBlock actual = m2.transposeSelfMatrixMultOperations(null, mType, k);
+		final String inString = m2.toString();
+		TestUtils.compareMatricesBitAvgDistance(expected, actual, 10L, 256L, inString);
+	}
+}