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