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