001 /*
002 * Java Genetic Algorithm Library (jenetics-4.3.0).
003 * Copyright (c) 2007-2018 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
024 import java.util.Objects;
025 import java.util.function.BiFunction;
026 import java.util.function.Function;
027
028 import io.jenetics.Gene;
029 import io.jenetics.Genotype;
030 import io.jenetics.util.Factory;
031 import io.jenetics.util.ISeq;
032
033 /**
034 * A problem {@code Codec} contains the information about how to encode a given
035 * argument type into a {@code Genotype}. It also lets convert the encoded
036 * {@code Genotype} back to the argument type. The engine creation and the
037 * implementation of the fitness function can be heavily simplified by using
038 * a {@code Codec} class. The example given in the {@link Engine} documentation
039 * can be simplified as follows:
040 *
041 * <pre>{@code
042 * public class RealFunction {
043 * // The conversion from the 'Genotype' to the argument type of the fitness
044 * // function is performed by the given 'Codec'. You can concentrate on the
045 * // implementation, because you are not bothered with the conversion code.
046 * private static double eval(final double x) {
047 * return cos(0.5 + sin(x)) * cos(x);
048 * }
049 *
050 * public static void main(final String[] args) {
051 * final Engine<DoubleGene, Double> engine = Engine
052 * // Create an Engine.Builder with the "pure" fitness function
053 * // and the appropriate Codec.
054 * .build(RealFunction::eval, Codecs.ofScalar(DoubleRange.of(0, 2*PI)))
055 * .build();
056 * ...
057 * }
058 * }
059 * }</pre>
060 *
061 * The {@code Codec} needed for the above usage example, will look like this:
062 * <pre>{@code
063 * final DoubleRange domain = DoubleRange.of(0, 2*PI);
064 * final Codec<Double, DoubleGene> codec = Codec.of(
065 * Genotype.of(DoubleChromosome.of(domain)),
066 * gt -> gt.getChromosome().getGene().getAllele()
067 * );
068 * }</pre>
069 *
070 * Calling the {@link Codec#of(Factory, Function)} method is the usual way for
071 * creating new {@code Codec} instances.
072 *
073 * @see Codecs
074 * @see Engine
075 * @see Engine.Builder
076 *
077 * @param <T> the argument type of a given problem
078 * @param <G> the {@code Gene} type used for encoding the argument type {@code T}
079 *
080 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
081 * @version 3.6
082 * @since 3.2
083 */
084 public interface Codec<T, G extends Gene<?, G>> {
085
086 /**
087 * Return the genotype factory for creating genotypes with the right
088 * encoding for the given problem. The genotype created with this factory
089 * must work together with the {@link #decoder()} function, which transforms
090 * the genotype into an object of the problem domain.
091 *
092 * <pre>{@code
093 * final Codec<SomeObject, DoubleGene> codec = ...
094 * final Genotype<DoubleGene> gt = codec.encoding().newInstance();
095 * final SomeObject arg = codec.decoder().apply(gt);
096 * }</pre>
097 *
098 * @see #decoder()
099 *
100 * @return the genotype (factory) representation of the problem domain
101 */
102 public Factory<Genotype<G>> encoding();
103
104 /**
105 * Return the <em>decoder</em> function which transforms the genotype back
106 * to the original problem domain representation.
107 *
108 * @see #encoding()
109 *
110 * @return genotype decoder
111 */
112 public Function<Genotype<G>, T> decoder();
113
114 /**
115 * Converts the given {@link Genotype} to the target type {@link T}. This is
116 * a shortcut for
117 * <pre>{@code
118 * final Codec<SomeObject, DoubleGene> codec = ...
119 * final Genotype<DoubleGene> gt = codec.encoding().newInstance();
120 *
121 * final SomeObject arg = codec.decoder().apply(gt);
122 * }</pre>
123 *
124 * @since 3.6
125 *
126 * @param genotype the genotype to be converted
127 * @return the converted genotype
128 * @throws NullPointerException if the given {@code genotype} is {@code null}
129 */
130 public default T decode(final Genotype<G> genotype) {
131 Objects.requireNonNull(genotype);
132 return decoder().apply(genotype);
133 }
134
135 /**
136 * Create a new {@code Codec} with the mapped result type. The following
137 * example creates a double codec who's values are not uniformly distributed
138 * between {@code [0..1)}. Instead the values now follow an exponential
139 * function.
140 *
141 * <pre>{@code
142 * final Codec<Double, DoubleGene> c = Codecs.ofScalar(DoubleRange.of(0, 1))
143 * .map(Math::exp);
144 * }</pre>
145 *
146 * @since 4.0
147 *
148 * @param mapper the mapper function
149 * @param <B> the new argument type of the given problem
150 * @return a new {@code Codec} with the mapped result type
151 * @throws NullPointerException if the mapper is {@code null}.
152 */
153 public default <B>
154 Codec<B, G> map(final Function<? super T, ? extends B> mapper) {
155 requireNonNull(mapper);
156
157 return Codec.of(
158 encoding(),
159 gt -> mapper.apply(decode(gt))
160 );
161 }
162
163 /**
164 * Create a new {@code Codec} object with the given {@code encoding} and
165 * {@code decoder} function.
166 *
167 * @param encoding the genotype factory used for creating new
168 * {@code Genotypes}.
169 * @param decoder decoder function, which converts a {@code Genotype} to a
170 * value in the problem domain.
171 * @param <G> the {@code Gene} type
172 * @param <T> the fitness function argument type in the problem domain
173 * @return a new {@code Codec} object with the given parameters.
174 * @throws NullPointerException if one of the arguments is {@code null}.
175 */
176 public static <G extends Gene<?, G>, T> Codec<T, G> of(
177 final Factory<Genotype<G>> encoding,
178 final Function<Genotype<G>, T> decoder
179 ) {
180 requireNonNull(encoding);
181 requireNonNull(decoder);
182
183 return new Codec<T, G>() {
184 @Override
185 public Factory<Genotype<G>> encoding() {
186 return encoding;
187 }
188
189 @Override
190 public Function<Genotype<G>, T> decoder() {
191 return decoder;
192 }
193 };
194 }
195
196
197 /**
198 * Converts two given {@code Codec} instances into one. This lets you divide
199 * a problem into sub problems and combine them again.
200 * <p>
201 * The following example shows how to combine two codecs, which converts a
202 * {@code LongGene} to a {@code LocalDate}, to a codec which combines the
203 * two {@code LocalDate} object (this are the argument types of the
204 * component codecs) to a {@code Duration}.
205 *
206 * <pre>{@code
207 * final Codec<LocalDate, LongGene> dateCodec1 = Codec.of(
208 * Genotype.of(LongChromosome.of(0, 10_000)),
209 * gt -> LocalDate.ofEpochDay(gt.getGene().longValue())
210 * );
211 *
212 * final Codec<LocalDate, LongGene> dateCodec2 = Codec.of(
213 * Genotype.of(LongChromosome.of(1_000_000, 10_000_000)),
214 * gt -> LocalDate.ofEpochDay(gt.getGene().longValue())
215 * );
216 *
217 * final Codec<Duration, LongGene> durationCodec = Codec.of(
218 * dateCodec1,
219 * dateCodec2,
220 * (d1, d2) -> Duration.ofDays(d2.toEpochDay() - d1.toEpochDay())
221 * );
222 *
223 * final Engine<LongGene, Long> engine = Engine
224 * .builder(Duration::toMillis, durationCodec)
225 * .build();
226 *
227 * final Phenotype<LongGene, Long> pt = engine.stream()
228 * .limit(100)
229 * .collect(EvolutionResult.toBestPhenotype());
230 * System.out.println(pt);
231 *
232 * final Duration duration = durationCodec.decoder()
233 * .apply(pt.getGenotype());
234 * System.out.println(duration);
235 * }</pre>
236 *
237 * @since 3.3
238 *
239 * @param <G> the gene type
240 * @param <A> the argument type of the first codec
241 * @param <B> the argument type of the second codec
242 * @param <T> the argument type of the compound codec
243 * @param codec1 the first codec
244 * @param codec2 the second codec
245 * @param decoder the decoder which combines the two argument types from the
246 * given given codecs, to the argument type of the resulting codec.
247 * @return a new codec which combines the given {@code codec1} and
248 * {@code codec2}
249 * @throws NullPointerException if one of the arguments is {@code null}
250 */
251 public static <G extends Gene<?, G>, A, B, T> Codec<T, G> of(
252 final Codec<A, G> codec1,
253 final Codec<B, G> codec2,
254 final BiFunction<A, B, T> decoder
255 ) {
256 @SuppressWarnings("unchecked")
257 final Function<Object[], T> decoderAdapter =
258 v -> decoder.apply((A)v[0], (B)v[1]);
259
260 return of(
261 ISeq.of(codec1, codec2),
262 decoderAdapter
263 );
264 }
265
266 /**
267 * Combines the given {@code codecs} into one codec. This lets you divide
268 * a problem into sub problems and combine them again.
269 * <p>
270 * The following example combines more than two sub-codecs into one.
271 * <pre>{@code
272 * final Codec<LocalDate, LongGene> dateCodec = Codec.of(
273 * Genotype.of(LongChromosome.of(0, 10_000)),
274 * gt -> LocalDate.ofEpochDay(gt.getGene().longValue())
275 * );
276 *
277 * final Codec<Duration, LongGene> durationCodec = Codec.of(
278 * ISeq.of(dateCodec, dateCodec, dateCodec),
279 * dates -> {
280 * final LocalDate ld1 = (LocalDate)dates[0];
281 * final LocalDate ld2 = (LocalDate)dates[1];
282 * final LocalDate ld3 = (LocalDate)dates[2];
283 *
284 * return Duration.ofDays(
285 * ld1.toEpochDay() + ld2.toEpochDay() - ld3.toEpochDay()
286 * );
287 * }
288 * );
289 *
290 * final Engine<LongGene, Long> engine = Engine
291 * .builder(Duration::toMillis, durationCodec)
292 * .build();
293 *
294 * final Phenotype<LongGene, Long> pt = engine.stream()
295 * .limit(100)
296 * .collect(EvolutionResult.toBestPhenotype());
297 * System.out.println(pt);
298 *
299 * final Duration duration = durationCodec.decoder()
300 * .apply(pt.getGenotype());
301 * System.out.println(duration);
302 * }</pre>
303 *
304 * @since 3.3
305 *
306 * @param <G> the gene type
307 * @param <T> the argument type of the compound codec
308 * @param codecs the {@code Codec} sequence of the sub-problems
309 * @param decoder the decoder which combines the argument types from the
310 * given given codecs, to the argument type of the resulting codec.
311 * @return a new codec which combines the given {@code codecs}
312 * @throws NullPointerException if one of the arguments is {@code null}
313 */
314 public static <G extends Gene<?, G>, T> Codec<T, G> of(
315 final ISeq<? extends Codec<?, G>> codecs,
316 final Function<? super Object[], ? extends T> decoder
317 ) {
318 return new CompositeCodec<>(codecs, decoder);
319 }
320
321 }
|