#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; } } }