public static MRInstruction[] parseCombineInstructions(String str)
      throws DMLUnsupportedOperationException, DMLRuntimeException {
    MRInstruction[] inst = null;
    if (str != null && !str.isEmpty()) {
      String[] strlist = str.split(Instruction.INSTRUCTION_DELIM);
      inst = new MRInstruction[strlist.length];

      for (int i = 0; i < strlist.length; i++) {
        MRINSTRUCTION_TYPE type = InstructionUtils.getMRType(strlist[i]);
        if (type == MRINSTRUCTION_TYPE.CombineBinary)
          inst[i] =
              (CombineBinaryInstruction) CombineBinaryInstruction.parseInstruction(strlist[i]);
        else if (type == MRINSTRUCTION_TYPE.CombineTernary)
          inst[i] =
              (CombineTernaryInstruction) CombineTernaryInstruction.parseInstruction(strlist[i]);
        else throw new DMLRuntimeException("unknown combine instruction: " + strlist[i]);
      }
    }
    return inst;
  }
  public static MRInstruction parseSingleInstruction(MRINSTRUCTION_TYPE mrtype, String str)
      throws DMLUnsupportedOperationException, DMLRuntimeException {
    if (str == null || str.isEmpty()) return null;

    switch (mrtype) {
      case Aggregate:
        return AggregateInstruction.parseInstruction(str);

      case ArithmeticBinary:
        {
          String opcode = InstructionUtils.getOpCode(str);
          String[] parts = InstructionUtils.getInstructionPartsWithValueType(str);
          // extract datatypes of first and second input operands
          String dt1 =
              parts[1].split(Instruction.DATATYPE_PREFIX)[1].split(Instruction.VALUETYPE_PREFIX)[0];
          String dt2 =
              parts[2].split(Instruction.DATATYPE_PREFIX)[1].split(Instruction.VALUETYPE_PREFIX)[0];
          if (dt1.equalsIgnoreCase("SCALAR") || dt2.equalsIgnoreCase("SCALAR")) {
            return ScalarInstruction.parseInstruction(str);
          } else {
            if (BinaryM.isOpcode(opcode)) return BinaryMInstruction.parseInstruction(str);
            else return BinaryInstruction.parseInstruction(str);
          }
        }

      case AggregateBinary:
        return AggregateBinaryInstruction.parseInstruction(str);

      case AggregateUnary:
        return AggregateUnaryInstruction.parseInstruction(str);

      case Ternary:
        return TernaryInstruction.parseInstruction(str);

      case Quaternary:
        return QuaternaryInstruction.parseInstruction(str);

      case Rand:
        return RandInstruction.parseInstruction(str);

      case Seq:
        return SeqInstruction.parseInstruction(str);

      case Reblock:
        return ReblockInstruction.parseInstruction(str);

      case Append:
        return AppendInstruction.parseInstruction(str);

      case Reorg:
        return ReorgInstruction.parseInstruction(str);

      case Replicate:
        return ReplicateInstruction.parseInstruction(str);

      case Unary:
        {
          String opcode = InstructionUtils.getOpCode(str);
          String[] parts = InstructionUtils.getInstructionPartsWithValueType(str);
          if (parts.length == 4
              && (opcode.equalsIgnoreCase("log") || opcode.equalsIgnoreCase("log_nz")))
            return ScalarInstruction.parseInstruction(str);
          else // default case
          return UnaryInstruction.parseInstruction(str);
        }
      case MMTSJ:
        return MMTSJMRInstruction.parseInstruction(str);

      case PMMJ:
        return PMMJMRInstruction.parseInstruction(str);

      case MapMultChain:
        return MapMultChainInstruction.parseInstruction(str);

      case BinUaggChain:
        return BinUaggChainInstruction.parseInstruction(str);

      case UaggOuterChain:
        return UaggOuterChainInstruction.parseInstruction(str);

      case CombineTernary:
        return CombineTernaryInstruction.parseInstruction(str);

      case CombineBinary:
        return CombineBinaryInstruction.parseInstruction(str);

      case CombineUnary:
        return CombineUnaryInstruction.parseInstruction(str);

      case PickByCount:
        return PickByCountInstruction.parseInstruction(str);

      case CM_N_COV:
        return CM_N_COVInstruction.parseInstruction(str);

      case GroupedAggregate:
        return GroupedAggregateInstruction.parseInstruction(str);

      case MapGroupedAggregate:
        return GroupedAggregateMInstruction.parseInstruction(str);

      case RangeReIndex:
        return RangeBasedReIndexInstruction.parseInstruction(str);

      case ZeroOut:
        return ZeroOutInstruction.parseInstruction(str);

      case MatrixReshape:
        return MatrixReshapeMRInstruction.parseInstruction(str);

      case Sort: // workaround for dummy MR sort instruction
        return SortMR.parseSortInstruction(str);

      case CSVReblock:
        return CSVReblockInstruction.parseInstruction(str);

      case CSVWrite:
        return CSVWriteInstruction.parseInstruction(str);

      case ParameterizedBuiltin:
        return ParameterizedBuiltinMRInstruction.parseInstruction(str);

      case RemoveEmpty:
        return RemoveEmptyMRInstruction.parseInstruction(str);

      case Partition:
        return DataPartitionMRInstruction.parseInstruction(str);

      case CumsumAggregate:
        return CumulativeAggregateInstruction.parseInstruction(str);

      case CumsumSplit:
        return CumulativeSplitInstruction.parseInstruction(str);

      case CumsumOffset:
        return CumulativeOffsetInstruction.parseInstruction(str);

      case INVALID:

      default:
        throw new DMLRuntimeException("Invalid MR Instruction Type: " + mrtype);
    }
  }