Interface Codec<T,​G extends Gene<?,​G>>

  • Type Parameters:
    T - the argument type of a given problem
    G - the Gene type used for encoding the argument type T
    All Known Subinterfaces:
    InvertibleCodec<T,​G>

    public interface Codec<T,​G extends Gene<?,​G>>
    A problem Codec contains the information about how to encode a given argument type into a Genotype. It also lets convert the encoded Genotype back to the argument type. The engine creation and the implementation of the fitness function can be heavily simplified by using a Codec class. The example given in the Engine documentation can be simplified as follows:
    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<DoubleGene, Double> 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 Codec needed for the above usage example, will look like this:
    final DoubleRange domain = DoubleRange.of(0, 2*PI); final Codec<Double, DoubleGene> codec = Codec.of( Genotype.of(DoubleChromosome.of(domain)), gt -> gt.chromosome().gene().allele() );
    Calling the of(Factory, Function) method is the usual way for creating new Codec instances.
    Since:
    3.2
    Version:
    3.6
    See Also:
    Codecs, Engine, Engine.Builder
    • Method Detail

      • encoding

        Factory<Genotype<G>> encoding()
        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 decoder() function, which transforms the genotype into an object of the problem domain.
        final Codec<SomeObject, DoubleGene> codec = ... final Genotype<DoubleGene> gt = codec.encoding().newInstance(); final SomeObject arg = codec.decoder().apply(gt);
        Returns:
        the genotype (factory) representation of the problem domain
        See Also:
        decoder()
      • decoder

        Function<Genotype<G>,​Tdecoder()
        Return the decoder function which transforms the genotype back to the original problem domain representation.
        Returns:
        genotype decoder
        See Also:
        encoding()
      • decode

        default T decode​(Genotype<G> genotype)
        Converts the given Genotype to the target type Codec. This is a shortcut for
        final Codec<SomeObject, DoubleGene> codec = ... final Genotype<DoubleGene> gt = codec.encoding().newInstance(); final SomeObject arg = codec.decoder().apply(gt);
        Parameters:
        genotype - the genotype to be converted
        Returns:
        the converted genotype
        Throws:
        NullPointerException - if the given genotype is null
        Since:
        3.6
      • map

        default <B> Codec<B,​Gmap​(Function<? super T,​? extends B> mapper)
        Create a new Codec with the mapped result type. The following example creates a double codec who's values are not uniformly distributed between [0..1). Instead the values now follow an exponential function.
        final Codec<Double, DoubleGene> c = Codecs.ofScalar(DoubleRange.of(0, 1)) .map(Math::exp);
        This method can also be used for creating non-trivial codes like split ranges, as shown in the following example, where only values between [0, 2) and [8, 10) are valid.
        +--+--+--+--+--+--+--+--+--+--+ | | | | | | | | | | | 0 1 2 3 4 5 6 7 8 9 10 |-----|xxxxxxxxxxxxxxxxx|-----| ^ |llllllll|rrrrrrrr| ^ | | | | +-------+ +------+
        final Codec<Double, DoubleGene> codec = Codecs .ofScalar(DoubleRange.of(0, 10)) .map(v -> { if (v >= 2 && v < 8) { return v < 5 ? ((v - 2)/3)*2 : ((8 - v)/3)*2 + 8; } return v; });
        Type Parameters:
        B - the new argument type of the given problem
        Parameters:
        mapper - the mapper function
        Returns:
        a new Codec with the mapped result type
        Throws:
        NullPointerException - if the mapper is null.
        Since:
        4.0
        See Also:
        InvertibleCodec.map(Function, Function)
      • of

        static <T,​G extends Gene<?,​G>> Codec<T,​G> of​(Factory<Genotype<G>> encoding,
                                                                       Function<? super Genotype<G>,​? extends T> decoder)
        Create a new Codec object with the given encoding and decoder function.
        Type Parameters:
        G - the Gene type
        T - the fitness function argument type in the problem domain
        Parameters:
        encoding - the genotype factory used for creating new Genotypes
        decoder - decoder function, which converts a Genotype to a value in the problem domain
        Returns:
        a new Codec object with the given parameters
        Throws:
        NullPointerException - if one of the arguments is null.
      • of

        static <A,​B,​T,​G extends Gene<?,​G>> Codec<T,​G> of​(Codec<A,​G> codec1,
                                                                                       Codec<B,​G> codec2,
                                                                                       BiFunction<A,​B,​T> decoder)
        Converts two given 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 LongGene to a LocalDate, to a codec which combines the two LocalDate object (this are the argument types of the component codecs) to a Duration.

        final Codec<LocalDate, LongGene> dateCodec1 = Codec.of( Genotype.of(LongChromosome.of(0, 10_000)), gt -> LocalDate.ofEpochDay(gt.gene().longValue()) ); final Codec<LocalDate, LongGene> dateCodec2 = Codec.of( Genotype.of(LongChromosome.of(1_000_000, 10_000_000)), gt -> LocalDate.ofEpochDay(gt.gene().longValue()) ); final Codec<Duration, LongGene> durationCodec = Codec.of( dateCodec1, dateCodec2, (d1, d2) -> Duration.ofDays(d2.toEpochDay() - d1.toEpochDay()) ); final Engine<LongGene, Long> engine = Engine .builder(Duration::toMillis, durationCodec) .build(); final Phenotype<LongGene, Long> pt = engine.stream() .limit(100) .collect(EvolutionResult.toBestPhenotype()); System.out.println(pt); final Duration duration = durationCodec.decoder() .apply(pt.genotype()); System.out.println(duration);
        Type Parameters:
        G - the gene type
        A - the argument type of the first codec
        B - the argument type of the second codec
        T - the argument type of the compound codec
        Parameters:
        codec1 - the first codec
        codec2 - the second codec
        decoder - the decoder which combines the two argument types from the given given codecs, to the argument type of the resulting codec.
        Returns:
        a new codec which combines the given codec1 and codec2
        Throws:
        NullPointerException - if one of the arguments is null
        Since:
        3.3
      • of

        static <T,​G extends Gene<?,​G>> Codec<T,​G> of​(ISeq<? extends Codec<?,​G>> codecs,
                                                                       Function<? super Object[],​? extends T> decoder)
        Combines the given codecs into one codec. This lets you divide a problem into sub problems and combine them again.

        The following example combines more than two sub-codecs into one.

        final Codec<LocalDate, LongGene> dateCodec = Codec.of( Genotype.of(LongChromosome.of(0, 10_000)), gt -> LocalDate.ofEpochDay(gt.getGene().longValue()) ); final Codec<Duration, LongGene> durationCodec = Codec.of( ISeq.of(dateCodec, dateCodec, dateCodec), dates -> { final LocalDate ld1 = (LocalDate)dates[0]; final LocalDate ld2 = (LocalDate)dates[1]; final LocalDate ld3 = (LocalDate)dates[2]; return Duration.ofDays( ld1.toEpochDay() + ld2.toEpochDay() - ld3.toEpochDay() ); } ); final Engine<LongGene, Long> engine = Engine .builder(Duration::toMillis, durationCodec) .build(); final Phenotype<LongGene, Long> pt = engine.stream() .limit(100) .collect(EvolutionResult.toBestPhenotype()); System.out.println(pt); final Duration duration = durationCodec.decoder() .apply(pt.genotype()); System.out.println(duration);
        Type Parameters:
        G - the gene type
        T - the argument type of the compound codec
        Parameters:
        codecs - the Codec sequence of the sub-problems
        decoder - the decoder which combines the argument types from the given given codecs, to the argument type of the resulting codec.
        Returns:
        a new codec which combines the given codecs
        Throws:
        NullPointerException - if one of the arguments is null
        IllegalArgumentException - if the given codecs sequence is empty
        Since:
        3.3