diff --git a/src/main/java/org/apache/sysds/parser/BuiltinFunctionExpression.java b/src/main/java/org/apache/sysds/parser/BuiltinFunctionExpression.java index ab0c7993b4e..98362dc46ba 100644 --- a/src/main/java/org/apache/sysds/parser/BuiltinFunctionExpression.java +++ b/src/main/java/org/apache/sysds/parser/BuiltinFunctionExpression.java @@ -2170,19 +2170,36 @@ private void setBinaryOutputProperties(DataIdentifier output) { } private void setTernaryOutputProperties(DataIdentifier output, boolean conditional) { - DataType dt1 = getFirstExpr().getOutput().getDataType(); - DataType dt2 = getSecondExpr().getOutput().getDataType(); - DataType dt3 = getThirdExpr().getOutput().getDataType(); - DataType dtOut = (dt1.isMatrix() || dt2.isMatrix() || dt3.isMatrix()) ? - DataType.MATRIX : DataType.SCALAR; - if( dt1==DataType.MATRIX && dt2==DataType.MATRIX ) - checkMatchingDimensions(getFirstExpr(), getSecondExpr(), false, conditional); - if( dt1==DataType.MATRIX && dt3==DataType.MATRIX ) - checkMatchingDimensions(getFirstExpr(), getThirdExpr(), false, conditional); - if( dt2==DataType.MATRIX && dt3==DataType.MATRIX ) - checkMatchingDimensions(getSecondExpr(), getThirdExpr(), false, conditional); + Expression expr1 = getFirstExpr(); + Expression expr2 = getSecondExpr(); + Expression expr3 = getThirdExpr(); + DataType dt1 = expr1.getOutput().getDataType(); + DataType dt2 = expr2.getOutput().getDataType(); + DataType dt3 = expr3.getOutput().getDataType(); + final long r1 = expr1.getOutput().getDim1(); + final long r2 = expr2.getOutput().getDim1(); + final long r3 = expr3.getOutput().getDim1(); + final long c1 = expr1.getOutput().getDim2(); + final long c2 = expr2.getOutput().getDim2(); + final long c3 = expr3.getOutput().getDim2(); + final long m = Math.max(Math.max(r1, r2), r3); + final long n = Math.max(Math.max(c1, c2), c3); + + boolean unknownDim = (r1 == -1 || r2 == -1 || r3 == -1 || c1 == -1 || c2 == -1 || c3 == -1); + if (!unknownDim && ((dt1 == DataType.MATRIX && r1 != 1 && r1 != m) + || (dt2 == DataType.MATRIX && r2 != 1 && r2 != m) + || (dt3 == DataType.MATRIX && r3 != 1 && r3 != m) + || (dt1 == DataType.MATRIX && c1 != 1 && c1 != n) + || (dt2 == DataType.MATRIX && c2 != 1 && c2 != n) + || (dt3 == DataType.MATRIX && c3 != 1 && c3 != n))) { + raiseValidateError("Mismatch in matrix dimensions of parameters for function " + + this.getOpCode(), conditional, LanguageErrorCodes.INVALID_PARAMETERS); + } + MatrixCharacteristics dims1 = getBinaryMatrixCharacteristics(getFirstExpr(), getSecondExpr()); MatrixCharacteristics dims2 = getBinaryMatrixCharacteristics(getSecondExpr(), getThirdExpr()); + DataType dtOut = (dt1.isMatrix() || dt2.isMatrix() || dt3.isMatrix()) ? + DataType.MATRIX : DataType.SCALAR; output.setDataType(dtOut); output.setValueType(dtOut==DataType.MATRIX ? ValueType.FP64 : computeValueType(getSecondExpr(), getThirdExpr(), true)); diff --git a/src/main/java/org/apache/sysds/runtime/compress/lib/CLALibTernaryOp.java b/src/main/java/org/apache/sysds/runtime/compress/lib/CLALibTernaryOp.java index 8dae24df79c..3576484406e 100644 --- a/src/main/java/org/apache/sysds/runtime/compress/lib/CLALibTernaryOp.java +++ b/src/main/java/org/apache/sysds/runtime/compress/lib/CLALibTernaryOp.java @@ -59,7 +59,7 @@ public static MatrixBlock ternaryOperations(TernaryOperator op, MatrixBlock m1, final int n = Math.max(Math.max(c1, c2), c3); // double check that the dimensions are valid. - MatrixBlock.ternaryOperationCheck(s1, s2, s3, m, r1, r2, r3, n, c1, c2, c3); + MatrixBlock.ternaryOperationCheck(op, s1, s2, s3, m, r1, r2, r3, n, c1, c2, c3); MatrixBlock ret; diff --git a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixTercell.java b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixTercell.java index 72aa51ed5c6..89da76aa880 100644 --- a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixTercell.java +++ b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixTercell.java @@ -27,6 +27,7 @@ import java.util.concurrent.Future; import org.apache.sysds.runtime.DMLRuntimeException; +import org.apache.sysds.runtime.functionobjects.IfElse; import org.apache.sysds.runtime.matrix.operators.TernaryOperator; import org.apache.sysds.runtime.util.CommonThreadPool; import org.apache.sysds.runtime.util.UtilFunctions; @@ -88,19 +89,87 @@ public static void tercellOp(MatrixBlock m1, MatrixBlock m2, MatrixBlock m3, Mat private static long unsafeTernary(MatrixBlock m1, MatrixBlock m2, MatrixBlock m3, MatrixBlock ret, TernaryOperator op, boolean s1, boolean s2, boolean s3, double d1, double d2, double d3, int rl, int ru) + { + if(op.fn instanceof IfElse) { + return unsafeTernaryIfElse(m1, m2, m3, ret, op, s1, s2, + s3, d1, d2, d3, rl, ru); + } + else { + return unsafeTernaryDefault(m1, m2, m3, ret, op, s1, s2, + s3, d1, d2, d3, rl, ru); + } + } + + private static long unsafeTernaryIfElse(MatrixBlock m1, MatrixBlock m2, MatrixBlock m3, MatrixBlock ret, + TernaryOperator op, boolean s1, boolean s2, boolean s3, double d1, double d2, double d3, int rl, int ru) + { + // IfElse specific optimizations are applied here + int n = ret.clen; + long lnnz = 0; + final int r1 = m1.getNumRows(); + final int c1 = m1.getNumColumns(); + if (c1 == 1) { + for( int i=rl; i dmlfile = readDMLMatrixFromOutputDir("R"); HashMap rfile = readRMatrixFromExpectedDir("R"); - TestUtils.compareMatrices(dmlfile, rfile, 0, "Stat-DML", "Stat-R"); + TestUtils.compareMatrices(dmlfile, rfile, eps, "Stat-DML", "Stat-R"); } finally { rtplatform = platformOld; @@ -263,7 +828,24 @@ private void runIfElseTest(boolean matrix1, boolean matrix2, boolean matrix3, bo } } - private static double[][] getScalar(int input) { - return new double[][]{{7d*input}}; + private double[][] getMatrixOfType(MatType mtype, boolean sparse, long seed) { + double[][] ret = null; + double sparsity = sparse ? sparsity2 : sparsity1; + switch(mtype) { + case SCALAR: + ret = getRandomMatrix(1, 1, 0, 1, sparsity, seed); + break; + case MATRIX: + ret = getRandomMatrix(rows, cols, 0, 1, sparsity, seed); + break; + case COL: + ret = getRandomMatrix(rows, 1, 0, 1, sparsity, seed); + break; + case ROW: + ret = getRandomMatrix(1, cols, 0, 1, sparsity, seed); + break; + default: + } + return ret; } } diff --git a/src/test/scripts/functions/ternary/TernaryIfElse.R b/src/test/scripts/functions/ternary/TernaryIfElse.R index a1e8a030021..d0e2f49c634 100644 --- a/src/test/scripts/functions/ternary/TernaryIfElse.R +++ b/src/test/scripts/functions/ternary/TernaryIfElse.R @@ -31,14 +31,20 @@ m = max(max(nrow(A), nrow(B)), nrow(C)) n = max(max(ncol(A), ncol(B)), ncol(C)) if( nrow(A)==1 ) { + A = matrix(A, m, n, byrow=TRUE); +} else if ( ncol(A) == 1 ) { A = matrix(A, m, n); } if( nrow(B)==1 ) { + B = matrix(B, m, n, byrow=TRUE); +} else if ( ncol(B)==1 ) { B = matrix(B, m, n); } if( nrow(C)==1 ) { + C = matrix(C, m, n, byrow=TRUE); +} else if( ncol(C)==1 ) { C = matrix(C, m, n); -} +} R = matrix(ifelse(as.vector(A), as.vector(B), as.vector(C)), m, n); diff --git a/src/test/scripts/functions/ternary/TernaryIfElse.dml b/src/test/scripts/functions/ternary/TernaryIfElse.dml index 12a11cc1253..9dca7c3d7f5 100644 --- a/src/test/scripts/functions/ternary/TernaryIfElse.dml +++ b/src/test/scripts/functions/ternary/TernaryIfElse.dml @@ -23,21 +23,25 @@ A = read($1); B = read($2); C = read($3); -if( nrow(A)==1 & nrow(B)==1 & nrow(C)==1 ) +isscalar = function(matrix[double] A) return (boolean C) { + C = nrow(A)==1 & ncol(A)==1 +} + +if( isscalar(A) & isscalar(B) & isscalar(C) ) R = as.matrix(ifelse(as.scalar(A), as.scalar(B), as.scalar(C))); -else if( nrow(A)>1 & nrow(B)==1 & nrow(C)==1 ) +else if( !isscalar(A) & isscalar(B) & isscalar(C)) R = ifelse(A, as.scalar(B), as.scalar(C)); -else if( nrow(A)==1 & nrow(B)>1 & nrow(C)==1 ) +else if( isscalar(A) & !isscalar(B) & isscalar(C) ) R = ifelse(as.scalar(A), B, as.scalar(C)); -else if( nrow(A)>1 & nrow(B)>1 & nrow(C)==1 ) +else if( !isscalar(A) & !isscalar(B) & isscalar(C) ) R = ifelse(A, B, as.scalar(C)); -else if( nrow(A)==1 & nrow(B)==1 & nrow(C)>1 ) +else if( isscalar(A)==1 & isscalar(B) & !isscalar(C) ) R = ifelse(as.scalar(A), as.scalar(B), C); -else if( nrow(A)>1 & nrow(B)==1 & nrow(C)>1 ) +else if( !isscalar(A) & isscalar(B) & !isscalar(C) ) R = ifelse(A, as.scalar(B), C); -else if( nrow(A)==1 & nrow(B)>1 & nrow(C)>1 ) +else if( isscalar(A)==1 & !isscalar(B) & !isscalar(C) ) R = ifelse(as.scalar(A), B, C); -else if( nrow(A)>1 & nrow(B)>1 & nrow(C)>1 ) +else if( !isscalar(A) & !isscalar(B) & !isscalar(C) ) R = ifelse(A, B, C); write(R, $4);