#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 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.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
using HeuristicLab.EvolutionTracking;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Tracking.Analyzers {
[Item("SymbolicDataAnalysisSchemaFrequencyAnalyzer", "An analyzer which counts schema frequencies in the population.")]
[StorableClass]
public class SymbolicDataAnalysisSchemaFrequencyAnalyzer : EvolutionTrackingAnalyzer {
private const string MinimumSchemaLengthParameterName = "MinimumSchemaLength";
[Storable]
private readonly SymbolicExpressionTreePhenotypicSimilarityCalculator phenotypicSimilarityCalculator;
[Storable]
private readonly SymbolicExpressionTreeBottomUpSimilarityCalculator genotypicSimilarityCalculator;
[Storable]
private readonly ISymbolicExpressionTreeNodeEqualityComparer comparer;
private QueryMatch qm;
public IFixedValueParameter MinimumSchemaLengthParameter {
get { return (IFixedValueParameter)Parameters[MinimumSchemaLengthParameterName]; }
}
public SymbolicDataAnalysisSchemaFrequencyAnalyzer() {
comparer = new SymbolicExpressionTreeNodeEqualityComparer {
MatchConstantValues = false,
MatchVariableNames = true,
MatchVariableWeights = false
};
qm = new QueryMatch(comparer) { MatchParents = true };
phenotypicSimilarityCalculator = new SymbolicExpressionTreePhenotypicSimilarityCalculator();
genotypicSimilarityCalculator = new SymbolicExpressionTreeBottomUpSimilarityCalculator { SolutionVariableName = "SymbolicExpressionTree" };
Parameters.Add(new FixedValueParameter(MinimumSchemaLengthParameterName, new IntValue(10)));
}
protected SymbolicDataAnalysisSchemaFrequencyAnalyzer(SymbolicDataAnalysisSchemaFrequencyAnalyzer original,
Cloner cloner) : base(original, cloner) {
comparer = original.comparer;
phenotypicSimilarityCalculator = original.phenotypicSimilarityCalculator;
genotypicSimilarityCalculator = original.genotypicSimilarityCalculator;
qm = new QueryMatch(comparer) { MatchParents = true };
}
public override IDeepCloneable Clone(Cloner cloner) {
return new SymbolicDataAnalysisSchemaFrequencyAnalyzer(this, cloner);
}
[StorableConstructor]
protected SymbolicDataAnalysisSchemaFrequencyAnalyzer(bool deserializing) : base(deserializing) { }
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
qm = new QueryMatch(comparer) { MatchParents = true };
}
public override IOperation Apply() {
int updateInterval = UpdateIntervalParameter.Value.Value;
IntValue updateCounter = UpdateCounterParameter.ActualValue;
// if counter does not yet exist then initialize it with update interval
// to make sure the solutions are analyzed on the first application of this operator
if (updateCounter == null) {
updateCounter = new IntValue(updateInterval);
UpdateCounterParameter.ActualValue = updateCounter;
}
//analyze solutions only every 'updateInterval' times
if (updateCounter.Value != updateInterval) {
updateCounter.Value++;
return base.Apply();
}
updateCounter.Value = 1;
if (PopulationGraph == null || Generation.Value == 0)
return base.Apply();
var minimumSchemaLength = MinimumSchemaLengthParameter.Value.Value;
var vertices = PopulationGraph.GetByRank(Generation.Value).Cast>().ToList();
var formatter = new SymbolicExpressionTreeStringFormatter { Indent = false, AppendNewLines = false };
var schemas = SchemaCreator.GenerateSchemas(vertices, minimumSchemaLength).ToList();
var trees = vertices.Select(x => x.Data).ToList();
var qualities = vertices.Select(x => x.Quality).ToList();
var scopes = ExecutionContext.Scope.SubScopes; // the scopes of all the individuals, needed because the tree evaluated values are stored in the scope and we use them for the phenotypic similarity
var matrix = new DoubleMatrix(schemas.Count, 5) {
RowNames = schemas.Select(x => formatter.Format(x.Root.GetSubtree(0).GetSubtree(0))),
ColumnNames = new[] { "Avg. Length", "Avg. Quality", "Relative Frequency", "Avg. Phen. Sim.", "Avg. Gen. Sim" },
SortableView = true
};
for (int i = 0; i < schemas.Count; ++i) {
var schema = schemas[i];
int count = 0;
double avgLength = 0;
double avgQuality = 0;
var matchingScopes = new ScopeList();
for (int j = 0; j < trees.Count; ++j) {
var tree = trees[j];
if (qm.Match(tree, schema)) {
count++;
avgLength += tree.Length;
avgQuality += qualities[j];
matchingScopes.Add(scopes[j]);
}
}
avgLength /= count;
avgQuality /= count;
double relativeFreq = (double)count / trees.Count;
double avgPhenotypicSimilarity = SchemaEvaluator.CalculateSimilarity(matchingScopes, phenotypicSimilarityCalculator, true, 4);
double avgGenotypicSimilarity = SchemaEvaluator.CalculateSimilarity(matchingScopes, genotypicSimilarityCalculator, true, 4);
matrix[i, 0] = avgLength;
matrix[i, 1] = avgQuality;
matrix[i, 2] = relativeFreq;
matrix[i, 3] = avgPhenotypicSimilarity;
matrix[i, 4] = avgGenotypicSimilarity;
}
if (Results.ContainsKey("Schema Frequencies")) {
var result = Results["Schema Frequencies"];
result.Value = matrix;
} else {
var result = new Result("Schema Frequencies", matrix);
Results.Add(result);
}
return base.Apply();
}
}
}