Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/StructureTemplate/StructureTemplate.cs @ 18188

Last change on this file since 18188 was 18188, checked in by mkommend, 23 months ago

#3136: Fixed backwards compatibility of StructureTemplate

File size: 6.8 KB
RevLine 
[18063]1using System;
[18146]2using System.Collections.Generic;
[18068]3using System.Linq;
[18063]4using HEAL.Attic;
5using HeuristicLab.Common;
[18146]6using HeuristicLab.Core;
[18063]7using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
8
9namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
10  [StorableType("E3C038DB-C6AA-457D-9F65-AF16C44CCE22")]
11  [Item("StructureTemplate", "Structure Template")]
12  public class StructureTemplate : Item {
13
[18065]14    #region Properties
[18063]15    [Storable]
[18075]16    private string template;
[18063]17    public string Template {
[18146]18      get => template;
[18063]19      set {
[18187]20        if (value == template) return;
21
[18068]22        template = value;
[18187]23        var parsedTree = Parser.Parse(template);
24        if (applyLinearScaling)
25          parsedTree = AddLinearScalingTerms(parsedTree);
26        Tree = parsedTree;
[18068]27        OnChanged();
[18146]28      }
[18063]29    }
30
[18188]31    private ISymbolicExpressionTree _oldTree;
32    [Storable(OldName = "treeWithoutLinearScaling")]
33    private ISymbolicExpressionTree _OldTreeW {
34      set => _oldTree = value;
35    }
36
[18063]37    [Storable]
[18187]38    private ISymbolicExpressionTree tree;
[18069]39    public ISymbolicExpressionTree Tree {
[18187]40      get => tree;
[18069]41      private set {
[18187]42        tree = value;
[18164]43
44        var newFunctions = GetSubFunctions();
[18187]45        var oldFunctions = subFunctions?.Intersect(newFunctions)
[18164]46                           ?? Enumerable.Empty<SubFunction>();
47        // adds new functions and keeps the old ones (if they match)
48        subFunctions = newFunctions.Except(oldFunctions).Concat(oldFunctions).ToList();
[18069]49      }
50    }
[18063]51
52    [Storable]
[18151]53    private IList<SubFunction> subFunctions = new List<SubFunction>();
54    public IEnumerable<SubFunction> SubFunctions => subFunctions;
[18063]55
[18069]56    [Storable]
[18075]57    private bool applyLinearScaling;
[18069]58    public bool ApplyLinearScaling {
59      get => applyLinearScaling;
60      set {
[18187]61        if (value == applyLinearScaling) return;
62
[18069]63        applyLinearScaling = value;
[18187]64        if (applyLinearScaling) Tree = AddLinearScalingTerms(Tree);
65        else Tree = RemoveLinearScalingTerms(Tree);
66
[18069]67        OnChanged();
68      }
69    }
70
[18063]71    protected InfixExpressionParser Parser { get; set; } = new InfixExpressionParser();
[18068]72
[18065]73    #endregion
[18063]74
[18065]75    #region Events
76    public event EventHandler Changed;
[18146]77
[18065]78    private void OnChanged() => Changed?.Invoke(this, EventArgs.Empty);
79    #endregion
[18063]80
81    #region Constructors
[18075]82    public StructureTemplate() {
83      Reset();
84    }
[18063]85
86    [StorableConstructor]
87    protected StructureTemplate(StorableConstructorFlag _) : base(_) { }
88
[18074]89    protected StructureTemplate(StructureTemplate original, Cloner cloner) : base(original, cloner) {
[18187]90      this.tree = cloner.Clone(original.tree);
91      this.template = original.Template;
92      this.applyLinearScaling = original.ApplyLinearScaling;
[18151]93      this.subFunctions = original.subFunctions.Select(cloner.Clone).ToList();
94      RegisterEventHandlers();
[18074]95    }
[18151]96
97
98    [StorableHook(HookType.AfterDeserialization)]
99    private void AfterDeserialization() {
[18188]100      if (Tree == null && _oldTree != null) {
101        if (ApplyLinearScaling) _oldTree = AddLinearScalingTerms(_oldTree);
102        Tree = _oldTree;
103        _oldTree = null;
104      }
105
[18151]106      RegisterEventHandlers();
107    }
[18063]108    #endregion
109
110    #region Cloning
111    public override IDeepCloneable Clone(Cloner cloner) =>
112      new StructureTemplate(this, cloner);
113    #endregion
114
[18075]115    public void Reset() {
[18151]116      subFunctions = new List<SubFunction>();
[18187]117      tree = null;
[18152]118      Template = "f(_)";
[18075]119    }
[18072]120
[18151]121    private IList<SubFunction> GetSubFunctions() {
122      var subFunctions = new List<SubFunction>();
[18069]123      foreach (var node in Tree.IterateNodesPrefix())
[18068]124        if (node is SubFunctionTreeNode subFunctionTreeNode) {
125          if (!subFunctionTreeNode.Arguments.Any())
126            throw new ArgumentException($"The sub-function '{subFunctionTreeNode}' requires inputs (e.g. {subFunctionTreeNode.Name}(var1, var2)).");
127
[18151]128          var existingSubFunction = subFunctions.Where(x => x.Name == subFunctionTreeNode.Name).FirstOrDefault();
129          if (existingSubFunction != null) {
[18187]130            // an existing subFunction must have the same signature
131            if (!existingSubFunction.Arguments.SequenceEqual(subFunctionTreeNode.Arguments))
[18068]132              throw new ArgumentException(
[18151]133                $"The sub-function '{existingSubFunction.Name}' has (at least two) different signatures " +
134                $"({existingSubFunction.Name}({string.Join(",", existingSubFunction.Arguments)}) <> " +
135                $"{subFunctionTreeNode.Name}({string.Join(",", subFunctionTreeNode.Arguments)})).");
[18068]136          } else {
137            var subFunction = new SubFunction() {
138              Name = subFunctionTreeNode.Name,
139              Arguments = subFunctionTreeNode.Arguments
140            };
141            subFunction.Changed += OnSubFunctionChanged;
[18151]142            subFunctions.Add(subFunction);
[18068]143          }
[18065]144        }
[18069]145      return subFunctions;
[18063]146    }
[18068]147
[18151]148    private void RegisterEventHandlers() {
[18187]149      foreach (var sf in SubFunctions) {
[18151]150        sf.Changed += OnSubFunctionChanged;
151      }
152    }
153
[18187]154    private static ISymbolicExpressionTree AddLinearScalingTerms(ISymbolicExpressionTree tree) {
[18069]155      var clonedTree = (ISymbolicExpressionTree)tree.Clone();
156      var startNode = clonedTree.Root.Subtrees.First();
157      var template = startNode.Subtrees.First();
158
[18187]159      var addNode = new Addition().CreateTreeNode();
160      var mulNode = new Multiplication().CreateTreeNode();
161      var offsetNode = new NumberTreeNode(0.0);
162      var scaleNode = new NumberTreeNode(1.0);
[18069]163
[18146]164      addNode.AddSubtree(offsetNode);
[18069]165      addNode.AddSubtree(mulNode);
[18146]166      mulNode.AddSubtree(scaleNode);
167
[18069]168      startNode.RemoveSubtree(0);
169      startNode.AddSubtree(addNode);
170      mulNode.AddSubtree(template);
171      return clonedTree;
172    }
173
[18187]174    private static ISymbolicExpressionTree RemoveLinearScalingTerms(ISymbolicExpressionTree tree) {
175      var clonedTree = (ISymbolicExpressionTree)tree.Clone();
176      var startNode = clonedTree.Root.Subtrees.First();
177
178      //check for scaling terms
179      var addNode = startNode.GetSubtree(0);
180      var offsetNode = addNode.GetSubtree(0);
181      var mulNode = addNode.GetSubtree(1);
182      var scaleNode = mulNode.GetSubtree(0);
183      var templateNode = mulNode.GetSubtree(1);
184
185      var error = false;
186      if (addNode.Symbol is not Addition) error = true;
187      if (mulNode.Symbol is not Multiplication) error = true;
188      if (offsetNode is not NumberTreeNode offset || offset.Value != 0.0) error = true;
189      if (scaleNode is not NumberTreeNode scale || scale.Value != 1.0) error = true;
190      if (error) throw new ArgumentException("Scaling terms cannot be found.");
191
192      startNode.RemoveSubtree(0);
193      startNode.AddSubtree(templateNode);
194
195      return clonedTree;
196    }
197
[18068]198    private void OnSubFunctionChanged(object sender, EventArgs e) => OnChanged();
[18063]199  }
200}
Note: See TracBrowser for help on using the repository browser.