001/*
002 * Java Genetic Algorithm Library (jenetics-9.1.0).
003 * Copyright (c) 2007-2026 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020package io.jenetics.engine;
021
022import static java.lang.String.format;
023import static java.util.Objects.requireNonNull;
024import static io.jenetics.internal.util.SerialIO.readLong;
025import static io.jenetics.internal.util.SerialIO.writeLong;
026
027import java.io.IOException;
028import java.io.InvalidObjectException;
029import java.io.ObjectInput;
030import java.io.ObjectInputStream;
031import java.io.ObjectOutput;
032import java.io.Serial;
033import java.io.Serializable;
034import java.util.Objects;
035
036import io.jenetics.Gene;
037import io.jenetics.Phenotype;
038import io.jenetics.internal.util.Requires;
039import io.jenetics.util.ISeq;
040
041/**
042 * Represents a state of the GA at the start of an evolution step.
043 *
044 * @see EvolutionResult
045 * @see EvolutionInit
046 * @see EvolutionStreamable#stream(EvolutionStart)
047 *
048 * @param <G> the gene type
049 * @param <C> the fitness type
050 *
051 * @implNote
052 * This class is immutable and thread-safe.
053 *
054 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
055 * @since 3.1
056 * @version 6.0
057 */
058public final class EvolutionStart<
059        G extends Gene<?, G>,
060        C extends Comparable<? super C>
061>
062        implements Serializable
063{
064
065        @Serial
066        private static final long serialVersionUID = 2L;
067
068        private final ISeq<Phenotype<G, C>> _population;
069        private final long _generation;
070
071        private final boolean _dirty;
072
073        EvolutionStart(
074                final ISeq<Phenotype<G, C>> population,
075                final long generation,
076                final boolean dirty
077        ) {
078                _population = requireNonNull(population);
079                _generation = Requires.positive(generation);
080                _dirty = dirty;
081        }
082
083        /**
084         * Return the population before the evolution step.
085         *
086         * @return the start population
087         */
088        public ISeq<Phenotype<G, C>> population() {
089                return _population;
090        }
091
092        /**
093         * Return the generation of the start population.
094         *
095         * @return the start generation
096         */
097        public long generation() {
098                return _generation;
099        }
100
101        /**
102         * Indicates whether the population is guaranteed to be evaluated. If this
103         * flag is {@code true}, the population possibly contains unevaluated
104         * individuals.
105         *
106         * @return {@code false}, if it is guaranteed that all individuals has
107         *         already been evaluated, {@code true} otherwise
108         */
109        boolean isDirty() {
110                return _dirty;
111        }
112
113        @Override
114        public int hashCode() {
115                return Objects.hash(_generation, _population);
116        }
117
118        @Override
119        public boolean equals(final Object obj) {
120                return obj instanceof EvolutionStart<?, ?> other &&
121                        _generation == other._generation &&
122                        Objects.equals(_population, other._population);
123        }
124
125        @Override
126        public String toString() {
127                return format(
128                        "EvolutionStart[population-size=%d, generation=%d]",
129                        _population.size(), _generation
130                );
131        }
132
133        /**
134         * Create a new evolution start object with the given population and for the
135         * given generation.
136         *
137         * @param <G> the gene type
138         * @param <C> the fitness type
139         * @param population the start population.
140         * @param generation the start generation of the population
141         * @return a new evolution start object
142         * @throws java.lang.NullPointerException if the given {@code population} is
143         *         {@code null}.
144         * @throws IllegalArgumentException if the given {@code generation} is
145         *         smaller then one
146         */
147        public static <G extends Gene<?, G>, C extends Comparable<? super C>>
148        EvolutionStart<G, C> of(
149                final ISeq<Phenotype<G, C>> population,
150                final long generation
151        ) {
152                return new EvolutionStart<>(population, generation, true);
153        }
154
155        /**
156         * An empty evolution start object, which can be used as initial evolution
157         * value. The evolution {@link Engine} is then responsible for creating the
158         * proper initial population,
159         *
160         * @since 5.1
161         *
162         * @param <G> the gene type
163         * @param <C> the fitness type
164         * @return an empty evolution start object
165         */
166        public static <G extends Gene<?, G>, C extends Comparable<? super C>>
167        EvolutionStart<G, C> empty() {
168                return new EvolutionStart<>(ISeq.empty(), 1, false);
169        }
170
171
172        /* *************************************************************************
173         *  Java object serialization
174         * ************************************************************************/
175
176        @Serial
177        private Object writeReplace() {
178                return new SerialProxy(SerialProxy.EVOLUTION_START, this);
179        }
180
181        @Serial
182        private void readObject(final ObjectInputStream stream)
183                throws InvalidObjectException
184        {
185                throw new InvalidObjectException("Serialization proxy required.");
186        }
187
188        void write(final ObjectOutput out) throws IOException {
189                out.writeObject(_population);
190                writeLong(_generation, out);
191        }
192
193        @SuppressWarnings({"unchecked", "rawtypes"})
194        static Object read(final ObjectInput in)
195                throws IOException, ClassNotFoundException
196        {
197                return new EvolutionStart(
198                        (ISeq)in.readObject(),
199                        readLong(in),
200                        true
201                );
202        }
203
204}