Free cookie consent management tool by TermsFeed Policy Generator

source: branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs @ 5649

Last change on this file since 5649 was 5574, checked in by gkronber, 14 years ago

#1418 Added test projects for data-analysis and symbolic data-analysis plugin. Moved grammars to version 3.4. Fixed bugs in interpretation and simplification of 'not' symbols.

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