/**
   * Multiply blocks of two matrices A,B and add to C.
   *
   * <p>Blocks of Matrix B are transformed to column-major layout (if not already) to facilitate
   * multiplication.<br>
   * (If matrices have been created optimally, B should already be column-major)
   */
  protected final void multiply() {
    final int step = blockStripeSize, blockSize = blockStripeSize * blockStripeSize;

    for (int m = fromM; m < toM; m += step) {
      final int aRows = matrixA.layout.getRowsInBlock(m);

      for (int k = fromK; k < toK; k += step) {
        final int bCols = matrixB.layout.getColumnsInBlock(k);

        final double[] cBlock = new double[aRows * bCols];

        for (int n = fromN; n < toN; n += step) {

          // ensure a and b are in optimal block order before
          // multiplication
          final double[] aBlock = matrixA.layout.toRowMajorBlock(matrixA, m, n);
          final double[] bBlock = matrixB.layout.toColMajorBlock(matrixB, n, k);

          if (aBlock != null && bBlock != null) {
            if (aBlock.length == blockSize && bBlock.length == blockSize) {
              multiplyAxB(aBlock, bBlock, cBlock, step);
            } else {
              int aCols = aBlock.length / aRows;
              int bRows = bBlock.length / bCols;
              assertTrue(aCols == bRows, "aCols!=bRows");
              multiplyRowMajorTimesColumnMajorBlocks(aBlock, bBlock, cBlock, aRows, aCols, bCols);
            }
          }
        }

        matrixC.addBlockData(m, k, cBlock);
      }
    }
  }
 private static void verifyInput(
     final BlockDenseDoubleMatrix2D a,
     final BlockDenseDoubleMatrix2D b,
     final BlockDenseDoubleMatrix2D c,
     final int fromM,
     final int toM,
     final int fromN,
     final int toN,
     final int fromK,
     final int toK) {
   assertTrue(a != null, "a cannot be null");
   assertTrue(b != null, "b cannot be null");
   assertTrue(c != null, "c cannot be null");
   assertTrue(fromM <= a.getRowCount() && fromM >= 0, "Invalid argument : fromM");
   assertTrue(toM <= a.getRowCount() && toM >= fromM, "Invalid argument : fromM/toM");
   assertTrue(fromN <= a.getColumnCount() && fromN >= 0, "Invalid argument : fromN");
   assertTrue(toN <= a.getColumnCount() && toN >= fromN, "Invalid argument : fromN/toN");
   assertTrue(fromK <= b.getColumnCount() && fromK >= 0, "Invalid argument : fromK");
   assertTrue(toK <= b.getColumnCount() && toK >= fromK, "Invalid argument : fromK/toK");
   assertTrue(a.getColumnCount() == b.getRowCount(), "Invalid argument : a.columns != b.rows");
   assertTrue(a.getRowCount() == c.getRowCount(), "Invalid argument : a.rows != c.rows");
   assertTrue(
       b.getColumnCount() == c.getColumnCount(), "Invalid argument : b.columns != c.columns");
 }