source: branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/MultivariateDual.cs @ 17303

Last change on this file since 17303 was 17303, checked in by gkronber, 3 years ago

#2994 continued refactoring and extended unit tests. Interval calculation still fails for some edge cases (mainly for undefined behaviour). VectorEvaluator and VectorAutoDiffEvaluator produce the same results as the LinearInterpreter. TODO: check gradient calculation

File size: 5.2 KB
Line 
1using System;
2using System.Diagnostics;
3
4namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
5  /// <summary>
6  /// An algebraic type which has a value as well as the partial derivatives of the value over multiple variables.
7  /// </summary>
8  /// <typeparam name="V"></typeparam>
9  [DebuggerDisplay("v={Value}; dv={dv}")]
10  public class MultivariateDual<V> : IAlgebraicType<MultivariateDual<V>> where V : IAlgebraicType<V>, new() {
11    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
12    private V v;
13    public V Value => v;
14
15    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
16    private AlgebraicSparseVector<object, V> dv;
17    public AlgebraicSparseVector<object, V> Gradient => dv; // <key,value> partial derivative identified via the key
18
19
20    private MultivariateDual(MultivariateDual<V> orig) { this.v = orig.v.Clone(); this.dv = orig.dv.Clone(); }
21
22    /// <summary>
23    /// Constructor which sets value and derivative to zero
24    /// </summary>
25    public MultivariateDual() {
26      v = new V(); // assumed to be zero
27      dv = new AlgebraicSparseVector<object, V>();
28    }
29
30    /// <summary>
31    /// Constructor without partial derivative
32    /// </summary>
33    /// <param name="v"></param>
34    public MultivariateDual(V v) { this.v = v.Clone(); this.dv = new AlgebraicSparseVector<object, V>(); }
35
36    /// <summary>
37    /// Constructor for multiple partial derivatives
38    /// </summary>
39    /// <param name="v"></param>
40    /// <param name="keys"></param>
41    /// <param name="dv"></param>
42    public MultivariateDual(V v, object[] keys, V[] dv) { this.v = v.Clone(); this.dv = new AlgebraicSparseVector<object, V>(keys, dv); }
43
44    /// <summary>
45    /// Constructor for a single partial derivative
46    /// </summary>
47    /// <param name="v"></param>
48    /// <param name="key"></param>
49    /// <param name="dv"></param>
50    public MultivariateDual(V v, object key, V dv) { this.v = v.Clone(); this.dv = new AlgebraicSparseVector<object, V>(new[] { key }, new[] { dv }); }
51
52    /// <summary>
53    /// Constructor with a given value and gradient. For internal use.
54    /// </summary>
55    /// <param name="v">The value (not cloned).</param>
56    /// <param name="gradient">The gradient (not cloned).</param>
57    internal MultivariateDual(V v, AlgebraicSparseVector<object, V> gradient) { this.v = v; this.dv = gradient; }
58
59    public MultivariateDual<V> Clone() { return new MultivariateDual<V>(this); }
60
61    public MultivariateDual<V> Zero => new MultivariateDual<V>(Value.Zero, Gradient.Zero);
62    public MultivariateDual<V> One => new MultivariateDual<V>(Value.One, Gradient.Zero);
63
64    public MultivariateDual<V> Scale(double s) { v.Scale(s); dv.Scale(s); return this; }
65
66    public MultivariateDual<V> Add(MultivariateDual<V> a) { v.Add(a.v); dv.Add(a.dv); return this; }
67    public MultivariateDual<V> Sub(MultivariateDual<V> a) { v.Sub(a.v); dv.Sub(a.dv); return this; }
68    public MultivariateDual<V> Assign(MultivariateDual<V> a) { v.Assign(a.v); dv.Assign(a.dv); return this; }
69    public MultivariateDual<V> Mul(MultivariateDual<V> a) {
70      // (a(x) * b(x))' = b(x)*a(x)' + b(x)'*a(x);
71      var t1 = a.dv.Clone().Scale(v);
72      var t2 = dv.Clone().Scale(a.v);
73      dv.Assign(t1).Add(t2);
74
75      v.Mul(a.v);
76      return this;
77    }
78    public MultivariateDual<V> Div(MultivariateDual<V> a) { v.Div(a.v); dv.Mul(a.dv.Inv()); return this; }
79    public MultivariateDual<V> AssignNeg(MultivariateDual<V> a) { v.AssignNeg(a.v); dv.AssignNeg(a.dv); return this; }
80    public MultivariateDual<V> AssignInv(MultivariateDual<V> a) { v.AssignInv(a.v); dv.AssignNeg(a.dv).Scale(v).Scale(v); return this; }   // (1/f(x))' = - f(x)' / f(x)^2
81
82    public MultivariateDual<V> AssignSin(MultivariateDual<V> a) { v.AssignSin(a.v); dv.Assign(a.dv).Scale(a.v.Clone().Cos()); return this; }
83    public MultivariateDual<V> AssignCos(MultivariateDual<V> a) { v.AssignCos(a.v); dv.AssignNeg(a.dv).Scale(a.v.Clone().Sin()); return this; }
84    public MultivariateDual<V> AssignTanh(MultivariateDual<V> a) { v.AssignTanh(a.v); dv.Assign(a.dv.Scale(v.Clone().IntPower(2).Neg().Add(Value.One))); return this; }     // tanh(f(x))' = f(x)'sech²(f(x)) = f(x)'(1 - tanh²(f(x)))
85
86    public MultivariateDual<V> AssignIntPower(MultivariateDual<V> a, int p) { v.AssignIntPower(a.v, p); dv.Assign(a.dv).Scale(p).Scale(a.v.Clone().IntPower(p - 1)); return this; }
87    public MultivariateDual<V> AssignIntRoot(MultivariateDual<V> a, int r) { v.AssignIntRoot(a.v, r); dv.Assign(a.dv).Scale(1.0 / r).Scale(a.v.IntRoot(r - 1)); return this; }
88
89    public MultivariateDual<V> AssignExp(MultivariateDual<V> a) { v.AssignExp(a.v); dv.Assign(a.dv).Scale(v); return this; } // exp(f(x)) = exp(f(x))*f(x)'     
90    public MultivariateDual<V> AssignLog(MultivariateDual<V> a) { v.AssignLog(a.v); dv.Assign(a.dv).Scale(a.v.Clone().Inv()); return this; }     // log(x)' = 1/f(x) * f(x)'
91
92    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     
93    public MultivariateDual<V> AssignSgn(MultivariateDual<V> a) { v.AssignSgn(a.v); dv = a.dv.Zero; return this; } // sign(f(x))' = 0;     
94  }
95}
Note: See TracBrowser for help on using the repository browser.