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•Sc•Sh•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•Sc•Sh•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 }
|