[SYSTEMML-1983] New codegen cplan rewrite framework (micro optims) This patch refactors the code generator by moving smaller micro optimizations from the templates into a new cplan rewrite framework to avoid redundancy and inconsistency across templates and to improve debuggability. The goal is NOT to provide a fusion-aware rewrite framework, but simply to apply smaller rewrites for better code quality. An example rewrite is rowSums(X!=0) -> rowNnzs(X), which avoids an unnecessary row intermediate and is realized as a meta data operation for sparse input rows.
Project: http://git-wip-us.apache.org/repos/asf/systemml/repo Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/e1f5866a Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/e1f5866a Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/e1f5866a Branch: refs/heads/master Commit: e1f5866a5c2e2100d68124b74a33a9022e89dd09 Parents: ee6060b Author: Matthias Boehm <[email protected]> Authored: Thu Nov 2 00:15:11 2017 -0700 Committer: Matthias Boehm <[email protected]> Committed: Thu Nov 2 00:39:18 2017 -0700 ---------------------------------------------------------------------- .../sysml/hops/codegen/SpoofCompiler.java | 43 +----- .../hops/codegen/template/CPlanOpRewriter.java | 130 +++++++++++++++++++ .../hops/codegen/template/TemplateCell.java | 11 +- .../codegen/template/TemplateOuterProduct.java | 9 +- .../hops/codegen/template/TemplateRow.java | 10 -- .../functions/codegen/RowAggTmplTest.java | 20 ++- .../scripts/functions/codegen/rowAggPattern34.R | 32 +++++ .../functions/codegen/rowAggPattern34.dml | 29 +++++ 8 files changed, 219 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java b/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java index 4af8540..51cd0a2 100644 --- a/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java +++ b/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java @@ -39,7 +39,6 @@ import org.apache.sysml.api.DMLScript.RUNTIME_PLATFORM; import org.apache.sysml.conf.ConfigurationManager; import org.apache.sysml.conf.DMLConfig; import org.apache.sysml.hops.codegen.cplan.CNode; -import org.apache.sysml.hops.codegen.cplan.CNodeBinary.BinType; import org.apache.sysml.hops.codegen.cplan.CNodeCell; import org.apache.sysml.hops.codegen.cplan.CNodeData; import org.apache.sysml.hops.codegen.cplan.CNodeMultiAgg; @@ -53,7 +52,6 @@ import org.apache.sysml.hops.codegen.opt.PlanSelectionFuseCostBased; import org.apache.sysml.hops.codegen.opt.PlanSelectionFuseCostBasedV2; import org.apache.sysml.hops.codegen.opt.PlanSelectionFuseNoRedundancy; import org.apache.sysml.hops.codegen.cplan.CNodeTpl; -import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType; import org.apache.sysml.hops.codegen.template.TemplateBase; import org.apache.sysml.hops.codegen.template.TemplateBase.CloseType; import org.apache.sysml.hops.codegen.template.TemplateBase.TemplateType; @@ -61,6 +59,7 @@ import org.apache.sysml.hops.codegen.template.CPlanCSERewriter; import org.apache.sysml.hops.codegen.template.CPlanMemoTable; import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry; import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntrySet; +import org.apache.sysml.hops.codegen.template.CPlanOpRewriter; import org.apache.sysml.hops.codegen.template.TemplateUtils; import org.apache.sysml.hops.recompile.RecompileStatus; import org.apache.sysml.hops.recompile.Recompiler; @@ -68,7 +67,6 @@ import org.apache.sysml.hops.AggUnaryOp; import org.apache.sysml.hops.Hop; import org.apache.sysml.hops.Hop.OpOp1; import org.apache.sysml.hops.HopsException; -import org.apache.sysml.hops.LiteralOp; import org.apache.sysml.hops.OptimizerUtils; import org.apache.sysml.hops.rewrite.HopRewriteUtils; import org.apache.sysml.hops.rewrite.ProgramRewriteStatus; @@ -684,13 +682,15 @@ public class SpoofCompiler private static HashMap<Long, Pair<Hop[],CNodeTpl>> cleanupCPlans(CPlanMemoTable memo, HashMap<Long, Pair<Hop[],CNodeTpl>> cplans) { HashMap<Long, Pair<Hop[],CNodeTpl>> cplans2 = new HashMap<>(); + CPlanOpRewriter rewriter = new CPlanOpRewriter(); CPlanCSERewriter cse = new CPlanCSERewriter(); for( Entry<Long, Pair<Hop[],CNodeTpl>> e : cplans.entrySet() ) { CNodeTpl tpl = e.getValue().getValue(); Hop[] inHops = e.getValue().getKey(); - //perform common subexpression elimination + //perform simplifications and cse rewrites + tpl = rewriter.simplifyCPlan(tpl); tpl = cse.eliminateCommonSubexpressions(tpl); //update input hops (order-preserving) @@ -727,10 +727,6 @@ public class SpoofCompiler else rFindAndRemoveLookup(tpl.getOutput(), in1, !(tpl instanceof CNodeRow)); - //remove unnecessary neq 0 on main input of outer template - if( tpl instanceof CNodeOuterProduct ) - rFindAndRemoveBinaryMS(tpl.getOutput(), in1, BinType.NOTEQUAL, "0", "1"); - //remove invalid row templates (e.g., unsatisfied blocksize constraint) if( tpl instanceof CNodeRow ) { //check for invalid row cplan over column vector @@ -810,37 +806,6 @@ public class SpoofCompiler } } - @SuppressWarnings("unused") - private static void rFindAndRemoveUnary(CNode node, CNodeData mainInput, UnaryType type) { - for( int i=0; i<node.getInput().size(); i++ ) { - CNode tmp = node.getInput().get(i); - if( TemplateUtils.isUnary(tmp, type) && tmp.getInput().get(0) instanceof CNodeData - && ((CNodeData)tmp.getInput().get(0)).getHopID()==mainInput.getHopID() ) - { - node.getInput().set(i, tmp.getInput().get(0)); - } - else - rFindAndRemoveUnary(tmp, mainInput, type); - } - } - - private static void rFindAndRemoveBinaryMS(CNode node, CNodeData mainInput, BinType type, String lit, String replace) { - for( int i=0; i<node.getInput().size(); i++ ) { - CNode tmp = node.getInput().get(i); - if( TemplateUtils.isBinary(tmp, type) && tmp.getInput().get(1).isLiteral() - && tmp.getInput().get(1).getVarname().equals(lit) - && tmp.getInput().get(0) instanceof CNodeData - && ((CNodeData)tmp.getInput().get(0)).getHopID()==mainInput.getHopID() ) - { - CNodeData cnode = new CNodeData(new LiteralOp(replace)); - cnode.setLiteral(true); - node.getInput().set(i, cnode); - } - else - rFindAndRemoveBinaryMS(tmp, mainInput, type, lit, replace); - } - } - private static boolean rHasLookupRC1(CNode node, CNodeData mainInput, boolean includeRC1) { boolean ret = false; for( int i=0; i<node.getInput().size() && !ret; i++ ) { http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/src/main/java/org/apache/sysml/hops/codegen/template/CPlanOpRewriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/CPlanOpRewriter.java b/src/main/java/org/apache/sysml/hops/codegen/template/CPlanOpRewriter.java new file mode 100644 index 0000000..8ec750c --- /dev/null +++ b/src/main/java/org/apache/sysml/hops/codegen/template/CPlanOpRewriter.java @@ -0,0 +1,130 @@ +/* + * 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.sysml.hops.codegen.template; + +import java.util.ArrayList; + +import org.apache.sysml.hops.LiteralOp; +import org.apache.sysml.hops.codegen.cplan.CNode; +import org.apache.sysml.hops.codegen.cplan.CNodeData; +import org.apache.sysml.hops.codegen.cplan.CNodeMultiAgg; +import org.apache.sysml.hops.codegen.cplan.CNodeOuterProduct; +import org.apache.sysml.hops.codegen.cplan.CNodeTpl; +import org.apache.sysml.hops.codegen.cplan.CNodeUnary; +import org.apache.sysml.hops.codegen.cplan.CNodeBinary.BinType; +import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType; + +/** + * This cplan rewriter is meant to be the central place for any cplan + * enhancements before code generation. These rewrites do not aim to + * handle reorderings or other algebraic simplifications but rather + * focus on low-level simplifications to produce better code, while + * keeping the cplan construction of the individual templates clean + * and without unnecessary redundancy. + * + * Assumption: This rewriter should be called before CSE as these + * rewrites potentially destroy common subexpressions. + */ +public class CPlanOpRewriter +{ + public CNodeTpl simplifyCPlan(CNodeTpl tpl) { + //apply template specific rewrites + tpl = rewriteRemoveOuterNeq0(tpl); // Outer(a!=0) -> Outer(1) + + //apply operation specific rewrites + if( tpl instanceof CNodeMultiAgg ) { + ArrayList<CNode> outputs = ((CNodeMultiAgg)tpl).getOutputs(); + for( int i=0; i< outputs.size(); i++ ) + outputs.set(i, rSimplifyCNode(outputs.get(i))); + } + else { + tpl.setOutput(rSimplifyCNode(tpl.getOutput())); + } + + return tpl; + } + + private static CNode rSimplifyCNode(CNode node) { + //process children recursively + for(int i=0; i<node.getInput().size(); i++) + node.getInput().set(i, rSimplifyCNode(node.getInput().get(i))); + + //apply all node-local simplification rewrites + node = rewriteRowCountNnz(node); //rowSums(X!=0) -> rowNnz(X) + node = rewriteRowSumSq(node); //rowSums(X^2) -> rowSumSqs(X) + node = rewriteBinaryPow2(node); //x^2 -> x*x + node = rewriteBinaryMult2(node); //x*2 -> x+x; + return node; + } + + private static CNode rewriteRowCountNnz(CNode node) { + return (TemplateUtils.isUnary(node, UnaryType.ROW_SUMS) + && TemplateUtils.isBinary(node.getInput().get(0), BinType.VECT_NOTEQUAL_SCALAR) + && node.getInput().get(0).getInput().get(1).isLiteral() + && node.getInput().get(0).getInput().get(1).getVarname().equals("0")) ? + new CNodeUnary(node.getInput().get(0).getInput().get(0), UnaryType.ROW_COUNTNNZS) : node; + } + + private static CNode rewriteRowSumSq(CNode node) { + return (TemplateUtils.isUnary(node, UnaryType.ROW_SUMS) + && TemplateUtils.isBinary(node.getInput().get(0), BinType.VECT_POW_SCALAR) + && node.getInput().get(0).getInput().get(1).isLiteral() + && node.getInput().get(0).getInput().get(1).getVarname().equals("2")) ? + new CNodeUnary(node.getInput().get(0).getInput().get(0), UnaryType.ROW_SUMSQS) : node; + } + + private static CNode rewriteBinaryPow2(CNode node) { + return (TemplateUtils.isBinary(node, BinType.POW) + && node.getInput().get(1).isLiteral() + && node.getInput().get(1).getVarname().equals("2")) ? + new CNodeUnary(node.getInput().get(0), UnaryType.POW2) : node; + } + + private static CNode rewriteBinaryMult2(CNode node) { + return (TemplateUtils.isBinary(node, BinType.MULT) + && node.getInput().get(1).isLiteral() + && node.getInput().get(1).getVarname().equals("2")) ? + new CNodeUnary(node.getInput().get(0), UnaryType.MULT2) : node; + } + + private static CNodeTpl rewriteRemoveOuterNeq0(CNodeTpl tpl) { + if( tpl instanceof CNodeOuterProduct ) + rFindAndRemoveBinaryMS(tpl.getOutput(), (CNodeData) + tpl.getInput().get(0), BinType.NOTEQUAL, "0", "1"); + return tpl; + } + + private static void rFindAndRemoveBinaryMS(CNode node, CNodeData mainInput, BinType type, String lit, String replace) { + for( int i=0; i<node.getInput().size(); i++ ) { + CNode tmp = node.getInput().get(i); + if( TemplateUtils.isBinary(tmp, type) && tmp.getInput().get(1).isLiteral() + && tmp.getInput().get(1).getVarname().equals(lit) + && tmp.getInput().get(0) instanceof CNodeData + && ((CNodeData)tmp.getInput().get(0)).getHopID()==mainInput.getHopID() ) + { + CNodeData cnode = new CNodeData(new LiteralOp(replace)); + cnode.setLiteral(true); + node.getInput().set(i, cnode); + } + else + rFindAndRemoveBinaryMS(tmp, mainInput, type, lit, replace); + } + } +} http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java index 4f3d4f4..fe5a1e7 100644 --- a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java +++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java @@ -195,12 +195,9 @@ public class TemplateCell extends TemplateBase cdata1 = TemplateUtils.wrapLookupIfNecessary(cdata1, hop.getInput().get(0)); cdata2 = TemplateUtils.wrapLookupIfNecessary(cdata2, hop.getInput().get(1)); - if( bop.getOp()==OpOp2.POW && cdata2.isLiteral() && cdata2.getVarname().equals("2") ) - out = new CNodeUnary(cdata1, UnaryType.POW2); - else if( bop.getOp()==OpOp2.MULT && cdata2.isLiteral() && cdata2.getVarname().equals("2") ) - out = new CNodeUnary(cdata1, UnaryType.MULT2); - else //default binary - out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(primitiveOpName)); + //construct binary cnode + out = new CNodeBinary(cdata1, cdata2, + BinType.valueOf(primitiveOpName)); } else if(hop instanceof TernaryOp) { @@ -215,7 +212,7 @@ public class TemplateCell extends TemplateBase //construct ternary cnode, primitive operation derived from OpOp3 out = new CNodeTernary(cdata1, cdata2, cdata3, - TernaryType.valueOf(top.getOp().name())); + TernaryType.valueOf(top.getOp().name())); } else if( hop instanceof ParameterizedBuiltinOp ) { http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateOuterProduct.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateOuterProduct.java b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateOuterProduct.java index 256f540..188bac2 100644 --- a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateOuterProduct.java +++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateOuterProduct.java @@ -174,7 +174,6 @@ public class TemplateOuterProduct extends TemplateBase { } else if(hop instanceof BinaryOp) { - BinaryOp bop = (BinaryOp) hop; CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID()); CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID()); String primitiveOpName = ((BinaryOp)hop).getOp().toString(); @@ -187,12 +186,8 @@ public class TemplateOuterProduct extends TemplateBase { //add lookups if required cdata1 = TemplateUtils.wrapLookupIfNecessary(cdata1, hop.getInput().get(0)); cdata2 = TemplateUtils.wrapLookupIfNecessary(cdata2, hop.getInput().get(1)); - if( bop.getOp()==OpOp2.POW && cdata2.isLiteral() && cdata2.getVarname().equals("2") ) - out = new CNodeUnary(cdata1, UnaryType.POW2); - else if( bop.getOp()==OpOp2.MULT && cdata2.isLiteral() && cdata2.getVarname().equals("2") ) - out = new CNodeUnary(cdata1, UnaryType.MULT2); - else - out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(primitiveOpName)); + + out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(primitiveOpName)); } else if(hop instanceof AggBinaryOp) { http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java index b862abf..dc08dbf 100644 --- a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java +++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java @@ -257,16 +257,6 @@ public class TemplateRow extends TemplateBase 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 if( HopRewriteUtils.isAggUnaryOp(hop, AggOp.SUM) - && HopRewriteUtils.isBinaryMatrixScalar(hop.getInput().get(0), OpOp2.NOTEQUAL, 0) - && cdata1 instanceof CNodeBinary ) { - out = new CNodeUnary(cdata1.getInput().get(0), UnaryType.ROW_COUNTNNZS); - } - else if( HopRewriteUtils.isAggUnaryOp(hop, AggOp.SUM) - && HopRewriteUtils.isBinaryMatrixScalar(hop.getInput().get(0), OpOp2.POW, 2) - && cdata1 instanceof CNodeBinary ) { - out = new CNodeUnary(cdata1.getInput().get(0), UnaryType.ROW_SUMSQS); - } else { String opcode = "ROW_"+((AggUnaryOp)hop).getOp().name().toUpperCase()+"S"; out = new CNodeUnary(cdata1, UnaryType.valueOf(opcode)); http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/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 5d2015f..b5426ae 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 @@ -70,6 +70,7 @@ public class RowAggTmplTest extends AutomatedTestBase private static final String TEST_NAME31 = TEST_NAME+"31"; //MLogreg - matrix-vector cbind 0s generalized private static final String TEST_NAME32 = TEST_NAME+"32"; //X[, 1] - rowSums(X) private static final String TEST_NAME33 = TEST_NAME+"33"; //Kmeans, inner loop + private static final String TEST_NAME34 = TEST_NAME+"34"; //X / rowSums(X!=0) private static final String TEST_DIR = "functions/codegen/"; private static final String TEST_CLASS_DIR = TEST_DIR + RowAggTmplTest.class.getSimpleName() + "/"; @@ -81,7 +82,7 @@ public class RowAggTmplTest extends AutomatedTestBase @Override public void setUp() { TestUtils.clearAssertionInformation(); - for(int i=1; i<=33; i++) + for(int i=1; i<=34; i++) addTestConfiguration( TEST_NAME+i, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME+i, new String[] { String.valueOf(i) }) ); } @@ -580,6 +581,21 @@ public class RowAggTmplTest extends AutomatedTestBase testCodegenIntegration( TEST_NAME33, false, ExecType.SPARK ); } + @Test + public void testCodegenRowAggRewrite34CP() { + testCodegenIntegration( TEST_NAME34, true, ExecType.CP ); + } + + @Test + public void testCodegenRowAgg34CP() { + testCodegenIntegration( TEST_NAME34, false, ExecType.CP ); + } + + @Test + public void testCodegenRowAgg34SP() { + testCodegenIntegration( TEST_NAME34, false, ExecType.SPARK ); + } + private void testCodegenIntegration( String testname, boolean rewrites, ExecType instType ) { boolean oldFlag = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION; @@ -601,7 +617,7 @@ public class RowAggTmplTest extends AutomatedTestBase String HOME = SCRIPT_DIR + TEST_DIR; fullDMLScriptName = HOME + testname + ".dml"; - programArgs = new String[]{"-explain", "recompile_hops", "-stats", "-args", output("S") }; + programArgs = new String[]{"-explain", "recompile_runtime", "-stats", "-args", output("S") }; fullRScriptName = HOME + testname + ".R"; rCmd = getRCmd(inputDir(), expectedDir()); http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/src/test/scripts/functions/codegen/rowAggPattern34.R ---------------------------------------------------------------------- diff --git a/src/test/scripts/functions/codegen/rowAggPattern34.R b/src/test/scripts/functions/codegen/rowAggPattern34.R new file mode 100644 index 0000000..2deea5d --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern34.R @@ -0,0 +1,32 @@ +#------------------------------------------------------------- +# +# 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,6000)/6000, 300, 20, byrow=TRUE); +X[,6:20] = matrix(0, 300, 15); + +R = X / rowSums(X!=0); + +writeMM(as(R, "CsparseMatrix"), paste(args[2], "S", sep="")); http://git-wip-us.apache.org/repos/asf/systemml/blob/e1f5866a/src/test/scripts/functions/codegen/rowAggPattern34.dml ---------------------------------------------------------------------- diff --git a/src/test/scripts/functions/codegen/rowAggPattern34.dml b/src/test/scripts/functions/codegen/rowAggPattern34.dml new file mode 100644 index 0000000..12d9b7f --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern34.dml @@ -0,0 +1,29 @@ +#------------------------------------------------------------- +# +# 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,6000)/6000, 300, 20); +X[,6:20] = matrix(0, 300, 15); +while(FALSE){} + +R = X / rowSums(X!=0); + +write(R, $1)
