#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.Operators;
using HeuristicLab.Optimization;
using HeuristicLab.Optimization.Operators;
using HeuristicLab.Parameters;
using HEAL.Attic;
using HeuristicLab.PluginInfrastructure;
namespace HeuristicLab.Encodings.RealVectorEncoding {
[Item("RealVectorSwarmUpdater", "Updates personal best point and quality as well as global best point and quality.")]
[StorableType("190172D5-090F-49DA-B2FB-AD2DF8064F77")]
[NonDiscoverableType]
[Obsolete("Use SPSOSwarmUpdater")]
internal sealed class RealVectorSwarmUpdater : 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 VelocityBoundsParameter {
get { return (ValueLookupParameter)Parameters["VelocityBounds"]; }
}
public ILookupParameter CurrentVelocityBoundsParameter {
get { return (ILookupParameter)Parameters["CurrentVelocityBounds"]; }
}
public LookupParameter ResultsParameter {
get { return (LookupParameter)Parameters["Results"]; }
}
#region Velocity Bounds Updating
public ILookupParameter VelocityBoundsScaleParameter {
get { return (ILookupParameter)Parameters["VelocityBoundsScale"]; }
}
public IConstrainedValueParameter VelocityBoundsScalingOperatorParameter {
get { return (IConstrainedValueParameter)Parameters["VelocityBoundsScalingOperator"]; }
}
public IValueLookupParameter VelocityBoundsStartValueParameter {
get { return (IValueLookupParameter)Parameters["VelocityBoundsStartValue"]; }
}
public IValueLookupParameter VelocityBoundsEndValueParameter {
get { return (IValueLookupParameter)Parameters["VelocityBoundsEndValue"]; }
}
public ILookupParameter VelocityBoundsIndexParameter {
get { return (ILookupParameter)Parameters["VelocityBoundsIndex"]; }
}
public IValueLookupParameter VelocityBoundsStartIndexParameter {
get { return (IValueLookupParameter)Parameters["VelocityBoundsStartIndex"]; }
}
public IValueLookupParameter VelocityBoundsEndIndexParameter {
get { return (IValueLookupParameter)Parameters["VelocityBoundsEndIndex"]; }
}
#endregion
#endregion
#region Parameter values
private DoubleValue SwarmBestQuality {
get { return SwarmBestQualityParameter.ActualValue; }
set { SwarmBestQualityParameter.ActualValue = value; }
}
private RealVector BestRealVector {
get { return BestRealVectorParameter.ActualValue; }
set { BestRealVectorParameter.ActualValue = value; }
}
private ItemArray Quality {
get { return QualityParameter.ActualValue; }
}
private ItemArray PersonalBestQuality {
get { return PersonalBestQualityParameter.ActualValue; }
set { PersonalBestQualityParameter.ActualValue = value; }
}
private ItemArray NeighborBestQuality {
get { return NeighborBestQualityParameter.ActualValue; }
set { NeighborBestQualityParameter.ActualValue = value; }
}
private ItemArray RealVector {
get { return RealVectorParameter.ActualValue; }
}
private ItemArray PersonalBest {
get { return PersonalBestParameter.ActualValue; }
set { PersonalBestParameter.ActualValue = value; }
}
private ItemArray NeighborBest {
get { return NeighborBestParameter.ActualValue; }
set { NeighborBestParameter.ActualValue = value; }
}
private bool Maximization {
get { return MaximizationParameter.ActualValue.Value; }
}
private ItemArray Neighbors {
get { return NeighborsParameter.ActualValue; }
}
private DoubleMatrix VelocityBounds {
get { return VelocityBoundsParameter.ActualValue; }
}
private DoubleMatrix CurrentVelocityBounds {
get { return CurrentVelocityBoundsParameter.ActualValue; }
set { CurrentVelocityBoundsParameter.ActualValue = value; }
}
private DoubleValue VelocityBoundsScale {
get { return VelocityBoundsScaleParameter.ActualValue; }
set { VelocityBoundsScaleParameter.ActualValue = value; }
}
private DoubleValue VelocityBoundsStartValue {
get { return VelocityBoundsStartValueParameter.ActualValue; }
}
public IDiscreteDoubleValueModifier VelocityBoundsScalingOperator {
get { return VelocityBoundsScalingOperatorParameter.Value; }
set { VelocityBoundsScalingOperatorParameter.Value = value; }
}
private ResultCollection Results {
get { return ResultsParameter.ActualValue; }
}
#endregion
#region Construction & Cloning
[StorableConstructor]
private RealVectorSwarmUpdater(StorableConstructorFlag _) : base(_) { }
private RealVectorSwarmUpdater(RealVectorSwarmUpdater original, Cloner cloner)
: base(original, cloner) {
ResultsCollector = cloner.Clone(original.ResultsCollector);
}
public RealVectorSwarmUpdater()
: 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("VelocityBounds", "Maximum velocity for each dimension.", new DoubleMatrix(new double[,] { { -1, 1 } })));
Parameters.Add(new LookupParameter("CurrentVelocityBounds", "Current value of velocity bounds."));
Parameters.Add(new LookupParameter("Results", "Results"));
#region Velocity Bounds Updating
Parameters.Add(new LookupParameter("VelocityBoundsScale", "Scale parameter."));
Parameters.Add(new OptionalConstrainedValueParameter("VelocityBoundsScalingOperator", "Modifies the value"));
Parameters.Add(new ValueLookupParameter("VelocityBoundsStartValue", "The start value of 'Value'.", new DoubleValue(1)));
Parameters.Add(new ValueLookupParameter("VelocityBoundsEndValue", "The end value of 'Value'.", new DoubleValue(1E-10)));
Parameters.Add(new LookupParameter("VelocityBoundsIndex", "The current index.", "Iterations"));
Parameters.Add(new ValueLookupParameter("VelocityBoundsStartIndex", "The start index at which to start modifying 'Value'.", new IntValue(0)));
Parameters.Add(new ValueLookupParameter("VelocityBoundsEndIndex", "The end index by which 'Value' should have reached 'EndValue'.", "MaxIterations"));
VelocityBoundsStartIndexParameter.Hidden = true;
VelocityBoundsEndIndexParameter.Hidden = true;
#endregion
Initialize();
RegisterEvents();
}
public override IDeepCloneable Clone(Cloner cloner) {
return new RealVectorSwarmUpdater(this, cloner);
}
#endregion
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
if (!Parameters.ContainsKey("SwarmBestQuality")) {
ILookupParameter oldBestQualityParameter = Parameters["BestQuality"] as ILookupParameter;
Parameters.Add(new LookupParameter("SwarmBestQuality", "Swarm's best quality."));
if (oldBestQualityParameter.ActualName != oldBestQualityParameter.Name)
SwarmBestQualityParameter.ActualName = oldBestQualityParameter.ActualName;
Parameters.Remove("BestQuality");
}
RegisterEvents();
}
private void RegisterEvents() {
VelocityBoundsStartValueParameter.ValueChanged += new EventHandler(VelocityBoundsStartValueParameter_ValueChanged);
VelocityBoundsStartValueParameter.Value.ValueChanged += new EventHandler(VelocityBoundsStartValueParameter_Value_ValueChanged);
}
void VelocityBoundsStartValueParameter_Value_ValueChanged(object sender, EventArgs e) {
UpdateVelocityBoundsParamater();
}
void UpdateVelocityBoundsParamater() {
if (VelocityBoundsParameter.Value == null) {
VelocityBoundsParameter.Value = new DoubleMatrix(1, 2);
} else if (VelocityBoundsParameter.Value.Columns != 2) {
VelocityBoundsParameter.Value = new DoubleMatrix(VelocityBoundsParameter.Value.Rows, 2);
}
if (VelocityBoundsStartValueParameter.Value != null) {
DoubleMatrix matrix = VelocityBoundsParameter.Value;
for (int i = 0; i < matrix.Rows; i++) {
matrix[i, 0] = (-1) * VelocityBoundsStartValueParameter.Value.Value;
matrix[i, 1] = VelocityBoundsStartValueParameter.Value.Value;
}
}
}
void VelocityBoundsStartValueParameter_ValueChanged(object sender, EventArgs e) {
if (VelocityBoundsStartValueParameter.Value != null) {
VelocityBoundsStartValueParameter.Value.ValueChanged += new EventHandler(VelocityBoundsStartValueParameter_Value_ValueChanged);
}
UpdateVelocityBoundsParamater();
}
private void Initialize() {
ResultsCollector = new ResultsCollector();
ResultsCollector.CollectedValues.Add(CurrentVelocityBoundsParameter);
ResultsCollector.CollectedValues.Add(VelocityBoundsParameter);
foreach (IDiscreteDoubleValueModifier op in ApplicationManager.Manager.GetInstances()) {
VelocityBoundsScalingOperatorParameter.ValidValues.Add(op);
op.ValueParameter.ActualName = VelocityBoundsScaleParameter.Name;
op.StartValueParameter.ActualName = VelocityBoundsStartValueParameter.Name;
op.EndValueParameter.ActualName = VelocityBoundsEndValueParameter.Name;
op.IndexParameter.ActualName = VelocityBoundsIndexParameter.Name;
op.StartIndexParameter.ActualName = VelocityBoundsStartIndexParameter.Name;
op.EndIndexParameter.ActualName = VelocityBoundsEndIndexParameter.Name;
}
VelocityBoundsScalingOperatorParameter.Value = null;
}
public override IOperation Apply() {
UpdateGlobalBest();
UpdateNeighborBest();
UpdatePersonalBest();
return UpdateVelocityBounds();
}
private void UpdateGlobalBest() {
if (SwarmBestQuality == null)
SwarmBestQuality = new DoubleValue();
SwarmBestQuality.Value = Maximization ? Quality.Max(v => v.Value) : Quality.Min(v => v.Value);
BestRealVector = (RealVector)RealVector[Quality.FindIndex(v => v.Value == SwarmBestQuality.Value)].Clone();
}
private void UpdateNeighborBest() {
if (Neighbors.Length > 0) {
var neighborBest = new ItemArray(Neighbors.Length);
var neighborBestQuality = new ItemArray(Neighbors.Length);
for (int n = 0; n < Neighbors.Length; n++) {
var pairs = Quality.Zip(RealVector, (q, p) => new { Quality = q, Point = p })
.Where((p, i) => i == n || Neighbors[n].Contains(i));
var bestNeighbor = Maximization ?
pairs.OrderByDescending(p => p.Quality.Value).First() :
pairs.OrderBy(p => p.Quality.Value).First();
neighborBest[n] = bestNeighbor.Point;
neighborBestQuality[n] = bestNeighbor.Quality;
}
NeighborBest = neighborBest;
NeighborBestQuality = neighborBestQuality;
}
}
private void UpdatePersonalBest() {
if (PersonalBestQuality.Length == 0)
PersonalBestQuality = (ItemArray)Quality.Clone();
for (int i = 0; i < RealVector.Length; i++) {
if (Maximization && Quality[i].Value > PersonalBestQuality[i].Value ||
!Maximization && Quality[i].Value < PersonalBestQuality[i].Value) {
PersonalBestQuality[i].Value = Quality[i].Value;
PersonalBest[i] = RealVector[i];
}
}
}
private IOperation UpdateVelocityBounds() {
if (CurrentVelocityBounds == null)
CurrentVelocityBounds = (DoubleMatrix)VelocityBounds.Clone();
if (VelocityBoundsScalingOperator == null)
return new OperationCollection() {
ExecutionContext.CreateChildOperation(ResultsCollector),
base.Apply()
};
DoubleMatrix matrix = CurrentVelocityBounds;
if (VelocityBoundsScale == null && VelocityBoundsStartValue != null) {
VelocityBoundsScale = new DoubleValue(VelocityBoundsStartValue.Value);
}
for (int i = 0; i < matrix.Rows; i++) {
for (int j = 0; j < matrix.Columns; j++) {
if (matrix[i, j] >= 0) {
matrix[i, j] = VelocityBoundsScale.Value;
} else {
matrix[i, j] = (-1) * VelocityBoundsScale.Value;
}
}
}
return new OperationCollection() {
ExecutionContext.CreateChildOperation(ResultsCollector),
ExecutionContext.CreateChildOperation(VelocityBoundsScalingOperator),
base.Apply()
};
}
}
}