#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using HEAL.Attic;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.IntegerVectorEncoding;
using HeuristicLab.Encodings.RealVectorEncoding;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
namespace HeuristicLab.Problems.Modifiers {
[StorableType("FADAA1BF-7B7A-4E28-AA15-22AF56D63CFE")]
[Item("MultiObjectiveEvaluationLogProblemModifier", "A problem modifier that logs evaluations in a file")]
public class EvaluationLoggingProblemModifier : ProblemModifier {
private readonly object fileLock = new object();
#region ParameterNames
private const string LogFileParameterName = "LogFile";
#endregion
#region Parameters
public IValueParameter LogFileParameter => (IValueParameter)Parameters[LogFileParameterName];
#endregion
#region ParameterNames
public FileValue LogFile => LogFileParameter.Value;
#endregion
#region Constructors & Cloning
[StorableConstructor]
protected EvaluationLoggingProblemModifier(StorableConstructorFlag _) : base(_) { }
protected EvaluationLoggingProblemModifier(EvaluationLoggingProblemModifier original, Cloner cloner) : base(original, cloner) {
}
public EvaluationLoggingProblemModifier() {
var defaultFileName = $"{Environment.CurrentDirectory}\\Log_{Guid.NewGuid()}.txt";
var value = new FileValue();
value.StringValue.Value = defaultFileName;
Parameters.Add(new ValueParameter(LogFileParameterName, "The log file into which evaluations should be logged.", value));
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() { }
public override IDeepCloneable Clone(Cloner cloner) {
return new EvaluationLoggingProblemModifier(this, cloner);
}
#endregion
#region ProblemModifier
public override double[] ModifiedEvaluate(Individual individual, IRandom random) {
var qualities = base.ModifiedEvaluate(individual, random);
lock (fileLock) { LogResultsToFile(individual, LogFile.Value, Encoding); }
return qualities;
}
#endregion
#region Helpers
private static void LogResultsToFile(Individual individual, string logFilePath, IEncoding enc) {
if (string.IsNullOrEmpty(logFilePath)) throw new ArgumentException("Log path is null or empty");
var logFile = new FileInfo(logFilePath);
if (!logFile.Exists) {
logFile.Directory?.Create();
logFile.Create();
}
var logLines = new List();
var sb = new StringBuilder();
var inputs = ExtractInputs(individual, enc).ToArray();
var additionalInfo = ExtractAdditionalInfo(individual, enc);
if (logFile.Length == 0) {
var digits = Math.Ceiling(Math.Log10(inputs.Length));
var header = Enumerable
.Range(0, inputs.Length)
.Select(x => string.Format($"X{{0:D{digits}}}", x))
.Concat(additionalInfo.Select(x => x.Item1));
logLines.Add(string.Join(";", header));
sb.Clear();
}
logLines.Add(string.Join(";", inputs.Concat(additionalInfo.Select(x => x.Item2))));
sb.Clear();
File.AppendAllLines(logFilePath, logLines);
}
private static Tuple[] ExtractAdditionalInfo(Individual individual, IEncoding enc) {
return individual.Values.Where(x => x.Key != enc.Name).OrderBy(x => x.Key).Select(x => Tuple.Create(x.Key, x.Value.ToString())).ToArray();
}
private static IEnumerable