#region License Information
/* HeuristicLab
* Copyright (C) 2002-2014 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.Analysis;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Operators;
using HeuristicLab.Optimization;
using HeuristicLab.Optimization.Operators;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.PluginInfrastructure;
namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm {
[Item("PopulationQualityComparator", "Compares the quality of the child to the population.")]
[StorableClass]
public class PopulationQualityComparator : SingleSuccessorOperator, ISubScopesQualityComparatorOperator, ISimilarityBasedOperator {
[Storable]
public ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
public IValueLookupParameter MaximizationParameter {
get { return (IValueLookupParameter)Parameters["Maximization"]; }
}
public ILookupParameter LeftSideParameter {
get { return (ILookupParameter)Parameters["LeftSide"]; }
}
public ILookupParameter> RightSideParameter {
get { return (ILookupParameter>)Parameters["RightSide"]; }
}
public ILookupParameter ResultParameter {
get { return (ILookupParameter)Parameters["Result"]; }
}
public ValueLookupParameter ComparisonFactorParameter {
get { return (ValueLookupParameter)Parameters["ComparisonFactor"]; }
}
public ValueLookupParameter DiversityComparisonFactorParameter {
get { return (ValueLookupParameter)Parameters["DiversityComparisonFactor"]; }
}
private ValueLookupParameter ComparisonFactorLowerBoundParameter {
get { return (ValueLookupParameter)Parameters["DiversityComparisonFactorLowerBound"]; }
}
private ValueLookupParameter ComparisonFactorUpperBoundParameter {
get { return (ValueLookupParameter)Parameters["DiversityComparisonFactorUpperBound"]; }
}
public IConstrainedValueParameter ComparisonFactorModifierParameter {
get { return (IConstrainedValueParameter)Parameters["ComparisonFactorModifier"]; }
}
public ValueLookupParameter ResultsParameter {
get { return (ValueLookupParameter)Parameters["Results"]; }
}
public ILookupParameter GenerationsParameter {
get { return (LookupParameter)Parameters["Generations"]; }
}
public ValueParameter EnableDivCriteriaParameter {
get { return (ValueParameter)Parameters["EnableDivCriteria"]; }
}
private const string spDetailsParameterName = "SPDetails";
private const string divDataRowName = "DiversitySuccessCount";
private const string qualityDataRowName = "QualitySuccessCount";
private const string divFailDataRowName = "DiversityFailCount";
private const string qualityFailDataRowName = "QualityFailCount";
private const string overallCountDataRowName = "OverallCount";
private const string successCountDataRowName = "SuccessCount";
[Storable]
private int currentGeneration;
[Storable]
private int divCount;
[Storable]
private int qualityCount;
[Storable]
private int badQualityCount;
[Storable]
private int badDivCount;
[Storable]
private int overallCount;
[Storable]
private int successCount;
[StorableConstructor]
protected PopulationQualityComparator(bool deserializing) : base(deserializing) { }
protected PopulationQualityComparator(PopulationQualityComparator original, Cloner cloner)
: base(original, cloner) {
SimilarityCalculator = cloner.Clone(original.SimilarityCalculator);
currentGeneration = original.currentGeneration;
divCount = original.divCount;
qualityCount = original.qualityCount;
overallCount = original.overallCount;
successCount = original.successCount;
badDivCount = original.badDivCount;
badQualityCount = original.badQualityCount;
}
public PopulationQualityComparator()
: base() {
Parameters.Add(new ValueLookupParameter("Maximization", "True if the problem is a maximization problem, false otherwise"));
Parameters.Add(new LookupParameter("LeftSide", "The quality of the child."));
Parameters.Add(new ScopeTreeLookupParameter("RightSide", "The qualities of the parents."));
Parameters.Add(new LookupParameter("Result", "The result of the comparison: True means Quality is better, False means it is worse than parents."));
Parameters.Add(new ValueLookupParameter("ComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them."));
Parameters.Add(new ValueLookupParameter("DiversityComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them.", new DoubleValue(0.0)));
Parameters.Add(new ValueLookupParameter("DiversityComparisonFactorLowerBound", "The lower bound of the comparison factor (start).", new DoubleValue(0.5)));
Parameters.Add(new ValueLookupParameter("DiversityComparisonFactorUpperBound", "The upper bound of the comparison factor (end).", new DoubleValue(1.0)));
Parameters.Add(new OptionalConstrainedValueParameter("ComparisonFactorModifier", "The operator used to modify the comparison factor.", new ItemSet(new IDiscreteDoubleValueModifier[] { new LinearDiscreteDoubleValueModifier() }), new LinearDiscreteDoubleValueModifier()));
Parameters.Add(new ValueLookupParameter("Results", "The result collection where the population diversity analysis results should be stored."));
Parameters.Add(new LookupParameter("Generations", "The current number of generations."));
Parameters.Add(new ValueParameter("EnableDivCriteria", "Use diversity as additional offspring selection criteria.", new BoolValue(false)));
foreach (IDiscreteDoubleValueModifier modifier in ApplicationManager.Manager.GetInstances().OrderBy(x => x.Name))
ComparisonFactorModifierParameter.ValidValues.Add(modifier);
IDiscreteDoubleValueModifier linearModifier = ComparisonFactorModifierParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("LinearDiscreteDoubleValueModifier"));
if (linearModifier != null) ComparisonFactorModifierParameter.Value = linearModifier;
ParameterizeComparisonFactorModifiers();
}
public override IDeepCloneable Clone(Cloner cloner) {
return new PopulationQualityComparator(this, cloner);
}
private void ParameterizeComparisonFactorModifiers() {
//TODO: does not work if Generations parameter names are changed
foreach (IDiscreteDoubleValueModifier modifier in ComparisonFactorModifierParameter.ValidValues) {
modifier.IndexParameter.ActualName = "Generations";
modifier.EndIndexParameter.ActualName = "MaximumGenerations";
modifier.EndValueParameter.ActualName = ComparisonFactorUpperBoundParameter.Name;
modifier.StartIndexParameter.Value = new IntValue(0);
modifier.StartValueParameter.ActualName = ComparisonFactorLowerBoundParameter.Name;
modifier.ValueParameter.ActualName = "DiversityComparisonFactor";
}
}
private IScope GetRemainingScope() {
var scope = ExecutionContext.Scope;
while (scope != null) {
if (scope.SubScopes.Any(x => x.Name == "Remaining")) {
return scope.SubScopes.Single(x => x.Name == "Remaining");
}
scope = scope.Parent;
}
return null;
}
public override IOperation Apply() {
double compFact = ComparisonFactorParameter.ActualValue.Value;
double diversityComFact = DiversityComparisonFactorParameter.ActualValue.Value;
bool maximization = MaximizationParameter.ActualValue.Value;
double leftQuality = LeftSideParameter.ActualValue.Value;
bool resultDiversity;
DataTable spDetailsTable;
if (ResultsParameter.ActualValue.ContainsKey(spDetailsParameterName)) {
spDetailsTable = (DataTable)ResultsParameter.ActualValue[spDetailsParameterName].Value;
} else {
spDetailsTable = new DataTable(spDetailsParameterName);
spDetailsTable.Rows.Add(new DataRow(divDataRowName));
spDetailsTable.Rows.Add(new DataRow(qualityDataRowName));
spDetailsTable.Rows.Add(new DataRow(overallCountDataRowName));
spDetailsTable.Rows.Add(new DataRow(successCountDataRowName));
spDetailsTable.Rows.Add(new DataRow(divFailDataRowName));
spDetailsTable.Rows.Add(new DataRow(qualityFailDataRowName));
ResultsParameter.ActualValue.Add(new Result(spDetailsParameterName, spDetailsTable));
}
if (GenerationsParameter.ActualValue.Value != currentGeneration) {
spDetailsTable.Rows[divDataRowName].Values.Add(divCount);
divCount = 0;
spDetailsTable.Rows[qualityDataRowName].Values.Add(qualityCount);
qualityCount = 0;
spDetailsTable.Rows[overallCountDataRowName].Values.Add(overallCount);
overallCount = 0;
spDetailsTable.Rows[successCountDataRowName].Values.Add(successCount);
successCount = 0;
spDetailsTable.Rows[qualityFailDataRowName].Values.Add(badQualityCount);
badQualityCount = 0;
spDetailsTable.Rows[divFailDataRowName].Values.Add(badDivCount);
badDivCount = 0;
currentGeneration = GenerationsParameter.ActualValue.Value;
}
string qualityVariableName = ((ISingleObjectiveSolutionSimilarityCalculator)SimilarityCalculator).QualityVariableName;
string solutionVariableName = ((ISingleObjectiveSolutionSimilarityCalculator)SimilarityCalculator).SolutionVariableName;
var remainingScope = GetRemainingScope();
double oldPopQuality = 0.0;
int popSize = 0;
foreach (IScope oldSolScope in remainingScope.SubScopes) {
double curQuality = ((DoubleValue)oldSolScope.Variables[qualityVariableName].Value).Value;
IItem curSol = oldSolScope.Variables[solutionVariableName].Value;
oldPopQuality += curQuality;
popSize++;
}
//diversity compared to population
Scope fakeScope = new Scope();
fakeScope.SubScopes.Add((IScope)ExecutionContext.Scope.Clone());
var similarities = SimilarityCalculator.CalculateSolutionCrowdSimilarity(fakeScope, remainingScope);
double averageSimilarity = similarities[0].Average();
resultDiversity = averageSimilarity < diversityComFact;
//quality compared to population
double averageQuality = oldPopQuality / popSize;
bool result = maximization && leftQuality > averageQuality || !maximization && leftQuality < averageQuality;
//collect statistics
if (result) {
qualityCount++;
} else {
badQualityCount++;
}
if (resultDiversity) {
divCount++;
} else {
badDivCount++;
}
if (result && resultDiversity) {
successCount++;
}
overallCount++;
//use diveristiy criteria or not
if (EnableDivCriteriaParameter.Value.Value) {
result = result && resultDiversity;
}
BoolValue resultValue = ResultParameter.ActualValue;
if (resultValue == null) {
ResultParameter.ActualValue = new BoolValue(result);
} else {
resultValue.Value = result;
}
//like the placeholder, though we create child operations
OperationCollection next = new OperationCollection(base.Apply());
IOperator op = ComparisonFactorModifierParameter.Value;
if (op != null)
next.Insert(0, ExecutionContext.CreateChildOperation(op));
return next;
}
}
}