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