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