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))

Reply via email to