Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/StructuredSymbolicRegressionSingleObjectiveProblem.cs @ 18194

Last change on this file since 18194 was 18194, checked in by mkommend, 2 years ago

#3136:

  • Added handling of numeric parameters in structur GP problem by using a real vector encoding.
  • Configured grammar in sub function.
  • Added property for numeric parameters in structure template.
File size: 17.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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.Linq;
24using HEAL.Attic;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Encodings.RealVectorEncoding;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32using HeuristicLab.Problems.Instances;
33using HeuristicLab.Problems.Instances.DataAnalysis;
34
35namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
36  [StorableType("7464E84B-65CC-440A-91F0-9FA920D730F9")]
37  [Item(Name = "Structured Symbolic Regression Single Objective Problem (single-objective)", Description = "A problem with a structural definition and unfixed subfunctions.")]
38  [Creatable(CreatableAttribute.Categories.GeneticProgrammingProblems, Priority = 150)]
39  public class StructuredSymbolicRegressionSingleObjectiveProblem : SingleObjectiveBasicProblem<MultiEncoding>, IRegressionProblem, IProblemInstanceConsumer<IRegressionProblemData> {
40
41    #region Constants
42    private const string ProblemDataParameterName = "ProblemData";
43    private const string StructureTemplateParameterName = "Structure Template";
44    private const string InterpreterParameterName = "Interpreter";
45    private const string EstimationLimitsParameterName = "EstimationLimits";
46    private const string BestTrainingSolutionParameterName = "Best Training Solution";
47    private const string ApplyLinearScalingParameterName = "Apply Linear Scaling";
48    private const string OptimizeParametersParameterName = "Optimize Parameters";
49
50    private const string SymbolicExpressionTreeName = "SymbolicExpressionTree";
51    private const string NumericParametersEncoding = "Numeric Parameters";
52
53    private const string StructureTemplateDescriptionText =
54      "Enter your expression as string in infix format into the empty input field.\n" +
55      "By checking the \"Apply Linear Scaling\" checkbox you can add the relevant scaling terms to your expression.\n" +
56      "After entering the expression click parse to build the tree.\n" +
57      "To edit the defined sub-functions, click on the corresponding-colored node in the tree view.\n" +
58      "Check the info box besides the input field for more information.";
59    #endregion
60
61    #region Parameters
62    public IValueParameter<IRegressionProblemData> ProblemDataParameter => (IValueParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName];
63    public IFixedValueParameter<StructureTemplate> StructureTemplateParameter => (IFixedValueParameter<StructureTemplate>)Parameters[StructureTemplateParameterName];
64    public IValueParameter<ISymbolicDataAnalysisExpressionTreeInterpreter> InterpreterParameter => (IValueParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>)Parameters[InterpreterParameterName];
65    public IFixedValueParameter<DoubleLimit> EstimationLimitsParameter => (IFixedValueParameter<DoubleLimit>)Parameters[EstimationLimitsParameterName];
66    public IResultParameter<ISymbolicRegressionSolution> BestTrainingSolutionParameter => (IResultParameter<ISymbolicRegressionSolution>)Parameters[BestTrainingSolutionParameterName];
67
68    public IFixedValueParameter<BoolValue> ApplyLinearScalingParameter => (IFixedValueParameter<BoolValue>)Parameters[ApplyLinearScalingParameterName];
69    public IFixedValueParameter<BoolValue> OptimizeParametersParameter => (IFixedValueParameter<BoolValue>)Parameters[OptimizeParametersParameterName];
70    #endregion
71
72    #region Properties
73
74    public IRegressionProblemData ProblemData {
75      get => ProblemDataParameter.Value;
76      set {
77        ProblemDataParameter.Value = value;
78        ProblemDataChanged?.Invoke(this, EventArgs.Empty);
79      }
80    }
81
82    public StructureTemplate StructureTemplate => StructureTemplateParameter.Value;
83
84    public ISymbolicDataAnalysisExpressionTreeInterpreter Interpreter => InterpreterParameter.Value;
85
86    IParameter IDataAnalysisProblem.ProblemDataParameter => ProblemDataParameter;
87    IDataAnalysisProblemData IDataAnalysisProblem.ProblemData => ProblemData;
88
89    public DoubleLimit EstimationLimits => EstimationLimitsParameter.Value;
90
91    public bool ApplyLinearScaling {
92      get => ApplyLinearScalingParameter.Value.Value;
93      set => ApplyLinearScalingParameter.Value.Value = value;
94    }
95
96    public bool OptimizeParameters {
97      get => OptimizeParametersParameter.Value.Value;
98      set => OptimizeParametersParameter.Value.Value = value;
99    }
100
101    public override bool Maximization => false;
102    #endregion
103
104    #region EventHandlers
105    public event EventHandler ProblemDataChanged;
106    #endregion
107
108    #region Constructors & Cloning
109    public StructuredSymbolicRegressionSingleObjectiveProblem() {
110      var provider = new PhysicsInstanceProvider();
111      var descriptor = new SheetBendingProcess();
112      var problemData = provider.LoadData(descriptor);
113      var shapeConstraintProblemData = new ShapeConstrainedRegressionProblemData(problemData);
114
115      var structureTemplate = new StructureTemplate();
116
117      Parameters.Add(new ValueParameter<IRegressionProblemData>(
118        ProblemDataParameterName,
119        shapeConstraintProblemData));
120
121      Parameters.Add(new FixedValueParameter<StructureTemplate>(
122        StructureTemplateParameterName,
123        StructureTemplateDescriptionText,
124        structureTemplate));
125
126      Parameters.Add(new FixedValueParameter<BoolValue>(
127        ApplyLinearScalingParameterName, new BoolValue(true)
128        ));
129
130      Parameters.Add(new FixedValueParameter<BoolValue>(
131        OptimizeParametersParameterName, new BoolValue(true)
132        ));
133
134      Parameters.Add(new ValueParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>(
135        InterpreterParameterName,
136        new SymbolicDataAnalysisExpressionTreeBatchInterpreter()) { Hidden = true });
137      Parameters.Add(new FixedValueParameter<DoubleLimit>(
138        EstimationLimitsParameterName,
139        new DoubleLimit(double.NegativeInfinity, double.PositiveInfinity)) { Hidden = true });
140      Parameters.Add(new ResultParameter<ISymbolicRegressionSolution>(BestTrainingSolutionParameterName, "") { Hidden = true });
141
142      this.EvaluatorParameter.Hidden = true;
143
144      Operators.Add(new SymbolicDataAnalysisVariableFrequencyAnalyzer());
145      Operators.Add(new MinAverageMaxSymbolicExpressionTreeLengthAnalyzer());
146      Operators.Add(new SymbolicExpressionSymbolFrequencyAnalyzer());
147
148      RegisterEventHandlers();
149
150      StructureTemplate.ApplyLinearScaling = ApplyLinearScaling;
151      StructureTemplate.Template =
152        "(" +
153          "(210000 / (210000 + h)) * ((sigma_y * t * t) / (wR * Rt * t)) + " +
154          "PlasticHardening(_) - Elasticity(_)" +
155        ")" +
156        " * C(_)";
157    }
158
159    public StructuredSymbolicRegressionSingleObjectiveProblem(StructuredSymbolicRegressionSingleObjectiveProblem original, Cloner cloner) : base(original, cloner) {
160      RegisterEventHandlers();
161    }
162
163    public override IDeepCloneable Clone(Cloner cloner) =>
164      new StructuredSymbolicRegressionSingleObjectiveProblem(this, cloner);
165
166    [StorableConstructor]
167    protected StructuredSymbolicRegressionSingleObjectiveProblem(StorableConstructorFlag _) : base(_) { }
168
169
170    [StorableHook(HookType.AfterDeserialization)]
171    private void AfterDeserialization() {
172      if (!Parameters.ContainsKey(ApplyLinearScalingParameterName)) {
173        Parameters.Add(new FixedValueParameter<BoolValue>(ApplyLinearScalingParameterName, new BoolValue(StructureTemplate.ApplyLinearScaling)));
174      }
175
176      if (!Parameters.ContainsKey(OptimizeParametersParameterName)) {
177        Parameters.Add(new FixedValueParameter<BoolValue>(OptimizeParametersParameterName, new BoolValue(false)));
178      }
179
180      RegisterEventHandlers();
181    }
182
183    #endregion
184
185    private void RegisterEventHandlers() {
186      if (StructureTemplate != null) {
187        StructureTemplate.Changed += OnTemplateChanged;
188      }
189
190      ProblemDataParameter.ValueChanged += ProblemDataParameterValueChanged;
191      ApplyLinearScalingParameter.Value.ValueChanged += (o, e) => StructureTemplate.ApplyLinearScaling = ApplyLinearScaling;
192    }
193
194    private void ProblemDataParameterValueChanged(object sender, EventArgs e) {
195      StructureTemplate.Reset();
196      // InfoBox for Reset?
197    }
198
199    private void OnTemplateChanged(object sender, EventArgs args) {
200      ApplyLinearScaling = StructureTemplate.ApplyLinearScaling;
201      SetupEncoding();
202    }
203
204    private void SetupEncoding() {
205      foreach (var e in Encoding.Encodings.ToArray())
206        Encoding.Remove(e);
207
208
209      var templateNumberTreeNodes = StructureTemplate.Tree.IterateNodesPrefix().OfType<NumberTreeNode>();
210      if (templateNumberTreeNodes.Any()) {
211        var templateParameterValues = templateNumberTreeNodes.Select(n => n.Value).ToArray();
212        var encoding = new RealVectorEncoding(NumericParametersEncoding, templateParameterValues.Length);
213
214        var creator = encoding.Operators.OfType<NormalDistributedRealVectorCreator>().First();
215        creator.MeanParameter.Value = new RealVector(templateParameterValues);
216        creator.SigmaParameter.Value = new DoubleArray(templateParameterValues.Length);
217        encoding.SolutionCreator = creator;
218
219        Encoding.Add(encoding);
220      }
221
222      foreach (var subFunction in StructureTemplate.SubFunctions) {
223        subFunction.SetupVariables(ProblemData.AllowedInputVariables);
224        // prevent the same encoding twice
225        if (Encoding.Encodings.Any(x => x.Name == subFunction.Name)) continue;
226
227        var encoding = new SymbolicExpressionTreeEncoding(
228          subFunction.Name,
229          subFunction.Grammar,
230          subFunction.MaximumSymbolicExpressionTreeLength,
231          subFunction.MaximumSymbolicExpressionTreeDepth);
232        Encoding.Add(encoding);
233      }
234
235      //set single point crossover for numeric parameters
236      var multiCrossover = (IParameterizedItem)Encoding.Operators.OfType<MultiEncodingCrossover>().First();
237      foreach (var param in multiCrossover.Parameters.OfType<ConstrainedValueParameter<ICrossover>>()) {
238        var singlePointCrossover = param.ValidValues.OfType<SinglePointCrossover>().FirstOrDefault();
239        param.Value = singlePointCrossover ?? param.ValidValues.First();
240      }
241
242      //adapt crossover probability for subtree crossover
243      foreach (var param in multiCrossover.Parameters.OfType<ConstrainedValueParameter<ICrossover>>()) {
244        var subtreeCrossover = param.ValidValues.OfType<SubtreeCrossover>().FirstOrDefault();
245        if (subtreeCrossover != null) {
246          subtreeCrossover.CrossoverProbability = 1.0 / Encoding.Encodings.OfType<SymbolicExpressionTreeEncoding>().Count();
247          param.Value = subtreeCrossover;
248        }
249      }
250
251      //set multi manipulator as default manipulator for all symbolic expression tree encoding parts
252      var manipulator = (IParameterizedItem)Encoding.Operators.OfType<MultiEncodingManipulator>().First();
253      foreach (var param in manipulator.Parameters.OfType<ConstrainedValueParameter<IManipulator>>()) {
254        var m = param.ValidValues.OfType<MultiSymbolicExpressionTreeManipulator>().FirstOrDefault();
255        param.Value = m ?? param.ValidValues.First();
256      }
257    }
258
259    public override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) {
260      base.Analyze(individuals, qualities, results, random);
261
262      var best = GetBestIndividual(individuals, qualities).Item1;
263
264      if (!results.ContainsKey(BestTrainingSolutionParameter.ActualName)) {
265        results.Add(new Result(BestTrainingSolutionParameter.ActualName, typeof(SymbolicRegressionSolution)));
266      }
267
268      var tree = (ISymbolicExpressionTree)best[SymbolicExpressionTreeName];
269      var model = new SymbolicRegressionModel(ProblemData.TargetVariable, tree, Interpreter);
270      var solution = model.CreateRegressionSolution(ProblemData);
271
272      results[BestTrainingSolutionParameter.ActualName].Value = solution;
273    }
274
275
276    public override double Evaluate(Individual individual, IRandom random) {
277      var templateTree = StructureTemplate.Tree;
278      if (templateTree == null)
279        throw new ArgumentException("No structure template defined!");
280
281      var tree = BuildTreeFromIndividual(templateTree, individual, updateNumericParameters: StructureTemplate.ContainsNumericParameters);
282      individual[SymbolicExpressionTreeName] = tree;
283
284      if (OptimizeParameters) {
285        ParameterOptimization.OptimizeTreeParameters(ProblemData, tree, interpreter: Interpreter);
286      } else if (ApplyLinearScaling) {
287        LinearScaling.AdjustLinearScalingParams(ProblemData, tree, Interpreter);
288      }
289
290      UpdateIndividualFromTree(tree, individual, updateNumericParameters: StructureTemplate.ContainsNumericParameters);
291
292      //calculate NMSE
293      var estimatedValues = Interpreter.GetSymbolicExpressionTreeValues(tree, ProblemData.Dataset, ProblemData.TrainingIndices);
294      var boundedEstimatedValues = estimatedValues.LimitToRange(EstimationLimits.Lower, EstimationLimits.Upper);
295      var targetValues = ProblemData.TargetVariableTrainingValues;
296      var nmse = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(targetValues, boundedEstimatedValues, out var errorState);
297      if (errorState != OnlineCalculatorError.None)
298        nmse = 1.0;
299
300      //evaluate constraints
301      var constraints = Enumerable.Empty<ShapeConstraint>();
302      if (ProblemData is ShapeConstrainedRegressionProblemData scProbData)
303        constraints = scProbData.ShapeConstraints.EnabledConstraints;
304      if (constraints.Any()) {
305        var boundsEstimator = new IntervalArithBoundsEstimator();
306        var constraintViolations = IntervalUtil.GetConstraintViolations(constraints, boundsEstimator, ProblemData.VariableRanges, tree);
307
308        // infinite/NaN constraints
309        if (constraintViolations.Any(x => double.IsNaN(x) || double.IsInfinity(x)))
310          nmse = 1.0;
311
312        if (constraintViolations.Any(x => x > 0.0))
313          nmse = 1.0;
314      }
315
316      return nmse;
317    }
318
319    private static ISymbolicExpressionTree BuildTreeFromIndividual(ISymbolicExpressionTree template, Individual individual, bool updateNumericParameters) {
320      var resolvedTree = (ISymbolicExpressionTree)template.Clone();
321
322      //set numeric parameter values
323      if (updateNumericParameters) {
324        var realVector = individual.RealVector(NumericParametersEncoding);
325        var numberTreeNodes = resolvedTree.IterateNodesPrefix().OfType<NumberTreeNode>().ToArray();
326
327        if (realVector.Length != numberTreeNodes.Length)
328          throw new InvalidOperationException("The number of numeric parameters in the tree does not match the provided numerical values.");
329
330        for (int i = 0; i < numberTreeNodes.Length; i++)
331          numberTreeNodes[i].Value = realVector[i];
332      }
333
334      // build main tree
335      foreach (var subFunctionTreeNode in resolvedTree.IterateNodesPrefix().OfType<SubFunctionTreeNode>()) {
336        var subFunctionTree = individual.SymbolicExpressionTree(subFunctionTreeNode.Name);
337
338        // extract function tree
339        var subTree = subFunctionTree.Root.GetSubtree(0)  // StartSymbol
340                                          .GetSubtree(0); // First Symbol
341        subTree = (ISymbolicExpressionTreeNode)subTree.Clone();
342        subFunctionTreeNode.AddSubtree(subTree);
343      }
344      return resolvedTree;
345    }
346
347    private static void UpdateIndividualFromTree(ISymbolicExpressionTree tree, Individual individual, bool updateNumericParameters) {
348      var clonedTree = (ISymbolicExpressionTree)tree.Clone();
349
350      foreach (var subFunctionTreeNode in clonedTree.IterateNodesPrefix().OfType<SubFunctionTreeNode>()) {
351        var grammar = ((ISymbolicExpressionTree)individual[subFunctionTreeNode.Name]).Root.Grammar;
352        var functionTreeNode = subFunctionTreeNode.GetSubtree(0);
353        //remove function code to make numeric parameters extraction easier
354        subFunctionTreeNode.RemoveSubtree(0);
355
356
357        var rootNode = (SymbolicExpressionTreeTopLevelNode)new ProgramRootSymbol().CreateTreeNode();
358        rootNode.SetGrammar(grammar);
359
360        var startNode = (SymbolicExpressionTreeTopLevelNode)new StartSymbol().CreateTreeNode();
361        startNode.SetGrammar(grammar);
362
363        rootNode.AddSubtree(startNode);
364        startNode.AddSubtree(functionTreeNode);
365        var functionTree = new SymbolicExpressionTree(rootNode);
366        individual[subFunctionTreeNode.Name] = functionTree;
367      }
368
369      //set numeric parameter values
370      if (updateNumericParameters) {
371        var realVector = individual.RealVector(NumericParametersEncoding);
372        var numberTreeNodes = clonedTree.IterateNodesPrefix().OfType<NumberTreeNode>().ToArray();
373
374        if (realVector.Length != numberTreeNodes.Length)
375          throw new InvalidOperationException("The number of numeric parameters in the tree does not match the provided numerical values.");
376
377        for (int i = 0; i < numberTreeNodes.Length; i++)
378          realVector[i] = numberTreeNodes[i].Value;
379      }
380    }
381
382    public void Load(IRegressionProblemData data) {
383      ProblemData = data;
384    }
385  }
386}
Note: See TracBrowser for help on using the repository browser.