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