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