org.jenetics.engine.Codec Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jenetics Show documentation
Show all versions of jenetics Show documentation
Jenetics - Java Genetic Algorithm Library
/*
* Java Genetic Algorithm Library (jenetics-3.9.0).
* Copyright (c) 2007-2017 Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter ([email protected])
*/
package org.jenetics.engine;
import static java.util.Objects.requireNonNull;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.jenetics.Gene;
import org.jenetics.Genotype;
import org.jenetics.util.Factory;
import org.jenetics.util.ISeq;
/**
* A problem {@code Codec} contains the information about how to encode a given
* argument type into a {@code Genotype}. It also lets convert the encoded
* {@code Genotype} back to the argument type. The engine creation and the
* implementation of the fitness function can be heavily simplified by using
* a {@code Codec} class. The example given in the {@link Engine} documentation
* can be simplified as follows:
*
* {@code
* public class RealFunction {
* // The conversion from the 'Genotype' to the argument type of the fitness
* // function is performed by the given 'Codec'. You can concentrate on the
* // implementation, because you are not bothered with the conversion code.
* private static double eval(final double x) {
* return cos(0.5 + sin(x)) * cos(x);
* }
*
* public static void main(final String[] args) {
* final Engine engine = Engine
* // Create an Engine.Builder with the "pure" fitness function
* // and the appropriate Codec.
* .build(RealFunction::eval, codecs.ofScalar(DoubleRange.of(0, 2*PI)))
* .build();
* ...
* }
* }
* }
*
* The {@code Codec} needed for the above usage example, will look like this:
* {@code
* final DoubleRange domain = DoubleRange.of(0, 2*PI);
* final Codec codec = Codec.of(
* Genotype.of(DoubleChromosome.of(domain)),
* gt -> gt.getChromosome().getGene().getAllele()
* );
* }
*
* Calling the {@link Codec#of(Factory, Function)} method is the usual way for
* creating new {@code Codec} instances.
*
* @see codecs
* @see Engine
* @see Engine.Builder
*
* @param the argument type of a given problem
* @param the {@code Gene} type used for encoding the argument type {@code T}
*
* @author Franz Wilhelmstötter
* @version 3.6
* @since 3.2
*/
public interface Codec> {
/**
* Return the genotype factory for creating genotypes with the right
* encoding for the given problem. The genotype created with this factory
* must work together with the {@link #decoder()} function, which transforms
* the genotype into an object of the problem domain.
*
* {@code
* final Codec codec = ...
* final Genotype gt = codec.encoding().newInstance();
* final SomeObject arg = codec.decoder().apply(gt);
* }
*
* @see #decoder()
*
* @return the genotype (factory) representation of the problem domain
*/
public Factory> encoding();
/**
* Return the decoder function which transforms the genotype back
* to the original problem domain representation.
*
* @see #encoding()
*
* @return genotype decoder
*/
public Function, T> decoder();
/**
* Converts the given {@link Genotype} to the target type {@link T}. This is
* a shortcut for
* {@code
* final Codec codec = ...
* final Genotype gt = codec.encoding().newInstance();
*
* final SomeObject arg = codec.decoder().apply(gt);
* }
*
* @since 3.6
*
* @param gt the genotype to be converted
* @return the converted genotype
*/
public default T decode(final Genotype gt) {
return decoder().apply(gt);
}
/**
* Create a new {@code Codec} object with the given {@code encoding} and
* {@code decoder} function.
*
* @param encoding the genotype factory used for creating new
* {@code Genotypes}.
* @param decoder decoder function, which converts a {@code Genotype} to a
* value in the problem domain.
* @param the {@code Gene} type
* @param the fitness function argument type in the problem domain
* @return a new {@code Codec} object with the given parameters.
* @throws NullPointerException if one of the arguments is {@code null}.
*/
public static , T> Codec of(
final Factory> encoding,
final Function, T> decoder
) {
requireNonNull(encoding);
requireNonNull(decoder);
return new Codec() {
@Override
public Factory> encoding() {
return encoding;
}
@Override
public Function, T> decoder() {
return decoder;
}
};
}
/**
* Converts two given {@code Codec} instances into one. This lets you divide
* a problem into sub problems and combine them again.
*
* The following example shows how to combine two codecs, which converts a
* {@code LongGene} to a {@code LocalDate}, to a codec which combines the
* two {@code LocalDate} object (this are the argument types of the
* component codecs) to a {@code Duration}.
*
*
{@code
* final Codec dateCodec1 = Codec.of(
* Genotype.of(LongChromosome.of(0, 10_000)),
* gt -> LocalDate.ofEpochDay(gt.getGene().longValue())
* );
*
* final Codec dateCodec2 = Codec.of(
* Genotype.of(LongChromosome.of(1_000_000, 10_000_000)),
* gt -> LocalDate.ofEpochDay(gt.getGene().longValue())
* );
*
* final Codec durationCodec = Codec.of(
* dateCodec1,
* dateCodec2,
* (d1, d2) -> Duration.ofDays(d2.toEpochDay() - d1.toEpochDay())
* );
*
* final Engine engine = Engine
* .builder(Duration::toMillis, durationCodec)
* .build();
*
* final Phenotype pt = engine.stream()
* .limit(100)
* .collect(EvolutionResult.toBestPhenotype());
* System.out.println(pt);
*
* final Duration duration = durationCodec.decoder()
* .apply(pt.getGenotype());
* System.out.println(duration);
* }
*
* @since 3.3
*
* @param the gene type
* @param the argument type of the first codec
* @param the argument type of the second codec
* @param the argument type of the compound codec
* @param codec1 the first codec
* @param codec2 the second codec
* @param decoder the decoder which combines the two argument types from the
* given given codecs, to the argument type of the resulting codec.
* @return a new codec which combines the given {@code codec1} and
* {@code codec2}
* @throws NullPointerException if one of the arguments is {@code null}
*/
public static , A, B, T> Codec of(
final Codec codec1,
final Codec codec2,
final BiFunction decoder
) {
@SuppressWarnings("unchecked")
final Function
© 2015 - 2025 Weber Informatics LLC | Privacy Policy