Changeset 16344


Ignore:
Timestamp:
12/06/18 18:59:09 (12 days ago)
Author:
gkronber
Message:

#2915: added a unit test cases for simplification of new symbols and extended the tree simplifier accordingly.

Location:
branches/2915-AbsoluteSymbol
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/2915-AbsoluteSymbol/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs

    r16240 r16344  
    263263      if (IsConstant(original) || IsVariableBase(original)) {
    264264        return (ISymbolicExpressionTreeNode)original.Clone();
     265      } else if (IsAbsolute(original)) {
     266        return SimplifyAbsolute(original);
    265267      } else if (IsAddition(original)) {
    266268        return SimplifyAddition(original);
     
    771773      } else if (IsSquareRoot(node)) {
    772774        return node.GetSubtree(0);
     775      } else if (IsMultiplication(node)) {
     776        // sqr( x * y ) = sqr(x) * sqr(y)
     777        var mulNode = mulSymbol.CreateTreeNode();
     778        foreach (var subtree in node.Subtrees) {
     779          mulNode.AddSubtree(MakeSquare(subtree));
     780        }
     781        return mulNode;
     782      } else if (IsAbsolute(node)) {
     783        return MakeSquare(node.GetSubtree(0)); // sqr(abs(x)) = sqr(x)
     784      } else if (IsExp(node)) {
     785        return MakeExp(MakeProduct(node.GetSubtree(0), MakeConstant(2.0))); // sqr(exp(x)) = exp(2x)
     786      } else if (IsCube(node)) {
     787        return MakePower(node.GetSubtree(0), MakeConstant(6));
    773788      } else {
    774789        var sqrNode = sqrSymbol.CreateTreeNode();
     
    790805      } else if (IsCubeRoot(node)) {
    791806        return node.GetSubtree(0); // NOTE: not really accurate because cuberoot(x) with negative x is evaluated to NaN and after this simplification we evaluate as x
     807      } else if (IsExp(node)) {
     808        return MakeExp(MakeProduct(node.GetSubtree(0), MakeConstant(3)));
     809      } else if (IsSquare(node)) {
     810        return MakePower(node.GetSubtree(0), MakeConstant(6));
    792811      } else {
    793812        var cubeNode = cubeSymbol.CreateTreeNode();
     
    807826        var binFactor = node as BinaryFactorVariableTreeNode;
    808827        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Abs(binFactor.Weight));
     828      } else if (IsSquare(node) || IsExp(node) || IsSquareRoot(node) || IsCubeRoot(node)) {
     829        return node; // abs(sqr(x)) = sqr(x), abs(exp(x)) = exp(x) ...
     830      } else if (IsMultiplication(node)) {
     831        var mul = mulSymbol.CreateTreeNode();
     832        foreach (var st in node.Subtrees) {
     833          mul.AddSubtree(MakeAbs(st));
     834        }
     835        return mul;
     836      } else if (IsDivision(node)) {
     837        var div = divSymbol.CreateTreeNode();
     838        foreach (var st in node.Subtrees) {
     839          div.AddSubtree(MakeAbs(st));
     840        }
     841        return div;
    809842      } else {
    810843        var absNode = absSymbol.CreateTreeNode();
     
    815848
    816849    // constant folding only
    817     private static ISymbolicExpressionTreeNode MakeAnalyticalQuotient(ISymbolicExpressionTreeNode x1, ISymbolicExpressionTreeNode x2) {
    818       if (IsConstant(x2)) {
    819         var c = x2 as ConstantTreeNode;
    820         return MakeFraction(x1, MakeConstant(Math.Sqrt(1.0 + c.Value*c.Value)));
    821       } else if (IsFactor(x2)) {
    822         var factNode = x2 as FactorVariableTreeNode;
    823         return MakeFraction(x1, MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(1.0 + w * w))));
    824       } else if (IsBinFactor(x2)) {
    825         var binFactor = x2 as BinaryFactorVariableTreeNode;
    826         return MakeFraction(x1, MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(1.0 + binFactor.Weight * binFactor.Weight)));
     850    private static ISymbolicExpressionTreeNode MakeAnalyticalQuotient(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
     851      if (IsConstant(b)) {
     852        var c = b as ConstantTreeNode;
     853        return MakeFraction(a, MakeConstant(Math.Sqrt(1.0 + c.Value * c.Value)));
     854      } else if (IsFactor(b)) {
     855        var factNode = b as FactorVariableTreeNode;
     856        return MakeFraction(a, MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(1.0 + w * w))));
     857      } else if (IsBinFactor(b)) {
     858        var binFactor = b as BinaryFactorVariableTreeNode;
     859        return MakeFraction(a, MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(1.0 + binFactor.Weight * binFactor.Weight)));
    827860      } else {
    828861        var aqNode = aqSymbol.CreateTreeNode();
    829         aqNode.AddSubtree(x1);
    830         aqNode.AddSubtree(x2);
     862        aqNode.AddSubtree(a);
     863        aqNode.AddSubtree(b);
    831864        return aqNode;
    832865      }
     
    10421075        // a / (b1 / b2) => (a * b2) / b1
    10431076        return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
     1077      } else if (IsAnalyticalQuotient(a)) {
     1078        return MakeAnalyticalQuotient(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
    10441079      } else {
    10451080        var div = divSymbol.CreateTreeNode();
     
    12701305        MergeVariablesAndConstantsInProduct(a);
    12711306        return a;
     1307      } else if (IsAbsolute(a) && IsAbsolute(b)) {
     1308        return MakeAbs(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)));
     1309      } else if (IsAbsolute(a) && IsConstant(b)) {
     1310        var constNode = b as ConstantTreeNode;
     1311        var posF = Math.Abs(constNode.Value);
     1312        if (constNode.Value > 0) {
     1313          return MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF)));
     1314        } else {
     1315          var mul = mulSymbol.CreateTreeNode();
     1316          mul.AddSubtree(MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF))));
     1317          mul.AddSubtree(MakeConstant(-1.0));
     1318          return mul;
     1319        }
     1320      } else if (IsAnalyticalQuotient(a)) {
     1321        return MakeAnalyticalQuotient(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
    12721322      } else {
    12731323        var mul = mulSymbol.CreateTreeNode();
  • branches/2915-AbsoluteSymbol/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeSimplifierTest.cs

    r15583 r16344  
    228228      AssertEqualAfterSimplification("(- (factor a 2.0 3.0) (binfactor a x0 2.0))", "(factor a 0.0 3.0)");
    229229      #endregion
     230
     231      #region abs
     232      AssertEqualAfterSimplification("(abs 2.0)", "2.0");
     233      AssertEqualAfterSimplification("(abs -2.0)", "2.0"); // constant folding
     234      AssertEqualAfterSimplification("(abs (exp (variable 2.0 x)))", "(exp (variable 2.0 x)))"); // exp is always positive
     235      AssertEqualAfterSimplification("(abs (exp (variable 2.0 x)))", "(exp (variable 2.0 x)))"); // exp is always positive
     236      AssertEqualAfterSimplification("(abs (sqr (variable 2.0 a)))", "(sqr (variable 2.0 a))"); // sqr is always positive
     237      AssertEqualAfterSimplification("(abs (sqrt (variable 2.0 a)))", "(sqrt (variable 2.0 a))"); // sqrt is always positive (for our cases)
     238      AssertEqualAfterSimplification("(abs (cuberoot (variable 2.0 a)))", "(cuberoot (variable 2.0 a))"); // cuberoot is always positive (for our cases)
     239
     240      AssertEqualAfterSimplification("(* (abs (variable 2.0 x)) 2.0)", "(abs (variable 4.0 x))");  // can multiply positive constants into abs
     241      AssertEqualAfterSimplification("(* (abs (variable 2.0 x)) -2.0)", "(* (abs (variable 4.0 x)) -1.0)"); // for negative constants keep the sign
     242
     243      AssertEqualAfterSimplification("(abs (* (variable 1.0 a) (variable 2.0 b)))", "(* (abs (variable 1.0 a)) (abs (variable 1.0 b)) 2.0))");
     244      AssertEqualAfterSimplification("(abs (/ (variable 1.0 a) (variable 2.0 b)))", "(/ (abs (variable 1.0 a)) (abs (variable 2.0 b))))");
     245      #endregion
     246
     247      #region square and sqrt
     248      AssertEqualAfterSimplification("(sqr (sqrt (variable 2.0 x)))", "(variable 2.0 x)");
     249      AssertEqualAfterSimplification("(sqrt (sqr (variable 2.0 x)))", "(variable 2.0 x)");
     250      AssertEqualAfterSimplification("(sqr (abs (variable 2.0 a)))", "(sqr (variable 2.0 a))");
     251      AssertEqualAfterSimplification("(sqr (exp (variable 2.0 x)))", "(exp (variable 4.0 x))");
     252
     253      AssertEqualAfterSimplification("(sqr (* (variable 2.0 a) (variable 3.0 b) (variable 4.0 c)))",
     254        "(* (sqr (variable 1.0 a)) (sqr (variable 1.0 b)) (sqr (variable 1.0 c)) 576)"); // 2²*3²*4²
     255      #endregion
     256
     257      #region cube and cuberoot
     258      AssertEqualAfterSimplification("(cube (cuberoot (variable 2.0 x)))", "(variable 2.0 x)");
     259      AssertEqualAfterSimplification("(cuberoot (cube (variable 2.0 x)))", "(variable 2.0 x)");
     260      AssertEqualAfterSimplification("(cube (exp (variable 2.0 x)))", "(exp (variable 6.0 x))");
     261
     262      AssertEqualAfterSimplification("(sqr (cube (variable 2.0 x)))", "(pow (variable 2.0 x) 6)");
     263      AssertEqualAfterSimplification("(cube (sqr (variable 2.0 x)))", "(pow (variable 2.0 x) 6)");
     264      #endregion
     265
     266      #region AQ
     267      AssertEqualAfterSimplification("(* (aq (variable 1.0 x) (variable 1.0 y)) 2.0)", "(aq (variable 2.0 x) (variable 1.0 y))");
     268      AssertEqualAfterSimplification("(/ (aq (variable 1.0 x) (variable 1.0 y)) 2.0)", "(aq (variable 0.5 x) (variable 1.0 y))");
     269
     270      #endregion
    230271    }
    231272
Note: See TracChangeset for help on using the changeset viewer.