public final Tuple<DenseIntMatrix, DenseIntMatrix> splitRandomMatrices(
      float percentage) {
    if (percentage < 0.0f || percentage > 1.0f) {
      throw new IllegalArgumentException(
          "Percentage must be between 0.0 and 1.0! Given " + percentage);
    }

    if (percentage == 1.0f) {
      return new Tuple<DenseIntMatrix, DenseIntMatrix>(this, null);
    } else if (percentage == 0.0f) {
      return new Tuple<DenseIntMatrix, DenseIntMatrix>(null, this);
    }

    final Random rand = new Random(System.nanoTime());
    int firstMatrixRowsCount = Math.round(percentage * numRows);

    // we first choose needed rows number of items to pick
    final HashSet<Integer> lowerMatrixRowIndices = new HashSet<Integer>();
    int missingRows = firstMatrixRowsCount;
    while (missingRows > 0) {
      final int nextIndex = rand.nextInt(numRows);
      if (lowerMatrixRowIndices.add(nextIndex)) {
        missingRows--;
      }
    }

    // make to new matrixes
    final int[][] firstMatrix = new int[firstMatrixRowsCount][numColumns];
    int firstMatrixIndex = 0;
    final int[][] secondMatrix = new int[numRows - firstMatrixRowsCount][numColumns];
    int secondMatrixIndex = 0;

    // then we loop over all items and put split the matrix
    for (int r = 0; r < numRows; r++) {
      if (lowerMatrixRowIndices.contains(r)) {
        firstMatrix[firstMatrixIndex++] = matrix[r];
      } else {
        secondMatrix[secondMatrixIndex++] = matrix[r];
      }
    }

    return new Tuple<DenseIntMatrix, DenseIntMatrix>(new DenseIntMatrix(
        firstMatrix), new DenseIntMatrix(secondMatrix));
  }