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