Repository: incubator-systemml Updated Branches: refs/heads/master de270219f -> 5de7beea2
[SYSTEMML-1448] Support rowMins/rowMaxs in codegen row aggregates This patch extends the codegen compiler by rowmins and rowmax for row aggregate templates and introduces the related runtime primitives. Furthermore, this patch also fixes various existing primitives such as sparse rowSums, and dense vector comparisons. Project: http://git-wip-us.apache.org/repos/asf/incubator-systemml/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-systemml/commit/18ab98a6 Tree: http://git-wip-us.apache.org/repos/asf/incubator-systemml/tree/18ab98a6 Diff: http://git-wip-us.apache.org/repos/asf/incubator-systemml/diff/18ab98a6 Branch: refs/heads/master Commit: 18ab98a6e2083551618f4bf62dba3a19574b115b Parents: de27021 Author: Matthias Boehm <[email protected]> Authored: Fri Apr 7 19:45:41 2017 -0700 Committer: Matthias Boehm <[email protected]> Committed: Fri Apr 7 19:45:41 2017 -0700 ---------------------------------------------------------------------- .../sysml/hops/codegen/cplan/CNodeUnary.java | 15 ++++- .../hops/codegen/template/TemplateRowAgg.java | 10 +++- .../runtime/codegen/LibSpoofPrimitives.java | 60 ++++++++++++++------ .../functions/codegen/AlgorithmLinregCG.java | 4 +- .../functions/codegen/RowAggTmplTest.java | 13 ++++- .../scripts/functions/codegen/rowAggPattern10.R | 34 +++++++++++ .../functions/codegen/rowAggPattern10.dml | 28 +++++++++ 7 files changed, 139 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/18ab98a6/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java b/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java index 9d3a877..262295c 100644 --- a/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java +++ b/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java @@ -21,13 +21,15 @@ package org.apache.sysml.hops.codegen.cplan; import java.util.Arrays; +import org.apache.commons.lang.StringUtils; import org.apache.sysml.parser.Expression.DataType; public class CNodeUnary extends CNode { public enum UnaryType { - ROW_SUMS, LOOKUP_R, LOOKUP_RC, LOOKUP0, //codegen specific + LOOKUP_R, LOOKUP_RC, LOOKUP0, //codegen specific + ROW_SUMS, ROW_MINS, ROW_MAXS, //codegen specific EXP, POW2, MULT2, SQRT, LOG, LOG_NZ, ABS, ROUND, CEIL, FLOOR, SIGN, SIN, COS, TAN, ASIN, ACOS, ATAN, @@ -43,8 +45,11 @@ public class CNodeUnary extends CNode public String getTemplate(boolean sparse) { switch( this ) { case ROW_SUMS: - return sparse ? " double %TMP% = LibSpoofPrimitives.vectSum(%IN1v%, %IN1i%, %POS1%, %LEN%);\n": - " double %TMP% = LibSpoofPrimitives.vectSum(%IN1%, %POS1%, %LEN%);\n"; + case ROW_MINS: + case ROW_MAXS: + String vectName = StringUtils.capitalize(this.toString().substring(4,7).toLowerCase()); + return sparse ? " double %TMP% = LibSpoofPrimitives.vect"+vectName+"(%IN1v%, %IN1i%, %POS1%, %LEN%);\n": + " double %TMP% = LibSpoofPrimitives.vect"+vectName+"(%IN1%, %POS1%, %LEN%);\n"; case EXP: return " double %TMP% = FastMath.exp(%IN1%);\n"; case LOOKUP_R: @@ -153,6 +158,8 @@ public class CNodeUnary extends CNode public String toString() { switch(_type) { case ROW_SUMS: return "u(R+)"; + case ROW_MINS: return "u(Rmin)"; + case ROW_MAXS: return "u(Rmax)"; case LOOKUP_R: return "u(ixr)"; case LOOKUP_RC: return "u(ixrc)"; case LOOKUP0: return "u(ix0)"; @@ -165,6 +172,8 @@ public class CNodeUnary extends CNode public void setOutputDims() { switch(_type) { case ROW_SUMS: + case ROW_MINS: + case ROW_MAXS: case EXP: case LOOKUP_R: case LOOKUP_RC: http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/18ab98a6/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRowAgg.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRowAgg.java b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRowAgg.java index 63f7cc6..49d0cb8 100644 --- a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRowAgg.java +++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRowAgg.java @@ -55,6 +55,7 @@ import org.apache.sysml.runtime.matrix.data.Pair; public class TemplateRowAgg extends TemplateBase { + private static final Hop.AggOp[] SUPPORTED_ROW_AGG = new AggOp[]{AggOp.SUM, AggOp.MIN, AggOp.MAX}; private static final Hop.OpOp2[] SUPPORTED_VECT_BINARY = new OpOp2[]{OpOp2.MULT, OpOp2.DIV, OpOp2.EQUAL, OpOp2.NOTEQUAL, OpOp2.LESS, OpOp2.LESSEQUAL, OpOp2.GREATER, OpOp2.GREATEREQUAL}; @@ -157,11 +158,12 @@ public class TemplateRowAgg extends TemplateBase if(hop instanceof AggUnaryOp) { CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID()); - if( ((AggUnaryOp)hop).getDirection() == Direction.Row && ((AggUnaryOp)hop).getOp() == AggOp.SUM ) { + if( ((AggUnaryOp)hop).getDirection() == Direction.Row && HopRewriteUtils.isAggUnaryOp(hop, SUPPORTED_ROW_AGG) ) { if(hop.getInput().get(0).getDim2()==1) out = (cdata1.getDataType()==DataType.SCALAR) ? cdata1 : new CNodeUnary(cdata1,UnaryType.LOOKUP_R); else { - out = new CNodeUnary(cdata1, UnaryType.ROW_SUMS); + String opcode = "ROW_"+((AggUnaryOp)hop).getOp().name().toUpperCase()+"S"; + out = new CNodeUnary(cdata1, UnaryType.valueOf(opcode)); inHops2.put("X", hop.getInput().get(0)); } } @@ -284,6 +286,10 @@ public class TemplateRowAgg extends TemplateBase TernaryType.LOOKUP_RC1); } + if( out == null ) { + throw new RuntimeException(hop.getHopID()+" "+hop.getOpString()); + } + if( out.getDataType().isMatrix() ) { out.setNumRows(hop.getDim1()); out.setNumCols(hop.getDim2()); http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/18ab98a6/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java b/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java index dfe3244..6907b0b 100644 --- a/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java +++ b/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java @@ -74,7 +74,7 @@ public class LibSpoofPrimitives return c; } - // custom vector sums + // custom vector sums, mins, maxs /** * Computes c = sum(A), where A is a dense vectors. @@ -89,14 +89,14 @@ public class LibSpoofPrimitives final int bn = len%8; //compute rest - for( int i = 0; i < bn; i++, ai++ ) - val += a[ ai ]; + for( int i = ai; i < ai+bn; i++ ) + val += a[ i ]; //unrolled 8-block (for better instruction-level parallelism) - for( int i = bn; i < len; i+=8, ai+=8 ) { + for( int i = ai+bn; i < ai+len; i+=8 ) { //read 64B cacheline of a, compute cval' = sum(a) + cval - val += a[ ai+0 ] + a[ ai+1 ] + a[ ai+2 ] + a[ ai+3 ] - + a[ ai+4 ] + a[ ai+5 ] + a[ ai+6 ] + a[ ai+7 ]; + val += a[ i+0 ] + a[ i+1 ] + a[ i+2 ] + a[ i+3 ] + + a[ i+4 ] + a[ i+5 ] + a[ i+6 ] + a[ i+7 ]; } //scalar result @@ -118,23 +118,51 @@ public class LibSpoofPrimitives //compute rest for( int i = ai; i < ai+bn; i++ ) - val += avals[ ai+aix[i] ]; + val += avals[ aix[i] ]; //unrolled 8-block (for better instruction-level parallelism) for( int i = ai+bn; i < ai+len; i+=8 ) { //read 64B of a via 'gather' //compute cval' = sum(a) + cval - val += avals[ ai+aix[i+0] ] + avals[ ai+aix[i+1] ] - + avals[ ai+aix[i+2] ] + avals[ ai+aix[i+3] ] - + avals[ ai+aix[i+4] ] + avals[ ai+aix[i+5] ] - + avals[ ai+aix[i+6] ] + avals[ ai+aix[i+7] ]; + val += avals[ aix[i+0] ] + avals[ aix[i+1] ] + + avals[ aix[i+2] ] + avals[ aix[i+3] ] + + avals[ aix[i+4] ] + avals[ aix[i+5] ] + + avals[ aix[i+6] ] + avals[ aix[i+7] ]; } //scalar result return val; + } + + public static double vectMin(double[] a, int ai, int len) { + double val = Double.MAX_VALUE; + for( int i = ai; i < ai+len; i++ ) + val = Math.min(a[ai], val); + return val; } + public static double vectMin(double[] avals, int[] aix, int ai, int len) { + double val = Double.MAX_VALUE; + for( int i = ai; i < ai+len; i++ ) + val = Math.min(avals[aix[i]], val); + return val; + } + + public static double vectMax(double[] a, int ai, int len) { + double val = -Double.MAX_VALUE; + for( int i = ai; i < ai+len; i++ ) + val = Math.max(a[ai], val); + return val; + } + + public static double vectMax(double[] avals, int[] aix, int ai, int len) { + double val = -Double.MAX_VALUE; + for( int i = ai; i < ai+len; i++ ) + val = Math.max(avals[aix[i]], val); + return val; + } + //custom vector div public static void vectDivAdd(double[] a, double bval, double[] c, int ai, int ci, int len) { @@ -202,7 +230,7 @@ public class LibSpoofPrimitives public static double[] vectNotequalWrite(double[] a, double bval, int ai, int len) { double[] c = allocVector(len, false); for( int j = 0; j < len; j++, ai++) - c[j] = (a[j] != bval) ? 1 : 0; + c[j] = (a[ai] != bval) ? 1 : 0; return c; } @@ -228,7 +256,7 @@ public class LibSpoofPrimitives public static double[] vectLessWrite(double[] a, double bval, int ai, int len) { double[] c = allocVector(len, false); for( int j = 0; j < len; j++, ai++) - c[j] = (a[j] < bval) ? 1 : 0; + c[j] = (a[ai] < bval) ? 1 : 0; return c; } @@ -254,7 +282,7 @@ public class LibSpoofPrimitives public static double[] vectLessequalWrite(double[] a, double bval, int ai, int len) { double[] c = allocVector(len, false); for( int j = 0; j < len; j++, ai++) - c[j] = (a[j] <= bval) ? 1 : 0; + c[j] = (a[ai] <= bval) ? 1 : 0; return c; } @@ -280,7 +308,7 @@ public class LibSpoofPrimitives public static double[] vectGreaterWrite(double[] a, double bval, int ai, int len) { double[] c = allocVector(len, false); for( int j = 0; j < len; j++, ai++) - c[j] = (a[j] > bval) ? 1 : 0; + c[j] = (a[ai] > bval) ? 1 : 0; return c; } @@ -306,7 +334,7 @@ public class LibSpoofPrimitives public static double[] vectGreaterequalWrite(double[] a, double bval, int ai, int len) { double[] c = allocVector(len, false); for( int j = 0; j < len; j++, ai++) - c[j] = (a[j] >= bval) ? 1 : 0; + c[j] = (a[ai] >= bval) ? 1 : 0; return c; } http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/18ab98a6/src/test/java/org/apache/sysml/test/integration/functions/codegen/AlgorithmLinregCG.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/sysml/test/integration/functions/codegen/AlgorithmLinregCG.java b/src/test/java/org/apache/sysml/test/integration/functions/codegen/AlgorithmLinregCG.java index 1a2ecfe..6e3549e 100644 --- a/src/test/java/org/apache/sysml/test/integration/functions/codegen/AlgorithmLinregCG.java +++ b/src/test/java/org/apache/sysml/test/integration/functions/codegen/AlgorithmLinregCG.java @@ -41,9 +41,7 @@ public class AlgorithmLinregCG extends AutomatedTestBase private final static String TEST_CONF = "SystemML-config-codegen.xml"; private final static File TEST_CONF_FILE = new File(SCRIPT_DIR + TEST_DIR, TEST_CONF); - //TODO Investigate numerical stability issues: on certain platforms this test, occasionally fails, - //for 1e-5 (specifically testLinregCGSparseRewritesCP); apparently due to the -(-(X)) -> X rewrite. - private final static double eps = 1e-1; + private final static double eps = 1e-5; private final static int rows = 2468; private final static int cols = 507; http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/18ab98a6/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 b783104..c83bff3 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 @@ -45,6 +45,7 @@ public class RowAggTmplTest extends AutomatedTestBase private static final String TEST_NAME7 = TEST_NAME+"7"; //t(X)%*%(X%*%v-y); sum((X%*%v-y)^2); private static final String TEST_NAME8 = TEST_NAME+"8"; //colSums((X/rowSums(X))>0.7) private static final String TEST_NAME9 = TEST_NAME+"9"; //t(X) %*% (v - abs(y)) + private static final String TEST_NAME10 = TEST_NAME+"10"; //Y=(X<=rowMins(X)); R=colSums((Y/rowSums(Y))); private static final String TEST_DIR = "functions/codegen/"; private static final String TEST_CLASS_DIR = TEST_DIR + RowAggTmplTest.class.getSimpleName() + "/"; @@ -56,7 +57,7 @@ public class RowAggTmplTest extends AutomatedTestBase @Override public void setUp() { TestUtils.clearAssertionInformation(); - for(int i=1; i<=9; i++) + for(int i=1; i<=10; i++) addTestConfiguration( TEST_NAME+i, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME+i, new String[] { String.valueOf(i) }) ); } @@ -105,6 +106,11 @@ public class RowAggTmplTest extends AutomatedTestBase testCodegenIntegration( TEST_NAME9, true, ExecType.CP ); } + @Test + public void testCodegenRowAggRewrite10() { + testCodegenIntegration( TEST_NAME10, true, ExecType.CP ); + } + @Test public void testCodegenRowAgg1() { testCodegenIntegration( TEST_NAME1, false, ExecType.CP ); @@ -150,6 +156,11 @@ public class RowAggTmplTest extends AutomatedTestBase testCodegenIntegration( TEST_NAME9, false, ExecType.CP ); } + @Test + public void testCodegenRowAgg10() { + testCodegenIntegration( TEST_NAME10, false, ExecType.CP ); + } + private void testCodegenIntegration( String testname, boolean rewrites, ExecType instType ) { boolean oldFlag = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION; http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/18ab98a6/src/test/scripts/functions/codegen/rowAggPattern10.R ---------------------------------------------------------------------- diff --git a/src/test/scripts/functions/codegen/rowAggPattern10.R b/src/test/scripts/functions/codegen/rowAggPattern10.R new file mode 100644 index 0000000..44e91ac --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern10.R @@ -0,0 +1,34 @@ +#------------------------------------------------------------- +# +# 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") +library("matrixStats") + + +X = matrix(seq(1,1500), 150, 10, byrow=TRUE); + +Y = (X <= rowMins(X)); +Z = (Y / rowSums(Y)); +R = t(colSums(Z)); + +writeMM(as(R, "CsparseMatrix"), paste(args[2], "S", sep="")); http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/18ab98a6/src/test/scripts/functions/codegen/rowAggPattern10.dml ---------------------------------------------------------------------- diff --git a/src/test/scripts/functions/codegen/rowAggPattern10.dml b/src/test/scripts/functions/codegen/rowAggPattern10.dml new file mode 100644 index 0000000..4572e68 --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern10.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(seq(1,1500), rows=150, cols=10); + +Y = (X <= rowMins(X)); +Z = (Y / rowSums(Y)); +R = colSums(Z); + +write(R, $1)
