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[] arguments) throws 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 }
|