Writers.java
0001 /*
0002  * Java Genetic Algorithm Library (jenetics-3.9.0).
0003  * Copyright (c) 2007-2017 Franz Wilhelmstötter
0004  *
0005  * Licensed under the Apache License, Version 2.0 (the "License");
0006  * you may not use this file except in compliance with the License.
0007  * You may obtain a copy of the License at
0008  *
0009  *      http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  *
0017  * Author:
0018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
0019  */
0020 package org.jenetics.xml;
0021 
0022 import static java.util.Objects.requireNonNull;
0023 import static org.jenetics.xml.stream.Writer.attr;
0024 import static org.jenetics.xml.stream.Writer.elem;
0025 import static org.jenetics.xml.stream.Writer.elems;
0026 import static org.jenetics.xml.stream.Writer.text;
0027 
0028 import java.io.OutputStream;
0029 import java.util.Collection;
0030 import java.util.stream.Collectors;
0031 
0032 import javax.xml.stream.XMLStreamException;
0033 
0034 import org.jenetics.BoundedGene;
0035 import org.jenetics.Chromosome;
0036 import org.jenetics.Gene;
0037 import org.jenetics.xml.stream.AutoCloseableXMLStreamWriter;
0038 import org.jenetics.xml.stream.Writer;
0039 import org.jenetics.xml.stream.XML;
0040 
0041 /**
0042  * This class contains static fields and methods, for creating chromosome- and
0043  * genotype writers for different gene types.
0044  *
0045  <pre>{@code
0046  * final Writer<Genotype<BitGene> bgw =
0047  *     Writers.Genotype.writer(Writers.BitChromosome.writer()));
0048  *
0049  * final Writer<Genotype<IntegerGene>> igw =
0050  *     Writers.Genotype.writer(Writers.IntegerChromosome.writer()));
0051  *
0052  * final Writer<Genotype<DoubleGene>> dgw =
0053  *     Writers.Genotype.writer(Writers.DoubleChromosome.writer()));
0054  * }</pre>
0055  *
0056  * This class also contains some helper methods, which makes it easier to write
0057  * Jenetics domain objects to a given output stream.
0058  <pre>{@code
0059  * final List<Genotype<BitGene>> genotypes = ...;
0060  * try (OutputStream out = Files.newOutputStream(Paths.get("path"))) {
0061  *     Writers.write(out, genotypes, Writers.BitChromosome.writer());
0062  * }
0063  * }</pre>
0064  *
0065  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
0066  @version 3.9
0067  @since 3.9
0068  */
0069 public final class Writers {
0070     private Writers() {}
0071 
0072     /**
0073      * This class contains static writer methods for
0074      {@link org.jenetics.BitChromosome} objects.
0075      <p>
0076      <b>Writer code</b>
0077      <pre>{@code
0078      * final BitChromosome value = BitChromosome.of(20, 0.5);
0079      * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
0080      *     Writers.BitChromosome.writer().write(value, xml);
0081      * }
0082      * }</pre>
0083      *
0084      <b>XML output</b>
0085      <pre> {@code
0086      <bit-chromosome length="20" ones-probability="0.5">11100011101011001010</bit-chromosome>
0087      * }</pre>
0088      *
0089      @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
0090      @version 3.9
0091      @since 3.9
0092      */
0093     public static final class BitChromosome {
0094         private BitChromosome() {}
0095 
0096         static final String ROOT_NAME = "bit-chromosome";
0097         static final String LENGTH_NAME = "length";
0098         static final String ONES_PROBABILITY_NAME = "ones-probability";
0099 
0100         /**
0101          * Return a {@link Writer} for {@link org.jenetics.BitChromosome}
0102          * objects.
0103          *
0104          @return a chromosome writer
0105          */
0106         public static Writer<org.jenetics.BitChromosome> writer() {
0107             return elem(ROOT_NAME,
0108                 attr(LENGTH_NAME).map(org.jenetics.BitChromosome::length),
0109                 attr(ONES_PROBABILITY_NAME).map(ch -> ch.getOneProbability()),
0110                 text().map(org.jenetics.BitChromosome::toCanonicalString)
0111             );
0112         }
0113 
0114         /**
0115          * Write the given {@link org.jenetics.BitChromosome} to the given
0116          * output stream.
0117          *
0118          @param out the target output stream
0119          @param data the bit-chromosome to write
0120          @throws XMLStreamException if an error occurs while writing the
0121          *         chromosome
0122          @throws NullPointerException if one of the given arguments is
0123          *         {@code null}
0124          */
0125         public static void write(
0126             final OutputStream out,
0127             final org.jenetics.BitChromosome data
0128         )
0129             throws XMLStreamException
0130         {
0131             requireNonNull(data);
0132             requireNonNull(out);
0133 
0134             try (AutoCloseableXMLStreamWriter xml = XML.writer(out)) {
0135                 writer().write(xml, data);
0136             }
0137         }
0138     }
0139 
0140 
0141     /**
0142      * This class contains static writer methods for
0143      {@link org.jenetics.CharacterChromosome} objects.
0144      <p>
0145      <b>Writer code</b>
0146      <pre>{@code
0147      * final CharacterChromosome value = CharacterChromosome.of("ASDF", CharSeq.of("A-Z"));
0148      * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
0149      *     Writers.CharacterChromosome.writer().write(value, xml);
0150      * }
0151      * }</pre>
0152      *
0153      <b>XML output</b>
0154      <pre> {@code
0155      <character-chromosome length="4">
0156      *     <valid-alleles>ABCDEFGHIJKLMNOPQRSTUVWXYZ<valid-alleles>
0157      *     <alleles>ASDF</alleles>
0158      </character-chromosome>
0159      * }</pre>
0160      */
0161     public static final class CharacterChromosome {
0162         private CharacterChromosome() {}
0163 
0164         static final String ROOT_NAME = "character-chromosome";
0165         static final String LENGTH_NAME = "length";
0166         static final String VALID_ALLELES_NAME = "valid-alleles";
0167         static final String ALLELES_NAME = "alleles";
0168 
0169         /**
0170          * Return a {@link Writer} for {@link org.jenetics.CharacterChromosome}
0171          * objects.
0172          *
0173          @return a chromosome writer
0174          */
0175         public static Writer<org.jenetics.CharacterChromosome> writer() {
0176             return elem(ROOT_NAME,
0177                 attr(LENGTH_NAME).map(org.jenetics.CharacterChromosome::length),
0178                 elem(VALID_ALLELES_NAME,
0179                     text().map(ch -> ch.getGene().getValidCharacters())),
0180                 elem(ALLELES_NAME,
0181                     text().map(org.jenetics.CharacterChromosome::toString))
0182             );
0183         }
0184 
0185         /**
0186          * Write the given {@link org.jenetics.CharacterChromosome} to the given
0187          * output stream.
0188          *
0189          @param out the target output stream
0190          @param data the chromosome to write
0191          @param indent the XML level indentation
0192          @throws XMLStreamException if an error occurs while writing the
0193          *         chromosome
0194          @throws NullPointerException if the {@code chromosome} or output
0195          *         stream is {@code null}
0196          */
0197         public static void write(
0198             final OutputStream out,
0199             final org.jenetics.CharacterChromosome data,
0200             final String indent
0201         )
0202             throws XMLStreamException
0203         {
0204             requireNonNull(data);
0205             requireNonNull(out);
0206 
0207             try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
0208                 writer().write(xml, data);
0209             }
0210         }
0211 
0212         /**
0213          * Write the given {@link org.jenetics.CharacterChromosome} to the given
0214          * output stream.
0215          *
0216          @param out the target output stream
0217          @param data the chromosome to write
0218          @throws XMLStreamException if an error occurs while writing the
0219          *         chromosome
0220          @throws NullPointerException if the {@code chromosome} or output
0221          *         stream is {@code null}
0222          */
0223         public static void write(
0224             final OutputStream out,
0225             final org.jenetics.CharacterChromosome data
0226         )
0227             throws XMLStreamException
0228         {
0229             write(out, data, null);
0230         }
0231 
0232     }
0233 
0234     /**
0235      * This class contains static writer methods for
0236      {@link org.jenetics.BoundedChromosome} objects.
0237      *
0238      <p>
0239      <b>XML template</b>
0240      <pre> {@code
0241      <root-name length="3">
0242      *     <min>aaa</min>
0243      *     <max>zzz</max>
0244      *     <alleles>
0245      *         <allele>iii</allele>
0246      *         <allele>fff</allele>
0247      *         <allele>ggg</allele>
0248      *     </alleles>
0249      </root-name>
0250      * }</pre>
0251      */
0252     public static final class BoundedChromosome {
0253         private BoundedChromosome() {}
0254 
0255         static final String LENGTH_NAME = "length";
0256         static final String MIN_NAME = "min";
0257         static final String MAX_NAME = "max";
0258         static final String ALLELE_NAME = "allele";
0259         static final String ALLELES_NAME = "alleles";
0260 
0261         /**
0262          * Create a bounded chromosome writer with the given configuration.
0263          *
0264          @param rootName the name of the root element. E.g. {@code int-chromosome}
0265          @param alleleWriter the XML writer used for the alleles
0266          @param <A> the allele type
0267          @param <G> the bounded gene type
0268          @param <C> the bounded chromosome type
0269          @return a bounded chromosome XML writer
0270          @throws NullPointerException if one of the arguments is {@code null}
0271          */
0272         public static <
0273             extends Comparable<? super A>,
0274             extends BoundedGene<A, G>,
0275             extends org.jenetics.BoundedChromosome<A, G>
0276         >
0277         Writer<C> writer(
0278             final String rootName,
0279             final Writer<? super A> alleleWriter
0280         ) {
0281             requireNonNull(rootName);
0282             requireNonNull(alleleWriter);
0283 
0284             return elem(rootName,
0285                 attr(LENGTH_NAME).map(ch -> ch.length()),
0286                 elem(MIN_NAME, alleleWriter.map(ch -> ch.getMin())),
0287                 elem(MAX_NAME, alleleWriter.map(ch -> ch.getMax())),
0288                 elem(ALLELES_NAME,
0289                     elems(ALLELE_NAME, alleleWriter)
0290                         .map(ch -> ch.toSeq().map(G::getAllele))
0291                 )
0292             );
0293         }
0294     }
0295 
0296     /**
0297      * This class contains static writer methods for
0298      {@link org.jenetics.IntegerChromosome} objects.
0299      <p>
0300      <b>Writer code</b>
0301      <pre>{@code
0302      * final IntegerChromosome value = IntegerChromosome
0303      *     .of(Integer.MIN_VALUE, Integer.MAX_VALUE, 3);
0304      * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
0305      *     Writers.IntegerChromosome.writer().write(value, xml);
0306      * }
0307      * }</pre>
0308      *
0309      <b>XML output</b>
0310      <pre> {@code
0311      <int-chromosome length="3">
0312      *     <min>-2147483648</min>
0313      *     <max>2147483647</max>
0314      *     <alleles>
0315      *         <allele>-1878762439</allele>
0316      *         <allele>-957346595</allele>
0317      *         <allele>-88668137</allele>
0318      *     </alleles>
0319      </int-chromosome>
0320      * }</pre>
0321      */
0322     public static final class IntegerChromosome {
0323         private IntegerChromosome() {}
0324 
0325         static final String ROOT_NAME = "int-chromosome";
0326 
0327         /**
0328          * Return the default integer allele writer for the
0329          * {@code IntegerChromosome}.
0330          *
0331          @return the default integer allele writer
0332          */
0333         public static Writer<Integer> alleleWriter() {
0334             return text();
0335         }
0336 
0337         /**
0338          * Return a {@link Writer} for {@link org.jenetics.IntegerChromosome}
0339          * objects.
0340          *
0341          @param alleleWriter the allele writer used for writing the integer
0342          *        allele. Might be useful for using different integer
0343          *        <i>encodings</i>.
0344          @return a chromosome writer
0345          @throws NullPointerException if the given {@code alleleWriter} is
0346          *         {@code null}
0347          */
0348         public static Writer<org.jenetics.IntegerChromosome>
0349         writer(final Writer<? super Integer> alleleWriter) {
0350             requireNonNull(alleleWriter);
0351 
0352             return BoundedChromosome.writer(ROOT_NAME, alleleWriter);
0353         }
0354 
0355         /**
0356          * Return a {@link Writer} for {@link org.jenetics.IntegerChromosome}
0357          * objects.
0358          *
0359          @return a chromosome writer
0360          */
0361         public static Writer<org.jenetics.IntegerChromosome> writer() {
0362             return writer(alleleWriter());
0363         }
0364 
0365         /**
0366          * Write the given {@link org.jenetics.IntegerChromosome} to the given
0367          * output stream.
0368          *
0369          @param out the target output stream
0370          @param data the chromosome to write
0371          @param indent the XML level indentation
0372          @throws XMLStreamException if an error occurs while writing the
0373          *         chromosome
0374          @throws NullPointerException if the {@code chromosome} or output
0375          *         stream is {@code null}
0376          */
0377         public static void write(
0378             final OutputStream out,
0379             final org.jenetics.IntegerChromosome data,
0380             final String indent
0381         )
0382             throws XMLStreamException
0383         {
0384             requireNonNull(data);
0385             requireNonNull(out);
0386 
0387             try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
0388                 writer().write(xml, data);
0389             }
0390         }
0391 
0392         /**
0393          * Write the given {@link org.jenetics.IntegerChromosome} to the given
0394          * output stream.
0395          *
0396          @param out the target output stream
0397          @param data the chromosome to write
0398          @throws XMLStreamException if an error occurs while writing the
0399          *         chromosome
0400          @throws NullPointerException if the {@code chromosome} or output
0401          *         stream is {@code null}
0402          */
0403         public static void write(
0404             final OutputStream out,
0405             final org.jenetics.IntegerChromosome data
0406         )
0407             throws XMLStreamException
0408         {
0409             write(out, data, null);
0410         }
0411     }
0412 
0413     /**
0414      * This class contains static writer methods for
0415      {@link org.jenetics.LongChromosome} objects.
0416      <p>
0417      <b>Writer code</b>
0418      <pre>{@code
0419      * final LongChromosome value = LongChromosome
0420      *     .of(Long.MIN_VALUE, Long.MAX_VALUE, 3);
0421      * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
0422      *     Writers.LongChromosome.writer().write(value, xml);
0423      * }
0424      * }</pre>
0425      *
0426      <b>XML output</b>
0427      <pre> {@code
0428      <long-chromosome length="3">
0429      *     <min>-9223372036854775808</min>
0430      *     <max>9223372036854775807</max>
0431      *     <alleles>
0432      *         <allele>-1345217698116542402</allele>
0433      *         <allele>-7144755673073475303</allele>
0434      *         <allele>6053786736809578435</allele>
0435      *     </alleles>
0436      </long-chromosome>
0437      * }</pre>
0438      */
0439     public static final class LongChromosome {
0440         private LongChromosome() {}
0441 
0442         static final String ROOT_NAME = "long-chromosome";
0443 
0444         /**
0445          * Return the default long allele writer for the
0446          * {@code IntegerChromosome}.
0447          *
0448          @return the default long allele writer
0449          */
0450         public static Writer<Long> alleleWriter() {
0451             return Writer.text();
0452         }
0453 
0454         /**
0455          * Return a {@link Writer} for {@link org.jenetics.LongChromosome}
0456          * objects.
0457          *
0458          @param alleleWriter the allele writer used for writing the long
0459          *        allele. Might be useful for using different long
0460          *        <i>encodings</i>.
0461          @return a chromosome writer
0462          @throws NullPointerException if the given {@code alleleWriter} is
0463          *         {@code null}
0464          */
0465         public static Writer<org.jenetics.LongChromosome>
0466         writer(final Writer<? super Long> alleleWriter) {
0467             return BoundedChromosome.writer(ROOT_NAME, alleleWriter);
0468         }
0469 
0470         /**
0471          * Return a {@link Writer} for {@link org.jenetics.LongChromosome}
0472          * objects.
0473          *
0474          @return a chromosome writer
0475          */
0476         public static Writer<org.jenetics.LongChromosome> writer() {
0477             return writer(alleleWriter());
0478         }
0479 
0480         /**
0481          * Write the given {@link org.jenetics.LongChromosome} to the given
0482          * output stream.
0483          *
0484          @param out the target output stream
0485          @param data the chromosome to write
0486          @param indent the XML level indentation
0487          @throws XMLStreamException if an error occurs while writing the
0488          *         chromosome
0489          @throws NullPointerException if the {@code chromosome} or output
0490          *         stream is {@code null}
0491          */
0492         public static void write(
0493             final OutputStream out,
0494             final org.jenetics.LongChromosome data,
0495             final String indent
0496         )
0497             throws XMLStreamException
0498         {
0499             requireNonNull(data);
0500             requireNonNull(out);
0501 
0502             try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
0503                 writer().write(xml, data);
0504             }
0505         }
0506 
0507         /**
0508          * Write the given {@link org.jenetics.LongChromosome} to the given
0509          * output stream.
0510          *
0511          @param out the target output stream
0512          @param data the chromosome to write
0513          @throws XMLStreamException if an error occurs while writing the
0514          *         chromosome
0515          @throws NullPointerException if the {@code chromosome} or output
0516          *         stream is {@code null}
0517          */
0518         public static void write(
0519             final OutputStream out,
0520             final org.jenetics.LongChromosome data
0521         )
0522             throws XMLStreamException
0523         {
0524             write(out, data, null);
0525         }
0526     }
0527 
0528     /**
0529      * This class contains static writer methods for
0530      {@link org.jenetics.DoubleChromosome} objects.
0531      <p>
0532      <b>Writer code</b>
0533      <pre>{@code
0534      * final DoubleChromosome value = DoubleChromosome.of(0.0, 1.0, 3);
0535      * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
0536      *     Writers.DoubleChromosome.writer().write(value, xml);
0537      * }
0538      * }</pre>
0539      *
0540      <b>XML output</b>
0541      <pre> {@code
0542      <double-chromosome length="3">
0543      *     <min>0.0</min>
0544      *     <max>1.0</max>
0545      *     <alleles>
0546      *         <allele>0.27251556008507416</allele>
0547      *         <allele>0.003140816229067145</allele>
0548      *         <allele>0.43947528327497376</allele>
0549      *     </alleles>
0550      </double-chromosome>
0551      * }</pre>
0552      */
0553     public static final class DoubleChromosome
0554         //extends WriterProvider<org.jenetics.DoubleChromosome>
0555     {
0556         private DoubleChromosome() {}
0557 
0558         static final String ROOT_NAME = "double-chromosome";
0559 
0560         /**
0561          * Return the default double allele writer for the
0562          * {@code DoubleChromosome}.
0563          *
0564          @return the default double allele writer
0565          */
0566         public static Writer<Double> alleleWriter() {
0567             return text().map(Object::toString);
0568         }
0569 
0570         /**
0571          * Return a {@link Writer} for {@link org.jenetics.DoubleChromosome}
0572          * objects.
0573          *
0574          @param alleleWriter the allele writer used for writing the long
0575          *        allele. Might be useful for using different long
0576          *        <i>encodings</i>.
0577          @return a chromosome writer
0578          @throws NullPointerException if the given {@code alleleWriter} is
0579          *         {@code null}
0580          */
0581         public static Writer<org.jenetics.DoubleChromosome>
0582         writer(final Writer<? super Double> alleleWriter) {
0583             return BoundedChromosome.writer(ROOT_NAME, alleleWriter);
0584         }
0585 
0586         /**
0587          * Return a {@link Writer} for {@link org.jenetics.DoubleChromosome}
0588          * objects.
0589          *
0590          @return a chromosome writer
0591          */
0592         public static Writer<org.jenetics.DoubleChromosome> writer() {
0593             return writer(alleleWriter());
0594         }
0595 
0596         public Class<org.jenetics.DoubleChromosome> type() {
0597             return org.jenetics.DoubleChromosome.class;
0598         }
0599 
0600         /**
0601          * Write the given {@link org.jenetics.DoubleChromosome} to the given
0602          * output stream.
0603          *
0604          @param out the target output stream
0605          @param data the chromosome to write
0606          @param indent the XML level indentation
0607          @throws XMLStreamException if an error occurs while writing the
0608          *         chromosome
0609          @throws NullPointerException if the {@code chromosome} or output
0610          *         stream is {@code null}
0611          */
0612         public static void write(
0613             final OutputStream out,
0614             final org.jenetics.DoubleChromosome data,
0615             final String indent
0616         )
0617             throws XMLStreamException
0618         {
0619             requireNonNull(data);
0620             requireNonNull(out);
0621 
0622             try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
0623                 writer().write(xml, data);
0624             }
0625         }
0626 
0627         /**
0628          * Write the given {@link org.jenetics.DoubleChromosome} to the given
0629          * output stream.
0630          *
0631          @param out the target output stream
0632          @param data the chromosome to write
0633          @throws XMLStreamException if an error occurs while writing the
0634          *         chromosome
0635          @throws NullPointerException if the {@code chromosome} or output
0636          *         stream is {@code null}
0637          */
0638         public static void write(
0639             final OutputStream out,
0640             final org.jenetics.DoubleChromosome data
0641         )
0642             throws XMLStreamException
0643         {
0644             write(out, data, null);
0645         }
0646     }
0647 
0648     /**
0649      * This class contains static writer methods for
0650      {@link org.jenetics.PermutationChromosome} objects.
0651      <p>
0652      <b>Writer code</b>
0653      <pre>{@code
0654      * final PermutationChromosome<Integer> value =
0655      *     PermutationChromosome.ofInteger(5)
0656      *
0657      * final Writer<PermutationChromosome<Integer> writer =
0658      *     Writers.PermutationChromosome.writer();
0659      *
0660      * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
0661      *     Writers.PermutationChromosome.writer().write(value, xml);
0662      * }
0663      * }</pre>
0664      *
0665      <b>XML output</b>
0666      <pre> {@code
0667      <permutation-chromosome length="5">
0668      *     <valid-alleles type="java.lang.Integer">
0669      *         <allele>0</allele>
0670      *         <allele>1</allele>
0671      *         <allele>2</allele>
0672      *         <allele>3</allele>
0673      *         <allele>4</allele>
0674      *     </valid-alleles>
0675      *     <order>2 1 3 5 4</order>
0676      </permutation-chromosome>
0677      * }</pre>
0678      */
0679     public static final class PermutationChromosome {
0680         private PermutationChromosome() {}
0681 
0682         static final String ROOT_NAME = "permutation-chromosome";
0683         static final String LENGTH_NAME = "length";
0684         static final String VALID_ALLELES_NAME = "valid-alleles";
0685         static final String ALLELE_NAME = "allele";
0686         static final String ORDER_NAME = "order";
0687 
0688         /**
0689          * Create a writer for permutation-chromosomes. How to write the valid
0690          * alleles is defined by the given {@link Writer}.
0691          *
0692          @param alleleWriter the allele writer
0693          @param <A> the allele type
0694          @return a new permutation chromosome writer
0695          @throws NullPointerException if the given allele {@code writer} is
0696          *         {@code null}
0697          */
0698         public static <A> Writer<org.jenetics.PermutationChromosome<A>>
0699         writer(final Writer<? super A> alleleWriter) {
0700             return elem(ROOT_NAME,
0701                 attr(LENGTH_NAME).map(org.jenetics.PermutationChromosome::length),
0702                 elem(VALID_ALLELES_NAME,
0703                     attr("type").map(PermutationChromosome::toAlleleTypeName),
0704                     elems(ALLELE_NAME, alleleWriter)
0705                         .map(ch -> ch.getValidAlleles())
0706                 ),
0707                 elem(ORDER_NAME, text())
0708                     .map(ch -> ch.stream()
0709                         .map(g -> Integer.toString(g.getAlleleIndex()))
0710                         .collect(Collectors.joining(" ")))
0711             );
0712         }
0713 
0714         private static String toAlleleTypeName(
0715             final org.jenetics.PermutationChromosome<?> ch
0716         ) {
0717             return ch.getGene().getAllele().getClass().getCanonicalName();
0718         }
0719 
0720         /**
0721          * Create a writer for permutation-chromosomes. The valid alleles are
0722          * serialized by calling the {@link Object#toString()} method. Calling
0723          * this method is equivalent with:
0724          <pre>{@code
0725          * final Writer<PermutationChromosome<Double> writer =
0726          *     PermutationChromosome.write(text().map(Objects::toString));
0727          * }</pre>
0728          *
0729          * Example output:
0730          <pre> {@code
0731          <permutation-chromosome length="15">
0732          *     <valid-alleles type="java.lang.Double">
0733          *         <allele>0.27251556008507416</allele>
0734          *         <allele>0.003140816229067145</allele>
0735          *         <allele>0.43947528327497376</allele>
0736          *         <allele>0.10654807463069327</allele>
0737          *         <allele>0.19696530915810317</allele>
0738          *         <allele>0.7450003838065538</allele>
0739          *         <allele>0.5594416969271359</allele>
0740          *         <allele>0.02823782430152355</allele>
0741          *         <allele>0.5741102315010789</allele>
0742          *         <allele>0.4533651041367144</allele>
0743          *         <allele>0.811148141800367</allele>
0744          *         <allele>0.5710456351848858</allele>
0745          *         <allele>0.30166768355230955</allele>
0746          *         <allele>0.5455492865240272</allele>
0747          *         <allele>0.21068427527733102</allele>
0748          *     </valid-alleles>
0749          *     <order>13 12 4 6 8 14 7 2 11 5 3 0 9 10 1</order>
0750          </permutation-chromosome>
0751          * }</pre>
0752          *
0753          @param <A> the allele type
0754          @return a new permutation chromosome writer
0755          */
0756         public static <A> Writer<org.jenetics.PermutationChromosome<A>> writer() {
0757             return writer(text());
0758         }
0759 
0760         /**
0761          * Write the given {@link org.jenetics.PermutationChromosome} to the
0762          * given output stream.
0763          *
0764          @param <A> the allele type
0765          @param out the target output stream
0766          @param data the chromosome to write
0767          @param indent the XML level indentation
0768          @throws XMLStreamException if an error occurs while writing the
0769          *         chromosome
0770          @throws NullPointerException if the {@code chromosome} or output
0771          *         stream is {@code null}
0772          */
0773         public static <A> void write(
0774             final OutputStream out,
0775             final org.jenetics.PermutationChromosome<A> data,
0776             final String indent
0777         )
0778             throws XMLStreamException
0779         {
0780             requireNonNull(data);
0781             requireNonNull(out);
0782 
0783             try (AutoCloseableXMLStreamWriter writer = XML.writer(out, indent)) {
0784                 PermutationChromosome.<A>writer().write(writer, data);
0785             }
0786         }
0787 
0788         /**
0789          * Write the given {@link org.jenetics.PermutationChromosome} to the
0790          * given output stream.
0791          *
0792          @param <A> the allele type
0793          @param out the target output stream
0794          @param data the chromosome to write
0795          @param indent the XML level indentation
0796          @param alleleWriter the allele writer of the permutation chromosome
0797          @throws XMLStreamException if an error occurs while writing the
0798          *         chromosome
0799          @throws NullPointerException if the {@code chromosome} or output
0800          *         stream is {@code null}
0801          */
0802         public static <A> void write(
0803             final OutputStream out,
0804             final org.jenetics.PermutationChromosome<A> data,
0805             final String indent,
0806             final Writer<? super A> alleleWriter
0807         )
0808             throws XMLStreamException
0809         {
0810             requireNonNull(data);
0811             requireNonNull(alleleWriter);
0812             requireNonNull(out);
0813 
0814             try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) {
0815                 PermutationChromosome.<A>writer(alleleWriter)
0816                     .write(xml, data);
0817             }
0818         }
0819 
0820         /**
0821          * Write the given {@link org.jenetics.PermutationChromosome} to the
0822          * given output stream.
0823          *
0824          @param <A> the allele type
0825          @param out the target output stream
0826          @param data the chromosome to write
0827          @throws XMLStreamException if an error occurs while writing the
0828          *         chromosome
0829          @throws NullPointerException if the {@code chromosome} or output
0830          *         stream is {@code null}
0831          */
0832         public static <A> void write(
0833             final OutputStream out,
0834             final org.jenetics.PermutationChromosome<A> data
0835         )
0836             throws XMLStreamException
0837         {
0838             write(out, data, null, text());
0839         }
0840 
0841         /**
0842          * Write the given {@link org.jenetics.PermutationChromosome} to the
0843          * given output stream.
0844          *
0845          @param <A> the allele type
0846          @param out the target output stream
0847          @param data the chromosome to write
0848          @param alleleWriter the allele writer used to write the chromosome
0849          *         alleles
0850          @throws XMLStreamException if an error occurs while writing the
0851          *         chromosome
0852          @throws NullPointerException if the {@code chromosome} or output
0853          *         stream is {@code null}
0854          */
0855         public static <A> void write(
0856             final OutputStream out,
0857             final org.jenetics.PermutationChromosome<A> data,
0858             final Writer<? super A> alleleWriter
0859         )
0860             throws XMLStreamException
0861         {
0862             write(out, data, null, alleleWriter);
0863         }
0864 
0865     }
0866 
0867     /**
0868      * This class contains static writer methods for
0869      {@link org.jenetics.Genotype} objects.
0870      <p>
0871      <b>Writer code</b>
0872      <pre>{@code
0873      * final Genotype<DoubleGene> gt = Genotype.of(
0874      *     DoubleChromosome.of(0.0, 1.0, 3),
0875      *     DoubleChromosome.of(0.0, 1.0, 2)
0876      * );
0877      * final Writer<Genotype<DoubleGene>> writer =
0878      *     Writers.Genotype.writer(Writers.DoubleChromosome.writer());
0879      *
0880      * try (AutoCloseableXMLStreamWriter xml = XML.writer(System.out, "    ")) {
0881      *     writer.write(value, xml);
0882      * }
0883      * }</pre>
0884      *
0885      <b>XML output</b>
0886      <pre> {@code
0887      <genotype length="2" ngenes="5">
0888      *     <double-chromosome length="3">
0889      *         <min>0.0</min>
0890      *         <max>1.0</max>
0891      *         <alleles>
0892      *             <allele>0.27251556008507416</allele>
0893      *             <allele>0.003140816229067145</allele>
0894      *             <allele>0.43947528327497376</allele>
0895      *         </alleles>
0896      *     </double-chromosome>
0897      *     <double-chromosome length="2">
0898      *         <min>0.0</min>
0899      *         <max>1.0</max>
0900      *         <alleles>
0901      *             <allele>0.4026521545744768</allele>
0902      *             <allele>0.36137605952663554</allele>
0903      *         <alleles>
0904      *     </double-chromosome>
0905      </genotype>
0906      * }</pre>
0907      */
0908     public static final class Genotype {
0909         private Genotype() {}
0910 
0911         static final String ROOT_NAME = "genotype";
0912         static final String LENGTH_NAME = "length";
0913         static final String NGENES_NAME = "ngenes";
0914 
0915         /**
0916          * Create a writer for genotypes of arbitrary chromosomes. How to write the
0917          * genotypes chromosomes is defined by the given {@link Writer}.
0918          *
0919          @param writer the chromosome writer
0920          @param <A> the allele type
0921          @param <G> the gene type
0922          @param <C> the chromosome type
0923          @return a new genotype writer
0924          @throws NullPointerException if the given chromosome {@code writer} is
0925          *         {@code null}
0926          */
0927         public static <
0928             A,
0929             extends Gene<A, G>,
0930             extends Chromosome<G>
0931         >
0932         Writer<org.jenetics.Genotype<G>> writer(final Writer<? super C> writer) {
0933             return elem(
0934                 ROOT_NAME,
0935                 attr(LENGTH_NAME).map(org.jenetics.Genotype<G>::length),
0936                 attr(NGENES_NAME).map(org.jenetics.Genotype<G>::getNumberOfGenes),
0937                 elems(writer).map(gt -> cast(gt.toSeq()))
0938             );
0939         }
0940 
0941         @SuppressWarnings("unchecked")
0942         private static <A, B> B cast(final A value) {
0943             return (B)value;
0944         }
0945 
0946         /**
0947          * Write the given {@link org.jenetics.Genotype} to the given output
0948          * stream.
0949          *
0950          @param <A> the allele type
0951          @param <G> the gene type
0952          @param <C> the chromosome type
0953          @param out the target output stream
0954          @param data the genotype to write
0955          @param indent the XML level indentation
0956          @param chromosomeWriter the chromosome writer used to write the
0957          *        genotypes
0958          @throws XMLStreamException if an error occurs while writing the
0959          *         chromosome
0960          @throws NullPointerException if the one of the arguments is
0961          *         {@code null}
0962          */
0963         public static <
0964             A,
0965             extends Gene<A, G>,
0966             extends Chromosome<G>
0967         >
0968         void write(
0969             final OutputStream out,
0970             final org.jenetics.Genotype<G> data,
0971             final String indent,
0972             final Writer<? super C> chromosomeWriter
0973         )
0974             throws XMLStreamException
0975         {
0976             requireNonNull(data);
0977             requireNonNull(chromosomeWriter);
0978             requireNonNull(out);
0979 
0980             try (AutoCloseableXMLStreamWriter writer = XML.writer(out, indent)) {
0981                 Genotype.<A, G, C>writer(chromosomeWriter).write(writer, data);
0982             }
0983         }
0984 
0985         /**
0986          * Write the given {@link org.jenetics.Genotype} to the given output
0987          * stream.
0988          *
0989          @param <A> the allele type
0990          @param <G> the gene type
0991          @param <C> the chromosome type
0992          @param out the target output stream
0993          @param data the genotype to write
0994          @param chromosomeWriter the chromosome writer used to write the
0995          *        genotypes
0996          @throws XMLStreamException if an error occurs while writing the
0997          *         chromosome
0998          @throws NullPointerException if the one of the arguments is
0999          *         {@code null}
1000          */
1001         public static <
1002             A,
1003             extends Gene<A, G>,
1004             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             extends Gene<A, G>,
1093             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             extends Gene<A, G>,
1124             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             extends Gene<A, G>,
1162             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         extends Gene<A, G>,
1204         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 }