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;
025import java.util.function.Predicate;
026
027import io.jenetics.Gene;
028import io.jenetics.Genotype;
029import io.jenetics.util.Factory;
030
031/**
032 * This interface extends the {@link Codec} and allows to encode an object from
033 * the problem space to a corresponding {@link Genotype}, which is the
034 * <em>inverse</em> functionality of the codec. The following example shows the
035 * relation between <em>encoder</em> and <em>decoder</em> function must fulfill.
036 * {@snippet lang="java":
037 * final InvertibleCodec<int[], IntegerGene> codec =
038 *     Codecs.ofVector(IntRange.of(0, 100), 6);
039 * final int[] value = new int[]{3, 4, 6, 7, 8, 3};
040 * final Genotype<IntegerGene> gt = codec.encode(value);
041 * assert Arrays.equals(value, codec.decode(gt));
042 * }
043 *
044 * The main usage of an invertible codec is to simplify the definition of
045 * {@link Constraint} objects. Instead of working with the GA classes
046 * ({@link io.jenetics.Phenotype} or {@link Genotype}), it is possible to work
047 * in the <em>native</em> problem domain {@code T}.
048 *
049 * @see Constraint#of(InvertibleCodec, Predicate, Function)
050 * @see RetryConstraint#of(InvertibleCodec, Predicate, Function)
051 * @see RetryConstraint#of(InvertibleCodec, Predicate, int)
052 *
053 * @param <T> the argument type of given problem
054 * @param <G> the {@code Gene} type used for encoding the argument type {@code T}
055 *
056 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
057 * @version 5.2
058 * @since 5.2
059 */
060public interface InvertibleCodec<T, G extends Gene<?, G>> extends Codec<T, G> {
061
062        /**
063         * Return the <em>encoder</em> function which transforms a value from the
064         * <em>native</em> problem domain back to the genotype. This is the
065         * <em>inverse</em> of the {@link #decoder()} function. The following code
066         * snippet shows how a given value in the <em>native</em> problem domain
067         * can be converted into a {@link Genotype} and transformed back.
068         * {@snippet lang="java":
069         * final InvertibleCodec<int[], IntegerGene> codec =
070         *     Codecs.ofVector(IntRange.of(0, 100), 6);
071         * final int[] value = new int[]{3, 4, 6, 7, 8, 3};
072         * final Genotype<IntegerGene> gt = codec.encode(value);
073         * assert Arrays.equals(value, codec.decode(gt));
074         * }
075         *
076         * @see #decoder()
077         * @see #encode(Object)
078         *
079         * @return value encoder function
080         */
081        Function<T, Genotype<G>> encoder();
082
083        /**
084         * Decodes the given {@code value}, which is an element of the <em>native</em>
085         * problem domain, into a {@link Genotype}.
086         *
087         * @param value the value of the <em>native</em> problem domain
088         * @return the genotype, which represents the given {@code value}
089         */
090        default Genotype<G> encode(final T value) {
091                return encoder().apply(value);
092        }
093
094        /**
095         * Create a new {@code InvertibleCodec} with the mapped result type.
096         *
097         * This method can also be used for creating non-trivial codes like split
098         * ranges, as shown in the following example, where only values between
099         * <em>[0, 2)</em> and <em>[8, 10)</em> are valid.
100         * <pre>{@code
101         *   +--+--+--+--+--+--+--+--+--+--+
102         *   |  |  |  |  |  |  |  |  |  |  |
103         *   0  1  2  3  4  5  6  7  8  9  10
104         *   |-----|xxxxxxxxxxxxxxxxx|-----|
105         *      ^  |llllllll|rrrrrrrr|  ^
106         *      |       |        |      |
107         *      +-------+        +------+
108         * }</pre>
109         *
110         * {@snippet lang="java":
111         * final InvertibleCodec<Double, DoubleGene> codec = Codecs
112         *     .ofScalar(DoubleRange.of(0, 10))
113         *     .map(v -> {
114         *             if (v >= 2 && v < 8) {
115         *                 return v < 5 ? ((v - 2)/3)*2 : ((8 - v)/3)*2 + 8;
116         *             }
117         *             return v;
118         *         },
119         *         Function.identity());
120         * }
121         *
122         * @see Codec#map(Function)
123         *
124         * @param mapper the mapper function
125         * @param inverseMapper the inverse function of the {@code mapper}
126         * @param <B> the new argument type of the given problem
127         * @return a new {@link InvertibleCodec} with the mapped result type
128         * @throws NullPointerException if one the mapper is {@code null}.
129         */
130        default <B>
131        InvertibleCodec<B, G> map(
132                final Function<? super T, ? extends B> mapper,
133                final Function<? super B, ? extends T> inverseMapper
134        ) {
135                requireNonNull(mapper);
136                requireNonNull(inverseMapper);
137
138                return InvertibleCodec.of(
139                        encoding(),
140                        mapper.compose(decoder()),
141                        encoder().compose(inverseMapper)
142                );
143        }
144
145        /**
146         * Create a new invertible codec from the given parameters.
147         *
148         * @param encoding the genotype factory used for creating new
149         *        {@code Genotypes}
150         * @param decoder decoder function, which converts a {@link Genotype} to a
151         *        value in the problem domain.
152         * @param encoder encoder function, which converts a value of the problem
153         *        domain into a {@link Genotype}
154         * @param <G> the {@link Gene} type
155         * @param <T> the fitness function argument type in the problem domain
156         * @return a new {@link InvertibleCodec} object with the given parameters.
157         * @throws NullPointerException if one of the arguments is {@code null}.
158         */
159        static <T, G extends Gene<?, G>> InvertibleCodec<T, G> of(
160                final Factory<Genotype<G>> encoding,
161                final Function<? super Genotype<G>, ? extends T> decoder,
162                final Function<? super T, Genotype<G>> encoder
163        ) {
164                requireNonNull(encoding);
165                requireNonNull(decoder);
166                requireNonNull(encoder);
167
168                return new InvertibleCodec<>() {
169                        @Override
170                        public Factory<Genotype<G>> encoding() {
171                                return encoding;
172                        }
173
174                        @Override
175                        @SuppressWarnings("unchecked")
176                        public Function<Genotype<G>, T> decoder() {
177                                return (Function<Genotype<G>, T>)decoder;
178                        }
179
180                        @Override
181                        @SuppressWarnings("unchecked")
182                        public Function<T, Genotype<G>> encoder() {
183                                return (Function<T, Genotype<G>>)encoder;
184                        }
185                };
186        }
187
188}