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