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