protected ExecType optFindExecType()

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;
	}