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