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