Free cookie consent management tool by TermsFeed Policy Generator

source: branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SymbolicSimplifier.cs @ 4695

Last change on this file since 4695 was 4554, checked in by gkronber, 14 years ago

Changed symbolic simplifier to handle time series specific terminals correctly. #1142

File size: 22.0 KB
RevLine 
[3442]1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
[4068]24using System.Diagnostics;
[3442]25using System.Linq;
26using HeuristicLab.Common;
27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[3462]28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;
[3442]29using HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols;
30
31namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
32  /// <summary>
33  /// Simplistic simplifier for arithmetic expressions
34  /// </summary>
35  public class SymbolicSimplifier {
[3462]36    private Addition addSymbol = new Addition();
37    private Multiplication mulSymbol = new Multiplication();
38    private Division divSymbol = new Division();
39    private Constant constSymbol = new Constant();
40    private Variable varSymbol = new Variable();
41
[3442]42    public SymbolicExpressionTree Simplify(SymbolicExpressionTree originalTree) {
43      var clone = (SymbolicExpressionTreeNode)originalTree.Root.Clone();
44      // macro expand (initially no argument trees)
45      var macroExpandedTree = MacroExpand(clone, clone.SubTrees[0], new List<SymbolicExpressionTreeNode>());
[4462]46      SymbolicExpressionTreeNode rootNode = (new ProgramRootSymbol()).CreateTreeNode();
47      rootNode.AddSubTree(GetSimplifiedTree(macroExpandedTree));
48      return new SymbolicExpressionTree(rootNode);
[3442]49    }
50
51    // the argumentTrees list contains already expanded trees used as arguments for invocations
52    private SymbolicExpressionTreeNode MacroExpand(SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode node, IList<SymbolicExpressionTreeNode> argumentTrees) {
53      List<SymbolicExpressionTreeNode> subtrees = new List<SymbolicExpressionTreeNode>(node.SubTrees);
[3985]54      while (node.SubTrees.Count > 0) node.RemoveSubTree(0);
[3442]55      if (node.Symbol is InvokeFunction) {
56        var invokeSym = node.Symbol as InvokeFunction;
57        var defunNode = FindFunctionDefinition(root, invokeSym.FunctionName);
58        var macroExpandedArguments = new List<SymbolicExpressionTreeNode>();
59        foreach (var subtree in subtrees) {
60          macroExpandedArguments.Add(MacroExpand(root, subtree, argumentTrees));
61        }
62        return MacroExpand(root, defunNode, macroExpandedArguments);
63      } else if (node.Symbol is Argument) {
64        var argSym = node.Symbol as Argument;
65        // return the correct argument sub-tree (already macro-expanded)
66        return (SymbolicExpressionTreeNode)argumentTrees[argSym.ArgumentIndex].Clone();
67      } else {
68        // recursive application
69        foreach (var subtree in subtrees) {
70          node.AddSubTree(MacroExpand(root, subtree, argumentTrees));
71        }
72        return node;
73      }
74    }
75
76    private SymbolicExpressionTreeNode FindFunctionDefinition(SymbolicExpressionTreeNode root, string functionName) {
77      foreach (var subtree in root.SubTrees.OfType<DefunTreeNode>()) {
78        if (subtree.FunctionName == functionName) return subtree.SubTrees[0];
79      }
80
81      throw new ArgumentException("Definition of function " + functionName + " not found.");
82    }
83
[4220]84
85    #region symbol predicates
86    private bool IsDivision(SymbolicExpressionTreeNode original) {
87      return original.Symbol is Division;
88    }
89
90    private bool IsMultiplication(SymbolicExpressionTreeNode original) {
91      return original.Symbol is Multiplication;
92    }
93
94    private bool IsSubtraction(SymbolicExpressionTreeNode original) {
95      return original.Symbol is Subtraction;
96    }
97
98    private bool IsAddition(SymbolicExpressionTreeNode original) {
99      return original.Symbol is Addition;
100    }
101
102    private bool IsVariable(SymbolicExpressionTreeNode original) {
103      return original.Symbol is Variable;
104    }
105
106    private bool IsConstant(SymbolicExpressionTreeNode original) {
107      return original.Symbol is Constant;
108    }
109
110    private bool IsAverage(SymbolicExpressionTreeNode original) {
111      return original.Symbol is Average;
112    }
113    private bool IsLog(SymbolicExpressionTreeNode original) {
114      return original.Symbol is Logarithm;
115    }
[4226]116    private bool IsIfThenElse(SymbolicExpressionTreeNode original) {
117      return original.Symbol is IfThenElse;
118    }
[4220]119    #endregion
120
[3442]121    /// <summary>
122    /// Creates a new simplified tree
123    /// </summary>
124    /// <param name="original"></param>
125    /// <returns></returns>
126    public SymbolicExpressionTreeNode GetSimplifiedTree(SymbolicExpressionTreeNode original) {
127      if (IsConstant(original) || IsVariable(original)) {
128        return (SymbolicExpressionTreeNode)original.Clone();
129      } else if (IsAddition(original)) {
[4220]130        return SimplifyAddition(original);
[3442]131      } else if (IsSubtraction(original)) {
[4220]132        return SimplifySubtraction(original);
[3442]133      } else if (IsMultiplication(original)) {
[4220]134        return SimplifyMultiplication(original);
[3442]135      } else if (IsDivision(original)) {
[4220]136        return SimplifyDivision(original);
[3876]137      } else if (IsAverage(original)) {
[4220]138        return SimplifyAverage(original);
139      } else if (IsLog(original)) {
[4226]140        // TODO simplify logarithm
[4220]141        return SimplifyAny(original);
[4226]142      } else if (IsIfThenElse(original)) {
143        // TODO simplify conditionals
144        return SimplifyAny(original);
[4220]145      } else if (IsAverage(original)) {
146        return SimplifyAverage(original);
[3442]147      } else {
[4220]148        return SimplifyAny(original);
[3442]149      }
150    }
151
[4220]152    #region specific simplification routines
153    private SymbolicExpressionTreeNode SimplifyAny(SymbolicExpressionTreeNode original) {
154      // can't simplify this function but simplify all subtrees
155      List<SymbolicExpressionTreeNode> subTrees = new List<SymbolicExpressionTreeNode>(original.SubTrees);
156      while (original.SubTrees.Count > 0) original.RemoveSubTree(0);
157      var clone = (SymbolicExpressionTreeNode)original.Clone();
158      List<SymbolicExpressionTreeNode> simplifiedSubTrees = new List<SymbolicExpressionTreeNode>();
159      foreach (var subTree in subTrees) {
160        simplifiedSubTrees.Add(GetSimplifiedTree(subTree));
161        original.AddSubTree(subTree);
162      }
163      foreach (var simplifiedSubtree in simplifiedSubTrees) {
164        clone.AddSubTree(simplifiedSubtree);
165      }
166      if (simplifiedSubTrees.TrueForAll(t => IsConstant(t))) {
167        SimplifyConstantExpression(clone);
168      }
169      return clone;
170    }
171
172    private SymbolicExpressionTreeNode SimplifyConstantExpression(SymbolicExpressionTreeNode original) {
173      // not yet implemented
174      return original;
175    }
176
177    private SymbolicExpressionTreeNode SimplifyAverage(SymbolicExpressionTreeNode original) {
178      if (original.SubTrees.Count == 1) {
179        return GetSimplifiedTree(original.SubTrees[0]);
[3442]180      } else {
[4220]181        // simplify expressions x0..xn
182        // make sum(x0..xn) / n
183        Trace.Assert(original.SubTrees.Count > 1);
184        var sum = original.SubTrees
185          .Select(x => GetSimplifiedTree(x))
186          .Aggregate((a, b) => MakeSum(a, b));
187        return MakeFraction(sum, MakeConstant(original.SubTrees.Count));
[3442]188      }
189    }
190
[4220]191    private SymbolicExpressionTreeNode SimplifyDivision(SymbolicExpressionTreeNode original) {
192      if (original.SubTrees.Count == 1) {
193        return Invert(GetSimplifiedTree(original.SubTrees[0]));
[3442]194      } else {
[4220]195        // simplify expressions x0..xn
196        // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
197        Trace.Assert(original.SubTrees.Count > 1);
198        var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x));
199        return
200          MakeProduct(simplifiedTrees.First(), Invert(simplifiedTrees.Skip(1).Aggregate((a, b) => MakeProduct(a, b))));
[3442]201      }
202    }
203
[4220]204    private SymbolicExpressionTreeNode SimplifyMultiplication(SymbolicExpressionTreeNode original) {
205      if (original.SubTrees.Count == 1) {
206        return GetSimplifiedTree(original.SubTrees[0]);
207      } else {
208        Trace.Assert(original.SubTrees.Count > 1);
209        return original.SubTrees
210          .Select(x => GetSimplifiedTree(x))
211          .Aggregate((a, b) => MakeProduct(a, b));
212      }
213    }
214
215    private SymbolicExpressionTreeNode SimplifySubtraction(SymbolicExpressionTreeNode original) {
216      if (original.SubTrees.Count == 1) {
217        return Negate(GetSimplifiedTree(original.SubTrees[0]));
218      } else {
219        // simplify expressions x0..xn
220        // make addition (x0,-x1..-xn)
221        Trace.Assert(original.SubTrees.Count > 1);
222        var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x));
223        return simplifiedTrees.Take(1)
224          .Concat(simplifiedTrees.Skip(1).Select(x => Negate(x)))
225          .Aggregate((a, b) => MakeSum(a, b));
226      }
227    }
228
229    private SymbolicExpressionTreeNode SimplifyAddition(SymbolicExpressionTreeNode original) {
230      if (original.SubTrees.Count == 1) {
231        return GetSimplifiedTree(original.SubTrees[0]);
232      } else {
233        // simplify expression x0..xn
234        // make addition (x0..xn)
235        Trace.Assert(original.SubTrees.Count > 1);
236        return original.SubTrees
237          .Select(x => GetSimplifiedTree(x))
238          .Aggregate((a, b) => MakeSum(a, b));
239      }
240    }
241    #endregion
242
243
244
245    #region low level tree restructuring
[4226]246    // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
[4220]247
248    private SymbolicExpressionTreeNode MakeFraction(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
[3442]249      if (IsConstant(a) && IsConstant(b)) {
[4220]250        // fold constants
[3442]251        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
[4220]252      } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) {
253        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
[3442]254      } else if (IsVariable(a) && IsConstant(b)) {
[4220]255        // merge constant values into variable weights
[3442]256        var constB = ((ConstantTreeNode)b).Value;
257        ((VariableTreeNode)a).Weight /= constB;
258        return a;
[4220]259      } else if (IsAddition(a) && IsConstant(b)) {
260        return a.SubTrees
[4389]261          .Select(x => GetSimplifiedTree(x))
[4220]262         .Select(x => MakeFraction(x, b))
263         .Aggregate((c, d) => MakeSum(c, d));
264      } else if (IsMultiplication(a) && IsConstant(b)) {
265        return MakeProduct(a, Invert(b));
266      } else if (IsDivision(a) && IsConstant(b)) {
267        // (a1 / a2) / c => (a1 / (a2 * c))
268        Trace.Assert(a.SubTrees.Count == 2);
269        return MakeFraction(a.SubTrees[0], MakeProduct(a.SubTrees[1], b));
270      } else if (IsDivision(a) && IsDivision(b)) {
271        // (a1 / a2) / (b1 / b2) =>
272        Trace.Assert(a.SubTrees.Count == 2);
273        Trace.Assert(b.SubTrees.Count == 2);
274        return MakeFraction(MakeProduct(a.SubTrees[0], b.SubTrees[1]), MakeProduct(a.SubTrees[1], b.SubTrees[0]));
275      } else if (IsDivision(a)) {
276        // (a1 / a2) / b => (a1 / (a2 * b))
277        Trace.Assert(a.SubTrees.Count == 2);
278        return MakeFraction(a.SubTrees[0], MakeProduct(a.SubTrees[1], b));
279      } else if (IsDivision(b)) {
280        // a / (b1 / b2) => (a * b2) / b1
281        Trace.Assert(b.SubTrees.Count == 2);
282        return MakeFraction(MakeProduct(a, b.SubTrees[1]), b.SubTrees[0]);
[3442]283      } else {
[3462]284        var div = divSymbol.CreateTreeNode();
[3985]285        div.AddSubTree(a);
286        div.AddSubTree(b);
[3442]287        return div;
288      }
289    }
290
[4220]291    private SymbolicExpressionTreeNode MakeSum(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
[3442]292      if (IsConstant(a) && IsConstant(b)) {
[4220]293        // fold constants
[3442]294        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
295        return a;
296      } else if (IsConstant(a)) {
297        // c + x => x + c
298        // b is not constant => make sure constant is on the right
[4220]299        return MakeSum(b, a);
[3442]300      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
301        // x + 0 => x
302        return a;
303      } else if (IsAddition(a) && IsAddition(b)) {
304        // merge additions
[3462]305        var add = addSymbol.CreateTreeNode();
[3442]306        for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]);
307        for (int i = 0; i < b.SubTrees.Count - 1; i++) add.AddSubTree(b.SubTrees[i]);
308        if (IsConstant(a.SubTrees.Last()) && IsConstant(b.SubTrees.Last())) {
[4220]309          add.AddSubTree(MakeSum(a.SubTrees.Last(), b.SubTrees.Last()));
[3442]310        } else if (IsConstant(a.SubTrees.Last())) {
311          add.AddSubTree(b.SubTrees.Last());
312          add.AddSubTree(a.SubTrees.Last());
313        } else {
314          add.AddSubTree(a.SubTrees.Last());
315          add.AddSubTree(b.SubTrees.Last());
316        }
[4220]317        MergeVariablesInSum(add);
[3442]318        return add;
319      } else if (IsAddition(b)) {
[4220]320        return MakeSum(b, a);
[3442]321      } else if (IsAddition(a) && IsConstant(b)) {
[4220]322        // a is an addition and b is a constant => append b to a and make sure the constants are merged
[3462]323        var add = addSymbol.CreateTreeNode();
[3442]324        for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]);
325        if (IsConstant(a.SubTrees.Last()))
[4220]326          add.AddSubTree(MakeSum(a.SubTrees.Last(), b));
[3442]327        else {
328          add.AddSubTree(a.SubTrees.Last());
329          add.AddSubTree(b);
330        }
331        return add;
332      } else if (IsAddition(a)) {
[4220]333        // a is already an addition => append b
[3462]334        var add = addSymbol.CreateTreeNode();
[3442]335        add.AddSubTree(b);
336        foreach (var subTree in a.SubTrees) {
337          add.AddSubTree(subTree);
338        }
[4220]339        MergeVariablesInSum(add);
[3442]340        return add;
341      } else {
[3462]342        var add = addSymbol.CreateTreeNode();
[3985]343        add.AddSubTree(a);
344        add.AddSubTree(b);
[4220]345        MergeVariablesInSum(add);
[3442]346        return add;
347      }
348    }
349
[4226]350    // makes sure variable symbols in sums are combined
351    // possible improvment: combine sums of products where the products only reference the same variable
[4220]352    private void MergeVariablesInSum(SymbolicExpressionTreeNode sum) {
353      var subtrees = new List<SymbolicExpressionTreeNode>(sum.SubTrees);
354      while (sum.SubTrees.Count > 0) sum.RemoveSubTree(0);
[3442]355      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
[4554]356                            where node.Symbol.Name == "Variable"
[3442]357                            group node by node.VariableName into g
358                            select g;
[4554]359      var unchangedSubTrees = subtrees.Where(t => t.Symbol.Name != "Variable");
[3442]360
361      foreach (var variableNodeGroup in groupedVarNodes) {
362        var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
363        var representative = variableNodeGroup.First();
364        representative.Weight = weightSum;
[4220]365        sum.AddSubTree(representative);
[3442]366      }
367      foreach (var unchangedSubtree in unchangedSubTrees)
[4220]368        sum.AddSubTree(unchangedSubtree);
[3442]369    }
370
[4220]371
372    private SymbolicExpressionTreeNode MakeProduct(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
[3442]373      if (IsConstant(a) && IsConstant(b)) {
[4220]374        // fold constants
[3442]375        ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
376        return a;
377      } else if (IsConstant(a)) {
[4220]378        // a * $ => $ * a
379        return MakeProduct(b, a);
[3442]380      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
[4220]381        // $ * 1.0 => $
[3442]382        return a;
383      } else if (IsConstant(b) && IsVariable(a)) {
[4220]384        // multiply constants into variables weights
[3442]385        ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value;
386        return a;
387      } else if (IsConstant(b) && IsAddition(a)) {
[4220]388        // multiply constants into additions
389        return a.SubTrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d));
[4068]390      } else if (IsDivision(a) && IsDivision(b)) {
[4220]391        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
392        Trace.Assert(a.SubTrees.Count == 2);
393        Trace.Assert(b.SubTrees.Count == 2);
394        return MakeFraction(MakeProduct(a.SubTrees[0], b.SubTrees[0]), MakeProduct(a.SubTrees[1], b.SubTrees[1]));
[3442]395      } else if (IsDivision(a)) {
[4220]396        // (a1 / a2) * b => (a1 * b) / a2
[3442]397        Trace.Assert(a.SubTrees.Count == 2);
[4220]398        return MakeFraction(MakeProduct(a.SubTrees[0], b), a.SubTrees[1]);
[3442]399      } else if (IsDivision(b)) {
[4220]400        // a * (b1 / b2) => (b1 * a) / b2
[3442]401        Trace.Assert(b.SubTrees.Count == 2);
[4220]402        return MakeFraction(MakeProduct(b.SubTrees[0], a), b.SubTrees[1]);
[3442]403      } else if (IsMultiplication(a) && IsMultiplication(b)) {
[4220]404        // merge multiplications (make sure constants are merged)
[3462]405        var mul = mulSymbol.CreateTreeNode();
[4220]406        for (int i = 0; i < a.SubTrees.Count; i++) mul.AddSubTree(a.SubTrees[i]);
407        for (int i = 0; i < b.SubTrees.Count; i++) mul.AddSubTree(b.SubTrees[i]);
408        MergeVariablesAndConstantsInProduct(mul);
[3442]409        return mul;
[4220]410      } else if (IsMultiplication(b)) {
411        return MakeProduct(b, a);
[3442]412      } else if (IsMultiplication(a)) {
[4220]413        // a is already an multiplication => append b
414        a.AddSubTree(b);
415        MergeVariablesAndConstantsInProduct(a);
416        return a;
[3442]417      } else {
[3462]418        var mul = mulSymbol.CreateTreeNode();
[3442]419        mul.SubTrees.Add(a);
420        mul.SubTrees.Add(b);
[4220]421        MergeVariablesAndConstantsInProduct(mul);
[3442]422        return mul;
423      }
424    }
[4220]425    #endregion
[3442]426
[4226]427    // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
[4220]428    private void MergeVariablesAndConstantsInProduct(SymbolicExpressionTreeNode prod) {
429      var subtrees = new List<SymbolicExpressionTreeNode>(prod.SubTrees);
430      while (prod.SubTrees.Count > 0) prod.RemoveSubTree(0);
431      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
[4554]432                            where node.Symbol.Name == "Variable"
[4220]433                            group node by node.VariableName into g
434                            orderby g.Count()
435                            select g;
436      var constantProduct = (from node in subtrees.OfType<VariableTreeNode>()
[4554]437                             where node.Symbol.Name == "Variable"
[4220]438                             select node.Weight)
439                            .Concat(from node in subtrees.OfType<ConstantTreeNode>()
440                                    select node.Value)
441                            .DefaultIfEmpty(1.0)
442                            .Aggregate((c1, c2) => c1 * c2);
[3442]443
[4220]444      var unchangedSubTrees = from tree in subtrees
[4554]445                              where !(tree is VariableTreeNode && tree.Symbol.Name == "Variable")
[4220]446                              where !(tree is ConstantTreeNode)
447                              select tree;
[3442]448
[4220]449      foreach (var variableNodeGroup in groupedVarNodes) {
450        var representative = variableNodeGroup.First();
451        representative.Weight = 1.0;
452        if (variableNodeGroup.Count() > 1) {
453          var poly = mulSymbol.CreateTreeNode();
454          for (int p = 0; p < variableNodeGroup.Count(); p++) {
455            poly.AddSubTree((SymbolicExpressionTreeNode)representative.Clone());
456          }
457          prod.AddSubTree(poly);
458        } else {
459          prod.AddSubTree(representative);
460        }
461      }
[3442]462
[4220]463      foreach (var unchangedSubtree in unchangedSubTrees)
464        prod.AddSubTree(unchangedSubtree);
[3442]465
[4220]466      if (!constantProduct.IsAlmost(1.0)) {
467        prod.AddSubTree(MakeConstant(constantProduct));
468      }
[3442]469    }
470
[4220]471
472    #region helper functions
473    /// <summary>
474    /// x => x * -1
475    /// Doesn't create new trees and manipulates x
476    /// </summary>
477    /// <param name="x"></param>
478    /// <returns>-x</returns>
479    private SymbolicExpressionTreeNode Negate(SymbolicExpressionTreeNode x) {
480      if (IsConstant(x)) {
481        ((ConstantTreeNode)x).Value *= -1;
482      } else if (IsVariable(x)) {
483        var variableTree = (VariableTreeNode)x;
484        variableTree.Weight *= -1.0;
485      } else if (IsAddition(x)) {
486        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
487        foreach (var subTree in x.SubTrees) {
488          Negate(subTree);
489        }
490      } else if (IsMultiplication(x) || IsDivision(x)) {
491        // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
492        Negate(x.SubTrees.Last()); // last is maybe a constant, prefer to negate the constant
493      } else {
494        // any other function
495        return MakeProduct(x, MakeConstant(-1));
496      }
497      return x;
[3442]498    }
[3876]499
[4220]500    /// <summary>
501    /// x => 1/x
502    /// Doesn't create new trees and manipulates x
503    /// </summary>
504    /// <param name="x"></param>
505    /// <returns></returns>
506    private SymbolicExpressionTreeNode Invert(SymbolicExpressionTreeNode x) {
507      if (IsConstant(x)) {
[4238]508        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
[4220]509      } else if (IsDivision(x)) {
510        Trace.Assert(x.SubTrees.Count == 2);
511        return MakeFraction(x.SubTrees[1], x.SubTrees[0]);
512      } else {
513        // any other function
514        return MakeFraction(MakeConstant(1), x);
515      }
[3876]516    }
[3442]517
518    private SymbolicExpressionTreeNode MakeConstant(double value) {
[3462]519      ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
[3442]520      constantTreeNode.Value = value;
521      return (SymbolicExpressionTreeNode)constantTreeNode;
522    }
523
524    private SymbolicExpressionTreeNode MakeVariable(double weight, string name) {
[3462]525      var tree = (VariableTreeNode)varSymbol.CreateTreeNode();
[3442]526      tree.Weight = weight;
527      tree.VariableName = name;
528      return tree;
529    }
[4220]530    #endregion
[3442]531  }
532}
Note: See TracBrowser for help on using the repository browser.