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