View Javadoc
1   package net.bmahe.genetics4j.core;
2   
3   import java.util.Iterator;
4   import java.util.Objects;
5   
6   /**
7    * Iterator implementation for traversing individuals in a population during evolutionary algorithms.
8    * 
9    * <p>PopulationIterator provides a standard Java Iterator interface for accessing individuals in a {@link Population},
10   * combining genotypes with their corresponding fitness values to create complete {@link Individual} instances during
11   * iteration.
12   * 
13   * <p>This iterator enables convenient traversal patterns such as:
14   * <ul>
15   * <li><strong>Enhanced for loops</strong>: Iterate over individuals using for-each syntax</li>
16   * <li><strong>Stream operations</strong>: Convert populations to streams for functional processing</li>
17   * <li><strong>Sequential access</strong>: Process individuals one at a time without loading all into memory</li>
18   * <li><strong>Collection integration</strong>: Use with Java Collection framework methods</li>
19   * </ul>
20   * 
21   * <p>The iterator maintains internal state to track the current position and constructs {@link Individual} objects
22   * on-demand by combining genotypes and fitness values from the underlying population at the same index.
23   * 
24   * <p>Key characteristics:
25   * <ul>
26   * <li><strong>Type safety</strong>: Parameterized with fitness type for compile-time type checking</li>
27   * <li><strong>Lazy evaluation</strong>: Creates Individual objects only when requested</li>
28   * <li><strong>Memory efficient</strong>: Doesn't duplicate population data, references original</li>
29   * <li><strong>Standard interface</strong>: Implements Java Iterator contract completely</li>
30   * </ul>
31   * 
32   * <p>Usage patterns:
33   * 
34   * <pre>{@code
35   * // Enhanced for loop iteration
36   * Population<Double> population = getPopulation();
37   * for (Individual<Double> individual : population) {
38   * 	System.out.println("Fitness: " + individual.fitness());
39   * }
40   * 
41   * // Stream-based processing
42   * population.stream()
43   * 		.filter(individual -> individual.fitness() > threshold)
44   * 		.mapToDouble(Individual::fitness)
45   * 		.average();
46   * 
47   * // Manual iteration
48   * Iterator<Individual<Double>> iterator = population.iterator();
49   * while (iterator.hasNext()) {
50   * 	Individual<Double> individual = iterator.next();
51   * 	processIndividual(individual);
52   * }
53   * }</pre>
54   * 
55   * <p>Thread safety considerations:
56   * <ul>
57   * <li><strong>Single-threaded use</strong>: Iterator instances are not thread-safe</li>
58   * <li><strong>Population stability</strong>: Underlying population should not be modified during iteration</li>
59   * <li><strong>Concurrent iterations</strong>: Multiple iterators can be created for the same population</li>
60   * </ul>
61   * 
62   * @param <T> the type of fitness values in the population, must be comparable for selection operations
63   * @see Population
64   * @see Individual
65   * @see java.util.Iterator
66   */
67  public class PopulationIterator<T extends Comparable<T>> implements Iterator<Individual<T>> {
68  
69  	private final Population<T> population;
70  
71  	private int currentIndex = 0;
72  
73  	/**
74  	 * Constructs a new iterator for the specified population.
75  	 * 
76  	 * <p>Creates an iterator that will traverse all individuals in the given population, starting from index 0 and
77  	 * proceeding sequentially through all individuals.
78  	 * 
79  	 * @param _population the population to iterate over
80  	 * @throws IllegalArgumentException if the population is null
81  	 */
82  	public PopulationIterator(final Population<T> _population) {
83  		Objects.requireNonNull(_population);
84  
85  		this.population = _population;
86  	}
87  
88  	/**
89  	 * Returns {@code true} if there are more individuals to iterate over.
90  	 * 
91  	 * <p>Checks whether the current position is within the bounds of the population. This method can be called multiple
92  	 * times without advancing the iterator position.
93  	 * 
94  	 * @return {@code true} if there are more individuals, {@code false} if all have been visited
95  	 */
96  	@Override
97  	public boolean hasNext() {
98  		return currentIndex < population.size();
99  	}
100 
101 	/**
102 	 * Returns the next individual in the population and advances the iterator position.
103 	 * 
104 	 * <p>Constructs an {@link Individual} by combining the genotype and fitness value at the current position, then
105 	 * advances to the next position for subsequent calls.
106 	 * 
107 	 * @return the next individual in the iteration sequence
108 	 * @throws java.util.NoSuchElementException if there are no more individuals (when {@link #hasNext()} returns false)
109 	 */
110 	@Override
111 	public Individual<T> next() {
112 		final Genotype genotype = population.getGenotype(currentIndex);
113 		final T fitness = population.getFitness(currentIndex);
114 		currentIndex++;
115 		return Individual.of(genotype, fitness);
116 	}
117 }