Fitness.java

package net.bmahe.genetics4j.core;

import java.util.Objects;
import java.util.function.Function;

import org.apache.commons.lang3.Validate;

/**
 * Functional interface for evaluating the fitness of a genotype in an evolutionary algorithm.
 * 
 * <p>The fitness function is a crucial component of evolutionary algorithms as it determines the quality or performance
 * of individual solutions. It maps a genotype to a fitness value that can be used for selection, ranking, and
 * determining evolutionary progress.
 * 
 * <p>Implementations should be:
 * <ul>
 * <li><strong>Deterministic</strong>: The same genotype should always produce the same fitness value</li>
 * <li><strong>Thread-safe</strong>: May be called concurrently from multiple threads</li>
 * <li><strong>Fast</strong>: Called frequently during evolution, performance matters</li>
 * </ul>
 * 
 * <p>Common fitness function patterns:
 * <ul>
 * <li><strong>Minimization</strong>: Lower values indicate better solutions (errors, costs)</li>
 * <li><strong>Maximization</strong>: Higher values indicate better solutions (profits, accuracy)</li>
 * <li><strong>Multi-objective</strong>: Use FitnessVector from the MOO module for multiple objectives</li>
 * </ul>
 * 
 * @param <T> the type of the fitness value, must be comparable for selection operations
 * @see Genotype
 * @see Individual
 * @see net.bmahe.genetics4j.core.evaluation.FitnessEvaluator
 */
@FunctionalInterface
public interface Fitness<T extends Comparable<T>> {

	/**
	 * Computes the fitness value for the specified genotype.
	 * 
	 * <p>This method should evaluate how well the genotype solves the problem and return a comparable fitness value. The
	 * interpretation of "better" depends on whether the optimization is for minimization or maximization.
	 * 
	 * @param genotype the genotype to evaluate
	 * @return the fitness value representing the quality of the genotype
	 * @throws RuntimeException if evaluation fails due to invalid genotype or computation error
	 */
	T compute(Genotype genotype);

	/**
	 * Creates a fitness function that evaluates a specific chromosome within a genotype.
	 *
	 * <p>This utility method simplifies fitness evaluation when the fitness depends on only one chromosome from the
	 * genotype. It extracts the chromosome at the specified index and applies the provided fitness function to it.
	 *
	 * <p>This is particularly useful for:
	 * <ul>
	 * <li>Single-chromosome problems where genotype contains only one chromosome</li>
	 * <li>Multi-chromosome problems where fitness depends on one specific chromosome</li>
	 * <li>Compositional fitness functions that evaluate chromosomes independently</li>
	 * </ul>
	 *
	 * @param <U>               the type of the chromosome to evaluate
	 * @param <V>               the type of the fitness value, must be comparable
	 * @param chromosomeIndex   the zero-based index of the chromosome to evaluate within the genotype
	 * @param chromosomeFitness the function that computes fitness for the extracted chromosome
	 * @return a fitness function that evaluates the specified chromosome
	 * @throws IllegalArgumentException if chromosomeIndex is negative
	 * @throws NullPointerException     if chromosomeFitness is null
	 * @throws ClassCastException       at runtime if the chromosome at the specified index cannot be cast to type U
	 * @throws IllegalArgumentException at runtime if chromosomeIndex exceeds the genotype size
	 */
	static <U, V extends Comparable<V>> Fitness<V> forChromosome(final int chromosomeIndex,
			final Function<U, V> chromosomeFitness) {
		Validate.isTrue(chromosomeIndex >= 0);
		Objects.requireNonNull(chromosomeFitness);

		return genotype -> {
			@SuppressWarnings("unchecked")
			final U chromosome = (U) genotype.getChromosome(chromosomeIndex);

			return chromosomeFitness.apply(chromosome);
		};
	}

}