Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs @ 9706

Last change on this file since 9706 was 5936, checked in by mkommend, 13 years ago

#1418: Removed asserts from SymbolicDataAnalysisExpressionTreeSimplifier.

File size: 38.7 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.SubtreesCount > 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        var sum = original.Subtrees
263          .Select(x => GetSimplifiedTree(x))
264          .Aggregate((a, b) => MakeSum(a, b));
265        return MakeFraction(sum, MakeConstant(original.Subtrees.Count()));
266      }
267    }
268
269    private ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
270      if (original.Subtrees.Count() == 1) {
271        return Invert(GetSimplifiedTree(original.GetSubtree(0)));
272      } else {
273        // simplify expressions x0..xn
274        // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
275        var simplifiedTrees = original.Subtrees.Select(x => GetSimplifiedTree(x));
276        return
277          MakeProduct(simplifiedTrees.First(), Invert(simplifiedTrees.Skip(1).Aggregate((a, b) => MakeProduct(a, b))));
278      }
279    }
280
281    private ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
282      if (original.Subtrees.Count() == 1) {
283        return GetSimplifiedTree(original.GetSubtree(0));
284      } else {
285        return original.Subtrees
286          .Select(x => GetSimplifiedTree(x))
287          .Aggregate((a, b) => MakeProduct(a, b));
288      }
289    }
290
291    private ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
292      if (original.Subtrees.Count() == 1) {
293        return Negate(GetSimplifiedTree(original.GetSubtree(0)));
294      } else {
295        // simplify expressions x0..xn
296        // make addition (x0,-x1..-xn)
297        var simplifiedTrees = original.Subtrees.Select(x => GetSimplifiedTree(x));
298        return simplifiedTrees.Take(1)
299          .Concat(simplifiedTrees.Skip(1).Select(x => Negate(x)))
300          .Aggregate((a, b) => MakeSum(a, b));
301      }
302    }
303
304    private ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
305      if (original.Subtrees.Count() == 1) {
306        return GetSimplifiedTree(original.GetSubtree(0));
307      } else {
308        // simplify expression x0..xn
309        // make addition (x0..xn)
310        return original.Subtrees
311          .Select(x => GetSimplifiedTree(x))
312          .Aggregate((a, b) => MakeSum(a, b));
313      }
314    }
315
316    private ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
317      return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
318    }
319    private ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
320      return original.Subtrees
321        .Select(x => GetSimplifiedTree(x))
322        .Aggregate((a, b) => MakeOr(a, b));
323    }
324    private ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
325      return original.Subtrees
326        .Select(x => GetSimplifiedTree(x))
327        .Aggregate((a, b) => MakeAnd(a, b));
328    }
329    private ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
330      return MakeLessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
331    }
332    private ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
333      return MakeGreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
334    }
335    private ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
336      return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)), GetSimplifiedTree(original.GetSubtree(2)));
337    }
338    private ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
339      return MakeTangent(GetSimplifiedTree(original.GetSubtree(0)));
340    }
341    private ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
342      return MakeCosine(GetSimplifiedTree(original.GetSubtree(0)));
343    }
344    private ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
345      return MakeSine(GetSimplifiedTree(original.GetSubtree(0)));
346    }
347    private ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
348      return MakeExp(GetSimplifiedTree(original.GetSubtree(0)));
349    }
350
351    private ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
352      return MakeLog(GetSimplifiedTree(original.GetSubtree(0)));
353    }
354    private ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
355      return MakeRoot(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
356    }
357
358    private ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
359      return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
360    }
361    #endregion
362
363    #region low level tree restructuring
364    private ISymbolicExpressionTreeNode MakeNot(ISymbolicExpressionTreeNode t) {
365      if (IsConstant(t)) {
366        var constNode = t as ConstantTreeNode;
367        if (constNode.Value > 0) return MakeConstant(-1.0);
368        else return MakeConstant(1.0);
369      } else if (IsNot(t)) {
370        return t.GetSubtree(0);
371      } else if (!IsBoolean(t)) {
372        var gtNode = gtSymbol.CreateTreeNode();
373        gtNode.AddSubtree(t); gtNode.AddSubtree(MakeConstant(0.0));
374        var notNode = notSymbol.CreateTreeNode();
375        notNode.AddSubtree(gtNode);
376        return notNode;
377      } else {
378        var notNode = notSymbol.CreateTreeNode();
379        notNode.AddSubtree(t);
380        return notNode;
381      }
382    }
383
384    private ISymbolicExpressionTreeNode MakeOr(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
385      if (IsConstant(a) && IsConstant(b)) {
386        var constA = a as ConstantTreeNode;
387        var constB = b as ConstantTreeNode;
388        if (constA.Value > 0.0 || constB.Value > 0.0) {
389          return MakeConstant(1.0);
390        } else {
391          return MakeConstant(-1.0);
392        }
393      } else if (IsConstant(a)) {
394        return MakeOr(b, a);
395      } else if (IsConstant(b)) {
396        var constT = b as ConstantTreeNode;
397        if (constT.Value > 0.0) {
398          // boolean expression is necessarily true
399          return MakeConstant(1.0);
400        } else {
401          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
402          var orNode = orSymbol.CreateTreeNode();
403          orNode.AddSubtree(a);
404          return orNode;
405        }
406      } else {
407        var orNode = orSymbol.CreateTreeNode();
408        orNode.AddSubtree(a);
409        orNode.AddSubtree(b);
410        return orNode;
411      }
412    }
413    private ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
414      if (IsConstant(a) && IsConstant(b)) {
415        var constA = a as ConstantTreeNode;
416        var constB = b as ConstantTreeNode;
417        if (constA.Value > 0.0 && constB.Value > 0.0) {
418          return MakeConstant(1.0);
419        } else {
420          return MakeConstant(-1.0);
421        }
422      } else if (IsConstant(a)) {
423        return MakeAnd(b, a);
424      } else if (IsConstant(b)) {
425        var constB = b as ConstantTreeNode;
426        if (constB.Value > 0.0) {
427          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
428          var andNode = andSymbol.CreateTreeNode();
429          andNode.AddSubtree(a);
430          return andNode;
431        } else {
432          // boolean expression is necessarily false
433          return MakeConstant(-1.0);
434        }
435      } else {
436        var andNode = andSymbol.CreateTreeNode();
437        andNode.AddSubtree(a);
438        andNode.AddSubtree(b);
439        return andNode;
440      }
441    }
442    private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
443      if (IsConstant(leftSide) && IsConstant(rightSide)) {
444        var lsConst = leftSide as ConstantTreeNode;
445        var rsConst = rightSide as ConstantTreeNode;
446        if (lsConst.Value < rsConst.Value) return MakeConstant(1.0);
447        else return MakeConstant(-1.0);
448      } else {
449        var ltNode = ltSymbol.CreateTreeNode();
450        ltNode.AddSubtree(leftSide);
451        ltNode.AddSubtree(rightSide);
452        return ltNode;
453      }
454    }
455    private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
456      if (IsConstant(leftSide) && IsConstant(rightSide)) {
457        var lsConst = leftSide as ConstantTreeNode;
458        var rsConst = rightSide as ConstantTreeNode;
459        if (lsConst.Value > rsConst.Value) return MakeConstant(1.0);
460        else return MakeConstant(-1.0);
461      } else {
462        var gtNode = gtSymbol.CreateTreeNode();
463        gtNode.AddSubtree(leftSide);
464        gtNode.AddSubtree(rightSide);
465        return gtNode;
466      }
467    }
468    private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition, ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
469      if (IsConstant(condition)) {
470        var constT = condition as ConstantTreeNode;
471        if (constT.Value > 0.0) return trueBranch;
472        else return falseBranch;
473      } else {
474        var ifNode = ifThenElseSymbol.CreateTreeNode();
475        if (IsBoolean(condition)) {
476          ifNode.AddSubtree(condition);
477        } else {
478          var gtNode = gtSymbol.CreateTreeNode();
479          gtNode.AddSubtree(condition); gtNode.AddSubtree(MakeConstant(0.0));
480          ifNode.AddSubtree(gtNode);
481        }
482        ifNode.AddSubtree(trueBranch);
483        ifNode.AddSubtree(falseBranch);
484        return ifNode;
485      }
486    }
487
488    private ISymbolicExpressionTreeNode MakeSine(ISymbolicExpressionTreeNode node) {
489      if (IsConstant(node)) {
490        var constT = node as ConstantTreeNode;
491        return MakeConstant(Math.Sin(constT.Value));
492      } else {
493        var sineNode = sineSymbol.CreateTreeNode();
494        sineNode.AddSubtree(node);
495        return sineNode;
496      }
497    }
498    private ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
499      if (IsConstant(node)) {
500        var constT = node as ConstantTreeNode;
501        return MakeConstant(Math.Tan(constT.Value));
502      } else {
503        var tanNode = tanSymbol.CreateTreeNode();
504        tanNode.AddSubtree(node);
505        return tanNode;
506      }
507    }
508    private ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
509      if (IsConstant(node)) {
510        var constT = node as ConstantTreeNode;
511        return MakeConstant(Math.Cos(constT.Value));
512      } else {
513        var cosNode = cosineSymbol.CreateTreeNode();
514        cosNode.AddSubtree(node);
515        return cosNode;
516      }
517    }
518    private ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
519      if (IsConstant(node)) {
520        var constT = node as ConstantTreeNode;
521        return MakeConstant(Math.Exp(constT.Value));
522      } else if (IsLog(node)) {
523        return node.GetSubtree(0);
524      } else if (IsAddition(node)) {
525        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, t));
526      } else if (IsSubtraction(node)) {
527        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, Negate(t)));
528      } else {
529        var expNode = expSymbol.CreateTreeNode();
530        expNode.AddSubtree(node);
531        return expNode;
532      }
533    }
534    private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
535      if (IsConstant(node)) {
536        var constT = node as ConstantTreeNode;
537        return MakeConstant(Math.Log(constT.Value));
538      } else if (IsExp(node)) {
539        return node.GetSubtree(0);
540      } else if (IsMultiplication(node)) {
541        return node.Subtrees.Select(s => MakeLog(s)).Aggregate((x, y) => MakeSum(x, y));
542      } else if (IsDivision(node)) {
543        var subtractionNode = subSymbol.CreateTreeNode();
544        foreach (var subtree in node.Subtrees) {
545          subtractionNode.AddSubtree(MakeLog(subtree));
546        }
547        return subtractionNode;
548      } else {
549        var logNode = logSymbol.CreateTreeNode();
550        logNode.AddSubtree(node);
551        return logNode;
552      }
553    }
554    private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
555      if (IsConstant(a) && IsConstant(b)) {
556        var constA = a as ConstantTreeNode;
557        var constB = b as ConstantTreeNode;
558        return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
559      } else if (IsConstant(b)) {
560        var constB = b as ConstantTreeNode;
561        var constBValue = Math.Round(constB.Value);
562        if (constBValue.IsAlmost(1.0)) {
563          return a;
564        } else if (constBValue.IsAlmost(0.0)) {
565          return MakeConstant(1.0);
566        } else if (constBValue.IsAlmost(-1.0)) {
567          return MakeFraction(MakeConstant(1.0), a);
568        } else if (constBValue < 0) {
569          var rootNode = rootSymbol.CreateTreeNode();
570          rootNode.AddSubtree(a);
571          rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
572          return MakeFraction(MakeConstant(1.0), rootNode);
573        } else {
574          var rootNode = rootSymbol.CreateTreeNode();
575          rootNode.AddSubtree(a);
576          rootNode.AddSubtree(MakeConstant(constBValue));
577          return rootNode;
578        }
579      } else {
580        var rootNode = rootSymbol.CreateTreeNode();
581        rootNode.AddSubtree(a);
582        rootNode.AddSubtree(b);
583        return rootNode;
584      }
585    }
586    private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
587      if (IsConstant(a) && IsConstant(b)) {
588        var constA = a as ConstantTreeNode;
589        var constB = b as ConstantTreeNode;
590        return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
591      } else if (IsConstant(b)) {
592        var constB = b as ConstantTreeNode;
593        double exponent = Math.Round(constB.Value);
594        if (exponent.IsAlmost(0.0)) {
595          return MakeConstant(1.0);
596        } else if (exponent.IsAlmost(1.0)) {
597          return a;
598        } else if (exponent.IsAlmost(-1.0)) {
599          return MakeFraction(MakeConstant(1.0), a);
600        } else if (exponent < 0) {
601          var powNode = powSymbol.CreateTreeNode();
602          powNode.AddSubtree(a);
603          powNode.AddSubtree(MakeConstant(-1.0 * exponent));
604          return MakeFraction(MakeConstant(1.0), powNode);
605        } else {
606          var powNode = powSymbol.CreateTreeNode();
607          powNode.AddSubtree(a);
608          powNode.AddSubtree(MakeConstant(exponent));
609          return powNode;
610        }
611      } else {
612        var powNode = powSymbol.CreateTreeNode();
613        powNode.AddSubtree(a);
614        powNode.AddSubtree(b);
615        return powNode;
616      }
617    }
618
619
620    // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
621    private ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
622      if (IsConstant(a) && IsConstant(b)) {
623        // fold constants
624        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
625      } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) {
626        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
627      } else if (IsVariable(a) && IsConstant(b)) {
628        // merge constant values into variable weights
629        var constB = ((ConstantTreeNode)b).Value;
630        ((VariableTreeNode)a).Weight /= constB;
631        return a;
632      } else if (IsVariable(a) && IsVariable(b) && AreSameVariable(a, b)) {
633        // cancel variables
634        var aVar = a as VariableTreeNode;
635        var bVar = b as VariableTreeNode;
636        return MakeConstant(aVar.Weight / bVar.Weight);
637      } else if (IsAddition(a) && IsConstant(b)) {
638        return a.Subtrees
639          .Select(x => GetSimplifiedTree(x))
640         .Select(x => MakeFraction(x, b))
641         .Aggregate((c, d) => MakeSum(c, d));
642      } else if (IsMultiplication(a) && IsConstant(b)) {
643        return MakeProduct(a, Invert(b));
644      } else if (IsDivision(a) && IsConstant(b)) {
645        // (a1 / a2) / c => (a1 / (a2 * c))
646        Trace.Assert(a.Subtrees.Count() == 2);
647        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
648      } else if (IsDivision(a) && IsDivision(b)) {
649        // (a1 / a2) / (b1 / b2) =>
650        Trace.Assert(a.Subtrees.Count() == 2);
651        Trace.Assert(b.Subtrees.Count() == 2);
652        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
653      } else if (IsDivision(a)) {
654        // (a1 / a2) / b => (a1 / (a2 * b))
655        Trace.Assert(a.Subtrees.Count() == 2);
656        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
657      } else if (IsDivision(b)) {
658        // a / (b1 / b2) => (a * b2) / b1
659        Trace.Assert(b.Subtrees.Count() == 2);
660        return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
661      } else {
662        var div = divSymbol.CreateTreeNode();
663        div.AddSubtree(a);
664        div.AddSubtree(b);
665        return div;
666      }
667    }
668
669    private ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
670      if (IsConstant(a) && IsConstant(b)) {
671        // fold constants
672        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
673        return a;
674      } else if (IsConstant(a)) {
675        // c + x => x + c
676        // b is not constant => make sure constant is on the right
677        return MakeSum(b, a);
678      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
679        // x + 0 => x
680        return a;
681      } else if (IsAddition(a) && IsAddition(b)) {
682        // merge additions
683        var add = addSymbol.CreateTreeNode();
684        // add all sub trees except for the last
685        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
686        for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
687        if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
688          add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
689        } else if (IsConstant(a.Subtrees.Last())) {
690          add.AddSubtree(b.Subtrees.Last());
691          add.AddSubtree(a.Subtrees.Last());
692        } else {
693          add.AddSubtree(a.Subtrees.Last());
694          add.AddSubtree(b.Subtrees.Last());
695        }
696        MergeVariablesInSum(add);
697        if (add.Subtrees.Count() == 1) {
698          return add.GetSubtree(0);
699        } else {
700          return add;
701        }
702      } else if (IsAddition(b)) {
703        return MakeSum(b, a);
704      } else if (IsAddition(a) && IsConstant(b)) {
705        // a is an addition and b is a constant => append b to a and make sure the constants are merged
706        var add = addSymbol.CreateTreeNode();
707        // add all sub trees except for the last
708        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
709        if (IsConstant(a.Subtrees.Last()))
710          add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
711        else {
712          add.AddSubtree(a.Subtrees.Last());
713          add.AddSubtree(b);
714        }
715        return add;
716      } else if (IsAddition(a)) {
717        // a is already an addition => append b
718        var add = addSymbol.CreateTreeNode();
719        add.AddSubtree(b);
720        foreach (var subtree in a.Subtrees) {
721          add.AddSubtree(subtree);
722        }
723        MergeVariablesInSum(add);
724        if (add.Subtrees.Count() == 1) {
725          return add.GetSubtree(0);
726        } else {
727          return add;
728        }
729      } else {
730        var add = addSymbol.CreateTreeNode();
731        add.AddSubtree(a);
732        add.AddSubtree(b);
733        MergeVariablesInSum(add);
734        if (add.Subtrees.Count() == 1) {
735          return add.GetSubtree(0);
736        } else {
737          return add;
738        }
739      }
740    }
741
742    // makes sure variable symbols in sums are combined
743    // possible improvement: combine sums of products where the products only reference the same variable
744    private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
745      var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
746      while (sum.Subtrees.Count() > 0) sum.RemoveSubtree(0);
747      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
748                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
749                            group node by node.VariableName + lag into g
750                            select g;
751      var unchangedSubtrees = subtrees.Where(t => !(t is VariableTreeNode));
752
753      foreach (var variableNodeGroup in groupedVarNodes) {
754        var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
755        var representative = variableNodeGroup.First();
756        representative.Weight = weightSum;
757        sum.AddSubtree(representative);
758      }
759      foreach (var unchangedSubtree in unchangedSubtrees)
760        sum.AddSubtree(unchangedSubtree);
761    }
762
763
764    private ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
765      if (IsConstant(a) && IsConstant(b)) {
766        // fold constants
767        ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
768        return a;
769      } else if (IsConstant(a)) {
770        // a * $ => $ * a
771        return MakeProduct(b, a);
772      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
773        // $ * 1.0 => $
774        return a;
775      } else if (IsConstant(b) && IsVariable(a)) {
776        // multiply constants into variables weights
777        ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value;
778        return a;
779      } else if (IsConstant(b) && IsAddition(a)) {
780        // multiply constants into additions
781        return a.Subtrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d));
782      } else if (IsDivision(a) && IsDivision(b)) {
783        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
784        Trace.Assert(a.Subtrees.Count() == 2);
785        Trace.Assert(b.Subtrees.Count() == 2);
786        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
787      } else if (IsDivision(a)) {
788        // (a1 / a2) * b => (a1 * b) / a2
789        Trace.Assert(a.Subtrees.Count() == 2);
790        return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
791      } else if (IsDivision(b)) {
792        // a * (b1 / b2) => (b1 * a) / b2
793        Trace.Assert(b.Subtrees.Count() == 2);
794        return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
795      } else if (IsMultiplication(a) && IsMultiplication(b)) {
796        // merge multiplications (make sure constants are merged)
797        var mul = mulSymbol.CreateTreeNode();
798        for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
799        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
800        MergeVariablesAndConstantsInProduct(mul);
801        return mul;
802      } else if (IsMultiplication(b)) {
803        return MakeProduct(b, a);
804      } else if (IsMultiplication(a)) {
805        // a is already an multiplication => append b
806        a.AddSubtree(b);
807        MergeVariablesAndConstantsInProduct(a);
808        return a;
809      } else {
810        var mul = mulSymbol.CreateTreeNode();
811        mul.AddSubtree(a);
812        mul.AddSubtree(b);
813        MergeVariablesAndConstantsInProduct(mul);
814        return mul;
815      }
816    }
817    #endregion
818
819
820    #region helper functions
821
822    private bool AreSameVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
823      var aLaggedVar = a as LaggedVariableTreeNode;
824      var bLaggedVar = b as LaggedVariableTreeNode;
825      if (aLaggedVar != null && bLaggedVar != null) {
826        return aLaggedVar.VariableName == bLaggedVar.VariableName &&
827          aLaggedVar.Lag == bLaggedVar.Lag;
828      }
829      var aVar = a as VariableTreeNode;
830      var bVar = b as VariableTreeNode;
831      if (aVar != null && bVar != null) {
832        return aVar.VariableName == bVar.VariableName;
833      }
834      return false;
835    }
836
837    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
838    private void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
839      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
840      while (prod.Subtrees.Count() > 0) prod.RemoveSubtree(0);
841      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
842                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
843                            group node by node.VariableName + lag into g
844                            orderby g.Count()
845                            select g;
846      var constantProduct = (from node in subtrees.OfType<VariableTreeNode>()
847                             select node.Weight)
848                            .Concat(from node in subtrees.OfType<ConstantTreeNode>()
849                                    select node.Value)
850                            .DefaultIfEmpty(1.0)
851                            .Aggregate((c1, c2) => c1 * c2);
852
853      var unchangedSubtrees = from tree in subtrees
854                              where !(tree is VariableTreeNode)
855                              where !(tree is ConstantTreeNode)
856                              select tree;
857
858      foreach (var variableNodeGroup in groupedVarNodes) {
859        var representative = variableNodeGroup.First();
860        representative.Weight = 1.0;
861        if (variableNodeGroup.Count() > 1) {
862          var poly = mulSymbol.CreateTreeNode();
863          for (int p = 0; p < variableNodeGroup.Count(); p++) {
864            poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
865          }
866          prod.AddSubtree(poly);
867        } else {
868          prod.AddSubtree(representative);
869        }
870      }
871
872      foreach (var unchangedSubtree in unchangedSubtrees)
873        prod.AddSubtree(unchangedSubtree);
874
875      if (!constantProduct.IsAlmost(1.0)) {
876        prod.AddSubtree(MakeConstant(constantProduct));
877      }
878    }
879
880
881    /// <summary>
882    /// x => x * -1
883    /// Doesn't create new trees and manipulates x
884    /// </summary>
885    /// <param name="x"></param>
886    /// <returns>-x</returns>
887    private ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
888      if (IsConstant(x)) {
889        ((ConstantTreeNode)x).Value *= -1;
890      } else if (IsVariable(x)) {
891        var variableTree = (VariableTreeNode)x;
892        variableTree.Weight *= -1.0;
893      } else if (IsAddition(x)) {
894        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
895        List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
896        while (x.Subtrees.Count() > 0) x.RemoveSubtree(0);
897        foreach (var subtree in subtrees) {
898          x.AddSubtree(Negate(subtree));
899        }
900      } else if (IsMultiplication(x) || IsDivision(x)) {
901        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
902        var lastSubTree = x.Subtrees.Last();
903        x.RemoveSubtree(x.SubtreesCount - 1);
904        x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
905      } else {
906        // any other function
907        return MakeProduct(x, MakeConstant(-1));
908      }
909      return x;
910    }
911
912    /// <summary>
913    /// x => 1/x
914    /// Doesn't create new trees and manipulates x
915    /// </summary>
916    /// <param name="x"></param>
917    /// <returns></returns>
918    private ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
919      if (IsConstant(x)) {
920        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
921      } else if (IsDivision(x)) {
922        Trace.Assert(x.Subtrees.Count() == 2);
923        return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
924      } else {
925        // any other function
926        return MakeFraction(MakeConstant(1), x);
927      }
928    }
929
930    private ISymbolicExpressionTreeNode MakeConstant(double value) {
931      ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
932      constantTreeNode.Value = value;
933      return constantTreeNode;
934    }
935
936    private ISymbolicExpressionTreeNode MakeVariable(double weight, string name) {
937      var tree = (VariableTreeNode)varSymbol.CreateTreeNode();
938      tree.Weight = weight;
939      tree.VariableName = name;
940      return tree;
941    }
942    #endregion
943  }
944}
Note: See TracBrowser for help on using the repository browser.