1 | using System;
|
---|
2 | using System.Diagnostics;
|
---|
3 |
|
---|
4 | namespace 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) { Mul(a.Inv()); return this; } // f(x) / g(x)
|
---|
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(a.v.IntPower(2).Inv()); 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).IntPower(r - 1).Inv()); 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 | } |
---|