Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs @ 16716

Last change on this file since 16716 was 16565, checked in by gkronber, 6 years ago

#2520: merged changes from PersistenceOverhaul branch (r16451:16564) into trunk

File size: 66.5 KB
Line 
1#region License Information
2
3/* HeuristicLab
4 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
5 *
6 * This file is part of HeuristicLab.
7 *
8 * HeuristicLab is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * HeuristicLab is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#endregion
23
24using System;
25using System.Collections.Generic;
26using System.Linq;
27using HeuristicLab.Common;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
29
30namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
31  /// <summary>
32  /// Simplifier for symbolic expressions
33  /// </summary>
34  public class TreeSimplifier {
35    private static readonly Addition addSymbol = new Addition();
36    private static readonly Multiplication mulSymbol = new Multiplication();
37    private static readonly Division divSymbol = new Division();
38    private static readonly Constant constSymbol = new Constant();
39    private static readonly Absolute absSymbol = new Absolute();
40    private static readonly Logarithm logSymbol = new Logarithm();
41    private static readonly Exponential expSymbol = new Exponential();
42    private static readonly Root rootSymbol = new Root();
43    private static readonly Square sqrSymbol = new Square();
44    private static readonly SquareRoot sqrtSymbol = new SquareRoot();
45    private static readonly AnalyticQuotient aqSymbol = new AnalyticQuotient();
46    private static readonly Cube cubeSymbol = new Cube();
47    private static readonly CubeRoot cubeRootSymbol = new CubeRoot();
48    private static readonly Power powSymbol = new Power();
49    private static readonly Sine sineSymbol = new Sine();
50    private static readonly Cosine cosineSymbol = new Cosine();
51    private static readonly Tangent tanSymbol = new Tangent();
52    private static readonly IfThenElse ifThenElseSymbol = new IfThenElse();
53    private static readonly And andSymbol = new And();
54    private static readonly Or orSymbol = new Or();
55    private static readonly Not notSymbol = new Not();
56    private static readonly GreaterThan gtSymbol = new GreaterThan();
57    private static readonly LessThan ltSymbol = new LessThan();
58    private static readonly Integral integralSymbol = new Integral();
59    private static readonly LaggedVariable laggedVariableSymbol = new LaggedVariable();
60    private static readonly TimeLag timeLagSymbol = new TimeLag();
61
62    [Obsolete("Use static method TreeSimplifier.Simplify instead")]
63    public TreeSimplifier() { }
64
65    public static ISymbolicExpressionTree Simplify(ISymbolicExpressionTree originalTree) {
66      var clone = (ISymbolicExpressionTreeNode)originalTree.Root.Clone();
67      // macro expand (initially no argument trees)
68      var macroExpandedTree = MacroExpand(clone, clone.GetSubtree(0), new List<ISymbolicExpressionTreeNode>());
69      ISymbolicExpressionTreeNode rootNode = (new ProgramRootSymbol()).CreateTreeNode();
70      rootNode.AddSubtree(GetSimplifiedTree(macroExpandedTree));
71
72#if DEBUG
73      // check that each node is only referenced once
74      var nodes = rootNode.IterateNodesPrefix().ToArray();
75      foreach (var n in nodes) if (nodes.Count(ni => ni == n) > 1) throw new InvalidOperationException();
76#endif
77      return new SymbolicExpressionTree(rootNode);
78    }
79
80    // the argumentTrees list contains already expanded trees used as arguments for invocations
81    private static ISymbolicExpressionTreeNode MacroExpand(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node,
82      IList<ISymbolicExpressionTreeNode> argumentTrees) {
83      List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
84      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
85      if (node.Symbol is InvokeFunction) {
86        var invokeSym = node.Symbol as InvokeFunction;
87        var defunNode = FindFunctionDefinition(root, invokeSym.FunctionName);
88        var macroExpandedArguments = new List<ISymbolicExpressionTreeNode>();
89        foreach (var subtree in subtrees) {
90          macroExpandedArguments.Add(MacroExpand(root, subtree, argumentTrees));
91        }
92        return MacroExpand(root, defunNode, macroExpandedArguments);
93      } else if (node.Symbol is Argument) {
94        var argSym = node.Symbol as Argument;
95        // return the correct argument sub-tree (already macro-expanded)
96        return (SymbolicExpressionTreeNode)argumentTrees[argSym.ArgumentIndex].Clone();
97      } else {
98        // recursive application
99        foreach (var subtree in subtrees) {
100          node.AddSubtree(MacroExpand(root, subtree, argumentTrees));
101        }
102        return node;
103      }
104    }
105
106    private static ISymbolicExpressionTreeNode FindFunctionDefinition(ISymbolicExpressionTreeNode root, string functionName) {
107      foreach (var subtree in root.Subtrees.OfType<DefunTreeNode>()) {
108        if (subtree.FunctionName == functionName) return subtree.GetSubtree(0);
109      }
110
111      throw new ArgumentException("Definition of function " + functionName + " not found.");
112    }
113
114    #region symbol predicates
115
116    // arithmetic
117    private static bool IsDivision(ISymbolicExpressionTreeNode node) {
118      return node.Symbol is Division;
119    }
120
121    private static bool IsMultiplication(ISymbolicExpressionTreeNode node) {
122      return node.Symbol is Multiplication;
123    }
124
125    private static bool IsSubtraction(ISymbolicExpressionTreeNode node) {
126      return node.Symbol is Subtraction;
127    }
128
129    private static bool IsAddition(ISymbolicExpressionTreeNode node) {
130      return node.Symbol is Addition;
131    }
132
133    private static bool IsAverage(ISymbolicExpressionTreeNode node) {
134      return node.Symbol is Average;
135    }
136
137    private static bool IsAbsolute(ISymbolicExpressionTreeNode node) {
138      return node.Symbol is Absolute;
139    }
140
141    // exponential
142    private static bool IsLog(ISymbolicExpressionTreeNode node) {
143      return node.Symbol is Logarithm;
144    }
145
146    private static bool IsExp(ISymbolicExpressionTreeNode node) {
147      return node.Symbol is Exponential;
148    }
149
150    private static bool IsRoot(ISymbolicExpressionTreeNode node) {
151      return node.Symbol is Root;
152    }
153
154    private static bool IsSquare(ISymbolicExpressionTreeNode node) {
155      return node.Symbol is Square;
156    }
157
158    private static bool IsSquareRoot(ISymbolicExpressionTreeNode node) {
159      return node.Symbol is SquareRoot;
160    }
161
162    private static bool IsCube(ISymbolicExpressionTreeNode node) {
163      return node.Symbol is Cube;
164    }
165
166    private static bool IsCubeRoot(ISymbolicExpressionTreeNode node) {
167      return node.Symbol is CubeRoot;
168    }
169
170    private static bool IsPower(ISymbolicExpressionTreeNode node) {
171      return node.Symbol is Power;
172    }
173
174    // trigonometric
175    private static bool IsSine(ISymbolicExpressionTreeNode node) {
176      return node.Symbol is Sine;
177    }
178
179    private static bool IsCosine(ISymbolicExpressionTreeNode node) {
180      return node.Symbol is Cosine;
181    }
182
183    private static bool IsTangent(ISymbolicExpressionTreeNode node) {
184      return node.Symbol is Tangent;
185    }
186
187    private static bool IsAnalyticalQuotient(ISymbolicExpressionTreeNode node) {
188      return node.Symbol is AnalyticQuotient;
189    }
190
191    // boolean
192    private static bool IsIfThenElse(ISymbolicExpressionTreeNode node) {
193      return node.Symbol is IfThenElse;
194    }
195
196    private static bool IsAnd(ISymbolicExpressionTreeNode node) {
197      return node.Symbol is And;
198    }
199
200    private static bool IsOr(ISymbolicExpressionTreeNode node) {
201      return node.Symbol is Or;
202    }
203
204    private static bool IsNot(ISymbolicExpressionTreeNode node) {
205      return node.Symbol is Not;
206    }
207
208    // comparison
209    private static bool IsGreaterThan(ISymbolicExpressionTreeNode node) {
210      return node.Symbol is GreaterThan;
211    }
212
213    private static bool IsLessThan(ISymbolicExpressionTreeNode node) {
214      return node.Symbol is LessThan;
215    }
216
217    private static bool IsBoolean(ISymbolicExpressionTreeNode node) {
218      return
219        node.Symbol is GreaterThan ||
220        node.Symbol is LessThan ||
221        node.Symbol is And ||
222        node.Symbol is Or;
223    }
224
225    // terminals
226    private static bool IsVariable(ISymbolicExpressionTreeNode node) {
227      return node.Symbol is Variable;
228    }
229
230    private static bool IsVariableBase(ISymbolicExpressionTreeNode node) {
231      return node is VariableTreeNodeBase;
232    }
233
234    private static bool IsFactor(ISymbolicExpressionTreeNode node) {
235      return node is FactorVariableTreeNode;
236    }
237
238    private static bool IsBinFactor(ISymbolicExpressionTreeNode node) {
239      return node is BinaryFactorVariableTreeNode;
240    }
241
242    private static bool IsConstant(ISymbolicExpressionTreeNode node) {
243      return node.Symbol is Constant;
244    }
245
246    // dynamic
247    private static bool IsTimeLag(ISymbolicExpressionTreeNode node) {
248      return node.Symbol is TimeLag;
249    }
250
251    private static bool IsIntegral(ISymbolicExpressionTreeNode node) {
252      return node.Symbol is Integral;
253    }
254
255    #endregion
256
257    /// <summary>
258    /// Creates a new simplified tree
259    /// </summary>
260    /// <param name="original"></param>
261    /// <returns></returns>
262    public static ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
263      if (IsConstant(original) || IsVariableBase(original)) {
264        return (ISymbolicExpressionTreeNode)original.Clone();
265      } else if (IsAbsolute(original)) {
266        return SimplifyAbsolute(original);
267      } else if (IsAddition(original)) {
268        return SimplifyAddition(original);
269      } else if (IsSubtraction(original)) {
270        return SimplifySubtraction(original);
271      } else if (IsMultiplication(original)) {
272        return SimplifyMultiplication(original);
273      } else if (IsDivision(original)) {
274        return SimplifyDivision(original);
275      } else if (IsAverage(original)) {
276        return SimplifyAverage(original);
277      } else if (IsLog(original)) {
278        return SimplifyLog(original);
279      } else if (IsExp(original)) {
280        return SimplifyExp(original);
281      } else if (IsSquare(original)) {
282        return SimplifySquare(original);
283      } else if (IsSquareRoot(original)) {
284        return SimplifySquareRoot(original);
285      } else if (IsCube(original)) {
286        return SimplifyCube(original);
287      } else if (IsCubeRoot(original)) {
288        return SimplifyCubeRoot(original);
289      } else if (IsPower(original)) {
290        return SimplifyPower(original);
291      } else if (IsRoot(original)) {
292        return SimplifyRoot(original);
293      } else if (IsSine(original)) {
294        return SimplifySine(original);
295      } else if (IsCosine(original)) {
296        return SimplifyCosine(original);
297      } else if (IsTangent(original)) {
298        return SimplifyTangent(original);
299      } else if (IsAnalyticalQuotient(original)) {
300        return SimplifyAnalyticalQuotient(original);
301      } else if (IsIfThenElse(original)) {
302        return SimplifyIfThenElse(original);
303      } else if (IsGreaterThan(original)) {
304        return SimplifyGreaterThan(original);
305      } else if (IsLessThan(original)) {
306        return SimplifyLessThan(original);
307      } else if (IsAnd(original)) {
308        return SimplifyAnd(original);
309      } else if (IsOr(original)) {
310        return SimplifyOr(original);
311      } else if (IsNot(original)) {
312        return SimplifyNot(original);
313      } else if (IsTimeLag(original)) {
314        return SimplifyTimeLag(original);
315      } else if (IsIntegral(original)) {
316        return SimplifyIntegral(original);
317      } else {
318        return SimplifyAny(original);
319      }
320    }
321
322    #region specific simplification routines
323
324    private static ISymbolicExpressionTreeNode SimplifyAny(ISymbolicExpressionTreeNode original) {
325      // can't simplify this function but simplify all subtrees
326      List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(original.Subtrees);
327      while (original.Subtrees.Count() > 0) original.RemoveSubtree(0);
328      var clone = (SymbolicExpressionTreeNode)original.Clone();
329      List<ISymbolicExpressionTreeNode> simplifiedSubtrees = new List<ISymbolicExpressionTreeNode>();
330      foreach (var subtree in subtrees) {
331        simplifiedSubtrees.Add(GetSimplifiedTree(subtree));
332        original.AddSubtree(subtree);
333      }
334      foreach (var simplifiedSubtree in simplifiedSubtrees) {
335        clone.AddSubtree(simplifiedSubtree);
336      }
337      if (simplifiedSubtrees.TrueForAll(t => IsConstant(t))) {
338        SimplifyConstantExpression(clone);
339      }
340      return clone;
341    }
342
343    private static ISymbolicExpressionTreeNode SimplifyConstantExpression(ISymbolicExpressionTreeNode original) {
344      // not yet implemented
345      return original;
346    }
347
348    private static ISymbolicExpressionTreeNode SimplifyAverage(ISymbolicExpressionTreeNode original) {
349      if (original.Subtrees.Count() == 1) {
350        return GetSimplifiedTree(original.GetSubtree(0));
351      } else {
352        // simplify expressions x0..xn
353        // make sum(x0..xn) / n
354        var sum = original.Subtrees
355          .Select(GetSimplifiedTree)
356          .Aggregate(MakeSum);
357        return MakeFraction(sum, MakeConstant(original.Subtrees.Count()));
358      }
359    }
360
361    private static ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
362      if (original.Subtrees.Count() == 1) {
363        return Invert(GetSimplifiedTree(original.GetSubtree(0)));
364      } else {
365        // simplify expressions x0..xn
366        // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
367        var first = original.GetSubtree(0);
368        var second = original.GetSubtree(1);
369        var remaining = original.Subtrees.Skip(2);
370        return
371          MakeProduct(GetSimplifiedTree(first),
372            Invert(remaining.Aggregate(GetSimplifiedTree(second), (a, b) => MakeProduct(a, GetSimplifiedTree(b)))));
373      }
374    }
375
376    private static ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
377      if (original.Subtrees.Count() == 1) {
378        return GetSimplifiedTree(original.GetSubtree(0));
379      } else {
380        return original.Subtrees
381          .Select(GetSimplifiedTree)
382          .Aggregate(MakeProduct);
383      }
384    }
385
386    private static ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
387      if (original.Subtrees.Count() == 1) {
388        return Negate(GetSimplifiedTree(original.GetSubtree(0)));
389      } else {
390        // simplify expressions x0..xn
391        // make addition (x0,-x1..-xn)
392        var first = original.Subtrees.First();
393        var remaining = original.Subtrees.Skip(1);
394        return remaining.Aggregate(GetSimplifiedTree(first), (a, b) => MakeSum(a, Negate(GetSimplifiedTree(b))));
395      }
396    }
397
398    private static ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
399      if (original.Subtrees.Count() == 1) {
400        return GetSimplifiedTree(original.GetSubtree(0));
401      } else {
402        // simplify expression x0..xn
403        // make addition (x0..xn)
404        return original.Subtrees
405          .Select(GetSimplifiedTree)
406          .Aggregate(MakeSum);
407      }
408    }
409
410    private static ISymbolicExpressionTreeNode SimplifyAbsolute(ISymbolicExpressionTreeNode original) {
411      return MakeAbs(GetSimplifiedTree(original.GetSubtree(0)));
412    }
413
414    private static ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
415      return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
416    }
417
418    private static ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
419      return original.Subtrees
420        .Select(GetSimplifiedTree)
421        .Aggregate(MakeOr);
422    }
423
424    private static ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
425      return original.Subtrees
426        .Select(GetSimplifiedTree)
427        .Aggregate(MakeAnd);
428    }
429
430    private static ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
431      return MakeLessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
432    }
433
434    private static ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
435      return MakeGreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
436    }
437
438    private static ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
439      return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)),
440        GetSimplifiedTree(original.GetSubtree(2)));
441    }
442
443    private static ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
444      return MakeTangent(GetSimplifiedTree(original.GetSubtree(0)));
445    }
446
447    private static ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
448      return MakeCosine(GetSimplifiedTree(original.GetSubtree(0)));
449    }
450
451    private static ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
452      return MakeSine(GetSimplifiedTree(original.GetSubtree(0)));
453    }
454
455    private static ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
456      return MakeExp(GetSimplifiedTree(original.GetSubtree(0)));
457    }
458
459    private static ISymbolicExpressionTreeNode SimplifySquare(ISymbolicExpressionTreeNode original) {
460      return MakeSquare(GetSimplifiedTree(original.GetSubtree(0)));
461    }
462
463    private static ISymbolicExpressionTreeNode SimplifySquareRoot(ISymbolicExpressionTreeNode original) {
464      return MakeSquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
465    }
466    private static ISymbolicExpressionTreeNode SimplifyCube(ISymbolicExpressionTreeNode original) {
467      return MakeCube(GetSimplifiedTree(original.GetSubtree(0)));
468    }
469
470    private static ISymbolicExpressionTreeNode SimplifyCubeRoot(ISymbolicExpressionTreeNode original) {
471      return MakeCubeRoot(GetSimplifiedTree(original.GetSubtree(0)));
472    }
473
474    private static ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
475      return MakeLog(GetSimplifiedTree(original.GetSubtree(0)));
476    }
477
478    private static ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
479      return MakeRoot(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
480    }
481
482    private static ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
483      return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
484    }
485
486    private static ISymbolicExpressionTreeNode SimplifyAnalyticalQuotient(ISymbolicExpressionTreeNode original) {
487      return MakeAnalyticalQuotient(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
488    }
489
490    private static ISymbolicExpressionTreeNode SimplifyTimeLag(ISymbolicExpressionTreeNode original) {
491      var laggedTreeNode = original as ILaggedTreeNode;
492      var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
493      if (!ContainsVariableCondition(simplifiedSubtree)) {
494        return AddLagToDynamicNodes(simplifiedSubtree, laggedTreeNode.Lag);
495      } else {
496        return MakeTimeLag(simplifiedSubtree, laggedTreeNode.Lag);
497      }
498    }
499
500    private static ISymbolicExpressionTreeNode SimplifyIntegral(ISymbolicExpressionTreeNode original) {
501      var laggedTreeNode = original as ILaggedTreeNode;
502      var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
503      if (IsConstant(simplifiedSubtree)) {
504        return GetSimplifiedTree(MakeProduct(simplifiedSubtree, MakeConstant(-laggedTreeNode.Lag)));
505      } else {
506        return MakeIntegral(simplifiedSubtree, laggedTreeNode.Lag);
507      }
508    }
509
510    #endregion
511
512    #region low level tree restructuring
513
514    private static ISymbolicExpressionTreeNode MakeTimeLag(ISymbolicExpressionTreeNode subtree, int lag) {
515      if (lag == 0) return subtree;
516      if (IsConstant(subtree)) return subtree;
517      var lagNode = (LaggedTreeNode)timeLagSymbol.CreateTreeNode();
518      lagNode.Lag = lag;
519      lagNode.AddSubtree(subtree);
520      return lagNode;
521    }
522
523    private static ISymbolicExpressionTreeNode MakeIntegral(ISymbolicExpressionTreeNode subtree, int lag) {
524      if (lag == 0) return subtree;
525      else if (lag == -1 || lag == 1) {
526        return MakeSum(subtree, AddLagToDynamicNodes((ISymbolicExpressionTreeNode)subtree.Clone(), lag));
527      } else {
528        var node = (LaggedTreeNode)integralSymbol.CreateTreeNode();
529        node.Lag = lag;
530        node.AddSubtree(subtree);
531        return node;
532      }
533    }
534
535    private static ISymbolicExpressionTreeNode MakeNot(ISymbolicExpressionTreeNode t) {
536      if (IsConstant(t)) {
537        var constNode = t as ConstantTreeNode;
538        if (constNode.Value > 0) return MakeConstant(-1.0);
539        else return MakeConstant(1.0);
540      } else if (IsNot(t)) {
541        return t.GetSubtree(0);
542      } else if (!IsBoolean(t)) {
543        var gtNode = gtSymbol.CreateTreeNode();
544        gtNode.AddSubtree(t);
545        gtNode.AddSubtree(MakeConstant(0.0));
546        var notNode = notSymbol.CreateTreeNode();
547        notNode.AddSubtree(gtNode);
548        return notNode;
549      } else {
550        var notNode = notSymbol.CreateTreeNode();
551        notNode.AddSubtree(t);
552        return notNode;
553      }
554    }
555
556    private static ISymbolicExpressionTreeNode MakeOr(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
557      if (IsConstant(a) && IsConstant(b)) {
558        var constA = a as ConstantTreeNode;
559        var constB = b as ConstantTreeNode;
560        if (constA.Value > 0.0 || constB.Value > 0.0) {
561          return MakeConstant(1.0);
562        } else {
563          return MakeConstant(-1.0);
564        }
565      } else if (IsConstant(a)) {
566        return MakeOr(b, a);
567      } else if (IsConstant(b)) {
568        var constT = b as ConstantTreeNode;
569        if (constT.Value > 0.0) {
570          // boolean expression is necessarily true
571          return MakeConstant(1.0);
572        } else {
573          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
574          var orNode = orSymbol.CreateTreeNode();
575          orNode.AddSubtree(a);
576          return orNode;
577        }
578      } else {
579        var orNode = orSymbol.CreateTreeNode();
580        orNode.AddSubtree(a);
581        orNode.AddSubtree(b);
582        return orNode;
583      }
584    }
585
586    private static ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
587      if (IsConstant(a) && IsConstant(b)) {
588        var constA = a as ConstantTreeNode;
589        var constB = b as ConstantTreeNode;
590        if (constA.Value > 0.0 && constB.Value > 0.0) {
591          return MakeConstant(1.0);
592        } else {
593          return MakeConstant(-1.0);
594        }
595      } else if (IsConstant(a)) {
596        return MakeAnd(b, a);
597      } else if (IsConstant(b)) {
598        var constB = b as ConstantTreeNode;
599        if (constB.Value > 0.0) {
600          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
601          var andNode = andSymbol.CreateTreeNode();
602          andNode.AddSubtree(a);
603          return andNode;
604        } else {
605          // boolean expression is necessarily false
606          return MakeConstant(-1.0);
607        }
608      } else {
609        var andNode = andSymbol.CreateTreeNode();
610        andNode.AddSubtree(a);
611        andNode.AddSubtree(b);
612        return andNode;
613      }
614    }
615
616    private static ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide,
617      ISymbolicExpressionTreeNode rightSide) {
618      if (IsConstant(leftSide) && IsConstant(rightSide)) {
619        var lsConst = leftSide as ConstantTreeNode;
620        var rsConst = rightSide as ConstantTreeNode;
621        if (lsConst.Value < rsConst.Value) return MakeConstant(1.0);
622        else return MakeConstant(-1.0);
623      } else {
624        var ltNode = ltSymbol.CreateTreeNode();
625        ltNode.AddSubtree(leftSide);
626        ltNode.AddSubtree(rightSide);
627        return ltNode;
628      }
629    }
630
631    private static ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide,
632      ISymbolicExpressionTreeNode rightSide) {
633      if (IsConstant(leftSide) && IsConstant(rightSide)) {
634        var lsConst = leftSide as ConstantTreeNode;
635        var rsConst = rightSide as ConstantTreeNode;
636        if (lsConst.Value > rsConst.Value) return MakeConstant(1.0);
637        else return MakeConstant(-1.0);
638      } else {
639        var gtNode = gtSymbol.CreateTreeNode();
640        gtNode.AddSubtree(leftSide);
641        gtNode.AddSubtree(rightSide);
642        return gtNode;
643      }
644    }
645
646    private static ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition,
647      ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
648      if (IsConstant(condition)) {
649        var constT = condition as ConstantTreeNode;
650        if (constT.Value > 0.0) return trueBranch;
651        else return falseBranch;
652      } else {
653        var ifNode = ifThenElseSymbol.CreateTreeNode();
654        if (IsBoolean(condition)) {
655          ifNode.AddSubtree(condition);
656        } else {
657          var gtNode = gtSymbol.CreateTreeNode();
658          gtNode.AddSubtree(condition);
659          gtNode.AddSubtree(MakeConstant(0.0));
660          ifNode.AddSubtree(gtNode);
661        }
662        ifNode.AddSubtree(trueBranch);
663        ifNode.AddSubtree(falseBranch);
664        return ifNode;
665      }
666    }
667
668    private static ISymbolicExpressionTreeNode MakeSine(ISymbolicExpressionTreeNode node) {
669      if (IsConstant(node)) {
670        var constT = node as ConstantTreeNode;
671        return MakeConstant(Math.Sin(constT.Value));
672      } else if (IsFactor(node)) {
673        var factor = node as FactorVariableTreeNode;
674        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Sin));
675      } else if (IsBinFactor(node)) {
676        var binFactor = node as BinaryFactorVariableTreeNode;
677        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sin(binFactor.Weight));
678      } else {
679        var sineNode = sineSymbol.CreateTreeNode();
680        sineNode.AddSubtree(node);
681        return sineNode;
682      }
683    }
684
685    private static ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
686      if (IsConstant(node)) {
687        var constT = node as ConstantTreeNode;
688        return MakeConstant(Math.Tan(constT.Value));
689      } else if (IsFactor(node)) {
690        var factor = node as FactorVariableTreeNode;
691        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Tan));
692      } else if (IsBinFactor(node)) {
693        var binFactor = node as BinaryFactorVariableTreeNode;
694        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Tan(binFactor.Weight));
695      } else {
696        var tanNode = tanSymbol.CreateTreeNode();
697        tanNode.AddSubtree(node);
698        return tanNode;
699      }
700    }
701
702    private static ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
703      if (IsConstant(node)) {
704        var constT = node as ConstantTreeNode;
705        return MakeConstant(Math.Cos(constT.Value));
706      } else if (IsFactor(node)) {
707        var factor = node as FactorVariableTreeNode;
708        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Cos));
709      } else if (IsBinFactor(node)) {
710        var binFactor = node as BinaryFactorVariableTreeNode;
711        // cos(0) = 1 see similar case for Exp(binfactor)
712        return MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Cos(binFactor.Weight) - 1),
713          MakeConstant(1.0));
714      } else {
715        var cosNode = cosineSymbol.CreateTreeNode();
716        cosNode.AddSubtree(node);
717        return cosNode;
718      }
719    }
720
721    private static ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
722      if (IsConstant(node)) {
723        var constT = node as ConstantTreeNode;
724        return MakeConstant(Math.Exp(constT.Value));
725      } else if (IsFactor(node)) {
726        var factNode = node as FactorVariableTreeNode;
727        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Exp(w)));
728      } else if (IsBinFactor(node)) {
729        // exp( binfactor w val=a) = if(val=a) exp(w) else exp(0) = binfactor( (exp(w) - 1) val a) + 1
730        var binFactor = node as BinaryFactorVariableTreeNode;
731        return
732          MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Exp(binFactor.Weight) - 1), MakeConstant(1.0));
733      } else if (IsLog(node)) {
734        return node.GetSubtree(0);
735      } else if (IsAddition(node)) {
736        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, t));
737      } else if (IsSubtraction(node)) {
738        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, Negate(t)));
739      } else {
740        var expNode = expSymbol.CreateTreeNode();
741        expNode.AddSubtree(node);
742        return expNode;
743      }
744    }
745    private static ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
746      if (IsConstant(node)) {
747        var constT = node as ConstantTreeNode;
748        return MakeConstant(Math.Log(constT.Value));
749      } else if (IsFactor(node)) {
750        var factNode = node as FactorVariableTreeNode;
751        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Log(w)));
752      } else if (IsExp(node)) {
753        return node.GetSubtree(0);
754      } else if (IsSquareRoot(node)) {
755        return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
756      } else {
757        var logNode = logSymbol.CreateTreeNode();
758        logNode.AddSubtree(node);
759        return logNode;
760      }
761    }
762
763    private static ISymbolicExpressionTreeNode MakeSquare(ISymbolicExpressionTreeNode node) {
764      if (IsConstant(node)) {
765        var constT = node as ConstantTreeNode;
766        return MakeConstant(constT.Value * constT.Value);
767      } else if (IsFactor(node)) {
768        var factNode = node as FactorVariableTreeNode;
769        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w));
770      } else if (IsBinFactor(node)) {
771        var binFactor = node as BinaryFactorVariableTreeNode;
772        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight);
773      } else if (IsSquareRoot(node)) {
774        return node.GetSubtree(0);
775      } else if (IsMultiplication(node)) {
776        // sqr( x * y ) = sqr(x) * sqr(y)
777        var mulNode = mulSymbol.CreateTreeNode();
778        foreach (var subtree in node.Subtrees) {
779          mulNode.AddSubtree(MakeSquare(subtree));
780        }
781        return mulNode;
782      } else if (IsAbsolute(node)) {
783        return MakeSquare(node.GetSubtree(0)); // sqr(abs(x)) = sqr(x)
784      } else if (IsExp(node)) {
785        return MakeExp(MakeProduct(node.GetSubtree(0), MakeConstant(2.0))); // sqr(exp(x)) = exp(2x)
786      } else if (IsCube(node)) {
787        return MakePower(node.GetSubtree(0), MakeConstant(6));
788      } else {
789        var sqrNode = sqrSymbol.CreateTreeNode();
790        sqrNode.AddSubtree(node);
791        return sqrNode;
792      }
793    }
794
795    private static ISymbolicExpressionTreeNode MakeCube(ISymbolicExpressionTreeNode node) {
796      if (IsConstant(node)) {
797        var constT = node as ConstantTreeNode;
798        return MakeConstant(constT.Value * constT.Value * constT.Value);
799      } else if (IsFactor(node)) {
800        var factNode = node as FactorVariableTreeNode;
801        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w * w));
802      } else if (IsBinFactor(node)) {
803        var binFactor = node as BinaryFactorVariableTreeNode;
804        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight * binFactor.Weight);
805      } else if (IsCubeRoot(node)) {
806        return node.GetSubtree(0); // NOTE: not really accurate because cuberoot(x) with negative x is evaluated to NaN and after this simplification we evaluate as x
807      } else if (IsExp(node)) {
808        return MakeExp(MakeProduct(node.GetSubtree(0), MakeConstant(3)));
809      } else if (IsSquare(node)) {
810        return MakePower(node.GetSubtree(0), MakeConstant(6));
811      } else {
812        var cubeNode = cubeSymbol.CreateTreeNode();
813        cubeNode.AddSubtree(node);
814        return cubeNode;
815      }
816    }
817
818    private static ISymbolicExpressionTreeNode MakeAbs(ISymbolicExpressionTreeNode node) {
819      if (IsConstant(node)) {
820        var constT = node as ConstantTreeNode;
821        return MakeConstant(Math.Abs(constT.Value));
822      } else if (IsFactor(node)) {
823        var factNode = node as FactorVariableTreeNode;
824        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Abs(w)));
825      } else if (IsBinFactor(node)) {
826        var binFactor = node as BinaryFactorVariableTreeNode;
827        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Abs(binFactor.Weight));
828      } else if (IsSquare(node) || IsExp(node) || IsSquareRoot(node) || IsCubeRoot(node)) {
829        return node; // abs(sqr(x)) = sqr(x), abs(exp(x)) = exp(x) ...
830      } else if (IsMultiplication(node)) {
831        var mul = mulSymbol.CreateTreeNode();
832        foreach (var st in node.Subtrees) {
833          mul.AddSubtree(MakeAbs(st));
834        }
835        return mul;
836      } else if (IsDivision(node)) {
837        var div = divSymbol.CreateTreeNode();
838        foreach (var st in node.Subtrees) {
839          div.AddSubtree(MakeAbs(st));
840        }
841        return div;
842      } else {
843        var absNode = absSymbol.CreateTreeNode();
844        absNode.AddSubtree(node);
845        return absNode;
846      }
847    }
848
849    // constant folding only
850    private static ISymbolicExpressionTreeNode MakeAnalyticalQuotient(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
851      if (IsConstant(b)) {
852        var c = b as ConstantTreeNode;
853        return MakeFraction(a, MakeConstant(Math.Sqrt(1.0 + c.Value * c.Value)));
854      } else if (IsFactor(b)) {
855        var factNode = b as FactorVariableTreeNode;
856        return MakeFraction(a, MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(1.0 + w * w))));
857      } else if (IsBinFactor(b)) {
858        var binFactor = b as BinaryFactorVariableTreeNode;
859        return MakeFraction(a, MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(1.0 + binFactor.Weight * binFactor.Weight)));
860      } else {
861        var aqNode = aqSymbol.CreateTreeNode();
862        aqNode.AddSubtree(a);
863        aqNode.AddSubtree(b);
864        return aqNode;
865      }
866    }
867
868    private static ISymbolicExpressionTreeNode MakeSquareRoot(ISymbolicExpressionTreeNode node) {
869      if (IsConstant(node)) {
870        var constT = node as ConstantTreeNode;
871        return MakeConstant(Math.Sqrt(constT.Value));
872      } else if (IsFactor(node)) {
873        var factNode = node as FactorVariableTreeNode;
874        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(w)));
875      } else if (IsBinFactor(node)) {
876        var binFactor = node as BinaryFactorVariableTreeNode;
877        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(binFactor.Weight));
878      } else if (IsSquare(node)) {
879        return node.GetSubtree(0); // NOTE: not really accurate because sqrt(x) with negative x is evaluated to NaN and after this simplification we evaluate as x
880      } else {
881        var sqrtNode = sqrtSymbol.CreateTreeNode();
882        sqrtNode.AddSubtree(node);
883        return sqrtNode;
884      }
885    }
886
887    private static ISymbolicExpressionTreeNode MakeCubeRoot(ISymbolicExpressionTreeNode node) {
888      if (IsConstant(node)) {
889        var constT = node as ConstantTreeNode;
890        return MakeConstant(Math.Pow(constT.Value, 1.0 / 3.0));
891      } else if (IsFactor(node)) {
892        var factNode = node as FactorVariableTreeNode;
893        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, 1.0 / 3.0)));
894      } else if (IsBinFactor(node)) {
895        var binFactor = node as BinaryFactorVariableTreeNode;
896        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(Math.Pow(binFactor.Weight, 1.0 / 3.0)));
897      } else if (IsCube(node)) {
898        return node.GetSubtree(0);
899      } else {
900        var cubeRootNode = cubeRootSymbol.CreateTreeNode();
901        cubeRootNode.AddSubtree(node);
902        return cubeRootNode;
903      }
904    }
905
906    private static ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
907      if (IsConstant(a) && IsConstant(b)) {
908        var constA = a as ConstantTreeNode;
909        var constB = b as ConstantTreeNode;
910        return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
911      } else if (IsFactor(a) && IsConstant(b)) {
912        var factNode = a as FactorVariableTreeNode;
913        var constNode = b as ConstantTreeNode;
914        return MakeFactor(factNode.Symbol, factNode.VariableName,
915          factNode.Weights.Select(w => Math.Pow(w, 1.0 / Math.Round(constNode.Value))));
916      } else if (IsBinFactor(a) && IsConstant(b)) {
917        var binFactor = a as BinaryFactorVariableTreeNode;
918        var constNode = b as ConstantTreeNode;
919        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, 1.0 / Math.Round(constNode.Value)));
920      } else if (IsConstant(a) && IsFactor(b)) {
921        var constNode = a as ConstantTreeNode;
922        var factNode = b as FactorVariableTreeNode;
923        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, 1.0 / Math.Round(w))));
924      } else if (IsConstant(a) && IsBinFactor(b)) {
925        var constNode = a as ConstantTreeNode;
926        var factNode = b as BinaryFactorVariableTreeNode;
927        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, 1.0 / Math.Round(factNode.Weight)));
928      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
929        var node0 = a as FactorVariableTreeNode;
930        var node1 = b as FactorVariableTreeNode;
931        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, 1.0 / Math.Round(v))));
932      } else if (IsConstant(b)) {
933        var constB = b as ConstantTreeNode;
934        var constBValue = Math.Round(constB.Value);
935        if (constBValue.IsAlmost(1.0)) {
936          return a;
937        } else if (constBValue.IsAlmost(0.0)) {
938          return MakeConstant(1.0);
939        } else if (constBValue.IsAlmost(-1.0)) {
940          return MakeFraction(MakeConstant(1.0), a);
941        } else if (constBValue < 0) {
942          var rootNode = rootSymbol.CreateTreeNode();
943          rootNode.AddSubtree(a);
944          rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
945          return MakeFraction(MakeConstant(1.0), rootNode);
946        } else {
947          var rootNode = rootSymbol.CreateTreeNode();
948          rootNode.AddSubtree(a);
949          rootNode.AddSubtree(MakeConstant(constBValue));
950          return rootNode;
951        }
952      } else {
953        var rootNode = rootSymbol.CreateTreeNode();
954        rootNode.AddSubtree(a);
955        rootNode.AddSubtree(b);
956        return rootNode;
957      }
958    }
959
960
961    private static ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
962      if (IsConstant(a) && IsConstant(b)) {
963        var constA = a as ConstantTreeNode;
964        var constB = b as ConstantTreeNode;
965        return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
966      } else if (IsFactor(a) && IsConstant(b)) {
967        var factNode = a as FactorVariableTreeNode;
968        var constNode = b as ConstantTreeNode;
969        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, Math.Round(constNode.Value))));
970      } else if (IsBinFactor(a) && IsConstant(b)) {
971        var binFactor = a as BinaryFactorVariableTreeNode;
972        var constNode = b as ConstantTreeNode;
973        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, Math.Round(constNode.Value)));
974      } else if (IsConstant(a) && IsFactor(b)) {
975        var constNode = a as ConstantTreeNode;
976        var factNode = b as FactorVariableTreeNode;
977        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, Math.Round(w))));
978      } else if (IsConstant(a) && IsBinFactor(b)) {
979        var constNode = a as ConstantTreeNode;
980        var factNode = b as BinaryFactorVariableTreeNode;
981        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, Math.Round(factNode.Weight)));
982      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
983        var node0 = a as FactorVariableTreeNode;
984        var node1 = b as FactorVariableTreeNode;
985        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, Math.Round(v))));
986      } else if (IsConstant(b)) {
987        var constB = b as ConstantTreeNode;
988        double exponent = Math.Round(constB.Value);
989        if (exponent.IsAlmost(0.0)) {
990          return MakeConstant(1.0);
991        } else if (exponent.IsAlmost(1.0)) {
992          return a;
993        } else if (exponent.IsAlmost(-1.0)) {
994          return MakeFraction(MakeConstant(1.0), a);
995        } else if (exponent < 0) {
996          var powNode = powSymbol.CreateTreeNode();
997          powNode.AddSubtree(a);
998          powNode.AddSubtree(MakeConstant(-1.0 * exponent));
999          return MakeFraction(MakeConstant(1.0), powNode);
1000        } else {
1001          var powNode = powSymbol.CreateTreeNode();
1002          powNode.AddSubtree(a);
1003          powNode.AddSubtree(MakeConstant(exponent));
1004          return powNode;
1005        }
1006      } else {
1007        var powNode = powSymbol.CreateTreeNode();
1008        powNode.AddSubtree(a);
1009        powNode.AddSubtree(b);
1010        return powNode;
1011      }
1012    }
1013
1014
1015    // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
1016    private static ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1017      if (IsConstant(a) && IsConstant(b)) {
1018        // fold constants
1019        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
1020      } else if ((IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0))) {
1021        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
1022      } else if (IsVariableBase(a) && IsConstant(b)) {
1023        // merge constant values into variable weights
1024        var constB = ((ConstantTreeNode)b).Value;
1025        ((VariableTreeNodeBase)a).Weight /= constB;
1026        return a;
1027      } else if (IsFactor(a) && IsConstant(b)) {
1028        var factNode = a as FactorVariableTreeNode;
1029        var constNode = b as ConstantTreeNode;
1030        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w / constNode.Value));
1031      } else if (IsBinFactor(a) && IsConstant(b)) {
1032        var factNode = a as BinaryFactorVariableTreeNode;
1033        var constNode = b as ConstantTreeNode;
1034        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, factNode.Weight / constNode.Value);
1035      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
1036        var node0 = a as FactorVariableTreeNode;
1037        var node1 = b as FactorVariableTreeNode;
1038        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u / v));
1039      } else if (IsFactor(a) && IsBinFactor(b) && ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
1040        var node0 = a as FactorVariableTreeNode;
1041        var node1 = b as BinaryFactorVariableTreeNode;
1042        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
1043        var wi = Array.IndexOf(varValues, node1.VariableValue);
1044        if (wi < 0) throw new ArgumentException();
1045        var newWeighs = new double[varValues.Length];
1046        node0.Weights.CopyTo(newWeighs, 0);
1047        for (int i = 0; i < newWeighs.Length; i++)
1048          if (wi == i) newWeighs[i] /= node1.Weight;
1049          else newWeighs[i] /= 0.0;
1050        return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
1051      } else if (IsFactor(a)) {
1052        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
1053      } else if (IsVariableBase(a) && IsVariableBase(b) && AreSameTypeAndVariable(a, b) && !IsBinFactor(b)) {
1054        // cancel variables (not allowed for bin factors because of division by zero)
1055        var aVar = a as VariableTreeNode;
1056        var bVar = b as VariableTreeNode;
1057        return MakeConstant(aVar.Weight / bVar.Weight);
1058      } else if (IsAddition(a) && IsConstant(b)) {
1059        return a.Subtrees
1060          .Select(x => GetSimplifiedTree(x))
1061          .Select(x => MakeFraction(x, GetSimplifiedTree(b)))
1062          .Aggregate((c, d) => MakeSum(c, d));
1063      } else if (IsMultiplication(a) && IsConstant(b)) {
1064        return MakeProduct(a, Invert(b));
1065      } else if (IsDivision(a) && IsConstant(b)) {
1066        // (a1 / a2) / c => (a1 / (a2 * c))
1067        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
1068      } else if (IsDivision(a) && IsDivision(b)) {
1069        // (a1 / a2) / (b1 / b2) =>
1070        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
1071      } else if (IsDivision(a)) {
1072        // (a1 / a2) / b => (a1 / (a2 * b))
1073        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
1074      } else if (IsDivision(b)) {
1075        // a / (b1 / b2) => (a * b2) / b1
1076        return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
1077      } else if (IsAnalyticalQuotient(a)) {
1078        return MakeAnalyticalQuotient(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
1079      } else {
1080        var div = divSymbol.CreateTreeNode();
1081        div.AddSubtree(a);
1082        div.AddSubtree(b);
1083        return div;
1084      }
1085    }
1086
1087    private static ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1088      if (IsConstant(a) && IsConstant(b)) {
1089        // fold constants
1090        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
1091        return a;
1092      } else if (IsConstant(a)) {
1093        // c + x => x + c
1094        // b is not constant => make sure constant is on the right
1095        return MakeSum(b, a);
1096      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
1097        // x + 0 => x
1098        return a;
1099      } else if (IsFactor(a) && IsConstant(b)) {
1100        var factNode = a as FactorVariableTreeNode;
1101        var constNode = b as ConstantTreeNode;
1102        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select((w) => w + constNode.Value));
1103      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
1104        var node0 = a as FactorVariableTreeNode;
1105        var node1 = b as FactorVariableTreeNode;
1106        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u + v));
1107      } else if (IsBinFactor(a) && IsFactor(b)) {
1108        return MakeSum(b, a);
1109      } else if (IsFactor(a) && IsBinFactor(b) &&
1110        ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
1111        var node0 = a as FactorVariableTreeNode;
1112        var node1 = b as BinaryFactorVariableTreeNode;
1113        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
1114        var wi = Array.IndexOf(varValues, node1.VariableValue);
1115        if (wi < 0) throw new ArgumentException();
1116        var newWeighs = new double[varValues.Length];
1117        node0.Weights.CopyTo(newWeighs, 0);
1118        newWeighs[wi] += node1.Weight;
1119        return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
1120      } else if (IsAddition(a) && IsAddition(b)) {
1121        // merge additions
1122        var add = addSymbol.CreateTreeNode();
1123        // add all sub trees except for the last
1124        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
1125        for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
1126        if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
1127          add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
1128        } else if (IsConstant(a.Subtrees.Last())) {
1129          add.AddSubtree(b.Subtrees.Last());
1130          add.AddSubtree(a.Subtrees.Last());
1131        } else {
1132          add.AddSubtree(a.Subtrees.Last());
1133          add.AddSubtree(b.Subtrees.Last());
1134        }
1135        MergeVariablesInSum(add);
1136        if (add.Subtrees.Count() == 1) {
1137          return add.GetSubtree(0);
1138        } else {
1139          return add;
1140        }
1141      } else if (IsAddition(b)) {
1142        return MakeSum(b, a);
1143      } else if (IsAddition(a) && IsConstant(b)) {
1144        // a is an addition and b is a constant => append b to a and make sure the constants are merged
1145        var add = addSymbol.CreateTreeNode();
1146        // add all sub trees except for the last
1147        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
1148        if (IsConstant(a.Subtrees.Last()))
1149          add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
1150        else {
1151          add.AddSubtree(a.Subtrees.Last());
1152          add.AddSubtree(b);
1153        }
1154        return add;
1155      } else if (IsAddition(a)) {
1156        // a is already an addition => append b
1157        var add = addSymbol.CreateTreeNode();
1158        add.AddSubtree(b);
1159        foreach (var subtree in a.Subtrees) {
1160          add.AddSubtree(subtree);
1161        }
1162        MergeVariablesInSum(add);
1163        if (add.Subtrees.Count() == 1) {
1164          return add.GetSubtree(0);
1165        } else {
1166          return add;
1167        }
1168      } else {
1169        var add = addSymbol.CreateTreeNode();
1170        add.AddSubtree(a);
1171        add.AddSubtree(b);
1172        MergeVariablesInSum(add);
1173        if (add.Subtrees.Count() == 1) {
1174          return add.GetSubtree(0);
1175        } else {
1176          return add;
1177        }
1178      }
1179    }
1180
1181    // makes sure variable symbols in sums are combined
1182    private static void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
1183      var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
1184      while (sum.Subtrees.Any()) sum.RemoveSubtree(0);
1185      var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
1186                            where node.SubtreeCount == 0
1187                            group node by GroupId(node) into g
1188                            select g;
1189      var constant = (from node in subtrees.OfType<ConstantTreeNode>()
1190                      select node.Value).DefaultIfEmpty(0.0).Sum();
1191      var unchangedSubtrees = subtrees.Where(t => t.SubtreeCount > 0 || !(t is IVariableTreeNode) && !(t is ConstantTreeNode));
1192
1193      foreach (var variableNodeGroup in groupedVarNodes) {
1194        var firstNode = variableNodeGroup.First();
1195        if (firstNode is VariableTreeNodeBase) {
1196          var representative = firstNode as VariableTreeNodeBase;
1197          var weightSum = variableNodeGroup.Cast<VariableTreeNodeBase>().Select(t => t.Weight).Sum();
1198          representative.Weight = weightSum;
1199          sum.AddSubtree(representative);
1200        } else if (firstNode is FactorVariableTreeNode) {
1201          var representative = firstNode as FactorVariableTreeNode;
1202          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
1203            for (int j = 0; j < representative.Weights.Length; j++) {
1204              representative.Weights[j] += node.Weights[j];
1205            }
1206          }
1207          sum.AddSubtree(representative);
1208        }
1209      }
1210      foreach (var unchangedSubtree in unchangedSubtrees)
1211        sum.AddSubtree(unchangedSubtree);
1212      if (!constant.IsAlmost(0.0)) {
1213        sum.AddSubtree(MakeConstant(constant));
1214      }
1215    }
1216
1217    // nodes referencing variables can be grouped if they have
1218    private static string GroupId(IVariableTreeNode node) {
1219      var binaryFactorNode = node as BinaryFactorVariableTreeNode;
1220      var factorNode = node as FactorVariableTreeNode;
1221      var variableNode = node as VariableTreeNode;
1222      var laggedVarNode = node as LaggedVariableTreeNode;
1223      if (variableNode != null) {
1224        return "var " + variableNode.VariableName;
1225      } else if (binaryFactorNode != null) {
1226        return "binfactor " + binaryFactorNode.VariableName + " " + binaryFactorNode.VariableValue;
1227      } else if (factorNode != null) {
1228        return "factor " + factorNode.VariableName;
1229      } else if (laggedVarNode != null) {
1230        return "lagged " + laggedVarNode.VariableName + " " + laggedVarNode.Lag;
1231      } else {
1232        throw new NotSupportedException();
1233      }
1234    }
1235
1236
1237    private static ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1238      if (IsConstant(a) && IsConstant(b)) {
1239        // fold constants
1240        return MakeConstant(((ConstantTreeNode)a).Value * ((ConstantTreeNode)b).Value);
1241      } else if (IsConstant(a)) {
1242        // a * $ => $ * a
1243        return MakeProduct(b, a);
1244      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
1245        var node0 = a as FactorVariableTreeNode;
1246        var node1 = b as FactorVariableTreeNode;
1247        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u * v));
1248      } else if (IsBinFactor(a) && IsBinFactor(b) && AreSameTypeAndVariable(a, b)) {
1249        var node0 = a as BinaryFactorVariableTreeNode;
1250        var node1 = b as BinaryFactorVariableTreeNode;
1251        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Weight);
1252      } else if (IsFactor(a) && IsConstant(b)) {
1253        var node0 = a as FactorVariableTreeNode;
1254        var node1 = b as ConstantTreeNode;
1255        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Select(w => w * node1.Value));
1256      } else if (IsBinFactor(a) && IsConstant(b)) {
1257        var node0 = a as BinaryFactorVariableTreeNode;
1258        var node1 = b as ConstantTreeNode;
1259        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Value);
1260      } else if (IsBinFactor(a) && IsFactor(b)) {
1261        return MakeProduct(b, a);
1262      } else if (IsFactor(a) && IsBinFactor(b) &&
1263        ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
1264        var node0 = a as FactorVariableTreeNode;
1265        var node1 = b as BinaryFactorVariableTreeNode;
1266        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
1267        var wi = Array.IndexOf(varValues, node1.VariableValue);
1268        if (wi < 0) throw new ArgumentException();
1269        return MakeBinFactor(node1.Symbol, node1.VariableName, node1.VariableValue, node1.Weight * node0.Weights[wi]);
1270      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
1271        // $ * 1.0 => $
1272        return a;
1273      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
1274        return MakeConstant(0);
1275      } else if (IsConstant(b) && IsVariableBase(a)) {
1276        // multiply constants into variables weights
1277        ((VariableTreeNodeBase)a).Weight *= ((ConstantTreeNode)b).Value;
1278        return a;
1279      } else if (IsConstant(b) && IsAddition(a) ||
1280          IsFactor(b) && IsAddition(a) ||
1281          IsBinFactor(b) && IsAddition(a)) {
1282        // multiply constants into additions
1283        return a.Subtrees.Select(x => MakeProduct(GetSimplifiedTree(x), GetSimplifiedTree(b))).Aggregate((c, d) => MakeSum(c, d));
1284      } else if (IsDivision(a) && IsDivision(b)) {
1285        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
1286        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
1287      } else if (IsDivision(a)) {
1288        // (a1 / a2) * b => (a1 * b) / a2
1289        return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
1290      } else if (IsDivision(b)) {
1291        // a * (b1 / b2) => (b1 * a) / b2
1292        return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
1293      } else if (IsMultiplication(a) && IsMultiplication(b)) {
1294        // merge multiplications (make sure constants are merged)
1295        var mul = mulSymbol.CreateTreeNode();
1296        for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
1297        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
1298        MergeVariablesAndConstantsInProduct(mul);
1299        return mul;
1300      } else if (IsMultiplication(b)) {
1301        return MakeProduct(b, a);
1302      } else if (IsMultiplication(a)) {
1303        // a is already an multiplication => append b
1304        a.AddSubtree(GetSimplifiedTree(b));
1305        MergeVariablesAndConstantsInProduct(a);
1306        return a;
1307      } else if (IsAbsolute(a) && IsAbsolute(b)) {
1308        return MakeAbs(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)));
1309      } else if (IsAbsolute(a) && IsConstant(b)) {
1310        var constNode = b as ConstantTreeNode;
1311        var posF = Math.Abs(constNode.Value);
1312        if (constNode.Value > 0) {
1313          return MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF)));
1314        } else {
1315          var mul = mulSymbol.CreateTreeNode();
1316          mul.AddSubtree(MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF))));
1317          mul.AddSubtree(MakeConstant(-1.0));
1318          return mul;
1319        }
1320      } else if (IsAnalyticalQuotient(a)) {
1321        return MakeAnalyticalQuotient(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
1322      } else {
1323        var mul = mulSymbol.CreateTreeNode();
1324        mul.AddSubtree(a);
1325        mul.AddSubtree(b);
1326        MergeVariablesAndConstantsInProduct(mul);
1327        return mul;
1328      }
1329    }
1330
1331    #endregion
1332
1333    #region helper functions
1334
1335    private static bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
1336      if (node.Symbol is VariableCondition) return true;
1337      foreach (var subtree in node.Subtrees)
1338        if (ContainsVariableCondition(subtree)) return true;
1339      return false;
1340    }
1341
1342    private static ISymbolicExpressionTreeNode AddLagToDynamicNodes(ISymbolicExpressionTreeNode node, int lag) {
1343      var laggedTreeNode = node as ILaggedTreeNode;
1344      var variableNode = node as VariableTreeNode;
1345      var variableConditionNode = node as VariableConditionTreeNode;
1346      if (laggedTreeNode != null)
1347        laggedTreeNode.Lag += lag;
1348      else if (variableNode != null) {
1349        var laggedVariableNode = (LaggedVariableTreeNode)laggedVariableSymbol.CreateTreeNode();
1350        laggedVariableNode.Lag = lag;
1351        laggedVariableNode.VariableName = variableNode.VariableName;
1352        return laggedVariableNode;
1353      } else if (variableConditionNode != null) {
1354        throw new NotSupportedException("Removal of time lags around variable condition symbols is not allowed.");
1355      }
1356      var subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
1357      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
1358      foreach (var subtree in subtrees) {
1359        node.AddSubtree(AddLagToDynamicNodes(subtree, lag));
1360      }
1361      return node;
1362    }
1363
1364    private static bool AreSameTypeAndVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1365      return GroupId((IVariableTreeNode)a) == GroupId((IVariableTreeNode)b);
1366    }
1367
1368    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
1369    private static void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
1370      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
1371      while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
1372      var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
1373                            where node.SubtreeCount == 0
1374                            group node by GroupId(node) into g
1375                            orderby g.Count()
1376                            select g;
1377      var constantProduct = (from node in subtrees.OfType<VariableTreeNodeBase>()
1378                             select node.Weight)
1379        .Concat(from node in subtrees.OfType<ConstantTreeNode>()
1380                select node.Value)
1381        .DefaultIfEmpty(1.0)
1382        .Aggregate((c1, c2) => c1 * c2);
1383
1384      var unchangedSubtrees = from tree in subtrees
1385                              where tree.SubtreeCount > 0 || !(tree is IVariableTreeNode) && !(tree is ConstantTreeNode)
1386                              select tree;
1387
1388      foreach (var variableNodeGroup in groupedVarNodes) {
1389        var firstNode = variableNodeGroup.First();
1390        if (firstNode is VariableTreeNodeBase) {
1391          var representative = (VariableTreeNodeBase)firstNode;
1392          representative.Weight = 1.0;
1393          if (variableNodeGroup.Count() > 1) {
1394            var poly = mulSymbol.CreateTreeNode();
1395            for (int p = 0; p < variableNodeGroup.Count(); p++) {
1396              poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
1397            }
1398            prod.AddSubtree(poly);
1399          } else {
1400            prod.AddSubtree(representative);
1401          }
1402        } else if (firstNode is FactorVariableTreeNode) {
1403          var representative = (FactorVariableTreeNode)firstNode;
1404          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
1405            for (int j = 0; j < representative.Weights.Length; j++) {
1406              representative.Weights[j] *= node.Weights[j];
1407            }
1408          }
1409          for (int j = 0; j < representative.Weights.Length; j++) {
1410            representative.Weights[j] *= constantProduct;
1411          }
1412          constantProduct = 1.0;
1413          // if the product already contains a factor it is not necessary to multiply a constant below
1414          prod.AddSubtree(representative);
1415        }
1416      }
1417
1418      foreach (var unchangedSubtree in unchangedSubtrees)
1419        prod.AddSubtree(unchangedSubtree);
1420
1421      if (!constantProduct.IsAlmost(1.0)) {
1422        prod.AddSubtree(MakeConstant(constantProduct));
1423      }
1424    }
1425
1426
1427    /// <summary>
1428    /// x => x * -1
1429    /// Is only used in cases where it is not necessary to create new tree nodes. Manipulates x directly.
1430    /// </summary>
1431    /// <param name="x"></param>
1432    /// <returns>-x</returns>
1433    private static ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
1434      if (IsConstant(x)) {
1435        ((ConstantTreeNode)x).Value *= -1;
1436      } else if (IsVariableBase(x)) {
1437        var variableTree = (VariableTreeNodeBase)x;
1438        variableTree.Weight *= -1.0;
1439      } else if (IsFactor(x)) {
1440        var factorNode = (FactorVariableTreeNode)x;
1441        for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
1442      } else if (IsBinFactor(x)) {
1443        var factorNode = (BinaryFactorVariableTreeNode)x;
1444        factorNode.Weight *= -1;
1445      } else if (IsAddition(x)) {
1446        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
1447        var subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
1448        while (x.Subtrees.Any()) x.RemoveSubtree(0);
1449        foreach (var subtree in subtrees) {
1450          x.AddSubtree(Negate(subtree));
1451        }
1452      } else if (IsMultiplication(x) || IsDivision(x)) {
1453        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
1454        var lastSubTree = x.Subtrees.Last();
1455        x.RemoveSubtree(x.SubtreeCount - 1);
1456        x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
1457      } else {
1458        // any other function
1459        return MakeProduct(x, MakeConstant(-1));
1460      }
1461      return x;
1462    }
1463
1464    /// <summary>
1465    /// x => 1/x
1466    /// Must create new tree nodes
1467    /// </summary>
1468    /// <param name="x"></param>
1469    /// <returns></returns>
1470    private static ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
1471      if (IsConstant(x)) {
1472        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
1473      } else if (IsFactor(x)) {
1474        var factorNode = (FactorVariableTreeNode)x;
1475        return MakeFactor(factorNode.Symbol, factorNode.VariableName, factorNode.Weights.Select(w => 1.0 / w));
1476      } else if (IsDivision(x)) {
1477        return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
1478      } else {
1479        // any other function
1480        return MakeFraction(MakeConstant(1), x);
1481      }
1482    }
1483
1484    private static ISymbolicExpressionTreeNode MakeConstant(double value) {
1485      ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
1486      constantTreeNode.Value = value;
1487      return constantTreeNode;
1488    }
1489
1490    private static ISymbolicExpressionTreeNode MakeFactor(FactorVariable sy, string variableName, IEnumerable<double> weights) {
1491      var tree = (FactorVariableTreeNode)sy.CreateTreeNode();
1492      tree.VariableName = variableName;
1493      tree.Weights = weights.ToArray();
1494      return tree;
1495    }
1496    private static ISymbolicExpressionTreeNode MakeBinFactor(BinaryFactorVariable sy, string variableName, string variableValue, double weight) {
1497      var tree = (BinaryFactorVariableTreeNode)sy.CreateTreeNode();
1498      tree.VariableName = variableName;
1499      tree.VariableValue = variableValue;
1500      tree.Weight = weight;
1501      return tree;
1502    }
1503
1504
1505    #endregion
1506  }
1507}
Note: See TracBrowser for help on using the repository browser.