Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs @ 8701

Last change on this file since 8701 was 8213, checked in by bburlacu, 12 years ago

#1772: Performance improvements for the GenealogyGraph. Minor refactoring to VisualGenealogyGraphArc and VisualGenealogyGraphNode classes. Added new functionality to the SymbolicExpressionTreeFragmentsAnalyzer, minor refactoring in the other two analyzers. Refactored View code. Updated project references and plugin dependencies and added HeuristicLab.Problems.DataAnalysis.Symbolic to the branch.

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