Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RegressionBenchmarks/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs @ 7317

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

#1669 merged r7209:7283 from trunk into regression benchmark branch

File size: 38.3 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
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.SubtreeCount > 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 {
541        var logNode = logSymbol.CreateTreeNode();
542        logNode.AddSubtree(node);
543        return logNode;
544      }
545    }
546    private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
547      if (IsConstant(a) && IsConstant(b)) {
548        var constA = a as ConstantTreeNode;
549        var constB = b as ConstantTreeNode;
550        return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
551      } else if (IsConstant(b)) {
552        var constB = b as ConstantTreeNode;
553        var constBValue = Math.Round(constB.Value);
554        if (constBValue.IsAlmost(1.0)) {
555          return a;
556        } else if (constBValue.IsAlmost(0.0)) {
557          return MakeConstant(1.0);
558        } else if (constBValue.IsAlmost(-1.0)) {
559          return MakeFraction(MakeConstant(1.0), a);
560        } else if (constBValue < 0) {
561          var rootNode = rootSymbol.CreateTreeNode();
562          rootNode.AddSubtree(a);
563          rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
564          return MakeFraction(MakeConstant(1.0), rootNode);
565        } else {
566          var rootNode = rootSymbol.CreateTreeNode();
567          rootNode.AddSubtree(a);
568          rootNode.AddSubtree(MakeConstant(constBValue));
569          return rootNode;
570        }
571      } else {
572        var rootNode = rootSymbol.CreateTreeNode();
573        rootNode.AddSubtree(a);
574        rootNode.AddSubtree(b);
575        return rootNode;
576      }
577    }
578    private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
579      if (IsConstant(a) && IsConstant(b)) {
580        var constA = a as ConstantTreeNode;
581        var constB = b as ConstantTreeNode;
582        return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
583      } else if (IsConstant(b)) {
584        var constB = b as ConstantTreeNode;
585        double exponent = Math.Round(constB.Value);
586        if (exponent.IsAlmost(0.0)) {
587          return MakeConstant(1.0);
588        } else if (exponent.IsAlmost(1.0)) {
589          return a;
590        } else if (exponent.IsAlmost(-1.0)) {
591          return MakeFraction(MakeConstant(1.0), a);
592        } else if (exponent < 0) {
593          var powNode = powSymbol.CreateTreeNode();
594          powNode.AddSubtree(a);
595          powNode.AddSubtree(MakeConstant(-1.0 * exponent));
596          return MakeFraction(MakeConstant(1.0), powNode);
597        } else {
598          var powNode = powSymbol.CreateTreeNode();
599          powNode.AddSubtree(a);
600          powNode.AddSubtree(MakeConstant(exponent));
601          return powNode;
602        }
603      } else {
604        var powNode = powSymbol.CreateTreeNode();
605        powNode.AddSubtree(a);
606        powNode.AddSubtree(b);
607        return powNode;
608      }
609    }
610
611
612    // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
613    private ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
614      if (IsConstant(a) && IsConstant(b)) {
615        // fold constants
616        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
617      } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) {
618        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
619      } else if (IsVariable(a) && IsConstant(b)) {
620        // merge constant values into variable weights
621        var constB = ((ConstantTreeNode)b).Value;
622        ((VariableTreeNode)a).Weight /= constB;
623        return a;
624      } else if (IsVariable(a) && IsVariable(b) && AreSameVariable(a, b)) {
625        // cancel variables
626        var aVar = a as VariableTreeNode;
627        var bVar = b as VariableTreeNode;
628        return MakeConstant(aVar.Weight / bVar.Weight);
629      } else if (IsAddition(a) && IsConstant(b)) {
630        return a.Subtrees
631          .Select(x => GetSimplifiedTree(x))
632         .Select(x => MakeFraction(x, b))
633         .Aggregate((c, d) => MakeSum(c, d));
634      } else if (IsMultiplication(a) && IsConstant(b)) {
635        return MakeProduct(a, Invert(b));
636      } else if (IsDivision(a) && IsConstant(b)) {
637        // (a1 / a2) / c => (a1 / (a2 * c))
638        Trace.Assert(a.Subtrees.Count() == 2);
639        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
640      } else if (IsDivision(a) && IsDivision(b)) {
641        // (a1 / a2) / (b1 / b2) =>
642        Trace.Assert(a.Subtrees.Count() == 2);
643        Trace.Assert(b.Subtrees.Count() == 2);
644        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
645      } else if (IsDivision(a)) {
646        // (a1 / a2) / b => (a1 / (a2 * b))
647        Trace.Assert(a.Subtrees.Count() == 2);
648        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
649      } else if (IsDivision(b)) {
650        // a / (b1 / b2) => (a * b2) / b1
651        Trace.Assert(b.Subtrees.Count() == 2);
652        return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
653      } else {
654        var div = divSymbol.CreateTreeNode();
655        div.AddSubtree(a);
656        div.AddSubtree(b);
657        return div;
658      }
659    }
660
661    private ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
662      if (IsConstant(a) && IsConstant(b)) {
663        // fold constants
664        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
665        return a;
666      } else if (IsConstant(a)) {
667        // c + x => x + c
668        // b is not constant => make sure constant is on the right
669        return MakeSum(b, a);
670      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
671        // x + 0 => x
672        return a;
673      } else if (IsAddition(a) && IsAddition(b)) {
674        // merge additions
675        var add = addSymbol.CreateTreeNode();
676        // add all sub trees except for the last
677        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
678        for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
679        if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
680          add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
681        } else if (IsConstant(a.Subtrees.Last())) {
682          add.AddSubtree(b.Subtrees.Last());
683          add.AddSubtree(a.Subtrees.Last());
684        } else {
685          add.AddSubtree(a.Subtrees.Last());
686          add.AddSubtree(b.Subtrees.Last());
687        }
688        MergeVariablesInSum(add);
689        if (add.Subtrees.Count() == 1) {
690          return add.GetSubtree(0);
691        } else {
692          return add;
693        }
694      } else if (IsAddition(b)) {
695        return MakeSum(b, a);
696      } else if (IsAddition(a) && IsConstant(b)) {
697        // a is an addition and b is a constant => append b to a and make sure the constants are merged
698        var add = addSymbol.CreateTreeNode();
699        // add all sub trees except for the last
700        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
701        if (IsConstant(a.Subtrees.Last()))
702          add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
703        else {
704          add.AddSubtree(a.Subtrees.Last());
705          add.AddSubtree(b);
706        }
707        return add;
708      } else if (IsAddition(a)) {
709        // a is already an addition => append b
710        var add = addSymbol.CreateTreeNode();
711        add.AddSubtree(b);
712        foreach (var subtree in a.Subtrees) {
713          add.AddSubtree(subtree);
714        }
715        MergeVariablesInSum(add);
716        if (add.Subtrees.Count() == 1) {
717          return add.GetSubtree(0);
718        } else {
719          return add;
720        }
721      } else {
722        var add = addSymbol.CreateTreeNode();
723        add.AddSubtree(a);
724        add.AddSubtree(b);
725        MergeVariablesInSum(add);
726        if (add.Subtrees.Count() == 1) {
727          return add.GetSubtree(0);
728        } else {
729          return add;
730        }
731      }
732    }
733
734    // makes sure variable symbols in sums are combined
735    // possible improvement: combine sums of products where the products only reference the same variable
736    private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
737      var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
738      while (sum.Subtrees.Count() > 0) sum.RemoveSubtree(0);
739      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
740                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
741                            group node by node.VariableName + lag into g
742                            select g;
743      var unchangedSubtrees = subtrees.Where(t => !(t is VariableTreeNode));
744
745      foreach (var variableNodeGroup in groupedVarNodes) {
746        var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
747        var representative = variableNodeGroup.First();
748        representative.Weight = weightSum;
749        sum.AddSubtree(representative);
750      }
751      foreach (var unchangedSubtree in unchangedSubtrees)
752        sum.AddSubtree(unchangedSubtree);
753    }
754
755
756    private ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
757      if (IsConstant(a) && IsConstant(b)) {
758        // fold constants
759        ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
760        return a;
761      } else if (IsConstant(a)) {
762        // a * $ => $ * a
763        return MakeProduct(b, a);
764      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
765        // $ * 1.0 => $
766        return a;
767      } else if (IsConstant(b) && IsVariable(a)) {
768        // multiply constants into variables weights
769        ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value;
770        return a;
771      } else if (IsConstant(b) && IsAddition(a)) {
772        // multiply constants into additions
773        return a.Subtrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d));
774      } else if (IsDivision(a) && IsDivision(b)) {
775        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
776        Trace.Assert(a.Subtrees.Count() == 2);
777        Trace.Assert(b.Subtrees.Count() == 2);
778        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
779      } else if (IsDivision(a)) {
780        // (a1 / a2) * b => (a1 * b) / a2
781        Trace.Assert(a.Subtrees.Count() == 2);
782        return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
783      } else if (IsDivision(b)) {
784        // a * (b1 / b2) => (b1 * a) / b2
785        Trace.Assert(b.Subtrees.Count() == 2);
786        return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
787      } else if (IsMultiplication(a) && IsMultiplication(b)) {
788        // merge multiplications (make sure constants are merged)
789        var mul = mulSymbol.CreateTreeNode();
790        for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
791        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
792        MergeVariablesAndConstantsInProduct(mul);
793        return mul;
794      } else if (IsMultiplication(b)) {
795        return MakeProduct(b, a);
796      } else if (IsMultiplication(a)) {
797        // a is already an multiplication => append b
798        a.AddSubtree(b);
799        MergeVariablesAndConstantsInProduct(a);
800        return a;
801      } else {
802        var mul = mulSymbol.CreateTreeNode();
803        mul.AddSubtree(a);
804        mul.AddSubtree(b);
805        MergeVariablesAndConstantsInProduct(mul);
806        return mul;
807      }
808    }
809    #endregion
810
811
812    #region helper functions
813
814    private bool AreSameVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
815      var aLaggedVar = a as LaggedVariableTreeNode;
816      var bLaggedVar = b as LaggedVariableTreeNode;
817      if (aLaggedVar != null && bLaggedVar != null) {
818        return aLaggedVar.VariableName == bLaggedVar.VariableName &&
819          aLaggedVar.Lag == bLaggedVar.Lag;
820      }
821      var aVar = a as VariableTreeNode;
822      var bVar = b as VariableTreeNode;
823      if (aVar != null && bVar != null) {
824        return aVar.VariableName == bVar.VariableName;
825      }
826      return false;
827    }
828
829    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
830    private void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
831      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
832      while (prod.Subtrees.Count() > 0) prod.RemoveSubtree(0);
833      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
834                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
835                            group node by node.VariableName + lag into g
836                            orderby g.Count()
837                            select g;
838      var constantProduct = (from node in subtrees.OfType<VariableTreeNode>()
839                             select node.Weight)
840                            .Concat(from node in subtrees.OfType<ConstantTreeNode>()
841                                    select node.Value)
842                            .DefaultIfEmpty(1.0)
843                            .Aggregate((c1, c2) => c1 * c2);
844
845      var unchangedSubtrees = from tree in subtrees
846                              where !(tree is VariableTreeNode)
847                              where !(tree is ConstantTreeNode)
848                              select tree;
849
850      foreach (var variableNodeGroup in groupedVarNodes) {
851        var representative = variableNodeGroup.First();
852        representative.Weight = 1.0;
853        if (variableNodeGroup.Count() > 1) {
854          var poly = mulSymbol.CreateTreeNode();
855          for (int p = 0; p < variableNodeGroup.Count(); p++) {
856            poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
857          }
858          prod.AddSubtree(poly);
859        } else {
860          prod.AddSubtree(representative);
861        }
862      }
863
864      foreach (var unchangedSubtree in unchangedSubtrees)
865        prod.AddSubtree(unchangedSubtree);
866
867      if (!constantProduct.IsAlmost(1.0)) {
868        prod.AddSubtree(MakeConstant(constantProduct));
869      }
870    }
871
872
873    /// <summary>
874    /// x => x * -1
875    /// Doesn't create new trees and manipulates x
876    /// </summary>
877    /// <param name="x"></param>
878    /// <returns>-x</returns>
879    private ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
880      if (IsConstant(x)) {
881        ((ConstantTreeNode)x).Value *= -1;
882      } else if (IsVariable(x)) {
883        var variableTree = (VariableTreeNode)x;
884        variableTree.Weight *= -1.0;
885      } else if (IsAddition(x)) {
886        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
887        List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
888        while (x.Subtrees.Count() > 0) x.RemoveSubtree(0);
889        foreach (var subtree in subtrees) {
890          x.AddSubtree(Negate(subtree));
891        }
892      } else if (IsMultiplication(x) || IsDivision(x)) {
893        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
894        var lastSubTree = x.Subtrees.Last();
895        x.RemoveSubtree(x.SubtreeCount - 1);
896        x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
897      } else {
898        // any other function
899        return MakeProduct(x, MakeConstant(-1));
900      }
901      return x;
902    }
903
904    /// <summary>
905    /// x => 1/x
906    /// Doesn't create new trees and manipulates x
907    /// </summary>
908    /// <param name="x"></param>
909    /// <returns></returns>
910    private ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
911      if (IsConstant(x)) {
912        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
913      } else if (IsDivision(x)) {
914        Trace.Assert(x.Subtrees.Count() == 2);
915        return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
916      } else {
917        // any other function
918        return MakeFraction(MakeConstant(1), x);
919      }
920    }
921
922    private ISymbolicExpressionTreeNode MakeConstant(double value) {
923      ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
924      constantTreeNode.Value = value;
925      return constantTreeNode;
926    }
927
928    private ISymbolicExpressionTreeNode MakeVariable(double weight, string name) {
929      var tree = (VariableTreeNode)varSymbol.CreateTreeNode();
930      tree.Weight = weight;
931      tree.VariableName = name;
932      return tree;
933    }
934    #endregion
935  }
936}
Note: See TracBrowser for help on using the repository browser.