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 }