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

Last change on this file since 17820 was 17820, checked in by mkommend, 9 months ago

#2985: changed behavior of root simplification (rootSymbol(a,0) => double.NaN) and added comments for performed simplifications.

File size: 66.8 KB
Line 
1#region License Information
2
3/* HeuristicLab
4 * Copyright (C) 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 == 1.0) {
936          // root(a, 1) => a
937          return a;
938        } else if (constBValue == 0.0) {
939          // root(a, 0) is not defined
940          //return MakeConstant(1.0);
941          return MakeConstant(double.NaN);
942        } else if (constBValue == -1.0) {
943          // root(a, -1) => a^(-1/1) => 1/a
944          return MakeFraction(MakeConstant(1.0), a);
945        } else if (constBValue < 0) {
946          // root(a, -b) => a^(-1/b) => (1/a)^(1/b) => root(1, b) / root(a, b) => 1 / root(a, b)
947          var rootNode = rootSymbol.CreateTreeNode();
948          rootNode.AddSubtree(a);
949          rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
950          return MakeFraction(MakeConstant(1.0), rootNode);
951        } else {
952          var rootNode = rootSymbol.CreateTreeNode();
953          rootNode.AddSubtree(a);
954          rootNode.AddSubtree(MakeConstant(constBValue));
955          return rootNode;
956        }
957      } else {
958        var rootNode = rootSymbol.CreateTreeNode();
959        rootNode.AddSubtree(a);
960        rootNode.AddSubtree(b);
961        return rootNode;
962      }
963    }
964
965
966    private static ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
967      if (IsConstant(a) && IsConstant(b)) {
968        var constA = a as ConstantTreeNode;
969        var constB = b as ConstantTreeNode;
970        return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
971      } else if (IsFactor(a) && IsConstant(b)) {
972        var factNode = a as FactorVariableTreeNode;
973        var constNode = b as ConstantTreeNode;
974        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, Math.Round(constNode.Value))));
975      } else if (IsBinFactor(a) && IsConstant(b)) {
976        var binFactor = a as BinaryFactorVariableTreeNode;
977        var constNode = b as ConstantTreeNode;
978        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, Math.Round(constNode.Value)));
979      } else if (IsConstant(a) && IsFactor(b)) {
980        var constNode = a as ConstantTreeNode;
981        var factNode = b as FactorVariableTreeNode;
982        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, Math.Round(w))));
983      } else if (IsConstant(a) && IsBinFactor(b)) {
984        var constNode = a as ConstantTreeNode;
985        var factNode = b as BinaryFactorVariableTreeNode;
986        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, Math.Round(factNode.Weight)));
987      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
988        var node0 = a as FactorVariableTreeNode;
989        var node1 = b as FactorVariableTreeNode;
990        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, Math.Round(v))));
991      } else if (IsConstant(b)) {
992        var constB = b as ConstantTreeNode;
993        double exponent = Math.Round(constB.Value);
994        if (exponent == 0.0) {
995          // a^0 => 1
996          return MakeConstant(1.0);
997        } else if (exponent == 1.0) {
998          // a^1 => a
999          return a;
1000        } else if (exponent == -1.0) {
1001          // a^-1 => 1/a
1002          return MakeFraction(MakeConstant(1.0), a);
1003        } else if (exponent < 0) {
1004          // a^-b => (1/a)^b => 1/(a^b)
1005          var powNode = powSymbol.CreateTreeNode();
1006          powNode.AddSubtree(a);
1007          powNode.AddSubtree(MakeConstant(-1.0 * exponent));
1008          return MakeFraction(MakeConstant(1.0), powNode);
1009        } else {
1010          var powNode = powSymbol.CreateTreeNode();
1011          powNode.AddSubtree(a);
1012          powNode.AddSubtree(MakeConstant(exponent));
1013          return powNode;
1014        }
1015      } else {
1016        var powNode = powSymbol.CreateTreeNode();
1017        powNode.AddSubtree(a);
1018        powNode.AddSubtree(b);
1019        return powNode;
1020      }
1021    }
1022
1023
1024    // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
1025    private static ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1026      if (IsConstant(a) && IsConstant(b)) {
1027        // fold constants
1028        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
1029      } else if ((IsConstant(a) && ((ConstantTreeNode)a).Value != 1.0)) {
1030        // a / x => (a * 1/a) / (x * 1/a) => 1 / (x * 1/a)
1031        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
1032      } else if (IsVariableBase(a) && IsConstant(b)) {
1033        // merge constant values into variable weights
1034        var constB = ((ConstantTreeNode)b).Value;
1035        ((VariableTreeNodeBase)a).Weight /= constB;
1036        return a;
1037      } else if (IsFactor(a) && IsConstant(b)) {
1038        var factNode = a as FactorVariableTreeNode;
1039        var constNode = b as ConstantTreeNode;
1040        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w / constNode.Value));
1041      } else if (IsBinFactor(a) && IsConstant(b)) {
1042        var factNode = a as BinaryFactorVariableTreeNode;
1043        var constNode = b as ConstantTreeNode;
1044        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, factNode.Weight / constNode.Value);
1045      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
1046        var node0 = a as FactorVariableTreeNode;
1047        var node1 = b as FactorVariableTreeNode;
1048        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u / v));
1049      } else if (IsFactor(a) && IsBinFactor(b) && ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
1050        var node0 = a as FactorVariableTreeNode;
1051        var node1 = b as BinaryFactorVariableTreeNode;
1052        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
1053        var wi = Array.IndexOf(varValues, node1.VariableValue);
1054        if (wi < 0) throw new ArgumentException();
1055        var newWeighs = new double[varValues.Length];
1056        node0.Weights.CopyTo(newWeighs, 0);
1057        for (int i = 0; i < newWeighs.Length; i++)
1058          if (wi == i) newWeighs[i] /= node1.Weight;
1059          else newWeighs[i] /= 0.0;
1060        return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
1061      } else if (IsFactor(a)) {
1062        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
1063      } else if (IsVariableBase(a) && IsVariableBase(b) && AreSameTypeAndVariable(a, b) && !IsBinFactor(b)) {
1064        // cancel variables (not allowed for bin factors because of division by zero)
1065        var aVar = a as VariableTreeNode;
1066        var bVar = b as VariableTreeNode;
1067        return MakeConstant(aVar.Weight / bVar.Weight);
1068      } else if (IsAddition(a) && IsConstant(b)) {
1069        return a.Subtrees
1070          .Select(x => GetSimplifiedTree(x))
1071          .Select(x => MakeFraction(x, GetSimplifiedTree(b)))
1072          .Aggregate((c, d) => MakeSum(c, d));
1073      } else if (IsMultiplication(a) && IsConstant(b)) {
1074        return MakeProduct(a, Invert(b));
1075      } else if (IsDivision(a) && IsConstant(b)) {
1076        // (a1 / a2) / c => (a1 / (a2 * c))
1077        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
1078      } else if (IsDivision(a) && IsDivision(b)) {
1079        // (a1 / a2) / (b1 / b2) =>
1080        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
1081      } else if (IsDivision(a)) {
1082        // (a1 / a2) / b => (a1 / (a2 * b))
1083        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
1084      } else if (IsDivision(b)) {
1085        // a / (b1 / b2) => (a * b2) / b1
1086        return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
1087      } else if (IsAnalyticalQuotient(a)) {
1088        return MakeAnalyticalQuotient(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
1089      } else {
1090        var div = divSymbol.CreateTreeNode();
1091        div.AddSubtree(a);
1092        div.AddSubtree(b);
1093        return div;
1094      }
1095    }
1096
1097    private static ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1098      if (IsConstant(a) && IsConstant(b)) {
1099        // fold constants
1100        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
1101        return a;
1102      } else if (IsConstant(a)) {
1103        // c + x => x + c
1104        // b is not constant => make sure constant is on the right
1105        return MakeSum(b, a);
1106      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value == 0.0) {
1107        // x + 0 => x
1108        return a;
1109      } else if (IsFactor(a) && IsConstant(b)) {
1110        var factNode = a as FactorVariableTreeNode;
1111        var constNode = b as ConstantTreeNode;
1112        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select((w) => w + constNode.Value));
1113      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
1114        var node0 = a as FactorVariableTreeNode;
1115        var node1 = b as FactorVariableTreeNode;
1116        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u + v));
1117      } else if (IsBinFactor(a) && IsFactor(b)) {
1118        return MakeSum(b, a);
1119      } else if (IsFactor(a) && IsBinFactor(b) &&
1120        ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
1121        var node0 = a as FactorVariableTreeNode;
1122        var node1 = b as BinaryFactorVariableTreeNode;
1123        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
1124        var wi = Array.IndexOf(varValues, node1.VariableValue);
1125        if (wi < 0) throw new ArgumentException();
1126        var newWeighs = new double[varValues.Length];
1127        node0.Weights.CopyTo(newWeighs, 0);
1128        newWeighs[wi] += node1.Weight;
1129        return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
1130      } else if (IsAddition(a) && IsAddition(b)) {
1131        // merge additions
1132        var add = addSymbol.CreateTreeNode();
1133        // add all sub trees except for the last
1134        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
1135        for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
1136        if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
1137          add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
1138        } else if (IsConstant(a.Subtrees.Last())) {
1139          add.AddSubtree(b.Subtrees.Last());
1140          add.AddSubtree(a.Subtrees.Last());
1141        } else {
1142          add.AddSubtree(a.Subtrees.Last());
1143          add.AddSubtree(b.Subtrees.Last());
1144        }
1145        MergeVariablesInSum(add);
1146        if (add.Subtrees.Count() == 1) {
1147          return add.GetSubtree(0);
1148        } else {
1149          return add;
1150        }
1151      } else if (IsAddition(b)) {
1152        return MakeSum(b, a);
1153      } else if (IsAddition(a) && IsConstant(b)) {
1154        // a is an addition and b is a constant => append b to a and make sure the constants are merged
1155        var add = addSymbol.CreateTreeNode();
1156        // add all sub trees except for the last
1157        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
1158        if (IsConstant(a.Subtrees.Last()))
1159          add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
1160        else {
1161          add.AddSubtree(a.Subtrees.Last());
1162          add.AddSubtree(b);
1163        }
1164        return add;
1165      } else if (IsAddition(a)) {
1166        // a is already an addition => append b
1167        var add = addSymbol.CreateTreeNode();
1168        add.AddSubtree(b);
1169        foreach (var subtree in a.Subtrees) {
1170          add.AddSubtree(subtree);
1171        }
1172        MergeVariablesInSum(add);
1173        if (add.Subtrees.Count() == 1) {
1174          return add.GetSubtree(0);
1175        } else {
1176          return add;
1177        }
1178      } else {
1179        var add = addSymbol.CreateTreeNode();
1180        add.AddSubtree(a);
1181        add.AddSubtree(b);
1182        MergeVariablesInSum(add);
1183        if (add.Subtrees.Count() == 1) {
1184          return add.GetSubtree(0);
1185        } else {
1186          return add;
1187        }
1188      }
1189    }
1190
1191    // makes sure variable symbols in sums are combined
1192    private static void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
1193      var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
1194      while (sum.Subtrees.Any()) sum.RemoveSubtree(0);
1195      var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
1196                            where node.SubtreeCount == 0
1197                            group node by GroupId(node) into g
1198                            select g;
1199      var constant = (from node in subtrees.OfType<ConstantTreeNode>()
1200                      select node.Value).DefaultIfEmpty(0.0).Sum();
1201      var unchangedSubtrees = subtrees.Where(t => t.SubtreeCount > 0 || !(t is IVariableTreeNode) && !(t is ConstantTreeNode));
1202
1203      foreach (var variableNodeGroup in groupedVarNodes) {
1204        var firstNode = variableNodeGroup.First();
1205        if (firstNode is VariableTreeNodeBase) {
1206          var representative = firstNode as VariableTreeNodeBase;
1207          var weightSum = variableNodeGroup.Cast<VariableTreeNodeBase>().Select(t => t.Weight).Sum();
1208          representative.Weight = weightSum;
1209          sum.AddSubtree(representative);
1210        } else if (firstNode is FactorVariableTreeNode) {
1211          var representative = firstNode as FactorVariableTreeNode;
1212          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
1213            for (int j = 0; j < representative.Weights.Length; j++) {
1214              representative.Weights[j] += node.Weights[j];
1215            }
1216          }
1217          sum.AddSubtree(representative);
1218        }
1219      }
1220      foreach (var unchangedSubtree in unchangedSubtrees)
1221        sum.AddSubtree(unchangedSubtree);
1222      if (constant != 0.0) {
1223        sum.AddSubtree(MakeConstant(constant));
1224      }
1225    }
1226
1227    // nodes referencing variables can be grouped if they have
1228    private static string GroupId(IVariableTreeNode node) {
1229      var binaryFactorNode = node as BinaryFactorVariableTreeNode;
1230      var factorNode = node as FactorVariableTreeNode;
1231      var variableNode = node as VariableTreeNode;
1232      var laggedVarNode = node as LaggedVariableTreeNode;
1233      if (variableNode != null) {
1234        return "var " + variableNode.VariableName;
1235      } else if (binaryFactorNode != null) {
1236        return "binfactor " + binaryFactorNode.VariableName + " " + binaryFactorNode.VariableValue;
1237      } else if (factorNode != null) {
1238        return "factor " + factorNode.VariableName;
1239      } else if (laggedVarNode != null) {
1240        return "lagged " + laggedVarNode.VariableName + " " + laggedVarNode.Lag;
1241      } else {
1242        throw new NotSupportedException();
1243      }
1244    }
1245
1246
1247    private static ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1248      if (IsConstant(a) && IsConstant(b)) {
1249        // fold constants
1250        return MakeConstant(((ConstantTreeNode)a).Value * ((ConstantTreeNode)b).Value);
1251      } else if (IsConstant(a)) {
1252        // a * $ => $ * a
1253        return MakeProduct(b, a);
1254      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
1255        var node0 = a as FactorVariableTreeNode;
1256        var node1 = b as FactorVariableTreeNode;
1257        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u * v));
1258      } else if (IsBinFactor(a) && IsBinFactor(b) && AreSameTypeAndVariable(a, b)) {
1259        var node0 = a as BinaryFactorVariableTreeNode;
1260        var node1 = b as BinaryFactorVariableTreeNode;
1261        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Weight);
1262      } else if (IsFactor(a) && IsConstant(b)) {
1263        var node0 = a as FactorVariableTreeNode;
1264        var node1 = b as ConstantTreeNode;
1265        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Select(w => w * node1.Value));
1266      } else if (IsBinFactor(a) && IsConstant(b)) {
1267        var node0 = a as BinaryFactorVariableTreeNode;
1268        var node1 = b as ConstantTreeNode;
1269        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Value);
1270      } else if (IsBinFactor(a) && IsFactor(b)) {
1271        return MakeProduct(b, a);
1272      } else if (IsFactor(a) && IsBinFactor(b) &&
1273        ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
1274        var node0 = a as FactorVariableTreeNode;
1275        var node1 = b as BinaryFactorVariableTreeNode;
1276        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
1277        var wi = Array.IndexOf(varValues, node1.VariableValue);
1278        if (wi < 0) throw new ArgumentException();
1279        return MakeBinFactor(node1.Symbol, node1.VariableName, node1.VariableValue, node1.Weight * node0.Weights[wi]);
1280      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value == 1.0) {
1281        // $ * 1.0 => $
1282        return a;
1283      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value == 0.0) {
1284        return MakeConstant(0);
1285      } else if (IsConstant(b) && IsVariableBase(a)) {
1286        // multiply constants into variables weights
1287        ((VariableTreeNodeBase)a).Weight *= ((ConstantTreeNode)b).Value;
1288        return a;
1289      } else if (IsConstant(b) && IsAddition(a) ||
1290          IsFactor(b) && IsAddition(a) ||
1291          IsBinFactor(b) && IsAddition(a)) {
1292        // multiply constants into additions
1293        return a.Subtrees.Select(x => MakeProduct(GetSimplifiedTree(x), GetSimplifiedTree(b))).Aggregate((c, d) => MakeSum(c, d));
1294      } else if (IsDivision(a) && IsDivision(b)) {
1295        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
1296        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
1297      } else if (IsDivision(a)) {
1298        // (a1 / a2) * b => (a1 * b) / a2
1299        return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
1300      } else if (IsDivision(b)) {
1301        // a * (b1 / b2) => (b1 * a) / b2
1302        return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
1303      } else if (IsMultiplication(a) && IsMultiplication(b)) {
1304        // merge multiplications (make sure constants are merged)
1305        var mul = mulSymbol.CreateTreeNode();
1306        for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
1307        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
1308        MergeVariablesAndConstantsInProduct(mul);
1309        return mul;
1310      } else if (IsMultiplication(b)) {
1311        return MakeProduct(b, a);
1312      } else if (IsMultiplication(a)) {
1313        // a is already an multiplication => append b
1314        a.AddSubtree(GetSimplifiedTree(b));
1315        MergeVariablesAndConstantsInProduct(a);
1316        return a;
1317      } else if (IsAbsolute(a) && IsAbsolute(b)) {
1318        return MakeAbs(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)));
1319      } else if (IsAbsolute(a) && IsConstant(b)) {
1320        var constNode = b as ConstantTreeNode;
1321        var posF = Math.Abs(constNode.Value);
1322        if (constNode.Value > 0) {
1323          return MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF)));
1324        } else {
1325          var mul = mulSymbol.CreateTreeNode();
1326          mul.AddSubtree(MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF))));
1327          mul.AddSubtree(MakeConstant(-1.0));
1328          return mul;
1329        }
1330      } else if (IsAnalyticalQuotient(a)) {
1331        return MakeAnalyticalQuotient(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
1332      } else {
1333        var mul = mulSymbol.CreateTreeNode();
1334        mul.AddSubtree(a);
1335        mul.AddSubtree(b);
1336        MergeVariablesAndConstantsInProduct(mul);
1337        return mul;
1338      }
1339    }
1340
1341    #endregion
1342
1343    #region helper functions
1344
1345    private static bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
1346      if (node.Symbol is VariableCondition) return true;
1347      foreach (var subtree in node.Subtrees)
1348        if (ContainsVariableCondition(subtree)) return true;
1349      return false;
1350    }
1351
1352    private static ISymbolicExpressionTreeNode AddLagToDynamicNodes(ISymbolicExpressionTreeNode node, int lag) {
1353      var laggedTreeNode = node as ILaggedTreeNode;
1354      var variableNode = node as VariableTreeNode;
1355      var variableConditionNode = node as VariableConditionTreeNode;
1356      if (laggedTreeNode != null)
1357        laggedTreeNode.Lag += lag;
1358      else if (variableNode != null) {
1359        var laggedVariableNode = (LaggedVariableTreeNode)laggedVariableSymbol.CreateTreeNode();
1360        laggedVariableNode.Lag = lag;
1361        laggedVariableNode.VariableName = variableNode.VariableName;
1362        return laggedVariableNode;
1363      } else if (variableConditionNode != null) {
1364        throw new NotSupportedException("Removal of time lags around variable condition symbols is not allowed.");
1365      }
1366      var subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
1367      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
1368      foreach (var subtree in subtrees) {
1369        node.AddSubtree(AddLagToDynamicNodes(subtree, lag));
1370      }
1371      return node;
1372    }
1373
1374    private static bool AreSameTypeAndVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1375      return GroupId((IVariableTreeNode)a) == GroupId((IVariableTreeNode)b);
1376    }
1377
1378    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
1379    private static void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
1380      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
1381      while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
1382      var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
1383                            where node.SubtreeCount == 0
1384                            group node by GroupId(node) into g
1385                            orderby g.Count()
1386                            select g;
1387      var constantProduct = (from node in subtrees.OfType<VariableTreeNodeBase>()
1388                             select node.Weight)
1389        .Concat(from node in subtrees.OfType<ConstantTreeNode>()
1390                select node.Value)
1391        .DefaultIfEmpty(1.0)
1392        .Aggregate((c1, c2) => c1 * c2);
1393
1394      var unchangedSubtrees = from tree in subtrees
1395                              where tree.SubtreeCount > 0 || !(tree is IVariableTreeNode) && !(tree is ConstantTreeNode)
1396                              select tree;
1397
1398      foreach (var variableNodeGroup in groupedVarNodes) {
1399        var firstNode = variableNodeGroup.First();
1400        if (firstNode is VariableTreeNodeBase) {
1401          var representative = (VariableTreeNodeBase)firstNode;
1402          representative.Weight = 1.0;
1403          if (variableNodeGroup.Count() > 1) {
1404            var poly = mulSymbol.CreateTreeNode();
1405            for (int p = 0; p < variableNodeGroup.Count(); p++) {
1406              poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
1407            }
1408            prod.AddSubtree(poly);
1409          } else {
1410            prod.AddSubtree(representative);
1411          }
1412        } else if (firstNode is FactorVariableTreeNode) {
1413          var representative = (FactorVariableTreeNode)firstNode;
1414          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
1415            for (int j = 0; j < representative.Weights.Length; j++) {
1416              representative.Weights[j] *= node.Weights[j];
1417            }
1418          }
1419          for (int j = 0; j < representative.Weights.Length; j++) {
1420            representative.Weights[j] *= constantProduct;
1421          }
1422          constantProduct = 1.0;
1423          // if the product already contains a factor it is not necessary to multiply a constant below
1424          prod.AddSubtree(representative);
1425        }
1426      }
1427
1428      foreach (var unchangedSubtree in unchangedSubtrees)
1429        prod.AddSubtree(unchangedSubtree);
1430
1431      if (constantProduct != 1.0) {
1432        prod.AddSubtree(MakeConstant(constantProduct));
1433      }
1434    }
1435
1436
1437    /// <summary>
1438    /// x => x * -1
1439    /// Is only used in cases where it is not necessary to create new tree nodes. Manipulates x directly.
1440    /// </summary>
1441    /// <param name="x"></param>
1442    /// <returns>-x</returns>
1443    private static ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
1444      if (IsConstant(x)) {
1445        ((ConstantTreeNode)x).Value *= -1;
1446      } else if (IsVariableBase(x)) {
1447        var variableTree = (VariableTreeNodeBase)x;
1448        variableTree.Weight *= -1.0;
1449      } else if (IsFactor(x)) {
1450        var factorNode = (FactorVariableTreeNode)x;
1451        for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
1452      } else if (IsBinFactor(x)) {
1453        var factorNode = (BinaryFactorVariableTreeNode)x;
1454        factorNode.Weight *= -1;
1455      } else if (IsAddition(x)) {
1456        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
1457        var subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
1458        while (x.Subtrees.Any()) x.RemoveSubtree(0);
1459        foreach (var subtree in subtrees) {
1460          x.AddSubtree(Negate(subtree));
1461        }
1462      } else if (IsMultiplication(x) || IsDivision(x)) {
1463        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
1464        var lastSubTree = x.Subtrees.Last();
1465        x.RemoveSubtree(x.SubtreeCount - 1);
1466        x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
1467      } else {
1468        // any other function
1469        return MakeProduct(x, MakeConstant(-1));
1470      }
1471      return x;
1472    }
1473
1474    /// <summary>
1475    /// x => 1/x
1476    /// Must create new tree nodes
1477    /// </summary>
1478    /// <param name="x"></param>
1479    /// <returns></returns>
1480    private static ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
1481      if (IsConstant(x)) {
1482        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
1483      } else if (IsFactor(x)) {
1484        var factorNode = (FactorVariableTreeNode)x;
1485        return MakeFactor(factorNode.Symbol, factorNode.VariableName, factorNode.Weights.Select(w => 1.0 / w));
1486      } else if (IsDivision(x)) {
1487        return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
1488      } else {
1489        // any other function
1490        return MakeFraction(MakeConstant(1), x);
1491      }
1492    }
1493
1494    private static ISymbolicExpressionTreeNode MakeConstant(double value) {
1495      ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
1496      constantTreeNode.Value = value;
1497      return constantTreeNode;
1498    }
1499
1500    private static ISymbolicExpressionTreeNode MakeFactor(FactorVariable sy, string variableName, IEnumerable<double> weights) {
1501      var tree = (FactorVariableTreeNode)sy.CreateTreeNode();
1502      tree.VariableName = variableName;
1503      tree.Weights = weights.ToArray();
1504      return tree;
1505    }
1506    private static ISymbolicExpressionTreeNode MakeBinFactor(BinaryFactorVariable sy, string variableName, string variableValue, double weight) {
1507      var tree = (BinaryFactorVariableTreeNode)sy.CreateTreeNode();
1508      tree.VariableName = variableName;
1509      tree.VariableValue = variableValue;
1510      tree.Weight = weight;
1511      return tree;
1512    }
1513
1514
1515    #endregion
1516  }
1517}
Note: See TracBrowser for help on using the repository browser.