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