Diagram.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.7.0).
003  * Copyright (c) 2007-2016 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019  */
020 package org.jenetics.tool.evaluation;
021 
022 import static java.io.File.createTempFile;
023 import static java.lang.String.format;
024 import static java.nio.file.Files.deleteIfExists;
025 import static java.util.Objects.requireNonNull;
026 import static java.util.stream.Stream.concat;
027 
028 import java.io.IOException;
029 import java.io.InputStream;
030 import java.io.UncheckedIOException;
031 import java.nio.file.Path;
032 import java.nio.file.Paths;
033 import java.util.Arrays;
034 import java.util.HashMap;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.regex.Pattern;
038 import java.util.stream.Collectors;
039 import java.util.stream.DoubleStream;
040 import java.util.stream.IntStream;
041 import java.util.stream.Stream;
042 
043 import org.jenetics.internal.util.Args;
044 
045 import org.jenetics.tool.trial.Gnuplot;
046 import org.jenetics.tool.trial.IO;
047 import org.jenetics.tool.trial.Params;
048 import org.jenetics.tool.trial.SampleSummary;
049 import org.jenetics.tool.trial.TrialMeter;
050 
051 /**
052  * Helper class for creating Gnuplot diagrams from result files.
053  *
054  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
055  @version 3.7
056  @since 3.4
057  */
058 public class Diagram {
059 
060     /**
061      * The available Gnuplot templates.
062      */
063     public static enum Template {
064 
065         /**
066          * Template for execution time termination diagrams.
067          */
068         EXECUTION_TIME("execution_time_termination"),
069 
070         GENERATION_POPULATION_SIZE("generation_population_size"),
071 
072         /**
073          * Template for fitness threshold termination diagrams.
074          */
075         FITNESS_THRESHOLD("fitness_threshold_termination"),
076 
077         /**
078          * Template for fitness threshold termination diagrams.
079          */
080         FITNESS_CONVERGENCE("fitness_convergence_termination"),
081 
082         /**
083          * Template for fixed generation termination diagrams.
084          */
085         FIXED_GENERATION("fixed_generation_termination"),
086 
087         /**
088          * Template for steady fitness termination diagrams,
089          */
090         STEADY_FITNESS("steady_fitness_termination"),
091 
092         /**
093          * Template for comparing different selectors.
094          */
095         SELECTOR_COMPARISON("selector_comparison"),
096 
097         POPULATION_SIZE("population_size");
098 
099         private final String _name;
100         private final String _path;
101 
102         private Template(final String name) {
103             _name = requireNonNull(name);
104             _path = "/org/jenetics/tool/evaluation/" +
105                 requireNonNull(name".gp";
106         }
107 
108         public String getName() {
109             return _name;
110         }
111 
112         /**
113          * Return the template content as string.
114          *
115          @return the template content
116          */
117         public String content() {
118             try (InputStream stream = Diagram.class.getResourceAsStream(_path)) {
119                 return IO.toText(stream);
120             catch (IOException e) {
121                 throw new UncheckedIOException(e);
122             }
123         }
124     }
125 
126     /**
127      * Create a performance diagram.
128      *
129      @param input the input data
130      @param template the Gnuplot template to use
131      @param params the diagram parameters (x-axis)
132      @param output the output file
133      @param summary the first summary data
134      @param summaries the rest of the summary data
135      @throws IOException if the diagram generation fails
136      @throws NullPointerException of one of the parameters is {@code null}
137      @throws IllegalArgumentException if the {@code params}, {@code generation}
138      *         and {@code fitness} doesn't have the same parameter count
139      */
140     public static void create(
141         final Path input,
142         final Template template,
143         final Params<?> params,
144         final Path output,
145         final SampleSummary summary,
146         final SampleSummary... summaries
147     )
148         throws IOException
149     {
150         final Stream<SampleSummary> summaryStream = Stream.concat(
151             Stream.of(summary), Stream.of(summaries)
152         );
153         summaryStream.forEach(s -> {
154             if (params.size() != s.parameterCount()) {
155                 throw new IllegalArgumentException(format(
156                     "Parameters have different size: %d", params.size()
157                 ));
158             }
159         });
160 
161         final Path templatePath = tempPath();
162         try {
163             IO.write(template.content(), templatePath);
164 
165             final Path dataPath = tempPath();
166             try {
167                 final String data = IntStream.range(0, params.size())
168                     .mapToObj(i -> toLineString(i, params, summary, summaries))
169                     .collect(Collectors.joining("\n"));
170                 IO.write(data, dataPath);
171 
172                 final Gnuplot gnuplot = new Gnuplot(templatePath);
173                 gnuplot.setEnv(params(input));
174                 gnuplot.create(dataPath, output);
175             finally {
176                 deleteIfExists(dataPath);
177             }
178         finally {
179             deleteIfExists(templatePath);
180         }
181     }
182 
183     private static Path tempPath() throws IOException {
184         return createTempFile("__diagram_template__""__").toPath();
185     }
186 
187     private static String toLineString(
188         final int index,
189         final Params<?> params,
190         final SampleSummary summary,
191         final SampleSummary... summaries
192     ) {
193         return concat(concat(
194                 Stream.of(params.get(index).toString().split(":")),
195                 DoubleStream.of(summary.getPoints().get(index).toArray())
196                     .mapToObj(Double::toString)),
197                 Stream.of(summaries)
198                     .flatMapToDouble(s -> DoubleStream.of(s.getPoints().get(index).toArray()))
199                     .mapToObj(Double::toString))
200             .collect(Collectors.joining(" "));
201     }
202 
203     public static void main(final String[] argumentsthrows Exception {
204         final Args args = Args.of(arguments);
205 
206         final Path input = args.arg("input")
207             .map(Paths::get)
208             .map(Path::toAbsolutePath)
209             .get();
210 
211         final String[] samples = args.arg("samples")
212             .map(s -> s.split(","))
213             .orElse(new String[]{"Generation""Fitness"});
214 
215         final TrialMeter<Integer> trial = TrialMeter.read(input);
216         final Params<Integer> params = trial.getParams();
217         final SampleSummary summary = trial.getData(samples[0]).summary();
218         final SampleSummary[] summaries = Arrays.stream(samples, 1, samples.length)
219             .map(s -> trial.getData(s).summary())
220             .toArray(SampleSummary[]::new);
221 
222         create(
223             input,
224             template(input),
225             params,
226             output(input),
227             summary,
228             summaries
229         );
230     }
231 
232     private static Template template(final Path path) {
233         final String name = path.getFileName().toString()
234             .split("-")[1]
235             .split("\\.")[0];
236 
237         return Arrays.stream(Template.values())
238             .filter(t -> t.getName().equals(name))
239             .findFirst().get();
240     }
241 
242     private static Map<String, String> params(final Path path) {
243         System.out.println(path.getFileName());
244         final List<String> parts = param(path.getFileName().toString())
245             .flatMap(p -> Stream.of(p.split("@")))
246             .collect(Collectors.toList());
247 
248         final Map<String, String> params = new HashMap<>();
249         for (int i = 0; i < parts.size(); ++i) {
250             final String key = format("PARAM_%s", i);
251             params.put(key, parts.get(i));
252         }
253 
254         return params;
255     }
256 
257     private static Stream<String> param(final String name) {
258         final String[] parts = name.split("-");
259         return parts.length == 3
260             ? Stream.of(parts[2].split("\\.")[0])
261             : Stream.empty();
262     }
263 
264     private static Path output(final Path path) {
265         final String name = path.getFileName().toString().split("\\.")[0];
266         return Paths.get(path.getParent().toString(), name + ".svg");
267     }
268 
269 }