001 /*
002 * Java Genetic Algorithm Library (jenetics-3.7.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 * @deprecated Use {@link #ofVector(Supplier, Predicate, Predicate, int)}
396 * instead
397 */
398 @Deprecated
399 public static <A> Codec<A[], AnyGene<A>> ofVector(
400 final Supplier<? extends A> supplier,
401 final IntFunction<A[]> generator,
402 final Predicate<? super A> alleleValidator,
403 final Predicate<? super ISeq<? super A>> alleleSeqValidator,
404 final int length
405 ) {
406 requireNonNull(supplier);
407 requireNonNull(generator);
408 requireNonNull(alleleSeqValidator);
409 requireNonNull(alleleSeqValidator);
410 require.positive(length);
411
412 return Codec.of(
413 Genotype.of(AnyChromosome
414 .of(supplier, alleleValidator, alleleSeqValidator, length)),
415 gt -> gt.getChromosome().toSeq().stream()
416 .map(Gene::getAllele)
417 .toArray(generator)
418 );
419 }
420
421 /**
422 * Return a scala {@code Codec} with the given allele {@link Supplier},
423 * allele {@code validator} and {@code Chromosome} length. The
424 * {@code supplier} is responsible for creating new random alleles, and the
425 * {@code validator} can verify it.
426 * <p>
427 * The following example shows a codec which creates and verifies
428 * {@code BigInteger} object arrays.
429 * <pre>{@code
430 * final Codec<BigInteger[], AnyGene<BigInteger>> codec = codecs.of(
431 * // Create new random 'BigInteger' object.
432 * () -> {
433 * final byte[] data = new byte[100];
434 * RandomRegistry.getRandom().nextBytes(data);
435 * return new BigInteger(data);
436 * },
437 * // Verify that bit 7 is set. (For illustration purpose.)
438 * bi -> bi.testBit(7),
439 * // The 'Chromosome' length.
440 * 123
441 * );
442 * }</pre>
443 *
444 * @see AnyChromosome#of(Supplier, Predicate, Predicate, int)
445 *
446 * @param <A> the allele type
447 * @param supplier the allele-supplier which is used for creating new,
448 * random alleles
449 * @param alleleValidator the validator used for validating the created gene.
450 * This predicate is used in the {@link AnyGene#isValid()} method.
451 * @param alleleSeqValidator the validator used for validating the created
452 * chromosome. This predicate is used in the
453 * {@link AnyChromosome#isValid()} method.
454 * @param length the vector length
455 * @return a new {@code Codec} with the given parameters
456 * @throws NullPointerException if one of the parameters is {@code null}
457 * @throws IllegalArgumentException if the length of the vector is smaller
458 * than one.
459 */
460 public static <A> Codec<ISeq<A>, AnyGene<A>> ofVector(
461 final Supplier<? extends A> supplier,
462 final Predicate<? super A> alleleValidator,
463 final Predicate<? super ISeq<? super A>> alleleSeqValidator,
464 final int length
465 ) {
466 requireNonNull(supplier);
467 requireNonNull(alleleSeqValidator);
468 requireNonNull(alleleSeqValidator);
469 require.positive(length);
470
471 return Codec.of(
472 Genotype.of(AnyChromosome
473 .of(supplier, alleleValidator, alleleSeqValidator, length)),
474 gt -> gt.getChromosome().toSeq().map(Gene::getAllele)
475 );
476 }
477
478 /**
479 * Return a scala {@code Codec} with the given allele {@link Supplier},
480 * allele {@code validator} and {@code Chromosome} length. The
481 * {@code supplier} is responsible for creating new random alleles, and the
482 * {@code validator} can verify it.
483 *
484 * @param <A> the allele type
485 * @param supplier the allele-supplier which is used for creating new,
486 * random alleles
487 * @param generator the array generator used for generating arrays of type
488 * {@code A}
489 * @param validator the validator used for validating the created gene. This
490 * predicate is used in the {@link AnyGene#isValid()} method.
491 * @param length the vector length
492 * @return a new {@code Codec} with the given parameters
493 * @throws NullPointerException if one of the parameters is {@code null}
494 * @throws IllegalArgumentException if the length of the vector is smaller
495 * than one.
496 *
497 * @deprecated Use {@link #ofVector(Supplier, Predicate, int)} instead
498 */
499 @Deprecated
500 public static <A> Codec<A[], AnyGene<A>> ofVector(
501 final Supplier<? extends A> supplier,
502 final IntFunction<A[]> generator,
503 final Predicate<? super A> validator,
504 final int length
505 ) {
506 return ofVector(supplier, generator, validator, Equality.TRUE, length);
507 }
508
509 /**
510 * Return a scala {@code Codec} with the given allele {@link Supplier},
511 * allele {@code validator} and {@code Chromosome} length. The
512 * {@code supplier} is responsible for creating new random alleles, and the
513 * {@code validator} can verify it.
514 *
515 * @param <A> the allele type
516 * @param supplier the allele-supplier which is used for creating new,
517 * random alleles
518 * @param validator the validator used for validating the created gene. This
519 * predicate is used in the {@link AnyGene#isValid()} method.
520 * @param length the vector length
521 * @return a new {@code Codec} with the given parameters
522 * @throws NullPointerException if one of the parameters is {@code null}
523 * @throws IllegalArgumentException if the length of the vector is smaller
524 * than one.
525 */
526 public static <A> Codec<ISeq<A>, AnyGene<A>> ofVector(
527 final Supplier<? extends A> supplier,
528 final Predicate<? super A> validator,
529 final int length
530 ) {
531 return ofVector(supplier, validator, Equality.TRUE, length);
532 }
533
534 /**
535 * Return a scala {@code Codec} with the given allele {@link Supplier} and
536 * {@code Chromosome} length. The {@code supplier} is responsible for
537 * creating new random alleles.
538 *
539 * @param <A> the allele type
540 * @param supplier the allele-supplier which is used for creating new,
541 * random alleles
542 * @param generator the array generator used for generating arrays of type
543 * {@code A}
544 * @param length the vector length
545 * @return a new {@code Codec} with the given parameters
546 * @throws NullPointerException if one of the parameters is {@code null}
547 * @throws IllegalArgumentException if the length of the vector is smaller
548 * than one.
549 *
550 * @deprecated Use {@link #ofVector(Supplier, int)} instead
551 */
552 @Deprecated
553 public static <A> Codec<A[], AnyGene<A>> ofVector(
554 final Supplier<? extends A> supplier,
555 final IntFunction<A[]> generator,
556 final int length
557 ) {
558 return ofVector(supplier, generator, Equality.TRUE, length);
559 }
560
561 /**
562 * Return a scala {@code Codec} with the given allele {@link Supplier} and
563 * {@code Chromosome} length. The {@code supplier} is responsible for
564 * creating new random alleles.
565 *
566 * @param <A> the allele type
567 * @param supplier the allele-supplier which is used for creating new,
568 * random alleles
569 * @param length the vector length
570 * @return a new {@code Codec} with the given parameters
571 * @throws NullPointerException if one of the parameters is {@code null}
572 * @throws IllegalArgumentException if the length of the vector is smaller
573 * than one.
574 */
575 public static <A> Codec<ISeq<A>, AnyGene<A>> ofVector(
576 final Supplier<? extends A> supplier,
577 final int length
578 ) {
579 return ofVector(supplier, Equality.TRUE, length);
580 }
581
582 /**
583 * Create a permutation {@code Codec} of integer in the range
584 * {@code [0, length)}.
585 *
586 * @param length the number of permutation elements
587 * @return a permutation {@code Codec} of integers
588 * @throws IllegalArgumentException if the {@code length} is smaller than
589 * one.
590 */
591 public static Codec<int[], EnumGene<Integer>> ofPermutation(final int length) {
592 require.positive(length);
593
594 return Codec.of(
595 Genotype.of(PermutationChromosome.ofInteger(length)),
596 gt -> gt.getChromosome().toSeq().stream()
597 .mapToInt(EnumGene<Integer>::getAllele)
598 .toArray()
599 );
600 }
601
602 /**
603 * Create a permutation {@code Codec} with the given alleles.
604 *
605 * @param alleles the alleles of the permutation
606 * @param <T> the allele type
607 * @return a new permutation {@code Codec}
608 * @throws IllegalArgumentException if the given allele array is empty
609 * @throws NullPointerException if one of the alleles is {@code null}
610 *
611 * @deprecated Use {@link #ofPermutation(ISeq)} instead
612 */
613 @Deprecated
614 @SafeVarargs
615 public static <T> Codec<T[], EnumGene<T>> ofPermutation(final T... alleles) {
616 if (alleles.length == 0) {
617 throw new IllegalArgumentException(
618 "Empty allele array is not allowed."
619 );
620 }
621
622 return Codec.of(
623 Genotype.of(PermutationChromosome.of(alleles)),
624 gt -> gt.getChromosome().toSeq().stream()
625 .map(EnumGene::getAllele)
626 .toArray(length -> newArray(alleles[0].getClass(), length))
627 );
628 }
629
630 @SuppressWarnings("unchecked")
631 private static <T> T[] newArray(final Class<?> type, final int length) {
632 return (T[])newInstance(type, length);
633 }
634
635 /**
636 * Create a permutation {@code Codec} with the given alleles.
637 *
638 * @param alleles the alleles of the permutation
639 * @param <T> the allele type
640 * @return a new permutation {@code Codec}
641 * @throws IllegalArgumentException if the given allele array is empty
642 * @throws NullPointerException if one of the alleles is {@code null}
643 */
644 public static <T> Codec<ISeq<T>, EnumGene<T>>
645 ofPermutation(final ISeq<T> alleles) {
646 if (alleles.isEmpty()) {
647 throw new IllegalArgumentException(
648 "Empty allele array is not allowed."
649 );
650 }
651
652 return Codec.of(
653 Genotype.of(PermutationChromosome.of(alleles)),
654 gt -> gt.getChromosome().toSeq().map(EnumGene::getAllele)
655 );
656 }
657
658 /**
659 * The subset {@code Codec} can be used for problems where it is required to
660 * find the best <b>variable-sized</b> subset from given basic set. A typical
661 * usage example of the returned {@code Codec} is the Knapsack problem.
662 * <p>
663 * The following code snippet shows a simplified variation of the Knapsack
664 * problem.
665 * <pre>{@code
666 * public final class Main {
667 * // The basic set from where to choose an 'optimal' subset.
668 * private final static ISeq<Integer> SET =
669 * ISeq.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
670 *
671 * // Fitness function directly takes an 'int' value.
672 * private static int fitness(final ISeq<Integer> subset) {
673 * assert(subset.size() <= SET.size());
674 * final int size = subset.stream()
675 * .collect(Collectors.summingInt(Integer::intValue));
676 * return size <= 20 ? size : 0;
677 * }
678 *
679 * public static void main(final String[] args) {
680 * final Engine<BitGene, Double> engine = Engine
681 * .builder(Main::fitness, codec.ofSubSet(SET))
682 * .build();
683 * ...
684 * }
685 * }
686 * }</pre>
687 *
688 * @param <T> the element type of the basic set
689 * @param basicSet the basic set, from where to choose the <i>optimal</i>
690 * subset.
691 * @return a new codec which can be used for modelling <i>subset</i>
692 * problems.
693 * @throws NullPointerException if the given {@code basicSet} is
694 * {@code null}; {@code null} elements are allowed.
695 * @throws IllegalArgumentException if the {@code basicSet} size is smaller
696 * than one.
697 */
698 public static <T> Codec<ISeq<T>, BitGene> ofSubSet(
699 final ISeq<? extends T> basicSet
700 ) {
701 requireNonNull(basicSet);
702 require.positive(basicSet.length());
703
704 return Codec.of(
705 Genotype.of(BitChromosome.of(basicSet.length())),
706 gt -> ((BitChromosome)gt.getChromosome()).ones()
707 .<T>mapToObj(basicSet::get)
708 .collect(ISeq.toISeq())
709 );
710 }
711
712 /**
713 * The subset {@code Codec} can be used for problems where it is required to
714 * find the best <b>fixed-size</b> subset from given basic set.
715 *
716 * @since 3.4
717 *
718 * @see PermutationChromosome
719 * @see PermutationChromosome#of(ISeq, int)
720 *
721 * @param <T> the element type of the basic set
722 * @param basicSet the basic set, from where to choose the <i>optimal</i>
723 * subset.
724 * @param size the length of the desired subsets
725 * @return a new codec which can be used for modelling <i>subset</i>
726 * problems.
727 * @throws NullPointerException if the given {@code basicSet} is
728 * {@code null}; {@code null} elements are allowed.
729 * @throws IllegalArgumentException if {@code basicSet.size() < size},
730 * {@code size <= 0} or {@code basicSet.size()*size} will cause an
731 * integer overflow.
732 */
733 public static <T> Codec<ISeq<T>, EnumGene<T>> ofSubSet(
734 final ISeq<? extends T> basicSet,
735 final int size
736 ) {
737 requireNonNull(basicSet);
738 base.checkSubSet(basicSet.size(), size);
739
740 return Codec.of(
741 Genotype.of(PermutationChromosome.of(basicSet, size)),
742 gt -> gt.getChromosome().stream()
743 .map(EnumGene::getAllele)
744 .collect(ISeq.toISeq())
745 );
746 }
747
748 // https://trac.osgeo.org/postgis/wiki/DevWikiAffineParameters
749
750 /**
751 * Creates a codec for a 2-dimensional affine transformation. The composed
752 * order of the transformation is: <i>R•Sc•Sh•T</i>
753 *
754 * @param sx the scale factor range in x direction
755 * @param sy the scale factor range in y direction
756 * @param tx the translation range in x direction
757 * @param ty the translation range in y direction
758 * @param th the rotation range (in radians)
759 * @param kx the shear range in x direction
760 * @param ky the shear range in x direction
761 * @return the affine transformation codec
762 * @throws NullPointerException if one of the arguments is {@code null}
763 */
764 static Codec<AffineTransform, DoubleGene> ofAffineTransform(
765 final DoubleRange sx, final DoubleRange sy,
766 final DoubleRange tx, final DoubleRange ty,
767 final DoubleRange th,
768 final DoubleRange kx, final DoubleRange ky
769 ) {
770 return Codec.of(
771 Genotype.of(
772 // Scale
773 DoubleChromosome.of(sx), DoubleChromosome.of(sy),
774 // Translation
775 DoubleChromosome.of(tx), DoubleChromosome.of(ty),
776 // Rotation
777 DoubleChromosome.of(th),
778 // Shear
779 DoubleChromosome.of(kx), DoubleChromosome.of(ky)
780 ),
781 gt -> {
782 final AffineTransform at = new AffineTransform();
783
784 at.translate(
785 gt.getChromosome(2).getGene().doubleValue(),
786 gt.getChromosome(3).getGene().doubleValue()
787 );
788 at.shear(
789 gt.getChromosome(5).getGene().doubleValue(),
790 gt.getChromosome(6).getGene().doubleValue()
791 );
792 at.scale(
793 gt.getChromosome(0).getGene().doubleValue(),
794 gt.getChromosome(1).getGene().doubleValue()
795 );
796 at.rotate(gt.getChromosome(4).getGene().doubleValue());
797
798 return at;
799 }
800 );
801 }
802
803 /**
804 * Creates a codec for a 2-dimensional affine transformation. The composed
805 * order of the transformation is: <i>R•Sc•Sh•T</i>
806 *
807 * @param s the scale factor range in x and y direction
808 * @param t the translation range in x and y direction
809 * @param th the rotation angle range
810 * @param k the shear range in x and y direction
811 * @return the affine transformation codec
812 * @throws NullPointerException if one of the arguments is {@code null}
813 */
814 static Codec<AffineTransform, DoubleGene> ofAffineTransform(
815 final DoubleRange s,
816 final DoubleRange t,
817 final DoubleRange th,
818 final DoubleRange k
819 ) {
820 return ofAffineTransform(s, s, t, t, th, k, k);
821 }
822
823 }
|