Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj (revision 15140)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj (revision 15141)
@@ -102,8 +102,4 @@
False
..\..\bin\ALGLIB-3.7.0.dll
- False
-
-
- ..\..\bin\AutoDiff-1.0.dll
False
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/Plugin.cs.frame
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/Plugin.cs.frame (revision 15140)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/Plugin.cs.frame (revision 15141)
@@ -29,5 +29,4 @@
[PluginFile("HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.dll", PluginFileType.Assembly)]
[PluginDependency("HeuristicLab.ALGLIB", "3.7.0")]
- [PluginDependency("HeuristicLab.AutoDiff", "1.0")]
[PluginDependency("HeuristicLab.Analysis", "3.3")]
[PluginDependency("HeuristicLab.Common", "3.3")]
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionConstantOptimizationEvaluator.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionConstantOptimizationEvaluator.cs (revision 15140)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionConstantOptimizationEvaluator.cs (revision 15141)
@@ -23,5 +23,4 @@
using System.Collections.Generic;
using System.Linq;
-using AutoDiff;
using HeuristicLab.Common;
using HeuristicLab.Core;
@@ -153,28 +152,4 @@
}
- #region derivations of functions
- // create function factory for arctangent
- private readonly Func arctan = UnaryFunc.Factory(
- eval: Math.Atan,
- diff: x => 1 / (1 + x * x));
- private static readonly Func sin = UnaryFunc.Factory(
- eval: Math.Sin,
- diff: Math.Cos);
- private static readonly Func cos = UnaryFunc.Factory(
- eval: Math.Cos,
- diff: x => -Math.Sin(x));
- private static readonly Func tan = UnaryFunc.Factory(
- eval: Math.Tan,
- diff: x => 1 + Math.Tan(x) * Math.Tan(x));
- private static readonly Func erf = UnaryFunc.Factory(
- eval: alglib.errorfunction,
- diff: x => 2.0 * Math.Exp(-(x * x)) / Math.Sqrt(Math.PI));
- private static readonly Func norm = UnaryFunc.Factory(
- eval: alglib.normaldistribution,
- diff: x => -(Math.Exp(-(x * x)) * Math.Sqrt(Math.Exp(x * x)) * x) / Math.Sqrt(2 * Math.PI));
- #endregion
-
-
-
public static double OptimizeConstants(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable rows, bool applyLinearScaling,
@@ -188,46 +163,21 @@
// variable name, variable value (for factor vars) and lag as a DataForVariable object.
// A dictionary is used to find parameters
- var variables = new List();
- var parameters = new Dictionary();
-
- AutoDiff.Term func;
- if (!TryTransformToAutoDiff(tree.Root.GetSubtree(0), variables, parameters, updateVariableWeights, out func))
+ double[] initialConstants;
+ var parameters = new List();
+
+ TreeToAutoDiffTermTransformator.ParametricFunction func;
+ TreeToAutoDiffTermTransformator.ParametricFunctionGradient func_grad;
+ if (!TreeToAutoDiffTermTransformator.TryTransformToAutoDiff(tree, updateVariableWeights, out parameters, out initialConstants, out func, out func_grad))
throw new NotSupportedException("Could not optimize constants of symbolic expression tree due to not supported symbols used in the tree.");
if (parameters.Count == 0) return 0.0; // gkronber: constant expressions always have a R² of 0.0
var parameterEntries = parameters.ToArray(); // order of entries must be the same for x
- AutoDiff.IParametricCompiledTerm compiledFunc = func.Compile(variables.ToArray(), parameterEntries.Select(kvp => kvp.Value).ToArray());
-
- List terminalNodes = null; // gkronber only used for extraction of initial constants
- if (updateVariableWeights)
- terminalNodes = tree.Root.IterateNodesPrefix().OfType().ToList();
- else
- terminalNodes = new List
- (tree.Root.IterateNodesPrefix()
- .OfType()
- .Where(node => node is ConstantTreeNode || node is FactorVariableTreeNode));
//extract inital constants
- double[] c = new double[variables.Count];
+ double[] c = new double[initialConstants.Length];
{
c[0] = 0.0;
c[1] = 1.0;
- int i = 2;
- foreach (var node in terminalNodes) {
- ConstantTreeNode constantTreeNode = node as ConstantTreeNode;
- VariableTreeNode variableTreeNode = node as VariableTreeNode;
- BinaryFactorVariableTreeNode binFactorVarTreeNode = node as BinaryFactorVariableTreeNode;
- FactorVariableTreeNode factorVarTreeNode = node as FactorVariableTreeNode;
- if (constantTreeNode != null)
- c[i++] = constantTreeNode.Value;
- else if (updateVariableWeights && variableTreeNode != null)
- c[i++] = variableTreeNode.Weight;
- else if (updateVariableWeights && binFactorVarTreeNode != null)
- c[i++] = binFactorVarTreeNode.Weight;
- else if (factorVarTreeNode != null) {
- // gkronber: a factorVariableTreeNode holds a category-specific constant therefore we can consider factors to be the same as constants
- foreach (var w in factorVarTreeNode.Weights) c[i++] = w;
- }
- }
+ Array.Copy(initialConstants, 0, c, 2, initialConstants.Length);
}
double[] originalConstants = (double[])c.Clone();
@@ -243,6 +193,5 @@
foreach (var r in rows) {
int col = 0;
- foreach (var kvp in parameterEntries) {
- var info = kvp.Key;
+ foreach (var info in parameterEntries) {
if (ds.VariableHasType(info.variableName)) {
x[row, col] = ds.GetDoubleValue(info.variableName, r + info.lag);
@@ -259,6 +208,6 @@
int k = c.Length;
- alglib.ndimensional_pfunc function_cx_1_func = CreatePFunc(compiledFunc);
- alglib.ndimensional_pgrad function_cx_1_grad = CreatePGrad(compiledFunc);
+ alglib.ndimensional_pfunc function_cx_1_func = CreatePFunc(func);
+ alglib.ndimensional_pgrad function_cx_1_grad = CreatePGrad(func_grad);
try {
@@ -305,304 +254,20 @@
}
- private static alglib.ndimensional_pfunc CreatePFunc(AutoDiff.IParametricCompiledTerm compiledFunc) {
- return (double[] c, double[] x, ref double func, object o) => {
- func = compiledFunc.Evaluate(c, x);
+ private static alglib.ndimensional_pfunc CreatePFunc(TreeToAutoDiffTermTransformator.ParametricFunction func) {
+ return (double[] c, double[] x, ref double fx, object o) => {
+ fx = func(c, x);
};
}
- private static alglib.ndimensional_pgrad CreatePGrad(AutoDiff.IParametricCompiledTerm compiledFunc) {
- return (double[] c, double[] x, ref double func, double[] grad, object o) => {
- var tupel = compiledFunc.Differentiate(c, x);
- func = tupel.Item2;
+ private static alglib.ndimensional_pgrad CreatePGrad(TreeToAutoDiffTermTransformator.ParametricFunctionGradient func_grad) {
+ return (double[] c, double[] x, ref double fx, double[] grad, object o) => {
+ var tupel = func_grad(c, x);
+ fx = tupel.Item2;
Array.Copy(tupel.Item1, grad, grad.Length);
};
}
-
- private static bool TryTransformToAutoDiff(ISymbolicExpressionTreeNode node,
- List variables, Dictionary parameters,
- bool updateVariableWeights, out AutoDiff.Term term) {
- if (node.Symbol is Constant) {
- var var = new AutoDiff.Variable();
- variables.Add(var);
- term = var;
- return true;
- }
- if (node.Symbol is Variable || node.Symbol is BinaryFactorVariable) {
- var varNode = node as VariableTreeNodeBase;
- var factorVarNode = node as BinaryFactorVariableTreeNode;
- // factor variable values are only 0 or 1 and set in x accordingly
- var varValue = factorVarNode != null ? factorVarNode.VariableValue : string.Empty;
- var par = FindOrCreateParameter(parameters, varNode.VariableName, varValue);
-
- if (updateVariableWeights) {
- var w = new AutoDiff.Variable();
- variables.Add(w);
- term = AutoDiff.TermBuilder.Product(w, par);
- } else {
- term = varNode.Weight * par;
- }
- return true;
- }
- if (node.Symbol is FactorVariable) {
- var factorVarNode = node as FactorVariableTreeNode;
- var products = new List();
- foreach (var variableValue in factorVarNode.Symbol.GetVariableValues(factorVarNode.VariableName)) {
- var par = FindOrCreateParameter(parameters, factorVarNode.VariableName, variableValue);
-
- var wVar = new AutoDiff.Variable();
- variables.Add(wVar);
-
- products.Add(AutoDiff.TermBuilder.Product(wVar, par));
- }
- term = AutoDiff.TermBuilder.Sum(products);
- return true;
- }
- if (node.Symbol is LaggedVariable) {
- var varNode = node as LaggedVariableTreeNode;
- var par = FindOrCreateParameter(parameters, varNode.VariableName, string.Empty, varNode.Lag);
-
- if (updateVariableWeights) {
- var w = new AutoDiff.Variable();
- variables.Add(w);
- term = AutoDiff.TermBuilder.Product(w, par);
- } else {
- term = varNode.Weight * par;
- }
- return true;
- }
- if (node.Symbol is Addition) {
- List terms = new List();
- foreach (var subTree in node.Subtrees) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(subTree, variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- }
- terms.Add(t);
- }
- term = AutoDiff.TermBuilder.Sum(terms);
- return true;
- }
- if (node.Symbol is Subtraction) {
- List terms = new List();
- for (int i = 0; i < node.SubtreeCount; i++) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(i), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- }
- if (i > 0) t = -t;
- terms.Add(t);
- }
- if (terms.Count == 1) term = -terms[0];
- else term = AutoDiff.TermBuilder.Sum(terms);
- return true;
- }
- if (node.Symbol is Multiplication) {
- List terms = new List();
- foreach (var subTree in node.Subtrees) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(subTree, variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- }
- terms.Add(t);
- }
- if (terms.Count == 1) term = terms[0];
- else term = terms.Aggregate((a, b) => new AutoDiff.Product(a, b));
- return true;
-
- }
- if (node.Symbol is Division) {
- List terms = new List();
- foreach (var subTree in node.Subtrees) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(subTree, variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- }
- terms.Add(t);
- }
- if (terms.Count == 1) term = 1.0 / terms[0];
- else term = terms.Aggregate((a, b) => new AutoDiff.Product(a, 1.0 / b));
- return true;
- }
- if (node.Symbol is Logarithm) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = AutoDiff.TermBuilder.Log(t);
- return true;
- }
- }
- if (node.Symbol is Exponential) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = AutoDiff.TermBuilder.Exp(t);
- return true;
- }
- }
- if (node.Symbol is Square) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = AutoDiff.TermBuilder.Power(t, 2.0);
- return true;
- }
- }
- if (node.Symbol is SquareRoot) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = AutoDiff.TermBuilder.Power(t, 0.5);
- return true;
- }
- }
- if (node.Symbol is Sine) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = sin(t);
- return true;
- }
- }
- if (node.Symbol is Cosine) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = cos(t);
- return true;
- }
- }
- if (node.Symbol is Tangent) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = tan(t);
- return true;
- }
- }
- if (node.Symbol is Erf) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = erf(t);
- return true;
- }
- }
- if (node.Symbol is Norm) {
- AutoDiff.Term t;
- if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
- term = null;
- return false;
- } else {
- term = norm(t);
- return true;
- }
- }
- if (node.Symbol is StartSymbol) {
- var alpha = new AutoDiff.Variable();
- var beta = new AutoDiff.Variable();
- variables.Add(beta);
- variables.Add(alpha);
- AutoDiff.Term branchTerm;
- if (TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out branchTerm)) {
- term = branchTerm * alpha + beta;
- return true;
- } else {
- term = null;
- return false;
- }
- }
- term = null;
- return false;
- }
-
- // for each factor variable value we need a parameter which represents a binary indicator for that variable & value combination
- // each binary indicator is only necessary once. So we only create a parameter if this combination is not yet available
- private static Term FindOrCreateParameter(Dictionary parameters,
- string varName, string varValue = "", int lag = 0) {
- var data = new DataForVariable(varName, varValue, lag);
-
- AutoDiff.Variable par = null;
- if (!parameters.TryGetValue(data, out par)) {
- // not found -> create new parameter and entries in names and values lists
- par = new AutoDiff.Variable();
- parameters.Add(data, par);
- }
- return par;
- }
-
public static bool CanOptimizeConstants(ISymbolicExpressionTree tree) {
- var containsUnknownSymbol = (
- from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
- where
- !(n.Symbol is Variable) &&
- !(n.Symbol is BinaryFactorVariable) &&
- !(n.Symbol is FactorVariable) &&
- !(n.Symbol is LaggedVariable) &&
- !(n.Symbol is Constant) &&
- !(n.Symbol is Addition) &&
- !(n.Symbol is Subtraction) &&
- !(n.Symbol is Multiplication) &&
- !(n.Symbol is Division) &&
- !(n.Symbol is Logarithm) &&
- !(n.Symbol is Exponential) &&
- !(n.Symbol is SquareRoot) &&
- !(n.Symbol is Square) &&
- !(n.Symbol is Sine) &&
- !(n.Symbol is Cosine) &&
- !(n.Symbol is Tangent) &&
- !(n.Symbol is Erf) &&
- !(n.Symbol is Norm) &&
- !(n.Symbol is StartSymbol)
- select n).
- Any();
- return !containsUnknownSymbol;
- }
-
-
- #region helper class
- private class DataForVariable {
- public readonly string variableName;
- public readonly string variableValue; // for factor vars
- public readonly int lag;
-
- public DataForVariable(string varName, string varValue, int lag) {
- this.variableName = varName;
- this.variableValue = varValue;
- this.lag = lag;
- }
-
- public override bool Equals(object obj) {
- var other = obj as DataForVariable;
- if (other == null) return false;
- return other.variableName.Equals(this.variableName) &&
- other.variableValue.Equals(this.variableValue) &&
- other.lag == this.lag;
- }
-
- public override int GetHashCode() {
- return variableName.GetHashCode() ^ variableValue.GetHashCode() ^ lag;
- }
- }
- #endregion
+ return TreeToAutoDiffTermTransformator.IsCompatible(tree);
+ }
}
}
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj (revision 15140)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj (revision 15141)
@@ -101,4 +101,8 @@
..\..\bin\ALGLIB-3.7.0.dll
+ False
+
+
+ ..\..\bin\AutoDiff-1.0.dll
False
@@ -145,5 +149,4 @@
-
@@ -188,5 +191,4 @@
-
@@ -248,5 +250,8 @@
-
+
+
+
+
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Plugin.cs.frame
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Plugin.cs.frame (revision 15140)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Plugin.cs.frame (revision 15141)
@@ -29,4 +29,5 @@
[PluginFile("HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.dll", PluginFileType.Assembly)]
[PluginDependency("HeuristicLab.ALGLIB", "3.7.0")]
+ [PluginDependency("HeuristicLab.AutoDiff", "1.0")]
[PluginDependency("HeuristicLab.Analysis", "3.3")]
[PluginDependency("HeuristicLab.Collections", "3.3")]
Index: able/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs (revision 15140)
+++ (revision )
@@ -1,1343 +1,0 @@
-#region License Information
-
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see .
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-
-namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
- ///
- /// Simplifier for symbolic expressions
- ///
- public class SymbolicDataAnalysisExpressionTreeSimplifier {
- private Addition addSymbol = new Addition();
- private Multiplication mulSymbol = new Multiplication();
- private Division divSymbol = new Division();
- private Constant constSymbol = new Constant();
- private Variable varSymbol = new Variable();
- private Logarithm logSymbol = new Logarithm();
- private Exponential expSymbol = new Exponential();
- private Root rootSymbol = new Root();
- private Square sqrSymbol = new Square();
- private SquareRoot sqrtSymbol = new SquareRoot();
- private Power powSymbol = new Power();
- private Sine sineSymbol = new Sine();
- private Cosine cosineSymbol = new Cosine();
- private Tangent tanSymbol = new Tangent();
- private IfThenElse ifThenElseSymbol = new IfThenElse();
- private And andSymbol = new And();
- private Or orSymbol = new Or();
- private Not notSymbol = new Not();
- private GreaterThan gtSymbol = new GreaterThan();
- private LessThan ltSymbol = new LessThan();
- private Integral integralSymbol = new Integral();
- private LaggedVariable laggedVariableSymbol = new LaggedVariable();
- private TimeLag timeLagSymbol = new TimeLag();
-
- public ISymbolicExpressionTree Simplify(ISymbolicExpressionTree originalTree) {
- var clone = (ISymbolicExpressionTreeNode)originalTree.Root.Clone();
- // macro expand (initially no argument trees)
- var macroExpandedTree = MacroExpand(clone, clone.GetSubtree(0), new List());
- ISymbolicExpressionTreeNode rootNode = (new ProgramRootSymbol()).CreateTreeNode();
- rootNode.AddSubtree(GetSimplifiedTree(macroExpandedTree));
-
-#if DEBUG
- // check that each node is only referenced once
- var nodes = rootNode.IterateNodesPrefix().ToArray();
- foreach(var n in nodes) if(nodes.Count(ni => ni == n) > 1) throw new InvalidOperationException();
-#endif
- return new SymbolicExpressionTree(rootNode);
- }
-
- // the argumentTrees list contains already expanded trees used as arguments for invocations
- private ISymbolicExpressionTreeNode MacroExpand(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node,
- IList argumentTrees) {
- List subtrees = new List(node.Subtrees);
- while (node.SubtreeCount > 0) node.RemoveSubtree(0);
- if (node.Symbol is InvokeFunction) {
- var invokeSym = node.Symbol as InvokeFunction;
- var defunNode = FindFunctionDefinition(root, invokeSym.FunctionName);
- var macroExpandedArguments = new List();
- foreach (var subtree in subtrees) {
- macroExpandedArguments.Add(MacroExpand(root, subtree, argumentTrees));
- }
- return MacroExpand(root, defunNode, macroExpandedArguments);
- } else if (node.Symbol is Argument) {
- var argSym = node.Symbol as Argument;
- // return the correct argument sub-tree (already macro-expanded)
- return (SymbolicExpressionTreeNode)argumentTrees[argSym.ArgumentIndex].Clone();
- } else {
- // recursive application
- foreach (var subtree in subtrees) {
- node.AddSubtree(MacroExpand(root, subtree, argumentTrees));
- }
- return node;
- }
- }
-
- private ISymbolicExpressionTreeNode FindFunctionDefinition(ISymbolicExpressionTreeNode root, string functionName) {
- foreach (var subtree in root.Subtrees.OfType()) {
- if (subtree.FunctionName == functionName) return subtree.GetSubtree(0);
- }
-
- throw new ArgumentException("Definition of function " + functionName + " not found.");
- }
-
- #region symbol predicates
-
- // arithmetic
- private bool IsDivision(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Division;
- }
-
- private bool IsMultiplication(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Multiplication;
- }
-
- private bool IsSubtraction(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Subtraction;
- }
-
- private bool IsAddition(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Addition;
- }
-
- private bool IsAverage(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Average;
- }
-
- // exponential
- private bool IsLog(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Logarithm;
- }
-
- private bool IsExp(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Exponential;
- }
-
- private bool IsRoot(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Root;
- }
-
- private bool IsSquare(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Square;
- }
-
- private bool IsSquareRoot(ISymbolicExpressionTreeNode node) {
- return node.Symbol is SquareRoot;
- }
-
- private bool IsPower(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Power;
- }
-
- // trigonometric
- private bool IsSine(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Sine;
- }
-
- private bool IsCosine(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Cosine;
- }
-
- private bool IsTangent(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Tangent;
- }
-
- // boolean
- private bool IsIfThenElse(ISymbolicExpressionTreeNode node) {
- return node.Symbol is IfThenElse;
- }
-
- private bool IsAnd(ISymbolicExpressionTreeNode node) {
- return node.Symbol is And;
- }
-
- private bool IsOr(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Or;
- }
-
- private bool IsNot(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Not;
- }
-
- // comparison
- private bool IsGreaterThan(ISymbolicExpressionTreeNode node) {
- return node.Symbol is GreaterThan;
- }
-
- private bool IsLessThan(ISymbolicExpressionTreeNode node) {
- return node.Symbol is LessThan;
- }
-
- private bool IsBoolean(ISymbolicExpressionTreeNode node) {
- return
- node.Symbol is GreaterThan ||
- node.Symbol is LessThan ||
- node.Symbol is And ||
- node.Symbol is Or;
- }
-
- // terminals
- private bool IsVariable(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Variable;
- }
-
- private bool IsVariableBase(ISymbolicExpressionTreeNode node) {
- return node is VariableTreeNodeBase;
- }
-
- private bool IsFactor(ISymbolicExpressionTreeNode node) {
- return node is FactorVariableTreeNode;
- }
-
- private bool IsBinFactor(ISymbolicExpressionTreeNode node) {
- return node is BinaryFactorVariableTreeNode;
- }
-
- private bool IsConstant(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Constant;
- }
-
- // dynamic
- private bool IsTimeLag(ISymbolicExpressionTreeNode node) {
- return node.Symbol is TimeLag;
- }
-
- private bool IsIntegral(ISymbolicExpressionTreeNode node) {
- return node.Symbol is Integral;
- }
-
- #endregion
-
- ///
- /// Creates a new simplified tree
- ///
- ///
- ///
- public ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
- if (IsConstant(original) || IsVariableBase(original)) {
- return (ISymbolicExpressionTreeNode)original.Clone();
- } else if (IsAddition(original)) {
- return SimplifyAddition(original);
- } else if (IsSubtraction(original)) {
- return SimplifySubtraction(original);
- } else if (IsMultiplication(original)) {
- return SimplifyMultiplication(original);
- } else if (IsDivision(original)) {
- return SimplifyDivision(original);
- } else if (IsAverage(original)) {
- return SimplifyAverage(original);
- } else if (IsLog(original)) {
- return SimplifyLog(original);
- } else if (IsExp(original)) {
- return SimplifyExp(original);
- } else if (IsSquare(original)) {
- return SimplifySquare(original);
- } else if (IsSquareRoot(original)) {
- return SimplifySquareRoot(original);
- } else if (IsPower(original)) {
- return SimplifyPower(original);
- } else if (IsRoot(original)) {
- return SimplifyRoot(original);
- } else if (IsSine(original)) {
- return SimplifySine(original);
- } else if (IsCosine(original)) {
- return SimplifyCosine(original);
- } else if (IsTangent(original)) {
- return SimplifyTangent(original);
- } else if (IsIfThenElse(original)) {
- return SimplifyIfThenElse(original);
- } else if (IsGreaterThan(original)) {
- return SimplifyGreaterThan(original);
- } else if (IsLessThan(original)) {
- return SimplifyLessThan(original);
- } else if (IsAnd(original)) {
- return SimplifyAnd(original);
- } else if (IsOr(original)) {
- return SimplifyOr(original);
- } else if (IsNot(original)) {
- return SimplifyNot(original);
- } else if (IsTimeLag(original)) {
- return SimplifyTimeLag(original);
- } else if (IsIntegral(original)) {
- return SimplifyIntegral(original);
- } else {
- return SimplifyAny(original);
- }
- }
-
- #region specific simplification routines
-
- private ISymbolicExpressionTreeNode SimplifyAny(ISymbolicExpressionTreeNode original) {
- // can't simplify this function but simplify all subtrees
- List subtrees = new List(original.Subtrees);
- while (original.Subtrees.Count() > 0) original.RemoveSubtree(0);
- var clone = (SymbolicExpressionTreeNode)original.Clone();
- List simplifiedSubtrees = new List();
- foreach (var subtree in subtrees) {
- simplifiedSubtrees.Add(GetSimplifiedTree(subtree));
- original.AddSubtree(subtree);
- }
- foreach (var simplifiedSubtree in simplifiedSubtrees) {
- clone.AddSubtree(simplifiedSubtree);
- }
- if (simplifiedSubtrees.TrueForAll(t => IsConstant(t))) {
- SimplifyConstantExpression(clone);
- }
- return clone;
- }
-
- private ISymbolicExpressionTreeNode SimplifyConstantExpression(ISymbolicExpressionTreeNode original) {
- // not yet implemented
- return original;
- }
-
- private ISymbolicExpressionTreeNode SimplifyAverage(ISymbolicExpressionTreeNode original) {
- if (original.Subtrees.Count() == 1) {
- return GetSimplifiedTree(original.GetSubtree(0));
- } else {
- // simplify expressions x0..xn
- // make sum(x0..xn) / n
- var sum = original.Subtrees
- .Select(GetSimplifiedTree)
- .Aggregate(MakeSum);
- return MakeFraction(sum, MakeConstant(original.Subtrees.Count()));
- }
- }
-
- private ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
- if (original.Subtrees.Count() == 1) {
- return Invert(GetSimplifiedTree(original.GetSubtree(0)));
- } else {
- // simplify expressions x0..xn
- // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
- var first = original.GetSubtree(0);
- var second = original.GetSubtree(1);
- var remaining = original.Subtrees.Skip(2);
- return
- MakeProduct(GetSimplifiedTree(first),
- Invert(remaining.Aggregate(GetSimplifiedTree(second), (a, b) => MakeProduct(a, GetSimplifiedTree(b)))));
- }
- }
-
- private ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
- if (original.Subtrees.Count() == 1) {
- return GetSimplifiedTree(original.GetSubtree(0));
- } else {
- return original.Subtrees
- .Select(GetSimplifiedTree)
- .Aggregate(MakeProduct);
- }
- }
-
- private ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
- if (original.Subtrees.Count() == 1) {
- return Negate(GetSimplifiedTree(original.GetSubtree(0)));
- } else {
- // simplify expressions x0..xn
- // make addition (x0,-x1..-xn)
- var first = original.Subtrees.First();
- var remaining = original.Subtrees.Skip(1);
- return remaining.Aggregate(GetSimplifiedTree(first), (a, b) => MakeSum(a, Negate(GetSimplifiedTree(b))));
- }
- }
-
- private ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
- if (original.Subtrees.Count() == 1) {
- return GetSimplifiedTree(original.GetSubtree(0));
- } else {
- // simplify expression x0..xn
- // make addition (x0..xn)
- return original.Subtrees
- .Select(GetSimplifiedTree)
- .Aggregate(MakeSum);
- }
- }
-
- private ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
- return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
- return original.Subtrees
- .Select(GetSimplifiedTree)
- .Aggregate(MakeOr);
- }
-
- private ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
- return original.Subtrees
- .Select(GetSimplifiedTree)
- .Aggregate(MakeAnd);
- }
-
- private ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
- return MakeLessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
- return MakeGreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
- return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)),
- GetSimplifiedTree(original.GetSubtree(2)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
- return MakeTangent(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
- return MakeCosine(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
- return MakeSine(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
- return MakeExp(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifySquare(ISymbolicExpressionTreeNode original) {
- return MakeSquare(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifySquareRoot(ISymbolicExpressionTreeNode original) {
- return MakeSquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
- return MakeLog(GetSimplifiedTree(original.GetSubtree(0)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
- return MakeRoot(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
- return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
- }
-
- private ISymbolicExpressionTreeNode SimplifyTimeLag(ISymbolicExpressionTreeNode original) {
- var laggedTreeNode = original as ILaggedTreeNode;
- var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
- if (!ContainsVariableCondition(simplifiedSubtree)) {
- return AddLagToDynamicNodes(simplifiedSubtree, laggedTreeNode.Lag);
- } else {
- return MakeTimeLag(simplifiedSubtree, laggedTreeNode.Lag);
- }
- }
-
- private ISymbolicExpressionTreeNode SimplifyIntegral(ISymbolicExpressionTreeNode original) {
- var laggedTreeNode = original as ILaggedTreeNode;
- var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
- if (IsConstant(simplifiedSubtree)) {
- return GetSimplifiedTree(MakeProduct(simplifiedSubtree, MakeConstant(-laggedTreeNode.Lag)));
- } else {
- return MakeIntegral(simplifiedSubtree, laggedTreeNode.Lag);
- }
- }
-
- #endregion
-
- #region low level tree restructuring
-
- private ISymbolicExpressionTreeNode MakeTimeLag(ISymbolicExpressionTreeNode subtree, int lag) {
- if (lag == 0) return subtree;
- if (IsConstant(subtree)) return subtree;
- var lagNode = (LaggedTreeNode)timeLagSymbol.CreateTreeNode();
- lagNode.Lag = lag;
- lagNode.AddSubtree(subtree);
- return lagNode;
- }
-
- private ISymbolicExpressionTreeNode MakeIntegral(ISymbolicExpressionTreeNode subtree, int lag) {
- if (lag == 0) return subtree;
- else if (lag == -1 || lag == 1) {
- return MakeSum(subtree, AddLagToDynamicNodes((ISymbolicExpressionTreeNode)subtree.Clone(), lag));
- } else {
- var node = (LaggedTreeNode)integralSymbol.CreateTreeNode();
- node.Lag = lag;
- node.AddSubtree(subtree);
- return node;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeNot(ISymbolicExpressionTreeNode t) {
- if (IsConstant(t)) {
- var constNode = t as ConstantTreeNode;
- if (constNode.Value > 0) return MakeConstant(-1.0);
- else return MakeConstant(1.0);
- } else if (IsNot(t)) {
- return t.GetSubtree(0);
- } else if (!IsBoolean(t)) {
- var gtNode = gtSymbol.CreateTreeNode();
- gtNode.AddSubtree(t);
- gtNode.AddSubtree(MakeConstant(0.0));
- var notNode = notSymbol.CreateTreeNode();
- notNode.AddSubtree(gtNode);
- return notNode;
- } else {
- var notNode = notSymbol.CreateTreeNode();
- notNode.AddSubtree(t);
- return notNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeOr(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- if (IsConstant(a) && IsConstant(b)) {
- var constA = a as ConstantTreeNode;
- var constB = b as ConstantTreeNode;
- if (constA.Value > 0.0 || constB.Value > 0.0) {
- return MakeConstant(1.0);
- } else {
- return MakeConstant(-1.0);
- }
- } else if (IsConstant(a)) {
- return MakeOr(b, a);
- } else if (IsConstant(b)) {
- var constT = b as ConstantTreeNode;
- if (constT.Value > 0.0) {
- // boolean expression is necessarily true
- return MakeConstant(1.0);
- } else {
- // the constant value has no effect on the result of the boolean condition so we can drop the constant term
- var orNode = orSymbol.CreateTreeNode();
- orNode.AddSubtree(a);
- return orNode;
- }
- } else {
- var orNode = orSymbol.CreateTreeNode();
- orNode.AddSubtree(a);
- orNode.AddSubtree(b);
- return orNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- if (IsConstant(a) && IsConstant(b)) {
- var constA = a as ConstantTreeNode;
- var constB = b as ConstantTreeNode;
- if (constA.Value > 0.0 && constB.Value > 0.0) {
- return MakeConstant(1.0);
- } else {
- return MakeConstant(-1.0);
- }
- } else if (IsConstant(a)) {
- return MakeAnd(b, a);
- } else if (IsConstant(b)) {
- var constB = b as ConstantTreeNode;
- if (constB.Value > 0.0) {
- // the constant value has no effect on the result of the boolean condition so we can drop the constant term
- var andNode = andSymbol.CreateTreeNode();
- andNode.AddSubtree(a);
- return andNode;
- } else {
- // boolean expression is necessarily false
- return MakeConstant(-1.0);
- }
- } else {
- var andNode = andSymbol.CreateTreeNode();
- andNode.AddSubtree(a);
- andNode.AddSubtree(b);
- return andNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide,
- ISymbolicExpressionTreeNode rightSide) {
- if (IsConstant(leftSide) && IsConstant(rightSide)) {
- var lsConst = leftSide as ConstantTreeNode;
- var rsConst = rightSide as ConstantTreeNode;
- if (lsConst.Value < rsConst.Value) return MakeConstant(1.0);
- else return MakeConstant(-1.0);
- } else {
- var ltNode = ltSymbol.CreateTreeNode();
- ltNode.AddSubtree(leftSide);
- ltNode.AddSubtree(rightSide);
- return ltNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide,
- ISymbolicExpressionTreeNode rightSide) {
- if (IsConstant(leftSide) && IsConstant(rightSide)) {
- var lsConst = leftSide as ConstantTreeNode;
- var rsConst = rightSide as ConstantTreeNode;
- if (lsConst.Value > rsConst.Value) return MakeConstant(1.0);
- else return MakeConstant(-1.0);
- } else {
- var gtNode = gtSymbol.CreateTreeNode();
- gtNode.AddSubtree(leftSide);
- gtNode.AddSubtree(rightSide);
- return gtNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition,
- ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
- if (IsConstant(condition)) {
- var constT = condition as ConstantTreeNode;
- if (constT.Value > 0.0) return trueBranch;
- else return falseBranch;
- } else {
- var ifNode = ifThenElseSymbol.CreateTreeNode();
- if (IsBoolean(condition)) {
- ifNode.AddSubtree(condition);
- } else {
- var gtNode = gtSymbol.CreateTreeNode();
- gtNode.AddSubtree(condition);
- gtNode.AddSubtree(MakeConstant(0.0));
- ifNode.AddSubtree(gtNode);
- }
- ifNode.AddSubtree(trueBranch);
- ifNode.AddSubtree(falseBranch);
- return ifNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeSine(ISymbolicExpressionTreeNode node) {
- if (IsConstant(node)) {
- var constT = node as ConstantTreeNode;
- return MakeConstant(Math.Sin(constT.Value));
- } else if (IsFactor(node)) {
- var factor = node as FactorVariableTreeNode;
- return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Sin));
- } else if (IsBinFactor(node)) {
- var binFactor = node as BinaryFactorVariableTreeNode;
- return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sin(binFactor.Weight));
- } else {
- var sineNode = sineSymbol.CreateTreeNode();
- sineNode.AddSubtree(node);
- return sineNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
- if (IsConstant(node)) {
- var constT = node as ConstantTreeNode;
- return MakeConstant(Math.Tan(constT.Value));
- } else if (IsFactor(node)) {
- var factor = node as FactorVariableTreeNode;
- return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Tan));
- } else if (IsBinFactor(node)) {
- var binFactor = node as BinaryFactorVariableTreeNode;
- return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Tan(binFactor.Weight));
- } else {
- var tanNode = tanSymbol.CreateTreeNode();
- tanNode.AddSubtree(node);
- return tanNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
- if (IsConstant(node)) {
- var constT = node as ConstantTreeNode;
- return MakeConstant(Math.Cos(constT.Value));
- } else if (IsFactor(node)) {
- var factor = node as FactorVariableTreeNode;
- return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Cos));
- } else if (IsBinFactor(node)) {
- var binFactor = node as BinaryFactorVariableTreeNode;
- // cos(0) = 1 see similar case for Exp(binfactor)
- return MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Cos(binFactor.Weight) - 1),
- MakeConstant(1.0));
- } else {
- var cosNode = cosineSymbol.CreateTreeNode();
- cosNode.AddSubtree(node);
- return cosNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
- if (IsConstant(node)) {
- var constT = node as ConstantTreeNode;
- return MakeConstant(Math.Exp(constT.Value));
- } else if (IsFactor(node)) {
- var factNode = node as FactorVariableTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Exp(w)));
- } else if (IsBinFactor(node)) {
- // exp( binfactor w val=a) = if(val=a) exp(w) else exp(0) = binfactor( (exp(w) - 1) val a) + 1
- var binFactor = node as BinaryFactorVariableTreeNode;
- return
- MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Exp(binFactor.Weight) - 1), MakeConstant(1.0));
- } else if (IsLog(node)) {
- return node.GetSubtree(0);
- } else if (IsAddition(node)) {
- return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, t));
- } else if (IsSubtraction(node)) {
- return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, Negate(t)));
- } else {
- var expNode = expSymbol.CreateTreeNode();
- expNode.AddSubtree(node);
- return expNode;
- }
- }
- private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
- if (IsConstant(node)) {
- var constT = node as ConstantTreeNode;
- return MakeConstant(Math.Log(constT.Value));
- } else if (IsFactor(node)) {
- var factNode = node as FactorVariableTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Log(w)));
- } else if (IsExp(node)) {
- return node.GetSubtree(0);
- } else if (IsSquareRoot(node)) {
- return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
- } else {
- var logNode = logSymbol.CreateTreeNode();
- logNode.AddSubtree(node);
- return logNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeSquare(ISymbolicExpressionTreeNode node) {
- if (IsConstant(node)) {
- var constT = node as ConstantTreeNode;
- return MakeConstant(constT.Value * constT.Value);
- } else if (IsFactor(node)) {
- var factNode = node as FactorVariableTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w));
- } else if (IsBinFactor(node)) {
- var binFactor = node as BinaryFactorVariableTreeNode;
- return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight);
- } else if (IsSquareRoot(node)) {
- return node.GetSubtree(0);
- } else {
- var sqrNode = sqrSymbol.CreateTreeNode();
- sqrNode.AddSubtree(node);
- return sqrNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeSquareRoot(ISymbolicExpressionTreeNode node) {
- if (IsConstant(node)) {
- var constT = node as ConstantTreeNode;
- return MakeConstant(Math.Sqrt(constT.Value));
- } else if (IsFactor(node)) {
- var factNode = node as FactorVariableTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(w)));
- } else if (IsBinFactor(node)) {
- var binFactor = node as BinaryFactorVariableTreeNode;
- return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(binFactor.Weight));
- } else if (IsSquare(node)) {
- return node.GetSubtree(0);
- } else {
- var sqrtNode = sqrtSymbol.CreateTreeNode();
- sqrtNode.AddSubtree(node);
- return sqrtNode;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- if (IsConstant(a) && IsConstant(b)) {
- var constA = a as ConstantTreeNode;
- var constB = b as ConstantTreeNode;
- return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
- } else if (IsFactor(a) && IsConstant(b)) {
- var factNode = a as FactorVariableTreeNode;
- var constNode = b as ConstantTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName,
- factNode.Weights.Select(w => Math.Pow(w, 1.0 / Math.Round(constNode.Value))));
- } else if (IsBinFactor(a) && IsConstant(b)) {
- var binFactor = a as BinaryFactorVariableTreeNode;
- var constNode = b as ConstantTreeNode;
- return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, 1.0 / Math.Round(constNode.Value)));
- } else if (IsConstant(a) && IsFactor(b)) {
- var constNode = a as ConstantTreeNode;
- var factNode = b as FactorVariableTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, 1.0 / Math.Round(w))));
- } else if (IsConstant(a) && IsBinFactor(b)) {
- var constNode = a as ConstantTreeNode;
- var factNode = b as BinaryFactorVariableTreeNode;
- return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, 1.0 / Math.Round(factNode.Weight)));
- } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as FactorVariableTreeNode;
- return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, 1.0 / Math.Round(v))));
- } else if (IsConstant(b)) {
- var constB = b as ConstantTreeNode;
- var constBValue = Math.Round(constB.Value);
- if (constBValue.IsAlmost(1.0)) {
- return a;
- } else if (constBValue.IsAlmost(0.0)) {
- return MakeConstant(1.0);
- } else if (constBValue.IsAlmost(-1.0)) {
- return MakeFraction(MakeConstant(1.0), a);
- } else if (constBValue < 0) {
- var rootNode = rootSymbol.CreateTreeNode();
- rootNode.AddSubtree(a);
- rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
- return MakeFraction(MakeConstant(1.0), rootNode);
- } else {
- var rootNode = rootSymbol.CreateTreeNode();
- rootNode.AddSubtree(a);
- rootNode.AddSubtree(MakeConstant(constBValue));
- return rootNode;
- }
- } else {
- var rootNode = rootSymbol.CreateTreeNode();
- rootNode.AddSubtree(a);
- rootNode.AddSubtree(b);
- return rootNode;
- }
- }
-
-
- private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- if (IsConstant(a) && IsConstant(b)) {
- var constA = a as ConstantTreeNode;
- var constB = b as ConstantTreeNode;
- return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
- } else if (IsFactor(a) && IsConstant(b)) {
- var factNode = a as FactorVariableTreeNode;
- var constNode = b as ConstantTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, Math.Round(constNode.Value))));
- } else if (IsBinFactor(a) && IsConstant(b)) {
- var binFactor = a as BinaryFactorVariableTreeNode;
- var constNode = b as ConstantTreeNode;
- return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, Math.Round(constNode.Value)));
- } else if (IsConstant(a) && IsFactor(b)) {
- var constNode = a as ConstantTreeNode;
- var factNode = b as FactorVariableTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, Math.Round(w))));
- } else if (IsConstant(a) && IsBinFactor(b)) {
- var constNode = a as ConstantTreeNode;
- var factNode = b as BinaryFactorVariableTreeNode;
- return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, Math.Round(factNode.Weight)));
- } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as FactorVariableTreeNode;
- return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, Math.Round(v))));
- } else if (IsConstant(b)) {
- var constB = b as ConstantTreeNode;
- double exponent = Math.Round(constB.Value);
- if (exponent.IsAlmost(0.0)) {
- return MakeConstant(1.0);
- } else if (exponent.IsAlmost(1.0)) {
- return a;
- } else if (exponent.IsAlmost(-1.0)) {
- return MakeFraction(MakeConstant(1.0), a);
- } else if (exponent < 0) {
- var powNode = powSymbol.CreateTreeNode();
- powNode.AddSubtree(a);
- powNode.AddSubtree(MakeConstant(-1.0 * exponent));
- return MakeFraction(MakeConstant(1.0), powNode);
- } else {
- var powNode = powSymbol.CreateTreeNode();
- powNode.AddSubtree(a);
- powNode.AddSubtree(MakeConstant(exponent));
- return powNode;
- }
- } else {
- var powNode = powSymbol.CreateTreeNode();
- powNode.AddSubtree(a);
- powNode.AddSubtree(b);
- return powNode;
- }
- }
-
-
- // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
- private ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- if (IsConstant(a) && IsConstant(b)) {
- // fold constants
- return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
- } else if ((IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0))) {
- return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
- } else if (IsVariableBase(a) && IsConstant(b)) {
- // merge constant values into variable weights
- var constB = ((ConstantTreeNode)b).Value;
- ((VariableTreeNodeBase)a).Weight /= constB;
- return a;
- } else if (IsFactor(a) && IsConstant(b)) {
- var factNode = a as FactorVariableTreeNode;
- var constNode = b as ConstantTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w / constNode.Value));
- } else if (IsBinFactor(a) && IsConstant(b)) {
- var factNode = a as BinaryFactorVariableTreeNode;
- var constNode = b as ConstantTreeNode;
- return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, factNode.Weight / constNode.Value);
- } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as FactorVariableTreeNode;
- return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u / v));
- } else if (IsFactor(a) && IsBinFactor(b) && ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as BinaryFactorVariableTreeNode;
- var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
- var wi = Array.IndexOf(varValues, node1.VariableValue);
- if (wi < 0) throw new ArgumentException();
- var newWeighs = new double[varValues.Length];
- node0.Weights.CopyTo(newWeighs, 0);
- for (int i = 0; i < newWeighs.Length; i++)
- if (wi == i) newWeighs[i] /= node1.Weight;
- else newWeighs[i] /= 0.0;
- return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
- } else if (IsFactor(a)) {
- return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
- } else if (IsVariableBase(a) && IsVariableBase(b) && AreSameTypeAndVariable(a, b) && !IsBinFactor(b)) {
- // cancel variables (not allowed for bin factors because of division by zero)
- var aVar = a as VariableTreeNode;
- var bVar = b as VariableTreeNode;
- return MakeConstant(aVar.Weight / bVar.Weight);
- } else if (IsAddition(a) && IsConstant(b)) {
- return a.Subtrees
- .Select(x => GetSimplifiedTree(x))
- .Select(x => MakeFraction(x, GetSimplifiedTree(b)))
- .Aggregate((c, d) => MakeSum(c, d));
- } else if (IsMultiplication(a) && IsConstant(b)) {
- return MakeProduct(a, Invert(b));
- } else if (IsDivision(a) && IsConstant(b)) {
- // (a1 / a2) / c => (a1 / (a2 * c))
- return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
- } else if (IsDivision(a) && IsDivision(b)) {
- // (a1 / a2) / (b1 / b2) =>
- return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
- } else if (IsDivision(a)) {
- // (a1 / a2) / b => (a1 / (a2 * b))
- return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
- } else if (IsDivision(b)) {
- // a / (b1 / b2) => (a * b2) / b1
- return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
- } else {
- var div = divSymbol.CreateTreeNode();
- div.AddSubtree(a);
- div.AddSubtree(b);
- return div;
- }
- }
-
- private ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- if (IsConstant(a) && IsConstant(b)) {
- // fold constants
- ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
- return a;
- } else if (IsConstant(a)) {
- // c + x => x + c
- // b is not constant => make sure constant is on the right
- return MakeSum(b, a);
- } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
- // x + 0 => x
- return a;
- } else if (IsFactor(a) && IsConstant(b)) {
- var factNode = a as FactorVariableTreeNode;
- var constNode = b as ConstantTreeNode;
- return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select((w) => w + constNode.Value));
- } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as FactorVariableTreeNode;
- return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u + v));
- } else if (IsBinFactor(a) && IsFactor(b)) {
- return MakeSum(b, a);
- } else if (IsFactor(a) && IsBinFactor(b) &&
- ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as BinaryFactorVariableTreeNode;
- var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
- var wi = Array.IndexOf(varValues, node1.VariableValue);
- if (wi < 0) throw new ArgumentException();
- var newWeighs = new double[varValues.Length];
- node0.Weights.CopyTo(newWeighs, 0);
- newWeighs[wi] += node1.Weight;
- return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
- } else if (IsAddition(a) && IsAddition(b)) {
- // merge additions
- var add = addSymbol.CreateTreeNode();
- // add all sub trees except for the last
- for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
- for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
- if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
- add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
- } else if (IsConstant(a.Subtrees.Last())) {
- add.AddSubtree(b.Subtrees.Last());
- add.AddSubtree(a.Subtrees.Last());
- } else {
- add.AddSubtree(a.Subtrees.Last());
- add.AddSubtree(b.Subtrees.Last());
- }
- MergeVariablesInSum(add);
- if (add.Subtrees.Count() == 1) {
- return add.GetSubtree(0);
- } else {
- return add;
- }
- } else if (IsAddition(b)) {
- return MakeSum(b, a);
- } else if (IsAddition(a) && IsConstant(b)) {
- // a is an addition and b is a constant => append b to a and make sure the constants are merged
- var add = addSymbol.CreateTreeNode();
- // add all sub trees except for the last
- for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
- if (IsConstant(a.Subtrees.Last()))
- add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
- else {
- add.AddSubtree(a.Subtrees.Last());
- add.AddSubtree(b);
- }
- return add;
- } else if (IsAddition(a)) {
- // a is already an addition => append b
- var add = addSymbol.CreateTreeNode();
- add.AddSubtree(b);
- foreach (var subtree in a.Subtrees) {
- add.AddSubtree(subtree);
- }
- MergeVariablesInSum(add);
- if (add.Subtrees.Count() == 1) {
- return add.GetSubtree(0);
- } else {
- return add;
- }
- } else {
- var add = addSymbol.CreateTreeNode();
- add.AddSubtree(a);
- add.AddSubtree(b);
- MergeVariablesInSum(add);
- if (add.Subtrees.Count() == 1) {
- return add.GetSubtree(0);
- } else {
- return add;
- }
- }
- }
-
- // makes sure variable symbols in sums are combined
- private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
- var subtrees = new List(sum.Subtrees);
- while (sum.Subtrees.Any()) sum.RemoveSubtree(0);
- var groupedVarNodes = from node in subtrees.OfType()
- where node.SubtreeCount == 0
- group node by GroupId(node) into g
- select g;
- var constant = (from node in subtrees.OfType()
- select node.Value).DefaultIfEmpty(0.0).Sum();
- var unchangedSubtrees = subtrees.Where(t => t.SubtreeCount > 0 || !(t is IVariableTreeNode) && !(t is ConstantTreeNode));
-
- foreach (var variableNodeGroup in groupedVarNodes) {
- var firstNode = variableNodeGroup.First();
- if (firstNode is VariableTreeNodeBase) {
- var representative = firstNode as VariableTreeNodeBase;
- var weightSum = variableNodeGroup.Cast().Select(t => t.Weight).Sum();
- representative.Weight = weightSum;
- sum.AddSubtree(representative);
- } else if (firstNode is FactorVariableTreeNode) {
- var representative = firstNode as FactorVariableTreeNode;
- foreach (var node in variableNodeGroup.Skip(1).Cast()) {
- for (int j = 0; j < representative.Weights.Length; j++) {
- representative.Weights[j] += node.Weights[j];
- }
- }
- for (int j = 0; j < representative.Weights.Length; j++) {
- representative.Weights[j] += constant;
- }
- sum.AddSubtree(representative);
- }
- }
- foreach (var unchangedSubtree in unchangedSubtrees)
- sum.AddSubtree(unchangedSubtree);
- if (!constant.IsAlmost(0.0)) {
- sum.AddSubtree(MakeConstant(constant));
- }
- }
-
- // nodes referencing variables can be grouped if they have
- private string GroupId(IVariableTreeNode node) {
- var binaryFactorNode = node as BinaryFactorVariableTreeNode;
- var factorNode = node as FactorVariableTreeNode;
- var variableNode = node as VariableTreeNode;
- var laggedVarNode = node as LaggedVariableTreeNode;
- if (variableNode != null) {
- return "var " + variableNode.VariableName;
- } else if (binaryFactorNode != null) {
- return "binfactor " + binaryFactorNode.VariableName + " " + binaryFactorNode.VariableValue;
- } else if (factorNode != null) {
- return "factor " + factorNode.VariableName;
- } else if (laggedVarNode != null) {
- return "lagged " + laggedVarNode.VariableName + " " + laggedVarNode.Lag;
- } else {
- throw new NotSupportedException();
- }
- }
-
-
- private ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- if (IsConstant(a) && IsConstant(b)) {
- // fold constants
- return MakeConstant(((ConstantTreeNode)a).Value * ((ConstantTreeNode)b).Value);
- } else if (IsConstant(a)) {
- // a * $ => $ * a
- return MakeProduct(b, a);
- } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as FactorVariableTreeNode;
- return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u * v));
- } else if (IsBinFactor(a) && IsBinFactor(b) && AreSameTypeAndVariable(a, b)) {
- var node0 = a as BinaryFactorVariableTreeNode;
- var node1 = b as BinaryFactorVariableTreeNode;
- return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Weight);
- } else if (IsFactor(a) && IsConstant(b)) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as ConstantTreeNode;
- return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Select(w => w * node1.Value));
- } else if (IsBinFactor(a) && IsConstant(b)) {
- var node0 = a as BinaryFactorVariableTreeNode;
- var node1 = b as ConstantTreeNode;
- return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Value);
- } else if (IsBinFactor(a) && IsFactor(b)) {
- return MakeProduct(b, a);
- } else if (IsFactor(a) && IsBinFactor(b) &&
- ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
- var node0 = a as FactorVariableTreeNode;
- var node1 = b as BinaryFactorVariableTreeNode;
- var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
- var wi = Array.IndexOf(varValues, node1.VariableValue);
- if (wi < 0) throw new ArgumentException();
- return MakeBinFactor(node1.Symbol, node1.VariableName, node1.VariableValue, node1.Weight * node0.Weights[wi]);
- } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
- // $ * 1.0 => $
- return a;
- } else if (IsConstant(b) && IsVariableBase(a)) {
- // multiply constants into variables weights
- ((VariableTreeNodeBase)a).Weight *= ((ConstantTreeNode)b).Value;
- return a;
- } else if (IsConstant(b) && IsAddition(a) ||
- IsFactor(b) && IsAddition(a) ||
- IsBinFactor(b) && IsAddition(a)) {
- // multiply constants into additions
- return a.Subtrees.Select(x => MakeProduct(GetSimplifiedTree(x), GetSimplifiedTree(b))).Aggregate((c, d) => MakeSum(c, d));
- } else if (IsDivision(a) && IsDivision(b)) {
- // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
- return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
- } else if (IsDivision(a)) {
- // (a1 / a2) * b => (a1 * b) / a2
- return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
- } else if (IsDivision(b)) {
- // a * (b1 / b2) => (b1 * a) / b2
- return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
- } else if (IsMultiplication(a) && IsMultiplication(b)) {
- // merge multiplications (make sure constants are merged)
- var mul = mulSymbol.CreateTreeNode();
- for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
- for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
- MergeVariablesAndConstantsInProduct(mul);
- return mul;
- } else if (IsMultiplication(b)) {
- return MakeProduct(b, a);
- } else if (IsMultiplication(a)) {
- // a is already an multiplication => append b
- a.AddSubtree(GetSimplifiedTree(b));
- MergeVariablesAndConstantsInProduct(a);
- return a;
- } else {
- var mul = mulSymbol.CreateTreeNode();
- mul.AddSubtree(a);
- mul.AddSubtree(b);
- MergeVariablesAndConstantsInProduct(mul);
- return mul;
- }
- }
-
- #endregion
-
- #region helper functions
-
- private bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
- if (node.Symbol is VariableCondition) return true;
- foreach (var subtree in node.Subtrees)
- if (ContainsVariableCondition(subtree)) return true;
- return false;
- }
-
- private ISymbolicExpressionTreeNode AddLagToDynamicNodes(ISymbolicExpressionTreeNode node, int lag) {
- var laggedTreeNode = node as ILaggedTreeNode;
- var variableNode = node as VariableTreeNode;
- var variableConditionNode = node as VariableConditionTreeNode;
- if (laggedTreeNode != null)
- laggedTreeNode.Lag += lag;
- else if (variableNode != null) {
- var laggedVariableNode = (LaggedVariableTreeNode)laggedVariableSymbol.CreateTreeNode();
- laggedVariableNode.Lag = lag;
- laggedVariableNode.VariableName = variableNode.VariableName;
- return laggedVariableNode;
- } else if (variableConditionNode != null) {
- throw new NotSupportedException("Removal of time lags around variable condition symbols is not allowed.");
- }
- var subtrees = new List(node.Subtrees);
- while (node.SubtreeCount > 0) node.RemoveSubtree(0);
- foreach (var subtree in subtrees) {
- node.AddSubtree(AddLagToDynamicNodes(subtree, lag));
- }
- return node;
- }
-
- private bool AreSameTypeAndVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
- return GroupId((IVariableTreeNode)a) == GroupId((IVariableTreeNode)b);
- }
-
- // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
- private void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
- var subtrees = new List(prod.Subtrees);
- while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
- var groupedVarNodes = from node in subtrees.OfType()
- where node.SubtreeCount == 0
- group node by GroupId(node) into g
- orderby g.Count()
- select g;
- var constantProduct = (from node in subtrees.OfType()
- select node.Weight)
- .Concat(from node in subtrees.OfType()
- select node.Value)
- .DefaultIfEmpty(1.0)
- .Aggregate((c1, c2) => c1 * c2);
-
- var unchangedSubtrees = from tree in subtrees
- where tree.SubtreeCount > 0 || !(tree is IVariableTreeNode) && !(tree is ConstantTreeNode)
- select tree;
-
- foreach (var variableNodeGroup in groupedVarNodes) {
- var firstNode = variableNodeGroup.First();
- if (firstNode is VariableTreeNodeBase) {
- var representative = (VariableTreeNodeBase)firstNode;
- representative.Weight = 1.0;
- if (variableNodeGroup.Count() > 1) {
- var poly = mulSymbol.CreateTreeNode();
- for (int p = 0; p < variableNodeGroup.Count(); p++) {
- poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
- }
- prod.AddSubtree(poly);
- } else {
- prod.AddSubtree(representative);
- }
- } else if (firstNode is FactorVariableTreeNode) {
- var representative = (FactorVariableTreeNode)firstNode;
- foreach (var node in variableNodeGroup.Skip(1).Cast()) {
- for (int j = 0; j < representative.Weights.Length; j++) {
- representative.Weights[j] *= node.Weights[j];
- }
- }
- for (int j = 0; j < representative.Weights.Length; j++) {
- representative.Weights[j] *= constantProduct;
- }
- constantProduct = 1.0;
- // if the product already contains a factor it is not necessary to multiply a constant below
- prod.AddSubtree(representative);
- }
- }
-
- foreach (var unchangedSubtree in unchangedSubtrees)
- prod.AddSubtree(unchangedSubtree);
-
- if (!constantProduct.IsAlmost(1.0)) {
- prod.AddSubtree(MakeConstant(constantProduct));
- }
- }
-
-
- ///
- /// x => x * -1
- /// Is only used in cases where it is not necessary to create new tree nodes. Manipulates x directly.
- ///
- ///
- /// -x
- private ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
- if (IsConstant(x)) {
- ((ConstantTreeNode)x).Value *= -1;
- } else if (IsVariableBase(x)) {
- var variableTree = (VariableTreeNodeBase)x;
- variableTree.Weight *= -1.0;
- } else if (IsFactor(x)) {
- var factorNode = (FactorVariableTreeNode)x;
- for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
- } else if (IsBinFactor(x)) {
- var factorNode = (BinaryFactorVariableTreeNode)x;
- factorNode.Weight *= -1;
- } else if (IsAddition(x)) {
- // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)
- var subtrees = new List(x.Subtrees);
- while (x.Subtrees.Any()) x.RemoveSubtree(0);
- foreach (var subtree in subtrees) {
- x.AddSubtree(Negate(subtree));
- }
- } else if (IsMultiplication(x) || IsDivision(x)) {
- // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
- var lastSubTree = x.Subtrees.Last();
- x.RemoveSubtree(x.SubtreeCount - 1);
- x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
- } else {
- // any other function
- return MakeProduct(x, MakeConstant(-1));
- }
- return x;
- }
-
- ///
- /// x => 1/x
- /// Must create new tree nodes
- ///
- ///
- ///
- private ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
- if (IsConstant(x)) {
- return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
- } else if (IsFactor(x)) {
- var factorNode = (FactorVariableTreeNode)x;
- return MakeFactor(factorNode.Symbol, factorNode.VariableName, factorNode.Weights.Select(w => 1.0 / w));
- } else if (IsDivision(x)) {
- return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
- } else {
- // any other function
- return MakeFraction(MakeConstant(1), x);
- }
- }
-
- private ISymbolicExpressionTreeNode MakeConstant(double value) {
- ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
- constantTreeNode.Value = value;
- return constantTreeNode;
- }
-
- private ISymbolicExpressionTreeNode MakeFactor(FactorVariable sy, string variableName, IEnumerable weights) {
- var tree = (FactorVariableTreeNode)sy.CreateTreeNode();
- tree.VariableName = variableName;
- tree.Weights = weights.ToArray();
- return tree;
- }
- private ISymbolicExpressionTreeNode MakeBinFactor(BinaryFactorVariable sy, string variableName, string variableValue, double weight) {
- var tree = (BinaryFactorVariableTreeNode)sy.CreateTreeNode();
- tree.VariableName = variableName;
- tree.VariableValue = variableValue;
- tree.Weight = weight;
- return tree;
- }
-
-
- #endregion
- }
-}
Index: able/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicExpressionTreeBacktransformator.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicExpressionTreeBacktransformator.cs (revision 15140)
+++ (revision )
@@ -1,97 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see .
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-
-namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
- public class SymbolicExpressionTreeBacktransformator : IModelBacktransformator {
- private readonly ITransformationMapper transformationMapper;
-
- public SymbolicExpressionTreeBacktransformator(ITransformationMapper transformationMapper) {
- this.transformationMapper = transformationMapper;
- }
-
- public ISymbolicDataAnalysisModel Backtransform(ISymbolicDataAnalysisModel model, IEnumerable transformations, string targetVariable) {
- var symbolicModel = (ISymbolicDataAnalysisModel)model.Clone();
-
- foreach (var transformation in transformations.Reverse()) {
- ApplyBacktransformation(transformation, symbolicModel.SymbolicExpressionTree, targetVariable);
- }
-
- return symbolicModel;
- }
-
- private void ApplyBacktransformation(ITransformation transformation, ISymbolicExpressionTree symbolicExpressionTree, string targetVariable) {
- if (transformation.Column != targetVariable) {
- var variableNodes = symbolicExpressionTree.IterateNodesBreadth()
- .OfType()
- .Where(n => n.VariableName == transformation.Column);
- ApplyRegularBacktransformation(transformation, variableNodes);
- } else if (!(transformation is CopyColumnTransformation)) {
- ApplyInverseBacktransformation(transformation, symbolicExpressionTree);
- }
- }
-
- private void ApplyRegularBacktransformation(ITransformation transformation, IEnumerable variableNodes) {
- foreach (var variableNode in variableNodes) {
- // generate new subtrees because same subtree cannot be added more than once
- var transformationTree = transformationMapper.GenerateModel(transformation);
- SwapVariableWithTree(variableNode, transformationTree);
- }
- }
-
- private void ApplyInverseBacktransformation(ITransformation transformation, ISymbolicExpressionTree symbolicExpressionTree) {
- var startSymbol = symbolicExpressionTree.Root.GetSubtree(0);
- var modelTree = startSymbol.GetSubtree(0);
- startSymbol.RemoveSubtree(0);
-
- var transformationTree = transformationMapper.GenerateInverseModel(transformation);
- var variableNode = transformationTree.IterateNodesBreadth()
- .OfType()
- .Single(n => n.VariableName == transformation.Column);
-
- SwapVariableWithTree(variableNode, modelTree);
-
- startSymbol.AddSubtree(transformationTree);
- }
-
- private void SwapVariableWithTree(VariableTreeNode variableNode, ISymbolicExpressionTreeNode treeNode) {
- var parent = variableNode.Parent;
- int index = parent.IndexOfSubtree(variableNode);
- parent.RemoveSubtree(index);
-
- if (!variableNode.Weight.IsAlmost(1.0))
- treeNode = CreateNodeFromWeight(treeNode, variableNode);
-
- parent.InsertSubtree(index, treeNode);
- }
-
- private ISymbolicExpressionTreeNode CreateNodeFromWeight(ISymbolicExpressionTreeNode transformationTree, VariableTreeNode variableNode) {
- var multiplicationNode = new SymbolicExpressionTreeNode(new Multiplication());
- multiplicationNode.AddSubtree(new ConstantTreeNode(new Constant()) { Value = variableNode.Weight });
- multiplicationNode.AddSubtree(transformationTree);
- return multiplicationNode;
- }
- }
-}
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/SymbolicDataAnalysisExpressionTreeSimplifier.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/SymbolicDataAnalysisExpressionTreeSimplifier.cs (revision 15141)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/SymbolicDataAnalysisExpressionTreeSimplifier.cs (revision 15141)
@@ -0,0 +1,1341 @@
+#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+ ///
+ /// Simplifier for symbolic expressions
+ ///
+ public class SymbolicDataAnalysisExpressionTreeSimplifier {
+ private Addition addSymbol = new Addition();
+ private Multiplication mulSymbol = new Multiplication();
+ private Division divSymbol = new Division();
+ private Constant constSymbol = new Constant();
+ private Variable varSymbol = new Variable();
+ private Logarithm logSymbol = new Logarithm();
+ private Exponential expSymbol = new Exponential();
+ private Root rootSymbol = new Root();
+ private Square sqrSymbol = new Square();
+ private SquareRoot sqrtSymbol = new SquareRoot();
+ private Power powSymbol = new Power();
+ private Sine sineSymbol = new Sine();
+ private Cosine cosineSymbol = new Cosine();
+ private Tangent tanSymbol = new Tangent();
+ private IfThenElse ifThenElseSymbol = new IfThenElse();
+ private And andSymbol = new And();
+ private Or orSymbol = new Or();
+ private Not notSymbol = new Not();
+ private GreaterThan gtSymbol = new GreaterThan();
+ private LessThan ltSymbol = new LessThan();
+ private Integral integralSymbol = new Integral();
+ private LaggedVariable laggedVariableSymbol = new LaggedVariable();
+ private TimeLag timeLagSymbol = new TimeLag();
+
+ public ISymbolicExpressionTree Simplify(ISymbolicExpressionTree originalTree) {
+ var clone = (ISymbolicExpressionTreeNode)originalTree.Root.Clone();
+ // macro expand (initially no argument trees)
+ var macroExpandedTree = MacroExpand(clone, clone.GetSubtree(0), new List());
+ ISymbolicExpressionTreeNode rootNode = (new ProgramRootSymbol()).CreateTreeNode();
+ rootNode.AddSubtree(GetSimplifiedTree(macroExpandedTree));
+
+#if DEBUG
+ // check that each node is only referenced once
+ var nodes = rootNode.IterateNodesPrefix().ToArray();
+ foreach(var n in nodes) if(nodes.Count(ni => ni == n) > 1) throw new InvalidOperationException();
+#endif
+ return new SymbolicExpressionTree(rootNode);
+ }
+
+ // the argumentTrees list contains already expanded trees used as arguments for invocations
+ private ISymbolicExpressionTreeNode MacroExpand(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node,
+ IList argumentTrees) {
+ List subtrees = new List(node.Subtrees);
+ while (node.SubtreeCount > 0) node.RemoveSubtree(0);
+ if (node.Symbol is InvokeFunction) {
+ var invokeSym = node.Symbol as InvokeFunction;
+ var defunNode = FindFunctionDefinition(root, invokeSym.FunctionName);
+ var macroExpandedArguments = new List();
+ foreach (var subtree in subtrees) {
+ macroExpandedArguments.Add(MacroExpand(root, subtree, argumentTrees));
+ }
+ return MacroExpand(root, defunNode, macroExpandedArguments);
+ } else if (node.Symbol is Argument) {
+ var argSym = node.Symbol as Argument;
+ // return the correct argument sub-tree (already macro-expanded)
+ return (SymbolicExpressionTreeNode)argumentTrees[argSym.ArgumentIndex].Clone();
+ } else {
+ // recursive application
+ foreach (var subtree in subtrees) {
+ node.AddSubtree(MacroExpand(root, subtree, argumentTrees));
+ }
+ return node;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode FindFunctionDefinition(ISymbolicExpressionTreeNode root, string functionName) {
+ foreach (var subtree in root.Subtrees.OfType()) {
+ if (subtree.FunctionName == functionName) return subtree.GetSubtree(0);
+ }
+
+ throw new ArgumentException("Definition of function " + functionName + " not found.");
+ }
+
+ #region symbol predicates
+
+ // arithmetic
+ private bool IsDivision(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Division;
+ }
+
+ private bool IsMultiplication(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Multiplication;
+ }
+
+ private bool IsSubtraction(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Subtraction;
+ }
+
+ private bool IsAddition(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Addition;
+ }
+
+ private bool IsAverage(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Average;
+ }
+
+ // exponential
+ private bool IsLog(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Logarithm;
+ }
+
+ private bool IsExp(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Exponential;
+ }
+
+ private bool IsRoot(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Root;
+ }
+
+ private bool IsSquare(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Square;
+ }
+
+ private bool IsSquareRoot(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is SquareRoot;
+ }
+
+ private bool IsPower(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Power;
+ }
+
+ // trigonometric
+ private bool IsSine(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Sine;
+ }
+
+ private bool IsCosine(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Cosine;
+ }
+
+ private bool IsTangent(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Tangent;
+ }
+
+ // boolean
+ private bool IsIfThenElse(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is IfThenElse;
+ }
+
+ private bool IsAnd(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is And;
+ }
+
+ private bool IsOr(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Or;
+ }
+
+ private bool IsNot(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Not;
+ }
+
+ // comparison
+ private bool IsGreaterThan(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is GreaterThan;
+ }
+
+ private bool IsLessThan(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is LessThan;
+ }
+
+ private bool IsBoolean(ISymbolicExpressionTreeNode node) {
+ return
+ node.Symbol is GreaterThan ||
+ node.Symbol is LessThan ||
+ node.Symbol is And ||
+ node.Symbol is Or;
+ }
+
+ // terminals
+ private bool IsVariable(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Variable;
+ }
+
+ private bool IsVariableBase(ISymbolicExpressionTreeNode node) {
+ return node is VariableTreeNodeBase;
+ }
+
+ private bool IsFactor(ISymbolicExpressionTreeNode node) {
+ return node is FactorVariableTreeNode;
+ }
+
+ private bool IsBinFactor(ISymbolicExpressionTreeNode node) {
+ return node is BinaryFactorVariableTreeNode;
+ }
+
+ private bool IsConstant(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Constant;
+ }
+
+ // dynamic
+ private bool IsTimeLag(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is TimeLag;
+ }
+
+ private bool IsIntegral(ISymbolicExpressionTreeNode node) {
+ return node.Symbol is Integral;
+ }
+
+ #endregion
+
+ ///
+ /// Creates a new simplified tree
+ ///
+ ///
+ ///
+ public ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
+ if (IsConstant(original) || IsVariableBase(original)) {
+ return (ISymbolicExpressionTreeNode)original.Clone();
+ } else if (IsAddition(original)) {
+ return SimplifyAddition(original);
+ } else if (IsSubtraction(original)) {
+ return SimplifySubtraction(original);
+ } else if (IsMultiplication(original)) {
+ return SimplifyMultiplication(original);
+ } else if (IsDivision(original)) {
+ return SimplifyDivision(original);
+ } else if (IsAverage(original)) {
+ return SimplifyAverage(original);
+ } else if (IsLog(original)) {
+ return SimplifyLog(original);
+ } else if (IsExp(original)) {
+ return SimplifyExp(original);
+ } else if (IsSquare(original)) {
+ return SimplifySquare(original);
+ } else if (IsSquareRoot(original)) {
+ return SimplifySquareRoot(original);
+ } else if (IsPower(original)) {
+ return SimplifyPower(original);
+ } else if (IsRoot(original)) {
+ return SimplifyRoot(original);
+ } else if (IsSine(original)) {
+ return SimplifySine(original);
+ } else if (IsCosine(original)) {
+ return SimplifyCosine(original);
+ } else if (IsTangent(original)) {
+ return SimplifyTangent(original);
+ } else if (IsIfThenElse(original)) {
+ return SimplifyIfThenElse(original);
+ } else if (IsGreaterThan(original)) {
+ return SimplifyGreaterThan(original);
+ } else if (IsLessThan(original)) {
+ return SimplifyLessThan(original);
+ } else if (IsAnd(original)) {
+ return SimplifyAnd(original);
+ } else if (IsOr(original)) {
+ return SimplifyOr(original);
+ } else if (IsNot(original)) {
+ return SimplifyNot(original);
+ } else if (IsTimeLag(original)) {
+ return SimplifyTimeLag(original);
+ } else if (IsIntegral(original)) {
+ return SimplifyIntegral(original);
+ } else {
+ return SimplifyAny(original);
+ }
+ }
+
+ #region specific simplification routines
+
+ private ISymbolicExpressionTreeNode SimplifyAny(ISymbolicExpressionTreeNode original) {
+ // can't simplify this function but simplify all subtrees
+ List subtrees = new List(original.Subtrees);
+ while (original.Subtrees.Count() > 0) original.RemoveSubtree(0);
+ var clone = (SymbolicExpressionTreeNode)original.Clone();
+ List simplifiedSubtrees = new List();
+ foreach (var subtree in subtrees) {
+ simplifiedSubtrees.Add(GetSimplifiedTree(subtree));
+ original.AddSubtree(subtree);
+ }
+ foreach (var simplifiedSubtree in simplifiedSubtrees) {
+ clone.AddSubtree(simplifiedSubtree);
+ }
+ if (simplifiedSubtrees.TrueForAll(t => IsConstant(t))) {
+ SimplifyConstantExpression(clone);
+ }
+ return clone;
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyConstantExpression(ISymbolicExpressionTreeNode original) {
+ // not yet implemented
+ return original;
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyAverage(ISymbolicExpressionTreeNode original) {
+ if (original.Subtrees.Count() == 1) {
+ return GetSimplifiedTree(original.GetSubtree(0));
+ } else {
+ // simplify expressions x0..xn
+ // make sum(x0..xn) / n
+ var sum = original.Subtrees
+ .Select(GetSimplifiedTree)
+ .Aggregate(MakeSum);
+ return MakeFraction(sum, MakeConstant(original.Subtrees.Count()));
+ }
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
+ if (original.Subtrees.Count() == 1) {
+ return Invert(GetSimplifiedTree(original.GetSubtree(0)));
+ } else {
+ // simplify expressions x0..xn
+ // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
+ var first = original.GetSubtree(0);
+ var second = original.GetSubtree(1);
+ var remaining = original.Subtrees.Skip(2);
+ return
+ MakeProduct(GetSimplifiedTree(first),
+ Invert(remaining.Aggregate(GetSimplifiedTree(second), (a, b) => MakeProduct(a, GetSimplifiedTree(b)))));
+ }
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
+ if (original.Subtrees.Count() == 1) {
+ return GetSimplifiedTree(original.GetSubtree(0));
+ } else {
+ return original.Subtrees
+ .Select(GetSimplifiedTree)
+ .Aggregate(MakeProduct);
+ }
+ }
+
+ private ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
+ if (original.Subtrees.Count() == 1) {
+ return Negate(GetSimplifiedTree(original.GetSubtree(0)));
+ } else {
+ // simplify expressions x0..xn
+ // make addition (x0,-x1..-xn)
+ var first = original.Subtrees.First();
+ var remaining = original.Subtrees.Skip(1);
+ return remaining.Aggregate(GetSimplifiedTree(first), (a, b) => MakeSum(a, Negate(GetSimplifiedTree(b))));
+ }
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
+ if (original.Subtrees.Count() == 1) {
+ return GetSimplifiedTree(original.GetSubtree(0));
+ } else {
+ // simplify expression x0..xn
+ // make addition (x0..xn)
+ return original.Subtrees
+ .Select(GetSimplifiedTree)
+ .Aggregate(MakeSum);
+ }
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
+ return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
+ return original.Subtrees
+ .Select(GetSimplifiedTree)
+ .Aggregate(MakeOr);
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
+ return original.Subtrees
+ .Select(GetSimplifiedTree)
+ .Aggregate(MakeAnd);
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
+ return MakeLessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
+ return MakeGreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
+ return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)),
+ GetSimplifiedTree(original.GetSubtree(2)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
+ return MakeTangent(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
+ return MakeCosine(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
+ return MakeSine(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
+ return MakeExp(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifySquare(ISymbolicExpressionTreeNode original) {
+ return MakeSquare(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifySquareRoot(ISymbolicExpressionTreeNode original) {
+ return MakeSquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
+ return MakeLog(GetSimplifiedTree(original.GetSubtree(0)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
+ return MakeRoot(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
+ return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyTimeLag(ISymbolicExpressionTreeNode original) {
+ var laggedTreeNode = original as ILaggedTreeNode;
+ var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
+ if (!ContainsVariableCondition(simplifiedSubtree)) {
+ return AddLagToDynamicNodes(simplifiedSubtree, laggedTreeNode.Lag);
+ } else {
+ return MakeTimeLag(simplifiedSubtree, laggedTreeNode.Lag);
+ }
+ }
+
+ private ISymbolicExpressionTreeNode SimplifyIntegral(ISymbolicExpressionTreeNode original) {
+ var laggedTreeNode = original as ILaggedTreeNode;
+ var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
+ if (IsConstant(simplifiedSubtree)) {
+ return GetSimplifiedTree(MakeProduct(simplifiedSubtree, MakeConstant(-laggedTreeNode.Lag)));
+ } else {
+ return MakeIntegral(simplifiedSubtree, laggedTreeNode.Lag);
+ }
+ }
+
+ #endregion
+
+ #region low level tree restructuring
+
+ private ISymbolicExpressionTreeNode MakeTimeLag(ISymbolicExpressionTreeNode subtree, int lag) {
+ if (lag == 0) return subtree;
+ if (IsConstant(subtree)) return subtree;
+ var lagNode = (LaggedTreeNode)timeLagSymbol.CreateTreeNode();
+ lagNode.Lag = lag;
+ lagNode.AddSubtree(subtree);
+ return lagNode;
+ }
+
+ private ISymbolicExpressionTreeNode MakeIntegral(ISymbolicExpressionTreeNode subtree, int lag) {
+ if (lag == 0) return subtree;
+ else if (lag == -1 || lag == 1) {
+ return MakeSum(subtree, AddLagToDynamicNodes((ISymbolicExpressionTreeNode)subtree.Clone(), lag));
+ } else {
+ var node = (LaggedTreeNode)integralSymbol.CreateTreeNode();
+ node.Lag = lag;
+ node.AddSubtree(subtree);
+ return node;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeNot(ISymbolicExpressionTreeNode t) {
+ if (IsConstant(t)) {
+ var constNode = t as ConstantTreeNode;
+ if (constNode.Value > 0) return MakeConstant(-1.0);
+ else return MakeConstant(1.0);
+ } else if (IsNot(t)) {
+ return t.GetSubtree(0);
+ } else if (!IsBoolean(t)) {
+ var gtNode = gtSymbol.CreateTreeNode();
+ gtNode.AddSubtree(t);
+ gtNode.AddSubtree(MakeConstant(0.0));
+ var notNode = notSymbol.CreateTreeNode();
+ notNode.AddSubtree(gtNode);
+ return notNode;
+ } else {
+ var notNode = notSymbol.CreateTreeNode();
+ notNode.AddSubtree(t);
+ return notNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeOr(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ if (IsConstant(a) && IsConstant(b)) {
+ var constA = a as ConstantTreeNode;
+ var constB = b as ConstantTreeNode;
+ if (constA.Value > 0.0 || constB.Value > 0.0) {
+ return MakeConstant(1.0);
+ } else {
+ return MakeConstant(-1.0);
+ }
+ } else if (IsConstant(a)) {
+ return MakeOr(b, a);
+ } else if (IsConstant(b)) {
+ var constT = b as ConstantTreeNode;
+ if (constT.Value > 0.0) {
+ // boolean expression is necessarily true
+ return MakeConstant(1.0);
+ } else {
+ // the constant value has no effect on the result of the boolean condition so we can drop the constant term
+ var orNode = orSymbol.CreateTreeNode();
+ orNode.AddSubtree(a);
+ return orNode;
+ }
+ } else {
+ var orNode = orSymbol.CreateTreeNode();
+ orNode.AddSubtree(a);
+ orNode.AddSubtree(b);
+ return orNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ if (IsConstant(a) && IsConstant(b)) {
+ var constA = a as ConstantTreeNode;
+ var constB = b as ConstantTreeNode;
+ if (constA.Value > 0.0 && constB.Value > 0.0) {
+ return MakeConstant(1.0);
+ } else {
+ return MakeConstant(-1.0);
+ }
+ } else if (IsConstant(a)) {
+ return MakeAnd(b, a);
+ } else if (IsConstant(b)) {
+ var constB = b as ConstantTreeNode;
+ if (constB.Value > 0.0) {
+ // the constant value has no effect on the result of the boolean condition so we can drop the constant term
+ var andNode = andSymbol.CreateTreeNode();
+ andNode.AddSubtree(a);
+ return andNode;
+ } else {
+ // boolean expression is necessarily false
+ return MakeConstant(-1.0);
+ }
+ } else {
+ var andNode = andSymbol.CreateTreeNode();
+ andNode.AddSubtree(a);
+ andNode.AddSubtree(b);
+ return andNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide,
+ ISymbolicExpressionTreeNode rightSide) {
+ if (IsConstant(leftSide) && IsConstant(rightSide)) {
+ var lsConst = leftSide as ConstantTreeNode;
+ var rsConst = rightSide as ConstantTreeNode;
+ if (lsConst.Value < rsConst.Value) return MakeConstant(1.0);
+ else return MakeConstant(-1.0);
+ } else {
+ var ltNode = ltSymbol.CreateTreeNode();
+ ltNode.AddSubtree(leftSide);
+ ltNode.AddSubtree(rightSide);
+ return ltNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide,
+ ISymbolicExpressionTreeNode rightSide) {
+ if (IsConstant(leftSide) && IsConstant(rightSide)) {
+ var lsConst = leftSide as ConstantTreeNode;
+ var rsConst = rightSide as ConstantTreeNode;
+ if (lsConst.Value > rsConst.Value) return MakeConstant(1.0);
+ else return MakeConstant(-1.0);
+ } else {
+ var gtNode = gtSymbol.CreateTreeNode();
+ gtNode.AddSubtree(leftSide);
+ gtNode.AddSubtree(rightSide);
+ return gtNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition,
+ ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
+ if (IsConstant(condition)) {
+ var constT = condition as ConstantTreeNode;
+ if (constT.Value > 0.0) return trueBranch;
+ else return falseBranch;
+ } else {
+ var ifNode = ifThenElseSymbol.CreateTreeNode();
+ if (IsBoolean(condition)) {
+ ifNode.AddSubtree(condition);
+ } else {
+ var gtNode = gtSymbol.CreateTreeNode();
+ gtNode.AddSubtree(condition);
+ gtNode.AddSubtree(MakeConstant(0.0));
+ ifNode.AddSubtree(gtNode);
+ }
+ ifNode.AddSubtree(trueBranch);
+ ifNode.AddSubtree(falseBranch);
+ return ifNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeSine(ISymbolicExpressionTreeNode node) {
+ if (IsConstant(node)) {
+ var constT = node as ConstantTreeNode;
+ return MakeConstant(Math.Sin(constT.Value));
+ } else if (IsFactor(node)) {
+ var factor = node as FactorVariableTreeNode;
+ return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Sin));
+ } else if (IsBinFactor(node)) {
+ var binFactor = node as BinaryFactorVariableTreeNode;
+ return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sin(binFactor.Weight));
+ } else {
+ var sineNode = sineSymbol.CreateTreeNode();
+ sineNode.AddSubtree(node);
+ return sineNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
+ if (IsConstant(node)) {
+ var constT = node as ConstantTreeNode;
+ return MakeConstant(Math.Tan(constT.Value));
+ } else if (IsFactor(node)) {
+ var factor = node as FactorVariableTreeNode;
+ return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Tan));
+ } else if (IsBinFactor(node)) {
+ var binFactor = node as BinaryFactorVariableTreeNode;
+ return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Tan(binFactor.Weight));
+ } else {
+ var tanNode = tanSymbol.CreateTreeNode();
+ tanNode.AddSubtree(node);
+ return tanNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
+ if (IsConstant(node)) {
+ var constT = node as ConstantTreeNode;
+ return MakeConstant(Math.Cos(constT.Value));
+ } else if (IsFactor(node)) {
+ var factor = node as FactorVariableTreeNode;
+ return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Cos));
+ } else if (IsBinFactor(node)) {
+ var binFactor = node as BinaryFactorVariableTreeNode;
+ // cos(0) = 1 see similar case for Exp(binfactor)
+ return MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Cos(binFactor.Weight) - 1),
+ MakeConstant(1.0));
+ } else {
+ var cosNode = cosineSymbol.CreateTreeNode();
+ cosNode.AddSubtree(node);
+ return cosNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
+ if (IsConstant(node)) {
+ var constT = node as ConstantTreeNode;
+ return MakeConstant(Math.Exp(constT.Value));
+ } else if (IsFactor(node)) {
+ var factNode = node as FactorVariableTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Exp(w)));
+ } else if (IsBinFactor(node)) {
+ // exp( binfactor w val=a) = if(val=a) exp(w) else exp(0) = binfactor( (exp(w) - 1) val a) + 1
+ var binFactor = node as BinaryFactorVariableTreeNode;
+ return
+ MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Exp(binFactor.Weight) - 1), MakeConstant(1.0));
+ } else if (IsLog(node)) {
+ return node.GetSubtree(0);
+ } else if (IsAddition(node)) {
+ return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, t));
+ } else if (IsSubtraction(node)) {
+ return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, Negate(t)));
+ } else {
+ var expNode = expSymbol.CreateTreeNode();
+ expNode.AddSubtree(node);
+ return expNode;
+ }
+ }
+ private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
+ if (IsConstant(node)) {
+ var constT = node as ConstantTreeNode;
+ return MakeConstant(Math.Log(constT.Value));
+ } else if (IsFactor(node)) {
+ var factNode = node as FactorVariableTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Log(w)));
+ } else if (IsExp(node)) {
+ return node.GetSubtree(0);
+ } else if (IsSquareRoot(node)) {
+ return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
+ } else {
+ var logNode = logSymbol.CreateTreeNode();
+ logNode.AddSubtree(node);
+ return logNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeSquare(ISymbolicExpressionTreeNode node) {
+ if (IsConstant(node)) {
+ var constT = node as ConstantTreeNode;
+ return MakeConstant(constT.Value * constT.Value);
+ } else if (IsFactor(node)) {
+ var factNode = node as FactorVariableTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w));
+ } else if (IsBinFactor(node)) {
+ var binFactor = node as BinaryFactorVariableTreeNode;
+ return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight);
+ } else if (IsSquareRoot(node)) {
+ return node.GetSubtree(0);
+ } else {
+ var sqrNode = sqrSymbol.CreateTreeNode();
+ sqrNode.AddSubtree(node);
+ return sqrNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeSquareRoot(ISymbolicExpressionTreeNode node) {
+ if (IsConstant(node)) {
+ var constT = node as ConstantTreeNode;
+ return MakeConstant(Math.Sqrt(constT.Value));
+ } else if (IsFactor(node)) {
+ var factNode = node as FactorVariableTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(w)));
+ } else if (IsBinFactor(node)) {
+ var binFactor = node as BinaryFactorVariableTreeNode;
+ return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(binFactor.Weight));
+ } else if (IsSquare(node)) {
+ return node.GetSubtree(0);
+ } else {
+ var sqrtNode = sqrtSymbol.CreateTreeNode();
+ sqrtNode.AddSubtree(node);
+ return sqrtNode;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ if (IsConstant(a) && IsConstant(b)) {
+ var constA = a as ConstantTreeNode;
+ var constB = b as ConstantTreeNode;
+ return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
+ } else if (IsFactor(a) && IsConstant(b)) {
+ var factNode = a as FactorVariableTreeNode;
+ var constNode = b as ConstantTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName,
+ factNode.Weights.Select(w => Math.Pow(w, 1.0 / Math.Round(constNode.Value))));
+ } else if (IsBinFactor(a) && IsConstant(b)) {
+ var binFactor = a as BinaryFactorVariableTreeNode;
+ var constNode = b as ConstantTreeNode;
+ return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, 1.0 / Math.Round(constNode.Value)));
+ } else if (IsConstant(a) && IsFactor(b)) {
+ var constNode = a as ConstantTreeNode;
+ var factNode = b as FactorVariableTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, 1.0 / Math.Round(w))));
+ } else if (IsConstant(a) && IsBinFactor(b)) {
+ var constNode = a as ConstantTreeNode;
+ var factNode = b as BinaryFactorVariableTreeNode;
+ return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, 1.0 / Math.Round(factNode.Weight)));
+ } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as FactorVariableTreeNode;
+ return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, 1.0 / Math.Round(v))));
+ } else if (IsConstant(b)) {
+ var constB = b as ConstantTreeNode;
+ var constBValue = Math.Round(constB.Value);
+ if (constBValue.IsAlmost(1.0)) {
+ return a;
+ } else if (constBValue.IsAlmost(0.0)) {
+ return MakeConstant(1.0);
+ } else if (constBValue.IsAlmost(-1.0)) {
+ return MakeFraction(MakeConstant(1.0), a);
+ } else if (constBValue < 0) {
+ var rootNode = rootSymbol.CreateTreeNode();
+ rootNode.AddSubtree(a);
+ rootNode.AddSubtree(MakeConstant(-1.0 * constBValue));
+ return MakeFraction(MakeConstant(1.0), rootNode);
+ } else {
+ var rootNode = rootSymbol.CreateTreeNode();
+ rootNode.AddSubtree(a);
+ rootNode.AddSubtree(MakeConstant(constBValue));
+ return rootNode;
+ }
+ } else {
+ var rootNode = rootSymbol.CreateTreeNode();
+ rootNode.AddSubtree(a);
+ rootNode.AddSubtree(b);
+ return rootNode;
+ }
+ }
+
+
+ private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ if (IsConstant(a) && IsConstant(b)) {
+ var constA = a as ConstantTreeNode;
+ var constB = b as ConstantTreeNode;
+ return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
+ } else if (IsFactor(a) && IsConstant(b)) {
+ var factNode = a as FactorVariableTreeNode;
+ var constNode = b as ConstantTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, Math.Round(constNode.Value))));
+ } else if (IsBinFactor(a) && IsConstant(b)) {
+ var binFactor = a as BinaryFactorVariableTreeNode;
+ var constNode = b as ConstantTreeNode;
+ return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, Math.Round(constNode.Value)));
+ } else if (IsConstant(a) && IsFactor(b)) {
+ var constNode = a as ConstantTreeNode;
+ var factNode = b as FactorVariableTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, Math.Round(w))));
+ } else if (IsConstant(a) && IsBinFactor(b)) {
+ var constNode = a as ConstantTreeNode;
+ var factNode = b as BinaryFactorVariableTreeNode;
+ return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, Math.Round(factNode.Weight)));
+ } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as FactorVariableTreeNode;
+ return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, Math.Round(v))));
+ } else if (IsConstant(b)) {
+ var constB = b as ConstantTreeNode;
+ double exponent = Math.Round(constB.Value);
+ if (exponent.IsAlmost(0.0)) {
+ return MakeConstant(1.0);
+ } else if (exponent.IsAlmost(1.0)) {
+ return a;
+ } else if (exponent.IsAlmost(-1.0)) {
+ return MakeFraction(MakeConstant(1.0), a);
+ } else if (exponent < 0) {
+ var powNode = powSymbol.CreateTreeNode();
+ powNode.AddSubtree(a);
+ powNode.AddSubtree(MakeConstant(-1.0 * exponent));
+ return MakeFraction(MakeConstant(1.0), powNode);
+ } else {
+ var powNode = powSymbol.CreateTreeNode();
+ powNode.AddSubtree(a);
+ powNode.AddSubtree(MakeConstant(exponent));
+ return powNode;
+ }
+ } else {
+ var powNode = powSymbol.CreateTreeNode();
+ powNode.AddSubtree(a);
+ powNode.AddSubtree(b);
+ return powNode;
+ }
+ }
+
+
+ // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
+ private ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ if (IsConstant(a) && IsConstant(b)) {
+ // fold constants
+ return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
+ } else if ((IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0))) {
+ return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
+ } else if (IsVariableBase(a) && IsConstant(b)) {
+ // merge constant values into variable weights
+ var constB = ((ConstantTreeNode)b).Value;
+ ((VariableTreeNodeBase)a).Weight /= constB;
+ return a;
+ } else if (IsFactor(a) && IsConstant(b)) {
+ var factNode = a as FactorVariableTreeNode;
+ var constNode = b as ConstantTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w / constNode.Value));
+ } else if (IsBinFactor(a) && IsConstant(b)) {
+ var factNode = a as BinaryFactorVariableTreeNode;
+ var constNode = b as ConstantTreeNode;
+ return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, factNode.Weight / constNode.Value);
+ } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as FactorVariableTreeNode;
+ return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u / v));
+ } else if (IsFactor(a) && IsBinFactor(b) && ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as BinaryFactorVariableTreeNode;
+ var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
+ var wi = Array.IndexOf(varValues, node1.VariableValue);
+ if (wi < 0) throw new ArgumentException();
+ var newWeighs = new double[varValues.Length];
+ node0.Weights.CopyTo(newWeighs, 0);
+ for (int i = 0; i < newWeighs.Length; i++)
+ if (wi == i) newWeighs[i] /= node1.Weight;
+ else newWeighs[i] /= 0.0;
+ return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
+ } else if (IsFactor(a)) {
+ return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
+ } else if (IsVariableBase(a) && IsVariableBase(b) && AreSameTypeAndVariable(a, b) && !IsBinFactor(b)) {
+ // cancel variables (not allowed for bin factors because of division by zero)
+ var aVar = a as VariableTreeNode;
+ var bVar = b as VariableTreeNode;
+ return MakeConstant(aVar.Weight / bVar.Weight);
+ } else if (IsAddition(a) && IsConstant(b)) {
+ return a.Subtrees
+ .Select(x => GetSimplifiedTree(x))
+ .Select(x => MakeFraction(x, GetSimplifiedTree(b)))
+ .Aggregate((c, d) => MakeSum(c, d));
+ } else if (IsMultiplication(a) && IsConstant(b)) {
+ return MakeProduct(a, Invert(b));
+ } else if (IsDivision(a) && IsConstant(b)) {
+ // (a1 / a2) / c => (a1 / (a2 * c))
+ return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
+ } else if (IsDivision(a) && IsDivision(b)) {
+ // (a1 / a2) / (b1 / b2) =>
+ return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
+ } else if (IsDivision(a)) {
+ // (a1 / a2) / b => (a1 / (a2 * b))
+ return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
+ } else if (IsDivision(b)) {
+ // a / (b1 / b2) => (a * b2) / b1
+ return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
+ } else {
+ var div = divSymbol.CreateTreeNode();
+ div.AddSubtree(a);
+ div.AddSubtree(b);
+ return div;
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ if (IsConstant(a) && IsConstant(b)) {
+ // fold constants
+ ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
+ return a;
+ } else if (IsConstant(a)) {
+ // c + x => x + c
+ // b is not constant => make sure constant is on the right
+ return MakeSum(b, a);
+ } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
+ // x + 0 => x
+ return a;
+ } else if (IsFactor(a) && IsConstant(b)) {
+ var factNode = a as FactorVariableTreeNode;
+ var constNode = b as ConstantTreeNode;
+ return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select((w) => w + constNode.Value));
+ } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as FactorVariableTreeNode;
+ return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u + v));
+ } else if (IsBinFactor(a) && IsFactor(b)) {
+ return MakeSum(b, a);
+ } else if (IsFactor(a) && IsBinFactor(b) &&
+ ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as BinaryFactorVariableTreeNode;
+ var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
+ var wi = Array.IndexOf(varValues, node1.VariableValue);
+ if (wi < 0) throw new ArgumentException();
+ var newWeighs = new double[varValues.Length];
+ node0.Weights.CopyTo(newWeighs, 0);
+ newWeighs[wi] += node1.Weight;
+ return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
+ } else if (IsAddition(a) && IsAddition(b)) {
+ // merge additions
+ var add = addSymbol.CreateTreeNode();
+ // add all sub trees except for the last
+ for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
+ for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
+ if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
+ add.AddSubtree(MakeSum(a.Subtrees.Last(), b.Subtrees.Last()));
+ } else if (IsConstant(a.Subtrees.Last())) {
+ add.AddSubtree(b.Subtrees.Last());
+ add.AddSubtree(a.Subtrees.Last());
+ } else {
+ add.AddSubtree(a.Subtrees.Last());
+ add.AddSubtree(b.Subtrees.Last());
+ }
+ MergeVariablesInSum(add);
+ if (add.Subtrees.Count() == 1) {
+ return add.GetSubtree(0);
+ } else {
+ return add;
+ }
+ } else if (IsAddition(b)) {
+ return MakeSum(b, a);
+ } else if (IsAddition(a) && IsConstant(b)) {
+ // a is an addition and b is a constant => append b to a and make sure the constants are merged
+ var add = addSymbol.CreateTreeNode();
+ // add all sub trees except for the last
+ for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
+ if (IsConstant(a.Subtrees.Last()))
+ add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
+ else {
+ add.AddSubtree(a.Subtrees.Last());
+ add.AddSubtree(b);
+ }
+ return add;
+ } else if (IsAddition(a)) {
+ // a is already an addition => append b
+ var add = addSymbol.CreateTreeNode();
+ add.AddSubtree(b);
+ foreach (var subtree in a.Subtrees) {
+ add.AddSubtree(subtree);
+ }
+ MergeVariablesInSum(add);
+ if (add.Subtrees.Count() == 1) {
+ return add.GetSubtree(0);
+ } else {
+ return add;
+ }
+ } else {
+ var add = addSymbol.CreateTreeNode();
+ add.AddSubtree(a);
+ add.AddSubtree(b);
+ MergeVariablesInSum(add);
+ if (add.Subtrees.Count() == 1) {
+ return add.GetSubtree(0);
+ } else {
+ return add;
+ }
+ }
+ }
+
+ // makes sure variable symbols in sums are combined
+ private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
+ var subtrees = new List(sum.Subtrees);
+ while (sum.Subtrees.Any()) sum.RemoveSubtree(0);
+ var groupedVarNodes = from node in subtrees.OfType()
+ where node.SubtreeCount == 0
+ group node by GroupId(node) into g
+ select g;
+ var constant = (from node in subtrees.OfType()
+ select node.Value).DefaultIfEmpty(0.0).Sum();
+ var unchangedSubtrees = subtrees.Where(t => t.SubtreeCount > 0 || !(t is IVariableTreeNode) && !(t is ConstantTreeNode));
+
+ foreach (var variableNodeGroup in groupedVarNodes) {
+ var firstNode = variableNodeGroup.First();
+ if (firstNode is VariableTreeNodeBase) {
+ var representative = firstNode as VariableTreeNodeBase;
+ var weightSum = variableNodeGroup.Cast().Select(t => t.Weight).Sum();
+ representative.Weight = weightSum;
+ sum.AddSubtree(representative);
+ } else if (firstNode is FactorVariableTreeNode) {
+ var representative = firstNode as FactorVariableTreeNode;
+ foreach (var node in variableNodeGroup.Skip(1).Cast()) {
+ for (int j = 0; j < representative.Weights.Length; j++) {
+ representative.Weights[j] += node.Weights[j];
+ }
+ }
+ for (int j = 0; j < representative.Weights.Length; j++) {
+ representative.Weights[j] += constant;
+ }
+ sum.AddSubtree(representative);
+ }
+ }
+ foreach (var unchangedSubtree in unchangedSubtrees)
+ sum.AddSubtree(unchangedSubtree);
+ if (!constant.IsAlmost(0.0)) {
+ sum.AddSubtree(MakeConstant(constant));
+ }
+ }
+
+ // nodes referencing variables can be grouped if they have
+ private string GroupId(IVariableTreeNode node) {
+ var binaryFactorNode = node as BinaryFactorVariableTreeNode;
+ var factorNode = node as FactorVariableTreeNode;
+ var variableNode = node as VariableTreeNode;
+ var laggedVarNode = node as LaggedVariableTreeNode;
+ if (variableNode != null) {
+ return "var " + variableNode.VariableName;
+ } else if (binaryFactorNode != null) {
+ return "binfactor " + binaryFactorNode.VariableName + " " + binaryFactorNode.VariableValue;
+ } else if (factorNode != null) {
+ return "factor " + factorNode.VariableName;
+ } else if (laggedVarNode != null) {
+ return "lagged " + laggedVarNode.VariableName + " " + laggedVarNode.Lag;
+ } else {
+ throw new NotSupportedException();
+ }
+ }
+
+
+ private ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ if (IsConstant(a) && IsConstant(b)) {
+ // fold constants
+ return MakeConstant(((ConstantTreeNode)a).Value * ((ConstantTreeNode)b).Value);
+ } else if (IsConstant(a)) {
+ // a * $ => $ * a
+ return MakeProduct(b, a);
+ } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as FactorVariableTreeNode;
+ return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u * v));
+ } else if (IsBinFactor(a) && IsBinFactor(b) && AreSameTypeAndVariable(a, b)) {
+ var node0 = a as BinaryFactorVariableTreeNode;
+ var node1 = b as BinaryFactorVariableTreeNode;
+ return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Weight);
+ } else if (IsFactor(a) && IsConstant(b)) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as ConstantTreeNode;
+ return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Select(w => w * node1.Value));
+ } else if (IsBinFactor(a) && IsConstant(b)) {
+ var node0 = a as BinaryFactorVariableTreeNode;
+ var node1 = b as ConstantTreeNode;
+ return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Value);
+ } else if (IsBinFactor(a) && IsFactor(b)) {
+ return MakeProduct(b, a);
+ } else if (IsFactor(a) && IsBinFactor(b) &&
+ ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
+ var node0 = a as FactorVariableTreeNode;
+ var node1 = b as BinaryFactorVariableTreeNode;
+ var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
+ var wi = Array.IndexOf(varValues, node1.VariableValue);
+ if (wi < 0) throw new ArgumentException();
+ return MakeBinFactor(node1.Symbol, node1.VariableName, node1.VariableValue, node1.Weight * node0.Weights[wi]);
+ } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
+ // $ * 1.0 => $
+ return a;
+ } else if (IsConstant(b) && IsVariableBase(a)) {
+ // multiply constants into variables weights
+ ((VariableTreeNodeBase)a).Weight *= ((ConstantTreeNode)b).Value;
+ return a;
+ } else if (IsConstant(b) && IsAddition(a) ||
+ IsFactor(b) && IsAddition(a) ||
+ IsBinFactor(b) && IsAddition(a)) {
+ // multiply constants into additions
+ return a.Subtrees.Select(x => MakeProduct(GetSimplifiedTree(x), GetSimplifiedTree(b))).Aggregate((c, d) => MakeSum(c, d));
+ } else if (IsDivision(a) && IsDivision(b)) {
+ // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
+ return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
+ } else if (IsDivision(a)) {
+ // (a1 / a2) * b => (a1 * b) / a2
+ return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
+ } else if (IsDivision(b)) {
+ // a * (b1 / b2) => (b1 * a) / b2
+ return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
+ } else if (IsMultiplication(a) && IsMultiplication(b)) {
+ // merge multiplications (make sure constants are merged)
+ var mul = mulSymbol.CreateTreeNode();
+ for (int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
+ for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
+ MergeVariablesAndConstantsInProduct(mul);
+ return mul;
+ } else if (IsMultiplication(b)) {
+ return MakeProduct(b, a);
+ } else if (IsMultiplication(a)) {
+ // a is already an multiplication => append b
+ a.AddSubtree(GetSimplifiedTree(b));
+ MergeVariablesAndConstantsInProduct(a);
+ return a;
+ } else {
+ var mul = mulSymbol.CreateTreeNode();
+ mul.AddSubtree(a);
+ mul.AddSubtree(b);
+ MergeVariablesAndConstantsInProduct(mul);
+ return mul;
+ }
+ }
+
+ #endregion
+
+ #region helper functions
+
+ private bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
+ if (node.Symbol is VariableCondition) return true;
+ foreach (var subtree in node.Subtrees)
+ if (ContainsVariableCondition(subtree)) return true;
+ return false;
+ }
+
+ private ISymbolicExpressionTreeNode AddLagToDynamicNodes(ISymbolicExpressionTreeNode node, int lag) {
+ var laggedTreeNode = node as ILaggedTreeNode;
+ var variableNode = node as VariableTreeNode;
+ var variableConditionNode = node as VariableConditionTreeNode;
+ if (laggedTreeNode != null)
+ laggedTreeNode.Lag += lag;
+ else if (variableNode != null) {
+ var laggedVariableNode = (LaggedVariableTreeNode)laggedVariableSymbol.CreateTreeNode();
+ laggedVariableNode.Lag = lag;
+ laggedVariableNode.VariableName = variableNode.VariableName;
+ return laggedVariableNode;
+ } else if (variableConditionNode != null) {
+ throw new NotSupportedException("Removal of time lags around variable condition symbols is not allowed.");
+ }
+ var subtrees = new List(node.Subtrees);
+ while (node.SubtreeCount > 0) node.RemoveSubtree(0);
+ foreach (var subtree in subtrees) {
+ node.AddSubtree(AddLagToDynamicNodes(subtree, lag));
+ }
+ return node;
+ }
+
+ private bool AreSameTypeAndVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+ return GroupId((IVariableTreeNode)a) == GroupId((IVariableTreeNode)b);
+ }
+
+ // helper to combine the constant factors in products and to combine variables (powers of 2, 3...)
+ private void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
+ var subtrees = new List(prod.Subtrees);
+ while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
+ var groupedVarNodes = from node in subtrees.OfType()
+ where node.SubtreeCount == 0
+ group node by GroupId(node) into g
+ orderby g.Count()
+ select g;
+ var constantProduct = (from node in subtrees.OfType()
+ select node.Weight)
+ .Concat(from node in subtrees.OfType()
+ select node.Value)
+ .DefaultIfEmpty(1.0)
+ .Aggregate((c1, c2) => c1 * c2);
+
+ var unchangedSubtrees = from tree in subtrees
+ where tree.SubtreeCount > 0 || !(tree is IVariableTreeNode) && !(tree is ConstantTreeNode)
+ select tree;
+
+ foreach (var variableNodeGroup in groupedVarNodes) {
+ var firstNode = variableNodeGroup.First();
+ if (firstNode is VariableTreeNodeBase) {
+ var representative = (VariableTreeNodeBase)firstNode;
+ representative.Weight = 1.0;
+ if (variableNodeGroup.Count() > 1) {
+ var poly = mulSymbol.CreateTreeNode();
+ for (int p = 0; p < variableNodeGroup.Count(); p++) {
+ poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
+ }
+ prod.AddSubtree(poly);
+ } else {
+ prod.AddSubtree(representative);
+ }
+ } else if (firstNode is FactorVariableTreeNode) {
+ var representative = (FactorVariableTreeNode)firstNode;
+ foreach (var node in variableNodeGroup.Skip(1).Cast()) {
+ for (int j = 0; j < representative.Weights.Length; j++) {
+ representative.Weights[j] *= node.Weights[j];
+ }
+ }
+ for (int j = 0; j < representative.Weights.Length; j++) {
+ representative.Weights[j] *= constantProduct;
+ }
+ constantProduct = 1.0;
+ // if the product already contains a factor it is not necessary to multiply a constant below
+ prod.AddSubtree(representative);
+ }
+ }
+
+ foreach (var unchangedSubtree in unchangedSubtrees)
+ prod.AddSubtree(unchangedSubtree);
+
+ if (!constantProduct.IsAlmost(1.0)) {
+ prod.AddSubtree(MakeConstant(constantProduct));
+ }
+ }
+
+
+ ///
+ /// x => x * -1
+ /// Is only used in cases where it is not necessary to create new tree nodes. Manipulates x directly.
+ ///
+ ///
+ /// -x
+ private ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
+ if (IsConstant(x)) {
+ ((ConstantTreeNode)x).Value *= -1;
+ } else if (IsVariableBase(x)) {
+ var variableTree = (VariableTreeNodeBase)x;
+ variableTree.Weight *= -1.0;
+ } else if (IsFactor(x)) {
+ var factorNode = (FactorVariableTreeNode)x;
+ for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
+ } else if (IsBinFactor(x)) {
+ var factorNode = (BinaryFactorVariableTreeNode)x;
+ factorNode.Weight *= -1;
+ } else if (IsAddition(x)) {
+ // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)
+ var subtrees = new List(x.Subtrees);
+ while (x.Subtrees.Any()) x.RemoveSubtree(0);
+ foreach (var subtree in subtrees) {
+ x.AddSubtree(Negate(subtree));
+ }
+ } else if (IsMultiplication(x) || IsDivision(x)) {
+ // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
+ var lastSubTree = x.Subtrees.Last();
+ x.RemoveSubtree(x.SubtreeCount - 1);
+ x.AddSubtree(Negate(lastSubTree)); // last is maybe a constant, prefer to negate the constant
+ } else {
+ // any other function
+ return MakeProduct(x, MakeConstant(-1));
+ }
+ return x;
+ }
+
+ ///
+ /// x => 1/x
+ /// Must create new tree nodes
+ ///
+ ///
+ ///
+ private ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
+ if (IsConstant(x)) {
+ return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
+ } else if (IsFactor(x)) {
+ var factorNode = (FactorVariableTreeNode)x;
+ return MakeFactor(factorNode.Symbol, factorNode.VariableName, factorNode.Weights.Select(w => 1.0 / w));
+ } else if (IsDivision(x)) {
+ return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
+ } else {
+ // any other function
+ return MakeFraction(MakeConstant(1), x);
+ }
+ }
+
+ private ISymbolicExpressionTreeNode MakeConstant(double value) {
+ ConstantTreeNode constantTreeNode = (ConstantTreeNode)(constSymbol.CreateTreeNode());
+ constantTreeNode.Value = value;
+ return constantTreeNode;
+ }
+
+ private ISymbolicExpressionTreeNode MakeFactor(FactorVariable sy, string variableName, IEnumerable weights) {
+ var tree = (FactorVariableTreeNode)sy.CreateTreeNode();
+ tree.VariableName = variableName;
+ tree.Weights = weights.ToArray();
+ return tree;
+ }
+ private ISymbolicExpressionTreeNode MakeBinFactor(BinaryFactorVariable sy, string variableName, string variableValue, double weight) {
+ var tree = (BinaryFactorVariableTreeNode)sy.CreateTreeNode();
+ tree.VariableName = variableName;
+ tree.VariableValue = variableValue;
+ tree.Weight = weight;
+ return tree;
+ }
+
+
+ #endregion
+ }
+}
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/SymbolicExpressionTreeBacktransformator.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/SymbolicExpressionTreeBacktransformator.cs (revision 15141)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/SymbolicExpressionTreeBacktransformator.cs (revision 15141)
@@ -0,0 +1,97 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+ public class SymbolicExpressionTreeBacktransformator : IModelBacktransformator {
+ private readonly ITransformationMapper transformationMapper;
+
+ public SymbolicExpressionTreeBacktransformator(ITransformationMapper transformationMapper) {
+ this.transformationMapper = transformationMapper;
+ }
+
+ public ISymbolicDataAnalysisModel Backtransform(ISymbolicDataAnalysisModel model, IEnumerable transformations, string targetVariable) {
+ var symbolicModel = (ISymbolicDataAnalysisModel)model.Clone();
+
+ foreach (var transformation in transformations.Reverse()) {
+ ApplyBacktransformation(transformation, symbolicModel.SymbolicExpressionTree, targetVariable);
+ }
+
+ return symbolicModel;
+ }
+
+ private void ApplyBacktransformation(ITransformation transformation, ISymbolicExpressionTree symbolicExpressionTree, string targetVariable) {
+ if (transformation.Column != targetVariable) {
+ var variableNodes = symbolicExpressionTree.IterateNodesBreadth()
+ .OfType()
+ .Where(n => n.VariableName == transformation.Column);
+ ApplyRegularBacktransformation(transformation, variableNodes);
+ } else if (!(transformation is CopyColumnTransformation)) {
+ ApplyInverseBacktransformation(transformation, symbolicExpressionTree);
+ }
+ }
+
+ private void ApplyRegularBacktransformation(ITransformation transformation, IEnumerable variableNodes) {
+ foreach (var variableNode in variableNodes) {
+ // generate new subtrees because same subtree cannot be added more than once
+ var transformationTree = transformationMapper.GenerateModel(transformation);
+ SwapVariableWithTree(variableNode, transformationTree);
+ }
+ }
+
+ private void ApplyInverseBacktransformation(ITransformation transformation, ISymbolicExpressionTree symbolicExpressionTree) {
+ var startSymbol = symbolicExpressionTree.Root.GetSubtree(0);
+ var modelTree = startSymbol.GetSubtree(0);
+ startSymbol.RemoveSubtree(0);
+
+ var transformationTree = transformationMapper.GenerateInverseModel(transformation);
+ var variableNode = transformationTree.IterateNodesBreadth()
+ .OfType()
+ .Single(n => n.VariableName == transformation.Column);
+
+ SwapVariableWithTree(variableNode, modelTree);
+
+ startSymbol.AddSubtree(transformationTree);
+ }
+
+ private void SwapVariableWithTree(VariableTreeNode variableNode, ISymbolicExpressionTreeNode treeNode) {
+ var parent = variableNode.Parent;
+ int index = parent.IndexOfSubtree(variableNode);
+ parent.RemoveSubtree(index);
+
+ if (!variableNode.Weight.IsAlmost(1.0))
+ treeNode = CreateNodeFromWeight(treeNode, variableNode);
+
+ parent.InsertSubtree(index, treeNode);
+ }
+
+ private ISymbolicExpressionTreeNode CreateNodeFromWeight(ISymbolicExpressionTreeNode transformationTree, VariableTreeNode variableNode) {
+ var multiplicationNode = new SymbolicExpressionTreeNode(new Multiplication());
+ multiplicationNode.AddSubtree(new ConstantTreeNode(new Constant()) { Value = variableNode.Weight });
+ multiplicationNode.AddSubtree(transformationTree);
+ return multiplicationNode;
+ }
+ }
+}
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/TransformationToSymbolicTreeMapper.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/TransformationToSymbolicTreeMapper.cs (revision 15141)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/TransformationToSymbolicTreeMapper.cs (revision 15141)
@@ -0,0 +1,294 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+#endregion
+
+using System;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+ public class TransformationToSymbolicTreeMapper : ITransformationMapper {
+ private ITransformation transformation;
+ private string column;
+
+ #region ITransformationMapper Members
+
+ public ISymbolicExpressionTreeNode GenerateModel(ITransformation transformation) {
+ InitComponents(transformation);
+
+ if (transformation is LinearTransformation) {
+ return GenerateModelForLinearTransformation();
+ } else if (transformation is ExponentialTransformation) {
+ return GenerateModelForExponentialTransformation();
+ } else if (transformation is LogarithmicTransformation) {
+ return GenerateModelForLogarithmicTransformation();
+ } else if (transformation is PowerTransformation) {
+ return GenerateModelForPowerTransformation();
+ } else if (transformation is ReciprocalTransformation) {
+ return GenerateModelForReciprocalTransformation();
+ } else if (transformation is ShiftStandardDistributionTransformation) {
+ return GenerateModelForShiftStandardDistributionTransformation();
+ } else if (transformation is CopyColumnTransformation) {
+ return GenerateTreeNodeForCopyColumnTransformation();
+ }
+ throw new NotImplementedException();
+ }
+
+ public ISymbolicExpressionTreeNode GenerateInverseModel(ITransformation transformation) {
+ InitComponents(transformation);
+
+ if (transformation is LinearTransformation) {
+ return GenerateInverseModelForLinearTransformation();
+ } else if (transformation is ExponentialTransformation) {
+ return GenerateInverseModelForExponentialTransformation();
+ } else if (transformation is LogarithmicTransformation) {
+ return GenerateInverseModelForLogarithmicTransformation();
+ } else if (transformation is PowerTransformation) {
+ return GenerateInverseModelForPowerTransformation();
+ } else if (transformation is ReciprocalTransformation) {
+ return GenerateInverseModelForReciprocalTransformation();
+ } else if (transformation is ShiftStandardDistributionTransformation) {
+ GenerateInverseModelForShiftStandardDistributionTransformation();
+ } else if (transformation is CopyColumnTransformation) {
+ return GenerateTreeNodeForCopyColumnTransformation();
+ }
+
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+ // helper
+
+ private ISymbolicExpressionTreeNode GenerateModelForLinearTransformation() {
+ var linearTransformation = (LinearTransformation)transformation;
+ var kValue = linearTransformation.Multiplier;
+ var dValue = linearTransformation.Addend;
+
+ // k * x
+ var multiplicationNode = new Multiplication().CreateTreeNode();
+ var kNode = CreateConstantTreeNode("k", kValue);
+ var xNode = CreateVariableTreeNode(column, "x");
+ multiplicationNode.AddSubtree(kNode);
+ multiplicationNode.AddSubtree(xNode);
+
+ // ( k * x ) + d
+ var additionNode = new Addition().CreateTreeNode();
+ var dNode = CreateConstantTreeNode("d", dValue);
+ additionNode.AddSubtree(multiplicationNode);
+ additionNode.AddSubtree(dNode);
+
+ return additionNode;
+ }
+
+ private ISymbolicExpressionTreeNode GenerateInverseModelForLinearTransformation() {
+ var linearTransformation = (LinearTransformation)transformation;
+ var kValue = linearTransformation.Multiplier;
+ var dValue = linearTransformation.Addend;
+
+ // x - d
+ var substractionNode = new Subtraction().CreateTreeNode();
+ var dNode = CreateConstantTreeNode("d", dValue);
+ var xNode = CreateVariableTreeNode(column, "x");
+ substractionNode.AddSubtree(xNode);
+ substractionNode.AddSubtree(dNode);
+
+ // ( x - d ) / k
+ var divisionNode = new Division().CreateTreeNode();
+ var kNode = CreateConstantTreeNode("k", kValue);
+ divisionNode.AddSubtree(substractionNode);
+ divisionNode.AddSubtree(kNode);
+
+ return divisionNode;
+ }
+
+
+ private ISymbolicExpressionTreeNode GenerateModelForExponentialTransformation() {
+ var exponentialTransformation = (ExponentialTransformation)transformation;
+ var bValue = exponentialTransformation.Base;
+
+ return GenTreePow_b_x(bValue);
+ }
+
+ private ISymbolicExpressionTreeNode GenerateInverseModelForExponentialTransformation() {
+ var exponentialTransformation = (ExponentialTransformation)transformation;
+ var bValue = exponentialTransformation.Base;
+
+ return GenTreeLog_x_b(bValue);
+ }
+
+
+ private ISymbolicExpressionTreeNode GenerateModelForLogarithmicTransformation() {
+ var logarithmicTransformation = (LogarithmicTransformation)transformation;
+ var bValue = logarithmicTransformation.Base;
+
+ return GenTreeLog_x_b(bValue);
+ }
+
+ private ISymbolicExpressionTreeNode GenerateInverseModelForLogarithmicTransformation() {
+ var logarithmicTransformation = (LogarithmicTransformation)transformation;
+ var bValue = logarithmicTransformation.Base;
+
+ return GenTreePow_b_x(bValue);
+ }
+
+
+ private ISymbolicExpressionTreeNode GenerateModelForPowerTransformation() {
+ var powerTransformation = (PowerTransformation)transformation;
+ var expValue = powerTransformation.Exponent;
+
+ // x ^ exp
+ var powerNode = new Power().CreateTreeNode();
+ var xNode = CreateVariableTreeNode(column, "x");
+ var expNode = CreateConstantTreeNode("exp", expValue);
+ powerNode.AddSubtree(xNode);
+ powerNode.AddSubtree(expNode);
+
+ return powerNode;
+ }
+
+ private ISymbolicExpressionTreeNode GenerateInverseModelForPowerTransformation() {
+ var powerTransformation = (PowerTransformation)transformation;
+ var expValue = powerTransformation.Exponent;
+
+ // rt(x, b)
+ var rootNode = new Root().CreateTreeNode();
+ var xNode = CreateVariableTreeNode(column, "x");
+ var bNode = CreateConstantTreeNode("b", expValue);
+ rootNode.AddSubtree(xNode);
+ rootNode.AddSubtree(bNode);
+
+ return rootNode;
+ }
+
+
+ private ISymbolicExpressionTreeNode GenerateModelForReciprocalTransformation() {
+ return GenTreeDiv_1_x();
+ }
+
+ private ISymbolicExpressionTreeNode GenerateInverseModelForReciprocalTransformation() {
+ return GenTreeDiv_1_x();
+ }
+
+
+ private ISymbolicExpressionTreeNode GenerateModelForShiftStandardDistributionTransformation() {
+ var shiftStandardDistributionTransformation = (ShiftStandardDistributionTransformation)transformation;
+ var m_orgValue = shiftStandardDistributionTransformation.OriginalMean;
+ var s_orgValue = shiftStandardDistributionTransformation.OriginalStandardDeviation;
+ var m_tarValue = shiftStandardDistributionTransformation.Mean;
+ var s_tarValue = shiftStandardDistributionTransformation.StandardDeviation;
+
+ return GenTreeShiftStdDist(column, m_orgValue, s_orgValue, m_tarValue, s_tarValue);
+ }
+
+ private ISymbolicExpressionTreeNode GenerateInverseModelForShiftStandardDistributionTransformation() {
+ var shiftStandardDistributionTransformation = (ShiftStandardDistributionTransformation)transformation;
+ var m_orgValue = shiftStandardDistributionTransformation.OriginalMean;
+ var s_orgValue = shiftStandardDistributionTransformation.OriginalStandardDeviation;
+ var m_tarValue = shiftStandardDistributionTransformation.Mean;
+ var s_tarValue = shiftStandardDistributionTransformation.StandardDeviation;
+
+ return GenTreeShiftStdDist(column, m_tarValue, s_tarValue, m_orgValue, s_orgValue);
+ }
+
+ private ISymbolicExpressionTreeNode GenerateTreeNodeForCopyColumnTransformation() {
+ var copyColumnTransformation = (CopyColumnTransformation)transformation;
+ var copiedColumnName = copyColumnTransformation.CopiedColumnName;
+
+ return CreateVariableTreeNode(copiedColumnName, copiedColumnName + "(original)");
+ }
+
+ // helper's helper:
+
+ private ISymbolicExpressionTreeNode GenTreeLog_x_b(double b) {
+ // log(x, b)
+ var logNode = new Logarithm().CreateTreeNode();
+ var bNode = CreateConstantTreeNode("b", b);
+ var xNode = CreateVariableTreeNode(column, "x");
+ logNode.AddSubtree(xNode);
+ logNode.AddSubtree(bNode);
+
+ return logNode;
+ }
+
+ private ISymbolicExpressionTreeNode GenTreePow_b_x(double b) {
+ // b ^ x
+ var powerNode = new Power().CreateTreeNode();
+ var bNode = CreateConstantTreeNode("b", b);
+ var xNode = CreateVariableTreeNode(column, "x");
+ powerNode.AddSubtree(bNode);
+ powerNode.AddSubtree(xNode);
+
+ return powerNode;
+ }
+
+ private ISymbolicExpressionTreeNode GenTreeDiv_1_x() {
+ // 1 / x
+ var divNode = new Division().CreateTreeNode();
+ var oneNode = CreateConstantTreeNode("1", 1.0);
+ var xNode = CreateVariableTreeNode(column, "x");
+ divNode.AddSubtree(oneNode);
+ divNode.AddSubtree(xNode);
+
+ return divNode;
+ }
+
+ private ISymbolicExpressionTreeNode GenTreeShiftStdDist(string variable, double m_org, double s_org, double m_tar, double s_tar) {
+ // x - m_org
+ var substractionNode = new Subtraction().CreateTreeNode();
+ var xNode = CreateVariableTreeNode(variable, "x");
+ var m_orgNode = CreateConstantTreeNode("m_org", m_org);
+ substractionNode.AddSubtree(xNode);
+ substractionNode.AddSubtree(m_orgNode);
+
+ // (x - m_org) / s_org
+ var divisionNode = new Division().CreateTreeNode();
+ var s_orgNode = CreateConstantTreeNode("s_org", s_org);
+ divisionNode.AddSubtree(substractionNode);
+ divisionNode.AddSubtree(s_orgNode);
+
+ // ((x - m_org) / s_org ) * s_tar
+ var multiplicationNode = new Multiplication().CreateTreeNode();
+ var s_tarNode = CreateConstantTreeNode("s_tar", s_tar);
+ multiplicationNode.AddSubtree(divisionNode);
+ multiplicationNode.AddSubtree(s_tarNode);
+
+ // ((x - m_org) / s_org ) * s_tar + m_tar
+ var additionNode = new Addition().CreateTreeNode();
+ var m_tarNode = CreateConstantTreeNode("m_tar", m_tar);
+ additionNode.AddSubtree(multiplicationNode);
+ additionNode.AddSubtree(m_tarNode);
+
+ return additionNode;
+ }
+
+ private ConstantTreeNode CreateConstantTreeNode(string description, double value) {
+ return new ConstantTreeNode(new Constant()) { Value = value };
+ }
+
+ private VariableTreeNode CreateVariableTreeNode(string name, string description) {
+ return new VariableTreeNode(new Variable(name, description)) { VariableName = name, Weight = 1.0 };
+ }
+
+ private void InitComponents(ITransformation transformation) {
+ this.transformation = transformation;
+ column = transformation.Column;
+ }
+ }
+}
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/TreeToAutoDiffTermTransformator.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/TreeToAutoDiffTermTransformator.cs (revision 15141)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Transformation/TreeToAutoDiffTermTransformator.cs (revision 15141)
@@ -0,0 +1,384 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AutoDiff;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+ public class TreeToAutoDiffTermTransformator {
+ public delegate double ParametricFunction(double[] vars, double[] @params);
+ public delegate Tuple ParametricFunctionGradient(double[] vars, double[] @params);
+
+ #region helper class
+ public class DataForVariable {
+ public readonly string variableName;
+ public readonly string variableValue; // for factor vars
+ public readonly int lag;
+
+ public DataForVariable(string varName, string varValue, int lag) {
+ this.variableName = varName;
+ this.variableValue = varValue;
+ this.lag = lag;
+ }
+
+ public override bool Equals(object obj) {
+ var other = obj as DataForVariable;
+ if (other == null) return false;
+ return other.variableName.Equals(this.variableName) &&
+ other.variableValue.Equals(this.variableValue) &&
+ other.lag == this.lag;
+ }
+
+ public override int GetHashCode() {
+ return variableName.GetHashCode() ^ variableValue.GetHashCode() ^ lag;
+ }
+ }
+ #endregion
+
+ #region derivations of functions
+ // create function factory for arctangent
+ private static readonly Func arctan = UnaryFunc.Factory(
+ eval: Math.Atan,
+ diff: x => 1 / (1 + x * x));
+ private static readonly Func sin = UnaryFunc.Factory(
+ eval: Math.Sin,
+ diff: Math.Cos);
+ private static readonly Func cos = UnaryFunc.Factory(
+ eval: Math.Cos,
+ diff: x => -Math.Sin(x));
+ private static readonly Func tan = UnaryFunc.Factory(
+ eval: Math.Tan,
+ diff: x => 1 + Math.Tan(x) * Math.Tan(x));
+ private static readonly Func erf = UnaryFunc.Factory(
+ eval: alglib.errorfunction,
+ diff: x => 2.0 * Math.Exp(-(x * x)) / Math.Sqrt(Math.PI));
+ private static readonly Func norm = UnaryFunc.Factory(
+ eval: alglib.normaldistribution,
+ diff: x => -(Math.Exp(-(x * x)) * Math.Sqrt(Math.Exp(x * x)) * x) / Math.Sqrt(2 * Math.PI));
+
+ #endregion
+
+ public static bool TryTransformToAutoDiff(ISymbolicExpressionTree tree, bool makeVariableWeightsVariable,
+ out List parameters, out double[] initialConstants,
+ out ParametricFunction func,
+ out ParametricFunctionGradient func_grad) {
+
+ // use a transformator object which holds the state (variable list, parameter list, ...) for recursive transformation of the tree
+ var transformator = new TreeToAutoDiffTermTransformator(makeVariableWeightsVariable);
+ AutoDiff.Term term;
+ var success = transformator.TryTransformToAutoDiff(tree.Root.GetSubtree(0), out term);
+ if (success) {
+ var parameterEntries = transformator.parameters.ToArray(); // guarantee same order for keys and values
+ var compiledTerm = term.Compile(transformator.variables.ToArray(), parameterEntries.Select(kvp => kvp.Value).ToArray());
+ parameters = new List(parameterEntries.Select(kvp => kvp.Key));
+ initialConstants = transformator.initialConstants.ToArray();
+ func = (vars, @params) => compiledTerm.Evaluate(vars, @params);
+ func_grad = (vars, @params) => compiledTerm.Differentiate(vars, @params);
+ } else {
+ func = null;
+ func_grad = null;
+ parameters = null;
+ initialConstants = null;
+ }
+ return success;
+ }
+
+ // state for recursive transformation of trees
+ private readonly List variableNames;
+ private readonly List lags;
+ private readonly List initialConstants;
+ private readonly Dictionary parameters;
+ private readonly List variables;
+ private readonly bool makeVariableWeightsVariable;
+
+ private TreeToAutoDiffTermTransformator(bool makeVariableWeightsVariable) {
+ this.makeVariableWeightsVariable = makeVariableWeightsVariable;
+ this.variableNames = new List();
+ this.lags = new List();
+ this.initialConstants = new List();
+ this.parameters = new Dictionary();
+ this.variables = new List();
+ }
+
+ private bool TryTransformToAutoDiff(ISymbolicExpressionTreeNode node, out AutoDiff.Term term) {
+ if (node.Symbol is Constant) {
+ initialConstants.Add(((ConstantTreeNode)node).Value);
+ var var = new AutoDiff.Variable();
+ variables.Add(var);
+ term = var;
+ return true;
+ }
+ if (node.Symbol is Variable || node.Symbol is BinaryFactorVariable) {
+ var varNode = node as VariableTreeNode;
+ var factorVarNode = node as BinaryFactorVariableTreeNode;
+ // factor variable values are only 0 or 1 and set in x accordingly
+ var varValue = factorVarNode != null ? factorVarNode.VariableValue : string.Empty;
+ var par = FindOrCreateParameter(parameters, varNode.VariableName, varValue);
+
+ if (makeVariableWeightsVariable) {
+ initialConstants.Add(varNode.Weight);
+ var w = new AutoDiff.Variable();
+ variables.Add(w);
+ term = AutoDiff.TermBuilder.Product(w, par);
+ } else {
+ term = varNode.Weight * par;
+ }
+ return true;
+ }
+ if (node.Symbol is FactorVariable) {
+ var factorVarNode = node as FactorVariableTreeNode;
+ var products = new List();
+ foreach (var variableValue in factorVarNode.Symbol.GetVariableValues(factorVarNode.VariableName)) {
+ var par = FindOrCreateParameter(parameters, factorVarNode.VariableName, variableValue);
+
+ initialConstants.Add(factorVarNode.GetValue(variableValue));
+ var wVar = new AutoDiff.Variable();
+ variables.Add(wVar);
+
+ products.Add(AutoDiff.TermBuilder.Product(wVar, par));
+ }
+ term = AutoDiff.TermBuilder.Sum(products);
+ return true;
+ }
+ if (node.Symbol is LaggedVariable) {
+ var varNode = node as LaggedVariableTreeNode;
+ var par = FindOrCreateParameter(parameters, varNode.VariableName, string.Empty, varNode.Lag);
+
+ if (makeVariableWeightsVariable) {
+ initialConstants.Add(varNode.Weight);
+ var w = new AutoDiff.Variable();
+ variables.Add(w);
+ term = AutoDiff.TermBuilder.Product(w, par);
+ } else {
+ term = varNode.Weight * par;
+ }
+ return true;
+ }
+ if (node.Symbol is Addition) {
+ List terms = new List();
+ foreach (var subTree in node.Subtrees) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(subTree, out t)) {
+ term = null;
+ return false;
+ }
+ terms.Add(t);
+ }
+ term = AutoDiff.TermBuilder.Sum(terms);
+ return true;
+ }
+ if (node.Symbol is Subtraction) {
+ List terms = new List();
+ for (int i = 0; i < node.SubtreeCount; i++) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(i), out t)) {
+ term = null;
+ return false;
+ }
+ if (i > 0) t = -t;
+ terms.Add(t);
+ }
+ if (terms.Count == 1) term = -terms[0];
+ else term = AutoDiff.TermBuilder.Sum(terms);
+ return true;
+ }
+ if (node.Symbol is Multiplication) {
+ List terms = new List();
+ foreach (var subTree in node.Subtrees) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(subTree, out t)) {
+ term = null;
+ return false;
+ }
+ terms.Add(t);
+ }
+ if (terms.Count == 1) term = terms[0];
+ else term = terms.Aggregate((a, b) => new AutoDiff.Product(a, b));
+ return true;
+
+ }
+ if (node.Symbol is Division) {
+ List terms = new List();
+ foreach (var subTree in node.Subtrees) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(subTree, out t)) {
+ term = null;
+ return false;
+ }
+ terms.Add(t);
+ }
+ if (terms.Count == 1) term = 1.0 / terms[0];
+ else term = terms.Aggregate((a, b) => new AutoDiff.Product(a, 1.0 / b));
+ return true;
+ }
+ if (node.Symbol is Logarithm) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = AutoDiff.TermBuilder.Log(t);
+ return true;
+ }
+ }
+ if (node.Symbol is Exponential) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = AutoDiff.TermBuilder.Exp(t);
+ return true;
+ }
+ }
+ if (node.Symbol is Square) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = AutoDiff.TermBuilder.Power(t, 2.0);
+ return true;
+ }
+ }
+ if (node.Symbol is SquareRoot) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = AutoDiff.TermBuilder.Power(t, 0.5);
+ return true;
+ }
+ }
+ if (node.Symbol is Sine) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = sin(t);
+ return true;
+ }
+ }
+ if (node.Symbol is Cosine) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = cos(t);
+ return true;
+ }
+ }
+ if (node.Symbol is Tangent) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = tan(t);
+ return true;
+ }
+ }
+ if (node.Symbol is Erf) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = erf(t);
+ return true;
+ }
+ }
+ if (node.Symbol is Norm) {
+ AutoDiff.Term t;
+ if (!TryTransformToAutoDiff(node.GetSubtree(0), out t)) {
+ term = null;
+ return false;
+ } else {
+ term = norm(t);
+ return true;
+ }
+ }
+ if (node.Symbol is StartSymbol) {
+ var alpha = new AutoDiff.Variable();
+ var beta = new AutoDiff.Variable();
+ variables.Add(beta);
+ variables.Add(alpha);
+ AutoDiff.Term branchTerm;
+ if (TryTransformToAutoDiff(node.GetSubtree(0), out branchTerm)) {
+ term = branchTerm * alpha + beta;
+ return true;
+ } else {
+ term = null;
+ return false;
+ }
+ }
+ term = null;
+ return false;
+ }
+
+
+ // for each factor variable value we need a parameter which represents a binary indicator for that variable & value combination
+ // each binary indicator is only necessary once. So we only create a parameter if this combination is not yet available
+ private static Term FindOrCreateParameter(Dictionary parameters,
+ string varName, string varValue = "", int lag = 0) {
+ var data = new DataForVariable(varName, varValue, lag);
+
+ AutoDiff.Variable par = null;
+ if (!parameters.TryGetValue(data, out par)) {
+ // not found -> create new parameter and entries in names and values lists
+ par = new AutoDiff.Variable();
+ parameters.Add(data, par);
+ }
+ return par;
+ }
+
+ public static bool IsCompatible(ISymbolicExpressionTree tree) {
+ var containsUnknownSymbol = (
+ from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
+ where
+ !(n.Symbol is Variable) &&
+ !(n.Symbol is LaggedVariable) &&
+ !(n.Symbol is Constant) &&
+ !(n.Symbol is Addition) &&
+ !(n.Symbol is Subtraction) &&
+ !(n.Symbol is Multiplication) &&
+ !(n.Symbol is Division) &&
+ !(n.Symbol is Logarithm) &&
+ !(n.Symbol is Exponential) &&
+ !(n.Symbol is SquareRoot) &&
+ !(n.Symbol is Square) &&
+ !(n.Symbol is Sine) &&
+ !(n.Symbol is Cosine) &&
+ !(n.Symbol is Tangent) &&
+ !(n.Symbol is Erf) &&
+ !(n.Symbol is Norm) &&
+ !(n.Symbol is StartSymbol)
+ select n).Any();
+ return !containsUnknownSymbol;
+ }
+ }
+}
Index: able/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TransformationToSymbolicTreeMapper.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TransformationToSymbolicTreeMapper.cs (revision 15140)
+++ (revision )
@@ -1,294 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see .
- */
-#endregion
-
-using System;
-using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-
-namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
- public class TransformationToSymbolicTreeMapper : ITransformationMapper {
- private ITransformation transformation;
- private string column;
-
- #region ITransformationMapper Members
-
- public ISymbolicExpressionTreeNode GenerateModel(ITransformation transformation) {
- InitComponents(transformation);
-
- if (transformation is LinearTransformation) {
- return GenerateModelForLinearTransformation();
- } else if (transformation is ExponentialTransformation) {
- return GenerateModelForExponentialTransformation();
- } else if (transformation is LogarithmicTransformation) {
- return GenerateModelForLogarithmicTransformation();
- } else if (transformation is PowerTransformation) {
- return GenerateModelForPowerTransformation();
- } else if (transformation is ReciprocalTransformation) {
- return GenerateModelForReciprocalTransformation();
- } else if (transformation is ShiftStandardDistributionTransformation) {
- return GenerateModelForShiftStandardDistributionTransformation();
- } else if (transformation is CopyColumnTransformation) {
- return GenerateTreeNodeForCopyColumnTransformation();
- }
- throw new NotImplementedException();
- }
-
- public ISymbolicExpressionTreeNode GenerateInverseModel(ITransformation transformation) {
- InitComponents(transformation);
-
- if (transformation is LinearTransformation) {
- return GenerateInverseModelForLinearTransformation();
- } else if (transformation is ExponentialTransformation) {
- return GenerateInverseModelForExponentialTransformation();
- } else if (transformation is LogarithmicTransformation) {
- return GenerateInverseModelForLogarithmicTransformation();
- } else if (transformation is PowerTransformation) {
- return GenerateInverseModelForPowerTransformation();
- } else if (transformation is ReciprocalTransformation) {
- return GenerateInverseModelForReciprocalTransformation();
- } else if (transformation is ShiftStandardDistributionTransformation) {
- GenerateInverseModelForShiftStandardDistributionTransformation();
- } else if (transformation is CopyColumnTransformation) {
- return GenerateTreeNodeForCopyColumnTransformation();
- }
-
- throw new NotImplementedException();
- }
-
- #endregion
-
- // helper
-
- private ISymbolicExpressionTreeNode GenerateModelForLinearTransformation() {
- var linearTransformation = (LinearTransformation)transformation;
- var kValue = linearTransformation.Multiplier;
- var dValue = linearTransformation.Addend;
-
- // k * x
- var multiplicationNode = new Multiplication().CreateTreeNode();
- var kNode = CreateConstantTreeNode("k", kValue);
- var xNode = CreateVariableTreeNode(column, "x");
- multiplicationNode.AddSubtree(kNode);
- multiplicationNode.AddSubtree(xNode);
-
- // ( k * x ) + d
- var additionNode = new Addition().CreateTreeNode();
- var dNode = CreateConstantTreeNode("d", dValue);
- additionNode.AddSubtree(multiplicationNode);
- additionNode.AddSubtree(dNode);
-
- return additionNode;
- }
-
- private ISymbolicExpressionTreeNode GenerateInverseModelForLinearTransformation() {
- var linearTransformation = (LinearTransformation)transformation;
- var kValue = linearTransformation.Multiplier;
- var dValue = linearTransformation.Addend;
-
- // x - d
- var substractionNode = new Subtraction().CreateTreeNode();
- var dNode = CreateConstantTreeNode("d", dValue);
- var xNode = CreateVariableTreeNode(column, "x");
- substractionNode.AddSubtree(xNode);
- substractionNode.AddSubtree(dNode);
-
- // ( x - d ) / k
- var divisionNode = new Division().CreateTreeNode();
- var kNode = CreateConstantTreeNode("k", kValue);
- divisionNode.AddSubtree(substractionNode);
- divisionNode.AddSubtree(kNode);
-
- return divisionNode;
- }
-
-
- private ISymbolicExpressionTreeNode GenerateModelForExponentialTransformation() {
- var exponentialTransformation = (ExponentialTransformation)transformation;
- var bValue = exponentialTransformation.Base;
-
- return GenTreePow_b_x(bValue);
- }
-
- private ISymbolicExpressionTreeNode GenerateInverseModelForExponentialTransformation() {
- var exponentialTransformation = (ExponentialTransformation)transformation;
- var bValue = exponentialTransformation.Base;
-
- return GenTreeLog_x_b(bValue);
- }
-
-
- private ISymbolicExpressionTreeNode GenerateModelForLogarithmicTransformation() {
- var logarithmicTransformation = (LogarithmicTransformation)transformation;
- var bValue = logarithmicTransformation.Base;
-
- return GenTreeLog_x_b(bValue);
- }
-
- private ISymbolicExpressionTreeNode GenerateInverseModelForLogarithmicTransformation() {
- var logarithmicTransformation = (LogarithmicTransformation)transformation;
- var bValue = logarithmicTransformation.Base;
-
- return GenTreePow_b_x(bValue);
- }
-
-
- private ISymbolicExpressionTreeNode GenerateModelForPowerTransformation() {
- var powerTransformation = (PowerTransformation)transformation;
- var expValue = powerTransformation.Exponent;
-
- // x ^ exp
- var powerNode = new Power().CreateTreeNode();
- var xNode = CreateVariableTreeNode(column, "x");
- var expNode = CreateConstantTreeNode("exp", expValue);
- powerNode.AddSubtree(xNode);
- powerNode.AddSubtree(expNode);
-
- return powerNode;
- }
-
- private ISymbolicExpressionTreeNode GenerateInverseModelForPowerTransformation() {
- var powerTransformation = (PowerTransformation)transformation;
- var expValue = powerTransformation.Exponent;
-
- // rt(x, b)
- var rootNode = new Root().CreateTreeNode();
- var xNode = CreateVariableTreeNode(column, "x");
- var bNode = CreateConstantTreeNode("b", expValue);
- rootNode.AddSubtree(xNode);
- rootNode.AddSubtree(bNode);
-
- return rootNode;
- }
-
-
- private ISymbolicExpressionTreeNode GenerateModelForReciprocalTransformation() {
- return GenTreeDiv_1_x();
- }
-
- private ISymbolicExpressionTreeNode GenerateInverseModelForReciprocalTransformation() {
- return GenTreeDiv_1_x();
- }
-
-
- private ISymbolicExpressionTreeNode GenerateModelForShiftStandardDistributionTransformation() {
- var shiftStandardDistributionTransformation = (ShiftStandardDistributionTransformation)transformation;
- var m_orgValue = shiftStandardDistributionTransformation.OriginalMean;
- var s_orgValue = shiftStandardDistributionTransformation.OriginalStandardDeviation;
- var m_tarValue = shiftStandardDistributionTransformation.Mean;
- var s_tarValue = shiftStandardDistributionTransformation.StandardDeviation;
-
- return GenTreeShiftStdDist(column, m_orgValue, s_orgValue, m_tarValue, s_tarValue);
- }
-
- private ISymbolicExpressionTreeNode GenerateInverseModelForShiftStandardDistributionTransformation() {
- var shiftStandardDistributionTransformation = (ShiftStandardDistributionTransformation)transformation;
- var m_orgValue = shiftStandardDistributionTransformation.OriginalMean;
- var s_orgValue = shiftStandardDistributionTransformation.OriginalStandardDeviation;
- var m_tarValue = shiftStandardDistributionTransformation.Mean;
- var s_tarValue = shiftStandardDistributionTransformation.StandardDeviation;
-
- return GenTreeShiftStdDist(column, m_tarValue, s_tarValue, m_orgValue, s_orgValue);
- }
-
- private ISymbolicExpressionTreeNode GenerateTreeNodeForCopyColumnTransformation() {
- var copyColumnTransformation = (CopyColumnTransformation)transformation;
- var copiedColumnName = copyColumnTransformation.CopiedColumnName;
-
- return CreateVariableTreeNode(copiedColumnName, copiedColumnName + "(original)");
- }
-
- // helper's helper:
-
- private ISymbolicExpressionTreeNode GenTreeLog_x_b(double b) {
- // log(x, b)
- var logNode = new Logarithm().CreateTreeNode();
- var bNode = CreateConstantTreeNode("b", b);
- var xNode = CreateVariableTreeNode(column, "x");
- logNode.AddSubtree(xNode);
- logNode.AddSubtree(bNode);
-
- return logNode;
- }
-
- private ISymbolicExpressionTreeNode GenTreePow_b_x(double b) {
- // b ^ x
- var powerNode = new Power().CreateTreeNode();
- var bNode = CreateConstantTreeNode("b", b);
- var xNode = CreateVariableTreeNode(column, "x");
- powerNode.AddSubtree(bNode);
- powerNode.AddSubtree(xNode);
-
- return powerNode;
- }
-
- private ISymbolicExpressionTreeNode GenTreeDiv_1_x() {
- // 1 / x
- var divNode = new Division().CreateTreeNode();
- var oneNode = CreateConstantTreeNode("1", 1.0);
- var xNode = CreateVariableTreeNode(column, "x");
- divNode.AddSubtree(oneNode);
- divNode.AddSubtree(xNode);
-
- return divNode;
- }
-
- private ISymbolicExpressionTreeNode GenTreeShiftStdDist(string variable, double m_org, double s_org, double m_tar, double s_tar) {
- // x - m_org
- var substractionNode = new Subtraction().CreateTreeNode();
- var xNode = CreateVariableTreeNode(variable, "x");
- var m_orgNode = CreateConstantTreeNode("m_org", m_org);
- substractionNode.AddSubtree(xNode);
- substractionNode.AddSubtree(m_orgNode);
-
- // (x - m_org) / s_org
- var divisionNode = new Division().CreateTreeNode();
- var s_orgNode = CreateConstantTreeNode("s_org", s_org);
- divisionNode.AddSubtree(substractionNode);
- divisionNode.AddSubtree(s_orgNode);
-
- // ((x - m_org) / s_org ) * s_tar
- var multiplicationNode = new Multiplication().CreateTreeNode();
- var s_tarNode = CreateConstantTreeNode("s_tar", s_tar);
- multiplicationNode.AddSubtree(divisionNode);
- multiplicationNode.AddSubtree(s_tarNode);
-
- // ((x - m_org) / s_org ) * s_tar + m_tar
- var additionNode = new Addition().CreateTreeNode();
- var m_tarNode = CreateConstantTreeNode("m_tar", m_tar);
- additionNode.AddSubtree(multiplicationNode);
- additionNode.AddSubtree(m_tarNode);
-
- return additionNode;
- }
-
- private ConstantTreeNode CreateConstantTreeNode(string description, double value) {
- return new ConstantTreeNode(new Constant()) { Value = value };
- }
-
- private VariableTreeNode CreateVariableTreeNode(string name, string description) {
- return new VariableTreeNode(new Variable(name, description)) { VariableName = name, Weight = 1.0 };
- }
-
- private void InitComponents(ITransformation transformation) {
- this.transformation = transformation;
- column = transformation.Column;
- }
- }
-}