public static void transposeSub(D1Submatrix64F A) {
   int temp = A.col0;
   A.col0 = A.row0;
   A.row0 = temp;
   temp = A.col1;
   A.col1 = A.row1;
   A.row1 = temp;
 }
  private static DenseMatrix64F multByExtract(
      int operationType, D1Submatrix64F subA, D1Submatrix64F subB, D1Submatrix64F subC) {
    SimpleMatrix A = subA.extract();
    SimpleMatrix B = subB.extract();
    SimpleMatrix C = subC.extract();

    if (operationType > 0) return A.mult(B).plus(C).getMatrix();
    else if (operationType < 0) return C.minus(A.mult(B)).getMatrix();
    else return A.mult(B).getMatrix();
  }
  /**
   * Multiplies the two sub-matrices together. Checks to see if the same result is found when
   * multiplied using the normal algorithm versus the submatrix one.
   */
  private static void checkMult_submatrix(
      Method func,
      int operationType,
      boolean transA,
      boolean transB,
      D1Submatrix64F A,
      D1Submatrix64F B) {
    if (A.col0 % BLOCK_LENGTH != 0 || A.row0 % BLOCK_LENGTH != 0)
      throw new IllegalArgumentException("Submatrix A is not block aligned");
    if (B.col0 % BLOCK_LENGTH != 0 || B.row0 % BLOCK_LENGTH != 0)
      throw new IllegalArgumentException("Submatrix B is not block aligned");

    BlockMatrix64F origA = BlockMatrixOps.createRandom(numRows, numCols, -1, 1, rand, BLOCK_LENGTH);
    BlockMatrix64F origB = BlockMatrixOps.createRandom(numCols, numRows, -1, 1, rand, BLOCK_LENGTH);

    A.original = origA;
    B.original = origB;
    int w = B.col1 - B.col0;
    int h = A.row1 - A.row0;

    // offset it to make the test harder
    // randomize to see if its set or adding
    BlockMatrix64F subC =
        BlockMatrixOps.createRandom(BLOCK_LENGTH + h, BLOCK_LENGTH + w, -1, 1, rand, BLOCK_LENGTH);
    D1Submatrix64F C =
        new D1Submatrix64F(subC, BLOCK_LENGTH, subC.numRows, BLOCK_LENGTH, subC.numCols);

    DenseMatrix64F rmC = multByExtract(operationType, A, B, C);

    if (transA) {
      origA = BlockMatrixOps.transpose(origA, null);
      transposeSub(A);
      A.original = origA;
    }

    if (transB) {
      origB = BlockMatrixOps.transpose(origB, null);
      transposeSub(B);
      B.original = origB;
    }

    try {
      func.invoke(null, BLOCK_LENGTH, A, B, C);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
      throw new RuntimeException(e);
    }

    for (int i = C.row0; i < C.row1; i++) {
      for (int j = C.col0; j < C.col1; j++) {
        //                System.out.println(i+" "+j);
        double diff = Math.abs(subC.get(i, j) - rmC.get(i - C.row0, j - C.col0));
        //                System.out.println(subC.get(i,j)+" "+rmC.get(i-C.row0,j-C.col0));
        if (diff >= 1e-12) {
          subC.print();
          rmC.print();
          System.out.println(func.getName());
          System.out.println("transA    " + transA);
          System.out.println("transB    " + transB);
          System.out.println("type      " + operationType);
          fail("Error too large");
        }
      }
    }
  }