Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 7695 was 7695, checked in by gkronber, 12 years ago

#1810 merged patch to add square and square root function symbols by mkommend

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