You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemml.apache.org by mb...@apache.org on 2017/03/25 22:53:49 UTC
[2/2] incubator-systemml git commit: [SYSTEMML-1418] New codegen plan
selection framework, fuse-all selector
[SYSTEMML-1418] New codegen plan selection framework, fuse-all selector
This patch introduces a new plan selection framework as well as the
initial fuse-all selector. Additionally, this includes the following
minor extensions:
* Refactoring existing rowagg, outer, cell templates
* Support for unary operations in row aggregate template
* New row aggregate test case with multiple dag roots
Project: http://git-wip-us.apache.org/repos/asf/incubator-systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-systemml/commit/b3120ce2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-systemml/tree/b3120ce2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-systemml/diff/b3120ce2
Branch: refs/heads/master
Commit: b3120ce24106a3593ff4353c99935adce41ed8b3
Parents: 0dd095f
Author: Matthias Boehm <mb...@gmail.com>
Authored: Fri Mar 24 20:13:00 2017 -0700
Committer: Matthias Boehm <mb...@gmail.com>
Committed: Sat Mar 25 15:54:54 2017 -0700
----------------------------------------------------------------------
.../sysml/hops/codegen/SpoofCompiler.java | 14 +-
.../sysml/hops/codegen/template/BaseTpl.java | 124 --------
.../hops/codegen/template/CPlanMemoTable.java | 109 +++----
.../sysml/hops/codegen/template/CellTpl.java | 304 -------------------
.../hops/codegen/template/OuterProductTpl.java | 213 -------------
.../hops/codegen/template/PlanSelection.java | 73 +++++
.../codegen/template/PlanSelectionFuseAll.java | 85 ++++++
.../sysml/hops/codegen/template/RowAggTpl.java | 246 ---------------
.../hops/codegen/template/TemplateBase.java | 129 ++++++++
.../hops/codegen/template/TemplateCell.java | 304 +++++++++++++++++++
.../codegen/template/TemplateOuterProduct.java | 213 +++++++++++++
.../hops/codegen/template/TemplateRowAgg.java | 259 ++++++++++++++++
.../hops/codegen/template/TemplateUtils.java | 16 +-
.../functions/codegen/RowAggTmplTest.java | 13 +-
.../scripts/functions/codegen/rowAggPattern7.R | 34 +++
.../functions/codegen/rowAggPattern7.dml | 31 ++
16 files changed, 1205 insertions(+), 962 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/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 8587367..17e2fcf 100644
--- a/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java
+++ b/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java
@@ -41,9 +41,9 @@ import org.apache.sysml.hops.codegen.cplan.CNodeTernary.TernaryType;
import org.apache.sysml.hops.codegen.cplan.CNodeTpl;
import org.apache.sysml.hops.codegen.cplan.CNodeUnary;
import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType;
-import org.apache.sysml.hops.codegen.template.BaseTpl;
-import org.apache.sysml.hops.codegen.template.BaseTpl.CloseType;
-import org.apache.sysml.hops.codegen.template.BaseTpl.TemplateType;
+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;
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;
@@ -317,7 +317,7 @@ public class SpoofCompiler
rExploreCPlans(hop, memo, compileLiterals);
//select optimal cplan candidates
- memo.pruneSuboptimal();
+ memo.pruneSuboptimal(roots);
//construct actual cplan representations
LinkedHashMap<Long, Pair<Hop[],CNodeTpl>> ret = new LinkedHashMap<Long, Pair<Hop[],CNodeTpl>>();
@@ -341,7 +341,7 @@ public class SpoofCompiler
rExploreCPlans(c, memo, compileLiterals);
//open initial operator plans, if possible
- for( BaseTpl tpl : TemplateUtils.TEMPLATES )
+ for( TemplateBase tpl : TemplateUtils.TEMPLATES )
if( tpl.open(hop) )
memo.add(hop, tpl.getType());
@@ -349,7 +349,7 @@ public class SpoofCompiler
for( Hop c : hop.getInput() ) {
if( memo.contains(c.getHopID()) )
for( MemoTableEntry me : memo.getDistinct(c.getHopID()) ) {
- BaseTpl tpl = TemplateUtils.createTemplate(me.type, me.closed);
+ TemplateBase tpl = TemplateUtils.createTemplate(me.type, me.closed);
if( tpl.fuse(hop, c) ) {
int pos = hop.getInput().indexOf(c);
MemoTableEntrySet P = new MemoTableEntrySet(tpl.getType(), pos, c.getHopID(), tpl.isClosed());
@@ -376,7 +376,7 @@ public class SpoofCompiler
Iterator<MemoTableEntry> iter = memo.get(hop.getHopID()).iterator();
while( iter.hasNext() ) {
MemoTableEntry me = iter.next();
- BaseTpl tpl = TemplateUtils.createTemplate(me.type);
+ TemplateBase tpl = TemplateUtils.createTemplate(me.type);
CloseType ccode = tpl.close(hop);
if( ccode == CloseType.CLOSED_INVALID )
iter.remove();
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/BaseTpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/BaseTpl.java b/src/main/java/org/apache/sysml/hops/codegen/template/BaseTpl.java
deleted file mode 100644
index 2f643af..0000000
--- a/src/main/java/org/apache/sysml/hops/codegen/template/BaseTpl.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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 org.apache.sysml.hops.Hop;
-import org.apache.sysml.hops.codegen.cplan.CNodeTpl;
-import org.apache.sysml.runtime.matrix.data.Pair;
-
-public abstract class BaseTpl
-{
- public enum TemplateType {
- CellTpl,
- OuterProdTpl,
- RowAggTpl
- }
-
- public enum CloseType {
- CLOSED_VALID,
- CLOSED_INVALID,
- OPEN,
- }
-
- protected TemplateType _type = null;
- protected boolean _closed = false;
-
- protected BaseTpl(TemplateType type) {
- _type = type;
- _closed = false;
- }
-
- public TemplateType getType() {
- return _type;
- }
-
- public boolean isClosed() {
- return _closed;
- }
-
- /////////////////////////////////////////////
- // Open-Fuse-Merge-Close interface
- // (for candidate generation and exploration)
-
- /**
- * Indicates if this template can be opened at the given hop,
- * where hop represents bottom (first operation on the inputs)
- * of the fused operator.
- *
- * @param hop current hop
- * @return true if template can be opened
- */
- public abstract boolean open(Hop hop);
-
- /**
- * Indicates if the template can be expanded to the given hop
- * starting from an open template at the input.
- *
- * @param hop current hop
- * @param input hop with open template of same type
- * @return true if the current hop can be fused into the operator.
- */
- public abstract boolean fuse(Hop hop, Hop input);
-
- /**
- * Indicates if the template at the current hop can be expanded
- * by merging another template available for one of its other inputs
- * which is not yet covered by the template of the current hop.
- *
- * @param hop current hop
- * @param input direct input of current hop with available template
- * @return true if the the input hop can be fused into the current hop
- */
- public abstract boolean merge(Hop hop, Hop input);
-
- /**
- * Indicates if the template must be closed at the current hop; either
- * due to final operations (e.g., aggregate) or unsupported operations.
- *
- * @param hop current hop
- * @return close type (closed invalid, closed valid, open)
- */
- public abstract CloseType close(Hop hop);
-
- /**
- * Mark the template as closed either invalid or valid.
- */
- public void close() {
- _closed = true;
- }
-
- /////////////////////////////////////////////
- // CPlan construction interface
- // (for plan creation of selected candidates)
-
- /**
- * Constructs a single cplan rooted at the given hop, according
- * to the plan given in the memo structure for this particular
- * hop and its recursive inputs.
- *
- * @param hop root of cplan
- * @param memo memoization table for partial subplans
- * @param compileLiterals if true compile non-integer literals
- * as constants, otherwise variables. note: integer literals are
- * always compiled as constants.
- * @return
- */
- public abstract Pair<Hop[], CNodeTpl> constructCplan(Hop hop, CPlanMemoTable memo, boolean compileLiterals);
-}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/CPlanMemoTable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/CPlanMemoTable.java b/src/main/java/org/apache/sysml/hops/codegen/template/CPlanMemoTable.java
index 03cb7e7..9a66f09 100644
--- a/src/main/java/org/apache/sysml/hops/codegen/template/CPlanMemoTable.java
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/CPlanMemoTable.java
@@ -35,19 +35,18 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.sysml.hops.Hop;
import org.apache.sysml.hops.codegen.SpoofCompiler;
-import org.apache.sysml.hops.codegen.template.BaseTpl.TemplateType;
-import org.apache.sysml.hops.rewrite.HopRewriteUtils;
+import org.apache.sysml.hops.codegen.template.TemplateBase.TemplateType;
public class CPlanMemoTable
{
private static final Log LOG = LogFactory.getLog(SpoofCompiler.class.getName());
- private HashMap<Long, ArrayList<MemoTableEntry>> _plans;
- private HashMap<Long, Hop> _hopRefs;
- private HashSet<Long> _plansBlacklist;
+ protected HashMap<Long, List<MemoTableEntry>> _plans;
+ protected HashMap<Long, Hop> _hopRefs;
+ protected HashSet<Long> _plansBlacklist;
public CPlanMemoTable() {
- _plans = new HashMap<Long, ArrayList<MemoTableEntry>>();
+ _plans = new HashMap<Long, List<MemoTableEntry>>();
_hopRefs = new HashMap<Long, Hop>();
_plansBlacklist = new HashSet<Long>();
}
@@ -94,6 +93,16 @@ public class CPlanMemoTable
_plans.put(hop.getHopID(), new ArrayList<MemoTableEntry>());
_plans.get(hop.getHopID()).addAll(P.plans);
}
+
+ public void remove(Hop hop, HashSet<MemoTableEntry> blackList) {
+ _plans.put(hop.getHopID(), _plans.get(hop.getHopID()).stream()
+ .filter(p -> !blackList.contains(p)).collect(Collectors.toList()));
+ }
+
+ public void setDistinct(long hopID, List<MemoTableEntry> plans) {
+ _plans.put(hopID, plans.stream()
+ .distinct().collect(Collectors.toList()));
+ }
@SuppressWarnings("unchecked")
public void pruneRedundant(long hopID) {
@@ -102,7 +111,7 @@ public class CPlanMemoTable
//prune redundant plans (i.e., equivalent)
HashSet<MemoTableEntry> set = new HashSet<MemoTableEntry>();
- ArrayList<MemoTableEntry> list = _plans.get(hopID);
+ List<MemoTableEntry> list = _plans.get(hopID);
for( MemoTableEntry me : list )
set.add(me);
@@ -127,13 +136,13 @@ public class CPlanMemoTable
list.addAll(CollectionUtils.subtract(set, rmList));
}
- public void pruneSuboptimal() {
+ public void pruneSuboptimal(ArrayList<Hop> roots) {
if( SpoofCompiler.LDEBUG )
LOG.info("#1: Memo before plan selection ("+size()+" plans)\n"+this);
//build index of referenced entries
HashSet<Long> ix = new HashSet<Long>();
- for( Entry<Long, ArrayList<MemoTableEntry>> e : _plans.entrySet() )
+ for( Entry<Long, List<MemoTableEntry>> e : _plans.entrySet() )
for( MemoTableEntry me : e.getValue() ) {
ix.add(me.input1);
ix.add(me.input2);
@@ -141,15 +150,13 @@ public class CPlanMemoTable
}
//prune single-operation (not referenced, and no child references)
- Iterator<Entry<Long, ArrayList<MemoTableEntry>>> iter = _plans.entrySet().iterator();
+ Iterator<Entry<Long, List<MemoTableEntry>>> iter = _plans.entrySet().iterator();
while( iter.hasNext() ) {
- Entry<Long, ArrayList<MemoTableEntry>> e = iter.next();
+ Entry<Long, List<MemoTableEntry>> e = iter.next();
if( !ix.contains(e.getKey()) ) {
- ArrayList<MemoTableEntry> list = e.getValue();
- for( int i=0; i<list.size(); i++ )
- if( !list.get(i).hasPlanRef() )
- list.remove(i--);
- if( list.isEmpty() )
+ e.setValue(e.getValue().stream().filter(
+ p -> p.hasPlanRef()).collect(Collectors.toList()));
+ if( e.getValue().isEmpty() )
iter.remove();
}
}
@@ -157,13 +164,23 @@ public class CPlanMemoTable
//prune dominated plans (e.g., plan referenced by other plan and this
//other plan is single consumer) by marking it as blacklisted because
//the chain of entries is still required for cplan construction
- for( Entry<Long, ArrayList<MemoTableEntry>> e : _plans.entrySet() )
+ for( Entry<Long, List<MemoTableEntry>> e : _plans.entrySet() )
for( MemoTableEntry me : e.getValue() ) {
for( int i=0; i<=2; i++ )
if( me.isPlanRef(i) && _hopRefs.get(me.intput(i)).getParent().size()==1 )
_plansBlacklist.add(me.intput(i));
}
+ //core plan selection
+ switch( SpoofCompiler.PLAN_SEL_POLICY ) {
+ case FUSE_ALL:
+ new PlanSelectionFuseAll().selectPlans(this, roots);
+ break;
+ case FUSE_NO_REDUNDANCY:
+ case FUSE_COST_BASED:
+ throw new RuntimeException("Not implemented yet.");
+ }
+
if( SpoofCompiler.LDEBUG )
LOG.info("#2: Memo after plan selection ("+size()+" plans)\n"+this);
}
@@ -183,51 +200,21 @@ public class CPlanMemoTable
List<MemoTableEntry> tmp = get(hopID);
if( tmp == null || tmp.isEmpty() )
return null;
-
- //get first plan by type preference
- TemplateType[] ttPrefOrder = new TemplateType[]{TemplateType.RowAggTpl,
- TemplateType.OuterProdTpl, TemplateType.CellTpl};
- for( TemplateType pref : ttPrefOrder )
- for( MemoTableEntry me : tmp )
- if( me.type == pref && isValid(me, _hopRefs.get(hopID)) )
- return me;
- return null;
+
+ //single plan per type, get plan w/ best rank in preferred order
+ //but ensure that the plans valid as a top-level plan
+ return tmp.stream().filter(p -> PlanSelection.isValid(p, _hopRefs.get(hopID)))
+ .min(Comparator.comparing(p -> p.type.getRank())).orElse(null);
}
- //TODO revisit requirement for preference once cost-based pruning (pruneSuboptimal) ready
public MemoTableEntry getBest(long hopID, TemplateType pref) {
List<MemoTableEntry> tmp = get(hopID);
- if( tmp.size()==1 ) //single plan available
- return tmp.get(0);
-
- //try to find plan with preferred type
- if( SpoofCompiler.LDEBUG )
- LOG.warn("Multiple memo table entries available, searching for preferred type.");
- ArrayList<MemoTableEntry> tmp2 = new ArrayList<MemoTableEntry>();
- for( MemoTableEntry me : tmp )
- if( me.type == pref )
- tmp2.add(me);
- if( !tmp2.isEmpty() ) {
- if( tmp2.size() > 1 && SpoofCompiler.LDEBUG )
- LOG.warn("Multiple memo table entries w/ preferred type available, return max refs entry.");
- return getMaxRefsEntry(tmp2);
- }
- else {
- if( SpoofCompiler.LDEBUG )
- LOG.warn("Multiple memo table entries available but none with preferred type, return max refs entry.");
- return getMaxRefsEntry(tmp);
- }
- }
-
- private static MemoTableEntry getMaxRefsEntry(List<MemoTableEntry> tmp) {
- return Collections.max(tmp, Comparator.comparing(p -> p.countPlanRefs()));
- }
-
- private static boolean isValid(MemoTableEntry me, Hop hop) {
- return (me.type == TemplateType.OuterProdTpl
- && (me.closed || HopRewriteUtils.isBinaryMatrixMatrixOperation(hop)))
- || (me.type == TemplateType.RowAggTpl && me.closed)
- || (me.type == TemplateType.CellTpl);
+ if( tmp == null || tmp.isEmpty() )
+ return null;
+
+ //single plan per type, get plan w/ best rank in preferred order
+ return Collections.min(tmp, Comparator.comparing(
+ p -> (p.type==pref) ? -1 : p.type.getRank()));
}
public int size() {
@@ -242,7 +229,7 @@ public class CPlanMemoTable
sb.append("----------------------------------\n");
sb.append("MEMO TABLE: \n");
sb.append("----------------------------------\n");
- for( Entry<Long, ArrayList<MemoTableEntry>> e : _plans.entrySet() ) {
+ for( Entry<Long, List<MemoTableEntry>> e : _plans.entrySet() ) {
sb.append(e.getKey() + " "+_hopRefs.get(e.getKey()).getOpString()+": ");
sb.append(Arrays.toString(e.getValue().toArray(new MemoTableEntry[0]))+"\n");
}
@@ -252,6 +239,10 @@ public class CPlanMemoTable
sb.append("----------------------------------\n");
return sb.toString();
}
+
+ ////////////////////////////////////////
+ // Memo table entry abstractions
+ //////
public static class MemoTableEntry
{
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/CellTpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/CellTpl.java b/src/main/java/org/apache/sysml/hops/codegen/template/CellTpl.java
deleted file mode 100644
index b919b6d..0000000
--- a/src/main/java/org/apache/sysml/hops/codegen/template/CellTpl.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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 java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.apache.sysml.hops.AggBinaryOp;
-import org.apache.sysml.hops.AggUnaryOp;
-import org.apache.sysml.hops.BinaryOp;
-import org.apache.sysml.hops.Hop;
-import org.apache.sysml.hops.UnaryOp;
-import org.apache.sysml.hops.Hop.AggOp;
-import org.apache.sysml.hops.Hop.Direction;
-import org.apache.sysml.hops.Hop.OpOp2;
-import org.apache.sysml.hops.IndexingOp;
-import org.apache.sysml.hops.LiteralOp;
-import org.apache.sysml.hops.TernaryOp;
-import org.apache.sysml.hops.codegen.cplan.CNode;
-import org.apache.sysml.hops.codegen.cplan.CNodeBinary;
-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.CNodeTpl;
-import org.apache.sysml.hops.codegen.cplan.CNodeUnary;
-import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType;
-import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry;
-import org.apache.sysml.hops.codegen.cplan.CNodeTernary;
-import org.apache.sysml.hops.codegen.cplan.CNodeTernary.TernaryType;
-import org.apache.sysml.hops.rewrite.HopRewriteUtils;
-import org.apache.sysml.parser.Expression.DataType;
-import org.apache.sysml.runtime.matrix.data.Pair;
-
-public class CellTpl extends BaseTpl
-{
- public CellTpl() {
- super(TemplateType.CellTpl);
- }
-
- @Override
- public boolean open(Hop hop) {
- return isValidOperation(hop)
- || (hop instanceof IndexingOp && ((IndexingOp)hop).isColLowerEqualsUpper());
- }
-
- @Override
- public boolean fuse(Hop hop, Hop input) {
- return !isClosed() && (isValidOperation(hop)
- || (HopRewriteUtils.isSum(hop) && ((AggUnaryOp) hop).getDirection()!= Direction.Col)
- || (HopRewriteUtils.isMatrixMultiply(hop) && hop.getDim1()==1 && hop.getDim2()==1)
- && HopRewriteUtils.isTransposeOperation(hop.getInput().get(0)));
- }
-
- @Override
- public boolean merge(Hop hop, Hop input) {
- //merge of other cell tpl possible
- return (!isClosed() && isValidOperation(hop));
- }
-
- @Override
- public CloseType close(Hop hop) {
- //need to close cell tpl after aggregation, see fuse for exact properties
- if( (HopRewriteUtils.isSum(hop) && ((AggUnaryOp) hop).getDirection()!= Direction.Col)
- || (HopRewriteUtils.isMatrixMultiply(hop) && hop.getDim1()==1 && hop.getDim2()==1) )
- return CloseType.CLOSED_VALID;
- else if( hop instanceof AggUnaryOp || hop instanceof AggBinaryOp )
- return CloseType.CLOSED_INVALID;
- else
- return CloseType.OPEN;
- }
-
- @Override
- public Pair<Hop[], CNodeTpl> constructCplan(Hop hop, CPlanMemoTable memo, boolean compileLiterals)
- {
- //recursively process required cplan output
- HashSet<Hop> inHops = new HashSet<Hop>();
- HashMap<Long, CNode> tmp = new HashMap<Long, CNode>();
- hop.resetVisitStatus();
- rConstructCplan(hop, memo, tmp, inHops, compileLiterals);
- hop.resetVisitStatus();
-
- //reorder inputs (ensure matrices/vectors come first) and prune literals
- //note: we order by number of cells and subsequently sparsity to ensure
- //that sparse inputs are used as the main input w/o unnecessary conversion
- List<Hop> sinHops = inHops.stream()
- .filter(h -> !(h.getDataType().isScalar() && tmp.get(h.getHopID()).isLiteral()))
- .sorted(new HopInputComparator()).collect(Collectors.toList());
-
- //construct template node
- ArrayList<CNode> inputs = new ArrayList<CNode>();
- for( Hop in : sinHops )
- inputs.add(tmp.get(in.getHopID()));
- CNode output = tmp.get(hop.getHopID());
- CNodeCell tpl = new CNodeCell(inputs, output);
- tpl.setCellType(TemplateUtils.getCellType(hop));
- tpl.setSparseSafe((HopRewriteUtils.isBinary(hop, OpOp2.MULT) && hop.getInput().contains(sinHops.get(0)))
- || (HopRewriteUtils.isBinary(hop, OpOp2.DIV) && hop.getInput().get(0) == sinHops.get(0)));
- tpl.setRequiresCastDtm(hop instanceof AggBinaryOp);
-
- // return cplan instance
- return new Pair<Hop[],CNodeTpl>(sinHops.toArray(new Hop[0]), tpl);
- }
-
- private void rConstructCplan(Hop hop, CPlanMemoTable memo, HashMap<Long, CNode> tmp, HashSet<Hop> inHops, boolean compileLiterals)
- {
- //recursively process required childs
- MemoTableEntry me = memo.getBest(hop.getHopID(), TemplateType.CellTpl);
- for( int i=0; i<hop.getInput().size(); i++ ) {
- Hop c = hop.getInput().get(i);
- if( me.isPlanRef(i) )
- rConstructCplan(c, memo, tmp, inHops, compileLiterals);
- else {
- CNodeData cdata = TemplateUtils.createCNodeData(c, compileLiterals);
- tmp.put(c.getHopID(), cdata);
- inHops.add(c);
- }
- }
-
- //construct cnode for current hop
- CNode out = null;
- if(hop instanceof UnaryOp)
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- if( TemplateUtils.isColVector(cdata1) )
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
- else if( cdata1 instanceof CNodeData && hop.getInput().get(0).getDataType().isMatrix() )
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_RC);
-
- String primitiveOpName = ((UnaryOp)hop).getOp().toString();
- out = new CNodeUnary(cdata1, UnaryType.valueOf(primitiveOpName));
- }
- 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 = bop.getOp().toString();
-
- //cdata1 is vector
- if( TemplateUtils.isColVector(cdata1) )
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
- else if( cdata1 instanceof CNodeData && hop.getInput().get(0).getDataType().isMatrix() )
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_RC);
-
- //cdata2 is vector
- if( TemplateUtils.isColVector(cdata2) )
- cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
- else if( cdata2 instanceof CNodeData && hop.getInput().get(1).getDataType().isMatrix() )
- cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_RC);
-
- 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));
- }
- else if(hop instanceof TernaryOp)
- {
- TernaryOp top = (TernaryOp) hop;
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
- CNode cdata3 = tmp.get(hop.getInput().get(2).getHopID());
-
- //cdata1 is vector
- if( TemplateUtils.isColVector(cdata1) )
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
- else if( cdata1 instanceof CNodeData && hop.getInput().get(0).getDataType().isMatrix() )
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_RC);
-
- //cdata3 is vector
- if( TemplateUtils.isColVector(cdata3) )
- cdata3 = new CNodeUnary(cdata3, UnaryType.LOOKUP_R);
- else if( cdata3 instanceof CNodeData && hop.getInput().get(2).getDataType().isMatrix() )
- cdata3 = new CNodeUnary(cdata3, UnaryType.LOOKUP_RC);
-
- //construct ternary cnode, primitive operation derived from OpOp3
- out = new CNodeTernary(cdata1, cdata2, cdata3,
- TernaryType.valueOf(top.getOp().toString()));
- }
- else if( hop instanceof IndexingOp )
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- out = new CNodeTernary(cdata1,
- TemplateUtils.createCNodeData(new LiteralOp(hop.getInput().get(0).getDim2()), true),
- TemplateUtils.createCNodeData(hop.getInput().get(4), true),
- TernaryType.LOOKUP_RC1);
- }
- else if( HopRewriteUtils.isTransposeOperation(hop) )
- {
- out = tmp.get(hop.getInput().get(0).getHopID());
- }
- else if( hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getOp() == AggOp.SUM
- && (((AggUnaryOp) hop).getDirection() == Direction.RowCol
- || ((AggUnaryOp) hop).getDirection() == Direction.Row) )
- {
- out = tmp.get(hop.getInput().get(0).getHopID());
- }
- else if( hop instanceof AggBinaryOp ) {
- //guaranteed to be a dot product, so there are two cases:
- //(1) t(X)%*%X -> sum(X^2) and t(X) %*% Y -> sum(X*Y)
- if( HopRewriteUtils.isTransposeOfItself(hop.getInput().get(0), hop.getInput().get(1)) ) {
- CNode cdata1 = tmp.get(hop.getInput().get(1).getHopID());
- out = new CNodeUnary(cdata1, UnaryType.POW2);
- }
- else {
- CNode cdata1 = TemplateUtils.skipTranspose(tmp.get(hop.getInput().get(0).getHopID()),
- hop.getInput().get(0), tmp, compileLiterals);
- if( TemplateUtils.isColVector(cdata1) )
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
- CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
- if( TemplateUtils.isColVector(cdata2) )
- cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
- out = new CNodeBinary(cdata1, cdata2, BinType.MULT);
- }
- }
-
- tmp.put(hop.getHopID(), out);
- }
-
- private static boolean isValidOperation(Hop hop)
- {
- //prepare indicators for binary operations
- boolean isBinaryMatrixScalar = false;
- boolean isBinaryMatrixVector = false;
- boolean isBinaryMatrixMatrixDense = false;
- if( hop instanceof BinaryOp && hop.getDataType().isMatrix() ) {
- Hop left = hop.getInput().get(0);
- Hop right = hop.getInput().get(1);
- DataType ldt = left.getDataType();
- DataType rdt = right.getDataType();
-
- isBinaryMatrixScalar = (ldt.isScalar() || rdt.isScalar());
- isBinaryMatrixVector = hop.dimsKnown()
- && ((ldt.isMatrix() && TemplateUtils.isVectorOrScalar(right) && !TemplateUtils.isBinaryMatrixRowVector(hop))
- || (rdt.isMatrix() && TemplateUtils.isVectorOrScalar(left) && !TemplateUtils.isBinaryMatrixRowVector(hop)) );
- isBinaryMatrixMatrixDense = hop.dimsKnown() && HopRewriteUtils.isEqualSize(left, right)
- && ldt.isMatrix() && rdt.isMatrix() && !HopRewriteUtils.isSparse(left) && !HopRewriteUtils.isSparse(right);
- }
-
- //prepare indicators for ternary operations
- boolean isTernaryVectorScalarVector = false;
- boolean isTernaryMatrixScalarMatrixDense = false;
- if( hop instanceof TernaryOp && hop.getInput().size()==3 && hop.dimsKnown()
- && HopRewriteUtils.checkInputDataTypes(hop, DataType.MATRIX, DataType.SCALAR, DataType.MATRIX)) {
- Hop left = hop.getInput().get(0);
- Hop right = hop.getInput().get(2);
-
- isTernaryVectorScalarVector = TemplateUtils.isVector(left) && TemplateUtils.isVector(right);
- isTernaryMatrixScalarMatrixDense = HopRewriteUtils.isEqualSize(left, right)
- && !HopRewriteUtils.isSparse(left) && !HopRewriteUtils.isSparse(right);
- }
-
- //check supported unary, binary, ternary operations
- return hop.getDataType() == DataType.MATRIX && TemplateUtils.isOperationSupported(hop) && (hop instanceof UnaryOp
- || isBinaryMatrixScalar || isBinaryMatrixVector || isBinaryMatrixMatrixDense
- || isTernaryVectorScalarVector || isTernaryMatrixScalarMatrixDense);
- }
-
- /**
- * Comparator to order input hops of the cell template. We try to order
- * matrices-vectors-scalars via sorting by number of cells and for
- * equal number of cells by sparsity to prefer sparse inputs as the main
- * input for sparsity exploitation.
- */
- public static class HopInputComparator implements Comparator<Hop>
- {
- @Override
- public int compare(Hop h1, Hop h2) {
- long ncells1 = h1.getDataType()==DataType.SCALAR ? Long.MIN_VALUE :
- h1.dimsKnown() ? h1.getDim1()*h1.getDim2() : Long.MAX_VALUE;
- long ncells2 = h2.getDataType()==DataType.SCALAR ? Long.MIN_VALUE :
- h2.dimsKnown() ? h2.getDim1()*h2.getDim2() : Long.MAX_VALUE;
- if( ncells1 > ncells2 )
- return -1;
- else if( ncells1 < ncells2)
- return 1;
- return Long.compare(
- h1.dimsKnown(true) ? h1.getNnz() : ncells1,
- h2.dimsKnown(true) ? h2.getNnz() : ncells2);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/OuterProductTpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/OuterProductTpl.java b/src/main/java/org/apache/sysml/hops/codegen/template/OuterProductTpl.java
deleted file mode 100644
index 3dce155..0000000
--- a/src/main/java/org/apache/sysml/hops/codegen/template/OuterProductTpl.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * 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 java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-
-import org.apache.sysml.hops.AggBinaryOp;
-import org.apache.sysml.hops.AggUnaryOp;
-import org.apache.sysml.hops.BinaryOp;
-import org.apache.sysml.hops.DataOp;
-import org.apache.sysml.hops.Hop;
-import org.apache.sysml.hops.UnaryOp;
-import org.apache.sysml.hops.Hop.AggOp;
-import org.apache.sysml.hops.Hop.Direction;
-import org.apache.sysml.hops.Hop.OpOp2;
-import org.apache.sysml.hops.codegen.cplan.CNode;
-import org.apache.sysml.hops.codegen.cplan.CNodeBinary;
-import org.apache.sysml.hops.codegen.cplan.CNodeBinary.BinType;
-import org.apache.sysml.hops.codegen.cplan.CNodeUnary;
-import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType;
-import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry;
-import org.apache.sysml.hops.codegen.cplan.CNodeData;
-import org.apache.sysml.hops.codegen.cplan.CNodeOuterProduct;
-import org.apache.sysml.hops.codegen.cplan.CNodeTpl;
-import org.apache.sysml.hops.rewrite.HopRewriteUtils;
-import org.apache.sysml.runtime.codegen.SpoofOuterProduct.OutProdType;
-import org.apache.sysml.runtime.matrix.data.Pair;
-
-public class OuterProductTpl extends BaseTpl {
-
- public OuterProductTpl() {
- super(TemplateType.OuterProdTpl);
- }
-
- @Override
- public boolean open(Hop hop) {
- //open on outer product like matrix mult (output larger than common dim)
- return HopRewriteUtils.isOuterProductLikeMM(hop)
- && hop.getDim1()>256 && hop.getDim2() > 256;
- }
-
- @Override
- public boolean fuse(Hop hop, Hop input) {
- return !isClosed()
- &&((hop instanceof UnaryOp && TemplateUtils.isOperationSupported(hop))
- || (hop instanceof BinaryOp && TemplateUtils.isOperationSupported(hop)
- && (TemplateUtils.isBinaryMatrixColVector(hop) || HopRewriteUtils.isBinaryMatrixScalarOperation(hop)
- || (HopRewriteUtils.isBinaryMatrixMatrixOperation(hop) && HopRewriteUtils.isBinary(hop, OpOp2.MULT, OpOp2.DIV)) ))
- || HopRewriteUtils.isTransposeOperation(hop)
- || (hop instanceof AggBinaryOp && !HopRewriteUtils.isOuterProductLikeMM(hop))
- || (hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getDirection()==Direction.RowCol));
- }
-
- @Override
- public boolean merge(Hop hop, Hop input) {
- return !isClosed() &&
- (TemplateUtils.isBinaryMatrixRowVector(hop)
- || HopRewriteUtils.isBinaryMatrixScalarOperation(hop));
- }
-
- @Override
- public CloseType close(Hop hop) {
- // close on second matrix multiply (after open) or unary aggregate
- if( hop instanceof AggUnaryOp && HopRewriteUtils.isOuterProductLikeMM(hop.getInput().get(0)) )
- return CloseType.CLOSED_INVALID;
- else if( (hop instanceof AggUnaryOp)
- || (hop instanceof AggBinaryOp && !HopRewriteUtils.isOuterProductLikeMM(hop)
- && !HopRewriteUtils.isTransposeOperation(hop.getParent().get(0)))
- || (HopRewriteUtils.isTransposeOperation(hop) && hop.getInput().get(0) instanceof AggBinaryOp
- && !HopRewriteUtils.isOuterProductLikeMM(hop.getInput().get(0)) ))
- return CloseType.CLOSED_VALID;
- else
- return CloseType.OPEN;
- }
-
- public Pair<Hop[], CNodeTpl> constructCplan(Hop hop, CPlanMemoTable memo, boolean compileLiterals)
- {
- //recursively process required cplan output
- HashSet<Hop> inHops = new HashSet<Hop>();
- HashMap<String,Hop> inHops2 = new HashMap<String, Hop>();
- HashMap<Long, CNode> tmp = new HashMap<Long, CNode>();
- hop.resetVisitStatus();
- rConstructCplan(hop, memo, tmp, inHops, inHops2, compileLiterals);
- hop.resetVisitStatus();
-
- //reorder inputs (ensure matrix is first input)
- Hop X = inHops2.get("_X");
- Hop U = inHops2.get("_U");
- Hop V = inHops2.get("_V");
- LinkedList<Hop> sinHops = new LinkedList<Hop>(inHops);
- sinHops.remove(V); sinHops.addFirst(V);
- sinHops.remove(U); sinHops.addFirst(U);
- sinHops.remove(X); sinHops.addFirst(X);
-
- //construct template node
- ArrayList<CNode> inputs = new ArrayList<CNode>();
- for( Hop in : sinHops )
- if( in != null )
- inputs.add(tmp.get(in.getHopID()));
-
- CNode output = tmp.get(hop.getHopID());
- CNodeOuterProduct tpl = new CNodeOuterProduct(inputs, output);
- tpl.setOutProdType(TemplateUtils.getOuterProductType(X, U, V, hop));
- tpl.setTransposeOutput(!HopRewriteUtils.isTransposeOperation(hop)
- && tpl.getOutProdType()==OutProdType.LEFT_OUTER_PRODUCT);
-
- return new Pair<Hop[],CNodeTpl>(sinHops.toArray(new Hop[0]), tpl);
- }
-
- private void rConstructCplan(Hop hop, CPlanMemoTable memo, HashMap<Long, CNode> tmp, HashSet<Hop> inHops, HashMap<String, Hop> inHops2, boolean compileLiterals)
- {
- //recursively process required childs
- MemoTableEntry me = memo.getBest(hop.getHopID(), TemplateType.OuterProdTpl);
- for( int i=0; i<hop.getInput().size(); i++ ) {
- Hop c = hop.getInput().get(i);
- if( me.isPlanRef(i) )
- rConstructCplan(c, memo, tmp, inHops, inHops2, compileLiterals);
- else {
- CNodeData cdata = TemplateUtils.createCNodeData(c, compileLiterals);
- tmp.put(c.getHopID(), cdata);
- inHops.add(c);
- }
- }
-
- //construct cnode for current hop
- CNode out = null;
- if(hop instanceof UnaryOp)
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- String primitiveOpName = ((UnaryOp)hop).getOp().toString();
- out = new CNodeUnary(cdata1, UnaryType.valueOf(primitiveOpName));
- }
- else if(hop instanceof BinaryOp)
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
- String primitiveOpName = ((BinaryOp)hop).getOp().toString();
-
- if( (cdata1.getNumRows() > 1 && cdata1.getNumCols() == 1) || (cdata1.getNumRows() == 1 && cdata1.getNumCols() > 1) ) {
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
- }
- if( (cdata2.getNumRows() > 1 && cdata2.getNumCols() == 1) || (cdata2.getNumRows() == 1 && cdata2.getNumCols() > 1) ) {
- cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
- }
-
- if( HopRewriteUtils.isEqualSize(hop.getInput().get(0), hop.getInput().get(1))
- && hop.getInput().get(0) instanceof DataOp )
- inHops2.put("_X", hop.getInput().get(0));
-
- out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(primitiveOpName));
- }
- else if(hop instanceof AggBinaryOp)
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
-
- //handle tanspose in outer or final product
- cdata1 = TemplateUtils.skipTranspose(cdata1, hop.getInput().get(0), tmp, compileLiterals);
- cdata2 = TemplateUtils.skipTranspose(cdata2, hop.getInput().get(1), tmp, compileLiterals);
-
- //outerproduct U%*%t(V), see open
- if( HopRewriteUtils.isOuterProductLikeMM(hop) )
- {
- //keep U and V for later reference
- inHops2.put("_U", hop.getInput().get(0));
- if( HopRewriteUtils.isTransposeOperation(hop.getInput().get(1)) )
- inHops2.put("_V", hop.getInput().get(1).getInput().get(0));
- else
- inHops2.put("_V", hop.getInput().get(1));
-
- out = new CNodeBinary(cdata1, cdata2, BinType.DOT_PRODUCT);
- }
- //final left/right matrix mult, see close
- else {
- if( cdata1.getDataType().isScalar() )
- out = new CNodeBinary(cdata1, cdata2, BinType.VECT_MULT_ADD);
- else
- out = new CNodeBinary(cdata2, cdata1, BinType.VECT_MULT_ADD);
- }
- }
- else if( HopRewriteUtils.isTransposeOperation(hop) )
- {
- out = tmp.get(hop.getInput().get(0).getHopID());
- }
- else if( hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getOp() == AggOp.SUM
- && ((AggUnaryOp)hop).getDirection() == Direction.RowCol )
- {
- out = tmp.get(hop.getInput().get(0).getHopID());
- }
-
- tmp.put(hop.getHopID(), out);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelection.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelection.java b/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelection.java
new file mode 100644
index 0000000..e7bc554
--- /dev/null
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelection.java
@@ -0,0 +1,73 @@
+/*
+ * 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 java.util.Comparator;
+
+import org.apache.sysml.hops.Hop;
+import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry;
+import org.apache.sysml.hops.codegen.template.TemplateBase.TemplateType;
+import org.apache.sysml.hops.rewrite.HopRewriteUtils;
+
+public abstract class PlanSelection
+{
+ /**
+ * Given a HOP DAG G, and a set of partial fusions plans P, find the set of optimal,
+ * non-conflicting fusion plans P' that applied to G minimizes costs C with
+ * P' = \argmin_{p \subseteq P} C(G, p) s.t. Z \vDash p, where Z is a set of
+ * constraints such as memory budgets and block size restrictions per fused operator.
+ *
+ * @param memo partial fusion plans P
+ * @param roots entry points of HOP DAG G
+ */
+ public abstract void selectPlans(CPlanMemoTable memo, ArrayList<Hop> roots);
+
+ /**
+ * Determines if the given partial fusion plan is valid.
+ *
+ * @param me memo table entry
+ * @param hop current hop
+ * @return true if entry is valid as top-level plan
+ */
+ protected static boolean isValid(MemoTableEntry me, Hop hop) {
+ return (me.type == TemplateType.OuterProdTpl
+ && (me.closed || HopRewriteUtils.isBinaryMatrixMatrixOperation(hop)))
+ || (me.type == TemplateType.RowAggTpl && me.closed)
+ || (me.type == TemplateType.CellTpl);
+ }
+
+ /**
+ * Basic plan comparator to compare memo table entries with regard to
+ * a pre-defined template preference order and the number of references.
+ */
+ protected class BasicPlanComparator implements Comparator<MemoTableEntry> {
+ @Override
+ public int compare(MemoTableEntry o1, MemoTableEntry o2) {
+ //for different types, select preferred type
+ if( o1.type != o2.type )
+ return Integer.compare(o1.type.getRank(), o2.type.getRank());
+
+ //for same type, prefer plan with more refs
+ return Integer.compare(
+ 3-o1.countPlanRefs(), 3-o2.countPlanRefs());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelectionFuseAll.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelectionFuseAll.java b/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelectionFuseAll.java
new file mode 100644
index 0000000..e615f0b
--- /dev/null
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/PlanSelectionFuseAll.java
@@ -0,0 +1,85 @@
+/*
+ * 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 java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.sysml.hops.Hop;
+import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry;
+import org.apache.sysml.hops.codegen.template.TemplateBase.TemplateType;
+
+
+public class PlanSelectionFuseAll extends PlanSelection
+{
+ private HashMap<Long, List<MemoTableEntry>> _bestPlans =
+ new HashMap<Long, List<MemoTableEntry>>();
+
+ @Override
+ public void selectPlans(CPlanMemoTable memo, ArrayList<Hop> roots) {
+ //pruning and collection pass
+ for( Hop hop : roots )
+ rSelectPlans(memo, hop, null);
+
+ //take all distinct best plans
+ for( Entry<Long, List<MemoTableEntry>> e : _bestPlans.entrySet() )
+ memo.setDistinct(e.getKey(), e.getValue());
+ }
+
+ private void rSelectPlans(CPlanMemoTable memo, Hop current, TemplateType currentType)
+ {
+ //step 1: prune subsumed plans of same type
+ if( memo.contains(current.getHopID()) ) {
+ HashSet<MemoTableEntry> rmSet = new HashSet<MemoTableEntry>();
+ List<MemoTableEntry> hopP = memo.get(current.getHopID());
+ for( MemoTableEntry e1 : hopP )
+ for( MemoTableEntry e2 : hopP )
+ if( e1 != e2 && e1.subsumes(e2) )
+ rmSet.add(e2);
+ memo.remove(current, rmSet);
+ }
+
+ //step 2: select plan for current path
+ MemoTableEntry best = null;
+ if( memo.contains(current.getHopID()) ) {
+ if( currentType == null ) {
+ best = memo.get(current.getHopID()).stream()
+ .filter(p -> isValid(p, current))
+ .min(new BasicPlanComparator()).orElse(null);
+ }
+ else {
+
+ best = memo.get(current.getHopID()).stream()
+ .filter(p -> p.type==currentType || p.type==TemplateType.CellTpl)
+ .min(Comparator.comparing(p -> 3-p.countPlanRefs())).orElse(null);
+ }
+ }
+
+ //step 3: recursively process children
+ for( int i=0; i< current.getInput().size(); i++ ) {
+ TemplateType pref = (best!=null && best.isPlanRef(i))? best.type : null;
+ rSelectPlans(memo, current.getInput().get(i), pref);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/RowAggTpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/RowAggTpl.java b/src/main/java/org/apache/sysml/hops/codegen/template/RowAggTpl.java
deleted file mode 100644
index c16c831..0000000
--- a/src/main/java/org/apache/sysml/hops/codegen/template/RowAggTpl.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * 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 java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.apache.sysml.hops.AggBinaryOp;
-import org.apache.sysml.hops.AggUnaryOp;
-import org.apache.sysml.hops.BinaryOp;
-import org.apache.sysml.hops.Hop;
-import org.apache.sysml.hops.IndexingOp;
-import org.apache.sysml.hops.LiteralOp;
-import org.apache.sysml.hops.codegen.cplan.CNode;
-import org.apache.sysml.hops.codegen.cplan.CNodeBinary;
-import org.apache.sysml.hops.codegen.cplan.CNodeBinary.BinType;
-import org.apache.sysml.hops.codegen.cplan.CNodeTernary.TernaryType;
-import org.apache.sysml.hops.codegen.cplan.CNodeData;
-import org.apache.sysml.hops.codegen.cplan.CNodeRowAgg;
-import org.apache.sysml.hops.codegen.cplan.CNodeTernary;
-import org.apache.sysml.hops.codegen.cplan.CNodeTpl;
-import org.apache.sysml.hops.codegen.cplan.CNodeUnary;
-import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType;
-import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry;
-import org.apache.sysml.hops.rewrite.HopRewriteUtils;
-import org.apache.sysml.hops.Hop.AggOp;
-import org.apache.sysml.hops.Hop.Direction;
-import org.apache.sysml.hops.Hop.OpOp2;
-import org.apache.sysml.parser.Expression.DataType;
-import org.apache.sysml.runtime.matrix.data.Pair;
-
-public class RowAggTpl extends BaseTpl {
-
- public RowAggTpl() {
- super(TemplateType.RowAggTpl);
- }
-
- @Override
- public boolean open(Hop hop) {
- //any unary or binary aggregate operation with a vector output, but exclude binary aggregate
- //with transposed input to avoid counter-productive fusion
- return ( ((hop instanceof AggBinaryOp && hop.getInput().get(1).getDim1()>1
- && !HopRewriteUtils.isTransposeOperation(hop.getInput().get(0)))
- || (hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getOp()==AggOp.SUM ))
- && ( (hop.getDim1()==1 && hop.getDim2()!=1) || (hop.getDim1()!=1 && hop.getDim2()==1) ) );
- }
-
- @Override
- public boolean fuse(Hop hop, Hop input) {
- return !isClosed() &&
- ( (hop instanceof BinaryOp && (HopRewriteUtils.isBinaryMatrixColVectorOperation(hop)
- || HopRewriteUtils.isBinaryMatrixScalarOperation(hop)))
- || (hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getDirection()==Direction.Col)
- || (hop instanceof AggBinaryOp && HopRewriteUtils.isTransposeOperation(hop.getInput().get(0))));
- }
-
- @Override
- public boolean merge(Hop hop, Hop input) {
- //merge rowagg tpl with cell tpl if input is a vector
- return !isClosed() &&
- (hop instanceof BinaryOp && input.getDim2()==1 ); //matrix-scalar/vector-vector ops )
- }
-
- @Override
- public CloseType close(Hop hop) {
- //close on column aggregate (e.g., colSums, t(X)%*%y)
- if( hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getDirection()==Direction.Col
- || (hop instanceof AggBinaryOp && HopRewriteUtils.isTransposeOperation(hop.getInput().get(0))) )
- return CloseType.CLOSED_VALID;
- else
- return CloseType.OPEN;
- }
-
- @Override
- public Pair<Hop[], CNodeTpl> constructCplan(Hop hop, CPlanMemoTable memo, boolean compileLiterals) {
- //recursively process required cplan output
- HashSet<Hop> inHops = new HashSet<Hop>();
- HashMap<String, Hop> inHops2 = new HashMap<String,Hop>();
- HashMap<Long, CNode> tmp = new HashMap<Long, CNode>();
- hop.resetVisitStatus();
- rConstructCplan(hop, memo, tmp, inHops, inHops2, compileLiterals);
- hop.resetVisitStatus();
-
- //reorder inputs (ensure matrix is first input, and other inputs ordered by size)
- List<Hop> sinHops = inHops.stream()
- .filter(h -> !(h.getDataType().isScalar() && tmp.get(h.getHopID()).isLiteral()))
- .sorted(new HopInputComparator(inHops2.get("X"))).collect(Collectors.toList());
-
- //construct template node
- ArrayList<CNode> inputs = new ArrayList<CNode>();
- for( Hop in : sinHops )
- inputs.add(tmp.get(in.getHopID()));
- CNode output = tmp.get(hop.getHopID());
- CNodeRowAgg tpl = new CNodeRowAgg(inputs, output);
-
- // return cplan instance
- return new Pair<Hop[],CNodeTpl>(sinHops.toArray(new Hop[0]), tpl);
- }
-
- private void rConstructCplan(Hop hop, CPlanMemoTable memo, HashMap<Long, CNode> tmp, HashSet<Hop> inHops, HashMap<String, Hop> inHops2, boolean compileLiterals)
- {
- //recursively process required childs
- MemoTableEntry me = memo.getBest(hop.getHopID(), TemplateType.RowAggTpl);
- for( int i=0; i<hop.getInput().size(); i++ ) {
- Hop c = hop.getInput().get(i);
- if( me.isPlanRef(i) )
- rConstructCplan(c, memo, tmp, inHops, inHops2, compileLiterals);
- else {
- CNodeData cdata = TemplateUtils.createCNodeData(c, compileLiterals);
- tmp.put(c.getHopID(), cdata);
- inHops.add(c);
- }
- }
-
- //construct cnode for current hop
- CNode out = null;
- if(hop instanceof AggUnaryOp)
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- if( ((AggUnaryOp)hop).getDirection() == Direction.Row && ((AggUnaryOp)hop).getOp() == AggOp.SUM ) {
- if(hop.getInput().get(0).getDim2()==1)
- out = (cdata1.getDataType()==DataType.SCALAR) ? cdata1 : new CNodeUnary(cdata1,UnaryType.LOOKUP_R);
- else {
- out = new CNodeUnary(cdata1, UnaryType.ROW_SUMS);
- inHops2.put("X", hop.getInput().get(0));
- }
- }
- else if (((AggUnaryOp)hop).getDirection() == Direction.Col && ((AggUnaryOp)hop).getOp() == AggOp.SUM ) {
- //vector div add without temporary copy
- if(cdata1 instanceof CNodeBinary && ((CNodeBinary)cdata1).getType()==BinType.VECT_DIV_SCALAR)
- out = new CNodeBinary(cdata1.getInput().get(0), cdata1.getInput().get(1), BinType.VECT_DIV_ADD);
- else
- out = cdata1;
- }
- }
- else if(hop instanceof AggBinaryOp)
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
-
- if( HopRewriteUtils.isTransposeOperation(hop.getInput().get(0)) )
- {
- //correct input under transpose
- cdata1 = TemplateUtils.skipTranspose(cdata1, hop.getInput().get(0), tmp, compileLiterals);
- inHops.remove(hop.getInput().get(0));
- inHops.add(hop.getInput().get(0).getInput().get(0));
-
- out = new CNodeBinary(cdata2, cdata1, BinType.VECT_MULT_ADD);
- }
- else
- {
- if(hop.getInput().get(0).getDim2()==1 && hop.getInput().get(1).getDim2()==1)
- out = new CNodeBinary((cdata1.getDataType()==DataType.SCALAR)? cdata1 : new CNodeUnary(cdata1, UnaryType.LOOKUP0),
- (cdata2.getDataType()==DataType.SCALAR)? cdata2 : new CNodeUnary(cdata2, UnaryType.LOOKUP0), BinType.MULT);
- else {
- out = new CNodeBinary(cdata1, cdata2, BinType.DOT_PRODUCT);
- inHops2.put("X", hop.getInput().get(0));
- }
- }
- }
- else if(hop instanceof BinaryOp)
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
-
- // if one input is a matrix then we need to do vector by scalar operations
- if(hop.getInput().get(0).getDim1() > 1 && hop.getInput().get(0).getDim2() > 1 )
- {
- if (((BinaryOp)hop).getOp()== OpOp2.DIV)
- out = new CNodeBinary(cdata1, cdata2, BinType.VECT_DIV_SCALAR);
- }
- else //one input is a vector/scalar other is a scalar
- {
- String primitiveOpName = ((BinaryOp)hop).getOp().toString();
- if( (cdata1.getNumRows() > 1 && cdata1.getNumCols() == 1) || (cdata1.getNumRows() == 1 && cdata1.getNumCols() > 1) ) {
- cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
- }
- if( (cdata2.getNumRows() > 1 && cdata2.getNumCols() == 1) || (cdata2.getNumRows() == 1 && cdata2.getNumCols() > 1) ) {
- cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
- }
- out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(primitiveOpName));
- }
- }
- else if( hop instanceof IndexingOp )
- {
- CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
- out = new CNodeTernary(cdata1,
- TemplateUtils.createCNodeData(new LiteralOp(hop.getInput().get(0).getDim2()), true),
- TemplateUtils.createCNodeData(hop.getInput().get(4), true),
- TernaryType.LOOKUP_RC1);
- }
-
- if( out.getDataType().isMatrix() ) {
- out.setNumRows(hop.getDim1());
- out.setNumCols(hop.getDim2());
- }
-
- tmp.put(hop.getHopID(), out);
- }
-
- /**
- * Comparator to order input hops of the row aggregate template. We try
- * to order matrices-vectors-scalars via sorting by number of cells but
- * we keep the given main input always at the first position.
- */
- public static class HopInputComparator implements Comparator<Hop>
- {
- private final Hop _X;
-
- public HopInputComparator(Hop X) {
- _X = X;
- }
-
- @Override
- public int compare(Hop h1, Hop h2) {
- long ncells1 = h1.getDataType()==DataType.SCALAR ? Long.MIN_VALUE :
- (h1==_X) ? Long.MAX_VALUE :
- h1.dimsKnown() ? h1.getDim1()*h1.getDim2() : Long.MAX_VALUE-1;
- long ncells2 = h2.getDataType()==DataType.SCALAR ? Long.MIN_VALUE :
- (h2==_X) ? Long.MAX_VALUE :
- h2.dimsKnown() ? h2.getDim1()*h2.getDim2() : Long.MAX_VALUE-1;
- return (ncells1 > ncells2) ? -1 : (ncells1 < ncells2) ? 1 : 0;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/src/main/java/org/apache/sysml/hops/codegen/template/TemplateBase.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateBase.java b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateBase.java
new file mode 100644
index 0000000..1c5ea56
--- /dev/null
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateBase.java
@@ -0,0 +1,129 @@
+/*
+ * 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 org.apache.sysml.hops.Hop;
+import org.apache.sysml.hops.codegen.cplan.CNodeTpl;
+import org.apache.sysml.runtime.matrix.data.Pair;
+
+public abstract class TemplateBase
+{
+ public enum TemplateType {
+ RowAggTpl,
+ OuterProdTpl,
+ CellTpl;
+
+ //rank in preferred order
+ public int getRank() {
+ return this.ordinal();
+ }
+ }
+
+ public enum CloseType {
+ CLOSED_VALID,
+ CLOSED_INVALID,
+ OPEN,
+ }
+
+ protected TemplateType _type = null;
+ protected boolean _closed = false;
+
+ protected TemplateBase(TemplateType type) {
+ _type = type;
+ _closed = false;
+ }
+
+ public TemplateType getType() {
+ return _type;
+ }
+
+ public boolean isClosed() {
+ return _closed;
+ }
+
+ /////////////////////////////////////////////
+ // Open-Fuse-Merge-Close interface
+ // (for candidate generation and exploration)
+
+ /**
+ * Indicates if this template can be opened at the given hop,
+ * where hop represents bottom (first operation on the inputs)
+ * of the fused operator.
+ *
+ * @param hop current hop
+ * @return true if template can be opened
+ */
+ public abstract boolean open(Hop hop);
+
+ /**
+ * Indicates if the template can be expanded to the given hop
+ * starting from an open template at the input.
+ *
+ * @param hop current hop
+ * @param input hop with open template of same type
+ * @return true if the current hop can be fused into the operator.
+ */
+ public abstract boolean fuse(Hop hop, Hop input);
+
+ /**
+ * Indicates if the template at the current hop can be expanded
+ * by merging another template available for one of its other inputs
+ * which is not yet covered by the template of the current hop.
+ *
+ * @param hop current hop
+ * @param input direct input of current hop with available template
+ * @return true if the the input hop can be fused into the current hop
+ */
+ public abstract boolean merge(Hop hop, Hop input);
+
+ /**
+ * Indicates if the template must be closed at the current hop; either
+ * due to final operations (e.g., aggregate) or unsupported operations.
+ *
+ * @param hop current hop
+ * @return close type (closed invalid, closed valid, open)
+ */
+ public abstract CloseType close(Hop hop);
+
+ /**
+ * Mark the template as closed either invalid or valid.
+ */
+ public void close() {
+ _closed = true;
+ }
+
+ /////////////////////////////////////////////
+ // CPlan construction interface
+ // (for plan creation of selected candidates)
+
+ /**
+ * Constructs a single cplan rooted at the given hop, according
+ * to the plan given in the memo structure for this particular
+ * hop and its recursive inputs.
+ *
+ * @param hop root of cplan
+ * @param memo memoization table for partial subplans
+ * @param compileLiterals if true compile non-integer literals
+ * as constants, otherwise variables. note: integer literals are
+ * always compiled as constants.
+ * @return
+ */
+ public abstract Pair<Hop[], CNodeTpl> constructCplan(Hop hop, CPlanMemoTable memo, boolean compileLiterals);
+}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/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
new file mode 100644
index 0000000..da74db2
--- /dev/null
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateCell.java
@@ -0,0 +1,304 @@
+/*
+ * 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 java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.sysml.hops.AggBinaryOp;
+import org.apache.sysml.hops.AggUnaryOp;
+import org.apache.sysml.hops.BinaryOp;
+import org.apache.sysml.hops.Hop;
+import org.apache.sysml.hops.UnaryOp;
+import org.apache.sysml.hops.Hop.AggOp;
+import org.apache.sysml.hops.Hop.Direction;
+import org.apache.sysml.hops.Hop.OpOp2;
+import org.apache.sysml.hops.IndexingOp;
+import org.apache.sysml.hops.LiteralOp;
+import org.apache.sysml.hops.TernaryOp;
+import org.apache.sysml.hops.codegen.cplan.CNode;
+import org.apache.sysml.hops.codegen.cplan.CNodeBinary;
+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.CNodeTpl;
+import org.apache.sysml.hops.codegen.cplan.CNodeUnary;
+import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType;
+import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry;
+import org.apache.sysml.hops.codegen.cplan.CNodeTernary;
+import org.apache.sysml.hops.codegen.cplan.CNodeTernary.TernaryType;
+import org.apache.sysml.hops.rewrite.HopRewriteUtils;
+import org.apache.sysml.parser.Expression.DataType;
+import org.apache.sysml.runtime.matrix.data.Pair;
+
+public class TemplateCell extends TemplateBase
+{
+ public TemplateCell() {
+ super(TemplateType.CellTpl);
+ }
+
+ @Override
+ public boolean open(Hop hop) {
+ return isValidOperation(hop)
+ || (hop instanceof IndexingOp && ((IndexingOp)hop).isColLowerEqualsUpper());
+ }
+
+ @Override
+ public boolean fuse(Hop hop, Hop input) {
+ return !isClosed() && (isValidOperation(hop)
+ || (HopRewriteUtils.isSum(hop) && ((AggUnaryOp) hop).getDirection()!= Direction.Col)
+ || (HopRewriteUtils.isMatrixMultiply(hop) && hop.getDim1()==1 && hop.getDim2()==1)
+ && HopRewriteUtils.isTransposeOperation(hop.getInput().get(0)));
+ }
+
+ @Override
+ public boolean merge(Hop hop, Hop input) {
+ //merge of other cell tpl possible
+ return (!isClosed() && isValidOperation(hop));
+ }
+
+ @Override
+ public CloseType close(Hop hop) {
+ //need to close cell tpl after aggregation, see fuse for exact properties
+ if( (HopRewriteUtils.isSum(hop) && ((AggUnaryOp) hop).getDirection()!= Direction.Col)
+ || (HopRewriteUtils.isMatrixMultiply(hop) && hop.getDim1()==1 && hop.getDim2()==1) )
+ return CloseType.CLOSED_VALID;
+ else if( hop instanceof AggUnaryOp || hop instanceof AggBinaryOp )
+ return CloseType.CLOSED_INVALID;
+ else
+ return CloseType.OPEN;
+ }
+
+ @Override
+ public Pair<Hop[], CNodeTpl> constructCplan(Hop hop, CPlanMemoTable memo, boolean compileLiterals)
+ {
+ //recursively process required cplan output
+ HashSet<Hop> inHops = new HashSet<Hop>();
+ HashMap<Long, CNode> tmp = new HashMap<Long, CNode>();
+ hop.resetVisitStatus();
+ rConstructCplan(hop, memo, tmp, inHops, compileLiterals);
+ hop.resetVisitStatus();
+
+ //reorder inputs (ensure matrices/vectors come first) and prune literals
+ //note: we order by number of cells and subsequently sparsity to ensure
+ //that sparse inputs are used as the main input w/o unnecessary conversion
+ List<Hop> sinHops = inHops.stream()
+ .filter(h -> !(h.getDataType().isScalar() && tmp.get(h.getHopID()).isLiteral()))
+ .sorted(new HopInputComparator()).collect(Collectors.toList());
+
+ //construct template node
+ ArrayList<CNode> inputs = new ArrayList<CNode>();
+ for( Hop in : sinHops )
+ inputs.add(tmp.get(in.getHopID()));
+ CNode output = tmp.get(hop.getHopID());
+ CNodeCell tpl = new CNodeCell(inputs, output);
+ tpl.setCellType(TemplateUtils.getCellType(hop));
+ tpl.setSparseSafe((HopRewriteUtils.isBinary(hop, OpOp2.MULT) && hop.getInput().contains(sinHops.get(0)))
+ || (HopRewriteUtils.isBinary(hop, OpOp2.DIV) && hop.getInput().get(0) == sinHops.get(0)));
+ tpl.setRequiresCastDtm(hop instanceof AggBinaryOp);
+
+ // return cplan instance
+ return new Pair<Hop[],CNodeTpl>(sinHops.toArray(new Hop[0]), tpl);
+ }
+
+ private void rConstructCplan(Hop hop, CPlanMemoTable memo, HashMap<Long, CNode> tmp, HashSet<Hop> inHops, boolean compileLiterals)
+ {
+ //recursively process required childs
+ MemoTableEntry me = memo.getBest(hop.getHopID(), TemplateType.CellTpl);
+ for( int i=0; i<hop.getInput().size(); i++ ) {
+ Hop c = hop.getInput().get(i);
+ if( me.isPlanRef(i) )
+ rConstructCplan(c, memo, tmp, inHops, compileLiterals);
+ else {
+ CNodeData cdata = TemplateUtils.createCNodeData(c, compileLiterals);
+ tmp.put(c.getHopID(), cdata);
+ inHops.add(c);
+ }
+ }
+
+ //construct cnode for current hop
+ CNode out = null;
+ if(hop instanceof UnaryOp)
+ {
+ CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
+ if( TemplateUtils.isColVector(cdata1) )
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
+ else if( cdata1 instanceof CNodeData && hop.getInput().get(0).getDataType().isMatrix() )
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_RC);
+
+ String primitiveOpName = ((UnaryOp)hop).getOp().toString();
+ out = new CNodeUnary(cdata1, UnaryType.valueOf(primitiveOpName));
+ }
+ 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 = bop.getOp().toString();
+
+ //cdata1 is vector
+ if( TemplateUtils.isColVector(cdata1) )
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
+ else if( cdata1 instanceof CNodeData && hop.getInput().get(0).getDataType().isMatrix() )
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_RC);
+
+ //cdata2 is vector
+ if( TemplateUtils.isColVector(cdata2) )
+ cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
+ else if( cdata2 instanceof CNodeData && hop.getInput().get(1).getDataType().isMatrix() )
+ cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_RC);
+
+ 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));
+ }
+ else if(hop instanceof TernaryOp)
+ {
+ TernaryOp top = (TernaryOp) hop;
+ CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
+ CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
+ CNode cdata3 = tmp.get(hop.getInput().get(2).getHopID());
+
+ //cdata1 is vector
+ if( TemplateUtils.isColVector(cdata1) )
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
+ else if( cdata1 instanceof CNodeData && hop.getInput().get(0).getDataType().isMatrix() )
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_RC);
+
+ //cdata3 is vector
+ if( TemplateUtils.isColVector(cdata3) )
+ cdata3 = new CNodeUnary(cdata3, UnaryType.LOOKUP_R);
+ else if( cdata3 instanceof CNodeData && hop.getInput().get(2).getDataType().isMatrix() )
+ cdata3 = new CNodeUnary(cdata3, UnaryType.LOOKUP_RC);
+
+ //construct ternary cnode, primitive operation derived from OpOp3
+ out = new CNodeTernary(cdata1, cdata2, cdata3,
+ TernaryType.valueOf(top.getOp().toString()));
+ }
+ else if( hop instanceof IndexingOp )
+ {
+ CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
+ out = new CNodeTernary(cdata1,
+ TemplateUtils.createCNodeData(new LiteralOp(hop.getInput().get(0).getDim2()), true),
+ TemplateUtils.createCNodeData(hop.getInput().get(4), true),
+ TernaryType.LOOKUP_RC1);
+ }
+ else if( HopRewriteUtils.isTransposeOperation(hop) )
+ {
+ out = tmp.get(hop.getInput().get(0).getHopID());
+ }
+ else if( hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getOp() == AggOp.SUM
+ && (((AggUnaryOp) hop).getDirection() == Direction.RowCol
+ || ((AggUnaryOp) hop).getDirection() == Direction.Row) )
+ {
+ out = tmp.get(hop.getInput().get(0).getHopID());
+ }
+ else if( hop instanceof AggBinaryOp ) {
+ //guaranteed to be a dot product, so there are two cases:
+ //(1) t(X)%*%X -> sum(X^2) and t(X) %*% Y -> sum(X*Y)
+ if( HopRewriteUtils.isTransposeOfItself(hop.getInput().get(0), hop.getInput().get(1)) ) {
+ CNode cdata1 = tmp.get(hop.getInput().get(1).getHopID());
+ out = new CNodeUnary(cdata1, UnaryType.POW2);
+ }
+ else {
+ CNode cdata1 = TemplateUtils.skipTranspose(tmp.get(hop.getInput().get(0).getHopID()),
+ hop.getInput().get(0), tmp, compileLiterals);
+ if( TemplateUtils.isColVector(cdata1) )
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
+ CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
+ if( TemplateUtils.isColVector(cdata2) )
+ cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
+ out = new CNodeBinary(cdata1, cdata2, BinType.MULT);
+ }
+ }
+
+ tmp.put(hop.getHopID(), out);
+ }
+
+ public static boolean isValidOperation(Hop hop)
+ {
+ //prepare indicators for binary operations
+ boolean isBinaryMatrixScalar = false;
+ boolean isBinaryMatrixVector = false;
+ boolean isBinaryMatrixMatrixDense = false;
+ if( hop instanceof BinaryOp && hop.getDataType().isMatrix() ) {
+ Hop left = hop.getInput().get(0);
+ Hop right = hop.getInput().get(1);
+ DataType ldt = left.getDataType();
+ DataType rdt = right.getDataType();
+
+ isBinaryMatrixScalar = (ldt.isScalar() || rdt.isScalar());
+ isBinaryMatrixVector = hop.dimsKnown()
+ && ((ldt.isMatrix() && TemplateUtils.isVectorOrScalar(right) && !TemplateUtils.isBinaryMatrixRowVector(hop))
+ || (rdt.isMatrix() && TemplateUtils.isVectorOrScalar(left) && !TemplateUtils.isBinaryMatrixRowVector(hop)) );
+ isBinaryMatrixMatrixDense = hop.dimsKnown() && HopRewriteUtils.isEqualSize(left, right)
+ && ldt.isMatrix() && rdt.isMatrix() && !HopRewriteUtils.isSparse(left) && !HopRewriteUtils.isSparse(right);
+ }
+
+ //prepare indicators for ternary operations
+ boolean isTernaryVectorScalarVector = false;
+ boolean isTernaryMatrixScalarMatrixDense = false;
+ if( hop instanceof TernaryOp && hop.getInput().size()==3 && hop.dimsKnown()
+ && HopRewriteUtils.checkInputDataTypes(hop, DataType.MATRIX, DataType.SCALAR, DataType.MATRIX)) {
+ Hop left = hop.getInput().get(0);
+ Hop right = hop.getInput().get(2);
+
+ isTernaryVectorScalarVector = TemplateUtils.isVector(left) && TemplateUtils.isVector(right);
+ isTernaryMatrixScalarMatrixDense = HopRewriteUtils.isEqualSize(left, right)
+ && !HopRewriteUtils.isSparse(left) && !HopRewriteUtils.isSparse(right);
+ }
+
+ //check supported unary, binary, ternary operations
+ return hop.getDataType() == DataType.MATRIX && TemplateUtils.isOperationSupported(hop) && (hop instanceof UnaryOp
+ || isBinaryMatrixScalar || isBinaryMatrixVector || isBinaryMatrixMatrixDense
+ || isTernaryVectorScalarVector || isTernaryMatrixScalarMatrixDense);
+ }
+
+ /**
+ * Comparator to order input hops of the cell template. We try to order
+ * matrices-vectors-scalars via sorting by number of cells and for
+ * equal number of cells by sparsity to prefer sparse inputs as the main
+ * input for sparsity exploitation.
+ */
+ public static class HopInputComparator implements Comparator<Hop>
+ {
+ @Override
+ public int compare(Hop h1, Hop h2) {
+ long ncells1 = h1.getDataType()==DataType.SCALAR ? Long.MIN_VALUE :
+ h1.dimsKnown() ? h1.getDim1()*h1.getDim2() : Long.MAX_VALUE;
+ long ncells2 = h2.getDataType()==DataType.SCALAR ? Long.MIN_VALUE :
+ h2.dimsKnown() ? h2.getDim1()*h2.getDim2() : Long.MAX_VALUE;
+ if( ncells1 > ncells2 )
+ return -1;
+ else if( ncells1 < ncells2)
+ return 1;
+ return Long.compare(
+ h1.dimsKnown(true) ? h1.getNnz() : ncells1,
+ h2.dimsKnown(true) ? h2.getNnz() : ncells2);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/b3120ce2/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
new file mode 100644
index 0000000..68aaa2a
--- /dev/null
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateOuterProduct.java
@@ -0,0 +1,213 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import org.apache.sysml.hops.AggBinaryOp;
+import org.apache.sysml.hops.AggUnaryOp;
+import org.apache.sysml.hops.BinaryOp;
+import org.apache.sysml.hops.DataOp;
+import org.apache.sysml.hops.Hop;
+import org.apache.sysml.hops.UnaryOp;
+import org.apache.sysml.hops.Hop.AggOp;
+import org.apache.sysml.hops.Hop.Direction;
+import org.apache.sysml.hops.Hop.OpOp2;
+import org.apache.sysml.hops.codegen.cplan.CNode;
+import org.apache.sysml.hops.codegen.cplan.CNodeBinary;
+import org.apache.sysml.hops.codegen.cplan.CNodeBinary.BinType;
+import org.apache.sysml.hops.codegen.cplan.CNodeUnary;
+import org.apache.sysml.hops.codegen.cplan.CNodeUnary.UnaryType;
+import org.apache.sysml.hops.codegen.template.CPlanMemoTable.MemoTableEntry;
+import org.apache.sysml.hops.codegen.cplan.CNodeData;
+import org.apache.sysml.hops.codegen.cplan.CNodeOuterProduct;
+import org.apache.sysml.hops.codegen.cplan.CNodeTpl;
+import org.apache.sysml.hops.rewrite.HopRewriteUtils;
+import org.apache.sysml.runtime.codegen.SpoofOuterProduct.OutProdType;
+import org.apache.sysml.runtime.matrix.data.Pair;
+
+public class TemplateOuterProduct extends TemplateBase {
+
+ public TemplateOuterProduct() {
+ super(TemplateType.OuterProdTpl);
+ }
+
+ @Override
+ public boolean open(Hop hop) {
+ //open on outer product like matrix mult (output larger than common dim)
+ return HopRewriteUtils.isOuterProductLikeMM(hop)
+ && hop.getDim1()>256 && hop.getDim2() > 256;
+ }
+
+ @Override
+ public boolean fuse(Hop hop, Hop input) {
+ return !isClosed()
+ &&((hop instanceof UnaryOp && TemplateUtils.isOperationSupported(hop))
+ || (hop instanceof BinaryOp && TemplateUtils.isOperationSupported(hop)
+ && (TemplateUtils.isBinaryMatrixColVector(hop) || HopRewriteUtils.isBinaryMatrixScalarOperation(hop)
+ || (HopRewriteUtils.isBinaryMatrixMatrixOperation(hop) && HopRewriteUtils.isBinary(hop, OpOp2.MULT, OpOp2.DIV)) ))
+ || HopRewriteUtils.isTransposeOperation(hop)
+ || (hop instanceof AggBinaryOp && !HopRewriteUtils.isOuterProductLikeMM(hop))
+ || (hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getDirection()==Direction.RowCol));
+ }
+
+ @Override
+ public boolean merge(Hop hop, Hop input) {
+ return !isClosed() &&
+ (TemplateUtils.isBinaryMatrixRowVector(hop)
+ || HopRewriteUtils.isBinaryMatrixScalarOperation(hop));
+ }
+
+ @Override
+ public CloseType close(Hop hop) {
+ // close on second matrix multiply (after open) or unary aggregate
+ if( hop instanceof AggUnaryOp && HopRewriteUtils.isOuterProductLikeMM(hop.getInput().get(0)) )
+ return CloseType.CLOSED_INVALID;
+ else if( (hop instanceof AggUnaryOp)
+ || (hop instanceof AggBinaryOp && !HopRewriteUtils.isOuterProductLikeMM(hop)
+ && !HopRewriteUtils.isTransposeOperation(hop.getParent().get(0)))
+ || (HopRewriteUtils.isTransposeOperation(hop) && hop.getInput().get(0) instanceof AggBinaryOp
+ && !HopRewriteUtils.isOuterProductLikeMM(hop.getInput().get(0)) ))
+ return CloseType.CLOSED_VALID;
+ else
+ return CloseType.OPEN;
+ }
+
+ public Pair<Hop[], CNodeTpl> constructCplan(Hop hop, CPlanMemoTable memo, boolean compileLiterals)
+ {
+ //recursively process required cplan output
+ HashSet<Hop> inHops = new HashSet<Hop>();
+ HashMap<String,Hop> inHops2 = new HashMap<String, Hop>();
+ HashMap<Long, CNode> tmp = new HashMap<Long, CNode>();
+ hop.resetVisitStatus();
+ rConstructCplan(hop, memo, tmp, inHops, inHops2, compileLiterals);
+ hop.resetVisitStatus();
+
+ //reorder inputs (ensure matrix is first input)
+ Hop X = inHops2.get("_X");
+ Hop U = inHops2.get("_U");
+ Hop V = inHops2.get("_V");
+ LinkedList<Hop> sinHops = new LinkedList<Hop>(inHops);
+ sinHops.remove(V); sinHops.addFirst(V);
+ sinHops.remove(U); sinHops.addFirst(U);
+ sinHops.remove(X); sinHops.addFirst(X);
+
+ //construct template node
+ ArrayList<CNode> inputs = new ArrayList<CNode>();
+ for( Hop in : sinHops )
+ if( in != null )
+ inputs.add(tmp.get(in.getHopID()));
+
+ CNode output = tmp.get(hop.getHopID());
+ CNodeOuterProduct tpl = new CNodeOuterProduct(inputs, output);
+ tpl.setOutProdType(TemplateUtils.getOuterProductType(X, U, V, hop));
+ tpl.setTransposeOutput(!HopRewriteUtils.isTransposeOperation(hop)
+ && tpl.getOutProdType()==OutProdType.LEFT_OUTER_PRODUCT);
+
+ return new Pair<Hop[],CNodeTpl>(sinHops.toArray(new Hop[0]), tpl);
+ }
+
+ private void rConstructCplan(Hop hop, CPlanMemoTable memo, HashMap<Long, CNode> tmp, HashSet<Hop> inHops, HashMap<String, Hop> inHops2, boolean compileLiterals)
+ {
+ //recursively process required childs
+ MemoTableEntry me = memo.getBest(hop.getHopID(), TemplateType.OuterProdTpl);
+ for( int i=0; i<hop.getInput().size(); i++ ) {
+ Hop c = hop.getInput().get(i);
+ if( me.isPlanRef(i) )
+ rConstructCplan(c, memo, tmp, inHops, inHops2, compileLiterals);
+ else {
+ CNodeData cdata = TemplateUtils.createCNodeData(c, compileLiterals);
+ tmp.put(c.getHopID(), cdata);
+ inHops.add(c);
+ }
+ }
+
+ //construct cnode for current hop
+ CNode out = null;
+ if(hop instanceof UnaryOp)
+ {
+ CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
+ String primitiveOpName = ((UnaryOp)hop).getOp().toString();
+ out = new CNodeUnary(cdata1, UnaryType.valueOf(primitiveOpName));
+ }
+ else if(hop instanceof BinaryOp)
+ {
+ CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
+ CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
+ String primitiveOpName = ((BinaryOp)hop).getOp().toString();
+
+ if( (cdata1.getNumRows() > 1 && cdata1.getNumCols() == 1) || (cdata1.getNumRows() == 1 && cdata1.getNumCols() > 1) ) {
+ cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R);
+ }
+ if( (cdata2.getNumRows() > 1 && cdata2.getNumCols() == 1) || (cdata2.getNumRows() == 1 && cdata2.getNumCols() > 1) ) {
+ cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R);
+ }
+
+ if( HopRewriteUtils.isEqualSize(hop.getInput().get(0), hop.getInput().get(1))
+ && hop.getInput().get(0) instanceof DataOp )
+ inHops2.put("_X", hop.getInput().get(0));
+
+ out = new CNodeBinary(cdata1, cdata2, BinType.valueOf(primitiveOpName));
+ }
+ else if(hop instanceof AggBinaryOp)
+ {
+ CNode cdata1 = tmp.get(hop.getInput().get(0).getHopID());
+ CNode cdata2 = tmp.get(hop.getInput().get(1).getHopID());
+
+ //handle tanspose in outer or final product
+ cdata1 = TemplateUtils.skipTranspose(cdata1, hop.getInput().get(0), tmp, compileLiterals);
+ cdata2 = TemplateUtils.skipTranspose(cdata2, hop.getInput().get(1), tmp, compileLiterals);
+
+ //outerproduct U%*%t(V), see open
+ if( HopRewriteUtils.isOuterProductLikeMM(hop) )
+ {
+ //keep U and V for later reference
+ inHops2.put("_U", hop.getInput().get(0));
+ if( HopRewriteUtils.isTransposeOperation(hop.getInput().get(1)) )
+ inHops2.put("_V", hop.getInput().get(1).getInput().get(0));
+ else
+ inHops2.put("_V", hop.getInput().get(1));
+
+ out = new CNodeBinary(cdata1, cdata2, BinType.DOT_PRODUCT);
+ }
+ //final left/right matrix mult, see close
+ else {
+ if( cdata1.getDataType().isScalar() )
+ out = new CNodeBinary(cdata1, cdata2, BinType.VECT_MULT_ADD);
+ else
+ out = new CNodeBinary(cdata2, cdata1, BinType.VECT_MULT_ADD);
+ }
+ }
+ else if( HopRewriteUtils.isTransposeOperation(hop) )
+ {
+ out = tmp.get(hop.getInput().get(0).getHopID());
+ }
+ else if( hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getOp() == AggOp.SUM
+ && ((AggUnaryOp)hop).getDirection() == Direction.RowCol )
+ {
+ out = tmp.get(hop.getInput().get(0).getHopID());
+ }
+
+ tmp.put(hop.getHopID(), out);
+ }
+}