codecs.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.7.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.lang.reflect.Array.newInstance;
023 import static java.util.Objects.requireNonNull;
024 
025 import java.awt.geom.AffineTransform;
026 import java.util.Objects;
027 import java.util.function.IntFunction;
028 import java.util.function.Predicate;
029 import java.util.function.Supplier;
030 import java.util.stream.Stream;
031 
032 import org.jenetics.internal.math.base;
033 import org.jenetics.internal.util.Equality;
034 import org.jenetics.internal.util.require;
035 
036 import org.jenetics.AnyChromosome;
037 import org.jenetics.AnyGene;
038 import org.jenetics.BitChromosome;
039 import org.jenetics.BitGene;
040 import org.jenetics.DoubleChromosome;
041 import org.jenetics.DoubleGene;
042 import org.jenetics.EnumGene;
043 import org.jenetics.Gene;
044 import org.jenetics.Genotype;
045 import org.jenetics.IntegerChromosome;
046 import org.jenetics.IntegerGene;
047 import org.jenetics.LongChromosome;
048 import org.jenetics.LongGene;
049 import org.jenetics.PermutationChromosome;
050 import org.jenetics.util.DoubleRange;
051 import org.jenetics.util.ISeq;
052 import org.jenetics.util.IntRange;
053 import org.jenetics.util.LongRange;
054 
055 /**
056  * This class contains factory methods for creating common  problem encodings.
057  *
058  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
059  @since 3.2
060  @version 3.4
061  */
062 public final class codecs {
063 
064     private codecs() {require.noInstance();}
065 
066     /**
067      * Return a scalar {@code Codec} for the given range.
068      *
069      @param domain the domain of the returned {@code Codec}
070      @return a new scalar {@code Codec} with the given domain.
071      @throws NullPointerException if the given {@code domain} is {@code null}
072      */
073     public static Codec<Integer, IntegerGene> ofScalar(final IntRange domain) {
074         requireNonNull(domain);
075 
076         return Codec.of(
077             Genotype.of(IntegerChromosome.of(domain)),
078             gt -> gt.getChromosome().getGene().getAllele()
079         );
080     }
081 
082     /**
083      * Return a scalar {@code Codec} for the given range.
084      *
085      @param domain the domain of the returned {@code Codec}
086      @return a new scalar {@code Codec} with the given domain.
087      @throws NullPointerException if the given {@code domain} is {@code null}
088      */
089     public static Codec<Long, LongGene> ofScalar(final LongRange domain) {
090         requireNonNull(domain);
091 
092         return Codec.of(
093             Genotype.of(LongChromosome.of(domain)),
094             gt -> gt.getChromosome().getGene().getAllele()
095         );
096     }
097 
098     /**
099      * Return a scalar {@code Codec} for the given range.
100      *
101      @param domain the domain of the returned {@code Codec}
102      @return a new scalar {@code Codec} with the given domain.
103      @throws NullPointerException if the given {@code domain} is {@code null}
104      */
105     public static Codec<Double, DoubleGene> ofScalar(final DoubleRange domain) {
106         requireNonNull(domain);
107 
108         return Codec.of(
109             Genotype.of(DoubleChromosome.of(domain)),
110             gt -> gt.getChromosome().getGene().getAllele()
111         );
112     }
113 
114     /**
115      * Return a scala {@code Codec} with the given allele {@link Supplier} and
116      * allele {@code validator}. The {@code supplier} is responsible for
117      * creating new random alleles, and the {@code validator} can verify it.
118      <p>
119      * The following example shows a codec which creates and verifies
120      * {@code BigInteger} objects.
121      <pre>{@code
122      * final Codec<BigInteger, AnyGene<BigInteger>> codec = codecs.of(
123      *     // Create new random 'BigInteger' object.
124      *     () -> {
125      *         final byte[] data = new byte[100];
126      *         RandomRegistry.getRandom().nextBytes(data);
127      *         return new BigInteger(data);
128      *     },
129      *     // Verify that bit 7 is set. (For illustration purpose.)
130      *     bi -> bi.testBit(7)
131      * );
132      * }</pre>
133      *
134      @see AnyGene#of(Supplier, Predicate)
135      @see AnyChromosome#of(Supplier, Predicate)
136      *
137      @param <A> the allele type
138      @param supplier the allele-supplier which is used for creating new,
139      *        random alleles
140      @param validator the validator used for validating the created gene. This
141      *        predicate is used in the {@link AnyGene#isValid()} method.
142      @return a new {@code Codec} with the given parameters
143      @throws NullPointerException if one of the parameters is {@code null}
144      */
145     public static <A> Codec<A, AnyGene<A>> ofScalar(
146         final Supplier<? extends A> supplier,
147         final Predicate<? super A> validator
148     ) {
149         return Codec.of(
150             Genotype.of(AnyChromosome.of(supplier, validator)),
151             gt -> gt.getGene().getAllele()
152         );
153     }
154 
155     /**
156      * Return a scala {@code Codec} with the given allele {@link Supplier} and
157      * allele {@code validator}. The {@code supplier} is responsible for
158      * creating new random alleles.
159      *
160      @see #ofScalar(Supplier, Predicate)
161      @see AnyGene#of(Supplier)
162      @see AnyChromosome#of(Supplier)
163      *
164      @param <A> the allele type
165      @param supplier the allele-supplier which is used for creating new,
166      *        random alleles
167      @return a new {@code Codec} with the given parameters
168      @throws NullPointerException if the parameter is {@code null}
169      */
170     public static <A> Codec<A, AnyGene<A>> ofScalar(
171         final Supplier<? extends A> supplier
172     ) {
173         return Codec.of(
174             Genotype.of(AnyChromosome.of(supplier)),
175             gt -> gt.getGene().getAllele()
176         );
177     }
178 
179     /**
180      * Return a vector {@code Codec} for the given range. All vector values
181      * are restricted by the same domain.
182      *
183      @param domain the domain of the vector values
184      @param length the vector length
185      @return a new vector {@code Codec}
186      @throws NullPointerException if the given {@code domain} is {@code null}
187      @throws IllegalArgumentException if the {@code length} is smaller than
188      *         one.
189      */
190     public static Codec<int[], IntegerGene> ofVector(
191         final IntRange domain,
192         final int length
193     ) {
194         requireNonNull(domain);
195         require.positive(length);
196 
197         return Codec.of(
198             Genotype.of(IntegerChromosome.of(domain, length)),
199             gt -> ((IntegerChromosome)gt.getChromosome()).toArray()
200         );
201     }
202 
203     /**
204      * Return a vector {@code Codec} for the given range. All vector values
205      * are restricted by the same domain.
206      *
207      @param domain the domain of the vector values
208      @param length the vector length
209      @return a new vector {@code Codec}
210      @throws NullPointerException if the given {@code domain} is {@code null}
211      @throws IllegalArgumentException if the {@code length} is smaller than
212      *         one.
213      */
214     public static Codec<long[], LongGene> ofVector(
215         final LongRange domain,
216         final int length
217     ) {
218         requireNonNull(domain);
219         require.positive(length);
220 
221         return Codec.of(
222             Genotype.of(LongChromosome.of(domain, length)),
223             gt -> ((LongChromosome)gt.getChromosome()).toArray()
224         );
225     }
226 
227     /**
228      * Return a vector {@code Codec} for the given range. All vector values
229      * are restricted by the same domain.
230      *
231      @param domain the domain of the vector values
232      @param length the vector length
233      @return a new vector {@code Codec}
234      @throws NullPointerException if the given {@code domain} is {@code null}
235      @throws IllegalArgumentException if the {@code length} is smaller than
236      *         one.
237      */
238     public static Codec<double[], DoubleGene> ofVector(
239         final DoubleRange domain,
240         final int length
241     ) {
242         requireNonNull(domain);
243         require.positive(length);
244 
245         return Codec.of(
246             Genotype.of(DoubleChromosome.of(domain, length)),
247             gt -> ((DoubleChromosome)gt.getChromosome()).toArray()
248         );
249     }
250 
251     /**
252      * Create a vector {@code Codec} for the given ranges. Each vector element
253      * might have a different domain. The vector length is equal to the number
254      * of domains.
255      *
256      @param domains the domain ranges
257      @return a new vector {@code Codec}
258      @throws NullPointerException if one of the arguments is {@code null}
259      @throws IllegalArgumentException if the {@code domains} array is empty
260      */
261     public static Codec<int[], IntegerGene> ofVector(final IntRange... domains) {
262         if (domains.length == 0) {
263             throw new IllegalArgumentException("Domains must not be empty.");
264         }
265 
266         final ISeq<IntegerChromosome> chromosomes = Stream.of(domains)
267             .map(Objects::requireNonNull)
268             .map(IntegerGene::of)
269             .map(IntegerChromosome::of)
270             .collect(ISeq.toISeq());
271 
272         return Codec.of(
273             Genotype.of(chromosomes),
274             gt -> {
275                 final int[] args = new int[chromosomes.length()];
276                 for (int i = chromosomes.length(); --i >= 0;) {
277                     args[i= gt.getChromosome(i).getGene().intValue();
278                 }
279                 return args;
280             }
281         );
282     }
283 
284     /**
285      * Create a vector {@code Codec} for the given ranges. Each vector element
286      * might have a different domain. The vector length is equal to the number
287      * of domains.
288      *
289      @param domains the domain ranges
290      @return a new vector {@code Codec}
291      @throws NullPointerException if one of the arguments is {@code null}
292      @throws IllegalArgumentException if the {@code domains} array is empty
293      */
294     public static Codec<long[], LongGene> ofVector(final LongRange... domains) {
295         if (domains.length == 0) {
296             throw new IllegalArgumentException("Domains must not be empty.");
297         }
298 
299         final ISeq<LongChromosome> chromosomes = Stream.of(domains)
300             .map(Objects::requireNonNull)
301             .map(LongGene::of)
302             .map(LongChromosome::of)
303             .collect(ISeq.toISeq());
304 
305         return Codec.of(
306             Genotype.of(chromosomes),
307             gt -> {
308                 final long[] args = new long[chromosomes.length()];
309                 for (int i = chromosomes.length(); --i >= 0;) {
310                     args[i= gt.getChromosome(i).getGene().longValue();
311                 }
312                 return args;
313             }
314         );
315     }
316 
317     /**
318      * Create a vector {@code Codec} for the given ranges. Each vector element
319      * might have a different domain. The vector length is equal to the number
320      * of domains.
321      *
322      @param domains the domain ranges
323      @return a new vector {@code Codec}
324      @throws NullPointerException if one of the arguments is {@code null}
325      @throws IllegalArgumentException if the {@code domains} array is empty
326      */
327     public static Codec<double[], DoubleGene> ofVector(
328         final DoubleRange... domains
329     ) {
330         if (domains.length == 0) {
331             throw new IllegalArgumentException("Domains must not be empty.");
332         }
333 
334         final ISeq<DoubleChromosome> chromosomes = Stream.of(domains)
335             .map(Objects::requireNonNull)
336             .map(DoubleGene::of)
337             .map(DoubleChromosome::of)
338             .collect(ISeq.toISeq());
339 
340         return Codec.of(
341             Genotype.of(chromosomes),
342             gt -> {
343                 final double[] args = new double[chromosomes.length()];
344                 for (int i = chromosomes.length(); --i >= 0;) {
345                     args[i= gt.getChromosome(i).getGene().doubleValue();
346                 }
347                 return args;
348             }
349         );
350     }
351 
352     /**
353      * Return a scala {@code Codec} with the given allele {@link Supplier},
354      * allele {@code validator} and {@code Chromosome} length. The
355      * {@code supplier} is responsible for creating new random alleles, and the
356      * {@code validator} can verify it.
357      <p>
358      * The following example shows a codec which creates and verifies
359      * {@code BigInteger} object arrays.
360      <pre>{@code
361      * final Codec<BigInteger[], AnyGene<BigInteger>> codec = codecs.of(
362      *     // Create new random 'BigInteger' object.
363      *     () -> {
364      *         final byte[] data = new byte[100];
365      *         RandomRegistry.getRandom().nextBytes(data);
366      *         return new BigInteger(data);
367      *     },
368      *     // The array generator.
369      *     BigInteger[]::new,
370      *     // Verify that bit 7 is set. (For illustration purpose.)
371      *     bi -> bi.testBit(7),
372      *     // The 'Chromosome' length.
373      *     123
374      * );
375      * }</pre>
376      *
377      @see AnyChromosome#of(Supplier, Predicate, Predicate, int)
378      *
379      @param <A> the allele type
380      @param supplier the allele-supplier which is used for creating new,
381      *        random alleles
382      @param generator the array generator used for generating arrays of type
383      *        {@code A}
384      @param alleleValidator the validator used for validating the created gene.
385      *        This predicate is used in the {@link AnyGene#isValid()} method.
386      @param alleleSeqValidator the validator used for validating the created
387      *        chromosome. This predicate is used in the
388      *        {@link AnyChromosome#isValid()} method.
389      @param length the vector length
390      @return a new {@code Codec} with the given parameters
391      @throws NullPointerException if one of the parameters is {@code null}
392      @throws IllegalArgumentException if the length of the vector is smaller
393      *         than one.
394      *
395      @deprecated Use {@link #ofVector(Supplier, Predicate, Predicate, int)}
396      *             instead
397      */
398     @Deprecated
399     public static <A> Codec<A[], AnyGene<A>> ofVector(
400         final Supplier<? extends A> supplier,
401         final IntFunction<A[]> generator,
402         final Predicate<? super A> alleleValidator,
403         final Predicate<? super ISeq<? super A>> alleleSeqValidator,
404         final int length
405     ) {
406         requireNonNull(supplier);
407         requireNonNull(generator);
408         requireNonNull(alleleSeqValidator);
409         requireNonNull(alleleSeqValidator);
410         require.positive(length);
411 
412         return Codec.of(
413             Genotype.of(AnyChromosome
414                 .of(supplier, alleleValidator, alleleSeqValidator, length)),
415             gt -> gt.getChromosome().toSeq().stream()
416                 .map(Gene::getAllele)
417                 .toArray(generator)
418         );
419     }
420 
421     /**
422      * Return a scala {@code Codec} with the given allele {@link Supplier},
423      * allele {@code validator} and {@code Chromosome} length. The
424      * {@code supplier} is responsible for creating new random alleles, and the
425      * {@code validator} can verify it.
426      <p>
427      * The following example shows a codec which creates and verifies
428      * {@code BigInteger} object arrays.
429      <pre>{@code
430      * final Codec<BigInteger[], AnyGene<BigInteger>> codec = codecs.of(
431      *     // Create new random 'BigInteger' object.
432      *     () -> {
433      *         final byte[] data = new byte[100];
434      *         RandomRegistry.getRandom().nextBytes(data);
435      *         return new BigInteger(data);
436      *     },
437      *     // Verify that bit 7 is set. (For illustration purpose.)
438      *     bi -> bi.testBit(7),
439      *     // The 'Chromosome' length.
440      *     123
441      * );
442      * }</pre>
443      *
444      @see AnyChromosome#of(Supplier, Predicate, Predicate, int)
445      *
446      @param <A> the allele type
447      @param supplier the allele-supplier which is used for creating new,
448      *        random alleles
449      @param alleleValidator the validator used for validating the created gene.
450      *        This predicate is used in the {@link AnyGene#isValid()} method.
451      @param alleleSeqValidator the validator used for validating the created
452      *        chromosome. This predicate is used in the
453      *        {@link AnyChromosome#isValid()} method.
454      @param length the vector length
455      @return a new {@code Codec} with the given parameters
456      @throws NullPointerException if one of the parameters is {@code null}
457      @throws IllegalArgumentException if the length of the vector is smaller
458      *         than one.
459      */
460     public static <A> Codec<ISeq<A>, AnyGene<A>> ofVector(
461         final Supplier<? extends A> supplier,
462         final Predicate<? super A> alleleValidator,
463         final Predicate<? super ISeq<? super A>> alleleSeqValidator,
464         final int length
465     ) {
466         requireNonNull(supplier);
467         requireNonNull(alleleSeqValidator);
468         requireNonNull(alleleSeqValidator);
469         require.positive(length);
470 
471         return Codec.of(
472             Genotype.of(AnyChromosome
473                 .of(supplier, alleleValidator, alleleSeqValidator, length)),
474             gt -> gt.getChromosome().toSeq().map(Gene::getAllele)
475         );
476     }
477 
478     /**
479      * Return a scala {@code Codec} with the given allele {@link Supplier},
480      * allele {@code validator} and {@code Chromosome} length. The
481      * {@code supplier} is responsible for creating new random alleles, and the
482      * {@code validator} can verify it.
483      *
484      @param <A> the allele type
485      @param supplier the allele-supplier which is used for creating new,
486      *        random alleles
487      @param generator the array generator used for generating arrays of type
488      *        {@code A}
489      @param validator the validator used for validating the created gene. This
490      *        predicate is used in the {@link AnyGene#isValid()} method.
491      @param length the vector length
492      @return a new {@code Codec} with the given parameters
493      @throws NullPointerException if one of the parameters is {@code null}
494      @throws IllegalArgumentException if the length of the vector is smaller
495      *         than one.
496      *
497      @deprecated Use {@link #ofVector(Supplier, Predicate, int)} instead
498      */
499     @Deprecated
500     public static <A> Codec<A[], AnyGene<A>> ofVector(
501         final Supplier<? extends A> supplier,
502         final IntFunction<A[]> generator,
503         final Predicate<? super A> validator,
504         final int length
505     ) {
506         return ofVector(supplier, generator, validator, Equality.TRUE, length);
507     }
508 
509     /**
510      * Return a scala {@code Codec} with the given allele {@link Supplier},
511      * allele {@code validator} and {@code Chromosome} length. The
512      * {@code supplier} is responsible for creating new random alleles, and the
513      * {@code validator} can verify it.
514      *
515      @param <A> the allele type
516      @param supplier the allele-supplier which is used for creating new,
517      *        random alleles
518      @param validator the validator used for validating the created gene. This
519      *        predicate is used in the {@link AnyGene#isValid()} method.
520      @param length the vector length
521      @return a new {@code Codec} with the given parameters
522      @throws NullPointerException if one of the parameters is {@code null}
523      @throws IllegalArgumentException if the length of the vector is smaller
524      *         than one.
525      */
526     public static <A> Codec<ISeq<A>, AnyGene<A>> ofVector(
527         final Supplier<? extends A> supplier,
528         final Predicate<? super A> validator,
529         final int length
530     ) {
531         return ofVector(supplier, validator, Equality.TRUE, length);
532     }
533 
534     /**
535      * Return a scala {@code Codec} with the given allele {@link Supplier} and
536      * {@code Chromosome} length. The {@code supplier} is responsible for
537      * creating new random alleles.
538      *
539      @param <A> the allele type
540      @param supplier the allele-supplier which is used for creating new,
541      *        random alleles
542      @param generator the array generator used for generating arrays of type
543      *        {@code A}
544      @param length the vector length
545      @return a new {@code Codec} with the given parameters
546      @throws NullPointerException if one of the parameters is {@code null}
547      @throws IllegalArgumentException if the length of the vector is smaller
548      *         than one.
549      *
550      @deprecated Use {@link #ofVector(Supplier, int)} instead
551      */
552     @Deprecated
553     public static <A> Codec<A[], AnyGene<A>> ofVector(
554         final Supplier<? extends A> supplier,
555         final IntFunction<A[]> generator,
556         final int length
557     ) {
558         return ofVector(supplier, generator, Equality.TRUE, length);
559     }
560 
561     /**
562      * Return a scala {@code Codec} with the given allele {@link Supplier} and
563      * {@code Chromosome} length. The {@code supplier} is responsible for
564      * creating new random alleles.
565      *
566      @param <A> the allele type
567      @param supplier the allele-supplier which is used for creating new,
568      *        random alleles
569      @param length the vector length
570      @return a new {@code Codec} with the given parameters
571      @throws NullPointerException if one of the parameters is {@code null}
572      @throws IllegalArgumentException if the length of the vector is smaller
573      *         than one.
574      */
575     public static <A> Codec<ISeq<A>, AnyGene<A>> ofVector(
576         final Supplier<? extends A> supplier,
577         final int length
578     ) {
579         return ofVector(supplier, Equality.TRUE, length);
580     }
581 
582     /**
583      * Create a permutation {@code Codec} of integer in the range
584      * {@code [0, length)}.
585      *
586      @param length the number of permutation elements
587      @return a permutation {@code Codec} of integers
588      @throws IllegalArgumentException if the {@code length} is smaller than
589      *         one.
590      */
591     public static Codec<int[], EnumGene<Integer>> ofPermutation(final int length) {
592         require.positive(length);
593 
594         return Codec.of(
595             Genotype.of(PermutationChromosome.ofInteger(length)),
596             gt -> gt.getChromosome().toSeq().stream()
597                 .mapToInt(EnumGene<Integer>::getAllele)
598                 .toArray()
599         );
600     }
601 
602     /**
603      * Create a permutation {@code Codec} with the given alleles.
604      *
605      @param alleles the alleles of the permutation
606      @param <T> the allele type
607      @return a new permutation {@code Codec}
608      @throws IllegalArgumentException if the given allele array is empty
609      @throws NullPointerException if one of the alleles is {@code null}
610      *
611      @deprecated Use {@link #ofPermutation(ISeq)} instead
612      */
613     @Deprecated
614     @SafeVarargs
615     public static <T> Codec<T[], EnumGene<T>> ofPermutation(final T... alleles) {
616         if (alleles.length == 0) {
617             throw new IllegalArgumentException(
618                 "Empty allele array is not allowed."
619             );
620         }
621 
622         return Codec.of(
623             Genotype.of(PermutationChromosome.of(alleles)),
624             gt -> gt.getChromosome().toSeq().stream()
625                 .map(EnumGene::getAllele)
626                 .toArray(length -> newArray(alleles[0].getClass(), length))
627         );
628     }
629 
630     @SuppressWarnings("unchecked")
631     private static <T> T[] newArray(final Class<?> type, final int length) {
632         return (T[])newInstance(type, length);
633     }
634 
635     /**
636      * Create a permutation {@code Codec} with the given alleles.
637      *
638      @param alleles the alleles of the permutation
639      @param <T> the allele type
640      @return a new permutation {@code Codec}
641      @throws IllegalArgumentException if the given allele array is empty
642      @throws NullPointerException if one of the alleles is {@code null}
643      */
644     public static <T> Codec<ISeq<T>, EnumGene<T>>
645     ofPermutation(final ISeq<T> alleles) {
646         if (alleles.isEmpty()) {
647             throw new IllegalArgumentException(
648                 "Empty allele array is not allowed."
649             );
650         }
651 
652         return Codec.of(
653             Genotype.of(PermutationChromosome.of(alleles)),
654             gt -> gt.getChromosome().toSeq().map(EnumGene::getAllele)
655         );
656     }
657 
658     /**
659      * The subset {@code Codec} can be used for problems where it is required to
660      * find the best <b>variable-sized</b> subset from given basic set. A typical
661      * usage example of the returned {@code Codec} is the Knapsack problem.
662      <p>
663      * The following code snippet shows a simplified variation of the Knapsack
664      * problem.
665      <pre>{@code
666      * public final class Main {
667      *     // The basic set from where to choose an 'optimal' subset.
668      *     private final static ISeq<Integer> SET =
669      *         ISeq.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
670      *
671      *     // Fitness function directly takes an 'int' value.
672      *     private static int fitness(final ISeq<Integer> subset) {
673      *         assert(subset.size() <= SET.size());
674      *         final int size = subset.stream()
675      *             .collect(Collectors.summingInt(Integer::intValue));
676      *         return size <= 20 ? size : 0;
677      *     }
678      *
679      *     public static void main(final String[] args) {
680      *         final Engine<BitGene, Double> engine = Engine
681      *             .builder(Main::fitness, codec.ofSubSet(SET))
682      *             .build();
683      *         ...
684      *     }
685      * }
686      * }</pre>
687      *
688      @param <T> the element type of the basic set
689      @param basicSet the basic set, from where to choose the <i>optimal</i>
690      *        subset.
691      @return a new codec which can be used for modelling <i>subset</i>
692      *         problems.
693      @throws NullPointerException if the given {@code basicSet} is
694      *         {@code null}; {@code null} elements are allowed.
695      @throws IllegalArgumentException if the {@code basicSet} size is smaller
696      *         than one.
697      */
698     public static <T> Codec<ISeq<T>, BitGene> ofSubSet(
699         final ISeq<? extends T> basicSet
700     ) {
701         requireNonNull(basicSet);
702         require.positive(basicSet.length());
703 
704         return Codec.of(
705             Genotype.of(BitChromosome.of(basicSet.length())),
706             gt -> ((BitChromosome)gt.getChromosome()).ones()
707                 .<T>mapToObj(basicSet::get)
708                 .collect(ISeq.toISeq())
709         );
710     }
711 
712     /**
713      * The subset {@code Codec} can be used for problems where it is required to
714      * find the best <b>fixed-size</b> subset from given basic set.
715      *
716      @since 3.4
717      *
718      @see PermutationChromosome
719      @see PermutationChromosome#of(ISeq, int)
720      *
721      @param <T> the element type of the basic set
722      @param basicSet the basic set, from where to choose the <i>optimal</i>
723      *        subset.
724      @param size the length of the desired subsets
725      @return a new codec which can be used for modelling <i>subset</i>
726      *         problems.
727      @throws NullPointerException if the given {@code basicSet} is
728      *         {@code null}; {@code null} elements are allowed.
729      @throws IllegalArgumentException if {@code basicSet.size() < size},
730      *         {@code size <= 0} or {@code basicSet.size()*size} will cause an
731      *         integer overflow.
732      */
733     public static <T> Codec<ISeq<T>, EnumGene<T>> ofSubSet(
734         final ISeq<? extends T> basicSet,
735         final int size
736     ) {
737         requireNonNull(basicSet);
738         base.checkSubSet(basicSet.size(), size);
739 
740         return Codec.of(
741             Genotype.of(PermutationChromosome.of(basicSet, size)),
742             gt -> gt.getChromosome().stream()
743                 .map(EnumGene::getAllele)
744                 .collect(ISeq.toISeq())
745         );
746     }
747 
748     // https://trac.osgeo.org/postgis/wiki/DevWikiAffineParameters
749 
750     /**
751      * Creates a codec for a 2-dimensional affine transformation. The composed
752      * order of the transformation is: <i>R&bull;Sc&bull;Sh&bull;T</i>
753      *
754      @param sx the scale factor range in x direction
755      @param sy the scale factor range in y direction
756      @param tx the translation range in x direction
757      @param ty the translation range in y direction
758      @param th the rotation range (in radians)
759      @param kx the shear range in x direction
760      @param ky the shear range in x direction
761      @return the affine transformation codec
762      @throws NullPointerException if one of the arguments is {@code null}
763      */
764     static Codec<AffineTransform, DoubleGene> ofAffineTransform(
765         final DoubleRange sx, final DoubleRange sy,
766         final DoubleRange tx, final DoubleRange ty,
767         final DoubleRange th,
768         final DoubleRange kx, final DoubleRange ky
769     ) {
770         return Codec.of(
771             Genotype.of(
772                 // Scale
773                 DoubleChromosome.of(sx), DoubleChromosome.of(sy),
774                 // Translation
775                 DoubleChromosome.of(tx), DoubleChromosome.of(ty),
776                 // Rotation
777                 DoubleChromosome.of(th),
778                 // Shear
779                 DoubleChromosome.of(kx), DoubleChromosome.of(ky)
780             ),
781             gt -> {
782                 final AffineTransform at = new AffineTransform();
783 
784                 at.translate(
785                     gt.getChromosome(2).getGene().doubleValue(),
786                     gt.getChromosome(3).getGene().doubleValue()
787                 );
788                 at.shear(
789                     gt.getChromosome(5).getGene().doubleValue(),
790                     gt.getChromosome(6).getGene().doubleValue()
791                 );
792                 at.scale(
793                     gt.getChromosome(0).getGene().doubleValue(),
794                     gt.getChromosome(1).getGene().doubleValue()
795                 );
796                 at.rotate(gt.getChromosome(4).getGene().doubleValue());
797 
798                 return at;
799             }
800         );
801     }
802 
803     /**
804      * Creates a codec for a 2-dimensional affine transformation. The composed
805      * order of the transformation is: <i>R&bull;Sc&bull;Sh&bull;T</i>
806      *
807      @param s the scale factor range in x and y direction
808      @param t the translation range in x and y direction
809      @param th the rotation angle range
810      @param k the shear range in x and y direction
811      @return the affine transformation codec
812      @throws NullPointerException if one of the arguments is {@code null}
813      */
814     static Codec<AffineTransform, DoubleGene> ofAffineTransform(
815         final DoubleRange s,
816         final DoubleRange t,
817         final DoubleRange th,
818         final DoubleRange k
819     ) {
820         return ofAffineTransform(s, s, t, t, th, k, k);
821     }
822 
823 }