source: branches/3140_NumberSymbol/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs @ 18113

Last change on this file since 18113 was 18113, checked in by chaider, 8 months ago

#3140

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