@@ -747,8 +747,8 @@ protected ExecType optFindExecType(boolean transitive) {
747747
748748 checkAndSetForcedPlatform ();
749749
750- DataType dt1 = getInput (). get (0 ).getDataType ();
751- DataType dt2 = getInput (). get (1 ).getDataType ();
750+ final DataType dt1 = getInput (0 ).getDataType ();
751+ final DataType dt2 = getInput (1 ).getDataType ();
752752
753753 if ( _etypeForced != null ) {
754754 setExecType (_etypeForced );
@@ -796,18 +796,28 @@ else if ( dt1 == DataType.SCALAR && dt2 == DataType.MATRIX ) {
796796 checkAndSetInvalidCPDimsAndSize ();
797797 }
798798
799- //spark-specific decision refinement (execute unary scalar w/ spark input and
799+ // spark-specific decision refinement (execute unary scalar w/ spark input and
800800 // single parent also in spark because it's likely cheap and reduces intermediates)
801- if (transitive && _etype == ExecType .CP && _etypeForced != ExecType .CP && _etypeForced != ExecType .FED &&
802- getDataType ().isMatrix () // output should be a matrix
803- && (dt1 .isScalar () || dt2 .isScalar ()) // one side should be scalar
804- && supportsMatrixScalarOperations () // scalar operations
805- && !(getInput ().get (dt1 .isScalar () ? 1 : 0 ) instanceof DataOp ) // input is not checkpoint
806- && getInput ().get (dt1 .isScalar () ? 1 : 0 ).getParent ().size () == 1 // unary scalar is only parent
807- && !HopRewriteUtils .isSingleBlock (getInput ().get (dt1 .isScalar () ? 1 : 0 )) // single block triggered exec
808- && getInput ().get (dt1 .isScalar () ? 1 : 0 ).optFindExecType () == ExecType .SPARK ) {
809- // pull unary scalar operation into spark
810- _etype = ExecType .SPARK ;
801+ if (transitive // we allow transitive Spark operations. continue sequences of spark operations
802+ && _etype == ExecType .CP // The instruction is currently in CP
803+ && _etypeForced != ExecType .CP // not forced CP
804+ && _etypeForced != ExecType .FED // not federated
805+ && (getDataType ().isMatrix () || getDataType ().isFrame ()) // output should be a matrix or frame
806+ ) {
807+ final boolean v1 = getInput (0 ).isScalarOrVectorBellowBlockSize ();
808+ final boolean v2 = getInput (1 ).isScalarOrVectorBellowBlockSize ();
809+ final boolean left = v1 == true ; // left side is the vector or scalar
810+ final Hop sparkIn = getInput (left ? 1 : 0 );
811+ if ((v1 ^ v2 ) // XOR only one side is allowed to be a vector or a scalar.
812+ && (supportsMatrixScalarOperations () || op == OpOp2 .APPLY_SCHEMA ) // supported operation
813+ && sparkIn .getParent ().size () == 1 // only one parent
814+ && !HopRewriteUtils .isSingleBlock (sparkIn ) // single block triggered exec
815+ && sparkIn .optFindExecType () == ExecType .SPARK // input was spark op.
816+ && !(sparkIn instanceof DataOp ) // input is not checkpoint
817+ ) {
818+ // pull operation into spark
819+ _etype = ExecType .SPARK ;
820+ }
811821 }
812822
813823 if ( OptimizerUtils .ALLOW_BINARY_UPDATE_IN_PLACE &&
@@ -837,7 +847,7 @@ else if( (op == OpOp2.CBIND && getDataType().isList())
837847 || (op == OpOp2 .RBIND && getDataType ().isList ())) {
838848 _etype = ExecType .CP ;
839849 }
840-
850+
841851 //mark for recompile (forever)
842852 setRequiresRecompileIfNecessary ();
843853
@@ -1154,17 +1164,35 @@ && getInput().get(0) == that2.getInput().get(0)
11541164 }
11551165
11561166 public boolean supportsMatrixScalarOperations () {
1157- return ( op ==OpOp2 .PLUS ||op ==OpOp2 .MINUS
1158- ||op ==OpOp2 .MULT ||op ==OpOp2 .DIV
1159- ||op ==OpOp2 .MODULUS ||op ==OpOp2 .INTDIV
1160- ||op ==OpOp2 .LESS ||op ==OpOp2 .LESSEQUAL
1161- ||op ==OpOp2 .GREATER ||op ==OpOp2 .GREATEREQUAL
1162- ||op ==OpOp2 .EQUAL ||op ==OpOp2 .NOTEQUAL
1163- ||op ==OpOp2 .MIN ||op ==OpOp2 .MAX
1164- ||op ==OpOp2 .LOG ||op ==OpOp2 .POW
1165- ||op ==OpOp2 .AND ||op ==OpOp2 .OR ||op ==OpOp2 .XOR
1166- ||op ==OpOp2 .BITWAND ||op ==OpOp2 .BITWOR ||op ==OpOp2 .BITWXOR
1167- ||op ==OpOp2 .BITWSHIFTL ||op ==OpOp2 .BITWSHIFTR );
1167+ switch (op ) {
1168+ case PLUS :
1169+ case MINUS :
1170+ case MULT :
1171+ case DIV :
1172+ case MODULUS :
1173+ case INTDIV :
1174+ case LESS :
1175+ case LESSEQUAL :
1176+ case GREATER :
1177+ case GREATEREQUAL :
1178+ case EQUAL :
1179+ case NOTEQUAL :
1180+ case MIN :
1181+ case MAX :
1182+ case LOG :
1183+ case POW :
1184+ case AND :
1185+ case OR :
1186+ case XOR :
1187+ case BITWAND :
1188+ case BITWOR :
1189+ case BITWXOR :
1190+ case BITWSHIFTL :
1191+ case BITWSHIFTR :
1192+ return true ;
1193+ default :
1194+ return false ;
1195+ }
11681196 }
11691197
11701198 public boolean isPPredOperation () {
0 commit comments