source: branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs @ 14238

Last change on this file since 14238 was 14238, checked in by gkronber, 3 years ago

#2650:

  • added weight for FactorVariable (necessary for LR)
  • introduced VariableBase and VariableTreeNodeBase and IVariableSymbol
  • support for factors in LR
  • extended variable impacts in solution view
  • fixed ERC view for regression
  • support for FactorVariable in simplifier
  • improved support for FactorVariable in constants optimizer
  • multiple related changes and small fixes
File size: 43.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
27
28namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
29  /// <summary>
30  /// Simplifier for symbolic expressions
31  /// </summary>
32  public class SymbolicDataAnalysisExpressionTreeSimplifier {
33    private Addition addSymbol = new Addition();
34    private Subtraction subSymbol = new Subtraction();
35    private Multiplication mulSymbol = new Multiplication();
36    private Division divSymbol = new Division();
37    private Constant constSymbol = new Constant();
38    private Variable varSymbol = new Variable();
39    private Logarithm logSymbol = new Logarithm();
40    private Exponential expSymbol = new Exponential();
41    private Root rootSymbol = new Root();
42    private Square sqrSymbol = new Square();
43    private SquareRoot sqrtSymbol = new SquareRoot();
44    private Power powSymbol = new Power();
45    private Sine sineSymbol = new Sine();
46    private Cosine cosineSymbol = new Cosine();
47    private Tangent tanSymbol = new Tangent();
48    private IfThenElse ifThenElseSymbol = new IfThenElse();
49    private And andSymbol = new And();
50    private Or orSymbol = new Or();
51    private Not notSymbol = new Not();
52    private GreaterThan gtSymbol = new GreaterThan();
53    private LessThan ltSymbol = new LessThan();
54    private Integral integralSymbol = new Integral();
55    private LaggedVariable laggedVariableSymbol = new LaggedVariable();
56    private TimeLag timeLagSymbol = new TimeLag();
57
58    public ISymbolicExpressionTree Simplify(ISymbolicExpressionTree originalTree) {
59      var clone = (ISymbolicExpressionTreeNode)originalTree.Root.Clone();
60      // macro expand (initially no argument trees)
61      var macroExpandedTree = MacroExpand(clone, clone.GetSubtree(0), new List<ISymbolicExpressionTreeNode>());
62      ISymbolicExpressionTreeNode rootNode = (new ProgramRootSymbol()).CreateTreeNode();
63      rootNode.AddSubtree(GetSimplifiedTree(macroExpandedTree));
64      return new SymbolicExpressionTree(rootNode);
65    }
66
67    // the argumentTrees list contains already expanded trees used as arguments for invocations
68    private ISymbolicExpressionTreeNode MacroExpand(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node, IList<ISymbolicExpressionTreeNode> argumentTrees) {
69      List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
70      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
71      if (node.Symbol is InvokeFunction) {
72        var invokeSym = node.Symbol as InvokeFunction;
73        var defunNode = FindFunctionDefinition(root, invokeSym.FunctionName);
74        var macroExpandedArguments = new List<ISymbolicExpressionTreeNode>();
75        foreach (var subtree in subtrees) {
76          macroExpandedArguments.Add(MacroExpand(root, subtree, argumentTrees));
77        }
78        return MacroExpand(root, defunNode, macroExpandedArguments);
79      } else if (node.Symbol is Argument) {
80        var argSym = node.Symbol as Argument;
81        // return the correct argument sub-tree (already macro-expanded)
82        return (SymbolicExpressionTreeNode)argumentTrees[argSym.ArgumentIndex].Clone();
83      } else {
84        // recursive application
85        foreach (var subtree in subtrees) {
86          node.AddSubtree(MacroExpand(root, subtree, argumentTrees));
87        }
88        return node;
89      }
90    }
91
92    private ISymbolicExpressionTreeNode FindFunctionDefinition(ISymbolicExpressionTreeNode root, string functionName) {
93      foreach (var subtree in root.Subtrees.OfType<DefunTreeNode>()) {
94        if (subtree.FunctionName == functionName) return subtree.GetSubtree(0);
95      }
96
97      throw new ArgumentException("Definition of function " + functionName + " not found.");
98    }
99
100
101    #region symbol predicates
102    // arithmetic
103    private bool IsDivision(ISymbolicExpressionTreeNode node) {
104      return node.Symbol is Division;
105    }
106
107    private bool IsMultiplication(ISymbolicExpressionTreeNode node) {
108      return node.Symbol is Multiplication;
109    }
110
111    private bool IsSubtraction(ISymbolicExpressionTreeNode node) {
112      return node.Symbol is Subtraction;
113    }
114
115    private bool IsAddition(ISymbolicExpressionTreeNode node) {
116      return node.Symbol is Addition;
117    }
118
119    private bool IsAverage(ISymbolicExpressionTreeNode node) {
120      return node.Symbol is Average;
121    }
122    // exponential
123    private bool IsLog(ISymbolicExpressionTreeNode node) {
124      return node.Symbol is Logarithm;
125    }
126    private bool IsExp(ISymbolicExpressionTreeNode node) {
127      return node.Symbol is Exponential;
128    }
129    private bool IsRoot(ISymbolicExpressionTreeNode node) {
130      return node.Symbol is Root;
131    }
132    private bool IsSquare(ISymbolicExpressionTreeNode node) {
133      return node.Symbol is Square;
134    }
135    private bool IsSquareRoot(ISymbolicExpressionTreeNode node) {
136      return node.Symbol is SquareRoot;
137    }
138    private bool IsPower(ISymbolicExpressionTreeNode node) {
139      return node.Symbol is Power;
140    }
141    // trigonometric
142    private bool IsSine(ISymbolicExpressionTreeNode node) {
143      return node.Symbol is Sine;
144    }
145    private bool IsCosine(ISymbolicExpressionTreeNode node) {
146      return node.Symbol is Cosine;
147    }
148    private bool IsTangent(ISymbolicExpressionTreeNode node) {
149      return node.Symbol is Tangent;
150    }
151    // boolean
152    private bool IsIfThenElse(ISymbolicExpressionTreeNode node) {
153      return node.Symbol is IfThenElse;
154    }
155    private bool IsAnd(ISymbolicExpressionTreeNode node) {
156      return node.Symbol is And;
157    }
158    private bool IsOr(ISymbolicExpressionTreeNode node) {
159      return node.Symbol is Or;
160    }
161    private bool IsNot(ISymbolicExpressionTreeNode node) {
162      return node.Symbol is Not;
163    }
164    // comparison
165    private bool IsGreaterThan(ISymbolicExpressionTreeNode node) {
166      return node.Symbol is GreaterThan;
167    }
168    private bool IsLessThan(ISymbolicExpressionTreeNode node) {
169      return node.Symbol is LessThan;
170    }
171
172    private bool IsBoolean(ISymbolicExpressionTreeNode node) {
173      return
174        node.Symbol is GreaterThan ||
175        node.Symbol is LessThan ||
176        node.Symbol is And ||
177        node.Symbol is Or;
178    }
179
180    // terminals
181    private bool IsVariable(ISymbolicExpressionTreeNode node) {
182      return node.Symbol is Variable;
183    }
184    private bool IsVariableBase(ISymbolicExpressionTreeNode node) {
185      return node.Symbol is VariableBase;
186    }
187    private bool IsConstant(ISymbolicExpressionTreeNode node) {
188      return node.Symbol is Constant;
189    }
190
191    // dynamic
192    private bool IsTimeLag(ISymbolicExpressionTreeNode node) {
193      return node.Symbol is TimeLag;
194    }
195    private bool IsIntegral(ISymbolicExpressionTreeNode node) {
196      return node.Symbol is Integral;
197    }
198
199    #endregion
200
201    /// <summary>
202    /// Creates a new simplified tree
203    /// </summary>
204    /// <param name="original"></param>
205    /// <returns></returns>
206    public ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
207      if (IsConstant(original) || IsVariableBase(original)) {
208        return (ISymbolicExpressionTreeNode)original.Clone();
209      } else if (IsAddition(original)) {
210        return SimplifyAddition(original);
211      } else if (IsSubtraction(original)) {
212        return SimplifySubtraction(original);
213      } else if (IsMultiplication(original)) {
214        return SimplifyMultiplication(original);
215      } else if (IsDivision(original)) {
216        return SimplifyDivision(original);
217      } else if (IsAverage(original)) {
218        return SimplifyAverage(original);
219      } else if (IsLog(original)) {
220        return SimplifyLog(original);
221      } else if (IsExp(original)) {
222        return SimplifyExp(original);
223      } else if (IsSquare(original)) {
224        return SimplifySquare(original);
225      } else if (IsSquareRoot(original)) {
226        return SimplifySquareRoot(original);
227      } else if (IsPower(original)) {
228        return SimplifyPower(original);
229      } else if (IsRoot(original)) {
230        return SimplifyRoot(original);
231      } else if (IsSine(original)) {
232        return SimplifySine(original);
233      } else if (IsCosine(original)) {
234        return SimplifyCosine(original);
235      } else if (IsTangent(original)) {
236        return SimplifyTangent(original);
237      } else if (IsIfThenElse(original)) {
238        return SimplifyIfThenElse(original);
239      } else if (IsGreaterThan(original)) {
240        return SimplifyGreaterThan(original);
241      } else if (IsLessThan(original)) {
242        return SimplifyLessThan(original);
243      } else if (IsAnd(original)) {
244        return SimplifyAnd(original);
245      } else if (IsOr(original)) {
246        return SimplifyOr(original);
247      } else if (IsNot(original)) {
248        return SimplifyNot(original);
249      } else if (IsTimeLag(original)) {
250        return SimplifyTimeLag(original);
251      } else if (IsIntegral(original)) {
252        return SimplifyIntegral(original);
253      } else {
254        return SimplifyAny(original);
255      }
256    }
257
258
259    #region specific simplification routines
260    private ISymbolicExpressionTreeNode SimplifyAny(ISymbolicExpressionTreeNode original) {
261      // can't simplify this function but simplify all subtrees
262      List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(original.Subtrees);
263      while (original.Subtrees.Count() > 0) original.RemoveSubtree(0);
264      var clone = (SymbolicExpressionTreeNode)original.Clone();
265      List<ISymbolicExpressionTreeNode> simplifiedSubtrees = new List<ISymbolicExpressionTreeNode>();
266      foreach (var subtree in subtrees) {
267        simplifiedSubtrees.Add(GetSimplifiedTree(subtree));
268        original.AddSubtree(subtree);
269      }
270      foreach (var simplifiedSubtree in simplifiedSubtrees) {
271        clone.AddSubtree(simplifiedSubtree);
272      }
273      if (simplifiedSubtrees.TrueForAll(t => IsConstant(t))) {
274        SimplifyConstantExpression(clone);
275      }
276      return clone;
277    }
278
279    private ISymbolicExpressionTreeNode SimplifyConstantExpression(ISymbolicExpressionTreeNode original) {
280      // not yet implemented
281      return original;
282    }
283
284    private ISymbolicExpressionTreeNode SimplifyAverage(ISymbolicExpressionTreeNode original) {
285      if (original.Subtrees.Count() == 1) {
286        return GetSimplifiedTree(original.GetSubtree(0));
287      } else {
288        // simplify expressions x0..xn
289        // make sum(x0..xn) / n
290        var sum = original.Subtrees
291          .Select(GetSimplifiedTree)
292          .Aggregate(MakeSum);
293        return MakeFraction(sum, MakeConstant(original.Subtrees.Count()));
294      }
295    }
296
297    private ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
298      if (original.Subtrees.Count() == 1) {
299        return Invert(GetSimplifiedTree(original.GetSubtree(0)));
300      } else {
301        // simplify expressions x0..xn
302        // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
303        var first = original.GetSubtree(0);
304        var second = original.GetSubtree(1);
305        var remaining = original.Subtrees.Skip(2);
306        return
307          MakeProduct(GetSimplifiedTree(first), Invert(remaining.Aggregate(GetSimplifiedTree(second), (a, b) => MakeProduct(a, GetSimplifiedTree(b)))));
308      }
309    }
310
311    private ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
312      if (original.Subtrees.Count() == 1) {
313        return GetSimplifiedTree(original.GetSubtree(0));
314      } else {
315        return original.Subtrees
316          .Select(GetSimplifiedTree)
317          .Aggregate(MakeProduct);
318      }
319    }
320
321    private ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
322      if (original.Subtrees.Count() == 1) {
323        return Negate(GetSimplifiedTree(original.GetSubtree(0)));
324      } else {
325        // simplify expressions x0..xn
326        // make addition (x0,-x1..-xn)
327        var first = original.Subtrees.First();
328        var remaining = original.Subtrees.Skip(1);
329        return remaining.Aggregate(GetSimplifiedTree(first), (a, b) => MakeSum(a, Negate(GetSimplifiedTree(b))));
330      }
331    }
332
333    private ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
334      if (original.Subtrees.Count() == 1) {
335        return GetSimplifiedTree(original.GetSubtree(0));
336      } else {
337        // simplify expression x0..xn
338        // make addition (x0..xn)
339        return original.Subtrees
340          .Select(GetSimplifiedTree)
341          .Aggregate(MakeSum);
342      }
343    }
344
345    private ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
346      return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
347    }
348    private ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
349      return original.Subtrees
350        .Select(GetSimplifiedTree)
351        .Aggregate(MakeOr);
352    }
353    private ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
354      return original.Subtrees
355        .Select(GetSimplifiedTree)
356        .Aggregate(MakeAnd);
357    }
358    private ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
359      return MakeLessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
360    }
361    private ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
362      return MakeGreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
363    }
364    private ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
365      return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)), GetSimplifiedTree(original.GetSubtree(2)));
366    }
367    private ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
368      return MakeTangent(GetSimplifiedTree(original.GetSubtree(0)));
369    }
370    private ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
371      return MakeCosine(GetSimplifiedTree(original.GetSubtree(0)));
372    }
373    private ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
374      return MakeSine(GetSimplifiedTree(original.GetSubtree(0)));
375    }
376    private ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
377      return MakeExp(GetSimplifiedTree(original.GetSubtree(0)));
378    }
379    private ISymbolicExpressionTreeNode SimplifySquare(ISymbolicExpressionTreeNode original) {
380      return MakeSquare(GetSimplifiedTree(original.GetSubtree(0)));
381    }
382    private ISymbolicExpressionTreeNode SimplifySquareRoot(ISymbolicExpressionTreeNode original) {
383      return MakeSquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
384    }
385
386    private ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
387      return MakeLog(GetSimplifiedTree(original.GetSubtree(0)));
388    }
389    private ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
390      return MakeRoot(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
391    }
392
393    private ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
394      return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
395    }
396    private ISymbolicExpressionTreeNode SimplifyTimeLag(ISymbolicExpressionTreeNode original) {
397      var laggedTreeNode = original as ILaggedTreeNode;
398      var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
399      if (!ContainsVariableCondition(simplifiedSubtree)) {
400        return AddLagToDynamicNodes(simplifiedSubtree, laggedTreeNode.Lag);
401      } else {
402        return MakeTimeLag(simplifiedSubtree, laggedTreeNode.Lag);
403      }
404    }
405    private ISymbolicExpressionTreeNode SimplifyIntegral(ISymbolicExpressionTreeNode original) {
406      var laggedTreeNode = original as ILaggedTreeNode;
407      var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
408      if (IsConstant(simplifiedSubtree)) {
409        return GetSimplifiedTree(MakeProduct(simplifiedSubtree, MakeConstant(-laggedTreeNode.Lag)));
410      } else {
411        return MakeIntegral(simplifiedSubtree, laggedTreeNode.Lag);
412      }
413    }
414
415    #endregion
416
417    #region low level tree restructuring
418    private ISymbolicExpressionTreeNode MakeTimeLag(ISymbolicExpressionTreeNode subtree, int lag) {
419      if (lag == 0) return subtree;
420      if (IsConstant(subtree)) return subtree;
421      var lagNode = (LaggedTreeNode)timeLagSymbol.CreateTreeNode();
422      lagNode.Lag = lag;
423      lagNode.AddSubtree(subtree);
424      return lagNode;
425    }
426
427    private ISymbolicExpressionTreeNode MakeIntegral(ISymbolicExpressionTreeNode subtree, int lag) {
428      if (lag == 0) return subtree;
429      else if (lag == -1 || lag == 1) {
430        return MakeSum(subtree, AddLagToDynamicNodes((ISymbolicExpressionTreeNode)subtree.Clone(), lag));
431      } else {
432        var node = (LaggedTreeNode)integralSymbol.CreateTreeNode();
433        node.Lag = lag;
434        node.AddSubtree(subtree);
435        return node;
436      }
437    }
438
439    private ISymbolicExpressionTreeNode MakeNot(ISymbolicExpressionTreeNode t) {
440      if (IsConstant(t)) {
441        var constNode = t as ConstantTreeNode;
442        if (constNode.Value > 0) return MakeConstant(-1.0);
443        else return MakeConstant(1.0);
444      } else if (IsNot(t)) {
445        return t.GetSubtree(0);
446      } else if (!IsBoolean(t)) {
447        var gtNode = gtSymbol.CreateTreeNode();
448        gtNode.AddSubtree(t); gtNode.AddSubtree(MakeConstant(0.0));
449        var notNode = notSymbol.CreateTreeNode();
450        notNode.AddSubtree(gtNode);
451        return notNode;
452      } else {
453        var notNode = notSymbol.CreateTreeNode();
454        notNode.AddSubtree(t);
455        return notNode;
456      }
457    }
458
459    private ISymbolicExpressionTreeNode MakeOr(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
460      if (IsConstant(a) && IsConstant(b)) {
461        var constA = a as ConstantTreeNode;
462        var constB = b as ConstantTreeNode;
463        if (constA.Value > 0.0 || constB.Value > 0.0) {
464          return MakeConstant(1.0);
465        } else {
466          return MakeConstant(-1.0);
467        }
468      } else if (IsConstant(a)) {
469        return MakeOr(b, a);
470      } else if (IsConstant(b)) {
471        var constT = b as ConstantTreeNode;
472        if (constT.Value > 0.0) {
473          // boolean expression is necessarily true
474          return MakeConstant(1.0);
475        } else {
476          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
477          var orNode = orSymbol.CreateTreeNode();
478          orNode.AddSubtree(a);
479          return orNode;
480        }
481      } else {
482        var orNode = orSymbol.CreateTreeNode();
483        orNode.AddSubtree(a);
484        orNode.AddSubtree(b);
485        return orNode;
486      }
487    }
488    private ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
489      if (IsConstant(a) && IsConstant(b)) {
490        var constA = a as ConstantTreeNode;
491        var constB = b as ConstantTreeNode;
492        if (constA.Value > 0.0 && constB.Value > 0.0) {
493          return MakeConstant(1.0);
494        } else {
495          return MakeConstant(-1.0);
496        }
497      } else if (IsConstant(a)) {
498        return MakeAnd(b, a);
499      } else if (IsConstant(b)) {
500        var constB = b as ConstantTreeNode;
501        if (constB.Value > 0.0) {
502          // the constant value has no effect on the result of the boolean condition so we can drop the constant term
503          var andNode = andSymbol.CreateTreeNode();
504          andNode.AddSubtree(a);
505          return andNode;
506        } else {
507          // boolean expression is necessarily false
508          return MakeConstant(-1.0);
509        }
510      } else {
511        var andNode = andSymbol.CreateTreeNode();
512        andNode.AddSubtree(a);
513        andNode.AddSubtree(b);
514        return andNode;
515      }
516    }
517    private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
518      if (IsConstant(leftSide) && IsConstant(rightSide)) {
519        var lsConst = leftSide as ConstantTreeNode;
520        var rsConst = rightSide as ConstantTreeNode;
521        if (lsConst.Value < rsConst.Value) return MakeConstant(1.0);
522        else return MakeConstant(-1.0);
523      } else {
524        var ltNode = ltSymbol.CreateTreeNode();
525        ltNode.AddSubtree(leftSide);
526        ltNode.AddSubtree(rightSide);
527        return ltNode;
528      }
529    }
530    private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
531      if (IsConstant(leftSide) && IsConstant(rightSide)) {
532        var lsConst = leftSide as ConstantTreeNode;
533        var rsConst = rightSide as ConstantTreeNode;
534        if (lsConst.Value > rsConst.Value) return MakeConstant(1.0);
535        else return MakeConstant(-1.0);
536      } else {
537        var gtNode = gtSymbol.CreateTreeNode();
538        gtNode.AddSubtree(leftSide);
539        gtNode.AddSubtree(rightSide);
540        return gtNode;
541      }
542    }
543    private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition, ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
544      if (IsConstant(condition)) {
545        var constT = condition as ConstantTreeNode;
546        if (constT.Value > 0.0) return trueBranch;
547        else return falseBranch;
548      } else {
549        var ifNode = ifThenElseSymbol.CreateTreeNode();
550        if (IsBoolean(condition)) {
551          ifNode.AddSubtree(condition);
552        } else {
553          var gtNode = gtSymbol.CreateTreeNode();
554          gtNode.AddSubtree(condition); gtNode.AddSubtree(MakeConstant(0.0));
555          ifNode.AddSubtree(gtNode);
556        }
557        ifNode.AddSubtree(trueBranch);
558        ifNode.AddSubtree(falseBranch);
559        return ifNode;
560      }
561    }
562
563    private ISymbolicExpressionTreeNode MakeSine(ISymbolicExpressionTreeNode node) {
564      if (IsConstant(node)) {
565        var constT = node as ConstantTreeNode;
566        return MakeConstant(Math.Sin(constT.Value));
567      } else {
568        var sineNode = sineSymbol.CreateTreeNode();
569        sineNode.AddSubtree(node);
570        return sineNode;
571      }
572    }
573    private ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
574      if (IsConstant(node)) {
575        var constT = node as ConstantTreeNode;
576        return MakeConstant(Math.Tan(constT.Value));
577      } else {
578        var tanNode = tanSymbol.CreateTreeNode();
579        tanNode.AddSubtree(node);
580        return tanNode;
581      }
582    }
583    private ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
584      if (IsConstant(node)) {
585        var constT = node as ConstantTreeNode;
586        return MakeConstant(Math.Cos(constT.Value));
587      } else {
588        var cosNode = cosineSymbol.CreateTreeNode();
589        cosNode.AddSubtree(node);
590        return cosNode;
591      }
592    }
593    private ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
594      if (IsConstant(node)) {
595        var constT = node as ConstantTreeNode;
596        return MakeConstant(Math.Exp(constT.Value));
597      } else if (IsLog(node)) {
598        return node.GetSubtree(0);
599      } else if (IsAddition(node)) {
600        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, t));
601      } else if (IsSubtraction(node)) {
602        return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, Negate(t)));
603      } else {
604        var expNode = expSymbol.CreateTreeNode();
605        expNode.AddSubtree(node);
606        return expNode;
607      }
608    }
609
610    private ISymbolicExpressionTreeNode MakeSquare(ISymbolicExpressionTreeNode node) {
611      if (IsConstant(node)) {
612        var constT = node as ConstantTreeNode;
613        return MakeConstant(constT.Value * constT.Value);
614      } else if (IsSquareRoot(node)) {
615        return node.GetSubtree(0);
616      } else {
617        var sqrNode = sqrSymbol.CreateTreeNode();
618        sqrNode.AddSubtree(node);
619        return sqrNode;
620      }
621    }
622    private ISymbolicExpressionTreeNode MakeSquareRoot(ISymbolicExpressionTreeNode node) {
623      if (IsConstant(node)) {
624        var constT = node as ConstantTreeNode;
625        return MakeConstant(Math.Sqrt(constT.Value));
626      } else if (IsSquare(node)) {
627        return node.GetSubtree(0);
628      } else {
629        var sqrtNode = sqrtSymbol.CreateTreeNode();
630        sqrtNode.AddSubtree(node);
631        return sqrtNode;
632      }
633    }
634
635    private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
636      if (IsConstant(node)) {
637        var constT = node as ConstantTreeNode;
638        return MakeConstant(Math.Log(constT.Value));
639      } else if (IsExp(node)) {
640        return node.GetSubtree(0);
641      } else if (IsSquareRoot(node)) {
642        return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
643      } else {
644        var logNode = logSymbol.CreateTreeNode();
645        logNode.AddSubtree(node);
646        return logNode;
647      }
648    }
649    private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
650      if (IsConstant(a) && IsConstant(b)) {
651        var constA = a as ConstantTreeNode;
652        var constB = b as ConstantTreeNode;
653        return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
654      } else if (IsConstant(b)) {
655        var constB = b as ConstantTreeNode;
656        var constBValue = Math.Round(constB.Value);
657        if (constBValue.IsAlmost(1.0)) {
658          return a;
659        } else if (constBValue.IsAlmost(0.0)) {
660          return MakeConstant(1.0);
661        } else if (constBValue.IsAlmost(-1.0)) {
662          return MakeFraction(MakeConstant(1.0), a);
663        } else if (constBValue < 0) {
664          var rootNode = rootSymbol.CreateTreeNode();
665          rootNode.AddSubtree(a);
666          rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
667          return MakeFraction(MakeConstant(1.0), rootNode);
668        } else {
669          var rootNode = rootSymbol.CreateTreeNode();
670          rootNode.AddSubtree(a);
671          rootNode.AddSubtree(MakeConstant(constBValue));
672          return rootNode;
673        }
674      } else {
675        var rootNode = rootSymbol.CreateTreeNode();
676        rootNode.AddSubtree(a);
677        rootNode.AddSubtree(b);
678        return rootNode;
679      }
680    }
681    private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
682      if (IsConstant(a) && IsConstant(b)) {
683        var constA = a as ConstantTreeNode;
684        var constB = b as ConstantTreeNode;
685        return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
686      } else if (IsConstant(b)) {
687        var constB = b as ConstantTreeNode;
688        double exponent = Math.Round(constB.Value);
689        if (exponent.IsAlmost(0.0)) {
690          return MakeConstant(1.0);
691        } else if (exponent.IsAlmost(1.0)) {
692          return a;
693        } else if (exponent.IsAlmost(-1.0)) {
694          return MakeFraction(MakeConstant(1.0), a);
695        } else if (exponent < 0) {
696          var powNode = powSymbol.CreateTreeNode();
697          powNode.AddSubtree(a);
698          powNode.AddSubtree(MakeConstant(-1.0 * exponent));
699          return MakeFraction(MakeConstant(1.0), powNode);
700        } else {
701          var powNode = powSymbol.CreateTreeNode();
702          powNode.AddSubtree(a);
703          powNode.AddSubtree(MakeConstant(exponent));
704          return powNode;
705        }
706      } else {
707        var powNode = powSymbol.CreateTreeNode();
708        powNode.AddSubtree(a);
709        powNode.AddSubtree(b);
710        return powNode;
711      }
712    }
713
714
715    // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
716    private ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
717      if (IsConstant(a) && IsConstant(b)) {
718        // fold constants
719        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
720      } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) {
721        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
722      } else if (IsVariableBase(a) && IsConstant(b)) {
723        // merge constant values into variable weights
724        var constB = ((ConstantTreeNode)b).Value;
725        ((VariableTreeNodeBase)a).Weight /= constB;
726        return a;
727      } else if (IsVariableBase(a) && IsVariableBase(b) && AreSameVariable(a, b)) {
728        // cancel variables
729        var aVar = a as VariableTreeNode;
730        var bVar = b as VariableTreeNode;
731        return MakeConstant(aVar.Weight / bVar.Weight);
732      } else if (IsAddition(a) && IsConstant(b)) {
733        return a.Subtrees
734          .Select(x => GetSimplifiedTree(x))
735         .Select(x => MakeFraction(x, b))
736         .Aggregate((c, d) => MakeSum(c, d));
737      } else if (IsMultiplication(a) && IsConstant(b)) {
738        return MakeProduct(a, Invert(b));
739      } else if (IsDivision(a) && IsConstant(b)) {
740        // (a1 / a2) / c => (a1 / (a2 * c))
741        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
742      } else if (IsDivision(a) && IsDivision(b)) {
743        // (a1 / a2) / (b1 / b2) =>
744        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
745      } else if (IsDivision(a)) {
746        // (a1 / a2) / b => (a1 / (a2 * b))
747        return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
748      } else if (IsDivision(b)) {
749        // a / (b1 / b2) => (a * b2) / b1
750        return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
751      } else {
752        var div = divSymbol.CreateTreeNode();
753        div.AddSubtree(a);
754        div.AddSubtree(b);
755        return div;
756      }
757    }
758
759    private ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
760      if (IsConstant(a) && IsConstant(b)) {
761        // fold constants
762        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
763        return a;
764      } else if (IsConstant(a)) {
765        // c + x => x + c
766        // b is not constant => make sure constant is on the right
767        return MakeSum(b, a);
768      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
769        // x + 0 => x
770        return a;
771      } else if (IsAddition(a) && IsAddition(b)) {
772        // merge additions
773        var add = addSymbol.CreateTreeNode();
774        // add all sub trees except for the last
775        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
776        for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
777        if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
778          add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
779        } else if (IsConstant(a.Subtrees.Last())) {
780          add.AddSubtree(b.Subtrees.Last());
781          add.AddSubtree(a.Subtrees.Last());
782        } else {
783          add.AddSubtree(a.Subtrees.Last());
784          add.AddSubtree(b.Subtrees.Last());
785        }
786        MergeVariablesInSum(add);
787        if (add.Subtrees.Count() == 1) {
788          return add.GetSubtree(0);
789        } else {
790          return add;
791        }
792      } else if (IsAddition(b)) {
793        return MakeSum(b, a);
794      } else if (IsAddition(a) && IsConstant(b)) {
795        // a is an addition and b is a constant => append b to a and make sure the constants are merged
796        var add = addSymbol.CreateTreeNode();
797        // add all sub trees except for the last
798        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
799        if (IsConstant(a.Subtrees.Last()))
800          add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
801        else {
802          add.AddSubtree(a.Subtrees.Last());
803          add.AddSubtree(b);
804        }
805        return add;
806      } else if (IsAddition(a)) {
807        // a is already an addition => append b
808        var add = addSymbol.CreateTreeNode();
809        add.AddSubtree(b);
810        foreach (var subtree in a.Subtrees) {
811          add.AddSubtree(subtree);
812        }
813        MergeVariablesInSum(add);
814        if (add.Subtrees.Count() == 1) {
815          return add.GetSubtree(0);
816        } else {
817          return add;
818        }
819      } else {
820        var add = addSymbol.CreateTreeNode();
821        add.AddSubtree(a);
822        add.AddSubtree(b);
823        MergeVariablesInSum(add);
824        if (add.Subtrees.Count() == 1) {
825          return add.GetSubtree(0);
826        } else {
827          return add;
828        }
829      }
830    }
831
832    // makes sure variable symbols in sums are combined
833    // possible improvement: combine sums of products where the products only reference the same variable
834    private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
835      var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
836      while (sum.Subtrees.Any()) sum.RemoveSubtree(0);
837      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNodeBase>()
838                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
839                            let cat = (node is FactorVariableTreeNode) ? ((FactorVariableTreeNode)node).VariableValue : string.Empty
840                            group node by node.VariableName + cat + lag into g
841                            select g;
842      var unchangedSubtrees = subtrees.Where(t => !(t is VariableTreeNodeBase));
843
844      foreach (var variableNodeGroup in groupedVarNodes) {
845        var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
846        var representative = variableNodeGroup.First();
847        representative.Weight = weightSum;
848        sum.AddSubtree(representative);
849      }
850      foreach (var unchangedSubtree in unchangedSubtrees)
851        sum.AddSubtree(unchangedSubtree);
852    }
853
854
855    private ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
856      if (IsConstant(a) && IsConstant(b)) {
857        // fold constants
858        ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
859        return a;
860      } else if (IsConstant(a)) {
861        // a * $ => $ * a
862        return MakeProduct(b, a);
863      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
864        // $ * 1.0 => $
865        return a;
866      } else if (IsConstant(b) && IsVariableBase(a)) {
867        // multiply constants into variables weights
868        ((VariableTreeNodeBase)a).Weight *= ((ConstantTreeNode)b).Value;
869        return a;
870      } else if (IsConstant(b) && IsAddition(a)) {
871        // multiply constants into additions
872        return a.Subtrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d));
873      } else if (IsDivision(a) && IsDivision(b)) {
874        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
875        return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
876      } else if (IsDivision(a)) {
877        // (a1 / a2) * b => (a1 * b) / a2
878        return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
879      } else if (IsDivision(b)) {
880        // a * (b1 / b2) => (b1 * a) / b2
881        return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
882      } else if (IsMultiplication(a) && IsMultiplication(b)) {
883        // merge multiplications (make sure constants are merged)
884        var mul = mulSymbol.CreateTreeNode();
885        for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
886        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
887        MergeVariablesAndConstantsInProduct(mul);
888        return mul;
889      } else if (IsMultiplication(b)) {
890        return MakeProduct(b, a);
891      } else if (IsMultiplication(a)) {
892        // a is already an multiplication => append b
893        a.AddSubtree(b);
894        MergeVariablesAndConstantsInProduct(a);
895        return a;
896      } else {
897        var mul = mulSymbol.CreateTreeNode();
898        mul.AddSubtree(a);
899        mul.AddSubtree(b);
900        MergeVariablesAndConstantsInProduct(mul);
901        return mul;
902      }
903    }
904    #endregion
905
906
907    #region helper functions
908    private bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
909      if (node.Symbol is VariableCondition) return true;
910      foreach (var subtree in node.Subtrees)
911        if (ContainsVariableCondition(subtree)) return true;
912      return false;
913    }
914
915    private ISymbolicExpressionTreeNode AddLagToDynamicNodes(ISymbolicExpressionTreeNode node, int lag) {
916      var laggedTreeNode = node as ILaggedTreeNode;
917      var variableNode = node as VariableTreeNode;
918      var variableConditionNode = node as VariableConditionTreeNode;
919      if (laggedTreeNode != null)
920        laggedTreeNode.Lag += lag;
921      else if (variableNode != null) {
922        var laggedVariableNode = (LaggedVariableTreeNode)laggedVariableSymbol.CreateTreeNode();
923        laggedVariableNode.Lag = lag;
924        laggedVariableNode.VariableName = variableNode.VariableName;
925        return laggedVariableNode;
926      } else if (variableConditionNode != null) {
927        throw new NotSupportedException("Removal of time lags around variable condition symbols is not allowed.");
928      }
929      var subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
930      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
931      foreach (var subtree in subtrees) {
932        node.AddSubtree(AddLagToDynamicNodes(subtree, lag));
933      }
934      return node;
935    }
936
937    private bool AreSameVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
938      var aLaggedVar = a as LaggedVariableTreeNode;
939      var bLaggedVar = b as LaggedVariableTreeNode;
940      if (aLaggedVar != null && bLaggedVar != null) {
941        return aLaggedVar.VariableName == bLaggedVar.VariableName &&
942          aLaggedVar.Lag == bLaggedVar.Lag;
943      }
944      var aVar = a as VariableTreeNode;
945      var bVar = b as VariableTreeNode;
946      if (aVar != null && bVar != null) {
947        return aVar.VariableName == bVar.VariableName;
948      }
949      var aFactor = a as FactorVariableTreeNode;
950      var bFactor = b as FactorVariableTreeNode;
951      if (aFactor != null && bFactor != null) {
952        return aFactor.VariableName == bFactor.VariableName &&
953          aFactor.VariableValue == bFactor.VariableValue;
954      }
955
956      return false;
957    }
958
959    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
960    private void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
961      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
962      while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
963      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNodeBase>()
964                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
965                            group node by node.VariableName + lag into g
966                            orderby g.Count()
967                            select g;
968      var constantProduct = (from node in subtrees.OfType<VariableTreeNodeBase>()
969                             select node.Weight)
970                            .Concat(from node in subtrees.OfType<ConstantTreeNode>()
971                                    select node.Value)
972                            .DefaultIfEmpty(1.0)
973                            .Aggregate((c1, c2) => c1 * c2);
974
975      var unchangedSubtrees = from tree in subtrees
976                              where !(tree is VariableTreeNodeBase)
977                              where !(tree is ConstantTreeNode)
978                              select tree;
979
980      foreach (var variableNodeGroup in groupedVarNodes) {
981        var representative = variableNodeGroup.First();
982        representative.Weight = 1.0;
983        if (variableNodeGroup.Count() > 1) {
984          var poly = mulSymbol.CreateTreeNode();
985          for (int p = 0; p < variableNodeGroup.Count(); p++) {
986            poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
987          }
988          prod.AddSubtree(poly);
989        } else {
990          prod.AddSubtree(representative);
991        }
992      }
993
994      foreach (var unchangedSubtree in unchangedSubtrees)
995        prod.AddSubtree(unchangedSubtree);
996
997      if (!constantProduct.IsAlmost(1.0)) {
998        prod.AddSubtree(MakeConstant(constantProduct));
999      }
1000    }
1001
1002
1003    /// <summary>
1004    /// x => x * -1
1005    /// Doesn't create new trees and manipulates x
1006    /// </summary>
1007    /// <param name="x"></param>
1008    /// <returns>-x</returns>
1009    private ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
1010      if (IsConstant(x)) {
1011        ((ConstantTreeNode)x).Value *= -1;
1012      } else if (IsVariableBase(x)) {
1013        var variableTree = (VariableTreeNodeBase)x;
1014        variableTree.Weight *= -1.0;
1015      } else if (IsAddition(x)) {
1016        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
1017        var subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
1018        while (x.Subtrees.Any()) x.RemoveSubtree(0);
1019        foreach (var subtree in subtrees) {
1020          x.AddSubtree(Negate(subtree));
1021        }
1022      } else if (IsMultiplication(x) || IsDivision(x)) {
1023        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
1024        var lastSubTree = x.Subtrees.Last();
1025        x.RemoveSubtree(x.SubtreeCount - 1);
1026        x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
1027      } else {
1028        // any other function
1029        return MakeProduct(x, MakeConstant(-1));
1030      }
1031      return x;
1032    }
1033
1034    /// <summary>
1035    /// x => 1/x
1036    /// Doesn't create new trees and manipulates x
1037    /// </summary>
1038    /// <param name="x"></param>
1039    /// <returns></returns>
1040    private ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
1041      if (IsConstant(x)) {
1042        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
1043      } else if (IsDivision(x)) {
1044        return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
1045      } else {
1046        // any other function
1047        return MakeFraction(MakeConstant(1), x);
1048      }
1049    }
1050
1051    private ISymbolicExpressionTreeNode MakeConstant(double value) {
1052      ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
1053      constantTreeNode.Value = value;
1054      return constantTreeNode;
1055    }
1056
1057    private ISymbolicExpressionTreeNode MakeVariable(double weight, string name) {
1058      var tree = (VariableTreeNode)varSymbol.CreateTreeNode();
1059      tree.Weight = weight;
1060      tree.VariableName = name;
1061      return tree;
1062    }
1063    #endregion
1064  }
1065}
Note: See TracBrowser for help on using the repository browser.