#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.Analysis; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization.Operators; using HeuristicLab.Parameters; using HEAL.Attic; namespace HeuristicLab.Problems.DataAnalysis.Symbolic { [StorableType("83603E95-3CBD-476C-B11F-B30C80ACD0D3")] [Item("SymbolicDataAnalysisSingleObjectivePruningAnalyzer", "An analyzer that prunes introns from trees in single objective symbolic data analysis problems.")] public abstract class SymbolicDataAnalysisSingleObjectivePruningAnalyzer : SymbolicDataAnalysisSingleObjectiveAnalyzer { #region parameter names private const string ProblemDataParameterName = "ProblemData"; private const string UpdateIntervalParameterName = "UpdateInverval"; private const string UpdateCounterParameterName = "UpdateCounter"; private const string PopulationSliceParameterName = "PopulationSlice"; private const string PruningProbabilityParameterName = "PruningProbability"; private const string TotalNumberOfPrunedSubtreesParameterName = "Number of pruned subtrees"; private const string TotalNumberOfPrunedTreesParameterName = "Number of pruned trees"; private const string TotalNumberOfPrunedNodesParameterName = "Number of pruned nodes"; private const string RandomParameterName = "Random"; private const string ResultsParameterName = "Results"; private const string PopulationSizeParameterName = "PopulationSize"; #endregion #region private members private DataReducer prunedNodesReducer; private DataReducer prunedSubtreesReducer; private DataReducer prunedTreesReducer; private DataTableValuesCollector valuesCollector; private ResultsCollector resultsCollector; #endregion #region parameter properties public ILookupParameter RandomParameter { get { return (ILookupParameter)Parameters[RandomParameterName]; } } public IFixedValueParameter UpdateIntervalParameter { get { return (IFixedValueParameter)Parameters[UpdateIntervalParameterName]; } } public IFixedValueParameter UpdateCounterParameter { get { return (IFixedValueParameter)Parameters[UpdateCounterParameterName]; } } public IFixedValueParameter PopulationSliceParameter { get { return (IFixedValueParameter)Parameters[PopulationSliceParameterName]; } } public IFixedValueParameter PruningProbabilityParameter { get { return (IFixedValueParameter)Parameters[PruningProbabilityParameterName]; } } public ILookupParameter PopulationSizeParameter { get { return (ILookupParameter)Parameters[PopulationSizeParameterName]; } } #endregion #region properties protected abstract SymbolicDataAnalysisExpressionPruningOperator PruningOperator { get; } protected int UpdateInterval { get { return UpdateIntervalParameter.Value.Value; } } protected int UpdateCounter { get { return UpdateCounterParameter.Value.Value; } set { UpdateCounterParameter.Value.Value = value; } } protected double PopulationSliceStart { get { return PopulationSliceParameter.Value.Start; } set { PopulationSliceParameter.Value.Start = value; } } protected double PopulationSliceEnd { get { return PopulationSliceParameter.Value.End; } set { PopulationSliceParameter.Value.End = value; } } protected double PruningProbability { get { return PruningProbabilityParameter.Value.Value; } set { PruningProbabilityParameter.Value.Value = value; } } #endregion #region IStatefulItem members public override void InitializeState() { base.InitializeState(); UpdateCounter = 0; } public override void ClearState() { base.ClearState(); UpdateCounter = 0; } #endregion [StorableConstructor] protected SymbolicDataAnalysisSingleObjectivePruningAnalyzer(StorableConstructorFlag _) : base(_) { } protected SymbolicDataAnalysisSingleObjectivePruningAnalyzer(SymbolicDataAnalysisSingleObjectivePruningAnalyzer original, Cloner cloner) : base(original, cloner) { if (original.prunedNodesReducer != null) this.prunedNodesReducer = (DataReducer)original.prunedNodesReducer.Clone(); if (original.prunedSubtreesReducer != null) this.prunedSubtreesReducer = (DataReducer)original.prunedSubtreesReducer.Clone(); if (original.prunedTreesReducer != null) this.prunedTreesReducer = (DataReducer)original.prunedTreesReducer.Clone(); if (original.valuesCollector != null) this.valuesCollector = (DataTableValuesCollector)original.valuesCollector.Clone(); if (original.resultsCollector != null) this.resultsCollector = (ResultsCollector)original.resultsCollector.Clone(); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (!Parameters.ContainsKey(PopulationSizeParameterName)) { Parameters.Add(new LookupParameter(PopulationSizeParameterName, "The population of individuals.")); } if (Parameters.ContainsKey(UpdateCounterParameterName)) { var fixedValueParameter = Parameters[UpdateCounterParameterName] as FixedValueParameter; if (fixedValueParameter == null) { var valueParameter = (ValueParameter)Parameters[UpdateCounterParameterName]; Parameters.Remove(UpdateCounterParameterName); Parameters.Add(new FixedValueParameter(UpdateCounterParameterName, valueParameter.Value)); } } if (Parameters.ContainsKey(UpdateIntervalParameterName)) { var fixedValueParameter = Parameters[UpdateIntervalParameterName] as FixedValueParameter; if (fixedValueParameter == null) { var valueParameter = (ValueParameter)Parameters[UpdateIntervalParameterName]; Parameters.Remove(UpdateIntervalParameterName); Parameters.Add(new FixedValueParameter(UpdateIntervalParameterName, valueParameter.Value)); } } if (Parameters.ContainsKey(PopulationSliceParameterName)) { var fixedValueParameter = Parameters[PopulationSliceParameterName] as FixedValueParameter; if (fixedValueParameter == null) { var valueParameter = (ValueParameter)Parameters[PopulationSliceParameterName]; Parameters.Remove(PopulationSliceParameterName); Parameters.Add(new FixedValueParameter(PopulationSliceParameterName, valueParameter.Value)); } } if (Parameters.ContainsKey(PruningProbabilityParameterName)) { var fixedValueParameter = Parameters[PruningProbabilityParameterName] as FixedValueParameter; if (fixedValueParameter == null) { var valueParameter = (ValueParameter)Parameters[PruningProbabilityParameterName]; Parameters.Remove(PruningProbabilityParameterName); Parameters.Add(new FixedValueParameter(PruningProbabilityParameterName, valueParameter.Value)); } } } protected SymbolicDataAnalysisSingleObjectivePruningAnalyzer() { #region add parameters Parameters.Add(new FixedValueParameter(PopulationSliceParameterName, "The slice of the population where pruning should be applied.", new DoubleRange(0.75, 1))); Parameters.Add(new FixedValueParameter(PruningProbabilityParameterName, "The probability for pruning an individual.", new DoubleValue(0.5))); Parameters.Add(new FixedValueParameter(UpdateIntervalParameterName, "The interval in which the tree length analysis should be applied.", new IntValue(1))); Parameters.Add(new FixedValueParameter(UpdateCounterParameterName, "The value which counts how many times the operator was called", new IntValue(0))); Parameters.Add(new LookupParameter(RandomParameterName, "The random number generator.")); Parameters.Add(new LookupParameter(ProblemDataParameterName, "The problem data.")); Parameters.Add(new LookupParameter(PopulationSizeParameterName, "The population of individuals.")); #endregion } // /// /// Computes the closed interval bounding the portion of the population that is to be pruned. /// /// Returns an int range [start, end] private IntRange GetSliceBounds() { if (PopulationSliceStart < 0 || PopulationSliceEnd < 0) throw new ArgumentOutOfRangeException("The slice bounds cannot be negative."); if (PopulationSliceStart > 1 || PopulationSliceEnd > 1) throw new ArgumentOutOfRangeException("The slice bounds should be expressed as unit percentages."); var count = PopulationSizeParameter.ActualValue.Value; var start = (int)Math.Round(PopulationSliceStart * count); var end = (int)Math.Round(PopulationSliceEnd * count); if (end > count) end = count; if (start >= end) throw new ArgumentOutOfRangeException("Invalid PopulationSlice bounds."); return new IntRange(start, end); } private IOperation CreatePruningOperation() { var operations = new OperationCollection { Parallel = true }; var range = GetSliceBounds(); var qualities = Quality.Select(x => x.Value).ToArray(); var indices = Enumerable.Range(0, qualities.Length).ToArray(); indices.StableSort((a, b) => qualities[a].CompareTo(qualities[b])); if (!Maximization.Value) Array.Reverse(indices); var subscopes = ExecutionContext.Scope.SubScopes; var random = RandomParameter.ActualValue; var empty = new EmptyOperator(); for (int i = 0; i < indices.Length; ++i) { IOperator @operator; if (range.Start <= i && i < range.End && random.NextDouble() <= PruningProbability) @operator = PruningOperator; else @operator = empty; var index = indices[i]; var subscope = subscopes[index]; operations.Add(ExecutionContext.CreateChildOperation(@operator, subscope)); } return operations; } public override IOperation Apply() { UpdateCounter++; if (UpdateCounter != UpdateInterval) return base.Apply(); UpdateCounter = 0; if (prunedNodesReducer == null || prunedSubtreesReducer == null || prunedTreesReducer == null || valuesCollector == null || resultsCollector == null) { InitializeOperators(); } var prune = CreatePruningOperation(); var reducePrunedNodes = ExecutionContext.CreateChildOperation(prunedNodesReducer); var reducePrunedSubtrees = ExecutionContext.CreateChildOperation(prunedSubtreesReducer); var reducePrunedTrees = ExecutionContext.CreateChildOperation(prunedTreesReducer); var collectValues = ExecutionContext.CreateChildOperation(valuesCollector); var collectResults = ExecutionContext.CreateChildOperation(resultsCollector); return new OperationCollection { prune, reducePrunedNodes, reducePrunedSubtrees, reducePrunedTrees, collectValues, collectResults, base.Apply() }; } private void InitializeOperators() { prunedNodesReducer = new DataReducer(); prunedNodesReducer.ParameterToReduce.ActualName = PruningOperator.PrunedNodesParameter.ActualName; prunedNodesReducer.ReductionOperation.Value = new ReductionOperation(ReductionOperations.Sum); // sum all the pruned subtrees parameter values prunedNodesReducer.TargetOperation.Value = new ReductionOperation(ReductionOperations.Assign); // asign the sum to the target parameter prunedNodesReducer.TargetParameter.ActualName = TotalNumberOfPrunedNodesParameterName; prunedSubtreesReducer = new DataReducer(); prunedSubtreesReducer.ParameterToReduce.ActualName = PruningOperator.PrunedSubtreesParameter.ActualName; prunedSubtreesReducer.ReductionOperation.Value = new ReductionOperation(ReductionOperations.Sum); // sum all the pruned subtrees parameter values prunedSubtreesReducer.TargetOperation.Value = new ReductionOperation(ReductionOperations.Assign); // asign the sum to the target parameter prunedSubtreesReducer.TargetParameter.ActualName = TotalNumberOfPrunedSubtreesParameterName; prunedTreesReducer = new DataReducer(); prunedTreesReducer.ParameterToReduce.ActualName = PruningOperator.PrunedTreesParameter.ActualName; prunedTreesReducer.ReductionOperation.Value = new ReductionOperation(ReductionOperations.Sum); prunedTreesReducer.TargetOperation.Value = new ReductionOperation(ReductionOperations.Assign); prunedTreesReducer.TargetParameter.ActualName = TotalNumberOfPrunedTreesParameterName; valuesCollector = new DataTableValuesCollector(); valuesCollector.CollectedValues.Add(new LookupParameter(TotalNumberOfPrunedNodesParameterName)); valuesCollector.CollectedValues.Add(new LookupParameter(TotalNumberOfPrunedSubtreesParameterName)); valuesCollector.CollectedValues.Add(new LookupParameter(TotalNumberOfPrunedTreesParameterName)); valuesCollector.DataTableParameter.ActualName = "Population pruning"; resultsCollector = new ResultsCollector(); resultsCollector.CollectedValues.Add(new LookupParameter("Population pruning")); resultsCollector.ResultsParameter.ActualName = ResultsParameterName; } } }