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

Type Parameters:
T - the argument type of 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:
  • Method Summary

    Modifier and Type
    Method
    Description
    static <A, B, T, G extends Gene<?, G>>
    Codec<T,G>
    combine(Codec<? extends A,G> codec1, Codec<? extends B,G> codec2, BiFunction<? super A,? super B,? extends T> decoder)
    Converts two given Codec instances into one.
    static <T, G extends Gene<?, G>>
    Codec<T,G>
    combine(ISeq<? extends Codec<?,G>> codecs, Function<? super Object[],? extends T> decoder)
    Combines the given codecs into one codec.
    default T
    decode(Genotype<G> genotype)
    Converts the given Genotype to the target type Codec.
    Return the decoder function which transforms the genotype back to the original problem domain representation.
    Return the genotype factory for creating genotypes with the right encoding for the given problem.
    default <B> Codec<B,G>
    map(Function<? super T,? extends B> mapper)
    Create a new Codec with the mapped result type.
    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)
    Deprecated, for removal: This API element is subject to removal in a future version.
    Will be removed in the next major version, use combine(Codec, Codec, BiFunction) instead
    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.
    static <T, G extends Gene<?, G>>
    Codec<T,G>
    of(ISeq<? extends Codec<?,G>> codecs, Function<? super Object[],? extends T> decoder)
    Deprecated, for removal: This API element is subject to removal in a future version.
    Will be removed in the next major version, use combine(ISeq, Function) instead
    toInvertibleCodec(Function<? super T,Genotype<G>> encoder)
    Converts this codec into an invertible codec, by using the given encoder (inversion) function.
  • Method Details

    • 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

      Return the decoder function which transforms the genotype back to the original problem domain representation.
      Returns:
      genotype decoder
      See Also:
    • 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,G> map(Function<? super T,? extends B> mapper)
      Create a new Codec with the mapped result type. The following example creates a double codec whose 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:
    • toInvertibleCodec

      default InvertibleCodec<T,G> toInvertibleCodec(Function<? super T,Genotype<G>> encoder)
      Converts this codec into an invertible codec, by using the given encoder (inversion) function.
      Parameters:
      encoder - the (inverse) encoder function
      Returns:
      a new invertible codec
      Throws:
      NullPointerException - if the given encoder is null
    • 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:
      T - the fitness function argument type in the problem domain
      G - the Gene type
      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

      @Deprecated(since="8.1", forRemoval=true) 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)
      Deprecated, for removal: This API element is subject to removal in a future version.
      Will be removed in the next major version, use combine(Codec, Codec, BiFunction) instead
      Converts two given Codec instances into one. This lets you divide a problem into subproblems 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 (these 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:
      A - the argument type of the first codec
      B - the argument type of the second codec
      T - the argument type of the compound codec
      G - the gene type
      Parameters:
      codec1 - the first codec
      codec2 - the second codec
      decoder - the decoder which combines the two argument types from the 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
      See Also:
    • combine

      static <A, B, T, G extends Gene<?, G>> Codec<T,G> combine(Codec<? extends A,G> codec1, Codec<? extends B,G> codec2, BiFunction<? super A,? super B,? extends T> decoder)
      Converts two given Codec instances into one. This lets you divide a problem into subproblems 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 (these 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.combine(
           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:
      A - the argument type of the first codec
      B - the argument type of the second codec
      T - the argument type of the compound codec
      G - the gene type
      Parameters:
      codec1 - the first codec
      codec2 - the second codec
      decoder - the decoder which combines the two argument types from the 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:
      8.1
    • of

      @Deprecated(since="8.1", forRemoval=true) static <T, G extends Gene<?, G>> Codec<T,G> of(ISeq<? extends Codec<?,G>> codecs, Function<? super Object[],? extends T> decoder)
      Deprecated, for removal: This API element is subject to removal in a future version.
      Will be removed in the next major version, use combine(ISeq, Function) instead
      Combines the given codecs into one codec. This lets you divide a problem into subproblems 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:
      T - the argument type of the compound codec
      G - the gene type
      Parameters:
      codecs - the Codec sequence of the subproblems
      decoder - the decoder which combines the argument types from the 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
    • combine

      static <T, G extends Gene<?, G>> Codec<T,G> combine(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 subproblems 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.combine(
          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:
      T - the argument type of the compound codec
      G - the gene type
      Parameters:
      codecs - the Codec sequence of the subproblems
      decoder - the decoder which combines the argument types from the 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:
      8.1