Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 14765 was 14540, checked in by gkronber, 7 years ago

#2650: fixed bugs in simplifier (causing multiple references to the same tree nodes within a tree)

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