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