1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022011 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 


22  using System.Collections.Generic;


23  using System.Linq;


24  using HeuristicLab.Common;


25  using HeuristicLab.Core;


26  using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;


27  using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;


28 


29  namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {


30  /// <summary>


31  /// Represents a symbolic regression model


32  /// </summary>


33  [StorableClass]


34  [Item(Name = "SymbolicRegressionModel", Description = "Represents a symbolic regression model.")]


35  public class SymbolicRegressionModel : SymbolicDataAnalysisModel, ISymbolicRegressionModel {


36  [Storable]


37  private double lowerEstimationLimit;


38  [Storable]


39  private double upperEstimationLimit;


40 


41  [StorableConstructor]


42  protected SymbolicRegressionModel(bool deserializing) : base(deserializing) { }


43  protected SymbolicRegressionModel(SymbolicRegressionModel original, Cloner cloner)


44  : base(original, cloner) {


45  this.lowerEstimationLimit = original.lowerEstimationLimit;


46  this.upperEstimationLimit = original.upperEstimationLimit;


47  }


48  public SymbolicRegressionModel(ISymbolicExpressionTree tree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,


49  double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue)


50  : base(tree, interpreter) {


51  this.lowerEstimationLimit = lowerEstimationLimit;


52  this.upperEstimationLimit = upperEstimationLimit;


53  }


54 


55  public override IDeepCloneable Clone(Cloner cloner) {


56  return new SymbolicRegressionModel(this, cloner);


57  }


58 


59  public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {


60  return Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, rows)


61  .LimitToRange(lowerEstimationLimit, upperEstimationLimit);


62  }


63 


64  public static void Scale(SymbolicRegressionModel model, IRegressionProblemData problemData) {


65  var dataset = problemData.Dataset;


66  var targetVariable = problemData.TargetVariable;


67  var rows = problemData.TrainingIndizes;


68  var estimatedValues = model.Interpreter.GetSymbolicExpressionTreeValues(model.SymbolicExpressionTree, dataset, rows);


69  var targetValues = dataset.GetEnumeratedVariableValues(targetVariable, rows);


70  double alpha;


71  double beta;


72  OnlineCalculatorError errorState;


73  OnlineLinearScalingParameterCalculator.Calculate(estimatedValues, targetValues, out alpha, out beta, out errorState);


74  if (errorState != OnlineCalculatorError.None) return;


75 


76  ConstantTreeNode alphaTreeNode = null;


77  ConstantTreeNode betaTreeNode = null;


78  // check if model has been scaled previously by analyzing the structure of the tree


79  var startNode = model.SymbolicExpressionTree.Root.GetSubtree(0);


80  if (startNode.GetSubtree(0).Symbol is Addition) {


81  var addNode = startNode.GetSubtree(0);


82  if (addNode.SubtreesCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication && addNode.GetSubtree(1).Symbol is Constant) {


83  alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode;


84  var mulNode = addNode.GetSubtree(0);


85  if (mulNode.SubtreesCount == 2 && mulNode.GetSubtree(1).Symbol is Constant) {


86  betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode;


87  }


88  }


89  }


90  // if tree structure matches the structure necessary for linear scaling then reuse the existing tree nodes


91  if (alphaTreeNode != null && betaTreeNode != null) {


92  betaTreeNode.Value *= beta;


93  alphaTreeNode.Value *= beta;


94  alphaTreeNode.Value += alpha;


95  } else {


96  var mainBranch = startNode.GetSubtree(0);


97  var product = MakeProduct(mainBranch, beta);


98  startNode.RemoveSubtree(0);


99  startNode.AddSubtree(product);


100 


101  var scaledMainBranch = MakeSum(product, alpha);


102  startNode.RemoveSubtree(0);


103  startNode.AddSubtree(scaledMainBranch);


104  }


105  }


106 


107  private static ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode treeNode, double alpha) {


108  if (alpha.IsAlmost(0.0)) {


109  return treeNode;


110  } else {


111  var addition = treeNode.Grammar.Symbols.OfType<Addition>().FirstOrDefault();


112  if (addition == null) addition = new Addition();


113  var node = addition.CreateTreeNode();


114  var alphaConst = MakeConstant(alpha);


115  node.AddSubtree(treeNode);


116  node.AddSubtree(alphaConst);


117  return node;


118  }


119  }


120 


121  private static ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode treeNode, double beta) {


122  if (beta.IsAlmost(1.0)) {


123  return treeNode;


124  } else {


125  var multipliciation = treeNode.Grammar.Symbols.OfType<Multiplication>().FirstOrDefault();


126  if (multipliciation == null) multipliciation = new Multiplication();


127  var node = multipliciation.CreateTreeNode();


128  var betaConst = MakeConstant(beta);


129  node.AddSubtree(treeNode);


130  node.AddSubtree(betaConst);


131  return node;


132  }


133  }


134 


135  private static ISymbolicExpressionTreeNode MakeConstant(double c) {


136  var node = (ConstantTreeNode)(new Constant()).CreateTreeNode();


137  node.Value = c;


138  return node;


139  }


140  }


141  }

