Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GP-MoveOperators/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/ReplaceBranchMultiMoveGenerator.cs @ 8214

Last change on this file since 8214 was 8214, checked in by gkronber, 12 years ago

#1847: bug fixes and improvements discussed with andreas

File size: 13.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
29using HeuristicLab.Operators;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33
34namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
35  [Item("ReplaceBranchMultiMoveGenerator", "")]
36  [StorableClass]
37  public class ReplaceBranchMultiMoveGenerator : SingleSuccessorOperator, IStochasticOperator, ISymbolicExpressionTreeMoveOperator, IMultiMoveGenerator,
38    ISymbolicDataAnalysisInterpreterOperator, ISymbolicExpressionTreeGrammarBasedOperator, ISymbolicExpressionTreeSizeConstraintOperator {
39    public ILookupParameter<IRandom> RandomParameter {
40      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
41    }
42    public IValueLookupParameter<IntValue> SampleSizeParameter {
43      get { return (IValueLookupParameter<IntValue>)Parameters["SampleSize"]; }
44    }
45    public ILookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter> SymbolicDataAnalysisTreeInterpreterParameter {
46      get { return (ILookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>)Parameters["Interpreter"]; }
47    }
48
49    public IValueLookupParameter<ISymbolicExpressionGrammar> SymbolicExpressionTreeGrammarParameter {
50      get { return (IValueLookupParameter<ISymbolicExpressionGrammar>)Parameters["Grammar"]; }
51    }
52    public ILookupParameter<IRegressionProblemData> ProblemDataParameter {
53      get { return (ILookupParameter<IRegressionProblemData>)Parameters["ProblemData"]; }
54    }
55    public IntValue SampleSize {
56      get { return SampleSizeParameter.Value; }
57      set { SampleSizeParameter.Value = value; }
58    }
59    public ILookupParameter<ISymbolicExpressionTree> SymbolicExpressionTreeParameter {
60      get { return (ILookupParameter<ISymbolicExpressionTree>)Parameters["SymbolicExpressionTree"]; }
61    }
62    public ILookupParameter<ReplaceBranchMove> ReplaceBranchMoveParameter {
63      get { return (LookupParameter<ReplaceBranchMove>)Parameters["ReplaceBranchMove"]; }
64    }
65
66    public IValueParameter<IntValue> ReplacementBranchesPoolSize {
67      get { return (IValueParameter<IntValue>)Parameters["ReplacementBranchesPoolSize"]; }
68    }
69
70    public IValueParameter<IntValue> MaxReplacementBranchLength {
71      get { return (IValueParameter<IntValue>)Parameters["MaxReplacementBranchLength"]; }
72    }
73
74    public IValueParameter<IntValue> MaxReplacementBranchDepth {
75      get { return (IValueParameter<IntValue>)Parameters["MaxReplacementBranchDepth"]; }
76    }
77
78    protected ScopeParameter CurrentScopeParameter {
79      get { return (ScopeParameter)Parameters["CurrentScope"]; }
80    }
81
82    public IValueLookupParameter<IntValue> MaximumSymbolicExpressionTreeDepthParameter {
83      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumSymbolicExpressionTreeDepth"]; }
84    }
85
86    public IValueLookupParameter<IntValue> MaximumSymbolicExpressionTreeLengthParameter {
87      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumSymbolicExpressionTreeLength"]; }
88    }
89
90    public IValueLookupParameter<IntValue> NeighbourhoodSizeParameter {
91      get { return (IValueLookupParameter<IntValue>)Parameters["NeighbourhoodSize"]; }
92    }
93
94
95    private IList<ISymbolicExpressionTree> fragments;
96    private IList<double[]> fragmentOutput;
97
98    [StorableConstructor]
99    protected ReplaceBranchMultiMoveGenerator(bool deserializing) : base(deserializing) { }
100    protected ReplaceBranchMultiMoveGenerator(ReplaceBranchMultiMoveGenerator original, Cloner cloner) : base(original, cloner) { }
101    public ReplaceBranchMultiMoveGenerator()
102      : base() {
103      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator."));
104      Parameters.Add(new ValueLookupParameter<IntValue>("SampleSize", "The number of moves to generate."));
105
106      Parameters.Add(new LookupParameter<ISymbolicExpressionTree>("SymbolicExpressionTree", "The symbolic expression tree for which moves should be generated."));
107      Parameters.Add(new LookupParameter<ReplaceBranchMove>("ReplaceBranchMove", "The moves that should be generated in subscopes."));
108      Parameters.Add(new ScopeParameter("CurrentScope", "The current scope where the moves should be added as subscopes."));
109      Parameters.Add(new ValueLookupParameter<ISymbolicExpressionGrammar>("Grammar"));
110      Parameters.Add(new LookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>("Interpreter"));
111      Parameters.Add(new LookupParameter<IRegressionProblemData>("ProblemData"));
112      Parameters.Add(new ValueParameter<IntValue>("ReplacementBranchesPoolSize", new IntValue(10000)));
113      Parameters.Add(new ValueParameter<IntValue>("MaxReplacementBranchLength", new IntValue(8)));
114      Parameters.Add(new ValueParameter<IntValue>("MaxReplacementBranchDepth", new IntValue(4)));
115      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumSymbolicExpressionTreeDepth"));
116      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumSymbolicExpressionTreeLength"));
117      Parameters.Add(new ValueLookupParameter<IntValue>("NeighbourhoodSize", new IntValue(5)));
118    }
119
120
121    [StorableHook(HookType.AfterDeserialization)]
122    private void AfterDeserialization() {
123      if (!Parameters.ContainsKey("MaximumSymbolicExpressionTreeDepth")) {
124        Parameters.Add(new ValueLookupParameter<IntValue>("MaximumSymbolicExpressionTreeDepth"));
125        Parameters.Add(new ValueLookupParameter<IntValue>("MaximumSymbolicExpressionTreeLength"));
126      }
127      if (!Parameters.ContainsKey("NeighbourhoodSize")) {
128        Parameters.Add(new ValueLookupParameter<IntValue>("NeighbourhoodSize", new IntValue(5)));
129      }
130
131    }
132
133
134    public override IDeepCloneable Clone(Cloner cloner) {
135      return new ReplaceBranchMultiMoveGenerator(this, cloner);
136    }
137
138    public override void ClearState() {
139      fragments = null;
140      fragmentOutput = null;
141      base.ClearState();
142    }
143    public override void InitializeState() {
144      fragments = null;
145      fragmentOutput = null;
146      base.InitializeState();
147    }
148
149    public override IOperation Apply() {
150      var random = RandomParameter.ActualValue;
151      if (fragments == null || fragmentOutput == null) {
152        InitializeOperator();
153      }
154
155      var tree = SymbolicExpressionTreeParameter.ActualValue;
156
157      string moveParameterName = ReplaceBranchMoveParameter.ActualName;
158      var moveScopes = new List<Scope>();
159      int n = SampleSizeParameter.ActualValue.Value;
160
161      var moves = GenerateMoves(tree, random, n);
162
163      foreach (var m in moves) {
164        var moveScope = new Scope(moveScopes.Count.ToString());
165        moveScope.Variables.Add(new HeuristicLab.Core.Variable(moveParameterName, m));
166        moveScopes.Add(moveScope);
167      }
168      CurrentScopeParameter.ActualValue.SubScopes.AddRange(moveScopes);
169      return base.Apply();
170    }
171
172    public IEnumerable<ReplaceBranchMove> GenerateMoves(ISymbolicExpressionTree tree, IRandom random, int n) {
173      int count = 0;
174      var possibleChildren = (from parent in tree.Root.GetSubtree(0).IterateNodesPrefix()
175                              from i in Enumerable.Range(0, parent.SubtreeCount)
176                              let currentChild = parent.GetSubtree(i)
177                              select new { parent, i }).ToArray();
178
179      var root = (new ProgramRootSymbol()).CreateTreeNode();
180      var start = (new StartSymbol()).CreateTreeNode();
181      root.AddSubtree(start);
182      var t = new SymbolicExpressionTree(root);
183      var interpreter = SymbolicDataAnalysisTreeInterpreterParameter.ActualValue;
184      var ds = ProblemDataParameter.ActualValue.Dataset;
185      var rows = ProblemDataParameter.ActualValue.TrainingIndices;
186
187      int maxDepth = MaximumSymbolicExpressionTreeDepthParameter.ActualValue.Value;
188      int maxLength = MaximumSymbolicExpressionTreeLengthParameter.ActualValue.Value;
189      int neighbourhoodSize = NeighbourhoodSizeParameter.ActualValue.Value;
190      while (count < n) {
191        // select a random replacement point
192        var selected = possibleChildren[random.Next(possibleChildren.Length)];
193        // evaluate
194        start.AddSubtree(selected.parent.GetSubtree(selected.i));
195        var output = interpreter.GetSymbolicExpressionTreeValues(t, ds, rows).ToArray();
196        start.RemoveSubtree(0);
197
198        var bestTrees = new SortedList<double, Tuple<ISymbolicExpressionTree, double[]>>(fragments.Count);
199        // iterate over the whole pool of branches for replacement
200        for (int i = 0; i < fragments.Count; i++) {
201          // if the branch is allowed in the selected point
202          if (tree.Length - selected.parent.GetSubtree(selected.i).GetLength() + fragments[i].Length <= maxLength + 2 &&
203            tree.Root.GetBranchLevel(selected.parent) + fragments[i].Depth - 2 <= maxDepth + 2 &&
204            tree.Root.Grammar.IsAllowedChildSymbol(selected.parent.Symbol, fragments[i].Root.GetSubtree(0).GetSubtree(0).Symbol, selected.i)) {
205            double similarity;
206            if (neighbourhoodSize > 0) {
207              OnlineCalculatorError error;
208              // calculate the similarity
209              similarity = OnlinePearsonsRSquaredCalculator.Calculate(output, fragmentOutput[i], out error);
210              if (error != OnlineCalculatorError.None) similarity = 0.0;
211            } else {
212              // neighbourhoodSize = 0 => similarity is not considered
213              similarity = 0.0;
214            }
215            // if we found a new bestSimilarity then keep the replacement branch in a sorted list (keep maximally the 30 best for this replacement point)
216            if (!similarity.IsAlmost(1.0)) {
217              bestTrees.Add(similarity + random.NextDouble() * 1E-6, Tuple.Create(fragments[i], fragmentOutput[i]));
218              if (neighbourhoodSize > 0 && bestTrees.Count > neighbourhoodSize)
219                bestTrees.RemoveAt(0); // remove moves with small R² at the beginning
220              else if (neighbourhoodSize == 0 && bestTrees.Count > 1) {
221                bestTrees.RemoveAt(bestTrees.Count - 1);  // remove the last tree => only a random fragment is kept
222              }
223            }
224          }
225        }
226        // yield moves (we need to add linear scaling parameters for the inserted tree)
227        foreach (var pair in bestTrees.Values) {
228          yield return
229            new ReplaceBranchMove(tree, selected.parent, selected.i, pair.Item1.Root.GetSubtree(0).GetSubtree(0), output, pair.Item2);
230          count++;
231        }
232      }
233    }
234
235    private void InitializeOperator() {
236      // init locally and set only at the end in case of exceptions
237      var trees = new List<ISymbolicExpressionTree>();
238      var treeOutput = new List<double[]>();
239      var random = RandomParameter.ActualValue;
240      var g = SymbolicExpressionTreeGrammarParameter.ActualValue;
241      var constSym = g.Symbols.Single(s => s is Constant);
242      // temporarily disable constants
243      double oldConstFreq = constSym.InitialFrequency;
244      constSym.InitialFrequency = 0.0;
245      var interpreter = SymbolicDataAnalysisTreeInterpreterParameter.ActualValue;
246      var ds = ProblemDataParameter.ActualValue.Dataset;
247      var rows = ProblemDataParameter.ActualValue.TrainingIndices;
248      // create pool of random branches for replacement (no constants)
249      // and evaluate the output
250      // only keep fragments if the output does not contain invalid values
251      var n = ReplacementBranchesPoolSize.Value.Value;
252      while (trees.Count < n) {
253        var t = ProbabilisticTreeCreator.Create(random, g, MaxReplacementBranchLength.Value.Value, MaxReplacementBranchDepth.Value.Value);
254        var output = interpreter.GetSymbolicExpressionTreeValues(t, ds, rows);
255        if (!output.Any(x => double.IsInfinity(x) || double.IsNaN(x))) {
256          trees.Add(t);
257          treeOutput.Add(output.ToArray());
258        }
259      }
260      // enable constants again
261      constSym.InitialFrequency = oldConstFreq;
262      this.fragments = trees;
263      this.fragmentOutput = treeOutput;
264    }
265  }
266}
Note: See TracBrowser for help on using the repository browser.