FitnessSharing.java

package net.bmahe.genetics4j.core.postevaluationprocess;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.apache.commons.lang3.Validate;
import org.immutables.value.Value;

import net.bmahe.genetics4j.core.Genotype;
import net.bmahe.genetics4j.core.Individual;
import net.bmahe.genetics4j.core.Population;

@Value.Immutable
public abstract class FitnessSharing<T extends Comparable<T>> implements Function<Population<T>, Population<T>> {

	@Value.Parameter
	public abstract BiFunction<Genotype, Genotype, Double> distance();

	@Value.Parameter
	public abstract Function<Double, Double> sharing();

	@Value.Parameter
	public abstract BiFunction<Individual<T>, Double, T> scaleFitness();

	@Override
	public Population<T> apply(final Population<T> population) {
		Validate.notNull(population);

		if (population.isEmpty()) {
			return population;
		}

		final List<T> newFitness = new ArrayList<>();
		for (int i = 0; i < population.size(); i++) {
			final Genotype genotypeI = population.getGenotype(i);
			final Individual<T> individual = population.getIndividual(i);

			double sumSharing = 0.0d;
			for (int j = 0; j < population.size(); j++) {
				final Genotype genotypeJ = population.getGenotype(j);

				final double distance = distance().apply(genotypeI, genotypeJ);
				final double sharing = sharing().apply(distance);
				sumSharing += sharing;
			}

			final T newFitnessI = scaleFitness().apply(individual, sumSharing);
			newFitness.add(newFitnessI);
		}

		return Population.<T>of(population.getAllGenotypes(), newFitness);
	}

	public static FitnessSharing<Double> of(final BiFunction<Genotype, Genotype, Double> distance,
			final Function<Double, Double> sharing) {
		return ImmutableFitnessSharing
				.of(distance, sharing, (individual, sumSharing) -> individual.fitness() / sumSharing);
	}

	public static FitnessSharing<Double> ofStandard(final BiFunction<Genotype, Genotype, Double> distance,
			final double sigma) {
		return FitnessSharing.of(distance, (d) -> {
			if (d < 0.0 || d > sigma) {
				return 0.0;
			}

			return 1 - d / sigma;
		});
	}

	public static FitnessSharing<Double> ofStandard(final BiFunction<Genotype, Genotype, Double> distance,
			final double sigma, final double alpha) {
		return FitnessSharing.of(distance, (d) -> {
			if (d < 0.0 || d > sigma) {
				return 0.0;
			}

			return 1 - Math.pow(d / sigma, alpha);
		});
	}

	public static FitnessSharing<Float> ofFloatFitness(final BiFunction<Genotype, Genotype, Double> distance,
			final Function<Double, Double> sharing) {
		return ImmutableFitnessSharing
				.of(distance, sharing, (individual, sumSharing) -> (float) (individual.fitness() / sumSharing));
	}
}