#region License Information
/* HeuristicLab
* Copyright (C) 2002-2019 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.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;
using HeuristicLab.Random;
namespace HeuristicLab.Problems.MovingPeaksBenchmark {
[Item("MovingPeaksBenchmarkProblemEvaluator", "Evaluation operator for the Moving Peaks Benchmark.")]
[StorableClass]
public class MovingPeaksBenchmarkProblemEvaluator : InstrumentedOperator, IMovingPeaksBenchmarkProblemEvaluator {
[Storable]
IRandom uniformRandom;
[Storable]
long executions;
[Storable]
double currentBest;
[Storable]
double offlineErrorSum;
#region Parameters
public ILookupParameter BoundsParameter {
get { return (ILookupParameter)Parameters["Bounds"]; }
}
public IValueLookupParameter PeakLocationsParameter {
get { return (IValueLookupParameter)Parameters["PeakLocations"]; }
}
public IValueLookupParameter PeakWidthsParameter {
get { return (IValueLookupParameter)Parameters["PeakWidths"]; }
}
public IValueLookupParameter PeakHeightsParameter {
get { return (IValueLookupParameter)Parameters["PeakHeights"]; }
}
public ILookupParameter MovingPeaksRandomSeedParameter {
get { return (ILookupParameter)Parameters["MovingPeaksRandomSeed"]; }
}
public ILookupParameter MinPeakWidthParameter {
get { return (ILookupParameter)Parameters["MinPeakWidth"]; }
}
public ILookupParameter MaxPeakWidthParameter {
get { return (ILookupParameter)Parameters["MaxPeakWidth"]; }
}
public ILookupParameter MinPeakHeightParameter {
get { return (ILookupParameter)Parameters["MinPeakHeight"]; }
}
public ILookupParameter MaxPeakHeightParameter {
get { return (ILookupParameter)Parameters["MaxPeakHeight"]; }
}
public ILookupParameter PeakMovementIntervalParameter {
get { return (ILookupParameter)Parameters["PeakMovementInterval"]; }
}
public ILookupParameter PeakMovementStrengthParameter {
get { return (ILookupParameter)Parameters["PeakMovementStrength"]; }
}
public ILookupParameter PointParameter {
get { return (ILookupParameter)Parameters["Point"]; }
}
public ILookupParameter QualityParameter {
get { return (ILookupParameter)Parameters["Quality"]; }
}
public ILookupParameter BestKnownQualityParameter {
get { return (ILookupParameter)Parameters["BestKnownQuality"]; }
}
public ILookupParameter BestKnownSolutionParameter {
get { return (ILookupParameter)Parameters["BestKnownSolution"]; }
}
public IValueLookupParameter ResultsParameter {
get { return (IValueLookupParameter)Parameters["Results"]; }
}
#endregion
[StorableConstructor]
protected MovingPeaksBenchmarkProblemEvaluator(bool deserializing) : base(deserializing) { }
protected MovingPeaksBenchmarkProblemEvaluator(MovingPeaksBenchmarkProblemEvaluator original, Cloner cloner) : base(original, cloner) { }
public MovingPeaksBenchmarkProblemEvaluator() : base() {
Parameters.Add(new LookupParameter("Bounds", "The lower and upper bounds in each dimension."));
Parameters.Add(new ValueLookupParameter("PeakLocations", "Current position of the peaks."));
PeakLocationsParameter.ActualName = "InitialPeakLocations";
Parameters.Add(new ValueLookupParameter("PeakWidths", "Current width of the peaks."));
PeakWidthsParameter.ActualName = "InitialPeakWidths";
Parameters.Add(new ValueLookupParameter("PeakHeights", "Current height of the peaks."));
PeakHeightsParameter.ActualName = "InitialPeakHeights";
Parameters.Add(new LookupParameter("MovingPeaksRandomSeed", "The random seed for initializing the PRNG for changing the peaks."));
Parameters.Add(new LookupParameter("MinPeakWidth", "The minimum width of each peak."));
Parameters.Add(new LookupParameter("MaxPeakWidth", "The maximum width of each peak."));
Parameters.Add(new LookupParameter("MinPeakHeight", "The minimum height of each peak."));
Parameters.Add(new LookupParameter("MaxPeakHeight", "The maximum height of each peak."));
Parameters.Add(new LookupParameter("PeakMovementInterval", "The interval in evaluated solutions in which peaks are moved."));
Parameters.Add(new LookupParameter("PeakMovementStrength", "The length of the random vector used for changing peak locations."));
Parameters.Add(new LookupParameter("Point", "The point which should be evaluated."));
Parameters.Add(new LookupParameter("Quality", "Quality value of the evaluated point."));
Parameters.Add(new LookupParameter("BestKnownQuality", "Quality value of the highest peak."));
Parameters.Add(new LookupParameter("BestKnownSolution", "The location of the highest peak."));
Parameters.Add(new ValueLookupParameter("Results", "The result collection for storing result values."));
PeakLocationsParameter.Hidden = true;
PeakWidthsParameter.Hidden = true;
PeakHeightsParameter.Hidden = true;
MovingPeaksRandomSeedParameter.Hidden = true;
MinPeakWidthParameter.Hidden = true;
MaxPeakWidthParameter.Hidden = true;
MinPeakHeightParameter.Hidden = true;
MaxPeakHeightParameter.Hidden = true;
PeakMovementIntervalParameter.Hidden = true;
PeakMovementStrengthParameter.Hidden = true;
BestKnownQualityParameter.Hidden = true;
BestKnownSolutionParameter.Hidden = true;
ResultsParameter.Hidden = true;
}
public override IDeepCloneable Clone(Cloner cloner) {
return new MovingPeaksBenchmarkProblemEvaluator(this, cloner);
}
public override IOperation InstrumentedApply() {
lock (this) {
if (uniformRandom == null) {
uniformRandom = new MersenneTwister();
uniformRandom.Reset(MovingPeaksRandomSeedParameter.ActualValue.Value);
}
}
DoubleMatrix peaks = PeakLocationsParameter.ActualValue;
DoubleArray widths = PeakWidthsParameter.ActualValue;
DoubleArray heights = PeakHeightsParameter.ActualValue;
if (PeakLocationsParameter.Value == null) {
peaks = peaks.Clone() as DoubleMatrix;
widths = widths.Clone() as DoubleArray;
heights = heights.Clone() as DoubleArray;
PeakLocationsParameter.Value = peaks;
PeakWidthsParameter.Value = widths;
PeakHeightsParameter.Value = heights;
ResultCollection results = ResultsParameter.ActualValue;
results.Add(new Result("Current Peak Locations", peaks));
results.Add(new Result("Current Peak Widths", widths));
results.Add(new Result("Current Peak Heights", heights));
for (int i = 0; i < widths.Length; i++) {
if (widths[i] < 0) {
widths[i] = MinPeakWidthParameter.ActualValue.Value + uniformRandom.NextDouble() * (MaxPeakWidthParameter.ActualValue.Value - MinPeakWidthParameter.ActualValue.Value);
}
if (heights[i] < 0) {
heights[i] = MinPeakHeightParameter.ActualValue.Value + uniformRandom.NextDouble() * (MaxPeakHeightParameter.ActualValue.Value - MinPeakHeightParameter.ActualValue.Value);
}
}
}
lock (this) {
// move peaks if peaks movement interval is reached
if ((executions % PeakMovementIntervalParameter.ActualValue.Value) == 0) {
MovePeaks(uniformRandom, peaks, widths, heights,
PeakMovementStrengthParameter.ActualValue.Value,
MinPeakWidthParameter.ActualValue.Value, MaxPeakWidthParameter.ActualValue.Value,
MinPeakHeightParameter.ActualValue.Value, MaxPeakHeightParameter.ActualValue.Value,
BoundsParameter.ActualValue[0, 0], BoundsParameter.ActualValue[0, 1]);
// update best known solution & quality according to highest peak
double maxHeight = heights.Max();
int peakIndex = Array.IndexOf(heights.CloneAsArray(), maxHeight);
double[] peak = new double[peaks.Columns];
for (int i = 0; i < peak.Length; i++) {
peak[i] = peaks[peakIndex, i];
}
BestKnownSolutionParameter.ActualValue = new RealVector(peak);
BestKnownQualityParameter.ActualValue.Value = heights.Max();
currentBest = -1;
}
executions++;
}
RealVector point = PointParameter.ActualValue;
double quality = Apply(peaks, widths, heights, point);
QualityParameter.ActualValue = new DoubleValue(quality);
lock (this) {
if (quality > currentBest) {
currentBest = quality;
}
offlineErrorSum += heights.Max() - currentBest;
ResultCollection results = ResultsParameter.ActualValue;
IResult offlineError;
if (results.TryGetValue("Offline Error", out offlineError)) {
(offlineError.Value as DoubleValue).Value = offlineErrorSum / executions;
} else {
results.Add(new Result("Offline Error", new DoubleValue(offlineErrorSum / executions)));
}
}
return base.InstrumentedApply();
}
public override void InitializeState() {
base.InitializeState();
executions = 0;
currentBest = -1;
offlineErrorSum = 0;
}
public override void ClearState() {
base.ClearState();
uniformRandom = null;
PeakLocationsParameter.Value = null;
PeakWidthsParameter.Value = null;
PeakHeightsParameter.Value = null;
}
public double Apply(DoubleMatrix peaks, DoubleArray widths, DoubleArray heights, RealVector point) {
double max = 0;
double val = 0;
for (int i = 0; i < widths.Length; i++) {
val = 0;
for (int j = 0; j < point.Length; j++) {
val += (point[j] - peaks[i, j]) * (point[j] - peaks[i, j]);
}
val = heights[i] / (1 + widths[i] * val);
if (val > max) max = val;
}
return max;
}
private void MovePeaks(IRandom uniformRandom, DoubleMatrix peaks, DoubleArray widths, DoubleArray heights, double strength,
double minWidth, double maxWidth, double minHeight, double maxHeight, double minLocation, double maxLocation) {
IRandom normalRandom = new NormalDistributedRandom(uniformRandom, 0, 1);
for (int i = 0; i < peaks.Rows; i++) {
double[] v = RandomVector(uniformRandom, peaks.Columns, strength);
for (int j = 0; j < v.Length; j++) {
peaks[i, j] += v[j];
if (peaks[i, j] < minLocation) peaks[i, j] = minLocation;
if (peaks[i, j] > maxLocation) peaks[i, j] = maxLocation;
}
widths[i] = NewRandomValue(normalRandom, widths[i], 1.0, minWidth, maxWidth);
heights[i] = NewRandomValue(normalRandom, heights[i], 7, minHeight, maxHeight);
}
}
private double[] RandomVector(IRandom uniformRandom, int dimensions, double length) {
double[] vector = new double[dimensions];
for (int i = 0; i < vector.Length; i++) {
vector[i] = uniformRandom.NextDouble() - 0.5;
}
double factor = length / Math.Sqrt(vector.Select(x => x * x).Sum());
for (int i = 0; i < vector.Length; i++) {
vector[i] *= factor;
}
return vector;
}
private double NewRandomValue(IRandom normalRandom, double value, double factor, double min, double max) {
double r, newValue;
do {
r = normalRandom.NextDouble();
newValue = value + factor * r;
} while ((newValue < min) || (newValue > max));
return newValue;
}
}
}