Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs @ 8694

Last change on this file since 8694 was 7696, checked in by gkronber, 13 years ago

#1810 implemented a number of additional special functions from alglib

File size: 39.6 KB
RevLine 
[5571]1#region License Information
2/* HeuristicLab
[7259]3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[5571]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.Encodings.SymbolicExpressionTreeEncoding;
27
28namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
29  /// <summary>
30  /// Simplifier for symbolic expressions
31  /// </summary>
32  public class SymbolicDataAnalysisExpressionTreeSimplifier {
33    private Addition addSymbol = new Addition();
34    private Subtraction subSymbol = new Subtraction();
35    private Multiplication mulSymbol = new Multiplication();
36    private Division divSymbol = new Division();
37    private Constant constSymbol = new Constant();
38    private Variable varSymbol = new Variable();
39    private Logarithm logSymbol = new Logarithm();
40    private Exponential expSymbol = new Exponential();
41    private Root rootSymbol = new Root();
[7695]42    private Square sqrSymbol = new Square();
43    private SquareRoot sqrtSymbol = new SquareRoot();
[5571]44    private Power powSymbol = new Power();
45    private Sine sineSymbol = new Sine();
46    private Cosine cosineSymbol = new Cosine();
47    private Tangent tanSymbol = new Tangent();
48    private IfThenElse ifThenElseSymbol = new IfThenElse();
49    private And andSymbol = new And();
50    private Or orSymbol = new Or();
51    private Not notSymbol = new Not();
52    private GreaterThan gtSymbol = new GreaterThan();
53    private LessThan ltSymbol = new LessThan();
54
55    public ISymbolicExpressionTree Simplify(ISymbolicExpressionTree originalTree) {
56      var clone = (ISymbolicExpressionTreeNode)originalTree.Root.Clone();
57      // macro expand (initially no argument trees)
[5733]58      var macroExpandedTree = MacroExpand(clone, clone.GetSubtree(0), new List<ISymbolicExpressionTreeNode>());
[5571]59      ISymbolicExpressionTreeNode rootNode = (new ProgramRootSymbol()).CreateTreeNode();
[5733]60      rootNode.AddSubtree(GetSimplifiedTree(macroExpandedTree));
[5571]61      return new SymbolicExpressionTree(rootNode);
62    }
63
64    // the argumentTrees list contains already expanded trees used as arguments for invocations
65    private ISymbolicExpressionTreeNode MacroExpand(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node, IList<ISymbolicExpressionTreeNode> argumentTrees) {
[5733]66      List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
[6803]67      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
[5571]68      if (node.Symbol is InvokeFunction) {
69        var invokeSym = node.Symbol as InvokeFunction;
70        var defunNode = FindFunctionDefinition(root, invokeSym.FunctionName);
71        var macroExpandedArguments = new List<ISymbolicExpressionTreeNode>();
72        foreach (var subtree in subtrees) {
73          macroExpandedArguments.Add(MacroExpand(root, subtree, argumentTrees));
74        }
75        return MacroExpand(root, defunNode, macroExpandedArguments);
76      } else if (node.Symbol is Argument) {
77        var argSym = node.Symbol as Argument;
78        // return the correct argument sub-tree (already macro-expanded)
79        return (SymbolicExpressionTreeNode)argumentTrees[argSym.ArgumentIndex].Clone();
80      } else {
81        // recursive application
82        foreach (var subtree in subtrees) {
[5733]83          node.AddSubtree(MacroExpand(root, subtree, argumentTrees));
[5571]84        }
85        return node;
86      }
87    }
88
89    private ISymbolicExpressionTreeNode FindFunctionDefinition(ISymbolicExpressionTreeNode root, string functionName) {
[5733]90      foreach (var subtree in root.Subtrees.OfType<DefunTreeNode>()) {
91        if (subtree.FunctionName == functionName) return subtree.GetSubtree(0);
[5571]92      }
93
94      throw new ArgumentException("Definition of function " + functionName + " not found.");
95    }
96
97
98    #region symbol predicates
99    // arithmetic
100    private bool IsDivision(ISymbolicExpressionTreeNode node) {
101      return node.Symbol is Division;
102    }
103
104    private bool IsMultiplication(ISymbolicExpressionTreeNode node) {
105      return node.Symbol is Multiplication;
106    }
107
108    private bool IsSubtraction(ISymbolicExpressionTreeNode node) {
109      return node.Symbol is Subtraction;
110    }
111
112    private bool IsAddition(ISymbolicExpressionTreeNode node) {
113      return node.Symbol is Addition;
114    }
115
116    private bool IsAverage(ISymbolicExpressionTreeNode node) {
117      return node.Symbol is Average;
118    }
119    // exponential
120    private bool IsLog(ISymbolicExpressionTreeNode node) {
121      return node.Symbol is Logarithm;
122    }
123    private bool IsExp(ISymbolicExpressionTreeNode node) {
124      return node.Symbol is Exponential;
125    }
126    private bool IsRoot(ISymbolicExpressionTreeNode node) {
127      return node.Symbol is Root;
128    }
[7695]129    private bool IsSquare(ISymbolicExpressionTreeNode node) {
130      return node.Symbol is Square;
131    }
132    private bool IsSquareRoot(ISymbolicExpressionTreeNode node) {
133      return node.Symbol is SquareRoot;
134    }
[5571]135    private bool IsPower(ISymbolicExpressionTreeNode node) {
136      return node.Symbol is Power;
137    }
138    // trigonometric
139    private bool IsSine(ISymbolicExpressionTreeNode node) {
140      return node.Symbol is Sine;
141    }
142    private bool IsCosine(ISymbolicExpressionTreeNode node) {
143      return node.Symbol is Cosine;
144    }
145    private bool IsTangent(ISymbolicExpressionTreeNode node) {
146      return node.Symbol is Tangent;
147    }
148    // boolean
149    private bool IsIfThenElse(ISymbolicExpressionTreeNode node) {
150      return node.Symbol is IfThenElse;
151    }
152    private bool IsAnd(ISymbolicExpressionTreeNode node) {
153      return node.Symbol is And;
154    }
155    private bool IsOr(ISymbolicExpressionTreeNode node) {
156      return node.Symbol is Or;
157    }
158    private bool IsNot(ISymbolicExpressionTreeNode node) {
159      return node.Symbol is Not;
160    }
161    // comparison
162    private bool IsGreaterThan(ISymbolicExpressionTreeNode node) {
163      return node.Symbol is GreaterThan;
164    }
165    private bool IsLessThan(ISymbolicExpressionTreeNode node) {
166      return node.Symbol is LessThan;
167    }
168
169    private bool IsBoolean(ISymbolicExpressionTreeNode node) {
170      return
171        node.Symbol is GreaterThan ||
172        node.Symbol is LessThan ||
173        node.Symbol is And ||
174        node.Symbol is Or;
175    }
176
177    // terminals
178    private bool IsVariable(ISymbolicExpressionTreeNode node) {
179      return node.Symbol is Variable;
180    }
181
182    private bool IsConstant(ISymbolicExpressionTreeNode node) {
183      return node.Symbol is Constant;
184    }
185
186    #endregion
187
188    /// <summary>
189    /// Creates a new simplified tree
190    /// </summary>
191    /// <param name="original"></param>
192    /// <returns></returns>
193    public ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
194      if (IsConstant(original) || IsVariable(original)) {
195        return (ISymbolicExpressionTreeNode)original.Clone();
196      } else if (IsAddition(original)) {
197        return SimplifyAddition(original);
198      } else if (IsSubtraction(original)) {
199        return SimplifySubtraction(original);
200      } else if (IsMultiplication(original)) {
201        return SimplifyMultiplication(original);
202      } else if (IsDivision(original)) {
203        return SimplifyDivision(original);
204      } else if (IsAverage(original)) {
205        return SimplifyAverage(original);
206      } else if (IsLog(original)) {
207        return SimplifyLog(original);
208      } else if (IsExp(original)) {
209        return SimplifyExp(original);
[7695]210      } else if (IsSquare(original)) {
211        return SimplifySquare(original);
212      } else if (IsSquareRoot(original)) {
213        return SimplifySquareRoot(original);
214      } else if (IsPower(original)) {
215        return SimplifyPower(original);
[5571]216      } else if (IsRoot(original)) {
217        return SimplifyRoot(original);
218      } else if (IsSine(original)) {
219        return SimplifySine(original);
220      } else if (IsCosine(original)) {
221        return SimplifyCosine(original);
222      } else if (IsTangent(original)) {
223        return SimplifyTangent(original);
224      } else if (IsIfThenElse(original)) {
225        return SimplifyIfThenElse(original);
226      } else if (IsGreaterThan(original)) {
227        return SimplifyGreaterThan(original);
228      } else if (IsLessThan(original)) {
229        return SimplifyLessThan(original);
230      } else if (IsAnd(original)) {
231        return SimplifyAnd(original);
232      } else if (IsOr(original)) {
233        return SimplifyOr(original);
234      } else if (IsNot(original)) {
235        return SimplifyNot(original);
236      } else {
237        return SimplifyAny(original);
238      }
239    }
240
241
242    #region specific simplification routines
243    private ISymbolicExpressionTreeNode SimplifyAny(ISymbolicExpressionTreeNode original) {
244      // can't simplify this function but simplify all subtrees
[5733]245      List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(original.Subtrees);
246      while (original.Subtrees.Count() > 0) original.RemoveSubtree(0);
[5571]247      var clone = (SymbolicExpressionTreeNode)original.Clone();
[5733]248      List<ISymbolicExpressionTreeNode> simplifiedSubtrees = new List<ISymbolicExpressionTreeNode>();
249      foreach (var subtree in subtrees) {
250        simplifiedSubtrees.Add(GetSimplifiedTree(subtree));
251        original.AddSubtree(subtree);
[5571]252      }
[5733]253      foreach (var simplifiedSubtree in simplifiedSubtrees) {
254        clone.AddSubtree(simplifiedSubtree);
[5571]255      }
[5733]256      if (simplifiedSubtrees.TrueForAll(t => IsConstant(t))) {
[5571]257        SimplifyConstantExpression(clone);
258      }
259      return clone;
260    }
261
262    private ISymbolicExpressionTreeNode SimplifyConstantExpression(ISymbolicExpressionTreeNode original) {
263      // not yet implemented
264      return original;
265    }
266
267    private ISymbolicExpressionTreeNode SimplifyAverage(ISymbolicExpressionTreeNode original) {
[5733]268      if (original.Subtrees.Count() == 1) {
269        return GetSimplifiedTree(original.GetSubtree(0));
[5571]270      } else {
271        // simplify expressions x0..xn
272        // make sum(x0..xn) / n
[5733]273        var sum = original.Subtrees
[5571]274          .Select(x => GetSimplifiedTree(x))
275          .Aggregate((a, b) => MakeSum(a, b));
[5733]276        return MakeFraction(sum, MakeConstant(original.Subtrees.Count()));
[5571]277      }
278    }
279
280    private ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
[5733]281      if (original.Subtrees.Count() == 1) {
282        return Invert(GetSimplifiedTree(original.GetSubtree(0)));
[5571]283      } else {
284        // simplify expressions x0..xn
285        // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
[5733]286        var simplifiedTrees = original.Subtrees.Select(x => GetSimplifiedTree(x));
[5571]287        return
288          MakeProduct(simplifiedTrees.First(), Invert(simplifiedTrees.Skip(1).Aggregate((a, b) => MakeProduct(a, b))));
289      }
290    }
291
292    private ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
[5733]293      if (original.Subtrees.Count() == 1) {
294        return GetSimplifiedTree(original.GetSubtree(0));
[5571]295      } else {
[5733]296        return original.Subtrees
[5571]297          .Select(x => GetSimplifiedTree(x))
298          .Aggregate((a, b) => MakeProduct(a, b));
299      }
300    }
301
302    private ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
[5733]303      if (original.Subtrees.Count() == 1) {
304        return Negate(GetSimplifiedTree(original.GetSubtree(0)));
[5571]305      } else {
306        // simplify expressions x0..xn
307        // make addition (x0,-x1..-xn)
[5733]308        var simplifiedTrees = original.Subtrees.Select(x => GetSimplifiedTree(x));
[5571]309        return simplifiedTrees.Take(1)
310          .Concat(simplifiedTrees.Skip(1).Select(x => Negate(x)))
311          .Aggregate((a, b) => MakeSum(a, b));
312      }
313    }
314
315    private ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
[5733]316      if (original.Subtrees.Count() == 1) {
317        return GetSimplifiedTree(original.GetSubtree(0));
[5571]318      } else {
319        // simplify expression x0..xn
320        // make addition (x0..xn)
[5733]321        return original.Subtrees
[5571]322          .Select(x => GetSimplifiedTree(x))
323          .Aggregate((a, b) => MakeSum(a, b));
324      }
325    }
326
327    private ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
[5733]328      return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
[5571]329    }
330    private ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
[5733]331      return original.Subtrees
[5571]332        .Select(x => GetSimplifiedTree(x))
333        .Aggregate((a, b) => MakeOr(a, b));
334    }
335    private ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
[5733]336      return original.Subtrees
[5571]337        .Select(x => GetSimplifiedTree(x))
338        .Aggregate((a, b) => MakeAnd(a, b));
339    }
340    private ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
[5733]341      return MakeLessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
[5571]342    }
343    private ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
[5733]344      return MakeGreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
[5571]345    }
346    private ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
[5733]347      return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)), GetSimplifiedTree(original.GetSubtree(2)));
[5571]348    }
349    private ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
[5733]350      return MakeTangent(GetSimplifiedTree(original.GetSubtree(0)));
[5571]351    }
352    private ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
[5733]353      return MakeCosine(GetSimplifiedTree(original.GetSubtree(0)));
[5571]354    }
355    private ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
[5733]356      return MakeSine(GetSimplifiedTree(original.GetSubtree(0)));
[5571]357    }
358    private ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
[5733]359      return MakeExp(GetSimplifiedTree(original.GetSubtree(0)));
[5571]360    }
[7695]361    private ISymbolicExpressionTreeNode SimplifySquare(ISymbolicExpressionTreeNode original) {
362      return MakeSquare(GetSimplifiedTree(original.GetSubtree(0)));
363    }
364    private ISymbolicExpressionTreeNode SimplifySquareRoot(ISymbolicExpressionTreeNode original) {
365      return MakeSquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
366    }
[5571]367
368    private ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
[5733]369      return MakeLog(GetSimplifiedTree(original.GetSubtree(0)));
[5571]370    }
371    private ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
[5733]372      return MakeRoot(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
[5571]373    }
374
375    private ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
[5733]376      return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
[5571]377    }
378    #endregion
379
380    #region low level tree restructuring
381    private ISymbolicExpressionTreeNode MakeNot(ISymbolicExpressionTreeNode t) {
[5574]382      if (IsConstant(t)) {
[5571]383        var constNode = t as ConstantTreeNode;
[5574]384        if (constNode.Value > 0) return MakeConstant(-1.0);
385        else return MakeConstant(1.0);
386      } else if (IsNot(t)) {
[5733]387        return t.GetSubtree(0);
[5574]388      } else if (!IsBoolean(t)) {
[5571]389        var gtNode = gtSymbol.CreateTreeNode();
[5733]390        gtNode.AddSubtree(t); gtNode.AddSubtree(MakeConstant(0.0));
[5574]391        var notNode = notSymbol.CreateTreeNode();
[5733]392        notNode.AddSubtree(gtNode);
[5574]393        return notNode;
394      } else {
395        var notNode = notSymbol.CreateTreeNode();
[5733]396        notNode.AddSubtree(t);
[5574]397        return notNode;
398      }
[5571]399    }
400
401    private ISymbolicExpressionTreeNode MakeOr(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
402      if (IsConstant(a) && IsConstant(b)) {
403        var constA = a as ConstantTreeNode;
404        var constB = b as ConstantTreeNode;
405        if (constA.Value > 0.0 || constB.Value > 0.0) {
406          return MakeConstant(1.0);
407        } else {
408          return MakeConstant(-1.0);
409        }
410      } else if (IsConstant(a)) {
411        return MakeOr(b, a);
412      } else if (IsConstant(b)) {
413        var constT = b as ConstantTreeNode;
414        if (constT.Value > 0.0) {
415          // boolean expression is necessarily true
416          return MakeConstant(1.0);
417        } else {
418          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
419          var orNode = orSymbol.CreateTreeNode();
[5733]420          orNode.AddSubtree(a);
[5571]421          return orNode;
422        }
423      } else {
424        var orNode = orSymbol.CreateTreeNode();
[5733]425        orNode.AddSubtree(a);
426        orNode.AddSubtree(b);
[5571]427        return orNode;
428      }
429    }
430    private ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
431      if (IsConstant(a) && IsConstant(b)) {
432        var constA = a as ConstantTreeNode;
433        var constB = b as ConstantTreeNode;
434        if (constA.Value > 0.0 && constB.Value > 0.0) {
435          return MakeConstant(1.0);
436        } else {
437          return MakeConstant(-1.0);
438        }
439      } else if (IsConstant(a)) {
440        return MakeAnd(b, a);
441      } else if (IsConstant(b)) {
442        var constB = b as ConstantTreeNode;
443        if (constB.Value > 0.0) {
444          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
445          var andNode = andSymbol.CreateTreeNode();
[5733]446          andNode.AddSubtree(a);
[5571]447          return andNode;
448        } else {
449          // boolean expression is necessarily false
450          return MakeConstant(-1.0);
451        }
452      } else {
453        var andNode = andSymbol.CreateTreeNode();
[5733]454        andNode.AddSubtree(a);
455        andNode.AddSubtree(b);
[5571]456        return andNode;
457      }
458    }
459    private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
460      if (IsConstant(leftSide) && IsConstant(rightSide)) {
461        var lsConst = leftSide as ConstantTreeNode;
462        var rsConst = rightSide as ConstantTreeNode;
463        if (lsConst.Value < rsConst.Value) return MakeConstant(1.0);
464        else return MakeConstant(-1.0);
465      } else {
466        var ltNode = ltSymbol.CreateTreeNode();
[5733]467        ltNode.AddSubtree(leftSide);
468        ltNode.AddSubtree(rightSide);
[5571]469        return ltNode;
470      }
471    }
472    private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
473      if (IsConstant(leftSide) && IsConstant(rightSide)) {
474        var lsConst = leftSide as ConstantTreeNode;
475        var rsConst = rightSide as ConstantTreeNode;
476        if (lsConst.Value > rsConst.Value) return MakeConstant(1.0);
477        else return MakeConstant(-1.0);
478      } else {
479        var gtNode = gtSymbol.CreateTreeNode();
[5733]480        gtNode.AddSubtree(leftSide);
481        gtNode.AddSubtree(rightSide);
[5571]482        return gtNode;
483      }
484    }
485    private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition, ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
486      if (IsConstant(condition)) {
487        var constT = condition as ConstantTreeNode;
488        if (constT.Value > 0.0) return trueBranch;
489        else return falseBranch;
490      } else {
491        var ifNode = ifThenElseSymbol.CreateTreeNode();
492        if (IsBoolean(condition)) {
[5733]493          ifNode.AddSubtree(condition);
[5571]494        } else {
495          var gtNode = gtSymbol.CreateTreeNode();
[5733]496          gtNode.AddSubtree(condition); gtNode.AddSubtree(MakeConstant(0.0));
497          ifNode.AddSubtree(gtNode);
[5571]498        }
[5733]499        ifNode.AddSubtree(trueBranch);
500        ifNode.AddSubtree(falseBranch);
[5571]501        return ifNode;
502      }
503    }
504
505    private ISymbolicExpressionTreeNode MakeSine(ISymbolicExpressionTreeNode node) {
506      if (IsConstant(node)) {
507        var constT = node as ConstantTreeNode;
508        return MakeConstant(Math.Sin(constT.Value));
509      } else {
510        var sineNode = sineSymbol.CreateTreeNode();
[5733]511        sineNode.AddSubtree(node);
[5571]512        return sineNode;
513      }
514    }
515    private ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
516      if (IsConstant(node)) {
517        var constT = node as ConstantTreeNode;
518        return MakeConstant(Math.Tan(constT.Value));
519      } else {
520        var tanNode = tanSymbol.CreateTreeNode();
[5733]521        tanNode.AddSubtree(node);
[5571]522        return tanNode;
523      }
524    }
525    private ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
526      if (IsConstant(node)) {
527        var constT = node as ConstantTreeNode;
528        return MakeConstant(Math.Cos(constT.Value));
529      } else {
530        var cosNode = cosineSymbol.CreateTreeNode();
[5733]531        cosNode.AddSubtree(node);
[5571]532        return cosNode;
533      }
534    }
535    private ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
536      if (IsConstant(node)) {
537        var constT = node as ConstantTreeNode;
538        return MakeConstant(Math.Exp(constT.Value));
539      } else if (IsLog(node)) {
[5733]540        return node.GetSubtree(0);
[5571]541      } else if (IsAddition(node)) {
[5733]542        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, t));
[5571]543      } else if (IsSubtraction(node)) {
[5733]544        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, Negate(t)));
[5571]545      } else {
546        var expNode = expSymbol.CreateTreeNode();
[5733]547        expNode.AddSubtree(node);
[5571]548        return expNode;
549      }
550    }
[7695]551
552    private ISymbolicExpressionTreeNode MakeSquare(ISymbolicExpressionTreeNode node) {
553      if (IsConstant(node)) {
554        var constT = node as ConstantTreeNode;
555        return MakeConstant(constT.Value * constT.Value);
556      } else if (IsSquareRoot(node)) {
557        return node.GetSubtree(0);
558      } else {
559        var sqrNode = sqrSymbol.CreateTreeNode();
560        sqrNode.AddSubtree(node);
561        return sqrNode;
562      }
563    }
564    private ISymbolicExpressionTreeNode MakeSquareRoot(ISymbolicExpressionTreeNode node) {
565      if (IsConstant(node)) {
566        var constT = node as ConstantTreeNode;
567        return MakeConstant(Math.Sqrt(constT.Value));
568      } else if (IsSquare(node)) {
569        return node.GetSubtree(0);
570      } else {
571        var sqrtNode = sqrtSymbol.CreateTreeNode();
572        sqrtNode.AddSubtree(node);
573        return sqrtNode;
574      }
575    }
576
[5571]577    private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
578      if (IsConstant(node)) {
579        var constT = node as ConstantTreeNode;
580        return MakeConstant(Math.Log(constT.Value));
581      } else if (IsExp(node)) {
[5733]582        return node.GetSubtree(0);
[7696]583      } else if (IsSquareRoot(node)) {
584        return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
[5571]585      } else {
586        var logNode = logSymbol.CreateTreeNode();
[5733]587        logNode.AddSubtree(node);
[5571]588        return logNode;
589      }
590    }
591    private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
592      if (IsConstant(a) && IsConstant(b)) {
593        var constA = a as ConstantTreeNode;
594        var constB = b as ConstantTreeNode;
595        return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
596      } else if (IsConstant(b)) {
597        var constB = b as ConstantTreeNode;
598        var constBValue = Math.Round(constB.Value);
599        if (constBValue.IsAlmost(1.0)) {
600          return a;
601        } else if (constBValue.IsAlmost(0.0)) {
602          return MakeConstant(1.0);
603        } else if (constBValue.IsAlmost(-1.0)) {
604          return MakeFraction(MakeConstant(1.0), a);
605        } else if (constBValue < 0) {
606          var rootNode = rootSymbol.CreateTreeNode();
[5733]607          rootNode.AddSubtree(a);
608          rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
[5571]609          return MakeFraction(MakeConstant(1.0), rootNode);
610        } else {
611          var rootNode = rootSymbol.CreateTreeNode();
[5733]612          rootNode.AddSubtree(a);
613          rootNode.AddSubtree(MakeConstant(constBValue));
[5571]614          return rootNode;
615        }
616      } else {
617        var rootNode = rootSymbol.CreateTreeNode();
[5733]618        rootNode.AddSubtree(a);
619        rootNode.AddSubtree(b);
[5571]620        return rootNode;
621      }
622    }
623    private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
624      if (IsConstant(a) && IsConstant(b)) {
625        var constA = a as ConstantTreeNode;
626        var constB = b as ConstantTreeNode;
627        return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
628      } else if (IsConstant(b)) {
629        var constB = b as ConstantTreeNode;
630        double exponent = Math.Round(constB.Value);
631        if (exponent.IsAlmost(0.0)) {
632          return MakeConstant(1.0);
633        } else if (exponent.IsAlmost(1.0)) {
634          return a;
635        } else if (exponent.IsAlmost(-1.0)) {
636          return MakeFraction(MakeConstant(1.0), a);
637        } else if (exponent < 0) {
638          var powNode = powSymbol.CreateTreeNode();
[5733]639          powNode.AddSubtree(a);
640          powNode.AddSubtree(MakeConstant(-1.0 * exponent));
[5571]641          return MakeFraction(MakeConstant(1.0), powNode);
642        } else {
643          var powNode = powSymbol.CreateTreeNode();
[5733]644          powNode.AddSubtree(a);
645          powNode.AddSubtree(MakeConstant(exponent));
[5571]646          return powNode;
647        }
648      } else {
649        var powNode = powSymbol.CreateTreeNode();
[5733]650        powNode.AddSubtree(a);
651        powNode.AddSubtree(b);
[5571]652        return powNode;
653      }
654    }
655
656
657    // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
658    private ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
659      if (IsConstant(a) && IsConstant(b)) {
660        // fold constants
661        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
662      } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) {
663        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
664      } else if (IsVariable(a) && IsConstant(b)) {
665        // merge constant values into variable weights
666        var constB = ((ConstantTreeNode)b).Value;
667        ((VariableTreeNode)a).Weight /= constB;
668        return a;
669      } else if (IsVariable(a) && IsVariable(b) && AreSameVariable(a, b)) {
670        // cancel variables
671        var aVar = a as VariableTreeNode;
672        var bVar = b as VariableTreeNode;
673        return MakeConstant(aVar.Weight / bVar.Weight);
674      } else if (IsAddition(a) && IsConstant(b)) {
[5733]675        return a.Subtrees
[5571]676          .Select(x => GetSimplifiedTree(x))
677         .Select(x => MakeFraction(x, b))
678         .Aggregate((c, d) => MakeSum(c, d));
679      } else if (IsMultiplication(a) && IsConstant(b)) {
680        return MakeProduct(a, Invert(b));
681      } else if (IsDivision(a) && IsConstant(b)) {
682        // (a1 / a2) / c => (a1 / (a2 * c))
[5733]683        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
[5571]684      } else if (IsDivision(a) && IsDivision(b)) {
685        // (a1 / a2) / (b1 / b2) =>
[5733]686        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
[5571]687      } else if (IsDivision(a)) {
688        // (a1 / a2) / b => (a1 / (a2 * b))
[5733]689        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
[5571]690      } else if (IsDivision(b)) {
691        // a / (b1 / b2) => (a * b2) / b1
[5733]692        return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
[5571]693      } else {
694        var div = divSymbol.CreateTreeNode();
[5733]695        div.AddSubtree(a);
696        div.AddSubtree(b);
[5571]697        return div;
698      }
699    }
700
701    private ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
702      if (IsConstant(a) && IsConstant(b)) {
703        // fold constants
704        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
705        return a;
706      } else if (IsConstant(a)) {
707        // c + x => x + c
708        // b is not constant => make sure constant is on the right
709        return MakeSum(b, a);
710      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
711        // x + 0 => x
712        return a;
713      } else if (IsAddition(a) && IsAddition(b)) {
714        // merge additions
715        var add = addSymbol.CreateTreeNode();
716        // add all sub trees except for the last
[5733]717        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
718        for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
719        if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
720          add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
721        } else if (IsConstant(a.Subtrees.Last())) {
722          add.AddSubtree(b.Subtrees.Last());
723          add.AddSubtree(a.Subtrees.Last());
[5571]724        } else {
[5733]725          add.AddSubtree(a.Subtrees.Last());
726          add.AddSubtree(b.Subtrees.Last());
[5571]727        }
728        MergeVariablesInSum(add);
[5733]729        if (add.Subtrees.Count() == 1) {
730          return add.GetSubtree(0);
[5571]731        } else {
732          return add;
733        }
734      } else if (IsAddition(b)) {
735        return MakeSum(b, a);
736      } else if (IsAddition(a) && IsConstant(b)) {
737        // a is an addition and b is a constant => append b to a and make sure the constants are merged
738        var add = addSymbol.CreateTreeNode();
739        // add all sub trees except for the last
[5733]740        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
741        if (IsConstant(a.Subtrees.Last()))
742          add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
[5571]743        else {
[5733]744          add.AddSubtree(a.Subtrees.Last());
745          add.AddSubtree(b);
[5571]746        }
747        return add;
748      } else if (IsAddition(a)) {
749        // a is already an addition => append b
750        var add = addSymbol.CreateTreeNode();
[5733]751        add.AddSubtree(b);
752        foreach (var subtree in a.Subtrees) {
753          add.AddSubtree(subtree);
[5571]754        }
755        MergeVariablesInSum(add);
[5733]756        if (add.Subtrees.Count() == 1) {
757          return add.GetSubtree(0);
[5571]758        } else {
759          return add;
760        }
761      } else {
762        var add = addSymbol.CreateTreeNode();
[5733]763        add.AddSubtree(a);
764        add.AddSubtree(b);
[5571]765        MergeVariablesInSum(add);
[5733]766        if (add.Subtrees.Count() == 1) {
767          return add.GetSubtree(0);
[5571]768        } else {
769          return add;
770        }
771      }
772    }
773
774    // makes sure variable symbols in sums are combined
775    // possible improvement: combine sums of products where the products only reference the same variable
776    private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
[5733]777      var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
778      while (sum.Subtrees.Count() > 0) sum.RemoveSubtree(0);
[5571]779      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
780                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
781                            group node by node.VariableName + lag into g
782                            select g;
[5733]783      var unchangedSubtrees = subtrees.Where(t => !(t is VariableTreeNode));
[5571]784
785      foreach (var variableNodeGroup in groupedVarNodes) {
786        var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
787        var representative = variableNodeGroup.First();
788        representative.Weight = weightSum;
[5733]789        sum.AddSubtree(representative);
[5571]790      }
[5733]791      foreach (var unchangedSubtree in unchangedSubtrees)
792        sum.AddSubtree(unchangedSubtree);
[5571]793    }
794
795
796    private ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
797      if (IsConstant(a) && IsConstant(b)) {
798        // fold constants
799        ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
800        return a;
801      } else if (IsConstant(a)) {
802        // a * $ => $ * a
803        return MakeProduct(b, a);
804      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
805        // $ * 1.0 => $
806        return a;
807      } else if (IsConstant(b) && IsVariable(a)) {
808        // multiply constants into variables weights
809        ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value;
810        return a;
811      } else if (IsConstant(b) && IsAddition(a)) {
812        // multiply constants into additions
[5733]813        return a.Subtrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d));
[5571]814      } else if (IsDivision(a) && IsDivision(b)) {
815        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
[5733]816        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
[5571]817      } else if (IsDivision(a)) {
818        // (a1 / a2) * b => (a1 * b) / a2
[5733]819        return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
[5571]820      } else if (IsDivision(b)) {
821        // a * (b1 / b2) => (b1 * a) / b2
[5733]822        return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
[5571]823      } else if (IsMultiplication(a) && IsMultiplication(b)) {
824        // merge multiplications (make sure constants are merged)
825        var mul = mulSymbol.CreateTreeNode();
[5733]826        for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
827        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
[5571]828        MergeVariablesAndConstantsInProduct(mul);
829        return mul;
830      } else if (IsMultiplication(b)) {
831        return MakeProduct(b, a);
832      } else if (IsMultiplication(a)) {
833        // a is already an multiplication => append b
[5733]834        a.AddSubtree(b);
[5571]835        MergeVariablesAndConstantsInProduct(a);
836        return a;
837      } else {
838        var mul = mulSymbol.CreateTreeNode();
[5733]839        mul.AddSubtree(a);
840        mul.AddSubtree(b);
[5571]841        MergeVariablesAndConstantsInProduct(mul);
842        return mul;
843      }
844    }
845    #endregion
846
847
848    #region helper functions
849
850    private bool AreSameVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
851      var aLaggedVar = a as LaggedVariableTreeNode;
852      var bLaggedVar = b as LaggedVariableTreeNode;
853      if (aLaggedVar != null && bLaggedVar != null) {
854        return aLaggedVar.VariableName == bLaggedVar.VariableName &&
855          aLaggedVar.Lag == bLaggedVar.Lag;
856      }
857      var aVar = a as VariableTreeNode;
858      var bVar = b as VariableTreeNode;
859      if (aVar != null && bVar != null) {
860        return aVar.VariableName == bVar.VariableName;
861      }
862      return false;
863    }
864
865    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
866    private void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
[5733]867      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
868      while (prod.Subtrees.Count() > 0) prod.RemoveSubtree(0);
[5571]869      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
870                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
871                            group node by node.VariableName + lag into g
872                            orderby g.Count()
873                            select g;
874      var constantProduct = (from node in subtrees.OfType<VariableTreeNode>()
875                             select node.Weight)
876                            .Concat(from node in subtrees.OfType<ConstantTreeNode>()
877                                    select node.Value)
878                            .DefaultIfEmpty(1.0)
879                            .Aggregate((c1, c2) => c1 * c2);
880
[5733]881      var unchangedSubtrees = from tree in subtrees
[5571]882                              where !(tree is VariableTreeNode)
883                              where !(tree is ConstantTreeNode)
884                              select tree;
885
886      foreach (var variableNodeGroup in groupedVarNodes) {
887        var representative = variableNodeGroup.First();
888        representative.Weight = 1.0;
889        if (variableNodeGroup.Count() > 1) {
890          var poly = mulSymbol.CreateTreeNode();
891          for (int p = 0; p < variableNodeGroup.Count(); p++) {
[5733]892            poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
[5571]893          }
[5733]894          prod.AddSubtree(poly);
[5571]895        } else {
[5733]896          prod.AddSubtree(representative);
[5571]897        }
898      }
899
[5733]900      foreach (var unchangedSubtree in unchangedSubtrees)
901        prod.AddSubtree(unchangedSubtree);
[5571]902
903      if (!constantProduct.IsAlmost(1.0)) {
[5733]904        prod.AddSubtree(MakeConstant(constantProduct));
[5571]905      }
906    }
907
908
909    /// <summary>
910    /// x => x * -1
911    /// Doesn't create new trees and manipulates x
912    /// </summary>
913    /// <param name="x"></param>
914    /// <returns>-x</returns>
915    private ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
916      if (IsConstant(x)) {
917        ((ConstantTreeNode)x).Value *= -1;
918      } else if (IsVariable(x)) {
919        var variableTree = (VariableTreeNode)x;
920        variableTree.Weight *= -1.0;
921      } else if (IsAddition(x)) {
922        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
[5733]923        List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
924        while (x.Subtrees.Count() > 0) x.RemoveSubtree(0);
925        foreach (var subtree in subtrees) {
926          x.AddSubtree(Negate(subtree));
[5571]927        }
928      } else if (IsMultiplication(x) || IsDivision(x)) {
929        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
[5915]930        var lastSubTree = x.Subtrees.Last();
[6803]931        x.RemoveSubtree(x.SubtreeCount - 1);
[5915]932        x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
[5571]933      } else {
934        // any other function
935        return MakeProduct(x, MakeConstant(-1));
936      }
937      return x;
938    }
939
940    /// <summary>
941    /// x => 1/x
942    /// Doesn't create new trees and manipulates x
943    /// </summary>
944    /// <param name="x"></param>
945    /// <returns></returns>
946    private ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
947      if (IsConstant(x)) {
948        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
949      } else if (IsDivision(x)) {
[5733]950        return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
[5571]951      } else {
952        // any other function
953        return MakeFraction(MakeConstant(1), x);
954      }
955    }
956
957    private ISymbolicExpressionTreeNode MakeConstant(double value) {
958      ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
959      constantTreeNode.Value = value;
960      return constantTreeNode;
961    }
962
963    private ISymbolicExpressionTreeNode MakeVariable(double weight, string name) {
964      var tree = (VariableTreeNode)varSymbol.CreateTreeNode();
965      tree.Weight = weight;
966      tree.VariableName = name;
967      return tree;
968    }
969    #endregion
970  }
971}
Note: See TracBrowser for help on using the repository browser.