001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.0).
003 * Copyright (c) 2007-2024 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.util.Objects.requireNonNull;
023
024import java.util.function.Function;
025
026import io.jenetics.Gene;
027
028/**
029 * The evolution interceptor allows updating the {@link EvolutionStart} object,
030 * <em>before</em> the evolution start, and update the {@link EvolutionResult}
031 * object <em>after</em> the evolution.
032 *
033 * @see EvolutionResult#toUniquePopulation()
034 * @see Engine.Builder#interceptor(EvolutionInterceptor)
035 *
036 * @param <G> the gene type
037 * @param <C> the fitness result type
038 *
039 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
040 * @since 6.0
041 * @version 6.0
042 */
043public interface EvolutionInterceptor<
044        G extends Gene<?, G>,
045        C extends Comparable<? super C>
046> {
047
048        /**
049         * This method is called right before the evaluation of a generation is
050         * started.
051         *
052         * @param start the evolution start object
053         * @return the possible <em>update</em> evolution start object
054         * @throws NullPointerException if the evolution {@code start} object is
055         *         {@code null}
056         */
057        default EvolutionStart<G, C> before(final EvolutionStart<G, C> start) {
058                return start;
059        }
060
061        /**
062         * This method is called after the evaluation of a generation. If this
063         * method alters the evolution result object, the population within this
064         * result object is re-evaluated.
065         *
066         * @param result the evolution result object to update
067         * @return the possible <em>updated</em> evolution result object
068         * @throws NullPointerException if the evolution {@code result} object is
069         *         {@code null}
070         */
071        default EvolutionResult<G, C> after(final EvolutionResult<G, C> result) {
072                return result;
073        }
074
075        /**
076         * Composes {@code this} interceptor with the {@code other} one. The
077         * {@link #before(EvolutionStart)} of {@code this} interceptor is called
078         * <em>after</em> the {@code before} method of the {@code other} interceptor.
079         * And the {@link #after(EvolutionResult)} of {@code this} interceptor is
080         * called <em>before</em> the {@code after} method of the {@code other}
081         * interceptor.
082         *
083         * @param other the other, composing interceptor
084         * @return a new, composed interceptor
085         * @throws NullPointerException if the {@code other} interceptor is
086         *         {@code null}
087         */
088        default EvolutionInterceptor<G, C>
089        compose(final EvolutionInterceptor<G, C> other) {
090                requireNonNull(other);
091                return EvolutionInterceptor.of(
092                        start -> before(other.before(start)),
093                        result -> other.after(after(result))
094                );
095        }
096
097        /**
098         * Create a new interceptor instance with the given {@code before} and
099         * {@code after} functions.
100         *
101         * @param before the function executed before each evolution step
102         * @param after the function executed after each evolution step
103         * @param <G> the gene type
104         * @param <C> the fitness result type
105         * @return a new interceptor instance with the given interceptor functions
106         * @throws NullPointerException if one of the functions is {@code null}
107         */
108        static <G extends Gene<?, G>, C extends Comparable<? super C>>
109        EvolutionInterceptor<G, C> of(
110                final Function<? super EvolutionStart<G, C>, EvolutionStart<G, C>> before,
111                final Function<? super EvolutionResult<G, C>, EvolutionResult<G, C>> after
112        ) {
113                requireNonNull(before);
114                requireNonNull(after);
115
116                return new EvolutionInterceptor<>() {
117                        @Override
118                        public EvolutionStart<G, C> before(final EvolutionStart<G, C> start) {
119                                return before.apply(start);
120                        }
121
122                        @Override
123                        public EvolutionResult<G, C> after(final EvolutionResult<G, C> result) {
124                                return after.apply(result);
125                        }
126                };
127        }
128
129        /**
130         * Create a new interceptor instance with the given {@code before} function.
131         *
132         * @param before the function executed before each evolution step
133         * @param <G> the gene type
134         * @param <C> the fitness result type
135         * @return a new interceptor instance with the given interceptor function
136         * @throws NullPointerException if the function is {@code null}
137         */
138        static <G extends Gene<?, G>, C extends Comparable<? super C>>
139        EvolutionInterceptor<G, C>
140        ofBefore(final Function<? super EvolutionStart<G, C>, EvolutionStart<G, C>> before) {
141                return EvolutionInterceptor.of(before, Function.identity());
142        }
143
144        /**
145         * Create a new interceptor instance with the given {@code after} function.
146         *
147         * @param after the function executed after each evolution step
148         * @param <G> the gene type
149         * @param <C> the fitness result type
150         * @return a new interceptor instance with the given interceptor function
151         * @throws NullPointerException if the function is {@code null}
152         */
153        static <G extends Gene<?, G>, C extends Comparable<? super C>>
154        EvolutionInterceptor<G, C>
155        ofAfter(final Function<? super EvolutionResult<G, C>, EvolutionResult<G, C>> after) {
156                return EvolutionInterceptor.of(Function.identity(), after);
157        }
158
159        /**
160         * Return an interceptor object which does nothing.
161         *
162         * @param <G> the gene type
163         * @param <C> the fitness result type
164         * @return a new <em>identity</em> interceptor
165         */
166        static <G extends Gene<?, G>, C extends Comparable<? super C>>
167        EvolutionInterceptor<G, C> identity() {
168                return EvolutionInterceptor.of(Function.identity(), Function.identity());
169        }
170
171}