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