Changeset 17212


Ignore:
Timestamp:
08/13/19 13:41:21 (10 days ago)
Author:
gkronber
Message:

#2994: fixed division, multiplication and cos for intervals based on failing tests

Location:
branches/2994-AutoDiffForIntervals
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/Interpreter.cs

    r17203 r17212  
    484484    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    485485    public AlgebraicDouble One => new AlgebraicDouble(1.0);
     486
     487    public bool IsInfinity => IsNegativeInfinity || IsPositiveInfinity;
     488    public bool IsNegativeInfinity => double.IsNegativeInfinity(Value);
     489    public bool IsPositiveInfinity => double.IsPositiveInfinity(Value);
    486490    public AlgebraicDouble() { }
    487491    public AlgebraicDouble(double value) { this.Value = value; }
     
    497501    public AlgebraicDouble AssignCos(AlgebraicDouble a) { Value = Math.Cos(a.Value); return this; }
    498502    public AlgebraicDouble AssignTanh(AlgebraicDouble a) { Value = Math.Tanh(a.Value); return this; }
    499     public AlgebraicDouble AssignLog(AlgebraicDouble a) { Value = a.Value <= 0 ? double.NegativeInfinity : Math.Log(a.Value); return this; } // alternative definiton of log to prevent NaN
     503    public AlgebraicDouble AssignLog(AlgebraicDouble a) { Value = Math.Log(a.Value); return this; }
    500504    public AlgebraicDouble AssignExp(AlgebraicDouble a) { Value = Math.Exp(a.Value); return this; }
    501505    public AlgebraicDouble AssignIntPower(AlgebraicDouble a, int p) { Value = Math.Pow(a.Value, p); return this; }
     
    803807      var v4 = high.Clone().Mul(a.high);
    804808
    805       low = Algebraic.Min(Algebraic.Min(v1, v2), Algebraic.Min(v3, v4));
    806       high = Algebraic.Max(Algebraic.Max(v1, v2), Algebraic.Max(v3, v4));
    807       return this;
     809      low = Min(Min(v1, v2), Min(v3, v4));
     810      high = Max(Max(v1, v2), Max(v3, v4));
     811
     812      return this;
     813    }
     814
     815    // algebraic min() / max() do not work for infinities
     816    // detect and handle infinite values explicitly
     817    private static MultivariateDual<AlgebraicDouble> Min(MultivariateDual<AlgebraicDouble> a, MultivariateDual<AlgebraicDouble> b) {
     818      if (a.Value.IsInfinity || b.Value.IsInfinity) return a.Value < b.Value ? a : b; // NOTE: this is not differentiable but for infinite values we do not care
     819      else return Algebraic.Min(a, b); // differentiable statement
     820    }
     821    private static MultivariateDual<AlgebraicDouble> Max(MultivariateDual<AlgebraicDouble> a, MultivariateDual<AlgebraicDouble> b) {
     822      if (a.Value.IsInfinity || b.Value.IsInfinity) return a.Value >= b.Value ? a : b; // NOTE: this is not differentiable but for infinite values we do not care
     823      else return Algebraic.Max(a, b); // differentiable statement
    808824    }
    809825
     
    815831
    816832    public AlgebraicInterval AssignCos(AlgebraicInterval a) {
    817       return AssignSin(a.Clone().Sub(new AlgebraicInterval(Math.PI / 2, Math.PI / 2)));
     833      return AssignSin(a.Clone().Add(new AlgebraicInterval(Math.PI / 2, Math.PI / 2)));
    818834    }
    819835
     
    821837      if (a.Contains(0.0)) {
    822838        if (a.low.Value.Value == 0 && a.high.Value.Value == 0) {
     839          if (this.low.Value >= 0) {
     840            // pos / 0
     841          } else if (this.high.Value <= 0) {
     842            // neg / 0
     843          } else {
     844            low = new MultivariateDual<AlgebraicDouble>(double.NegativeInfinity);
     845            high = new MultivariateDual<AlgebraicDouble>(double.PositiveInfinity);
     846          }
     847        } else if (a.low.Value.Value >= 0) {
     848          // a is positive
     849          Mul(new AlgebraicInterval(a.Clone().high.Inv(), new MultivariateDual<AlgebraicDouble>(double.PositiveInfinity)));
     850        } else if (a.high.Value <= 0) {
     851          // a is negative
     852          Mul(new AlgebraicInterval(new MultivariateDual<AlgebraicDouble>(double.NegativeInfinity), a.low.Clone().Inv()));
     853        } else {
     854          // a is interval over zero
    823855          low = new MultivariateDual<AlgebraicDouble>(double.NegativeInfinity);
    824856          high = new MultivariateDual<AlgebraicDouble>(double.PositiveInfinity);
    825         } else if (a.low.Value.Value == 0)
    826           Mul(new AlgebraicInterval(a.Clone().high.Inv(), new MultivariateDual<AlgebraicDouble>(double.PositiveInfinity)));
    827         else
    828           Mul(new AlgebraicInterval(new MultivariateDual<AlgebraicDouble>(double.NegativeInfinity), a.low.Clone().Inv()));
     857        }
    829858      } else {
    830859        Mul(new AlgebraicInterval(a.high.Clone().Inv(), a.low.Clone().Inv())); // inverting leads to inverse roles of high and low
     
    947976        low = new MultivariateDual<AlgebraicDouble>(-1.0); // zero gradient
    948977        high = new MultivariateDual<AlgebraicDouble>(1.0);
     978        return this;
    949979      }
    950980
     
    11451175    public MultivariateDual<V> AssignAbs(MultivariateDual<V> a) { v.AssignAbs(a.v); dv.Assign(a.dv).Scale(a.v.Clone().Sgn()); return this; }      // abs(f(x))' = f(x)*f'(x) / |f(x)|  doesn't work for intervals     
    11461176    public MultivariateDual<V> AssignSgn(MultivariateDual<V> a) { v.AssignSgn(a.v); dv = a.dv.Zero; return this; } // sign(f(x))' = 0;     
     1177
    11471178  }
    11481179}
  • branches/2994-AutoDiffForIntervals/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis-3.4/AutoDiffIntervalTest.cs

    r17205 r17212  
    1111    private readonly AlgebraicInterval d = new AlgebraicInterval(1, 3);
    1212    private readonly AlgebraicInterval e = new AlgebraicInterval(4, 6);
    13     private readonly IntervalEvaluator eval = new  IntervalEvaluator();
     13    private readonly IntervalEvaluator eval = new IntervalEvaluator();
    1414
    1515    [TestMethod]
     
    2020
    2121      // [-1,1] + [-2,2] = [-3,3]
    22       Assert.AreEqual(Add(a, b), new AlgebraicInterval(-3, 3));
     22      AssertAreEqualInterval(Add(a, b), new AlgebraicInterval(-3, 3));
    2323      //([-1, 1] + [-2, 2]) + [0, 3] = [-3, 6]
    24       Assert.AreEqual(Add(Add(a, b), c), new AlgebraicInterval(-3, 6));
     24      AssertAreEqualInterval(Add(Add(a, b), c), new AlgebraicInterval(-3, 6));
    2525      //([-1, 1] + [0, 3]) + [-2, 2] = [-3, 6]
    26       Assert.AreEqual(Add(Add(a, c), b), new AlgebraicInterval(-3, 6));
     26      AssertAreEqualInterval(Add(Add(a, c), b), new AlgebraicInterval(-3, 6));
     27    }
     28
     29    private void AssertAreEqualInterval(AlgebraicInterval a, AlgebraicInterval b) {
     30      if (double.IsNaN(a.LowerBound.Value)) {
     31        Assert.IsTrue(double.IsNaN(b.LowerBound.Value));
     32      } else {
     33        Assert.AreEqual(a.LowerBound.Value.Value, b.LowerBound.Value.Value, 1e-10);
     34      }
     35
     36      if (double.IsNaN(a.UpperBound.Value)) {
     37        Assert.IsTrue(double.IsNaN(b.UpperBound.Value));
     38      } else {
     39        Assert.AreEqual(a.UpperBound.Value.Value, b.UpperBound.Value.Value, 1e-10);
     40      }
    2741    }
    2842
     
    3852
    3953      //[-1, 1] - [-2, 2] = [-3, 3]
    40       Assert.AreEqual(Subtract(a, b), new AlgebraicInterval(-3, 3));
     54      AssertAreEqualInterval(Subtract(a, b), new AlgebraicInterval(-3, 3));
    4155      //([-1, 1] - [-2, 2]) - [0, 3] = [-6, 3]
    42       Assert.AreEqual(Subtract(Subtract(a, b), c), new AlgebraicInterval(-6, 3));
     56      AssertAreEqualInterval(Subtract(Subtract(a, b), c), new AlgebraicInterval(-6, 3));
    4357      //([-1, 1] - [0, 3]) - [-2, 2] = [-6, 3]
    44       Assert.AreEqual(Subtract(Subtract(a, c), b), new AlgebraicInterval(-6, 3));
     58      AssertAreEqualInterval(Subtract(Subtract(a, c), b), new AlgebraicInterval(-6, 3));
    4559    }
    4660
     
    5670
    5771      //[-1, 1] * [-2, 2] = [-2, 2]
    58       Assert.AreEqual(Multiply(a, b), new AlgebraicInterval(-2, 2));
     72      AssertAreEqualInterval(Multiply(a, b), new AlgebraicInterval(-2, 2));
    5973      //([-1, 1] * [-2, 2]) * [0, 3] = [-6, 6]
    60       Assert.AreEqual(Multiply(Multiply(a, b), c), new AlgebraicInterval(-6, 6));
     74      AssertAreEqualInterval(Multiply(Multiply(a, b), c), new AlgebraicInterval(-6, 6));
    6175      //([-1, 1] * [0, 3]) * [-2, 2] = [-6, 6]
    62       Assert.AreEqual(Multiply(Multiply(a, c), b), new AlgebraicInterval(-6, 6));
     76      AssertAreEqualInterval(Multiply(Multiply(a, c), b), new AlgebraicInterval(-6, 6));
    6377
    6478      // [-2, 0] * [-2, 0]  = [0, 4]
    65       Assert.AreEqual(new AlgebraicInterval(0, 4), Multiply(new AlgebraicInterval(-2, 0), new AlgebraicInterval(-2, 0)));
     79      AssertAreEqualInterval(new AlgebraicInterval(0, 4), Multiply(new AlgebraicInterval(-2, 0), new AlgebraicInterval(-2, 0)));
    6680    }
    6781
     
    7791
    7892      //[4, 6] / [1, 3] = [4/3, 6]
    79       Assert.AreEqual(Divide(e, d), new AlgebraicInterval(4.0 / 3.0, 6));
     93      AssertAreEqualInterval(Divide(e, d), new AlgebraicInterval(4.0 / 3.0, 6));
    8094      //([4, 6] / [1, 3]) / [1, 3] = [4/9, 6]
    81       Assert.AreEqual(Divide(Divide(e, d), d), new AlgebraicInterval(4.0 / 9.0, 6));
     95      AssertAreEqualInterval(Divide(Divide(e, d), d), new AlgebraicInterval(4.0 / 9.0, 6));
    8296      //[4, 6] / [0, 3] = [4/3, +Inf]
    83       Assert.AreEqual(Divide(e, c), new AlgebraicInterval(4.0 / 3.0, double.PositiveInfinity));
     97      AssertAreEqualInterval(Divide(e, c), new AlgebraicInterval(4.0 / 3.0, double.PositiveInfinity));
    8498      //[-1, 1] / [0, 3] = [+Inf, -Inf]
    85       Assert.AreEqual(Divide(a, c), new AlgebraicInterval(double.NegativeInfinity, double.PositiveInfinity));
    86       //Devision by 0 ==> IsInfiniteOrUndefined == true
    87      
    88       //Devision by 0 ==> IsInfiniteOrUndefined == true
    89      
    90       Assert.AreEqual(Divide(d, b), new AlgebraicInterval(double.NegativeInfinity, double.PositiveInfinity));
     99      AssertAreEqualInterval(Divide(a, c), new AlgebraicInterval(double.NegativeInfinity, double.PositiveInfinity));
     100
     101      //Division by 0 ==> IsInfiniteOrUndefined == true
     102      AssertAreEqualInterval(Divide(d, b), new AlgebraicInterval(double.NegativeInfinity, double.PositiveInfinity));
    91103    }
    92104
     
    101113      //sine depends on interval
    102114      //sin([0, 2*pi]) = [-1, 1]
    103       Assert.AreEqual(Sine(new AlgebraicInterval(0, 2 * Math.PI)), new AlgebraicInterval(-1, 1));
     115      AssertAreEqualInterval(Sine(new AlgebraicInterval(0, 2 * Math.PI)), new AlgebraicInterval(-1, 1));
    104116      //sin([-pi/2, pi/2]) = [sin(-pi/2), sin(pi/2)]
    105       Assert.AreEqual(Sine(new AlgebraicInterval(-1 * Math.PI / 2, Math.PI / 2)), new AlgebraicInterval(-1, 1));
     117      AssertAreEqualInterval(Sine(new AlgebraicInterval(-1 * Math.PI / 2, Math.PI / 2)), new AlgebraicInterval(-1, 1));
    106118      //sin([0, pi/2]) = [sin(0), sin(pi/2)]
    107       Assert.AreEqual(Sine(new AlgebraicInterval(0, Math.PI / 2)), new AlgebraicInterval(0, 1));
     119      AssertAreEqualInterval(Sine(new AlgebraicInterval(0, Math.PI / 2)), new AlgebraicInterval(0, 1));
    108120      //sin([pi, 3*pi/2]) = [sin(pi), sin(3*pi/2)]
    109       Assert.AreEqual(Sine(new AlgebraicInterval(Math.PI, 3 * Math.PI / 2)), new AlgebraicInterval(-1, 0));
    110       Assert.AreEqual(Sine(new AlgebraicInterval(1, 2)), new AlgebraicInterval(Math.Min(Math.Sin(1), Math.Sin(2)), 1));
    111       Assert.AreEqual(Sine(new AlgebraicInterval(1, 3)), new AlgebraicInterval(Math.Min(Math.Sin(1), Math.Sin(3)), 1));
    112       Assert.AreEqual(Sine(new AlgebraicInterval(Math.PI, 5 * Math.PI / 2)), new AlgebraicInterval(-1, 1));
     121      AssertAreEqualInterval(Sine(new AlgebraicInterval(Math.PI, 3 * Math.PI / 2)), new AlgebraicInterval(-1, 0));
     122      AssertAreEqualInterval(Sine(new AlgebraicInterval(1, 2)), new AlgebraicInterval(Math.Min(Math.Sin(1), Math.Sin(2)), 1));
     123      AssertAreEqualInterval(Sine(new AlgebraicInterval(1, 3)), new AlgebraicInterval(Math.Min(Math.Sin(1), Math.Sin(3)), 1));
     124      AssertAreEqualInterval(Sine(new AlgebraicInterval(Math.PI, 5 * Math.PI / 2)), new AlgebraicInterval(-1, 1));
    113125    }
    114126
     
    122134    public void TestIntervalCosineOperator() {
    123135      //Cosine uses sine Sine(Subtract(a, new AlgebraicInterval(Math.PI / 2, Math.PI / 2)));
    124       Assert.AreEqual(Cosine(new AlgebraicInterval(0, 2 * Math.PI)), new AlgebraicInterval(-1, 1));
    125       Assert.AreEqual(new AlgebraicInterval(-1, 1), Cosine(new AlgebraicInterval(Math.PI, 4 * Math.PI / 2)));
     136      AssertAreEqualInterval(Cosine(new AlgebraicInterval(0, 2 * Math.PI)), new AlgebraicInterval(-1, 1));
     137      AssertAreEqualInterval(new AlgebraicInterval(-1, 1), Cosine(new AlgebraicInterval(Math.PI, 4 * Math.PI / 2)));
    126138    }
    127139
     
    135147    public void TestIntervalLogOperator() {
    136148      //Log([3, 5]) = [log(3), log(5)]
    137       Assert.AreEqual(new AlgebraicInterval(Math.Log(3), Math.Log(5)), Logarithm(new AlgebraicInterval(3, 5)));
     149      AssertAreEqualInterval(new AlgebraicInterval(Math.Log(3), Math.Log(5)), Logarithm(new AlgebraicInterval(3, 5)));
    138150      //Log([0.5, 1]) = [log(0.5), log(1)]
    139       Assert.AreEqual(new AlgebraicInterval(Math.Log(0.5), 0), Logarithm(new AlgebraicInterval(0.5, 1)));
     151      AssertAreEqualInterval(new AlgebraicInterval(Math.Log(0.5), 0), Logarithm(new AlgebraicInterval(0.5, 1)));
    140152      //Log([-1, 5]) = [NaN, log(5)]
    141153      var result = Logarithm(new AlgebraicInterval(-1, 5));
    142       Assert.AreEqual(new AlgebraicInterval(double.NaN, Math.Log(5)),result);
    143      
     154      AssertAreEqualInterval(new AlgebraicInterval(double.NaN, Math.Log(5)), result);
     155
    144156    }
    145157
     
    153165    public void TestIntervalExpOperator() {
    154166      //Exp([0, 1]) = [exp(0), exp(1)]
    155       Assert.AreEqual(new AlgebraicInterval(1, Math.Exp(1)), Exponential(new AlgebraicInterval(0, 1)));
     167      AssertAreEqualInterval(new AlgebraicInterval(1, Math.Exp(1)), Exponential(new AlgebraicInterval(0, 1)));
    156168    }
    157169
     
    164176    [TestProperty("Time", "short")]
    165177    public void TestIntervalSqrOperator() {
    166       Assert.AreEqual(new AlgebraicInterval(1, 4), Square(new AlgebraicInterval(1, 2)));
    167       Assert.AreEqual(new AlgebraicInterval(1, 4), Square(new AlgebraicInterval(-2, -1)));
    168       Assert.AreEqual(new AlgebraicInterval(0, 4), Square(new AlgebraicInterval(-2, 2)));
     178      AssertAreEqualInterval(new AlgebraicInterval(1, 4), Square(new AlgebraicInterval(1, 2)));
     179      AssertAreEqualInterval(new AlgebraicInterval(1, 4), Square(new AlgebraicInterval(-2, -1)));
     180      AssertAreEqualInterval(new AlgebraicInterval(0, 4), Square(new AlgebraicInterval(-2, 2)));
    169181    }
    170182
     
    177189    [TestProperty("Time", "short")]
    178190    public void TestIntervalSqrtOperator() {
    179       Assert.AreEqual(new AlgebraicInterval(1, 2), SquareRoot(new AlgebraicInterval(1, 4)));
    180       Assert.AreEqual(new AlgebraicInterval(double.NaN, double.NaN), SquareRoot(new AlgebraicInterval(-4, -1)));
     191      AssertAreEqualInterval(new AlgebraicInterval(1, 2), SquareRoot(new AlgebraicInterval(1, 4)));
     192      AssertAreEqualInterval(new AlgebraicInterval(double.NaN, double.NaN), SquareRoot(new AlgebraicInterval(-4, -1)));
    181193    }
    182194
     
    189201    [TestProperty("Time", "short")]
    190202    public void TestIntervalCubeOperator() {
    191       Assert.AreEqual(new AlgebraicInterval(1, 8), Cube(new AlgebraicInterval(1, 2)));
    192       Assert.AreEqual(new AlgebraicInterval(-8, -1), Cube(new AlgebraicInterval(-2, -1)));
    193       Assert.AreEqual(new AlgebraicInterval(-8, 8), Cube(new AlgebraicInterval(-2, 2)));
     203      AssertAreEqualInterval(new AlgebraicInterval(1, 8), Cube(new AlgebraicInterval(1, 2)));
     204      AssertAreEqualInterval(new AlgebraicInterval(-8, -1), Cube(new AlgebraicInterval(-2, -1)));
     205      AssertAreEqualInterval(new AlgebraicInterval(-8, 8), Cube(new AlgebraicInterval(-2, 2)));
    194206    }
    195207
     
    202214    [TestProperty("Time", "short")]
    203215    public void TestIntervalCbrtOperator() {
    204       Assert.AreEqual(new AlgebraicInterval(1, 2), CubicRoot(new AlgebraicInterval(1, 8)));
    205       Assert.AreEqual(new AlgebraicInterval(double.NaN, double.NaN), CubicRoot(new AlgebraicInterval(-8, -1)));
     216      AssertAreEqualInterval(new AlgebraicInterval(1, 2), CubicRoot(new AlgebraicInterval(1, 8)));
     217      AssertAreEqualInterval(new AlgebraicInterval(double.NaN, double.NaN), CubicRoot(new AlgebraicInterval(-8, -1)));
    206218    }
    207219
  • branches/2994-AutoDiffForIntervals/HeuristicLab.Tests/HeuristicLab.Tests.csproj

    r17205 r17212  
    112112      <HintPath>..\bin\ALGLIB-3.7.0.dll</HintPath>
    113113      <Private>False</Private>
     114    </Reference>
     115    <Reference Include="HEAL.Attic, Version=1.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
     116      <SpecificVersion>False</SpecificVersion>
     117      <HintPath>..\bin\HEAL.Attic.dll</HintPath>
    114118    </Reference>
    115119    <Reference Include="HeuristicLab.Algorithms.ALPS-3.3">
     
    605609    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\DeriveTest.cs" />
    606610    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\InfixExpressionParserTest.cs" />
     611    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\AutoDiffIntervalInterpreterTest.cs" />
    607612    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\IntervalInterpreterTest.cs" />
    608613    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\SymbolicExpressionTreeBottomUpSimilarityCalculatorTest.cs" />
Note: See TracChangeset for help on using the changeset viewer.