#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; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.EvolutionTracking; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Tracking { [Item("SchemaEvaluator", "An operator that builds schemas based on the heredity relationship in the genealogy graph.")] [StorableClass] public class SchemaEvaluator : EvolutionTrackingOperator { #region parameter names private const string MinimumSchemaFrequencyParameterName = "MinimumSchemaFrequency"; private const string MinimumPhenotypicSimilarityParameterName = "MinimumPhenotypicSimilarity"; private const string ReplacementRatioParameterName = "ReplacementRatio"; private const string SchemaParameterName = "Schema"; private const string PopulationSizeParameterName = "PopulationSize"; private const string RandomParameterName = "Random"; private const string EvaluatorParameterName = "Evaluator"; private const string ProblemDataParameterName = "ProblemData"; private const string InterpreterParameterName = "SymbolicExpressionTreeInterpreter"; private const string EstimationLimitsParameterName = "EstimationLimits"; private const string ApplyLinearScalingParameterName = "ApplyLinearScaling"; private const string MutatorParameterName = "Mutator"; private const string RandomReplacementParameterName = "RandomReplacement"; private const string ChangedTreesParameterName = "ChangedTrees"; #endregion #region parameters public ILookupParameter> EvaluatorParameter { get { return (ILookupParameter>)Parameters[EvaluatorParameterName]; } } public ILookupParameter ProblemDataParameter { get { return (ILookupParameter)Parameters[ProblemDataParameterName]; } } public ILookupParameter InterpreterParameter { get { return (ILookupParameter)Parameters[InterpreterParameterName]; } } public ILookupParameter EstimationLimitsParameter { get { return (ILookupParameter)Parameters[EstimationLimitsParameterName]; } } public ILookupParameter ApplyLinearScalingParameter { get { return (ILookupParameter)Parameters[ApplyLinearScalingParameterName]; } } public ILookupParameter RandomReplacementParameter { get { return (ILookupParameter)Parameters[RandomReplacementParameterName]; } } public ILookupParameter MutatorParameter { get { return (ILookupParameter)Parameters[MutatorParameterName]; } } public ILookupParameter RandomParameter { get { return (ILookupParameter)Parameters[RandomParameterName]; } } public ILookupParameter PopulationSizeParameter { get { return (ILookupParameter)Parameters[PopulationSizeParameterName]; } } public ILookupParameter SchemaParameter { get { return (ILookupParameter)Parameters[SchemaParameterName]; } } public ILookupParameter MinimumSchemaFrequencyParameter { get { return (ILookupParameter)Parameters[MinimumSchemaFrequencyParameterName]; } } public ILookupParameter ReplacementRatioParameter { get { return (ILookupParameter)Parameters[ReplacementRatioParameterName]; } } public ILookupParameter MinimumPhenotypicSimilarityParameter { get { return (ILookupParameter)Parameters[MinimumPhenotypicSimilarityParameterName]; } } public LookupParameter ChangedTreesParameter { get { return (LookupParameter)Parameters[ChangedTreesParameterName]; } } #endregion #region parameter properties public PercentValue MinimumSchemaFrequency { get { return MinimumSchemaFrequencyParameter.ActualValue; } } public PercentValue ReplacementRatio { get { return ReplacementRatioParameter.ActualValue; } } public PercentValue MinimumPhenotypicSimilarity { get { return MinimumPhenotypicSimilarityParameter.ActualValue; } } public BoolValue RandomReplacement { get { return RandomReplacementParameter.ActualValue; } } #endregion private readonly SymbolicExpressionTreePhenotypicSimilarityCalculator calculator = new SymbolicExpressionTreePhenotypicSimilarityCalculator(); private readonly QueryMatch qm; private readonly ISymbolicExpressionTreeNodeEqualityComparer comp = new SymbolicExpressionTreeNodeEqualityComparer { MatchConstantValues = false, MatchVariableWeights = false, MatchVariableNames = true }; [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (!Parameters.ContainsKey(ChangedTreesParameterName)) Parameters.Add(new LookupParameter(ChangedTreesParameterName)); } public SchemaEvaluator() { qm = new QueryMatch(comp) { MatchParents = true }; Parameters.Add(new LookupParameter(SchemaParameterName, "The current schema to be evaluated")); Parameters.Add(new LookupParameter(MinimumSchemaFrequencyParameterName)); Parameters.Add(new LookupParameter(ReplacementRatioParameterName)); Parameters.Add(new LookupParameter(MinimumPhenotypicSimilarityParameterName)); Parameters.Add(new LookupParameter(PopulationSizeParameterName)); Parameters.Add(new LookupParameter(RandomParameterName)); Parameters.Add(new LookupParameter>(EvaluatorParameterName)); Parameters.Add(new LookupParameter(ProblemDataParameterName)); Parameters.Add(new LookupParameter(InterpreterParameterName)); Parameters.Add(new LookupParameter(EstimationLimitsParameterName)); Parameters.Add(new LookupParameter(ApplyLinearScalingParameterName)); Parameters.Add(new LookupParameter(MutatorParameterName)); Parameters.Add(new LookupParameter(RandomReplacementParameterName)); Parameters.Add(new LookupParameter(ChangedTreesParameterName)); } protected SchemaEvaluator(SchemaEvaluator original, Cloner cloner) : base(original, cloner) { this.comp = original.comp; this.qm = original.qm; } public override IDeepCloneable Clone(Cloner cloner) { return new SchemaEvaluator(this, cloner); } private static double CalculatePhenotypicSimilarity(ScopeList individuals, SymbolicExpressionTreePhenotypicSimilarityCalculator calculator) { double similarity = 0; int count = individuals.Count; for (int i = 0; i < count - 1; ++i) { for (int j = i + 1; j < count; ++j) { similarity += calculator.CalculateSolutionSimilarity(individuals[i], individuals[j]); } } return similarity / (count * (count - 1) / 2.0); } public override IOperation Apply() { var individuals = ExecutionContext.Scope.SubScopes; // the scopes represent the individuals var random = RandomParameter.ActualValue; var mutator = MutatorParameter.ActualValue; var evaluator = EvaluatorParameter.ActualValue; var updateEstimatedValuesOperator = new UpdateEstimatedValuesOperator(); var s = SchemaParameter.ActualValue; var matchingIndividuals = new ScopeList(from ind in individuals let t = (ISymbolicExpressionTree)ind.Variables["SymbolicExpressionTree"].Value where qm.Match(t, s) select ind); if (matchingIndividuals.Count < MinimumSchemaFrequency.Value * individuals.Count) { ChangedTreesParameter.ActualValue = new IntValue(0); return base.Apply(); } var similarity = CalculatePhenotypicSimilarity(matchingIndividuals, calculator); if (similarity < MinimumPhenotypicSimilarity.Value) { ChangedTreesParameter.ActualValue = new IntValue(0); return base.Apply(); } var oc = new OperationCollection(); int n = (int)Math.Round(matchingIndividuals.Count * ReplacementRatio.Value); var individualsToReplace = RandomReplacement.Value ? matchingIndividuals.SampleRandomWithoutRepetition(random, n).ToList() : matchingIndividuals.OrderBy(x => (DoubleValue)x.Variables["Quality"].Value).Take(n).ToList(); foreach (var ind in individualsToReplace) { var mutatorOp = ExecutionContext.CreateChildOperation(mutator, ind); var evaluatorOp = ExecutionContext.CreateChildOperation(evaluator, ind); var updateEstimatedValuesOp = ExecutionContext.CreateChildOperation(updateEstimatedValuesOperator, ind); oc.Add(mutatorOp); oc.Add(evaluatorOp); oc.Add(updateEstimatedValuesOp); } ChangedTreesParameter.ActualValue = new IntValue(individualsToReplace.Count); return new OperationCollection(oc, base.Apply()); } } }