#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(); } } }