Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/VectorTreeSimplifier.cs @ 17597

Last change on this file since 17597 was 17597, checked in by pfleck, 4 years ago

#3040: Added simplification rules for length-aggregation.

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