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.util.Objects.requireNonNull;
023import static io.jenetics.xml.stream.Writer.attr;
024import static io.jenetics.xml.stream.Writer.elem;
025import static io.jenetics.xml.stream.Writer.elems;
026import static io.jenetics.xml.stream.Writer.text;
027
028import java.io.OutputStream;
029import java.util.Collection;
030import java.util.stream.Collectors;
031
032import javax.xml.stream.XMLStreamException;
033
034import io.jenetics.BoundedGene;
035import io.jenetics.Chromosome;
036import io.jenetics.DoubleGene;
037import io.jenetics.Gene;
038import io.jenetics.IntegerGene;
039import io.jenetics.LongGene;
040
041import io.jenetics.xml.stream.AutoCloseableXMLStreamWriter;
042import io.jenetics.xml.stream.Writer;
043import io.jenetics.xml.stream.XML;
044
045/**
046 * This class contains static fields and methods, for creating chromosome- and
047 * genotype writers for different gene types.
048 *
049 * <pre>{@code
050 * final Writer<Genotype<BitGene> bgw =
051 *     Writers.Genotype.writer(Writers.BitChromosome.writer()));
052 *
053 * final Writer<Genotype<IntegerGene>> igw =
054 *     Writers.Genotype.writer(Writers.IntegerChromosome.writer()));
055 *
056 * final Writer<Genotype<DoubleGene>> dgw =
057 *     Writers.Genotype.writer(Writers.DoubleChromosome.writer()));
058 * }</pre>
059 *
060 * This class also contains some helper methods, which makes it easier to write
061 * Jenetics domain objects to a given output stream.
062 * <pre>{@code
063 * final List<Genotype<BitGene>> genotypes = ...;
064 * try (OutputStream out = Files.newOutputStream(Paths.get("path"))) {
065 *     Writers.write(out, genotypes, Writers.BitChromosome.writer());
066 * }
067 * }</pre>
068 *
069 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
070 * @version 3.9
071 * @since 3.9
072 */
073public final class Writers {
074        private Writers() {}
075
076        /**
077         * This class contains static writer methods for
078         * {@link io.jenetics.BitChromosome} objects.
079         * <p>
080         * <b>Writer code</b>
081         * <pre>{@code
082         * final BitChromosome value = BitChromosome.of(20, 0.5);
083         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
084         *     Writers.BitChromosome.writer().write(value, xml);
085         * }
086         * }</pre>
087         *
088         * <b>XML output</b>
089         * <pre> {@code
090         * <bit-chromosome length="20" ones-probability="0.5">11100011101011001010</bit-chromosome>
091         * }</pre>
092         *
093         * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
094         * @version 3.9
095         * @since 3.9
096         */
097        public static final class BitChromosome {
098                private BitChromosome() {}
099
100                static final String ROOT_NAME = "bit-chromosome";
101                static final String LENGTH_NAME = "length";
102                static final String ONES_PROBABILITY_NAME = "ones-probability";
103
104                /**
105                 * Return a {@link Writer} for {@link io.jenetics.BitChromosome}
106                 * objects.
107                 *
108                 * @return a chromosome writer
109                 */
110                public static Writer<io.jenetics.BitChromosome> writer() {
111                        return elem(ROOT_NAME,
112                                attr(LENGTH_NAME).map(io.jenetics.BitChromosome::length),
113                                attr(ONES_PROBABILITY_NAME).map(ch -> ch.getOneProbability()),
114                                text().map(io.jenetics.BitChromosome::toCanonicalString)
115                        );
116                }
117
118                /**
119                 * Write the given {@link io.jenetics.BitChromosome} to the given
120                 * output stream.
121                 *
122                 * @param out the target output stream
123                 * @param data the bit-chromosome to write
124                 * @throws XMLStreamException if an error occurs while writing the
125                 *         chromosome
126                 * @throws NullPointerException if one of the given arguments is
127                 *         {@code null}
128                 */
129                public static void write(
130                        final OutputStream out,
131                        final io.jenetics.BitChromosome data
132                )
133                        throws XMLStreamException
134                {
135                        requireNonNull(data);
136                        requireNonNull(out);
137
138                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out)) {
139                                writer().write(xml, data);
140                        }
141                }
142        }
143
144
145        /**
146         * This class contains static writer methods for
147         * {@link io.jenetics.CharacterChromosome} objects.
148         * <p>
149         * <b>Writer code</b>
150         * <pre>{@code
151         * final CharacterChromosome value = CharacterChromosome.of("ASDF", CharSeq.of("A-Z"));
152         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
153         *     Writers.CharacterChromosome.writer().write(value, xml);
154         * }
155         * }</pre>
156         *
157         * <b>XML output</b>
158         * <pre> {@code
159         * <character-chromosome length="4">
160         *     <valid-alleles>ABCDEFGHIJKLMNOPQRSTUVWXYZ<valid-alleles>
161         *     <alleles>ASDF</alleles>
162         * </character-chromosome>
163         * }</pre>
164         */
165        public static final class CharacterChromosome {
166                private CharacterChromosome() {}
167
168                static final String ROOT_NAME = "character-chromosome";
169                static final String LENGTH_NAME = "length";
170                static final String VALID_ALLELES_NAME = "valid-alleles";
171                static final String ALLELES_NAME = "alleles";
172
173                /**
174                 * Return a {@link Writer} for {@link io.jenetics.CharacterChromosome}
175                 * objects.
176                 *
177                 * @return a chromosome writer
178                 */
179                public static Writer<io.jenetics.CharacterChromosome> writer() {
180                        return elem(ROOT_NAME,
181                                attr(LENGTH_NAME).map(io.jenetics.CharacterChromosome::length),
182                                elem(VALID_ALLELES_NAME,
183                                        text().map(ch -> ch.getGene().getValidCharacters())),
184                                elem(ALLELES_NAME,
185                                        text().map(io.jenetics.CharacterChromosome::toString))
186                        );
187                }
188
189                /**
190                 * Write the given {@link io.jenetics.CharacterChromosome} to the given
191                 * output stream.
192                 *
193                 * @param out the target output stream
194                 * @param data the chromosome to write
195                 * @param indent the XML level indentation
196                 * @throws XMLStreamException if an error occurs while writing the
197                 *         chromosome
198                 * @throws NullPointerException if the {@code chromosome} or output
199                 *         stream is {@code null}
200                 */
201                public static void write(
202                        final OutputStream out,
203                        final io.jenetics.CharacterChromosome data,
204                        final String indent
205                )
206                        throws XMLStreamException
207                {
208                        requireNonNull(data);
209                        requireNonNull(out);
210
211                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
212                                writer().write(xml, data);
213                        }
214                }
215
216                /**
217                 * Write the given {@link io.jenetics.CharacterChromosome} to the given
218                 * output stream.
219                 *
220                 * @param out the target output stream
221                 * @param data the chromosome to write
222                 * @throws XMLStreamException if an error occurs while writing the
223                 *         chromosome
224                 * @throws NullPointerException if the {@code chromosome} or output
225                 *         stream is {@code null}
226                 */
227                public static void write(
228                        final OutputStream out,
229                        final io.jenetics.CharacterChromosome data
230                )
231                        throws XMLStreamException
232                {
233                        write(out, data, null);
234                }
235
236        }
237
238        /**
239         * This class contains static writer methods for
240         * {@link io.jenetics.BoundedChromosome} objects.
241         *
242         * <p>
243         * <b>XML template</b>
244         * <pre> {@code
245         * <root-name length="3">
246         *     <min>aaa</min>
247         *     <max>zzz</max>
248         *     <alleles>
249         *         <allele>iii</allele>
250         *         <allele>fff</allele>
251         *         <allele>ggg</allele>
252         *     </alleles>
253         * </root-name>
254         * }</pre>
255         */
256        public static final class BoundedChromosome {
257                private BoundedChromosome() {}
258
259                static final String LENGTH_NAME = "length";
260                static final String MIN_NAME = "min";
261                static final String MAX_NAME = "max";
262                static final String ALLELE_NAME = "allele";
263                static final String ALLELES_NAME = "alleles";
264
265                /**
266                 * Create a bounded chromosome writer with the given configuration.
267                 *
268                 * @param rootName the name of the root element. E.g. {@code int-chromosome}
269                 * @param alleleWriter the XML writer used for the alleles
270                 * @param <A> the allele type
271                 * @param <G> the bounded gene type
272                 * @param <C> the bounded chromosome type
273                 * @return a bounded chromosome XML writer
274                 * @throws NullPointerException if one of the arguments is {@code null}
275                 */
276                public static <
277                        A extends Comparable<? super A>,
278                        G extends BoundedGene<A, G>,
279                        C extends io.jenetics.BoundedChromosome<A, G>
280                >
281                Writer<C> writer(
282                        final String rootName,
283                        final Writer<? super A> alleleWriter
284                ) {
285                        requireNonNull(rootName);
286                        requireNonNull(alleleWriter);
287
288                        return elem(rootName,
289                                attr(LENGTH_NAME).map(ch -> ch.length()),
290                                elem(MIN_NAME, alleleWriter.map(ch -> ch.getMin())),
291                                elem(MAX_NAME, alleleWriter.map(ch -> ch.getMax())),
292                                elem(ALLELES_NAME,
293                                        elems(ALLELE_NAME, alleleWriter)
294                                                .map(ch -> ch.toSeq().map(G::getAllele))
295                                )
296                        );
297                }
298        }
299
300        /**
301         * This class contains static writer methods for
302         * {@link io.jenetics.IntegerChromosome} objects.
303         * <p>
304         * <b>Writer code</b>
305         * <pre>{@code
306         * final IntegerChromosome value = IntegerChromosome
307         *     .of(Integer.MIN_VALUE, Integer.MAX_VALUE, 3);
308         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
309         *     Writers.IntegerChromosome.writer().write(value, xml);
310         * }
311         * }</pre>
312         *
313         * <b>XML output</b>
314         * <pre> {@code
315         * <int-chromosome length="3">
316         *     <min>-2147483648</min>
317         *     <max>2147483647</max>
318         *     <alleles>
319         *         <allele>-1878762439</allele>
320         *         <allele>-957346595</allele>
321         *         <allele>-88668137</allele>
322         *     </alleles>
323         * </int-chromosome>
324         * }</pre>
325         */
326        public static final class IntegerChromosome {
327                private IntegerChromosome() {}
328
329                static final String ROOT_NAME = "int-chromosome";
330
331                /**
332                 * Return the default integer allele writer for the
333                 * {@code IntegerChromosome}.
334                 *
335                 * @return the default integer allele writer
336                 */
337                public static Writer<Integer> alleleWriter() {
338                        return text();
339                }
340
341                /**
342                 * Return a {@link Writer} for {@link io.jenetics.IntegerChromosome}
343                 * objects.
344                 *
345                 * @param alleleWriter the allele writer used for writing the integer
346                 *        allele. Might be useful for using different integer
347                 *        <i>encodings</i>.
348                 * @return a chromosome writer
349                 * @throws NullPointerException if the given {@code alleleWriter} is
350                 *         {@code null}
351                 */
352                public static Writer<io.jenetics.IntegerChromosome>
353                writer(final Writer<? super Integer> alleleWriter) {
354                        requireNonNull(alleleWriter);
355
356                        return BoundedChromosome.<
357                                Integer,
358                                IntegerGene,
359                                io.jenetics.IntegerChromosome
360                        >writer(ROOT_NAME, alleleWriter);
361                }
362
363                /**
364                 * Return a {@link Writer} for {@link io.jenetics.IntegerChromosome}
365                 * objects.
366                 *
367                 * @return a chromosome writer
368                 */
369                public static Writer<io.jenetics.IntegerChromosome> writer() {
370                        return writer(alleleWriter());
371                }
372
373                /**
374                 * Write the given {@link io.jenetics.IntegerChromosome} to the given
375                 * output stream.
376                 *
377                 * @param out the target output stream
378                 * @param data the chromosome to write
379                 * @param indent the XML level indentation
380                 * @throws XMLStreamException if an error occurs while writing the
381                 *         chromosome
382                 * @throws NullPointerException if the {@code chromosome} or output
383                 *         stream is {@code null}
384                 */
385                public static void write(
386                        final OutputStream out,
387                        final io.jenetics.IntegerChromosome data,
388                        final String indent
389                )
390                        throws XMLStreamException
391                {
392                        requireNonNull(data);
393                        requireNonNull(out);
394
395                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
396                                writer().write(xml, data);
397                        }
398                }
399
400                /**
401                 * Write the given {@link io.jenetics.IntegerChromosome} to the given
402                 * output stream.
403                 *
404                 * @param out the target output stream
405                 * @param data the chromosome to write
406                 * @throws XMLStreamException if an error occurs while writing the
407                 *         chromosome
408                 * @throws NullPointerException if the {@code chromosome} or output
409                 *         stream is {@code null}
410                 */
411                public static void write(
412                        final OutputStream out,
413                        final io.jenetics.IntegerChromosome data
414                )
415                        throws XMLStreamException
416                {
417                        write(out, data, null);
418                }
419        }
420
421        /**
422         * This class contains static writer methods for
423         * {@link io.jenetics.LongChromosome} objects.
424         * <p>
425         * <b>Writer code</b>
426         * <pre>{@code
427         * final LongChromosome value = LongChromosome
428         *     .of(Long.MIN_VALUE, Long.MAX_VALUE, 3);
429         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
430         *     Writers.LongChromosome.writer().write(value, xml);
431         * }
432         * }</pre>
433         *
434         * <b>XML output</b>
435         * <pre> {@code
436         * <long-chromosome length="3">
437         *     <min>-9223372036854775808</min>
438         *     <max>9223372036854775807</max>
439         *     <alleles>
440         *         <allele>-1345217698116542402</allele>
441         *         <allele>-7144755673073475303</allele>
442         *         <allele>6053786736809578435</allele>
443         *     </alleles>
444         * </long-chromosome>
445         * }</pre>
446         */
447        public static final class LongChromosome {
448                private LongChromosome() {}
449
450                static final String ROOT_NAME = "long-chromosome";
451
452                /**
453                 * Return the default long allele writer for the
454                 * {@code IntegerChromosome}.
455                 *
456                 * @return the default long allele writer
457                 */
458                public static Writer<Long> alleleWriter() {
459                        return Writer.text();
460                }
461
462                /**
463                 * Return a {@link Writer} for {@link io.jenetics.LongChromosome}
464                 * objects.
465                 *
466                 * @param alleleWriter the allele writer used for writing the long
467                 *        allele. Might be useful for using different long
468                 *        <i>encodings</i>.
469                 * @return a chromosome writer
470                 * @throws NullPointerException if the given {@code alleleWriter} is
471                 *         {@code null}
472                 */
473                public static Writer<io.jenetics.LongChromosome>
474                writer(final Writer<? super Long> alleleWriter) {
475                        return BoundedChromosome.<
476                                Long,
477                                LongGene,
478                                io.jenetics.LongChromosome
479                        >writer(ROOT_NAME, alleleWriter);
480                }
481
482                /**
483                 * Return a {@link Writer} for {@link io.jenetics.LongChromosome}
484                 * objects.
485                 *
486                 * @return a chromosome writer
487                 */
488                public static Writer<io.jenetics.LongChromosome> writer() {
489                        return writer(alleleWriter());
490                }
491
492                /**
493                 * Write the given {@link io.jenetics.LongChromosome} to the given
494                 * output stream.
495                 *
496                 * @param out the target output stream
497                 * @param data the chromosome to write
498                 * @param indent the XML level indentation
499                 * @throws XMLStreamException if an error occurs while writing the
500                 *         chromosome
501                 * @throws NullPointerException if the {@code chromosome} or output
502                 *         stream is {@code null}
503                 */
504                public static void write(
505                        final OutputStream out,
506                        final io.jenetics.LongChromosome data,
507                        final String indent
508                )
509                        throws XMLStreamException
510                {
511                        requireNonNull(data);
512                        requireNonNull(out);
513
514                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
515                                writer().write(xml, data);
516                        }
517                }
518
519                /**
520                 * Write the given {@link io.jenetics.LongChromosome} to the given
521                 * output stream.
522                 *
523                 * @param out the target output stream
524                 * @param data the chromosome to write
525                 * @throws XMLStreamException if an error occurs while writing the
526                 *         chromosome
527                 * @throws NullPointerException if the {@code chromosome} or output
528                 *         stream is {@code null}
529                 */
530                public static void write(
531                        final OutputStream out,
532                        final io.jenetics.LongChromosome data
533                )
534                        throws XMLStreamException
535                {
536                        write(out, data, null);
537                }
538        }
539
540        /**
541         * This class contains static writer methods for
542         * {@link io.jenetics.DoubleChromosome} objects.
543         * <p>
544         * <b>Writer code</b>
545         * <pre>{@code
546         * final DoubleChromosome value = DoubleChromosome.of(0.0, 1.0, 3);
547         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
548         *     Writers.DoubleChromosome.writer().write(value, xml);
549         * }
550         * }</pre>
551         *
552         * <b>XML output</b>
553         * <pre> {@code
554         * <double-chromosome length="3">
555         *     <min>0.0</min>
556         *     <max>1.0</max>
557         *     <alleles>
558         *         <allele>0.27251556008507416</allele>
559         *         <allele>0.003140816229067145</allele>
560         *         <allele>0.43947528327497376</allele>
561         *     </alleles>
562         * </double-chromosome>
563         * }</pre>
564         */
565        public static final class DoubleChromosome
566                //extends WriterProvider<io.jenetics.DoubleChromosome>
567        {
568                private DoubleChromosome() {}
569
570                static final String ROOT_NAME = "double-chromosome";
571
572                /**
573                 * Return the default double allele writer for the
574                 * {@code DoubleChromosome}.
575                 *
576                 * @return the default double allele writer
577                 */
578                public static Writer<Double> alleleWriter() {
579                        return text().map(Object::toString);
580                }
581
582                /**
583                 * Return a {@link Writer} for {@link io.jenetics.DoubleChromosome}
584                 * objects.
585                 *
586                 * @param alleleWriter the allele writer used for writing the long
587                 *        allele. Might be useful for using different long
588                 *        <i>encodings</i>.
589                 * @return a chromosome writer
590                 * @throws NullPointerException if the given {@code alleleWriter} is
591                 *         {@code null}
592                 */
593                public static Writer<io.jenetics.DoubleChromosome>
594                writer(final Writer<? super Double> alleleWriter) {
595                        return BoundedChromosome.<
596                                Double,
597                                DoubleGene,
598                                io.jenetics.DoubleChromosome
599                        >writer(ROOT_NAME, alleleWriter);
600                }
601
602                /**
603                 * Return a {@link Writer} for {@link io.jenetics.DoubleChromosome}
604                 * objects.
605                 *
606                 * @return a chromosome writer
607                 */
608                public static Writer<io.jenetics.DoubleChromosome> writer() {
609                        return writer(alleleWriter());
610                }
611
612                public Class<io.jenetics.DoubleChromosome> type() {
613                        return io.jenetics.DoubleChromosome.class;
614                }
615
616                /**
617                 * Write the given {@link io.jenetics.DoubleChromosome} to the given
618                 * output stream.
619                 *
620                 * @param out the target output stream
621                 * @param data the chromosome to write
622                 * @param indent the XML level indentation
623                 * @throws XMLStreamException if an error occurs while writing the
624                 *         chromosome
625                 * @throws NullPointerException if the {@code chromosome} or output
626                 *         stream is {@code null}
627                 */
628                public static void write(
629                        final OutputStream out,
630                        final io.jenetics.DoubleChromosome data,
631                        final String indent
632                )
633                        throws XMLStreamException
634                {
635                        requireNonNull(data);
636                        requireNonNull(out);
637
638                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
639                                writer().write(xml, data);
640                        }
641                }
642
643                /**
644                 * Write the given {@link io.jenetics.DoubleChromosome} to the given
645                 * output stream.
646                 *
647                 * @param out the target output stream
648                 * @param data the chromosome to write
649                 * @throws XMLStreamException if an error occurs while writing the
650                 *         chromosome
651                 * @throws NullPointerException if the {@code chromosome} or output
652                 *         stream is {@code null}
653                 */
654                public static void write(
655                        final OutputStream out,
656                        final io.jenetics.DoubleChromosome data
657                )
658                        throws XMLStreamException
659                {
660                        write(out, data, null);
661                }
662        }
663
664        /**
665         * This class contains static writer methods for
666         * {@link io.jenetics.PermutationChromosome} objects.
667         * <p>
668         * <b>Writer code</b>
669         * <pre>{@code
670         * final PermutationChromosome<Integer> value =
671         *     PermutationChromosome.ofInteger(5)
672         *
673         * final Writer<PermutationChromosome<Integer> writer =
674         *     Writers.PermutationChromosome.writer();
675         *
676         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
677         *     Writers.PermutationChromosome.writer().write(value, xml);
678         * }
679         * }</pre>
680         *
681         * <b>XML output</b>
682         * <pre> {@code
683         * <permutation-chromosome length="5">
684         *     <valid-alleles type="java.lang.Integer">
685         *         <allele>0</allele>
686         *         <allele>1</allele>
687         *         <allele>2</allele>
688         *         <allele>3</allele>
689         *         <allele>4</allele>
690         *     </valid-alleles>
691         *     <order>2 1 3 5 4</order>
692         * </permutation-chromosome>
693         * }</pre>
694         */
695        public static final class PermutationChromosome {
696                private PermutationChromosome() {}
697
698                static final String ROOT_NAME = "permutation-chromosome";
699                static final String LENGTH_NAME = "length";
700                static final String VALID_ALLELES_NAME = "valid-alleles";
701                static final String ALLELE_NAME = "allele";
702                static final String ORDER_NAME = "order";
703
704                /**
705                 * Create a writer for permutation-chromosomes. How to write the valid
706                 * alleles is defined by the given {@link Writer}.
707                 *
708                 * @param alleleWriter the allele writer
709                 * @param <A> the allele type
710                 * @return a new permutation chromosome writer
711                 * @throws NullPointerException if the given allele {@code writer} is
712                 *         {@code null}
713                 */
714                public static <A> Writer<io.jenetics.PermutationChromosome<A>>
715                writer(final Writer<? super A> alleleWriter) {
716                        return Writer.<io.jenetics.PermutationChromosome<A>>elem(
717                                ROOT_NAME,
718                                attr(LENGTH_NAME).map(io.jenetics.PermutationChromosome::length),
719                                elem(VALID_ALLELES_NAME,
720                                        attr("type").map(PermutationChromosome::toAlleleTypeName),
721                                        Writer.<A>elems(ALLELE_NAME, alleleWriter)
722                                                .map(ch -> ch.getValidAlleles())
723                                ),
724                                elem(ORDER_NAME, text())
725                                        .map(ch -> ch.stream()
726                                                .map(g -> Integer.toString(g.getAlleleIndex()))
727                                                .collect(Collectors.joining(" ")))
728                        );
729                }
730
731                private static String toAlleleTypeName(
732                        final io.jenetics.PermutationChromosome<?> ch
733                ) {
734                        return ch.getGene().getAllele().getClass().getCanonicalName();
735                }
736
737                /**
738                 * Create a writer for permutation-chromosomes. The valid alleles are
739                 * serialized by calling the {@link Object#toString()} method. Calling
740                 * this method is equivalent with:
741                 * <pre>{@code
742                 * final Writer<PermutationChromosome<Double> writer =
743                 *     PermutationChromosome.write(text().map(Objects::toString));
744                 * }</pre>
745                 *
746                 * Example output:
747                 * <pre> {@code
748                 * <permutation-chromosome length="15">
749                 *     <valid-alleles type="java.lang.Double">
750                 *         <allele>0.27251556008507416</allele>
751                 *         <allele>0.003140816229067145</allele>
752                 *         <allele>0.43947528327497376</allele>
753                 *         <allele>0.10654807463069327</allele>
754                 *         <allele>0.19696530915810317</allele>
755                 *         <allele>0.7450003838065538</allele>
756                 *         <allele>0.5594416969271359</allele>
757                 *         <allele>0.02823782430152355</allele>
758                 *         <allele>0.5741102315010789</allele>
759                 *         <allele>0.4533651041367144</allele>
760                 *         <allele>0.811148141800367</allele>
761                 *         <allele>0.5710456351848858</allele>
762                 *         <allele>0.30166768355230955</allele>
763                 *         <allele>0.5455492865240272</allele>
764                 *         <allele>0.21068427527733102</allele>
765                 *     </valid-alleles>
766                 *     <order>13 12 4 6 8 14 7 2 11 5 3 0 9 10 1</order>
767                 * </permutation-chromosome>
768                 * }</pre>
769                 *
770                 * @param <A> the allele type
771                 * @return a new permutation chromosome writer
772                 */
773                public static <A> Writer<io.jenetics.PermutationChromosome<A>> writer() {
774                        return writer(text());
775                }
776
777                /**
778                 * Write the given {@link io.jenetics.PermutationChromosome} to the
779                 * given output stream.
780                 *
781                 * @param <A> the allele type
782                 * @param out the target output stream
783                 * @param data the chromosome to write
784                 * @param indent the XML level indentation
785                 * @throws XMLStreamException if an error occurs while writing the
786                 *         chromosome
787                 * @throws NullPointerException if the {@code chromosome} or output
788                 *         stream is {@code null}
789                 */
790                public static <A> void write(
791                        final OutputStream out,
792                        final io.jenetics.PermutationChromosome<A> data,
793                        final String indent
794                )
795                        throws XMLStreamException
796                {
797                        requireNonNull(data);
798                        requireNonNull(out);
799
800                        try (AutoCloseableXMLStreamWriter writer = XML.writer(out, indent)) {
801                                PermutationChromosome.<A>writer().write(writer, data);
802                        }
803                }
804
805                /**
806                 * Write the given {@link io.jenetics.PermutationChromosome} to the
807                 * given output stream.
808                 *
809                 * @param <A> the allele type
810                 * @param out the target output stream
811                 * @param data the chromosome to write
812                 * @param indent the XML level indentation
813                 * @param alleleWriter the allele writer of the permutation chromosome
814                 * @throws XMLStreamException if an error occurs while writing the
815                 *         chromosome
816                 * @throws NullPointerException if the {@code chromosome} or output
817                 *         stream is {@code null}
818                 */
819                public static <A> void write(
820                        final OutputStream out,
821                        final io.jenetics.PermutationChromosome<A> data,
822                        final String indent,
823                        final Writer<? super A> alleleWriter
824                )
825                        throws XMLStreamException
826                {
827                        requireNonNull(data);
828                        requireNonNull(alleleWriter);
829                        requireNonNull(out);
830
831                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
832                                PermutationChromosome.<A>writer(alleleWriter)
833                                        .write(xml, data);
834                        }
835                }
836
837                /**
838                 * Write the given {@link io.jenetics.PermutationChromosome} to the
839                 * given output stream.
840                 *
841                 * @param <A> the allele type
842                 * @param out the target output stream
843                 * @param data the chromosome to write
844                 * @throws XMLStreamException if an error occurs while writing the
845                 *         chromosome
846                 * @throws NullPointerException if the {@code chromosome} or output
847                 *         stream is {@code null}
848                 */
849                public static <A> void write(
850                        final OutputStream out,
851                        final io.jenetics.PermutationChromosome<A> data
852                )
853                        throws XMLStreamException
854                {
855                        write(out, data, null, text());
856                }
857
858                /**
859                 * Write the given {@link io.jenetics.PermutationChromosome} to the
860                 * given output stream.
861                 *
862                 * @param <A> the allele type
863                 * @param out the target output stream
864                 * @param data the chromosome to write
865                 * @param alleleWriter the allele writer used to write the chromosome
866                 *         alleles
867                 * @throws XMLStreamException if an error occurs while writing the
868                 *         chromosome
869                 * @throws NullPointerException if the {@code chromosome} or output
870                 *         stream is {@code null}
871                 */
872                public static <A> void write(
873                        final OutputStream out,
874                        final io.jenetics.PermutationChromosome<A> data,
875                        final Writer<? super A> alleleWriter
876                )
877                        throws XMLStreamException
878                {
879                        write(out, data, null, alleleWriter);
880                }
881
882        }
883
884        /**
885         * This class contains static writer methods for
886         * {@link io.jenetics.Genotype} objects.
887         * <p>
888         * <b>Writer code</b>
889         * <pre>{@code
890         * final Genotype<DoubleGene> gt = Genotype.of(
891         *     DoubleChromosome.of(0.0, 1.0, 3),
892         *     DoubleChromosome.of(0.0, 1.0, 2)
893         * );
894         * final Writer<Genotype<DoubleGene>> writer =
895         *     Writers.Genotype.writer(Writers.DoubleChromosome.writer());
896         *
897         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
898         *     writer.write(value, xml);
899         * }
900         * }</pre>
901         *
902         * <b>XML output</b>
903         * <pre> {@code
904         * <genotype length="2" ngenes="5">
905         *     <double-chromosome length="3">
906         *         <min>0.0</min>
907         *         <max>1.0</max>
908         *         <alleles>
909         *             <allele>0.27251556008507416</allele>
910         *             <allele>0.003140816229067145</allele>
911         *             <allele>0.43947528327497376</allele>
912         *         </alleles>
913         *     </double-chromosome>
914         *     <double-chromosome length="2">
915         *         <min>0.0</min>
916         *         <max>1.0</max>
917         *         <alleles>
918         *             <allele>0.4026521545744768</allele>
919         *             <allele>0.36137605952663554</allele>
920         *         <alleles>
921         *     </double-chromosome>
922         * </genotype>
923         * }</pre>
924         */
925        public static final class Genotype {
926                private Genotype() {}
927
928                static final String ROOT_NAME = "genotype";
929                static final String LENGTH_NAME = "length";
930                static final String NGENES_NAME = "ngenes";
931
932                /**
933                 * Create a writer for genotypes of arbitrary chromosomes. How to write the
934                 * genotypes chromosomes is defined by the given {@link Writer}.
935                 *
936                 * @param writer the chromosome writer
937                 * @param <A> the allele type
938                 * @param <G> the gene type
939                 * @param <C> the chromosome type
940                 * @return a new genotype writer
941                 * @throws NullPointerException if the given chromosome {@code writer} is
942                 *         {@code null}
943                 */
944                public static <
945                        A,
946                        G extends Gene<A, G>,
947                        C extends Chromosome<G>
948                >
949                Writer<io.jenetics.Genotype<G>> writer(final Writer<? super C> writer) {
950                        return elem(
951                                ROOT_NAME,
952                                attr(LENGTH_NAME).map(io.jenetics.Genotype<G>::length),
953                                attr(NGENES_NAME).map(io.jenetics.Genotype<G>::geneCount),
954                                elems(writer).map(gt -> cast(gt.toSeq()))
955                        );
956                }
957
958                @SuppressWarnings("unchecked")
959                private static <A, B> B cast(final A value) {
960                        return (B)value;
961                }
962
963                /**
964                 * Write the given {@link io.jenetics.Genotype} to the given output
965                 * stream.
966                 *
967                 * @param <A> the allele type
968                 * @param <G> the gene type
969                 * @param <C> the chromosome type
970                 * @param out the target output stream
971                 * @param data the genotype to write
972                 * @param indent the XML level indentation
973                 * @param chromosomeWriter the chromosome writer used to write the
974                 *        genotypes
975                 * @throws XMLStreamException if an error occurs while writing the
976                 *         chromosome
977                 * @throws NullPointerException if the one of the arguments is
978                 *         {@code null}
979                 */
980                public static <
981                        A,
982                        G extends Gene<A, G>,
983                        C extends Chromosome<G>
984                >
985                void write(
986                        final OutputStream out,
987                        final io.jenetics.Genotype<G> data,
988                        final String indent,
989                        final Writer<? super C> chromosomeWriter
990                )
991                        throws XMLStreamException
992                {
993                        requireNonNull(data);
994                        requireNonNull(chromosomeWriter);
995                        requireNonNull(out);
996
997                        try (AutoCloseableXMLStreamWriter writer = XML.writer(out, indent)) {
998                                Genotype.<A, G, C>writer(chromosomeWriter).write(writer, data);
999                        }
1000                }
1001
1002                /**
1003                 * Write the given {@link io.jenetics.Genotype} to the given output
1004                 * stream.
1005                 *
1006                 * @param <A> the allele type
1007                 * @param <G> the gene type
1008                 * @param <C> the chromosome type
1009                 * @param out the target output stream
1010                 * @param data the genotype to write
1011                 * @param chromosomeWriter the chromosome writer used to write the
1012                 *        genotypes
1013                 * @throws XMLStreamException if an error occurs while writing the
1014                 *         chromosome
1015                 * @throws NullPointerException if the one of the arguments is
1016                 *         {@code null}
1017                 */
1018                public static <
1019                        A,
1020                        G extends Gene<A, G>,
1021                        C extends Chromosome<G>
1022                >
1023                void write(
1024                        final OutputStream out,
1025                        final io.jenetics.Genotype<G> data,
1026                        final Writer<? super C> chromosomeWriter
1027                )
1028                        throws XMLStreamException
1029                {
1030                        requireNonNull(data);
1031                        requireNonNull(chromosomeWriter);
1032                        requireNonNull(out);
1033
1034                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out)) {
1035                                Genotype.<A, G, C>writer(chromosomeWriter).write(xml, data);
1036                        }
1037                }
1038
1039        }
1040
1041        /**
1042         * This class contains static writer methods for
1043         * {@link io.jenetics.Genotype} objects.
1044         * <p>
1045         * <b>Writer code</b>
1046         * <pre>{@code
1047         * final Genotype<DoubleGene> gt = Genotype.of(
1048         *     DoubleChromosome.of(0.0, 1.0, 3),
1049         *     DoubleChromosome.of(0.0, 1.0, 2)
1050         * );
1051         *
1052         * final Writer<Collection<Genotype<DoubleGene>>> writer =
1053         *     Writers.Genotypes.writer(Writers.DoubleChromosome.writer());
1054         *
1055         * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
1056         *     writer.write(asList(value), xml);
1057         * }
1058         * }</pre>
1059         *
1060         * <pre> {@code
1061         * <genotypes length="1">
1062         *     <genotype length="2" ngenes="5">
1063         *         <double-chromosome length="3">
1064         *             <min>0.0</min>
1065         *             <max>1.0</max>
1066         *             <alleles>
1067         *                 <allele>0.27251556008507416</allele>
1068         *                 <allele>0.003140816229067145</allele>
1069         *                 <allele>0.43947528327497376</allele>
1070         *             </alleles>
1071         *         </double-chromosome>
1072         *         <double-chromosome length="2">
1073         *             <min>0.0</min>
1074         *             <max>1.0</max>
1075         *             <alleles>
1076         *                 <allele>0.4026521545744768</allele>
1077         *                 <allele>0.36137605952663554</allele>
1078         *             <alleles>
1079         *         </double-chromosome>
1080         *     </genotype>
1081         * </genotypes>
1082         * }</pre>
1083         */
1084        public static final class Genotypes {
1085                private Genotypes() {}
1086
1087                static final String ROOT_NAME = "genotypes";
1088                static final String LENGTH_NAME = "length";
1089
1090                /**
1091                 * Create a writer for genotypes of arbitrary chromosomes. How to write the
1092                 * genotypes chromosomes is defined by the given {@link Writer}. The
1093                 * following writer allows to write double-gene chromosomes:
1094                 * <pre>{@code
1095                 * final Writer<Collection<Genotype<DoubleGene>>> writer =
1096                 *     Writers.Genotypes.writer(Writers.DoubleChromosome.writer());
1097                 * }</pre>
1098                 *
1099                 * @param writer the chromosome writer
1100                 * @param <A> the allele type
1101                 * @param <G> the gene type
1102                 * @param <C> the chromosome type
1103                 * @return a new genotype writer
1104                 * @throws NullPointerException if the given chromosome {@code writer} is
1105                 *         {@code null}
1106                 */
1107                public static <
1108                        A,
1109                        G extends Gene<A, G>,
1110                        C extends Chromosome<G>
1111                >
1112                Writer<Collection<io.jenetics.Genotype<G>>>
1113                writer(final Writer<? super C> writer) {
1114                        return elem(
1115                                ROOT_NAME,
1116                                attr(LENGTH_NAME).map(Collection::size),
1117                                elems(Genotype.writer(writer))
1118                        );
1119                }
1120
1121                /**
1122                 * Write the given {@link io.jenetics.Genotype} to the given output
1123                 * stream.
1124                 *
1125                 * @param <A> the allele type
1126                 * @param <G> the gene type
1127                 * @param <C> the chromosome type
1128                 * @param out the target output stream
1129                 * @param data the genotypes to write
1130                 * @param indent the XML level indentation
1131                 * @param chromosomeWriter the chromosome writer used to write the
1132                 *        genotypes
1133                 * @throws XMLStreamException if an error occurs while writing the
1134                 *         chromosome
1135                 * @throws NullPointerException if the one of the arguments is
1136                 *         {@code null}
1137                 */
1138                public static <
1139                        A,
1140                        G extends Gene<A, G>,
1141                        C extends Chromosome<G>
1142                >
1143                void write(
1144                        final OutputStream out,
1145                        final Collection<io.jenetics.Genotype<G>> data,
1146                        final String indent,
1147                        final Writer<? super C> chromosomeWriter
1148                )
1149                        throws XMLStreamException
1150                {
1151                        requireNonNull(data);
1152                        requireNonNull(chromosomeWriter);
1153                        requireNonNull(out);
1154
1155                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
1156                                Genotypes.<A, G, C>writer(chromosomeWriter).write(xml, data);
1157                        }
1158                }
1159
1160                /**
1161                 * Write the given {@link io.jenetics.Genotype} to the given output
1162                 * stream.
1163                 *
1164                 * @param <A> the allele type
1165                 * @param <G> the gene type
1166                 * @param <C> the chromosome type
1167                 * @param out the target output stream
1168                 * @param data the genotypes to write
1169                 * @param chromosomeWriter the chromosome writer used to write the
1170                 *        genotypes
1171                 * @throws XMLStreamException if an error occurs while writing the
1172                 *         chromosome
1173                 * @throws NullPointerException if the one of the arguments is
1174                 *         {@code null}
1175                 */
1176                public static <
1177                        A,
1178                        G extends Gene<A, G>,
1179                        C extends Chromosome<G>
1180                >
1181                void write(
1182                        final OutputStream out,
1183                        final Collection<io.jenetics.Genotype<G>> data,
1184                        final Writer<? super C> chromosomeWriter
1185                )
1186                        throws XMLStreamException
1187                {
1188                        requireNonNull(data);
1189                        requireNonNull(chromosomeWriter);
1190                        requireNonNull(out);
1191
1192                        try (AutoCloseableXMLStreamWriter xml = XML.writer(out)) {
1193                                Genotypes.<A, G, C>writer(chromosomeWriter).write(xml, data);
1194                        }
1195                }
1196
1197        }
1198
1199
1200        /**
1201         * Write the given {@link io.jenetics.Genotype} to the given output
1202         * stream.
1203         *
1204         * @see Genotypes#write(OutputStream, Collection, Writer)
1205         *
1206         * @param <A> the allele type
1207         * @param <G> the gene type
1208         * @param <C> the chromosome type
1209         * @param out the target output stream
1210         * @param data the genotypes to write
1211         * @param chromosomeWriter the chromosome writer used to write the
1212         *        genotypes
1213         * @throws XMLStreamException if an error occurs while writing the
1214         *         chromosome
1215         * @throws NullPointerException if the one of the arguments is
1216         *         {@code null}
1217         */
1218        public static <
1219                A,
1220                G extends Gene<A, G>,
1221                C extends Chromosome<G>
1222        >
1223        void write(
1224                final OutputStream out,
1225                final Collection<io.jenetics.Genotype<G>> data,
1226                final Writer<? super C> chromosomeWriter
1227        )
1228                throws XMLStreamException
1229        {
1230                Genotypes.write(out, data, chromosomeWriter);
1231        }
1232
1233}