SPEA2Replacement.java

package net.bmahe.genetics4j.moo.spea2.spec.replacement;

import java.util.Comparator;
import java.util.Optional;
import java.util.function.BiFunction;

import org.immutables.value.Value;

import net.bmahe.genetics4j.core.Genotype;
import net.bmahe.genetics4j.core.spec.replacement.ReplacementStrategy;
import net.bmahe.genetics4j.moo.FitnessVector;

@Value.Immutable
public abstract class SPEA2Replacement<T extends Comparable<T>> implements ReplacementStrategy {

	/**
	 * Defines the Pareto dominance relation
	 * 
	 * @return
	 */
	@Value.Default
	public Comparator<T> dominance() {
		return (a, b) -> a.compareTo(b);
	}

	/**
	 * Comparator used for deduplication of solution prior to processing
	 * <p>
	 * If not specified, it defaults to not do any deduplication
	 * 
	 * @return
	 */
	@Value.Default
	public Optional<Comparator<Genotype>> deduplicate() {
		return Optional.empty();
	}

	/**
	 * Determine the k-nearest distance to compute.
	 * <p>
	 * It will default to sqrt(|archive| + |population|)
	 * 
	 * @return
	 */
	@Value.Default
	public Optional<Integer> k() {
		return Optional.empty();
	}

	/**
	 * Define how to compute distances in objective space between two solutions
	 * 
	 * @return Distance
	 */
	@Value.Parameter
	public abstract BiFunction<T, T, Double> distance();

	public static class Builder<T extends Comparable<T>> extends ImmutableSPEA2Replacement.Builder<T> {
	}

	public static <U extends Comparable<U>> Builder<U> builder() {
		return new Builder<U>();
	}

	/**
	 * Factory method to instantiate a SPEA2Selection when fitness is defined as a
	 * FitnessVector of a Number
	 * 
	 * @param <U>         Type of the fitness measurement
	 * @param deduplicate Deduplicator comparator. Null value with disable
	 *                    deduplication
	 * @return A new instance of SPEA2Replacement
	 */
	public static <U extends Number & Comparable<U>> SPEA2Replacement<FitnessVector<U>>
			ofFitnessVector(final Comparator<Genotype> deduplicate) {

		final var builder = new Builder<FitnessVector<U>>();
		builder.deduplicate(Optional.ofNullable(deduplicate));

		builder.distance((fv1, fv2) -> {

			final int dimensions = fv1.dimensions();

			double sum = 0.0;
			for (int i = 0; i < dimensions; i++) {
				final double v1 = fv1.get(i).doubleValue();
				final double v2 = fv2.get(i).doubleValue();

				sum += (v2 - v1) * (v2 - v1);
			}

			return Math.sqrt(sum);
		});

		return builder.build();
	}

	/**
	 * Factory method to instantiate a SPEA2Selection when fitness is defined as a
	 * FitnessVector of a Number
	 * 
	 * @param <U> Type of the fitness measurement
	 * @return A new instance of SPEA2Replacement
	 */
	public static <U extends Number & Comparable<U>> SPEA2Replacement<FitnessVector<U>> ofFitnessVector() {

		return ofFitnessVector(null);
	}
}