/* Copyright 2009-2015 David Hadka * * This file is part of the MOEA Framework. * * The MOEA Framework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * The MOEA Framework is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>. */ package org.moeaframework.analysis.sensitivity; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import org.moeaframework.core.FrameworkException; import org.moeaframework.core.Settings; import org.moeaframework.core.indicator.QualityIndicator; import org.moeaframework.util.io.FileUtils; /** * Writes metric files. A metric file is the output of {@code Evaluator} and * contains on each line one or more metrics separated by whitespace from one * parameterization. * <p> * This writer will append the results to the file, if a previous file exists. * By reading the previous file with a {@link MetricFileReader}, this writer * will being appending after the last valid entry. Query the * {@link #getNumberOfEntries()} method to determine how many valid entries are * contained in the file. * * @see MetricFileReader */ public class MetricFileWriter implements OutputWriter { /** * The number of metrics supported by {@code MetricFileWriter}. */ public static final int NUMBER_OF_METRICS = 6; /** * The stream for appending data to the file. */ private final PrintWriter writer; /** * The quality indicator for producing the metrics. */ private final QualityIndicator qualityIndicator; /** * The number of lines in the file. */ private int numberOfEntries; /** * Constructs an output writer for writing metric files to the specified * file. If the file already exists, a cleanup operation is first performed. * The cleanup operation removes the last line if incomplete and records the * number of correct lines in the file. The {@link #getNumberOfEntries()} * can then be used to resume evaluation from the last recorded entry. * * @param qualityIndicator the quality indicator for producing the metrics * @param file the file to which the metrics are written * @throws IOException if an I/O error occurred */ public MetricFileWriter(QualityIndicator qualityIndicator, File file) throws IOException { super(); this.qualityIndicator = qualityIndicator; // if the file already exists, move it to a temporary location File existingFile = new File(file.getParent(), "." + file.getName() + ".unclean"); if (existingFile.exists()) { if (Settings.getCleanupStrategy().equalsIgnoreCase("restore")) { if (file.exists()) { FileUtils.delete(existingFile); } else { // do nothing, the unclean file is ready for recovery } } else if (Settings.getCleanupStrategy().equalsIgnoreCase("overwrite")) { FileUtils.delete(existingFile); } else { throw new FrameworkException(ResultFileWriter.EXISTING_FILE); } } if (file.exists()) { FileUtils.move(file, existingFile); } // prepare this class for writing numberOfEntries = 0; writer = new PrintWriter(new BufferedWriter(new FileWriter(file)), true); writer.println("#Hypervolume GenerationalDistance InvertedGenerationalDistance Spacing EpsilonIndicator MaximumParetoFrontError"); // if the file already existed, copy all complete entries if (existingFile.exists()) { MetricFileReader reader = null; try { reader = new MetricFileReader(existingFile); while (reader.hasNext()) { double[] data = reader.next(); writer.print(data[0]); for (int i = 1; i < data.length; i++) { writer.print(' '); writer.print(data[i]); } writer.println(); numberOfEntries++; } } finally { if (reader != null) { reader.close(); } } FileUtils.delete(existingFile); } } @Override public int getNumberOfEntries() { return numberOfEntries; } /** * Evaluates the specified non-dominated population and outputs the * resulting metrics to the file. */ @Override public void append(ResultEntry entry) { qualityIndicator.calculate(entry.getPopulation()); writer.print(qualityIndicator.getHypervolume()); writer.print(' '); writer.print(qualityIndicator.getGenerationalDistance()); writer.print(' '); writer.print(qualityIndicator.getInvertedGenerationalDistance()); writer.print(' '); writer.print(qualityIndicator.getSpacing()); writer.print(' '); writer.print(qualityIndicator.getAdditiveEpsilonIndicator()); writer.print(' '); writer.print(qualityIndicator.getMaximumParetoFrontError()); writer.println(); numberOfEntries++; } @Override public void close() { writer.close(); } }