#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.Collections.Generic; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Optimization.Operators; using HeuristicLab.Parameters; using HEAL.Attic; using HeuristicLab.PluginInfrastructure; namespace HeuristicLab.Encodings.RealVectorEncoding { [Item("Swarm Updater (SPSO)", "Updates personal best point and quality as well as neighbor best point and quality.")] [StorableType("B8244196-9DB9-477C-A0A1-C1EB5BF4E1C1")] public sealed class SPSOSwarmUpdater : SingleSuccessorOperator, IRealVectorSwarmUpdater, ISingleObjectiveOperator { [Storable] private ResultsCollector ResultsCollector; public override bool CanChangeName { get { return false; } } #region Parameter properties public IScopeTreeLookupParameter QualityParameter { get { return (IScopeTreeLookupParameter)Parameters["Quality"]; } } public IScopeTreeLookupParameter PersonalBestQualityParameter { get { return (IScopeTreeLookupParameter)Parameters["PersonalBestQuality"]; } } public IScopeTreeLookupParameter NeighborBestQualityParameter { get { return (IScopeTreeLookupParameter)Parameters["NeighborBestQuality"]; } } public IScopeTreeLookupParameter RealVectorParameter { get { return (IScopeTreeLookupParameter)Parameters["RealVector"]; } } public IScopeTreeLookupParameter PersonalBestParameter { get { return (IScopeTreeLookupParameter)Parameters["PersonalBest"]; } } public IScopeTreeLookupParameter NeighborBestParameter { get { return (IScopeTreeLookupParameter)Parameters["NeighborBest"]; } } public ILookupParameter MaximizationParameter { get { return (ILookupParameter)Parameters["Maximization"]; } } public ILookupParameter SwarmBestQualityParameter { get { return (ILookupParameter)Parameters["SwarmBestQuality"]; } } public ILookupParameter BestRealVectorParameter { get { return (ILookupParameter)Parameters["BestRealVector"]; } } public IScopeTreeLookupParameter NeighborsParameter { get { return (IScopeTreeLookupParameter)Parameters["Neighbors"]; } } public IValueLookupParameter MaxVelocityParameter { get { return (ValueLookupParameter)Parameters["MaxVelocity"]; } } public ILookupParameter CurrentMaxVelocityParameter { get { return (ILookupParameter)Parameters["CurrentMaxVelocity"]; } } public LookupParameter ResultsParameter { get { return (LookupParameter)Parameters["Results"]; } } #region Max Velocity Updating public IConstrainedValueParameter MaxVelocityScalingOperatorParameter { get { return (IConstrainedValueParameter)Parameters["MaxVelocityScalingOperator"]; } } public IValueLookupParameter FinalMaxVelocityParameter { get { return (IValueLookupParameter)Parameters["FinalMaxVelocity"]; } } public ILookupParameter MaxVelocityIndexParameter { get { return (ILookupParameter)Parameters["MaxVelocityIndex"]; } } public IValueLookupParameter MaxVelocityStartIndexParameter { get { return (IValueLookupParameter)Parameters["MaxVelocityStartIndex"]; } } public IValueLookupParameter MaxVelocityEndIndexParameter { get { return (IValueLookupParameter)Parameters["MaxVelocityEndIndex"]; } } #endregion #endregion #region Construction & Cloning [StorableConstructor] private SPSOSwarmUpdater(StorableConstructorFlag _) : base(_) { } private SPSOSwarmUpdater(SPSOSwarmUpdater original, Cloner cloner) : base(original, cloner) { ResultsCollector = cloner.Clone(original.ResultsCollector); } public SPSOSwarmUpdater() : base() { Parameters.Add(new LookupParameter("SwarmBestQuality", "Swarm's best quality.")); Parameters.Add(new LookupParameter("BestRealVector", "Global best particle position.")); Parameters.Add(new ScopeTreeLookupParameter("Quality", "Particles' qualities.")); Parameters.Add(new ScopeTreeLookupParameter("PersonalBestQuality", "Particles' personal best qualities.")); Parameters.Add(new ScopeTreeLookupParameter("NeighborBestQuality", "Best neighbor particles' qualities.")); Parameters.Add(new ScopeTreeLookupParameter("RealVector", "Particles' positions.")); Parameters.Add(new ScopeTreeLookupParameter("PersonalBest", "Particles' personal best positions.")); Parameters.Add(new ScopeTreeLookupParameter("NeighborBest", "Neighborhood (or global in case of totally connected neighborhood) best particle positions.")); Parameters.Add(new ScopeTreeLookupParameter("Neighbors", "The list of neighbors for each particle.")); Parameters.Add(new LookupParameter("Maximization", "True if the problem is a maximization problem, otherwise false.")); Parameters.Add(new ValueLookupParameter("MaxVelocity", "The maximum velocity for each particle and initial velocity if scaling is used.", new DoubleValue(double.MaxValue))); Parameters.Add(new LookupParameter("CurrentMaxVelocity", "Current value of the speed limit.")); Parameters.Add(new LookupParameter("Results", "Results")); #region Max Velocity Updating Parameters.Add(new OptionalConstrainedValueParameter("MaxVelocityScalingOperator", "Modifies the value")); Parameters.Add(new ValueLookupParameter("FinalMaxVelocity", "The value of maximum velocity if scaling is used and PSO has reached maximum iterations.", new DoubleValue(1E-10))); Parameters.Add(new LookupParameter("MaxVelocityIndex", "The current index.", "Iterations")); Parameters.Add(new ValueLookupParameter("MaxVelocityStartIndex", "The start index at which to start modifying 'Value'.", new IntValue(0))); Parameters.Add(new ValueLookupParameter("MaxVelocityEndIndex", "The end index by which 'Value' should have reached 'EndValue'.", "MaxIterations")); MaxVelocityStartIndexParameter.Hidden = true; MaxVelocityEndIndexParameter.Hidden = true; #endregion Initialize(); } public override IDeepCloneable Clone(Cloner cloner) { return new SPSOSwarmUpdater(this, cloner); } #endregion private void Initialize() { ResultsCollector = new ResultsCollector(); ResultsCollector.CollectedValues.Add(CurrentMaxVelocityParameter); ResultsCollector.CollectedValues.Add(MaxVelocityParameter); foreach (IDiscreteDoubleValueModifier op in ApplicationManager.Manager.GetInstances()) { MaxVelocityScalingOperatorParameter.ValidValues.Add(op); op.ValueParameter.ActualName = CurrentMaxVelocityParameter.Name; op.StartValueParameter.ActualName = MaxVelocityParameter.Name; op.EndValueParameter.ActualName = FinalMaxVelocityParameter.Name; op.IndexParameter.ActualName = MaxVelocityIndexParameter.Name; op.StartIndexParameter.ActualName = MaxVelocityStartIndexParameter.Name; op.EndIndexParameter.ActualName = MaxVelocityEndIndexParameter.Name; } MaxVelocityScalingOperatorParameter.Value = null; } public override IOperation Apply() { var max = MaximizationParameter.ActualValue.Value; // Update of the personal bests var points = RealVectorParameter.ActualValue; var qualities = QualityParameter.ActualValue; var particles = points.Select((p, i) => new { Particle = p, Index = i }) .Zip(qualities, (p, q) => Tuple.Create(p.Index, p.Particle, q.Value)).ToList(); UpdatePersonalBest(max, particles); // SPSO: update of the neighbor bests from the personal bests var personalBestPoints = PersonalBestParameter.ActualValue; var personalBestQualities = PersonalBestQualityParameter.ActualValue; particles = personalBestPoints.Select((p, i) => new { Particle = p, Index = i }) .Zip(personalBestQualities, (p, q) => Tuple.Create(p.Index, p.Particle, q.Value)).ToList(); UpdateNeighborBest(max, particles); var next = new OperationCollection() { base.Apply() }; next.Insert(0, ExecutionContext.CreateChildOperation(ResultsCollector)); if (MaxVelocityScalingOperatorParameter.Value != null) { next.Insert(0, ExecutionContext.CreateChildOperation(MaxVelocityScalingOperatorParameter.Value)); } else CurrentMaxVelocityParameter.ActualValue = new DoubleValue(MaxVelocityParameter.ActualValue.Value); return next; } private void UpdateNeighborBest(bool maximization, IList> particles) { var neighbors = NeighborsParameter.ActualValue; if (neighbors.Length > 0) { var neighborBest = new ItemArray(neighbors.Length); var neighborBestQuality = new ItemArray(neighbors.Length); double overallBest = double.NaN; RealVector overallBestVector = null; for (int n = 0; n < neighbors.Length; n++) { var neighborhood = particles.Where(x => neighbors[n].Contains(x.Item1)); var bestNeighbor = (maximization ? neighborhood.MaxItems(p => p.Item3) : neighborhood.MinItems(p => p.Item3)).First(); neighborBest[n] = bestNeighbor.Item2; neighborBestQuality[n] = new DoubleValue(bestNeighbor.Item3); if (double.IsNaN(overallBest) || maximization && bestNeighbor.Item3 > overallBest || !maximization && bestNeighbor.Item3 < overallBest) { overallBest = bestNeighbor.Item3; overallBestVector = bestNeighbor.Item2; } } NeighborBestParameter.ActualValue = neighborBest; NeighborBestQualityParameter.ActualValue = neighborBestQuality; SwarmBestQualityParameter.ActualValue = new DoubleValue(overallBest); BestRealVectorParameter.ActualValue = overallBestVector; } else { // Neighbor best = Global best var best = maximization ? particles.MaxItems(x => x.Item3).First() : particles.MinItems(x => x.Item3).First(); NeighborBestParameter.ActualValue = new ItemArray(Enumerable.Repeat(best.Item2, particles.Count)); NeighborBestQualityParameter.ActualValue = new ItemArray(Enumerable.Repeat(new DoubleValue(best.Item3), particles.Count)); SwarmBestQualityParameter.ActualValue = new DoubleValue(best.Item3); BestRealVectorParameter.ActualValue = best.Item2; } } private void UpdatePersonalBest(bool maximization, IList> particles) { var personalBest = PersonalBestParameter.ActualValue; var personalBestQuality = PersonalBestQualityParameter.ActualValue; if (personalBestQuality.Length == 0) { personalBestQuality = new ItemArray(particles.Select(x => new DoubleValue(x.Item3))); PersonalBestQualityParameter.ActualValue = personalBestQuality; } foreach (var p in particles) { if (maximization && p.Item3 > personalBestQuality[p.Item1].Value || !maximization && p.Item3 < personalBestQuality[p.Item1].Value) { personalBestQuality[p.Item1].Value = p.Item3; personalBest[p.Item1] = new RealVector(p.Item2); } } PersonalBestParameter.ActualValue = personalBest; } } }