#region License Information /* HeuristicLab * Copyright (C) 2002-2015 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.Collections.Generic; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.RealVectorEncoding; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.ParameterOptimization { [Item("BestSolutionsAnalyzer", "Tracks the best parameter vector solutions of the current algorithm run.")] [StorableType("D9D7710F-38CD-4B46-8BE9-6482B3830536")] public class BestSolutionsAnalyzer : SingleSuccessorOperator, IAnalyzer { private const string MaximizationParameterName = "Maximization"; private const string ParameterVectorParameterName = "RealVector"; private const string ParameterNamesParameterName = "ParameterNames"; private const string QualityParameterName = "Quality"; private const string PreviousBestQualityParameterName = "PreviousBestQuality"; private const string BestQualityParameterName = "BestQuality"; private const string BestKnownQualityParameterName = "BestKnownQuality"; private const string ResultsParameterName = "Results"; private const string BestSolutionsResultName = "Best Solutions Store"; public virtual bool EnabledByDefault { get { return false; } } public ILookupParameter MaximizationParameter { get { return (ILookupParameter)Parameters[MaximizationParameterName]; } } public IScopeTreeLookupParameter ParameterVectorParameter { get { return (IScopeTreeLookupParameter)Parameters[ParameterVectorParameterName]; } } public ILookupParameter ParameterNamesParameter { get { return (ILookupParameter)Parameters[ParameterNamesParameterName]; } } public IScopeTreeLookupParameter QualityParameter { get { return (IScopeTreeLookupParameter)Parameters[QualityParameterName]; } } public ILookupParameter PreviousBestQualityParameter { get { return (ILookupParameter)Parameters[PreviousBestQualityParameterName]; } } public ILookupParameter BestQualityParameter { get { return (ILookupParameter)Parameters[BestQualityParameterName]; } } public ILookupParameter BestKnownQualityParameter { get { return (ILookupParameter)Parameters[BestKnownQualityParameterName]; } } public IValueLookupParameter ResultsParameter { get { return (IValueLookupParameter)Parameters[ResultsParameterName]; } } [StorableConstructor] protected BestSolutionsAnalyzer(bool deserializing) : base(deserializing) { } protected BestSolutionsAnalyzer(BestSolutionsAnalyzer original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new BestSolutionsAnalyzer(this, cloner); } public BestSolutionsAnalyzer() : base() { Parameters.Add(new LookupParameter(MaximizationParameterName, "True if the problem is a maximization problem.")); Parameters.Add(new ScopeTreeLookupParameter(ParameterVectorParameterName, "The parameter vector which should be evaluated.")); Parameters.Add(new LookupParameter(ParameterNamesParameterName, "The names of the elements in the parameter vector.")); Parameters.Add(new ScopeTreeLookupParameter(QualityParameterName, "The quality name for the parameter vectors.")); Parameters.Add(new LookupParameter(PreviousBestQualityParameterName, "The best quality of the previous iteration.")); Parameters.Add(new LookupParameter(BestQualityParameterName, "The best quality found so far.")); Parameters.Add(new LookupParameter(BestKnownQualityParameterName, "The quality of the best known solution.")); Parameters.Add(new ValueLookupParameter(ResultsParameterName, "The result collection where the results should be stored.")); } public override IOperation Apply() { ItemArray parameterVectors = ParameterVectorParameter.ActualValue; ItemArray qualities = QualityParameter.ActualValue; bool max = MaximizationParameter.ActualValue.Value; DoubleValue bestKnownQuality = BestKnownQualityParameter.ActualValue; var solutions = parameterVectors.Zip(qualities, (ParameterVector, Quality) => new { ParameterVector, Quality }); if (max) solutions = solutions.MaxItems(s => s.Quality.Value); else solutions = solutions.MinItems(s => s.Quality.Value); if (BestQualityParameter.ActualValue == null) { if (max) BestQualityParameter.ActualValue = new DoubleValue(double.MinValue); else BestQualityParameter.ActualValue = new DoubleValue(double.MaxValue); } if (PreviousBestQualityParameter.ActualValue == null) PreviousBestQualityParameter.ActualValue = (DoubleValue)BestQualityParameter.ActualValue.Clone(); //add result for best solutions ResultCollection results = ResultsParameter.ActualValue; if (!results.ContainsKey(BestSolutionsResultName)) results.Add(new Result(BestSolutionsResultName, new ItemSet(new DoubleArrayEqualityComparer()))); var previousBestQuality = PreviousBestQualityParameter.ActualValue.Value; var bestQuality = solutions.First().Quality.Value; var bestSolutions = (ItemSet)results[BestSolutionsResultName].Value; //clear best solutions if new found quality is better than the existing one if (max && bestQuality > previousBestQuality || !max && bestQuality < previousBestQuality) bestSolutions.Clear(); //add new found solutions if (max && bestQuality >= BestQualityParameter.ActualValue.Value || !max && bestQuality <= BestQualityParameter.ActualValue.Value) { foreach (var solution in solutions) { var newSolution = (DoubleArray)solution.ParameterVector.Clone(); newSolution.ElementNames = ParameterNamesParameter.ActualValue; bestSolutions.Add(newSolution); } } //update best quality if (max && bestQuality >= BestQualityParameter.ActualValue.Value || !max && bestQuality <= BestQualityParameter.ActualValue.Value) { BestQualityParameter.ActualValue.Value = bestQuality; } //update best known quality if (bestKnownQuality == null || max && bestQuality > bestKnownQuality.Value || !max && bestQuality < bestKnownQuality.Value) { BestKnownQualityParameter.ActualValue = new DoubleValue(bestQuality); } PreviousBestQualityParameter.ActualValue = (DoubleValue)BestQualityParameter.ActualValue.Clone(); return base.Apply(); } } public class DoubleArrayEqualityComparer : IEqualityComparer { public bool Equals(DoubleArray x, DoubleArray y) { if (x == null && y == null) return true; if (x == null) return false; if (y == null) return false; return x.SequenceEqual(y); } public int GetHashCode(DoubleArray obj) { if (obj == null) return 0; return (int)obj.Aggregate(23L, (current, item) => current ^ System.BitConverter.DoubleToInt64Bits(item)); } } }