using System.Collections.Generic; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Selection; namespace HeuristicLab.Analysis.FitnessLandscape { [Item("BestOrWorstSelector", "A selection operator that moves towards the next local optimum, when found reverses direction and so on.")] [StorableClass] public class BestWorstSelector : SingleObjectiveSelector, ISingleObjectiveSelector { #region Parameters public ScopePathLookupParameter MoveTowardsOptimumParameter { get { return (ScopePathLookupParameter)Parameters["MoveTowardsOptimum"]; } } public ScopePathLookupParameter BaseQualityParameter { get { return (ScopePathLookupParameter)Parameters["BaseQuality"]; } } public LookupParameter RandomParameter { get { return (LookupParameter)Parameters["Random"]; } } #endregion #region Construction & Cloning [StorableConstructor] protected BestWorstSelector(bool deserializing) : base(deserializing) { } protected BestWorstSelector(BestWorstSelector original, Cloner cloner) : base(original, cloner) { } public BestWorstSelector() { Parameters.Add(new ScopePathLookupParameter("MoveTowardsOptimum", "Specifies whether the selector should optimize towards or away from the optimum.")); Parameters.Add(new ScopePathLookupParameter("BaseQuality", "The base quality value to compare to. This is required to determine wheter a local optimum has been found and the direction should be reversed.")); Parameters.Add(new LookupParameter("Random", "Random number generator")); MoveTowardsOptimumParameter.Hidden = false; BaseQualityParameter.Hidden = false; MoveTowardsOptimumParameter.Path = ".."; BaseQualityParameter.Path = "../Remaining/{0}"; BaseQualityParameter.ActualName = "Quality"; QualityParameter.Hidden = false; MaximizationParameter.Hidden = true; NumberOfSelectedSubScopesParameter.Value = new IntValue(1); NumberOfSelectedSubScopesParameter.Hidden = true; } public override IDeepCloneable Clone(Cloner cloner) { return new BestWorstSelector(this, cloner); } #endregion protected override IScope[] Select(List scopes) { bool optimize = true; if (MoveTowardsOptimumParameter.ActualValue == null) { MoveTowardsOptimumParameter.ActualValue = new BoolValue(true); } else { optimize = MoveTowardsOptimumParameter.ActualValue.Value; } double baseQuality = BaseQualityParameter.ActualValue.Value; int count = NumberOfSelectedSubScopesParameter.ActualValue.Value; bool copy = CopySelectedParameter.Value.Value; bool maximization = MaximizationParameter.ActualValue.Value; ItemArray qualities = QualityParameter.ActualValue; IScope[] selected = new IScope[count]; IRandom random = RandomParameter.ActualValue; var list = qualities.Select((x, i) => new { Index=i, Quality=x.Value }).ToList(); if (random != null) list.Shuffle(random); if (maximization && optimize || !maximization && !optimize) { list = list.OrderByDescending(x => x.Quality).ToList(); if (list.Count > 0 && list[0].Quality <= baseQuality) MoveTowardsOptimumParameter.ActualValue = new BoolValue(!optimize); } else { list = list.OrderBy(x => x.Quality).ToList(); if (list.Count > 0 && list[0].Quality >= baseQuality) MoveTowardsOptimumParameter.ActualValue = new BoolValue(!optimize); } if (copy) { int j = 0; for (int i = 0; i < count; i++) { selected[i] = (IScope)scopes[list[j].Index].Clone(); j++; if (j >= list.Count) j = 0; } } else { for (int i = 0; i < count; i++) { selected[i] = scopes[list[0].Index]; scopes[list[0].Index] = null; list.RemoveAt(0); } scopes.RemoveAll(x => x == null); } return selected; } } }