EvolutionDurations.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.2.0).
003  * Copyright (c) 2007-2021 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  */
020 package io.jenetics.engine;
021 
022 import static java.util.Objects.requireNonNull;
023 import static io.jenetics.internal.util.Hashes.hash;
024 import static io.jenetics.internal.util.SerialIO.readInt;
025 import static io.jenetics.internal.util.SerialIO.readLong;
026 import static io.jenetics.internal.util.SerialIO.writeInt;
027 import static io.jenetics.internal.util.SerialIO.writeLong;
028 
029 import java.io.DataInput;
030 import java.io.DataOutput;
031 import java.io.IOException;
032 import java.io.InvalidObjectException;
033 import java.io.ObjectInput;
034 import java.io.ObjectInputStream;
035 import java.io.ObjectOutput;
036 import java.io.Serializable;
037 import java.time.Duration;
038 import java.util.Objects;
039 
040 /**
041  * This class contains timing information about one evolution step.
042  *
043  * @implNote
044  * This class is immutable and thread-safe.
045  *
046  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
047  @since 3.0
048  @version 6.0
049  */
050 public final /*record*/ class EvolutionDurations
051     implements
052         Comparable<EvolutionDurations>,
053         Serializable
054 {
055     private static final long serialVersionUID = 2L;
056 
057     /**
058      * Constant for zero evolution durations.
059      */
060     public static final EvolutionDurations ZERO = EvolutionDurations.of(
061         Duration.ZERO,
062         Duration.ZERO,
063         Duration.ZERO,
064         Duration.ZERO,
065         Duration.ZERO,
066         Duration.ZERO,
067         Duration.ZERO
068     );
069 
070     private final Duration _offspringSelectionDuration;
071     private final Duration _survivorsSelectionDuration;
072     private final Duration _offspringAlterDuration;
073     private final Duration _offspringFilterDuration;
074     private final Duration _survivorFilterDuration;
075     private final Duration _evaluationDuration;
076     private final Duration _evolveDuration;
077 
078     EvolutionDurations(
079         final Duration offspringSelectionDuration,
080         final Duration survivorsSelectionDuration,
081         final Duration offspringAlterDuration,
082         final Duration offspringFilterDuration,
083         final Duration survivorFilterDuration,
084         final Duration evaluationDuration,
085         final Duration evolveDuration
086     ) {
087         _offspringSelectionDuration = requireNonNull(offspringSelectionDuration);
088         _survivorsSelectionDuration = requireNonNull(survivorsSelectionDuration);
089         _offspringAlterDuration = requireNonNull(offspringAlterDuration);
090         _offspringFilterDuration = requireNonNull(offspringFilterDuration);
091         _survivorFilterDuration = requireNonNull(survivorFilterDuration);
092         _evaluationDuration = requireNonNull(evaluationDuration);
093         _evolveDuration = requireNonNull(evolveDuration);
094     }
095 
096     /**
097      * Return the duration needed for selecting the offspring population.
098      *
099      @return the duration needed for selecting the offspring population
100      */
101     public Duration offspringSelectionDuration() {
102         return _offspringSelectionDuration;
103     }
104 
105     /**
106      * Return the duration needed for selecting the survivors population.
107      *
108      @return the duration needed for selecting the survivors population
109      */
110     public Duration survivorsSelectionDuration() {
111         return _survivorsSelectionDuration;
112     }
113 
114     /**
115      * Return the duration needed for altering the offspring population.
116      *
117      @return the duration needed for altering the offspring population
118      */
119     public Duration offspringAlterDuration() {
120         return _offspringAlterDuration;
121     }
122 
123     /**
124      * Return the duration needed for removing and replacing invalid offspring
125      * individuals.
126      *
127      @return the duration needed for removing and replacing invalid offspring
128      *         individuals
129      */
130     public Duration offspringFilterDuration() {
131         return _offspringFilterDuration;
132     }
133 
134     /**
135      * Return the duration needed for removing and replacing old and invalid
136      * survivor individuals.
137      *
138      @return the duration needed for removing and replacing old and invalid
139      *         survivor individuals
140      */
141     public Duration survivorFilterDuration() {
142         return _survivorFilterDuration;
143     }
144 
145     /**
146      * Return the duration needed for evaluating the fitness function of the new
147      * individuals.
148      *
149      @return the duration needed for evaluating the fitness function of the new
150      *         individuals
151      */
152     public Duration evaluationDuration() {
153         return _evaluationDuration;
154     }
155 
156     /**
157      * Return the duration needed for the whole evolve step.
158      *
159      @return the duration needed for the whole evolve step
160      */
161     public Duration evolveDuration() {
162         return _evolveDuration;
163     }
164 
165     /**
166      * Returns a copy of this duration with the specified duration added.
167      <p>
168      * This instance is immutable and unaffected by this method call.
169      *
170      @param other the duration to add
171      @return a {@code EvolutionDurations} based on this duration with the
172      *         specified duration added
173      @throws NullPointerException if the {@code other} duration is {@code null}
174      @throws ArithmeticException if numeric overflow occurs
175      */
176     public EvolutionDurations plus(final EvolutionDurations other) {
177         requireNonNull(other);
178         return of(
179             _offspringSelectionDuration.plus(other._offspringSelectionDuration),
180             _survivorsSelectionDuration.plus(other._survivorsSelectionDuration),
181             _offspringAlterDuration.plus(other._offspringAlterDuration),
182             _offspringFilterDuration.plus(other._offspringFilterDuration),
183             _survivorFilterDuration.plus(other._survivorFilterDuration),
184             _evaluationDuration.plus(other._evaluationDuration),
185             _evolveDuration.plus(other._evolveDuration)
186         );
187     }
188 
189     EvolutionDurations plusEvaluation(final Duration duration) {
190         return of(
191             _offspringSelectionDuration,
192             _survivorsSelectionDuration,
193             _offspringAlterDuration,
194             _offspringFilterDuration,
195             _survivorFilterDuration,
196             _evaluationDuration.plus(duration),
197             _evolveDuration
198         );
199     }
200 
201     EvolutionDurations plusEvolve(final Duration duration) {
202         return of(
203             _offspringSelectionDuration,
204             _survivorsSelectionDuration,
205             _offspringAlterDuration,
206             _offspringFilterDuration,
207             _survivorFilterDuration,
208             _evaluationDuration,
209             _evolveDuration.plus(duration)
210         );
211     }
212 
213     /**
214      * Compares two durations objects. Only the {@link #evolveDuration()}
215      * property is taken into account for the comparison.
216      *
217      @param other the other durations object this object is compared with
218      @return a integer smaller/equal/greater than 0 if the
219      *         {@link #evolveDuration()} property of {@code this} object is
220      *         smaller/equal/greater than the corresponding property of the
221      *         {@code other} project.
222      */
223     @Override
224     public int compareTo(final EvolutionDurations other) {
225         return _evolveDuration.compareTo(other._evolveDuration);
226     }
227 
228     @Override
229     public int hashCode() {
230         return
231             hash(_offspringSelectionDuration,
232             hash(_survivorFilterDuration,
233             hash(_offspringAlterDuration,
234             hash(_offspringFilterDuration,
235             hash(_survivorsSelectionDuration,
236             hash(_evaluationDuration,
237             hash(_evolveDuration)))))));
238     }
239 
240     @Override
241     public boolean equals(final Object obj) {
242         return obj == this ||
243             obj instanceof EvolutionDurations &&
244             Objects.equals(_offspringSelectionDuration,
245                 ((EvolutionDurations)obj)._offspringSelectionDuration&&
246             Objects.equals(_survivorsSelectionDuration,
247                 ((EvolutionDurations)obj)._survivorsSelectionDuration&&
248             Objects.equals(_offspringAlterDuration,
249                 ((EvolutionDurations)obj)._offspringAlterDuration&&
250             Objects.equals(_offspringFilterDuration,
251                 ((EvolutionDurations)obj)._offspringFilterDuration&&
252             Objects.equals(_survivorFilterDuration,
253                 ((EvolutionDurations)obj)._survivorFilterDuration&&
254             Objects.equals(_evaluationDuration,
255                 ((EvolutionDurations)obj)._evaluationDuration&&
256             Objects.equals(_evolveDuration,
257                 ((EvolutionDurations)obj)._evolveDuration);
258     }
259 
260     /**
261      * Return an new {@code EvolutionDurations} object with the given values.
262      *
263      @param offspringSelectionDuration the duration needed for selecting the
264      *        offspring population
265      @param survivorsSelectionDuration the duration needed for selecting the
266      *        survivors population
267      @param offspringAlterDuration the duration needed for altering the
268      *        offspring population
269      @param offspringFilterDuration the duration needed for removing and
270      *        replacing invalid offspring individuals
271      @param survivorFilterDuration the duration needed for removing and
272      *        replacing old and invalid survivor individuals
273      @param evaluationDuration the duration needed for evaluating the fitness
274      *        function of the new individuals
275      @param evolveDuration the duration needed for the whole evolve step
276      @return an new durations object
277      @throws NullPointerException if one of the arguments is
278      *         {@code null}
279      */
280     public static EvolutionDurations of(
281         final Duration offspringSelectionDuration,
282         final Duration survivorsSelectionDuration,
283         final Duration offspringAlterDuration,
284         final Duration offspringFilterDuration,
285         final Duration survivorFilterDuration,
286         final Duration evaluationDuration,
287         final Duration evolveDuration
288     ) {
289         return new EvolutionDurations(
290             offspringSelectionDuration,
291             survivorsSelectionDuration,
292             offspringAlterDuration,
293             offspringFilterDuration,
294             survivorFilterDuration,
295             evaluationDuration,
296             evolveDuration
297         );
298     }
299 
300 
301     /* *************************************************************************
302      *  Java object serialization
303      * ************************************************************************/
304 
305     private Object writeReplace() {
306         return new Serial(Serial.EVOLUTION_DURATIONS, this);
307     }
308 
309     private void readObject(final ObjectInputStream stream)
310         throws InvalidObjectException
311     {
312         throw new InvalidObjectException("Serialization proxy required.");
313     }
314 
315     void write(final ObjectOutput outthrows IOException {
316         writeDuration(_offspringSelectionDuration, out);
317         writeDuration(_survivorsSelectionDuration, out);
318         writeDuration(_offspringAlterDuration, out);
319         writeDuration(_offspringFilterDuration, out);
320         writeDuration(_survivorFilterDuration, out);
321         writeDuration(_evaluationDuration, out);
322         writeDuration(_evolveDuration, out);
323     }
324 
325     private static void writeDuration(final Duration duration, final DataOutput out)
326         throws IOException
327     {
328         writeLong(duration.getSeconds(), out);
329         writeInt(duration.getNano(), out);
330     }
331 
332     static EvolutionDurations read(final ObjectInput inthrows IOException {
333         return new EvolutionDurations(
334             readDuration(in),
335             readDuration(in),
336             readDuration(in),
337             readDuration(in),
338             readDuration(in),
339             readDuration(in),
340             readDuration(in)
341         );
342     }
343 
344     private static Duration readDuration(final DataInput inthrows IOException {
345         final long seconds = readLong(in);
346         final int nanos = readInt(in);
347         return Duration.ofSeconds(seconds, nanos);
348     }
349 
350 }