Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs @ 7463

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

#1081 improved formatter, line chart view, simplifier for time series prognosis solutions

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