View Javadoc
1   package net.bmahe.genetics4j.core;
2   
3   import java.util.Objects;
4   import java.util.function.Function;
5   
6   import org.apache.commons.lang3.Validate;
7   
8   /**
9    * Functional interface for evaluating the fitness of a genotype in an evolutionary algorithm.
10   * 
11   * <p>The fitness function is a crucial component of evolutionary algorithms as it determines the quality or performance
12   * of individual solutions. It maps a genotype to a fitness value that can be used for selection, ranking, and
13   * determining evolutionary progress.
14   * 
15   * <p>Implementations should be:
16   * <ul>
17   * <li><strong>Deterministic</strong>: The same genotype should always produce the same fitness value</li>
18   * <li><strong>Thread-safe</strong>: May be called concurrently from multiple threads</li>
19   * <li><strong>Fast</strong>: Called frequently during evolution, performance matters</li>
20   * </ul>
21   * 
22   * <p>Common fitness function patterns:
23   * <ul>
24   * <li><strong>Minimization</strong>: Lower values indicate better solutions (errors, costs)</li>
25   * <li><strong>Maximization</strong>: Higher values indicate better solutions (profits, accuracy)</li>
26   * <li><strong>Multi-objective</strong>: Use FitnessVector from the MOO module for multiple objectives</li>
27   * </ul>
28   * 
29   * @param <T> the type of the fitness value, must be comparable for selection operations
30   * @see Genotype
31   * @see Individual
32   * @see net.bmahe.genetics4j.core.evaluation.FitnessEvaluator
33   */
34  @FunctionalInterface
35  public interface Fitness<T extends Comparable<T>> {
36  
37  	/**
38  	 * Computes the fitness value for the specified genotype.
39  	 * 
40  	 * <p>This method should evaluate how well the genotype solves the problem and return a comparable fitness value. The
41  	 * interpretation of "better" depends on whether the optimization is for minimization or maximization.
42  	 * 
43  	 * @param genotype the genotype to evaluate
44  	 * @return the fitness value representing the quality of the genotype
45  	 * @throws RuntimeException if evaluation fails due to invalid genotype or computation error
46  	 */
47  	T compute(Genotype genotype);
48  
49  	/**
50  	 * Creates a fitness function that evaluates a specific chromosome within a genotype.
51  	 *
52  	 * <p>This utility method simplifies fitness evaluation when the fitness depends on only one chromosome from the
53  	 * genotype. It extracts the chromosome at the specified index and applies the provided fitness function to it.
54  	 *
55  	 * <p>This is particularly useful for:
56  	 * <ul>
57  	 * <li>Single-chromosome problems where genotype contains only one chromosome</li>
58  	 * <li>Multi-chromosome problems where fitness depends on one specific chromosome</li>
59  	 * <li>Compositional fitness functions that evaluate chromosomes independently</li>
60  	 * </ul>
61  	 *
62  	 * @param <U>               the type of the chromosome to evaluate
63  	 * @param <V>               the type of the fitness value, must be comparable
64  	 * @param chromosomeIndex   the zero-based index of the chromosome to evaluate within the genotype
65  	 * @param chromosomeFitness the function that computes fitness for the extracted chromosome
66  	 * @return a fitness function that evaluates the specified chromosome
67  	 * @throws IllegalArgumentException if chromosomeIndex is negative
68  	 * @throws NullPointerException     if chromosomeFitness is null
69  	 * @throws ClassCastException       at runtime if the chromosome at the specified index cannot be cast to type U
70  	 * @throws IllegalArgumentException at runtime if chromosomeIndex exceeds the genotype size
71  	 */
72  	static <U, V extends Comparable<V>> Fitness<V> forChromosome(final int chromosomeIndex,
73  			final Function<U, V> chromosomeFitness) {
74  		Validate.isTrue(chromosomeIndex >= 0);
75  		Objects.requireNonNull(chromosomeFitness);
76  
77  		return genotype -> {
78  			@SuppressWarnings("unchecked")
79  			final U chromosome = (U) genotype.getChromosome(chromosomeIndex);
80  
81  			return chromosomeFitness.apply(chromosome);
82  		};
83  	}
84  
85  }