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}