#region License Information
/* HeuristicLab
* Copyright (C) 2002-2010 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.Linq;
using HEAL.Attic;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Operators;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
namespace HeuristicLab.Analysis.FitnessLandscape {
[Item("Up/Down Walk Analyzer", "Analyzes the quality trail produced from an up/down walk.")]
[StorableType("4077933C-844C-4C38-9A68-78769C969065")]
public class UpDownWalkAnalyzer : SingleSuccessorOperator, IQualityTrailAnalyzer {
public bool EnabledByDefault {
get { return false; }
}
#region Parameters
public LookupParameter QualityTrailParameter {
get { return (LookupParameter)Parameters["Quality Trail"]; }
}
public LookupParameter ResultsParameter {
get { return (LookupParameter)Parameters["Results"]; }
}
public LookupParameter UpWalkLengthParameter {
get { return (LookupParameter)Parameters["UpWalkLength"]; }
}
public LookupParameter DownWalkLengthParameter {
get { return (LookupParameter)Parameters["DownWalkLength"]; }
}
public LookupParameter UpWalkLenVarParameter {
get { return (LookupParameter)Parameters["UpWalkLenVar"]; }
}
public LookupParameter DownWalkLenVarParameter {
get { return (LookupParameter)Parameters["DownWalkLenVar"]; }
}
public LookupParameter UpperVarianceParameter {
get { return (LookupParameter)Parameters["UpperVariance"]; }
}
public LookupParameter LowerVarianceParameter {
get { return (LookupParameter)Parameters["LowerVariance"]; }
}
#endregion
[StorableConstructor]
protected UpDownWalkAnalyzer(StorableConstructorFlag _) : base(_) { }
protected UpDownWalkAnalyzer(UpDownWalkAnalyzer original, Cloner cloner) : base(original, cloner) { }
public UpDownWalkAnalyzer() {
Parameters.Add(new LookupParameter("Quality Trail", "The qualities of the solutions"));
Parameters.Add(new LookupParameter("Results", "The collection of all results of this algorithm"));
Parameters.Add(new LookupParameter("DownWalkLength", "Average downward walk length."));
Parameters.Add(new LookupParameter("UpWalkLength", "Average updward walk length."));
Parameters.Add(new LookupParameter("UpWalkLenVar", "Upward walk length variance."));
Parameters.Add(new LookupParameter("DownWalkLenVar", "Downward walk length variance."));
Parameters.Add(new LookupParameter("LowerVariance", "Lower level variance."));
Parameters.Add(new LookupParameter("UpperVariance", "Upper level variance."));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new UpDownWalkAnalyzer(this, cloner);
}
public override IOperation Apply() {
var qualityTrail = QualityTrailParameter.ActualValue;
if (qualityTrail != null && qualityTrail.Rows.Count > 0) {
var qualities = qualityTrail.Rows.First().Values.ToList();
if (qualities.Count > 2) {
var results = ResultsParameter.ActualValue;
var extremes = qualities
.Delta((a, b) => new { a, b, diff = b - a })
.Select((p, i) => new { p.a, p.b, p.diff, i = i + 1 })
.Delta((s1, s2) => new {
s1.i,
value = s2.a,
top = s1.diff >= 0 && s2.diff < 0,
bottom = s1.diff <= 0 && s2.diff > 0
})
.Where(x => x.top || x.bottom)
.GroupConsecutive(x => x.bottom)
.Select(g => g.Count() == 1
? g.First()
: (g.First().bottom
? g.OrderBy(x => x.value).First()
: g.OrderByDescending(x => x.value).First())).ToList();
var maxima = extremes.Where(x => x.top).ToList();
var minima = extremes.Where(x => x.bottom).ToList();
var tops = Enumerable.Repeat(new { length = 0, value = 0.0 }, 0).ToList();
var bottoms = tops;
if (maxima.Count > 0 && minima.Count > 0) {
if (maxima.First().i < minima.First().i) {
bottoms = maxima.Zip(minima, (t, b) => new { length = b.i - t.i, b.value }).ToList();
minima.Insert(0, new { i = -1, value = 0.0, top = false, bottom = false });
tops = maxima.Zip(minima, (t, b) => new { length = t.i - b.i, t.value }).ToList();
} else {
tops = maxima.Zip(minima, (t, b) => new { length = t.i - b.i, t.value }).ToList();
maxima.Insert(0, new { i = -1, value = 0.0, top = false, bottom = false });
bottoms = maxima.Zip(minima, (t, b) => new { length = b.i - t.i, b.value }).ToList();
}
if (tops.Count > 0) {
var topLengths = tops.Select(t => (double)t.length).ToList();
var topVals = tops.Select(t => t.value).ToList();
var uv = new DoubleValue(topVals.Variance());
UpperVarianceParameter.ActualValue = uv;
AddOrUpdateResult(results, UpperVarianceParameter.Name, uv);
var ul = new DoubleValue(topLengths.Average());
UpWalkLengthParameter.ActualValue = ul;
AddOrUpdateResult(results, UpWalkLengthParameter.Name, ul);
var ulv = new DoubleValue(topLengths.Variance());
UpWalkLenVarParameter.ActualValue = ulv;
AddOrUpdateResult(results, UpWalkLenVarParameter.Name, ulv);
}
if (bottoms.Count > 0) {
var bottomLengths = bottoms.Select(b => (double)b.length).ToList();
var bottomVals = bottoms.Select(b => b.value).ToList();
var lv = new DoubleValue(bottomVals.Variance());
LowerVarianceParameter.ActualValue = lv;
AddOrUpdateResult(results, LowerVarianceParameter.Name, lv);
var dl = new DoubleValue(bottomLengths.Average());
DownWalkLengthParameter.ActualValue = dl;
AddOrUpdateResult(results, DownWalkLengthParameter.Name, dl);
var dlv = new DoubleValue(bottomLengths.Variance());
DownWalkLenVarParameter.ActualValue = dlv;
AddOrUpdateResult(results, DownWalkLenVarParameter.Name, dlv);
}
}
}
}
return base.Apply();
}
private static void AddOrUpdateResult(ResultCollection results, string name, IItem item, bool clone = false) {
IResult r;
if (!results.TryGetValue(name, out r)) {
results.Add(new Result(name, clone ? (IItem)item.Clone() : item));
} else r.Value = clone ? (IItem)item.Clone() : item;
}
}
}