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}