using System; using System.Diagnostics; namespace HeuristicLab.Problems.DataAnalysis.Symbolic { public class Dual : IAlgebraicType> where V : IComparableAlgebraicType { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private V v; public V Value => v; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private V dv; public V Derivative => dv; public Dual(V v, V dv) { this.v = v; this.dv = dv; } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public Dual Zero => new Dual(Value.Zero, Derivative.Zero); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public Dual One => new Dual(Value.One, Derivative.Zero); public Dual Assign(Dual a) { v.Assign(a.v); dv.Assign(a.dv); return this; } public Dual Scale(double s) { v.Scale(s); dv.Scale(s); return this; } public Dual Add(Dual a) { v.Add(a.v); dv.Add(a.dv); return this; } public Dual Sub(Dual a) { v.Sub(a.v); dv.Sub(a.dv); return this; } public Dual AssignNeg(Dual a) { v.AssignNeg(a.v); dv.AssignNeg(a.dv); return this; } public Dual AssignInv(Dual a) { v.AssignInv(a.v); dv.AssignNeg(a.dv).Mul(v.IntPower(2).Inv()); return this; } // (1/f(x))' = - f(x)' / f(x)^2 // (a(x) * b(x))' = b(x)*a(x)' + b(x)'*a(x); public Dual Mul(Dual a) { var t1 = a.dv.Clone().Mul(v); var t2 = dv.Clone().Mul(a.v); dv.Assign(t1).Add(t2); v.Mul(a.v); return this; } public Dual Div(Dual a) { Mul(a.Inv()); return this; } // f(x) / g(x) = f(x) * 1/g(x) public Dual AssignExp(Dual a) { v.AssignExp(a.v); dv.Assign(a.dv).Mul(v); return this; } // exp(f(x)) = exp(f(x))*f(x)' public Dual AssignLog(Dual a) { v.AssignLog(a.v); dv.Assign(a.dv).Div(a.v); return this; } // log(x)' = 1/f(x) * f(x)' public Dual AssignIntPower(Dual a, int p) { v.AssignIntPower(a.v, p); dv.Assign(a.dv).Scale(p).Mul(a.v.Clone().IntPower(p - 1)); return this; } public Dual AssignIntRoot(Dual a, int r) { v.AssignIntRoot(a.v, r); dv.Assign(a.dv).Scale(1.0 / r).Div(a.v.IntRoot(r).IntPower(r-1)); return this; } public Dual AssignSin(Dual a) { v.AssignSin(a.v); dv.Assign(a.dv).Mul(a.v.Clone().Cos()); return this; } public Dual AssignCos(Dual a) { v.AssignCos(a.v); dv.AssignNeg(a.dv).Mul(a.v.Clone().Sin()); return this; } public Dual AssignTanh(Dual a) { v.AssignTanh(a.v); dv.Assign(a.dv.Mul(v.Clone().IntPower(2).Neg().Add(Value.One))); return this; } public Dual AssignAbs(Dual a) { v.AssignAbs(a.v); dv.Assign(a.dv).Mul(a.v.Clone().Sgn()); return this; } // abs(f(x))' = f(x)*f'(x) / |f(x)| public Dual AssignSgn(Dual a) { v.AssignSgn(a.v); dv.Assign(a.dv.Zero); return this; } public Dual Clone() { return new Dual(v.Clone(), dv.Clone()); } public Dual AssignMin(Dual other) { if(v.CompareTo(other.v) > 0) { v.Assign(other.v); dv.Assign(other.dv); } return this; } public Dual AssignMax(Dual other) { if (v.CompareTo(other.v) <= 0) { v.Assign(other.v); dv.Assign(other.dv); } return this; } } }