1 /*
2 Copyright (c) 2013-2021 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 /**
30  * Dual numbers
31  *
32  * Copyright: Timur Gafarov 2013-2021.
33  * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
34  * Authors: Timur Gafarov
35  */
36 module dlib.math.dual;
37 
38 private
39 {
40     import std.math;
41 }
42 
43 /**
44  * Dual number representation
45  */
46 struct Dual(T)
47 {
48     T re;
49     T du;
50 
51     this(T r)
52     {
53         re = r;
54         du = 0.0;
55     }
56 
57     this(T r, T d)
58     {
59         re = r;
60         du = d;
61     }
62 
63     this(in int e)
64     {
65         re = cast(T)e;
66         du = 0.0;
67     }
68 
69     static Dual!(T) opCast(in T x)
70     {
71         return Dual!(T)(x, 0.0);
72     }
73 
74     Dual!(T) opAssign(in T x)
75     {
76         re = x;
77         du = 0.0;
78         return this;
79     }
80 
81     Dual!(T) opBinary(string op)(in T x) const if (op == "+")
82     {
83         return this + Dual!(T)(x);
84     }
85 
86     Dual!(T) opBinary(string op)(in T x) const if (op == "-")
87     {
88         return this - Dual!(T)(x);
89     }
90 
91     Dual!(T) opBinary(string op)(in T x) const if (op == "*")
92     {
93         return this * Dual!(T)(x);
94     }
95 
96     Dual!(T) opBinary(string op)(in T x) const if (op == "/")
97     {
98         return this / Dual!(T)(x);
99     }
100 
101     Dual!(T) opUnary(string s)() const if (s == "-")
102     {
103         return Dual!(T)(-re, -du);
104     }
105 
106     Dual!(T) opBinary(string op)(in Dual!(T) x) const if (op == "+")
107     {
108         return Dual!(T)(
109             re + x.re,
110             du + x.du
111         );
112     }
113 
114     Dual!(T) opBinary(string op)(in Dual!(T) x) const if (op == "-")
115     {
116         return Dual!(T)(
117             re - x.re,
118             du - x.du
119         );
120     }
121 
122     Dual!(T) opBinary(string op)(in Dual!(T) x) const if (op == "*")
123     {
124         return Dual!(T)(
125             re * x.re,
126             re * x.du + du * x.re
127         );
128     }
129 
130     Dual!(T) opBinary(string op)(in Dual!(T) x) const if (op == "/")
131     {
132         return Dual!(T)(
133             re / x.re,
134             (re * x.du - du * x.re) / (x.re * x.re)
135         );
136     }
137 
138     Dual!(T) opOpAssign(string op)(in Dual!(T) x) if (op == "+")
139     {
140         re += x.re;
141         du += x.du;
142         return this;
143     }
144 
145     Dual!(T) opOpAssign(string op)(in Dual!(T) x) if (op == "-")
146     {
147         re -= x.re;
148         du -= x.du;
149         return this;
150     }
151 
152     Dual!(T) opOpAssign(string op)(in Dual!(T) x) if (op == "*")
153     {
154         re *= x.re,
155         du = re * x.du + du * x.re;
156         return this;
157     }
158 
159     Dual!(T) opOpAssign(string op)(in Dual!(T) x) if (op == "/")
160     {
161         re /= x.re,
162         du = (re * x.du - du * x.re) / (x.re * x.re);
163         return this;
164     }
165 
166     Dual!(T) sqrt() const
167     {
168         T tmp = std.math.sqrt(re);
169         return Dual!(T)(
170             tmp,
171             du / (2.0 * tmp)
172         );
173     }
174 
175     Dual!(T) opBinaryRight(string op)(in T v) const if (op == "+")
176     {
177         return Dual!(T)(v) + this;
178     }
179 
180     Dual!(T) opBinaryRight(string op)(in T v) const if (op == "-")
181     {
182         return Dual!(T)(v) - this;
183     }
184 
185     Dual!(T) opBinaryRight(string op)(in T v) const if (op == "*")
186     {
187         return Dual!(T)(v) * this;
188     }
189 
190     Dual!(T) opBinaryRight(string op)(in T v) const if (op == "/")
191     {
192         return Dual!(T)(v) / this;
193     }
194 
195     int opCmp(in double s) const
196     {
197         return cast(int)((re - s) * 100);
198     }
199 
200     Dual!(T) sin() const
201     {
202         return Dual!(T)(.sin(re), du * .cos(re));
203     }
204 
205     Dual!(T) cos() const
206     {
207         return Dual!(T)(.cos(re), -du * .sin(re));
208     }
209 
210     Dual!(T) exp() const
211     {
212         return Dual!(T)(.exp(re), du * .exp(re));
213     }
214 
215     Dual!(T) pow(T k) const
216     {
217         return Dual!(T)(re^^k, k * (re^^(k-1)) * du);
218     }
219 }
220 
221 /// Alias for single precision Dual specialization
222 alias Dualf = Dual!(float);
223 
224 /// Alias for double precision Dual specialization
225 alias Duald = Dual!(double);