docs: public static void extract(DMatrixSparseCSC src, int srcY0, int srcY1, int srcX0, int srcX1,
                                 DMatrixSparseCSC dst, int dstY0, int dstX0)
      {
          if( srcY1 < srcY0 || srcY0 < 0 || srcY1 > src.getNumRows() )
              throw new MatrixDimensionException("srcY1 < srcY0 || srcY0 < 0 || srcY1 > src.numRows. "+stringShapes(src,dst));
          if( srcX1 < srcX0 || srcX0 < 0 || srcX1 > src.getNumCols() )
              throw new MatrixDimensionException("srcX1 < srcX0 || srcX0 < 0 || srcX1 > src.numCols. "+stringShapes(src,dst));
  
          int w = srcX1-srcX0;
          int h = srcY1-srcY0;
  
          if( dstY0+h > dst.getNumRows() )
              throw new IllegalArgumentException("dst is too small in rows. "+dst.getNumRows()+" < "+(dstY0+h));
          if( dstX0+w > dst.getNumCols() )
              throw new IllegalArgumentException("dst is too small in columns. "+dst.getNumCols()+" < "+(dstX0+w));
  
          zero(dst,dstY0,dstY0+h,dstX0,dstX0+w);
  
          // NOTE: One possible optimization would be to determine the non-zero pattern in dst after the change is
          //       applied, modify it's structure, then copy the values in. That way you aren't shifting memory constantly.
          //
          // NOTE: Another optimization would be to sort the src so that it doesn't need to go through every row
          for (int colSrc = srcX0; colSrc < srcX1; colSrc++) {
              int idxS0 = src.col_idx[colSrc];
              int idxS1 = src.col_idx[colSrc + 1];
  
              for (int i = idxS0; i < idxS1; i++) {
                  int row = src.nz_rows[i];
                  if (row >= srcY0 && row < srcY1) {
                      dst.set(row - srcY0 + dstY0, colSrc - srcX0 + dstX0, src.nz_values[i]);
                  }
              }
          }
      }