001/* 002 * Java Genetic Algorithm Library (jenetics-8.1.0). 003 * Copyright (c) 2007-2024 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 */ 020package io.jenetics.xml; 021 022import static java.lang.String.format; 023import static java.util.Objects.requireNonNull; 024import static io.jenetics.xml.stream.Reader.attr; 025import static io.jenetics.xml.stream.Reader.elem; 026import static io.jenetics.xml.stream.Reader.elems; 027import static io.jenetics.xml.stream.Reader.text; 028 029import java.io.InputStream; 030import java.util.List; 031import java.util.function.Function; 032import java.util.function.IntFunction; 033import java.util.stream.Stream; 034 035import javax.xml.stream.XMLStreamException; 036 037import io.jenetics.BoundedGene; 038import io.jenetics.Chromosome; 039import io.jenetics.DoubleGene; 040import io.jenetics.EnumGene; 041import io.jenetics.Gene; 042import io.jenetics.IntegerGene; 043import io.jenetics.LongGene; 044import io.jenetics.util.CharSeq; 045import io.jenetics.util.ISeq; 046import io.jenetics.util.MSeq; 047import io.jenetics.xml.stream.AutoCloseableXMLStreamReader; 048import io.jenetics.xml.stream.Reader; 049import io.jenetics.xml.stream.XML; 050 051/** 052 * This class contains static fields and methods, for creating chromosome- and 053 * genotype readers for different gene types. 054 * 055 * {@snippet lang="java": 056 * final Reader<Genotype<BitGene>> bgr = 057 * Readers.Genotype.reader(Readers.BitChromosome.reader()); 058 * 059 * final Reader<Genotype<IntegerGene>> igr = 060 * Writers.Genotype.reader(Readers.IntegerChromosome.reader()); 061 * 062 * final Reader<Genotype<DoubleGene>> dgr = 063 * Readers.Genotype.reader(Readers.DoubleChromosome.reader()); 064 * } 065 * 066 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 067 * @version 3.9 068 * @since 3.9 069 */ 070public final class Readers { 071 private Readers() {} 072 073 /** 074 * Bit chromosome reader methods, which reads XML-representations of 075 * bit-chromosomes. 076 * <p> 077 * <b>XML</b> 078 * <pre> {@code 079 * <bit-chromosome length="20" ones-probability="0.5">11100011101011001010</bit-chromosome> 080 * } </pre> 081 */ 082 public static final class BitChromosome { 083 private BitChromosome() {} 084 085 /** 086 * Return a XML reader for {@link io.jenetics.BitChromosome} objects. 087 * 088 * @return a chromosome reader 089 */ 090 public static Reader<io.jenetics.BitChromosome> reader() { 091 return elem( 092 v -> io.jenetics.BitChromosome.of( 093 (String)v[2], (int)v[0], (double)v[1] 094 ), 095 Writers.BitChromosome.ROOT_NAME, 096 attr(Writers.BitChromosome.LENGTH_NAME) 097 .map(Integer::parseInt), 098 attr(Writers.BitChromosome.ONES_PROBABILITY_NAME) 099 .map(Double::parseDouble), 100 text() 101 ); 102 } 103 104 /** 105 * Read a new {@link io.jenetics.BitChromosome} from the given input 106 * stream. 107 * 108 * @param in the data source of the bit-chromosome 109 * @return the bit-chromosome read from the input stream 110 * @throws XMLStreamException if reading the chromosome fails 111 * @throws NullPointerException if the given input stream is {@code null} 112 */ 113 public static io.jenetics.BitChromosome read(final InputStream in) 114 throws XMLStreamException 115 { 116 try (AutoCloseableXMLStreamReader xml = XML.reader(in)) { 117 xml.next(); 118 return reader().read(xml); 119 } 120 } 121 } 122 123 /** 124 * Reader methods for {@link io.jenetics.CharacterChromosome} objects. 125 * <p> 126 * <b>XML format</b> 127 * <pre> {@code 128 * <character-chromosome length="4"> 129 * <valid-alleles>ABCDEFGHIJKLMNOPQRSTUVWXYZ<valid-alleles> 130 * <alleles>ASDF</alleles> 131 * </character-chromosome> 132 * } </pre> 133 */ 134 public static final class CharacterChromosome { 135 private CharacterChromosome() {} 136 137 /** 138 * Return a XML reader for {@link io.jenetics.CharacterChromosome} 139 * objects. 140 * 141 * @return a chromosome reader 142 */ 143 public static Reader<io.jenetics.CharacterChromosome> reader() { 144 return elem( 145 v -> io.jenetics.CharacterChromosome.of( 146 (String)v[2], (CharSeq)v[1] 147 ), 148 Writers.CharacterChromosome.ROOT_NAME, 149 attr(Writers.CharacterChromosome.LENGTH_NAME) 150 .map(Integer::parseInt), 151 elem(Writers.CharacterChromosome.VALID_ALLELES_NAME, 152 text().map(CharSeq::new)), 153 elem(Writers.CharacterChromosome.ALLELES_NAME, text()) 154 ); 155 } 156 157 /** 158 * Read a new {@link io.jenetics.CharacterChromosome} from the given 159 * input stream. 160 * 161 * @param in the data source of the chromosome 162 * @return the bit-chromosome read from the input stream 163 * @throws XMLStreamException if reading the chromosome fails 164 * @throws NullPointerException if the given input stream is {@code null} 165 */ 166 public static io.jenetics.CharacterChromosome read(final InputStream in) 167 throws XMLStreamException 168 { 169 try (AutoCloseableXMLStreamReader xml = XML.reader(in)) { 170 xml.next(); 171 return reader().read(xml); 172 } 173 } 174 175 } 176 177 /** 178 * Reader methods for {@link io.jenetics.BoundedChromosome} objects. 179 * <p> 180 * <b>XML format</b> 181 * <pre> {@code 182 * <root-name length="3"> 183 * <min>aaa</min> 184 * <max>zzz</max> 185 * <alleles> 186 * <allele>iii</allele> 187 * <allele>fff</allele> 188 * <allele>ggg</allele> 189 * </alleles> 190 * </root-name> 191 * } </pre> 192 */ 193 public static final class BoundedChromosome { 194 private BoundedChromosome() {} 195 196 /** 197 * Create a bounded chromosome reader with the given configuration. 198 * 199 * @param name the root element name 200 * @param gene the gene creator 201 * @param genes the gene array creator 202 * @param chromosome the chromosome creator 203 * @param alleleReader the allele reader 204 * @param <A> the allele type 205 * @param <G> the gene type 206 * @param <C> the chromosome type 207 * @return a bounded chromosome reader 208 * @throws NullPointerException if one of the arguments is {@code null} 209 */ 210 public static < 211 A extends Comparable<? super A>, 212 G extends BoundedGene<A, G>, 213 C extends io.jenetics.BoundedChromosome<A, G> 214 > 215 Reader<C> reader( 216 final String name, 217 final BoundedGeneCreator<A, G> gene, 218 final IntFunction<G[]> genes, 219 final Function<G[], C> chromosome, 220 final Reader<? extends A> alleleReader 221 ) { 222 return elem(v -> { 223 final int length = (int)v[0]; 224 @SuppressWarnings("unchecked") 225 final A min = (A)v[1]; 226 @SuppressWarnings("unchecked") 227 final A max = (A)v[2]; 228 @SuppressWarnings("unchecked") 229 final List<A> alleles = (List<A>)v[3]; 230 231 if (alleles.size() != length) { 232 throw new IllegalArgumentException(format( 233 "Expected %d alleles, but got %d,", 234 length, alleles.size() 235 )); 236 } 237 238 return chromosome.apply( 239 alleles.stream() 240 .map(value -> gene.create(value, min, max)) 241 .toArray(genes) 242 ); 243 }, name, 244 attr(Writers.BoundedChromosome.LENGTH_NAME).map(Integer::parseInt), 245 elem(Writers.BoundedChromosome.MIN_NAME, alleleReader), 246 elem(Writers.BoundedChromosome.MAX_NAME, alleleReader), 247 elem(Writers.BoundedChromosome.ALLELES_NAME, 248 elems(elem(Writers.BoundedChromosome.ALLELE_NAME, alleleReader)) 249 ) 250 ); 251 } 252 253 } 254 255 /** 256 * Reader methods for {@link io.jenetics.IntegerChromosome} objects. 257 * <p> 258 * <b>XML format</b> 259 * <pre> {@code 260 * <int-chromosome length="3"> 261 * <min>-2147483648</min> 262 * <max>2147483647</max> 263 * <alleles> 264 * <allele>-1878762439</allele> 265 * <allele>-957346595</allele> 266 * <allele>-88668137</allele> 267 * </alleles> 268 * </int-chromosome> 269 * } </pre> 270 */ 271 public static final class IntegerChromosome { 272 private IntegerChromosome() {} 273 274 /** 275 * Return the default allele reader for the {@code IntegerChromosome}. 276 * 277 * @return the default allele reader 278 */ 279 public static Reader<Integer> alleleReader() { 280 return text().map(Integer::parseInt); 281 } 282 283 /** 284 * Return a {@link io.jenetics.IntegerChromosome} reader. 285 * 286 * @return a integer chromosome reader 287 */ 288 public static Reader<io.jenetics.IntegerChromosome> reader() { 289 return BoundedChromosome.reader( 290 Writers.IntegerChromosome.ROOT_NAME, 291 IntegerGene::of, 292 IntegerGene[]::new, 293 io.jenetics.IntegerChromosome::of, 294 alleleReader() 295 ); 296 } 297 298 /** 299 * Read a new {@link io.jenetics.IntegerChromosome} from the given 300 * input stream. 301 * 302 * @param in the data source of the chromosome 303 * @return a new chromosome 304 * @throws XMLStreamException if reading the chromosome fails 305 * @throws NullPointerException if the given input stream is {@code null} 306 */ 307 public static io.jenetics.IntegerChromosome read(final InputStream in) 308 throws XMLStreamException 309 { 310 try (AutoCloseableXMLStreamReader reader = XML.reader(in)) { 311 reader.next(); 312 return reader().read(reader); 313 } 314 } 315 316 } 317 318 /** 319 * Reader methods for {@link io.jenetics.LongChromosome} objects. 320 * <p> 321 * <b>XML format</b> 322 * <pre> {@code 323 * <long-chromosome length="3"> 324 * <min>-9223372036854775808</min> 325 * <max>9223372036854775807</max> 326 * <alleles> 327 * <allele>-1345217698116542402</allele> 328 * <allele>-7144755673073475303</allele> 329 * <allele>6053786736809578435</allele> 330 * </alleles> 331 * </long-chromosome> 332 * } </pre> 333 */ 334 public static final class LongChromosome { 335 private LongChromosome() {} 336 337 /** 338 * Return the default allele reader for the {@code LongChromosome}. 339 * 340 * @return the default allele reader 341 */ 342 public static Reader<Long> alleleReader() { 343 return text().map(Long::parseLong); 344 } 345 346 /** 347 * Return a {@link io.jenetics.LongChromosome} reader. 348 * 349 * @return a long chromosome reader 350 */ 351 public static Reader<io.jenetics.LongChromosome> reader() { 352 return BoundedChromosome.reader( 353 Writers.LongChromosome.ROOT_NAME, 354 LongGene::of, 355 LongGene[]::new, 356 io.jenetics.LongChromosome::of, 357 alleleReader() 358 ); 359 } 360 361 /** 362 * Read a new {@link io.jenetics.LongChromosome} from the given 363 * input stream. 364 * 365 * @param in the data source of the chromosome 366 * @return a new chromosome 367 * @throws XMLStreamException if reading the chromosome fails 368 * @throws NullPointerException if the given input stream is {@code null} 369 */ 370 public static io.jenetics.LongChromosome read(final InputStream in) 371 throws XMLStreamException 372 { 373 try (var reader = XML.reader(in)) { 374 reader.next(); 375 return reader().read(reader); 376 } 377 } 378 379 } 380 381 /** 382 * Reader methods for {@link io.jenetics.DoubleChromosome} objects. 383 * <p> 384 * <b>XML format</b> 385 * <pre> {@code 386 * <double-chromosome length="3"> 387 * <min>0.0</min> 388 * <max>1.0</max> 389 * <alleles> 390 * <allele>0.27251556008507416</allele> 391 * <allele>0.003140816229067145</allele> 392 * <allele>0.43947528327497376</allele> 393 * </alleles> 394 * </double-chromosome> 395 * }</pre> 396 */ 397 public static final class DoubleChromosome { 398 private DoubleChromosome() {} 399 400 /** 401 * Return the default allele reader for the {@code DoubleChromosome}. 402 * 403 * @return the default allele reader 404 */ 405 public static Reader<Double> alleleReader() { 406 return text().map(Double::parseDouble); 407 } 408 409 /** 410 * Return a {@link io.jenetics.DoubleChromosome} reader. 411 * 412 * @return a double chromosome reader 413 */ 414 public static Reader<io.jenetics.DoubleChromosome> reader() { 415 return BoundedChromosome.reader( 416 Writers.DoubleChromosome.ROOT_NAME, 417 DoubleGene::of, 418 DoubleGene[]::new, 419 io.jenetics.DoubleChromosome::of, 420 alleleReader() 421 ); 422 } 423 424 /** 425 * Read a new {@link io.jenetics.DoubleChromosome} from the given 426 * input stream. 427 * 428 * @param in the data source of the chromosome 429 * @return a new chromosome 430 * @throws XMLStreamException if reading the chromosome fails 431 * @throws NullPointerException if the given input stream is {@code null} 432 */ 433 public static io.jenetics.DoubleChromosome read(final InputStream in) 434 throws XMLStreamException 435 { 436 try (var reader = XML.reader(in)) { 437 reader.next(); 438 return reader().read(reader); 439 } 440 } 441 442 } 443 444 /** 445 * Reader methods for {@link io.jenetics.PermutationChromosome} objects. 446 * <p> 447 * <b>XML format</b> 448 * <pre> {@code 449 * <permutation-chromosome length="5"> 450 * <valid-alleles type="java.lang.Integer"> 451 * <allele>0</allele> 452 * <allele>1</allele> 453 * <allele>2</allele> 454 * <allele>3</allele> 455 * <allele>4</allele> 456 * </valid-alleles> 457 * <order>2 1 3 5 4</order> 458 * </permutation-chromosome> 459 * } </pre> 460 */ 461 public static final class PermutationChromosome { 462 private PermutationChromosome() {} 463 464 /** 465 * Return a reader for permutation chromosomes with the given allele 466 * reader. 467 * 468 * @param alleleReader the allele reader 469 * @param <A> the allele type 470 * @return a permutation chromosome reader 471 * @throws NullPointerException if the given allele reader is 472 * {@code null} 473 */ 474 public static <A> Reader<io.jenetics.PermutationChromosome<A>> 475 reader(final Reader<? extends A> alleleReader) { 476 requireNonNull(alleleReader); 477 478 return elem(v -> { 479 final int length = (int)v[0]; 480 @SuppressWarnings("unchecked") 481 final ISeq<A> validAlleles = ISeq.of((List<A>)v[1]); 482 483 final int[] order = Stream.of(((String) v[2]).split("\\s")) 484 .mapToInt(Integer::parseInt) 485 .toArray(); 486 487 final MSeq<EnumGene<A>> alleles = MSeq.ofLength(length); 488 for (int i = 0; i < length; ++i) { 489 final EnumGene<A> gene = EnumGene.of(order[i], validAlleles); 490 alleles.set(i, gene); 491 } 492 493 return new io.jenetics.PermutationChromosome<>(alleles.toISeq()); 494 }, 495 Writers.PermutationChromosome.ROOT_NAME, 496 attr(Writers.PermutationChromosome.LENGTH_NAME).map(Integer::parseInt), 497 elem(Writers.PermutationChromosome.VALID_ALLELES_NAME, 498 elems(elem(Writers.PermutationChromosome.ALLELE_NAME, alleleReader)) 499 ), 500 elem(Writers.PermutationChromosome.ORDER_NAME, text()) 501 ); 502 } 503 504 /** 505 * Reads a new {@link io.jenetics.PermutationChromosome} from the given 506 * input stream. 507 * 508 * @param <A> the allele type 509 * @param in the data source of the chromosome 510 * @param alleleReader the allele reader 511 * @return a new permutation chromosome 512 * @throws XMLStreamException if reading the chromosome fails 513 * @throws NullPointerException if one of the arguments is {@code null} 514 */ 515 public static <A> io.jenetics.PermutationChromosome<A> 516 read(final InputStream in, final Reader<? extends A> alleleReader) 517 throws XMLStreamException 518 { 519 requireNonNull(alleleReader); 520 requireNonNull(in); 521 522 try (var xml = XML.reader(in)) { 523 xml.next(); 524 return PermutationChromosome.<A>reader(alleleReader).read(xml); 525 } 526 } 527 528 } 529 530 /** 531 * Writer methods for {@link io.jenetics.Genotype} objects. 532 * <p> 533 * <b>XML format</b> 534 * <pre> {@code 535 * <genotype length="2" ngenes="5"> 536 * <double-chromosome length="3"> 537 * <min>0.0</min> 538 * <max>1.0</max> 539 * <alleles> 540 * <allele>0.27251556008507416</allele> 541 * <allele>0.003140816229067145</allele> 542 * <allele>0.43947528327497376</allele> 543 * </alleles> 544 * </double-chromosome> 545 * <double-chromosome length="2"> 546 * <min>0.0</min> 547 * <max>1.0</max> 548 * <alleles> 549 * <allele>0.4026521545744768</allele> 550 * <allele>0.36137605952663554</allele> 551 * <alleles> 552 * </double-chromosome> 553 * </genotype> 554 * } </pre> 555 */ 556 public static final class Genotype { 557 private Genotype() {} 558 559 /** 560 * Create a genotype reader with the given chromosome reader. 561 * 562 * @param chromosomeReader the underlying chromosome reader 563 * @param <A> the allele type 564 * @param <G> the gene type 565 * @param <C> the chromosome type 566 * @return a genotype reader with the given chromosome reader 567 * @throws NullPointerException if the given {@code chromosomeReader} is 568 * {@code null} 569 */ 570 public static < 571 A, 572 G extends Gene<A, G>, 573 C extends Chromosome<G> 574 > 575 Reader<io.jenetics.Genotype<G>> 576 reader(final Reader<? extends C> chromosomeReader) { 577 requireNonNull(chromosomeReader); 578 579 return elem(v -> { 580 @SuppressWarnings("unchecked") 581 final List<C> chromosomes = (List<C>)v[2]; 582 final io.jenetics.Genotype<G> genotype = 583 io.jenetics.Genotype.of(chromosomes); 584 585 final int length = (int)v[0]; 586 final int ngenes = (int)v[1]; 587 if (length != genotype.length()) { 588 throw new IllegalArgumentException(format( 589 "Expected %d chromosome, but read %d.", 590 length, genotype.length() 591 )); 592 } 593 if (ngenes != genotype.geneCount()) { 594 throw new IllegalArgumentException(format( 595 "Expected %d genes, but read %d.", 596 ngenes, genotype.geneCount() 597 )); 598 } 599 600 return genotype; 601 }, 602 Writers.Genotype.ROOT_NAME, 603 attr(Writers.Genotype.LENGTH_NAME).map(Integer::parseInt), 604 attr(Writers.Genotype.NGENES_NAME).map(Integer::parseInt), 605 elems(chromosomeReader) 606 ); 607 } 608 609 /** 610 * Reads a genotype by using the given chromosome reader. 611 * 612 * @param <A> the allele type 613 * @param <G> the gene type 614 * @param <C> the chromosome type 615 * @param in the input stream to read the genotype from 616 * @param chromosomeReader the used chromosome reader 617 * @return a genotype by using the given chromosome reader 618 * @throws XMLStreamException if reading the genotype fails 619 * @throws NullPointerException if one of the arguments is {@code null} 620 */ 621 public static < 622 A, 623 G extends Gene<A, G>, 624 C extends Chromosome<G> 625 > 626 io.jenetics.Genotype<G> 627 read(final InputStream in, final Reader<? extends C> chromosomeReader) 628 throws XMLStreamException 629 { 630 requireNonNull(chromosomeReader); 631 requireNonNull(in); 632 633 try (var xml = XML.reader(in)) { 634 xml.next(); 635 return reader(chromosomeReader).read(xml); 636 } 637 } 638 } 639 640 /** 641 * This class contains static reader methods for 642 * {@link io.jenetics.Genotype} objects. 643 * <p> 644 * <b>XML format</b> 645 * <pre> {@code 646 * <genotypes length="1"> 647 * <genotype length="2" ngenes="5"> 648 * <double-chromosome length="3"> 649 * <min>0.0</min> 650 * <max>1.0</max> 651 * <alleles> 652 * <allele>0.27251556008507416</allele> 653 * <allele>0.003140816229067145</allele> 654 * <allele>0.43947528327497376</allele> 655 * </alleles> 656 * </double-chromosome> 657 * <double-chromosome length="2"> 658 * <min>0.0</min> 659 * <max>1.0</max> 660 * <alleles> 661 * <allele>0.4026521545744768</allele> 662 * <allele>0.36137605952663554</allele> 663 * <alleles> 664 * </double-chromosome> 665 * </genotype> 666 * </genotypes> 667 * } </pre> 668 */ 669 public static final class Genotypes { 670 private Genotypes() {} 671 672 /** 673 * Return a genotype reader using the given chromosome reader. 674 * 675 * @param chromosomeReader the underlying chromosome reader 676 * @param <A> the allele type 677 * @param <G> the gene type 678 * @param <C> the chromosome type 679 * @return a genotype reader using the given chromosome reader 680 * @throws NullPointerException if the given {@code chromosomeReader} is 681 * {@code null} 682 */ 683 @SuppressWarnings("unchecked") 684 public static < 685 A, 686 G extends Gene<A, G>, 687 C extends Chromosome<G> 688 > 689 Reader<List<io.jenetics.Genotype<G>>> 690 reader(final Reader<C> chromosomeReader) { 691 return elem( 692 p -> (List<io.jenetics.Genotype<G>>)p[0], 693 Writers.Genotypes.ROOT_NAME, 694 elems(Genotype.reader(chromosomeReader)) 695 ); 696 } 697 698 /** 699 * Reads the genotypes by using the given chromosome reader. 700 * 701 * @param <A> the allele type 702 * @param <G> the gene type 703 * @param <C> the chromosome type 704 * @param in the input stream to read the genotype from 705 * @param chromosomeReader the used chromosome reader 706 * @return a genotype by using the given chromosome reader 707 * @throws XMLStreamException if reading the genotype fails 708 * @throws NullPointerException if one of the arguments is {@code null} 709 */ 710 public static < 711 A, 712 G extends Gene<A, G>, 713 C extends Chromosome<G> 714 > 715 List<io.jenetics.Genotype<G>> 716 read(final InputStream in, final Reader<? extends C> chromosomeReader) 717 throws XMLStreamException 718 { 719 requireNonNull(chromosomeReader); 720 requireNonNull(in); 721 722 try (var xml = XML.reader(in)) { 723 xml.next(); 724 return reader(chromosomeReader).read(xml); 725 } 726 } 727 728 } 729 730 /** 731 * Reads the genotypes by using the given chromosome reader. 732 * 733 * @see Genotypes#read(InputStream, Reader) 734 * 735 * @param <A> the allele type 736 * @param <G> the gene type 737 * @param <C> the chromosome type 738 * @param in the input stream to read the genotype from 739 * @param chromosomeReader the used chromosome reader 740 * @return a genotype by using the given chromosome reader 741 * @throws XMLStreamException if reading the genotype fails 742 * @throws NullPointerException if one of the arguments is {@code null} 743 */ 744 public static < 745 A, 746 G extends Gene<A, G>, 747 C extends Chromosome<G> 748 > 749 List<io.jenetics.Genotype<G>> 750 read(final InputStream in, final Reader<? extends C> chromosomeReader) 751 throws XMLStreamException 752 { 753 return Genotypes.read(in, chromosomeReader); 754 } 755 756}