package ru.ifmo.nds.jmh.main;

import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import ru.ifmo.nds.IdCollection;
import ru.ifmo.nds.NonDominatedSorting;

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Timeout(time = 1, timeUnit = TimeUnit.HOURS)
@Warmup(time = 6, iterations = 1)
@Measurement(time = 1, iterations = 1)
@Fork(11)
public class WorstCaseCollection {
    private static final int INSTANCES = 4;

    @Param("The algorithm should be set explicitly")
    private String algorithmId;
    private NonDominatedSorting sorting;
    private double[][][] dataset;
    private int[] ranks;

    @Param({"10", "100", "1000", "10000"})
    private int n;

    @Param({"2", "3", "5", "10"})
    private int d;

    @Setup
    public void initializeSorterAndData() {
        sorting = IdCollection.getNonDominatedSortingFactory(algorithmId).getInstance(n, d);
        ranks = new int[n];
        dataset = new double[INSTANCES][n][d];
        Random random = new Random(Arrays.hashCode(new int[] {n, d}));

        fillCorrelated(random, dataset[0], 0);
        fillCorrelated(random, dataset[1], 1);
        fillCorrelated(random, dataset[2], d - 1);
        fillMultipleLayers(random, dataset[3]);
    }

    private void fillMultipleLayers(Random random, double[][] instance) {
        int points = n;
        int fronts = n / 3;
        int pointsInLayer = (points + fronts - 1) / fronts;
        for (int i = 0; i < pointsInLayer; ++i) {
            for (int j = 1; j < d; ++j) {
                instance[i][j] = random.nextDouble();
                instance[i][0] -= instance[i][j];
            }
            instance[i][0] += 0.5 * d;
        }
    }

    private void fillCorrelated(Random random, double[][] instance, int x) {
        for (int i = 0; i < n; ++i) {
            double first = random.nextDouble();
            for (int k = 0; k < d; ++k) {
                instance[i][k] = k == x ? -first : first;
            }
        }
        Collections.shuffle(Arrays.asList(instance), random);
    }

    @OperationsPerInvocation(INSTANCES)
    @Benchmark
    public void benchmarkCall(Blackhole blackhole) {
        for (double[][] instance : dataset) {
            Arrays.fill(ranks, 0);
            sorting.sort(instance, ranks);
            blackhole.consume(ranks);
        }
    }

    @TearDown
    public void destroySorter() {
        sorting.close();
    }
}

@@ -601,9 +601,9 @@
 S = 
-4
+9
 ;%0A%0A 
@@ -822,17 +822,8 @@
 000%22
-, %2210000%22
 %7D)%0A 
@@ -1383,16 +1383,467 @@
 et%5B3%5D);%0A
+        fillMultipleLayers(random, dataset%5B4%5D);%0A        fillMultipleLayers(random, dataset%5B5%5D);%0A        fillUniform(random, dataset%5B6%5D);%0A        fillUniform(random, dataset%5B7%5D);%0A        fillUniform(random, dataset%5B8%5D);%0A    %7D%0A%0A    private void fillUniform(Random random, double%5B%5D%5B%5D instance) %7B%0A        for (int i = 0; i %3C n; ++i) %7B%0A            for (int j = 0; j %3C d; ++j) %7B%0A                instance%5Bi%5D%5Bj%5D = random.nextDouble();%0A            %7D%0A        %7D%0A
     %7D%0A%0A 
@@ -2276,16 +2276,16 @@
 .5 * d;%0A
-
         
@@ -2278,32 +2278,336 @@
  * d;%0A        %7D%0A
+        for (int i = pointsInLayer; i %3C points; ++i) %7B%0A            System.arraycopy(instance%5Bi - pointsInLayer%5D, 0, instance%5Bi%5D, 0, d);%0A            for (int j = 0; j %3C d; ++j) %7B%0A                instance%5Bi%5D%5Bj%5D += 1e-8;%0A            %7D%0A        %7D%0A        Collections.shuffle(Arrays.asList(instance), random);%0A
     %7D%0A%0A    priva

Fix and update worst-case collection; reduce the size limit.