Repository: systemml Updated Branches: refs/heads/master 1e851ef62 -> db0207900
[SYSTEMML-2488] Fix function inlining of multi-return builtin functions The inlining during parser validate of functions that call multi-return builtin functions is invalid in special cases as the append of output mapping statements can violate internal assumptions. This patch introduces new mechanics for doing in-place function output mapping. Since the compiler still struggles to handle these multi-return builtin operations, this also includes a correctness fix for deciding on function inlining. Project: http://git-wip-us.apache.org/repos/asf/systemml/repo Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/db020790 Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/db020790 Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/db020790 Branch: refs/heads/master Commit: db02079000e1cba56c938374b1fa1641d40b551d Parents: 1e851ef Author: Matthias Boehm <mboe...@gmail.com> Authored: Tue Aug 14 01:10:09 2018 -0700 Committer: Matthias Boehm <mboe...@gmail.com> Committed: Tue Aug 14 01:14:01 2018 -0700 ---------------------------------------------------------------------- .../sysml/parser/AssignmentStatement.java | 4 + .../sysml/parser/MultiAssignmentStatement.java | 6 + .../org/apache/sysml/parser/StatementBlock.java | 295 +++++++++++-------- .../functions/misc/FunctionPotpourriTest.java | 21 +- .../misc/FunPotpourriMultiReturnBuiltin1.dml | 28 ++ .../misc/FunPotpourriMultiReturnBuiltin2.dml | 34 +++ 6 files changed, 260 insertions(+), 128 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/main/java/org/apache/sysml/parser/AssignmentStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/AssignmentStatement.java b/src/main/java/org/apache/sysml/parser/AssignmentStatement.java index 72b2ce8..1a4963c 100644 --- a/src/main/java/org/apache/sysml/parser/AssignmentStatement.java +++ b/src/main/java/org/apache/sysml/parser/AssignmentStatement.java @@ -73,6 +73,10 @@ public class AssignmentStatement extends Statement return _targetList; } + public void setTarget(DataIdentifier di) { + _targetList.set(0, di); + } + public Expression getSource(){ return _source; } http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java b/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java index b01dd2e..7909f71 100644 --- a/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java +++ b/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java @@ -20,6 +20,7 @@ package org.apache.sysml.parser; import java.util.ArrayList; +import java.util.List; import org.apache.sysml.api.DMLScript; import org.apache.sysml.debug.DMLBreakpointManager; @@ -61,6 +62,11 @@ public class MultiAssignmentStatement extends Statement return _targetList; } + public void setTargetList(List<DataIdentifier> diList) { + _targetList.clear(); + _targetList.addAll(diList); + } + public Expression getSource(){ return _source; } http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/main/java/org/apache/sysml/parser/StatementBlock.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/StatementBlock.java b/src/main/java/org/apache/sysml/parser/StatementBlock.java index 4498eaa..3988a7f 100644 --- a/src/main/java/org/apache/sysml/parser/StatementBlock.java +++ b/src/main/java/org/apache/sysml/parser/StatementBlock.java @@ -288,12 +288,18 @@ public class StatementBlock extends LiveVariableAnalysis implements ParseInfo if( !ret ) return false; } - if( s instanceof MultiAssignmentStatement && ((MultiAssignmentStatement)s).getSource() instanceof FunctionCallIdentifier ) - { - FunctionCallIdentifier fcall = (FunctionCallIdentifier) ((MultiAssignmentStatement)s).getSource(); - FunctionStatementBlock fblock2 = prog.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName()); - ret &= rIsInlineableFunction(fblock2, prog); - if( !ret ) return false; + else if( s instanceof MultiAssignmentStatement ) { + MultiAssignmentStatement mas = (MultiAssignmentStatement)s; + if( mas.getSource() instanceof FunctionCallIdentifier ) { + FunctionCallIdentifier fcall = (FunctionCallIdentifier) ((MultiAssignmentStatement)s).getSource(); + FunctionStatementBlock fblock2 = prog.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName()); + ret &= rIsInlineableFunction(fblock2, prog); + if( !ret ) return false; + } + else if( mas.getSource() instanceof BuiltinFunctionExpression + && ((BuiltinFunctionExpression)mas.getSource()).multipleReturns() ) { + return false; + } } } } @@ -574,143 +580,180 @@ public class StatementBlock extends LiveVariableAnalysis implements ParseInfo public ArrayList<Statement> rewriteFunctionCallStatements (DMLProgram dmlProg, ArrayList<Statement> statements) { ArrayList<Statement> newStatements = new ArrayList<>(); - for (Statement current : statements){ - if (isRewritableFunctionCall(current, dmlProg)){ - - Expression sourceExpr = null; - if (current instanceof AssignmentStatement) - sourceExpr = ((AssignmentStatement)current).getSource(); - else - sourceExpr = ((MultiAssignmentStatement)current).getSource(); + for (Statement current : statements) { + if( !isRewritableFunctionCall(current, dmlProg) ) { + newStatements.add(current); + continue; + } - FunctionCallIdentifier fcall = (FunctionCallIdentifier) sourceExpr; - FunctionStatementBlock fblock = dmlProg.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName()); - if (fblock == null){ - fcall.raiseValidateError("function " + fcall.getName() + " is undefined in namespace " + fcall.getNamespace(), false); - } - FunctionStatement fstmt = (FunctionStatement)fblock.getStatement(0); + Expression sourceExpr = (current instanceof AssignmentStatement) ? + ((AssignmentStatement)current).getSource() : + ((MultiAssignmentStatement)current).getSource(); + FunctionCallIdentifier fcall = (FunctionCallIdentifier) sourceExpr; + FunctionStatementBlock fblock = dmlProg.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName()); + if( fblock == null ) + fcall.raiseValidateError("function " + fcall.getName() + " is undefined in namespace " + fcall.getNamespace(), false); + FunctionStatement fstmt = (FunctionStatement)fblock.getStatement(0); + + // recursive inlining (no memo required because update-inplace of function statement blocks, so no redundant inlining) + if( rIsInlineableFunction(fblock, dmlProg) ){ + fstmt.getBody().get(0).setStatements( + rewriteFunctionCallStatements(dmlProg, fstmt.getBody().get(0).getStatements())); + } - // recursive inlining (no memo required because update-inplace of function statement blocks, so no redundant inlining) - if( rIsInlineableFunction(fblock, dmlProg) ){ - fstmt.getBody().get(0).setStatements(rewriteFunctionCallStatements(dmlProg, fstmt.getBody().get(0).getStatements())); - } + //MB: we cannot use the hash since multiple interleaved inlined functions should be independent. + String prefix = _seq.getNextID() + "_"; - //MB: we cannot use the hash since multiple interleaved inlined functions should be independent. - String prefix = _seq.getNextID() + "_"; + if (fstmt.getBody().size() > 1){ + sourceExpr.raiseValidateError("rewritable function can only have 1 statement block", false); + } + StatementBlock sblock = fstmt.getBody().get(0); - if (fstmt.getBody().size() > 1){ - sourceExpr.raiseValidateError("rewritable function can only have 1 statement block", false); - } - StatementBlock sblock = fstmt.getBody().get(0); + if( fcall.getParamExprs().size() != fstmt.getInputParams().size() ) { + sourceExpr.raiseValidateError("Wrong number of function input arguments: "+ + fcall.getParamExprs().size() + " found, but " + fstmt.getInputParams().size()+" expected."); + } - if( fcall.getParamExprs().size() != fstmt.getInputParams().size() ) { - sourceExpr.raiseValidateError("Wrong number of function input arguments: "+ - fcall.getParamExprs().size() + " found, but " + fstmt.getInputParams().size()+" expected."); + for (int i =0; i < fcall.getParamExprs().size(); i++) { + ParameterExpression inputArg = fcall.getParamExprs().get(i); + DataIdentifier currFormalParam = (inputArg.getName()==null) ? + fstmt.getInputParams().get(i) : fstmt.getInputParam(inputArg.getName()); + if( currFormalParam == null ) + throw new LanguageException("Non-existing named function argument '" + + inputArg.getName()+"' in call to "+fcall.getName()+"."); + + // create new assignment statement + String newFormalParameterName = prefix + currFormalParam.getName(); + DataIdentifier newTarget = new DataIdentifier(currFormalParam); + newTarget.setName(newFormalParameterName); + + Expression currCallParam = inputArg.getExpr(); + + //auto casting of inputs on inlining (if required) + ValueType targetVT = newTarget.getValueType(); + if (newTarget.getDataType() == DataType.SCALAR && currCallParam.getOutput() != null + && targetVT != currCallParam.getOutput().getValueType() && targetVT != ValueType.STRING) { + currCallParam = new BuiltinFunctionExpression( + BuiltinFunctionExpression.getValueTypeCastOperator(targetVT), + new Expression[] { currCallParam }, newTarget); } - for (int i =0; i < fcall.getParamExprs().size(); i++) { - ParameterExpression inputArg = fcall.getParamExprs().get(i); - DataIdentifier currFormalParam = (inputArg.getName()==null) ? - fstmt.getInputParams().get(i) : fstmt.getInputParam(inputArg.getName()); - if( currFormalParam == null ) - throw new LanguageException("Non-existing named function argument '" - + inputArg.getName()+"' in call to "+fcall.getName()+"."); - - // create new assignment statement - String newFormalParameterName = prefix + currFormalParam.getName(); - DataIdentifier newTarget = new DataIdentifier(currFormalParam); - newTarget.setName(newFormalParameterName); - - Expression currCallParam = inputArg.getExpr(); - - //auto casting of inputs on inlining (if required) - ValueType targetVT = newTarget.getValueType(); - if (newTarget.getDataType() == DataType.SCALAR && currCallParam.getOutput() != null - && targetVT != currCallParam.getOutput().getValueType() && targetVT != ValueType.STRING) { - currCallParam = new BuiltinFunctionExpression( - BuiltinFunctionExpression.getValueTypeCastOperator(targetVT), - new Expression[] { currCallParam }, newTarget); - } - - // create the assignment statement to bind the call parameter to formal parameter - newStatements.add(new AssignmentStatement(newTarget, currCallParam, newTarget)); - } + // create the assignment statement to bind the call parameter to formal parameter + newStatements.add(new AssignmentStatement(newTarget, currCallParam, newTarget)); + } - for (Statement stmt : sblock._statements){ - // rewrite the statement to use the "rewritten" name - Statement rewrittenStmt = stmt.rewriteStatement(prefix); - newStatements.add(rewrittenStmt); - } + for (Statement stmt : sblock._statements){ + // rewrite the statement to use the "rewritten" name + Statement rewrittenStmt = stmt.rewriteStatement(prefix); + newStatements.add(rewrittenStmt); + } - if (current instanceof AssignmentStatement) { - if (fstmt.getOutputParams().size() == 0) { - AssignmentStatement as = (AssignmentStatement) current; - if ((as.getTargetList().size() == 1) && (as.getTargetList().get(0) != null)) { - raiseValidateError("Function '" + fcall.getName() - + "' does not return a value but is assigned to " + as.getTargetList().get(0), - true); - } - } - } else if (current instanceof MultiAssignmentStatement) { - if (fstmt.getOutputParams().size() == 0) { - MultiAssignmentStatement mas = (MultiAssignmentStatement) current; + if (current instanceof AssignmentStatement) { + if (fstmt.getOutputParams().size() == 0) { + AssignmentStatement as = (AssignmentStatement) current; + if ((as.getTargetList().size() == 1) && (as.getTargetList().get(0) != null)) { raiseValidateError("Function '" + fcall.getName() - + "' does not return a value but is assigned to " + mas.getTargetList(), true); + + "' does not return a value but is assigned to " + as.getTargetList().get(0), + true); } } - // handle the return values - for (int i = 0; i < fstmt.getOutputParams().size(); i++){ - - // get the target (return parameter from function) - DataIdentifier currReturnParam = fstmt.getOutputParams().get(i); - String newSourceName = prefix + currReturnParam.getName(); - DataIdentifier newSource = new DataIdentifier(currReturnParam); - newSource.setName(newSourceName); - - // get binding - DataIdentifier newTarget = null; - if (current instanceof AssignmentStatement){ - if (i > 0) { - fstmt.raiseValidateError("Assignment statement cannot return multiple values", false); - } - AssignmentStatement as = (AssignmentStatement) current; - DataIdentifier targ = as.getTarget(); - if (targ == null) { - Expression exp = as.getSource(); - FunctionCallIdentifier fci = (FunctionCallIdentifier) exp; - String functionName = fci.getName(); - fstmt.raiseValidateError(functionName + " requires LHS value", false); - } else { - newTarget = new DataIdentifier(((AssignmentStatement)current).getTarget()); - } - } - else{ - newTarget = new DataIdentifier(((MultiAssignmentStatement)current).getTargetList().get(i)); - } - - //auto casting of inputs on inlining (always, redundant cast removed during Hop Rewrites) - ValueType sourceVT = newSource.getValueType(); - if (newSource.getDataType() == DataType.SCALAR && sourceVT != ValueType.STRING) { - newSource = new BuiltinFunctionExpression( - BuiltinFunctionExpression.getValueTypeCastOperator(sourceVT), - new Expression[] { newSource }, newTarget); - } - - // create the assignment statement to bind the call parameter to formal parameter - AssignmentStatement binding = new AssignmentStatement(newTarget, newSource, newTarget); - - newStatements.add(binding); + } else if (current instanceof MultiAssignmentStatement) { + if (fstmt.getOutputParams().size() == 0) { + MultiAssignmentStatement mas = (MultiAssignmentStatement) current; + raiseValidateError("Function '" + fcall.getName() + + "' does not return a value but is assigned to " + mas.getTargetList(), true); } - - } // end if (isRewritableFunctionCall(current, dmlProg) - - else { - newStatements.add(current); } + + // handle returns by appending name mappings, but with special handling of + // statements that contain function calls or multi-return builtin expressions (but disabled) +// Statement lastAdd = newStatements.get(newStatements.size()-1); +// if( isOutputBindingViaFunctionCall(lastAdd, prefix, fstmt) && lastAdd instanceof AssignmentStatement ) +// ((AssignmentStatement)lastAdd).setTarget(((AssignmentStatement)current).getTarget()); +// else if ( isOutputBindingViaFunctionCall(lastAdd, prefix, fstmt) && lastAdd instanceof MultiAssignmentStatement ) +// if( current instanceof MultiAssignmentStatement ) +// ((MultiAssignmentStatement)lastAdd).setTargetList(((MultiAssignmentStatement)current).getTargetList()); +// else //correct for multi-assignment to assignment transform +// newStatements.set(newStatements.size()-1, createNewPartialMultiAssignment(lastAdd, current, prefix, fstmt)); +// else + appendOutputAssignments(current, prefix, fstmt, newStatements); } - return newStatements; } + + @SuppressWarnings("unused") + private static boolean isOutputBindingViaFunctionCall(Statement last, String prefix, FunctionStatement fstmt) { + if( last instanceof AssignmentStatement ) { + AssignmentStatement as = (AssignmentStatement) last; + String newName = prefix + fstmt.getOutputParams().get(0).getName(); + return as.getSource() instanceof FunctionCallIdentifier + && as.getTarget().getName().equals(newName); + } + else if( last instanceof MultiAssignmentStatement ) { + MultiAssignmentStatement mas = (MultiAssignmentStatement) last; + List<DataIdentifier> tlist1 = mas.getTargetList(); + boolean ret = mas.getSource() instanceof FunctionCallIdentifier + || (mas.getSource() instanceof BuiltinFunctionExpression + && ((BuiltinFunctionExpression)mas.getSource()).multipleReturns()); + for( DataIdentifier di : fstmt.getOutputParams() ) + ret &= tlist1.stream().anyMatch(d -> d.getName().equals(prefix+di.getName())); + return ret; + } + return false; //default + } + + @SuppressWarnings("unused") + private static MultiAssignmentStatement createNewPartialMultiAssignment(Statement last, Statement current, String prefix, FunctionStatement fstmt) { + MultiAssignmentStatement mas = (MultiAssignmentStatement) last; + AssignmentStatement as = (AssignmentStatement) current; + ArrayList<DataIdentifier> tlist = new ArrayList<>(); + String tmpStr = prefix+fstmt.getOutputParams().get(0).getName(); + for( DataIdentifier di : mas.getTargetList() ) + tlist.add( di.getName().equals(tmpStr) ? as.getTarget() : di ); + return new MultiAssignmentStatement(tlist, mas.getSource()); + } + + private static void appendOutputAssignments(Statement current, String prefix, FunctionStatement fstmt, List<Statement> newStatements) { + for (int i = 0; i < fstmt.getOutputParams().size(); i++){ + // get the target (return parameter from function) + DataIdentifier currReturnParam = fstmt.getOutputParams().get(i); + String newSourceName = prefix + currReturnParam.getName(); + DataIdentifier newSource = new DataIdentifier(currReturnParam); + newSource.setName(newSourceName); + + // get binding + DataIdentifier newTarget = null; + if (current instanceof AssignmentStatement){ + if (i > 0) { + fstmt.raiseValidateError("Assignment statement cannot return multiple values", false); + } + AssignmentStatement as = (AssignmentStatement) current; + DataIdentifier targ = as.getTarget(); + if (targ == null) { + Expression exp = as.getSource(); + FunctionCallIdentifier fci = (FunctionCallIdentifier) exp; + String functionName = fci.getName(); + fstmt.raiseValidateError(functionName + " requires LHS value", false); + } else { + newTarget = new DataIdentifier(((AssignmentStatement)current).getTarget()); + } + } + else{ + newTarget = new DataIdentifier(((MultiAssignmentStatement)current).getTargetList().get(i)); + } + + //auto casting of inputs on inlining (always, redundant cast removed during Hop Rewrites) + ValueType sourceVT = newSource.getValueType(); + if (newSource.getDataType() == DataType.SCALAR && sourceVT != ValueType.STRING) { + newSource = new BuiltinFunctionExpression( + BuiltinFunctionExpression.getValueTypeCastOperator(sourceVT), + new Expression[] { newSource }, newTarget); + } + + // create the assignment statement to bind the call parameter to formal parameter + newStatements.add(new AssignmentStatement(newTarget, newSource, newTarget)); + } + } public VariableSet validate(DMLProgram dmlProg, VariableSet ids, HashMap<String, ConstIdentifier> constVars, boolean conditional) { http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java b/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java index 68e8f00..f1ce7b0 100644 --- a/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java +++ b/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java @@ -20,6 +20,7 @@ package org.apache.sysml.test.integration.functions.misc; +import org.junit.Assert; import org.junit.Test; import org.apache.sysml.api.DMLException; import org.apache.sysml.test.integration.AutomatedTestBase; @@ -45,6 +46,8 @@ public class FunctionPotpourriTest extends AutomatedTestBase private final static String TEST_NAME15 = "FunPotpourriDefaultArgScalarMatrix1"; private final static String TEST_NAME16 = "FunPotpourriDefaultArgScalarMatrix2"; private final static String TEST_NAME17 = "FunPotpourriNamedArgsQuotedAssign"; + private final static String TEST_NAME18 = "FunPotpourriMultiReturnBuiltin1"; + private final static String TEST_NAME19 = "FunPotpourriMultiReturnBuiltin2"; private final static String TEST_DIR = "functions/misc/"; private final static String TEST_CLASS_DIR = TEST_DIR + FunctionPotpourriTest.class.getSimpleName() + "/"; @@ -69,6 +72,8 @@ public class FunctionPotpourriTest extends AutomatedTestBase addTestConfiguration( TEST_NAME15, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME15, new String[] { "R" }) ); addTestConfiguration( TEST_NAME16, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME16, new String[] { "R" }) ); addTestConfiguration( TEST_NAME17, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME17, new String[] { "R" }) ); + addTestConfiguration( TEST_NAME18, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME18, new String[] { "R" }) ); + addTestConfiguration( TEST_NAME19, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME19, new String[] { "R" }) ); } @Test @@ -166,16 +171,28 @@ public class FunctionPotpourriTest extends AutomatedTestBase runFunctionTest( TEST_NAME17, false ); } + @Test + public void testFunctionMultiReturnBuiltin1() { + runFunctionTest( TEST_NAME18, false ); + } + + @Test + public void testFunctionMultiReturnBuiltin2() { + runFunctionTest( TEST_NAME19, false ); + } + private void runFunctionTest(String testName, boolean error) { TestConfiguration config = getTestConfiguration(testName); loadTestConfiguration(config); String HOME = SCRIPT_DIR + TEST_DIR; fullDMLScriptName = HOME + testName + ".dml"; - programArgs = new String[]{"-explain", "-stats", + programArgs = new String[]{"-explain","hops", "-stats", "-args", String.valueOf(error).toUpperCase()}; - + //run script and compare output runTest(true, error, DMLException.class, -1); + if( testName.equals(TEST_NAME18) ) + Assert.assertTrue(heavyHittersContainsString("print")); } } http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.dml ---------------------------------------------------------------------- diff --git a/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.dml b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.dml new file mode 100644 index 0000000..cac2ac4 --- /dev/null +++ b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.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. +# +#------------------------------------------------------------- + +foo = function(Matrix[Double] A) return (Matrix[Double] B) { + [w, B] = eigen(A) +} + +X = matrix(0.1, rows=100, cols=100); +Y = foo(X); +print(toString(Y)) http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml ---------------------------------------------------------------------- diff --git a/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml new file mode 100644 index 0000000..1efcab4 --- /dev/null +++ b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml @@ -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. +# +#------------------------------------------------------------- + +foo2 = function(Matrix[Double] A) return (Matrix[Double] w, Matrix[Double] B) { + while(FALSE){} + w = A - 1; + B = A + 1; +} + +foo = function(Matrix[Double] A) return (Matrix[Double] B) { + [w, B] = foo2(A) +} + +X = matrix(0.1, rows=100, cols=100); +Y = foo(X); +print(toString(Y))