public Iterator<TrainTestFold<T>> split(Dataset<T> dataset, boolean shuffle) {
        int nsamples = dataset.size();
        if (nsamples == 0) {
            throw new IllegalArgumentException("empty input data");
        }
        if (nsplits > nsamples) {
            throw new IllegalArgumentException("cannot have nsplits > nsamples");
        }
        int[] indices;
        if (shuffle) {
            indices = Util.randperm(nsamples,rng);
        } else {
            indices = IntStream.range(0, nsamples).toArray();
        }
        int[] foldSizes = new int[nsplits];
        Arrays.fill(foldSizes, nsamples/nsplits);
        for (int i = 0; i < (nsamples%nsplits); i++) {
            foldSizes[i] += 1;
        }

        return new Iterator<TrainTestFold<T>>() {
            int foldPtr = 0;
            int dataPtr = 0;

            @Override
            public boolean hasNext() {
                return foldPtr < foldSizes.length;
            }

            @Override
            public TrainTestFold<T> next() {
                int size = foldSizes[foldPtr];
                foldPtr++;
                int start = dataPtr;
                int stop = dataPtr+size;
                dataPtr = stop;
                int[] holdOut = Arrays.copyOfRange(indices, start, stop);
                int[] rest = new int[indices.length - holdOut.length];
                System.arraycopy(indices, 0, rest, 0, start);
                System.arraycopy(indices, stop, rest, start, nsamples-stop);
                return new TrainTestFold<>(
                        new DatasetView<>(dataset, rest, "TrainFold(seed="+seed+","+foldPtr+" of " + nsplits+")"),
                        new DatasetView<>(dataset, holdOut, "TestFold(seed="+seed+","+foldPtr+" of " + nsplits+")" )
                );
            }
        };
    }
@Test
    public void testKFolder() {
        int n = 50;
        int nsplits = 10;
        Dataset<MockOutput> data = getData(n);
        int expectTestSize = n/nsplits;
        int expectTrainSize = n-expectTestSize;
        KFoldSplitter<MockOutput> kf = new KFoldSplitter<>(nsplits, 3);
        Iterator<KFoldSplitter.TrainTestFold<MockOutput>> iter = kf.split(data, true);
        int ct = 0;
        while (iter.hasNext()) {
            KFoldSplitter.TrainTestFold<MockOutput> fold = iter.next();
            assertEquals(expectTrainSize, fold.train.size());
            assertEquals(expectTestSize, fold.test.size());
            ct++;
        }
        assertEquals(nsplits, ct);
    }