/*
 * Java Genetic Algorithm Library (@__identifier__@).
 * Copyright (c) @__year__@ Franz Wilhelmstötter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
 */
package io.jenetics.ext.moea;

import static java.lang.Math.PI;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.String.format;

import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.testng.Assert;
import org.testng.annotations.Test;

import io.jenetics.DoubleGene;
import io.jenetics.Optimize;
import io.jenetics.Phenotype;
import io.jenetics.Selector;
import io.jenetics.engine.Codecs;
import io.jenetics.engine.Problem;
import io.jenetics.util.DoubleRange;
import io.jenetics.util.ISeq;

/**
 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
 */
public class UFTournamentSelectorTest {

	private static final Problem<double[], DoubleGene, Vec<double[]>> PROBLEM = Problem.of(
		v -> Vec.of(new double[]{v[0]*cos(v[1]), v[0]*sin(v[1])}),
		Codecs.ofVector(
			DoubleRange.of(0, 1),
			DoubleRange.of(0, 2*PI)
		)
	);

	@Test
	public void selectMax() {
		final Selector<DoubleGene, Vec<double[]>> selector =
			UFTournamentSelector.ofVec();

		final ISeq<Phenotype<DoubleGene, Vec<double[]>>> population =
			Stream.generate(this::phenotype)
				.limit(2000)
				.collect(ISeq.toISeq());

		final ISeq<Phenotype<DoubleGene, Vec<double[]>>> selected =
			selector.select(population, 100, Optimize.MAXIMUM);

		/*
		selected.stream().limit(100)
			.map(Phenotype::getFitness)
			.forEach(f -> System.out.println(f.data()[0] + " " + f.data()[1]));
		*/

		final double mean = selected.stream()
			.map(Phenotype::getFitness)
			.mapToDouble(NSGA2SelectorTest::dist)
			.sum()/selected.size();

		Assert.assertTrue(mean > 0.16, format("Expect mean > 0.16: %s", mean));

		Assert.assertEquals(
			selected.stream()
				.map(Phenotype::getFitness)
				.collect(Collectors.toSet())
				.size(),
			selected.size()
		);
	}

	@Test
	public void selectMin() {
		final Selector<DoubleGene, Vec<double[]>> selector =
			UFTournamentSelector.ofVec();


		final ISeq<Phenotype<DoubleGene, Vec<double[]>>> population =
			Stream.generate(this::phenotype)
				.limit(2000)
				.collect(ISeq.toISeq());

		final ISeq<Phenotype<DoubleGene, Vec<double[]>>> selected =
			selector.select(population, 100, Optimize.MINIMUM);

		final double mean = selected.stream()
			.map(Phenotype::getFitness)
			.mapToDouble(NSGA2SelectorTest::dist)
			.sum()/selected.size();

		Assert.assertTrue(mean < -0.16, format("Expect mean < -0.16: %s", mean));

		Assert.assertEquals(
			selected.stream()
				.map(Phenotype::getFitness)
				.collect(Collectors.toSet())
				.size(),
			selected.size()
		);
	}

	private Phenotype<DoubleGene, Vec<double[]>> phenotype() {
		return Phenotype.of(
			PROBLEM.codec().encoding().newInstance(),
			1L,
			gt -> PROBLEM.fitness().apply(PROBLEM.codec().decode(gt))
		);
	}

}

@@ -1026,23 +1026,97 @@
 tng.
-annotations.Tes
+ITestResult;%0Aimport org.testng.annotations.Test;%0Aimport org.testng.util.RetryAnalyzerCoun
 t;%0A%0A
@@ -1505,16 +1505,169 @@
 Test %7B%0A%0A
+%09static final class Retry extends RetryAnalyzerCount %7B%0A%09%09@Override%0A%09%09public boolean retryMethod(ITestResult result) %7B%0A%09%09%09return getCount() %3C= 1;%0A%09%09%7D%0A%09%7D%0A%0A
 %09private
@@ -1886,32 +1886,61 @@
 %0A%09%09)%0A%09);%0A%0A%09@Test
+(retryAnalyzer = Retry.class)
 %0A%09public void se
@@ -2619,17 +2619,17 @@
 an %3E 0.1
-6
+5
 , format
@@ -2647,17 +2647,17 @@
 an %3E 0.1
-6
+5
 : %25s%22, m
@@ -2820,16 +2820,45 @@
 %0A%0A%09@Test
+(retryAnalyzer = Retry.class)
 %0A%09public
@@ -3403,17 +3403,17 @@
 n %3C -0.1
-6
+5
 , format
@@ -3436,9 +3436,9 @@
 -0.1
-6
+5
 : %25s

Make tests more robust.