/**
* (C) Copyright IBM Corp. 2010, 2015
*
* Licensed 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 com.ibm.bi.dml.hops.globalopt.gdfgraph;
import java.util.ArrayList;
import com.ibm.bi.dml.hops.AggUnaryOp;
import com.ibm.bi.dml.hops.DataGenOp;
import com.ibm.bi.dml.hops.Hop;
import com.ibm.bi.dml.hops.Hop.DataGenMethod;
import com.ibm.bi.dml.hops.Hop.Direction;
import com.ibm.bi.dml.hops.Hop.FileFormatTypes;
import com.ibm.bi.dml.hops.Hop.OpOp1;
import com.ibm.bi.dml.hops.Hop.ReOrgOp;
import com.ibm.bi.dml.hops.ReorgOp;
import com.ibm.bi.dml.hops.UnaryOp;
import com.ibm.bi.dml.parser.Expression.DataType;
import com.ibm.bi.dml.runtime.controlprogram.Program;
import com.ibm.bi.dml.runtime.controlprogram.ProgramBlock;
import com.ibm.bi.dml.runtime.controlprogram.parfor.util.IDSequence;
/**
* The reason of a custom graph structure is to unify both within DAG
* and cross DAG enumeration. Conceptually, we would only need interesting
* properties of transient reads and could compile locally.
*
* Furthermore, having a global graph structure also allows for more advanced
* algebraic simplification rewrites because the semantics of transient read
* inputs are always available.
*
*/
public class GDFNode
{
public enum NodeType{
HOP_NODE,
LOOP_NODE,
CROSS_BLOCK_NODE,
}
private static IDSequence _seqID = new IDSequence();
protected NodeType _type = null;
protected long _ID = -1;
//references to original program and hop dag
protected Hop _hop = null;
protected ProgramBlock _pb = null;
//input nodes
protected ArrayList<GDFNode> _inputs = null;
public GDFNode()
{
_ID = _seqID.getNextID();
}
public GDFNode( Hop hop, ProgramBlock pb, ArrayList<GDFNode> inputs )
{
this();
_type = NodeType.HOP_NODE;
_hop = hop;
_pb = pb;
_inputs = inputs;
}
public NodeType getNodeType()
{
return _type;
}
public long getID()
{
return _ID;
}
public Hop getHop()
{
return _hop;
}
public ProgramBlock getProgramBlock()
{
return _pb;
}
public Program getProgram()
{
if( _pb != null )
return _pb.getProgram();
return null;
}
public ArrayList<GDFNode> getInputs()
{
return _inputs;
}
public DataType getDataType()
{
return _hop.getDataType();
}
/**
* If the output or any input is a matrix we need to consider
* MR configurations. This for examples excludes Literals or
* any purely scalar operation.
*
* @return
*/
public boolean requiresMREnumeration()
{
//general rule: MR generation required if at least one matrix input/output
boolean ret = (_hop.getDataType() == DataType.MATRIX);
for( Hop c : _hop.getInput() )
ret |= (c.getDataType() == DataType.MATRIX);
//special cases of CP-only operators
if( _hop instanceof UnaryOp && ((UnaryOp)_hop).getOp()==OpOp1.CAST_AS_SCALAR ) //as.scalar
ret = false;
if( _hop instanceof DataGenOp && ((DataGenOp)_hop).getOp()==DataGenMethod.SINIT ) //matrix(str, )
ret = false;
if( _hop instanceof UnaryOp && ((UnaryOp)_hop).getOp()==OpOp1.NROW ) //nrow - meta data only
ret = false;
if( _hop instanceof UnaryOp && ((UnaryOp)_hop).getOp()==OpOp1.NCOL ) //ncol - meta data only
ret = false;
return ret;
}
/**
*
* @param format
* @return
*/
public boolean isValidInputFormatForOperation( FileFormatTypes format )
{
return ( _hop instanceof UnaryOp && format!=FileFormatTypes.CSV
|| (_hop instanceof AggUnaryOp && ((AggUnaryOp)_hop).getDirection()==Direction.RowCol && format!=FileFormatTypes.CSV)
|| (_hop instanceof ReorgOp && ((ReorgOp)_hop).getOp()==ReOrgOp.TRANSPOSE && format!=FileFormatTypes.CSV)
|| format==FileFormatTypes.BINARY ); //any op
}
/**
*
* @param deps
* @return
*/
public String explain(String deps)
{
String ldeps = (deps!=null) ? deps : "";
//node details
if( _hop!=null )
return "Node "+ldeps+" ["+_hop.getHopID()+", "+_hop.getOpString()+"]";
else
return "Node "+ldeps+" [null]";
}
}