Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 18132 was 18132, checked in by gkronber, 2 years ago

#3140: merged r18091:18131 from branch to trunk

File size: 65.3 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 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      var 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 IsNumber(ISymbolicExpressionTreeNode node) {
243      return node.Symbol is Number;
244    }
245    private static bool IsConstant(ISymbolicExpressionTreeNode node) {
246      return node.Symbol is Constant;
247    }
248    private static bool IsConstantOrNumber(ISymbolicExpressionTreeNode node) {
249      return node is INumericTreeNode;
250    }
251
252    private static bool IsTimeLag(ISymbolicExpressionTreeNode node) {
253      return node.Symbol is TimeLag;
254    }
255
256    private static bool IsIntegral(ISymbolicExpressionTreeNode node) {
257      return node.Symbol is Integral;
258    }
259
260    #endregion
261
262    /// <summary>
263    /// Creates a new simplified tree
264    /// </summary>
265    /// <param name="original"></param>
266    /// <returns></returns>
267    public static ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
268      if (IsConstantOrNumber(original) || IsVariableBase(original)) {
269        return (ISymbolicExpressionTreeNode)original.Clone();
270      } else if (IsAbsolute(original)) {
271        return SimplifyAbsolute(original);
272      } else if (IsAddition(original)) {
273        return SimplifyAddition(original);
274      } else if (IsSubtraction(original)) {
275        return SimplifySubtraction(original);
276      } else if (IsMultiplication(original)) {
277        return SimplifyMultiplication(original);
278      } else if (IsDivision(original)) {
279        return SimplifyDivision(original);
280      } else if (IsAverage(original)) {
281        return SimplifyAverage(original);
282      } else if (IsLog(original)) {
283        return SimplifyLog(original);
284      } else if (IsExp(original)) {
285        return SimplifyExp(original);
286      } else if (IsSquare(original)) {
287        return SimplifySquare(original);
288      } else if (IsSquareRoot(original)) {
289        return SimplifySquareRoot(original);
290      } else if (IsCube(original)) {
291        return SimplifyCube(original);
292      } else if (IsCubeRoot(original)) {
293        return SimplifyCubeRoot(original);
294      } else if (IsPower(original)) {
295        return SimplifyPower(original);
296      } else if (IsRoot(original)) {
297        return SimplifyRoot(original);
298      } else if (IsSine(original)) {
299        return SimplifySine(original);
300      } else if (IsCosine(original)) {
301        return SimplifyCosine(original);
302      } else if (IsTangent(original)) {
303        return SimplifyTangent(original);
304      } else if (IsAnalyticalQuotient(original)) {
305        return SimplifyAnalyticalQuotient(original);
306      } else if (IsIfThenElse(original)) {
307        return SimplifyIfThenElse(original);
308      } else if (IsGreaterThan(original)) {
309        return SimplifyGreaterThan(original);
310      } else if (IsLessThan(original)) {
311        return SimplifyLessThan(original);
312      } else if (IsAnd(original)) {
313        return SimplifyAnd(original);
314      } else if (IsOr(original)) {
315        return SimplifyOr(original);
316      } else if (IsNot(original)) {
317        return SimplifyNot(original);
318      } else if (IsTimeLag(original)) {
319        return SimplifyTimeLag(original);
320      } else if (IsIntegral(original)) {
321        return SimplifyIntegral(original);
322      } else {
323        return SimplifyAny(original);
324      }
325    }
326
327    #region specific simplification routines
328
329    private static ISymbolicExpressionTreeNode SimplifyAny(ISymbolicExpressionTreeNode original) {
330      // can't simplify this function but simplify all subtrees
331      var subtrees = new List<ISymbolicExpressionTreeNode>(original.Subtrees);
332      while (original.Subtrees.Count() > 0) original.RemoveSubtree(0);
333      var clone = (SymbolicExpressionTreeNode)original.Clone();
334      var simplifiedSubtrees = new List<ISymbolicExpressionTreeNode>();
335      foreach (var subtree in subtrees) {
336        simplifiedSubtrees.Add(GetSimplifiedTree(subtree));
337        original.AddSubtree(subtree);
338      }
339      foreach (var simplifiedSubtree in simplifiedSubtrees) {
340        clone.AddSubtree(simplifiedSubtree);
341      }
342      if (simplifiedSubtrees.TrueForAll(IsNumber)) {
343        FoldNumbers(clone);
344      }
345      return clone;
346    }
347
348    private static ISymbolicExpressionTreeNode FoldNumbers(ISymbolicExpressionTreeNode original) {
349      // TODO not implemented
350      return original;
351    }
352
353    private static ISymbolicExpressionTreeNode SimplifyAverage(ISymbolicExpressionTreeNode original) {
354      if (original.Subtrees.Count() == 1) {
355        return GetSimplifiedTree(original.GetSubtree(0));
356      } else {
357        // simplify expressions x0..xn
358        // make sum(x0..xn) / n
359        var sum = original.Subtrees
360          .Select(GetSimplifiedTree)
361          .Aggregate(Sum);
362        return Fraction(sum, Number(original.Subtrees.Count()));
363      }
364    }
365
366    private static ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
367      if (original.Subtrees.Count() == 1) {
368        return Invert(GetSimplifiedTree(original.GetSubtree(0)));
369      } else {
370        // simplify expressions x0..xn
371        // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
372        var first = original.GetSubtree(0);
373        var second = original.GetSubtree(1);
374        var remaining = original.Subtrees.Skip(2);
375        return
376          Product(GetSimplifiedTree(first),
377            Invert(remaining.Aggregate(GetSimplifiedTree(second), (a, b) => Product(a, GetSimplifiedTree(b)))));
378      }
379    }
380
381    private static ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
382      if (original.Subtrees.Count() == 1) {
383        return GetSimplifiedTree(original.GetSubtree(0));
384      } else {
385        return original.Subtrees
386          .Select(GetSimplifiedTree)
387          .Aggregate(Product);
388      }
389    }
390
391    private static ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
392      if (original.Subtrees.Count() == 1) {
393        return Negate(GetSimplifiedTree(original.GetSubtree(0)));
394      } else {
395        // simplify expressions x0..xn
396        // make addition (x0,-x1..-xn)
397        var first = original.Subtrees.First();
398        var remaining = original.Subtrees.Skip(1);
399        return remaining.Aggregate(GetSimplifiedTree(first), (a, b) => Sum(a, Negate(GetSimplifiedTree(b))));
400      }
401    }
402
403    private static ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
404      if (original.Subtrees.Count() == 1) {
405        return GetSimplifiedTree(original.GetSubtree(0));
406      } else {
407        // simplify expression x0..xn
408        // make addition (x0..xn)
409        return original.Subtrees
410          .Select(GetSimplifiedTree)
411          .Aggregate(Sum);
412      }
413    }
414
415    private static ISymbolicExpressionTreeNode SimplifyAbsolute(ISymbolicExpressionTreeNode original) {
416      return Abs(GetSimplifiedTree(original.GetSubtree(0)));
417    }
418
419    private static ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
420      return Not(GetSimplifiedTree(original.GetSubtree(0)));
421    }
422
423    private static ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
424      return original.Subtrees
425        .Select(GetSimplifiedTree)
426        .Aggregate(Or);
427    }
428
429    private static ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
430      return original.Subtrees
431        .Select(GetSimplifiedTree)
432        .Aggregate(And);
433    }
434
435    private static ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
436      return LessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
437    }
438
439    private static ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
440      return GreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
441    }
442
443    private static ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
444      return IfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)),
445        GetSimplifiedTree(original.GetSubtree(2)));
446    }
447
448    private static ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
449      return Tangent(GetSimplifiedTree(original.GetSubtree(0)));
450    }
451
452    private static ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
453      return Cosine(GetSimplifiedTree(original.GetSubtree(0)));
454    }
455
456    private static ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
457      return Sine(GetSimplifiedTree(original.GetSubtree(0)));
458    }
459
460    private static ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
461      return Exp(GetSimplifiedTree(original.GetSubtree(0)));
462    }
463
464    private static ISymbolicExpressionTreeNode SimplifySquare(ISymbolicExpressionTreeNode original) {
465      return Square(GetSimplifiedTree(original.GetSubtree(0)));
466    }
467
468    private static ISymbolicExpressionTreeNode SimplifySquareRoot(ISymbolicExpressionTreeNode original) {
469      return SquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
470    }
471    private static ISymbolicExpressionTreeNode SimplifyCube(ISymbolicExpressionTreeNode original) {
472      return Cube(GetSimplifiedTree(original.GetSubtree(0)));
473    }
474
475    private static ISymbolicExpressionTreeNode SimplifyCubeRoot(ISymbolicExpressionTreeNode original) {
476      return CubeRoot(GetSimplifiedTree(original.GetSubtree(0)));
477    }
478
479    private static ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
480      return Log(GetSimplifiedTree(original.GetSubtree(0)));
481    }
482
483    private static ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
484      return Root(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
485    }
486
487    private static ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
488      return Power(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
489    }
490
491    private static ISymbolicExpressionTreeNode SimplifyAnalyticalQuotient(ISymbolicExpressionTreeNode original) {
492      return AQ(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
493    }
494
495    private static ISymbolicExpressionTreeNode SimplifyTimeLag(ISymbolicExpressionTreeNode original) {
496      var laggedTreeNode = original as ILaggedTreeNode;
497      var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
498      if (!ContainsVariableCondition(simplifiedSubtree)) {
499        return AddLagToDynamicNodes(simplifiedSubtree, laggedTreeNode.Lag);
500      } else {
501        return Lag(simplifiedSubtree, laggedTreeNode.Lag);
502      }
503    }
504
505    private static ISymbolicExpressionTreeNode SimplifyIntegral(ISymbolicExpressionTreeNode original) {
506      var laggedTreeNode = original as ILaggedTreeNode;
507      var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
508      if (IsConstantOrNumber(simplifiedSubtree)) {
509        return GetSimplifiedTree(Product(simplifiedSubtree, Number(-laggedTreeNode.Lag)));
510      } else {
511        return Integral(simplifiedSubtree, laggedTreeNode.Lag);
512      }
513    }
514
515    #endregion
516
517    #region low level tree restructuring
518
519    private static ISymbolicExpressionTreeNode Lag(ISymbolicExpressionTreeNode subtree, int lag) {
520      if (lag == 0) return subtree;
521      if (IsConstantOrNumber(subtree)) return subtree;
522      var lagNode = (LaggedTreeNode)timeLagSymbol.CreateTreeNode();
523      lagNode.Lag = lag;
524      lagNode.AddSubtree(subtree);
525      return lagNode;
526    }
527
528    private static ISymbolicExpressionTreeNode Integral(ISymbolicExpressionTreeNode subtree, int lag) {
529      if (lag == 0) return subtree;
530      else if (lag == -1 || lag == 1) {
531        return Sum(subtree, AddLagToDynamicNodes((ISymbolicExpressionTreeNode)subtree.Clone(), lag));
532      } else {
533        var node = (LaggedTreeNode)integralSymbol.CreateTreeNode();
534        node.Lag = lag;
535        node.AddSubtree(subtree);
536        return node;
537      }
538    }
539
540    private static ISymbolicExpressionTreeNode Not(ISymbolicExpressionTreeNode t) {
541      if (IsNumber(t)) {
542        var numNode = t as NumberTreeNode;
543        if (numNode.Value > 0) return Number(-1.0);
544        else return Number(1.0);
545      } else if (IsNot(t)) {
546        return t.GetSubtree(0);
547      } else if (!IsBoolean(t)) {
548        var gtNode = gtSymbol.CreateTreeNode();
549        gtNode.AddSubtree(t);
550        gtNode.AddSubtree(Number(0.0));
551        var notNode = notSymbol.CreateTreeNode();
552        notNode.AddSubtree(gtNode);
553        return notNode;
554      } else {
555        var notNode = notSymbol.CreateTreeNode();
556        notNode.AddSubtree(t);
557        return notNode;
558      }
559    }
560
561    private static ISymbolicExpressionTreeNode Or(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
562      if (IsNumber(a) && IsNumber(b)) {
563        var aNode = a as NumberTreeNode;
564        var bNode = b as NumberTreeNode;
565        if (aNode.Value > 0.0 || bNode.Value > 0.0) {
566          return Number(1.0);
567        } else {
568          return Number(-1.0);
569        }
570      } else if (IsNumber(a)) {
571        return Or(b, a);
572      } else if (IsNumber(b)) {
573        var bNode = b as NumberTreeNode;
574        if (bNode.Value > 0.0) {
575          // boolean expression is necessarily true
576          return Number(1.0);
577        } else {
578          // the value has no effect on the result of the boolean condition so we can drop the number
579          var orNode = orSymbol.CreateTreeNode();
580          orNode.AddSubtree(a);
581          return orNode;
582        }
583      } else {
584        var orNode = orSymbol.CreateTreeNode();
585        orNode.AddSubtree(a);
586        orNode.AddSubtree(b);
587        return orNode;
588      }
589    }
590
591    private static ISymbolicExpressionTreeNode And(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
592      if (IsNumber(a) && IsNumber(b)) {
593        var aNode = a as NumberTreeNode;
594        var bNode = b as NumberTreeNode;
595        if (aNode.Value > 0.0 && bNode.Value > 0.0) {
596          return Number(1.0);
597        } else {
598          return Number(-1.0);
599        }
600      } else if (IsNumber(a)) {
601        return And(b, a);
602      } else if (IsNumber(b)) {
603        var bNode = b as NumberTreeNode;
604        if (bNode.Value > 0.0) {
605          // the value has no effect on the result of the boolean condition so we can drop the number
606          var andNode = andSymbol.CreateTreeNode();
607          andNode.AddSubtree(a);
608          return andNode;
609        } else {
610          // boolean expression is necessarily false
611          return Number(-1.0);
612        }
613      } else {
614        var andNode = andSymbol.CreateTreeNode();
615        andNode.AddSubtree(a);
616        andNode.AddSubtree(b);
617        return andNode;
618      }
619    }
620
621    private static ISymbolicExpressionTreeNode LessThan(ISymbolicExpressionTreeNode leftSide,
622      ISymbolicExpressionTreeNode rightSide) {
623      if (IsNumber(leftSide) && IsNumber(rightSide)) {
624        var lsNode = leftSide as NumberTreeNode;
625        var rsNode = rightSide as NumberTreeNode;
626        if (lsNode.Value < rsNode.Value) return Number(1.0);
627        else return Number(-1.0);
628      } else {
629        var ltNode = ltSymbol.CreateTreeNode();
630        ltNode.AddSubtree(leftSide);
631        ltNode.AddSubtree(rightSide);
632        return ltNode;
633      }
634    }
635
636    private static ISymbolicExpressionTreeNode GreaterThan(ISymbolicExpressionTreeNode leftSide,
637      ISymbolicExpressionTreeNode rightSide) {
638      if (IsNumber(leftSide) && IsNumber(rightSide)) {
639        var lsNode = leftSide as NumberTreeNode;
640        var rsNode = rightSide as NumberTreeNode;
641        if (lsNode.Value > rsNode.Value) return Number(1.0);
642        else return Number(-1.0);
643      } else {
644        var gtNode = gtSymbol.CreateTreeNode();
645        gtNode.AddSubtree(leftSide);
646        gtNode.AddSubtree(rightSide);
647        return gtNode;
648      }
649    }
650
651    private static ISymbolicExpressionTreeNode IfThenElse(ISymbolicExpressionTreeNode condition,
652      ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
653      if (IsConstantOrNumber(condition)) {
654        var condNode = condition as INumericTreeNode;
655        if (condNode.Value > 0.0) return trueBranch;
656        else return falseBranch;
657      } else {
658        var ifNode = ifThenElseSymbol.CreateTreeNode();
659        if (IsBoolean(condition)) {
660          ifNode.AddSubtree(condition);
661        } else {
662          var gtNode = gtSymbol.CreateTreeNode();
663          gtNode.AddSubtree(condition);
664          gtNode.AddSubtree(Number(0.0));
665          ifNode.AddSubtree(gtNode);
666        }
667        ifNode.AddSubtree(trueBranch);
668        ifNode.AddSubtree(falseBranch);
669        return ifNode;
670      }
671    }
672
673    private static ISymbolicExpressionTreeNode Sine(ISymbolicExpressionTreeNode node) {
674      if (IsNumber(node)) {
675        var numNode = node as NumberTreeNode;
676        return Number(Math.Sin(numNode.Value));
677      } else if (IsFactor(node)) {
678        var factor = node as FactorVariableTreeNode;
679        return Factor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Sin));
680      } else if (IsBinFactor(node)) {
681        var binFactor = node as BinaryFactorVariableTreeNode;
682        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sin(binFactor.Weight));
683      } else {
684        var sineNode = sineSymbol.CreateTreeNode();
685        sineNode.AddSubtree(node);
686        return sineNode;
687      }
688    }
689
690    private static ISymbolicExpressionTreeNode Tangent(ISymbolicExpressionTreeNode node) {
691      if (IsNumber(node)) {
692        var numNode = node as NumberTreeNode;
693        return Number(Math.Tan(numNode.Value));
694      } else if (IsFactor(node)) {
695        var factor = node as FactorVariableTreeNode;
696        return Factor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Tan));
697      } else if (IsBinFactor(node)) {
698        var binFactor = node as BinaryFactorVariableTreeNode;
699        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Tan(binFactor.Weight));
700      } else {
701        var tanNode = tanSymbol.CreateTreeNode();
702        tanNode.AddSubtree(node);
703        return tanNode;
704      }
705    }
706
707    private static ISymbolicExpressionTreeNode Cosine(ISymbolicExpressionTreeNode node) {
708      if (IsNumber(node)) {
709        var numNode = node as NumberTreeNode;
710        return Number(Math.Cos(numNode.Value));
711      } else if (IsFactor(node)) {
712        var factor = node as FactorVariableTreeNode;
713        return Factor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Cos));
714      } else if (IsBinFactor(node)) {
715        var binFactor = node as BinaryFactorVariableTreeNode;
716        // cos(0) = 1 see similar case for Exp(binfactor)
717        return Sum(BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Cos(binFactor.Weight) - 1),
718          Number(1.0));
719      } else {
720        var cosNode = cosineSymbol.CreateTreeNode();
721        cosNode.AddSubtree(node);
722        return cosNode;
723      }
724    }
725
726    private static ISymbolicExpressionTreeNode Exp(ISymbolicExpressionTreeNode node) {
727      if (IsNumber(node)) {
728        var numNode = node as NumberTreeNode;
729        return Number(Math.Exp(numNode.Value));
730      } else if (IsFactor(node)) {
731        var factNode = node as FactorVariableTreeNode;
732        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Exp(w)));
733      } else if (IsBinFactor(node)) {
734        // exp( binfactor w val=a) = if(val=a) exp(w) else exp(0) = binfactor( (exp(w) - 1) val a) + 1
735        var binFactor = node as BinaryFactorVariableTreeNode;
736        return
737          Sum(BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Exp(binFactor.Weight) - 1), Number(1.0));
738      } else if (IsLog(node)) {
739        return node.GetSubtree(0);
740      } else if (IsAddition(node)) {
741        return node.Subtrees.Select(s => Exp(s)).Aggregate((s, t) => Product(s, t));
742      } else if (IsSubtraction(node)) {
743        return node.Subtrees.Select(s => Exp(s)).Aggregate((s, t) => Product(s, Negate(t)));
744      } else {
745        var expNode = expSymbol.CreateTreeNode();
746        expNode.AddSubtree(node);
747        return expNode;
748      }
749    }
750    private static ISymbolicExpressionTreeNode Log(ISymbolicExpressionTreeNode node) {
751      if (IsNumber(node)) {
752        var numNode = node as NumberTreeNode;
753        return Number(Math.Log(numNode.Value));
754      } else if (IsFactor(node)) {
755        var factNode = node as FactorVariableTreeNode;
756        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Log(w)));
757      } else if (IsExp(node)) {
758        return node.GetSubtree(0);
759      } else if (IsSquareRoot(node)) {
760        return Fraction(Log(node.GetSubtree(0)), Number(2.0));
761      } else {
762        var logNode = logSymbol.CreateTreeNode();
763        logNode.AddSubtree(node);
764        return logNode;
765      }
766    }
767
768    private static ISymbolicExpressionTreeNode Square(ISymbolicExpressionTreeNode node) {
769      if (IsNumber(node)) {
770        var numNode = node as NumberTreeNode;
771        return Number(numNode.Value * numNode.Value);
772      } else if (IsFactor(node)) {
773        var factNode = node as FactorVariableTreeNode;
774        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w));
775      } else if (IsBinFactor(node)) {
776        var binFactor = node as BinaryFactorVariableTreeNode;
777        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight);
778      } else if (IsSquareRoot(node)) {
779        return node.GetSubtree(0);
780      } else if (IsMultiplication(node)) {
781        // sqr( x * y ) = sqr(x) * sqr(y)
782        var mulNode = mulSymbol.CreateTreeNode();
783        foreach (var subtree in node.Subtrees) {
784          mulNode.AddSubtree(Square(subtree));
785        }
786        return mulNode;
787      } else if (IsAbsolute(node)) {
788        return Square(node.GetSubtree(0)); // sqr(abs(x)) = sqr(x)
789      } else if (IsExp(node)) {
790        return Exp(Product(node.GetSubtree(0), Number(2.0))); // sqr(exp(x)) = exp(2x)
791      } else if (IsSquare(node)) {
792        return Power(node.GetSubtree(0), Number(4));
793      } else if (IsCube(node)) {
794        return Power(node.GetSubtree(0), Number(6));
795      } else {
796        var sqrNode = sqrSymbol.CreateTreeNode();
797        sqrNode.AddSubtree(node);
798        return sqrNode;
799      }
800    }
801
802    private static ISymbolicExpressionTreeNode Cube(ISymbolicExpressionTreeNode node) {
803      if (IsNumber(node)) {
804        var numNode = node as NumberTreeNode;
805        return Number(numNode.Value * numNode.Value * numNode.Value);
806      } else if (IsFactor(node)) {
807        var factNode = node as FactorVariableTreeNode;
808        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w * w));
809      } else if (IsBinFactor(node)) {
810        var binFactor = node as BinaryFactorVariableTreeNode;
811        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight * binFactor.Weight);
812      } else if (IsCubeRoot(node)) {
813        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
814      } else if (IsExp(node)) {
815        return Exp(Product(node.GetSubtree(0), Number(3)));
816      } else if (IsSquare(node)) {
817        return Power(node.GetSubtree(0), Number(6));
818      } else if (IsCube(node)) {
819        return Power(node.GetSubtree(0), Number(9));
820      } else {
821        var cubeNode = cubeSymbol.CreateTreeNode();
822        cubeNode.AddSubtree(node);
823        return cubeNode;
824      }
825    }
826
827    private static ISymbolicExpressionTreeNode Abs(ISymbolicExpressionTreeNode node) {
828      if (IsNumber(node)) {
829        var numNode = node as NumberTreeNode;
830        return Number(Math.Abs(numNode.Value));
831      } else if (IsFactor(node)) {
832        var factNode = node as FactorVariableTreeNode;
833        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Abs(w)));
834      } else if (IsBinFactor(node)) {
835        var binFactor = node as BinaryFactorVariableTreeNode;
836        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Abs(binFactor.Weight));
837      } else if (IsSquare(node) || IsExp(node) || IsSquareRoot(node) || IsCubeRoot(node)) {
838        return node; // abs(sqr(x)) = sqr(x), abs(exp(x)) = exp(x) ...
839      } else if (IsMultiplication(node)) {
840        var mul = mulSymbol.CreateTreeNode();
841        foreach (var st in node.Subtrees) {
842          mul.AddSubtree(Abs(st));
843        }
844        return mul;
845      } else if (IsDivision(node)) {
846        var div = divSymbol.CreateTreeNode();
847        foreach (var st in node.Subtrees) {
848          div.AddSubtree(Abs(st));
849        }
850        return div;
851      } else {
852        var absNode = absSymbol.CreateTreeNode();
853        absNode.AddSubtree(node);
854        return absNode;
855      }
856    }
857
858    // constant folding only
859    private static ISymbolicExpressionTreeNode AQ(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
860      if (IsNumber(b)) {
861        var nNode = b as NumberTreeNode;
862        return Fraction(a, Number(Math.Sqrt(1.0 + nNode.Value * nNode.Value)));
863      } else if (IsFactor(b)) {
864        var factNode = b as FactorVariableTreeNode;
865        return Fraction(a, Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(1.0 + w * w))));
866      } else if (IsBinFactor(b)) {
867        var binFactor = b as BinaryFactorVariableTreeNode;
868        return Fraction(a, BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(1.0 + binFactor.Weight * binFactor.Weight)));
869      } else {
870        var aqNode = aqSymbol.CreateTreeNode();
871        aqNode.AddSubtree(a);
872        aqNode.AddSubtree(b);
873        return aqNode;
874      }
875    }
876
877    private static ISymbolicExpressionTreeNode SquareRoot(ISymbolicExpressionTreeNode node) {
878      if (IsNumber(node)) {
879        var numNode = node as NumberTreeNode;
880        return Number(Math.Sqrt(numNode.Value));
881      } else if (IsFactor(node)) {
882        var factNode = node as FactorVariableTreeNode;
883        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(w)));
884      } else if (IsBinFactor(node)) {
885        var binFactor = node as BinaryFactorVariableTreeNode;
886        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(binFactor.Weight));
887      } else if (IsSquare(node)) {
888        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
889      } else {
890        var sqrtNode = sqrtSymbol.CreateTreeNode();
891        sqrtNode.AddSubtree(node);
892        return sqrtNode;
893      }
894    }
895
896    private static ISymbolicExpressionTreeNode CubeRoot(ISymbolicExpressionTreeNode node) {
897      if (IsNumber(node)) {
898        var numNode = node as NumberTreeNode;
899        return Number(Math.Pow(numNode.Value, 1.0 / 3.0));
900      } else if (IsFactor(node)) {
901        var factNode = node as FactorVariableTreeNode;
902        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, 1.0 / 3.0)));
903      } else if (IsBinFactor(node)) {
904        var binFactor = node as BinaryFactorVariableTreeNode;
905        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(Math.Pow(binFactor.Weight, 1.0 / 3.0)));
906      } else if (IsCube(node)) {
907        return node.GetSubtree(0);
908      } else {
909        var cubeRootNode = cubeRootSymbol.CreateTreeNode();
910        cubeRootNode.AddSubtree(node);
911        return cubeRootNode;
912      }
913    }
914
915    private static ISymbolicExpressionTreeNode Root(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
916      if (IsNumber(a) && IsNumber(b)) {
917        var aNode = a as NumberTreeNode;
918        var bNode = b as NumberTreeNode;
919        return Number(Math.Pow(aNode.Value, 1.0 / Math.Round(bNode.Value)));
920      } else if (IsFactor(a) && IsNumber(b)) {
921        var factNode = a as FactorVariableTreeNode;
922        var bNode = b as NumberTreeNode;
923        return Factor(factNode.Symbol, factNode.VariableName,
924          factNode.Weights.Select(w => Math.Pow(w, 1.0 / Math.Round(bNode.Value))));
925      } else if (IsBinFactor(a) && IsNumber(b)) {
926        var binFactor = a as BinaryFactorVariableTreeNode;
927        var bNode = b as NumberTreeNode;
928        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, 1.0 / Math.Round(bNode.Value)));
929      } else if (IsNumber(a) && IsFactor(b)) {
930        var aNode = a as NumberTreeNode;
931        var factNode = b as FactorVariableTreeNode;
932        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(aNode.Value, 1.0 / Math.Round(w))));
933      } else if (IsNumber(a) && IsBinFactor(b)) {
934        var aNode = a as NumberTreeNode;
935        var factNode = b as BinaryFactorVariableTreeNode;
936        return BinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(aNode.Value, 1.0 / Math.Round(factNode.Weight)));
937      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
938        var node0 = a as FactorVariableTreeNode;
939        var node1 = b as FactorVariableTreeNode;
940        return Factor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, 1.0 / Math.Round(v))));
941      } else if (IsNumber(b)) {
942        var bNode = b as NumberTreeNode;
943        var bVal = Math.Round(bNode.Value);
944        if (bVal == 1.0) {
945          // root(a, 1) => a
946          return a;
947        } else if (bVal == 0.0) {
948          // root(a, 0) is not defined
949          return Number(double.NaN);
950        } else if (bVal == -1.0) {
951          // root(a, -1) => a^(-1/1) => 1/a
952          return Fraction(Number(1.0), a);
953        } else if (bVal < 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(Number(-1.0 * bVal));
958          return Fraction(Number(1.0), rootNode);
959        } else {
960          var rootNode = rootSymbol.CreateTreeNode();
961          rootNode.AddSubtree(a);
962          rootNode.AddSubtree(Number(bVal));
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 Power(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
975      if (IsNumber(a) && IsNumber(b)) {
976        var aNode = a as NumberTreeNode;
977        var bNode = b as NumberTreeNode;
978        return Number(Math.Pow(aNode.Value, Math.Round(bNode.Value)));
979      } else if (IsFactor(a) && IsNumber(b)) {
980        var factNode = a as FactorVariableTreeNode;
981        var bNode = b as NumberTreeNode;
982        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, Math.Round(bNode.Value))));
983      } else if (IsBinFactor(a) && IsNumber(b)) {
984        var binFactor = a as BinaryFactorVariableTreeNode;
985        var bNode = b as NumberTreeNode;
986        return BinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, Math.Round(bNode.Value)));
987      } else if (IsNumber(a) && IsFactor(b)) {
988        var aNode = a as NumberTreeNode;
989        var factNode = b as FactorVariableTreeNode;
990        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(aNode.Value, Math.Round(w))));
991      } else if (IsNumber(a) && IsBinFactor(b)) {
992        var aNode = a as NumberTreeNode;
993        var factNode = b as BinaryFactorVariableTreeNode;
994        return BinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(aNode.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 Factor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, Math.Round(v))));
999      } else if (IsNumber(b)) {
1000        var bNode = b as NumberTreeNode;
1001        double exponent = Math.Round(bNode.Value);
1002        if (exponent == 0.0) {
1003          // a^0 => 1
1004          return Number(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 Fraction(Number(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(Number(-1.0 * exponent));
1016          return Fraction(Number(1.0), powNode);
1017        } else {
1018          var powNode = powSymbol.CreateTreeNode();
1019          powNode.AddSubtree(a);
1020          powNode.AddSubtree(Number(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    // Fraction, Product and Sum take two already simplified trees and create a new simplified tree
1033    private static ISymbolicExpressionTreeNode Fraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1034      if (IsNumber(a) && IsNumber(b)) {
1035        // fold constants
1036        return Number(((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 Fraction(Number(1.0), Product(b, Invert(a)));
1040      } else if (IsVariableBase(a) && IsNumber(b)) {
1041        // merge constant values into variable weights
1042        var bVal = ((NumberTreeNode)b).Value;
1043        ((VariableTreeNodeBase)a).Weight /= bVal;
1044        return a;
1045      } else if (IsFactor(a) && IsNumber(b)) {
1046        var factNode = a as FactorVariableTreeNode;
1047        var bNode = b as NumberTreeNode;
1048        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w / bNode.Value));
1049      } else if (IsBinFactor(a) && IsNumber(b)) {
1050        var factNode = a as BinaryFactorVariableTreeNode;
1051        var bNode = b as NumberTreeNode;
1052        return BinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, factNode.Weight / bNode.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 Factor(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 Factor(node0.Symbol, node0.VariableName, newWeighs);
1069      } else if (IsFactor(a)) {
1070        return Fraction(Number(1.0), Product(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 Number(aVar.Weight / bVar.Weight);
1076      } else if (IsAddition(a) && IsNumber(b)) {
1077        return a.Subtrees
1078          .Select(x => GetSimplifiedTree(x))
1079          .Select(x => Fraction(x, GetSimplifiedTree(b)))
1080          .Aggregate((c, d) => Sum(c, d));
1081      } else if (IsMultiplication(a) && IsNumber(b)) {
1082        return Product(a, Invert(b));
1083      } else if (IsDivision(a) && IsNumber(b)) {
1084        // (a1 / a2) / c => (a1 / (a2 * c))
1085        return Fraction(a.GetSubtree(0), Product(a.GetSubtree(1), b));
1086      } else if (IsDivision(a) && IsDivision(b)) {
1087        // (a1 / a2) / (b1 / b2) =>
1088        return Fraction(Product(a.GetSubtree(0), b.GetSubtree(1)), Product(a.GetSubtree(1), b.GetSubtree(0)));
1089      } else if (IsDivision(a)) {
1090        // (a1 / a2) / b => (a1 / (a2 * b))
1091        return Fraction(a.GetSubtree(0), Product(a.GetSubtree(1), b));
1092      } else if (IsDivision(b)) {
1093        // a / (b1 / b2) => (a * b2) / b1
1094        return Fraction(Product(a, b.GetSubtree(1)), b.GetSubtree(0));
1095      } else if (IsAnalyticalQuotient(a)) {
1096        return AQ(a.GetSubtree(0), Product(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 Sum(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 Sum(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 bNode = b as NumberTreeNode;
1120        return Factor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select((w) => w + bNode.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 Factor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u + v));
1125      } else if (IsBinFactor(a) && IsFactor(b)) {
1126        return Sum(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 Factor(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(Sum(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 Sum(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(Sum(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 sumNumbers = (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 (sumNumbers != 0.0) {
1231        sum.AddSubtree(Number(sumNumbers));
1232      }
1233    }
1234
1235    // nodes referencing variables can be grouped if they have
1236    private static string GroupId(IVariableTreeNode node) {
1237      if (node is VariableTreeNode variableNode) {
1238        return "var " + variableNode.VariableName;
1239      } else if (node is BinaryFactorVariableTreeNode binaryFactorNode) {
1240        return "binfactor " + binaryFactorNode.VariableName + " " + binaryFactorNode.VariableValue;
1241      } else if (node is FactorVariableTreeNode factorNode) {
1242        return "factor " + factorNode.VariableName;
1243      } else if (node is LaggedVariableTreeNode laggedVarNode) {
1244        return "lagged " + laggedVarNode.VariableName + " " + laggedVarNode.Lag;
1245      } else {
1246        throw new NotSupportedException();
1247      }
1248    }
1249
1250
1251    private static ISymbolicExpressionTreeNode Product(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1252      if (IsNumber(a) && IsNumber(b)) {
1253        // fold constants
1254        return Number(((NumberTreeNode)a).Value * ((NumberTreeNode)b).Value);
1255      } else if (IsNumber(a)) {
1256        // a * $ => $ * a
1257        return Product(b, a);
1258      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
1259        var node0 = a as FactorVariableTreeNode;
1260        var node1 = b as FactorVariableTreeNode;
1261        return Factor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u * v));
1262      } else if (IsBinFactor(a) && IsBinFactor(b) && AreSameTypeAndVariable(a, b)) {
1263        var node0 = a as BinaryFactorVariableTreeNode;
1264        var node1 = b as BinaryFactorVariableTreeNode;
1265        return BinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Weight);
1266      } else if (IsFactor(a) && IsNumber(b)) {
1267        var node0 = a as FactorVariableTreeNode;
1268        var node1 = b as NumberTreeNode;
1269        return Factor(node0.Symbol, node0.VariableName, node0.Weights.Select(w => w * node1.Value));
1270      } else if (IsBinFactor(a) && IsNumber(b)) {
1271        var node0 = a as BinaryFactorVariableTreeNode;
1272        var node1 = b as NumberTreeNode;
1273        return BinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Value);
1274      } else if (IsBinFactor(a) && IsFactor(b)) {
1275        return Product(b, a);
1276      } else if (IsFactor(a) && IsBinFactor(b) &&
1277        ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
1278        var node0 = a as FactorVariableTreeNode;
1279        var node1 = b as BinaryFactorVariableTreeNode;
1280        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
1281        var wi = Array.IndexOf(varValues, node1.VariableValue);
1282        if (wi < 0) throw new ArgumentException();
1283        return BinFactor(node1.Symbol, node1.VariableName, node1.VariableValue, node1.Weight * node0.Weights[wi]);
1284      } else if (IsNumber(b) && ((NumberTreeNode)b).Value == 1.0) {
1285        // $ * 1.0 => $
1286        return a;
1287      } else if (IsNumber(b) && ((NumberTreeNode)b).Value == 0.0) {
1288        return Number(0);
1289      } else if (IsNumber(b) && IsVariableBase(a)) {
1290        // multiply constants into variables weights
1291        ((VariableTreeNodeBase)a).Weight *= ((NumberTreeNode)b).Value;
1292        return a;
1293      } else if (IsNumber(b) && IsAddition(a) ||
1294          IsFactor(b) && IsAddition(a) ||
1295          IsBinFactor(b) && IsAddition(a)) {
1296        // multiply numbers into additions
1297        return a.Subtrees.Select(x => Product(GetSimplifiedTree(x), GetSimplifiedTree(b))).Aggregate((c, d) => Sum(c, d));
1298      } else if (IsDivision(a) && IsDivision(b)) {
1299        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
1300        return Fraction(Product(a.GetSubtree(0), b.GetSubtree(0)), Product(a.GetSubtree(1), b.GetSubtree(1)));
1301      } else if (IsDivision(a)) {
1302        // (a1 / a2) * b => (a1 * b) / a2
1303        return Fraction(Product(a.GetSubtree(0), b), a.GetSubtree(1));
1304      } else if (IsDivision(b)) {
1305        // a * (b1 / b2) => (b1 * a) / b2
1306        return Fraction(Product(b.GetSubtree(0), a), b.GetSubtree(1));
1307      } else if (IsMultiplication(a) && IsMultiplication(b)) {
1308        // merge multiplications (make sure constants are merged)
1309        var mul = mulSymbol.CreateTreeNode();
1310        for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
1311        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
1312        MergeVariablesAndConstantsInProduct(mul);
1313        return mul;
1314      } else if (IsMultiplication(b)) {
1315        return Product(b, a);
1316      } else if (IsMultiplication(a)) {
1317        // a is already an multiplication => append b
1318        a.AddSubtree(GetSimplifiedTree(b));
1319        MergeVariablesAndConstantsInProduct(a);
1320        return a;
1321      } else if (IsAbsolute(a) && IsAbsolute(b)) {
1322        return Abs(Product(a.GetSubtree(0), b.GetSubtree(0)));
1323      } else if (IsAbsolute(a) && IsNumber(b)) {
1324        var bNode = b as NumberTreeNode;
1325        var posF = Math.Abs(bNode.Value);
1326        if (bNode.Value > 0) {
1327          return Abs(Product(a.GetSubtree(0), Number(posF)));
1328        } else {
1329          var mul = mulSymbol.CreateTreeNode();
1330          mul.AddSubtree(Abs(Product(a.GetSubtree(0), Number(posF))));
1331          mul.AddSubtree(Number(-1.0));
1332          return mul;
1333        }
1334      } else if (IsAnalyticalQuotient(a)) {
1335        return AQ(Product(a.GetSubtree(0), b), a.GetSubtree(1));
1336      } else {
1337        var mul = mulSymbol.CreateTreeNode();
1338        mul.AddSubtree(a);
1339        mul.AddSubtree(b);
1340        MergeVariablesAndConstantsInProduct(mul);
1341        return mul;
1342      }
1343    }
1344
1345    #endregion
1346
1347    #region helper functions
1348
1349    private static bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
1350      if (node.Symbol is VariableCondition) return true;
1351      foreach (var subtree in node.Subtrees)
1352        if (ContainsVariableCondition(subtree)) return true;
1353      return false;
1354    }
1355
1356    private static ISymbolicExpressionTreeNode AddLagToDynamicNodes(ISymbolicExpressionTreeNode node, int lag) {
1357      if (node is ILaggedTreeNode laggedTreeNode)
1358        laggedTreeNode.Lag += lag;
1359      else if (node is VariableTreeNode variableNode) {
1360        var laggedVariableNode = (LaggedVariableTreeNode)laggedVariableSymbol.CreateTreeNode();
1361        laggedVariableNode.Lag = lag;
1362        laggedVariableNode.VariableName = variableNode.VariableName;
1363        return laggedVariableNode;
1364      } else if (node is VariableConditionTreeNode) {
1365        throw new NotSupportedException("Removal of time lags around variable condition symbols is not allowed.");
1366      }
1367      var subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
1368      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
1369      foreach (var subtree in subtrees) {
1370        node.AddSubtree(AddLagToDynamicNodes(subtree, lag));
1371      }
1372      return node;
1373    }
1374
1375    private static bool AreSameTypeAndVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
1376      return GroupId((IVariableTreeNode)a) == GroupId((IVariableTreeNode)b);
1377    }
1378
1379    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
1380    private static void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
1381      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
1382      while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
1383      var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
1384                            where node.SubtreeCount == 0
1385                            group node by GroupId(node) into g
1386                            orderby g.Count()
1387                            select g;
1388      var numberProduct = (from node in subtrees.OfType<VariableTreeNodeBase>()
1389                           select node.Weight)
1390                          .Concat(from node in subtrees.OfType<NumberTreeNode>()
1391                                  select node.Value)
1392                          .DefaultIfEmpty(1.0)
1393                          .Aggregate((c1, c2) => c1 * c2);
1394
1395      var unchangedSubtrees = from tree in subtrees
1396                              where tree.SubtreeCount > 0 || !(tree is IVariableTreeNode) && !(tree is NumberTreeNode)
1397                              select tree;
1398
1399      foreach (var variableNodeGroup in groupedVarNodes) {
1400        var firstNode = variableNodeGroup.First();
1401        if (firstNode is VariableTreeNodeBase) {
1402          var representative = (VariableTreeNodeBase)firstNode;
1403          representative.Weight = 1.0;
1404          if (variableNodeGroup.Count() > 1) {
1405            var poly = mulSymbol.CreateTreeNode();
1406            for (int p = 0; p < variableNodeGroup.Count(); p++) {
1407              poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
1408            }
1409            prod.AddSubtree(poly);
1410          } else {
1411            prod.AddSubtree(representative);
1412          }
1413        } else if (firstNode is FactorVariableTreeNode) {
1414          var representative = (FactorVariableTreeNode)firstNode;
1415          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
1416            for (int j = 0; j < representative.Weights.Length; j++) {
1417              representative.Weights[j] *= node.Weights[j];
1418            }
1419          }
1420          for (int j = 0; j < representative.Weights.Length; j++) {
1421            representative.Weights[j] *= numberProduct;
1422          }
1423          numberProduct = 1.0;
1424          // if the product already contains a factor it is not necessary to multiply a constant below
1425          prod.AddSubtree(representative);
1426        }
1427      }
1428
1429      foreach (var unchangedSubtree in unchangedSubtrees)
1430        prod.AddSubtree(unchangedSubtree);
1431
1432      if (numberProduct != 1.0) {
1433        prod.AddSubtree(Number(numberProduct));
1434      }
1435    }
1436
1437
1438    /// <summary>
1439    /// x => x * -1
1440    /// Is only used in cases where it is not necessary to create new tree nodes. Manipulates x directly.
1441    /// </summary>
1442    /// <param name="x"></param>
1443    /// <returns>-x</returns>
1444    private static ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
1445      if (IsNumber(x)) {
1446        ((NumberTreeNode)x).Value *= -1;
1447      } else if (IsVariableBase(x)) {
1448        var variableTree = (VariableTreeNodeBase)x;
1449        variableTree.Weight *= -1.0;
1450      } else if (IsFactor(x)) {
1451        var factorNode = (FactorVariableTreeNode)x;
1452        for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
1453      } else if (IsBinFactor(x)) {
1454        var factorNode = (BinaryFactorVariableTreeNode)x;
1455        factorNode.Weight *= -1;
1456      } else if (IsAddition(x)) {
1457        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
1458        var subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
1459        while (x.Subtrees.Any()) x.RemoveSubtree(0);
1460        foreach (var subtree in subtrees) {
1461          x.AddSubtree(Negate(subtree));
1462        }
1463      } else if (IsMultiplication(x) || IsDivision(x)) {
1464        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
1465        var lastSubTree = x.Subtrees.Last();
1466        x.RemoveSubtree(x.SubtreeCount - 1);
1467        x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
1468      } else {
1469        // any other function
1470        return Product(x, Number(-1));
1471      }
1472      return x;
1473    }
1474
1475    /// <summary>
1476    /// x => 1/x
1477    /// Must create new tree nodes
1478    /// </summary>
1479    /// <param name="x"></param>
1480    /// <returns></returns>
1481    private static ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
1482      if (IsNumber(x)) {
1483        return Number(1.0 / ((NumberTreeNode)x).Value);
1484      } else if (IsFactor(x)) {
1485        var factorNode = (FactorVariableTreeNode)x;
1486        return Factor(factorNode.Symbol, factorNode.VariableName, factorNode.Weights.Select(w => 1.0 / w));
1487      } else if (IsDivision(x)) {
1488        return Fraction(x.GetSubtree(1), x.GetSubtree(0));
1489      } else {
1490        // any other function
1491        return Fraction(Number(1), x);
1492      }
1493    }
1494
1495    private static ISymbolicExpressionTreeNode Number(double value) {
1496      var numberTreeNode = (NumberTreeNode)numberSymbol.CreateTreeNode();
1497      numberTreeNode.Value = value;
1498      return numberTreeNode;
1499    }
1500
1501    private static ISymbolicExpressionTreeNode Factor(FactorVariable sy, string variableName, IEnumerable<double> weights) {
1502      var tree = (FactorVariableTreeNode)sy.CreateTreeNode();
1503      tree.VariableName = variableName;
1504      tree.Weights = weights.ToArray();
1505      return tree;
1506    }
1507    private static ISymbolicExpressionTreeNode BinFactor(BinaryFactorVariable sy, string variableName, string variableValue, double weight) {
1508      var tree = (BinaryFactorVariableTreeNode)sy.CreateTreeNode();
1509      tree.VariableName = variableName;
1510      tree.VariableValue = variableValue;
1511      tree.Weight = weight;
1512      return tree;
1513    }
1514
1515
1516    #endregion
1517  }
1518}
Note: See TracBrowser for help on using the repository browser.