in src/main/java/org/apache/sysds/hops/BinaryOp.java [762:861]
protected ExecType optFindExecType(boolean transitive) {
checkAndSetForcedPlatform();
DataType dt1 = getInput().get(0).getDataType();
DataType dt2 = getInput().get(1).getDataType();
if( _etypeForced != null ) {
setExecType(_etypeForced);
}
else
{
if ( OptimizerUtils.isMemoryBasedOptLevel() ) {
setExecType(findExecTypeByMemEstimate());
}
else
{
_etype = null;
if ( dt1 == DataType.MATRIX && dt2 == DataType.MATRIX ) {
// choose CP if the dimensions of both inputs are below Hops.CPThreshold
// OR if both are vectors
if ( (getInput().get(0).areDimsBelowThreshold() && getInput().get(1).areDimsBelowThreshold())
|| (getInput().get(0).isVector() && getInput().get(1).isVector()))
{
setExecType(ExecType.CP);
}
}
else if ( dt1 == DataType.MATRIX && dt2 == DataType.SCALAR ) {
if ( getInput().get(0).areDimsBelowThreshold() || getInput().get(0).isVector() )
{
setExecType(ExecType.CP);
}
}
else if ( dt1 == DataType.SCALAR && dt2 == DataType.MATRIX ) {
if ( getInput().get(1).areDimsBelowThreshold() || getInput().get(1).isVector() )
{
setExecType(ExecType.CP);
}
}
else
{
setExecType(ExecType.CP);
}
//if no CP condition applied
if( _etype == null )
setExecType(ExecType.SPARK);
}
//check for valid CP dimensions and matrix size
checkAndSetInvalidCPDimsAndSize();
}
//spark-specific decision refinement (execute unary scalar w/ spark input and
// single parent also in spark because it's likely cheap and reduces intermediates)
if(transitive && _etype == ExecType.CP && _etypeForced != ExecType.CP && _etypeForced != ExecType.FED &&
getDataType().isMatrix() // output should be a matrix
&& (dt1.isScalar() || dt2.isScalar()) // one side should be scalar
&& supportsMatrixScalarOperations() // scalar operations
&& !(getInput().get(dt1.isScalar() ? 1 : 0) instanceof DataOp) // input is not checkpoint
&& getInput().get(dt1.isScalar() ? 1 : 0).getParent().size() == 1 // unary scalar is only parent
&& !HopRewriteUtils.isSingleBlock(getInput().get(dt1.isScalar() ? 1 : 0)) // single block triggered exec
&& getInput().get(dt1.isScalar() ? 1 : 0).optFindExecType() == ExecType.SPARK) {
// pull unary scalar operation into spark
_etype = ExecType.SPARK;
}
if( OptimizerUtils.ALLOW_BINARY_UPDATE_IN_PLACE &&
transitive && _etypeForced != ExecType.SPARK && _etypeForced != ExecType.FED &&
getDataType().isMatrix() // Output is a matrix
&& op == OpOp2.DIV // Operation is division
&& dt1.isMatrix() // Left hand side is a Matrix
// right hand side is a scalar or a vector.
&& (dt2.isScalar() || (dt2.isMatrix() & getInput().get(1).isVector())) //
&& memOfInputIsLessThanBudget() //
&& getInput().get(0).getExecType() != ExecType.SPARK // Is not already a spark operation
&& doesNotContainNanAndInf(getInput().get(1)) // Guaranteed not to densify the operation
&& LineageCacheConfig.ReuseCacheType.isNone() // Inplace update corrupts the already cached input matrix block
) {
inplace = true;
_etype = ExecType.CP;
}
//ensure cp exec type for single-node operations
if ( op == OpOp2.SOLVE ) {
if (isGPUEnabled())
_etype = ExecType.GPU;
else
_etype = ExecType.CP;
}
else if( (op == OpOp2.CBIND && getDataType().isList())
|| (op == OpOp2.RBIND && getDataType().isList())) {
_etype = ExecType.CP;
}
//mark for recompile (forever)
setRequiresRecompileIfNecessary();
return _etype;
}