/* * Java Genetic Algorithm Library (@__identifier__@). * Copyright (c) @__year__@ Franz Wilhelmstötter * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Author: * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at) */ package org.jenetics.tool.evaluation; import static java.io.File.createTempFile; import static java.lang.String.format; import static java.nio.file.Files.deleteIfExists; import static java.util.Objects.requireNonNull; import static java.util.stream.Stream.concat; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.Stream; import org.jenetics.internal.util.Args; import org.jenetics.tool.trial.Gnuplot; import org.jenetics.tool.trial.IO; import org.jenetics.tool.trial.Params; import org.jenetics.tool.trial.SampleSummary; import org.jenetics.tool.trial.TrialMeter; /** * Helper class for creating Gnuplot diagrams from result files. * * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> * @version 3.4 * @since 3.4 */ public class Diagram { /** * The available Gnuplot templates. */ public static enum Template { /** * Template for execution time termination diagrams. */ EXECUTION_TIME("execution_time_termination"), GENERATIO_POPULATION_SIZE("generation_population_size"), /** * Template for fitness threshold termination diagrams. */ FITNESS_THRESHOLD("fitness_threshold_termination"), /** * Template for fixed generation termination diagrams. */ FIXED_GENERATION("fixed_generation_termination"), /** * Template for steady fitness termination diagrams, */ STEADY_FITNESS("steady_fitness_termination"), /** * Template for comparing different selectors. */ SELECTOR_COMPARISON("selector_comparison"), POPULATION_SIZE("population_size"); private final String _name; private final String _path; private Template(final String name) { _name = requireNonNull(name); _path = "/org/jenetics/tool/evaluation/" + requireNonNull(name) + ".gp"; } public String getName() { return _name; } /** * Return the template content as string. * * @return the template content */ public String content() { try (InputStream stream = Diagram.class.getResourceAsStream(_path)) { return IO.toText(stream); } catch (IOException e) { throw new UncheckedIOException(e); } } } /** * Create a performance diagram. * * @param template the Gnuplot template to use * @param params the diagram parameters (x-axis) * @param output the output file * @param summary the first summary data * @param summaries the rest of the summary data * @throws IOException if the diagram generation fails * @throws NullPointerException of one of the parameters is {@code null} * @throws IllegalArgumentException if the {@code params}, {@code generation} * and {@code fitness} doesn't have the same parameter count */ public static void create( final Template template, final Params<?> params, final Path output, final SampleSummary summary, final SampleSummary... summaries ) throws IOException { final Stream<SampleSummary> summaryStream = Stream.concat( Stream.of(summary), Stream.of(summaries) ); summaryStream.forEach(s -> { if (params.size() != s.parameterCount()) { throw new IllegalArgumentException(format( "Parameters have different size: %d", params.size() )); } }); final Path templatePath = tempPath(); try { IO.write(template.content(), templatePath); final Path dataPath = tempPath(); try { final String data = IntStream.range(0, params.size()) .mapToObj(i -> toLineString(i, params, summary, summaries)) .collect(Collectors.joining("\n")); IO.write(data, dataPath); final Gnuplot gnuplot = new Gnuplot(templatePath); gnuplot.create(dataPath, output); } finally { deleteIfExists(dataPath); } } finally { deleteIfExists(templatePath); } } private static Path tempPath() throws IOException { return createTempFile("__diagram_template__", "__").toPath(); } private static String toLineString( final int index, final Params<?> params, final SampleSummary summary, final SampleSummary... summaries ) { return concat(concat( Stream.of(params.get(index).toString().split(":")), DoubleStream.of(summary.getPoints().get(index).toArray()) .mapToObj(Double::toString)), Stream.of(summaries) .flatMapToDouble(s -> DoubleStream.of(s.getPoints().get(index).toArray())) .mapToObj(Double::toString)) .collect(Collectors.joining(" ")); } public static void main(final String[] arguments) throws Exception { final Args args = Args.of(arguments); final Path input = args.arg("input") .map(Paths::get) .map(Path::toAbsolutePath) .get(); final String[] samples = args.arg("samples") .map(s -> s.split(",")) .orElse(new String[]{"Generation", "Fitness"}); final TrialMeter<Integer> trial = TrialMeter.read(input); final Params<Integer> params = trial.getParams(); final SampleSummary summary = trial.getData(samples[0]).summary(); final SampleSummary[] summaries = Arrays.stream(samples, 1, samples.length) .map(s -> trial.getData(s).summary()) .toArray(SampleSummary[]::new); create( template(input), params, output(input), summary, summaries ); } private static Template template(final Path path) { final String name = path.getFileName().toString() .split("-")[1] .split("\\.")[0]; return Arrays.stream(Template.values()) .filter(t -> t.getName().equals(name)) .findFirst().get(); } private static Path output(final Path path) { final String name = path.getFileName().toString().split("\\.")[0]; return Paths.get(path.getParent().toString(), name + ".svg"); } }