Theoretica
Scientific Computing
Loading...
Searching...
No Matches
multidual.h
Go to the documentation of this file.
1#ifndef THEORETICA_MULTIDUAL_H
2#define THEORETICA_MULTIDUAL_H
3
4
8
9#ifndef THEORETICA_NO_PRINT
10#include <sstream>
11#include <ostream>
12#endif
13
14#include "../algebra/vec.h"
15#include "../algebra/mat.h"
16
17
18namespace theoretica {
19
25 template<unsigned int N = 0>
26 class multidual {
27
28 public:
29
32
36
37 // The template argument of the vector type used
38 static constexpr size_t size_argument = N;
39
40
43 multidual() : a(0) {}
44
45
49
50
53 multidual(real r) : a(r), v(vec<real, N>()) {}
54
55 ~multidual() = default;
56
57
60 a = x;
61 v = vec<real, N>();
62 return *this;
63 }
64
65
67 inline real Re() const {
68 return a;
69 }
70
71
73 inline real& Re() {
74 return a;
75 }
76
77
79 inline vec<real, N> Dual() const {
80 return v;
81 }
82
83
85 inline vec<real, N>& Dual() {
86 return v;
87 }
88
89
93 inline real Dual(unsigned int i) const {
94 return v[i];
95 }
96
97
101 inline real& Dual(unsigned int i) {
102 return v[i];
103 }
104
105
107 inline multidual conjugate() const {
108 return multidual(a, -v);
109 }
110
111
113 inline multidual inverse() const {
114
115 if(a == 0) {
116 TH_MATH_ERROR("multidual::inverse", 0, MathError::DivByZero);
117 return multidual(nan(), vec<real, N>(N, nan()));
118 }
119
120 return multidual(1.0 / a, v * (-1 / (a * a)));
121 }
122
123
125 inline multidual operator+() const {
126 return multidual(a, v);
127 }
128
129
131 inline multidual operator+(const multidual& other) const {
132 return multidual(a + other.a, v + other.v);
133 }
134
135
137 inline multidual operator+(real r) const {
138 return multidual(a + r, v);
139 }
140
141
143 inline multidual operator-() const {
144 return multidual(-a, -v);
145 }
146
147
149 inline multidual operator-(const multidual& other) const {
150 return multidual(a - other.a, v - other.v);
151 }
152
153
155 inline multidual operator-(real r) const {
156 return multidual(a - r, v);
157 }
158
159
161 inline multidual operator*(const multidual& other) const {
162
163 // Equal sizes
164 if (v.size() == other.v.size()) {
165 return multidual(a * other.a, other.v * a + v * other.a);
166 }
167
168 // Trivial scalar cases
169 if (v.size() == 0) {
170 return multidual(a * other.a, other.v * a);
171 }
172
173 if (other.v.size() == 0) {
174 return multidual(a * other.a, v * other.a);
175 }
176
177 // Treat missing entries as zero
178 const unsigned int new_size = th::max(v.size(), other.v.size());
181
182 for (unsigned int i = 0; i < res_v.size(); ++i) {
183 real lhs = (i < other.v.size()) ? other.v[i] : 0.0;
184 real rhs = (i < v.size()) ? v[i] : 0.0;
185 res_v[i] = lhs * a + rhs * other.a;
186 }
187
188 return multidual(a * other.a, res_v);
189 }
190
191
193 inline multidual operator*(real r) const {
194 return multidual(a * r, v * r);
195 }
196
197
199 inline multidual operator/(const multidual& other) const {
200
201 if(abs(a) < MACH_EPSILON) {
202 TH_MATH_ERROR("multidual::operator/", 0, MathError::DivByZero);
203 return multidual(nan(), vec<real, N>(N, nan()));
204 }
205
206 const real res_a = a / other.a;
207 const real denom = other.a * other.a;
208
209 // Equal sizes
210 if (v.size() == other.v.size()) {
211 return multidual(res_a, (v * other.a - other.v * a) / denom);
212 }
213
214 // Trivial scalar cases
215 if (v.size() == 0) {
216 return multidual(res_a, other.v * (-a / denom));
217 }
218
219 if (other.v.size() == 0) {
220 return multidual(res_a, v / other.a);
221 }
222
223 // Treat missing entries as zero
224 const unsigned int new_size = th::max(v.size(), other.v.size());
227
228 for (unsigned int i = 0; i < res_v.size(); ++i) {
229
230 real lhs = (i < v.size()) ? v[i] : 0.0;
231 real rhs = (i < other.v.size()) ? other.v[i] : 0.0;
232
233 res_v[i] = (lhs * other.a - rhs * a) / denom;
234 }
235
236 return multidual(res_a, res_v);
237 }
238
240 inline multidual operator/(real r) const {
241 return multidual(a / r, v / r);
242 }
243
244
247
248 a += other.a;
249 v += other.v;
250 return *this;
251 }
252
253
256
257 a += r;
258 return *this;
259 }
260
263
264 a -= other.a;
265 v -= other.v;
266 return *this;
267 }
268
271
272 a -= r;
273 return *this;
274 }
275
278
279 const real a_old = a;
280
281 // Equal sizes
282 if (v.size() == other.v.size()) {
283 a = a_old * other.a;
284 v = other.v * a_old + v * other.a;
285 return *this;
286 }
287
288 // Trivial scalar cases
289 if (v.size() == 0) {
290 a = a_old * other.a;
291 v = other.v * a_old;
292 return *this;
293 }
294
295 if (other.v.size() == 0) {
296 a = a_old * other.a;
297 v = v * other.a;
298 return *this;
299 }
300
301 // Treat missing entries as zero
302 const unsigned int new_size = th::max(v.size(), other.v.size());
305
306 for (unsigned int i = 0; i < new_v.size(); ++i) {
307
308 real lhs = (i < other.v.size()) ? other.v[i] : 0.0;
309 real rhs = (i < v.size()) ? v[i] : 0.0;
310
311 new_v[i] = lhs * a_old + rhs * other.a;
312 }
313
314 a = a_old * other.a;
315 v = new_v;
316
317 return *this;
318 }
319
322
323 a *= r;
324 v *= r;
325 return *this;
326 }
327
330
331 const real a_old = a;
332 const real denom = other.a * other.a;
333
334 // Equal sizes
335 if (v.size() == other.v.size()) {
336 a = a_old / other.a;
337 v = (v * other.a - other.v * a_old) / denom;
338 return *this;
339 }
340
341 // Trivial scalar cases
342 if (v.size() == 0) {
343 a = a_old / other.a;
344 v = other.v * (-a_old / denom);
345 return *this;
346 }
347
348 if (other.v.size() == 0) {
349 a = a_old / other.a;
350 v = v / other.a;
351 return *this;
352 }
353
354 // Treat missing entries as zero
355 const unsigned int new_size = th::max(v.size(), other.v.size());
358
359 for (unsigned int i = 0; i < new_v.size(); ++i) {
360
361 real lhs = (i < v.size()) ? v[i] : 0.0;
362 real rhs = (i < other.v.size()) ? other.v[i] : 0.0;
363
364 new_v[i] = (lhs * other.a - rhs * a_old) / denom;
365 }
366
367 a = a_old / other.a;
368 v = new_v;
369
370 return *this;
371 }
372
375
376 if(r == 0) {
377 TH_MATH_ERROR("multidual::operator/=", 0, MathError::DivByZero);
378 a = nan();
379 v = vec<real, N>(N, nan());
380 return *this;
381 }
382
383 a /= r;
384 v /= r;
385
386 return *this;
387 }
388
389
392 inline bool operator==(const multidual& other) {
393 return (a == other.a) && (v == other.v);
394 }
395
396
400 template<typename Vector = vec<real, N>, enable_vector<Vector> = true>
401 inline static vec<multidual<N>, N> make_argument(const Vector& x) {
402
403 vec<multidual<N>, N> arg;
404 arg.resize(x.size());
405
406 for (unsigned int i = 0; i < x.size(); ++i)
407 arg[i] = multidual<N>(
408 x[i], vec<real, N>::euclidean_base(i, x.size())
409 );
410
411 return arg;
412 }
413
414
418 const vec<multidual<N>, N>& v) {
419
420 vec<real, N> x;
421 x.resize(v.size());
422
423 for (unsigned int i = 0; i < N; ++i)
424 x[i] = v[i].Re();
425
426 return x;
427 }
428
429
434 const vec<multidual<N>, N>& v) {
435
437 J.resize(v.size(), v.size());
438
439 for (unsigned int i = 0; i < N; ++i)
440 for (unsigned int j = 0; j < N; ++j)
441 J(j, i) = v[j].Dual(i);
442
443 return J;
444 }
445
446
450 inline static void extract(
451 const vec<multidual<N>, N>& v,
452 vec<real, N>& x,
454
455 for (unsigned int i = 0; i < N; ++i) {
456
457 for (unsigned int j = 0; j < N; ++j)
458 J(j, i) = v[j].Dual(i);
459
460 x[i] = v[i].Re();
461 }
462 }
463
464
467 unsigned int size() const {
468 return v.size();
469 }
470
471
474 inline void resize(unsigned int size) {
475 v.resize(size);
476 }
477
478
479 // Friend operators to enable equations of the form
480 // (real) op. (multidual)
481
482 inline friend multidual operator+(real a, const multidual& d) {
483 return d + a;
484 }
485
486 inline friend multidual operator-(real a, const multidual& d) {
487 return -d + a;
488 }
489
490 inline friend multidual operator*(real a, const multidual& d) {
491 return d * a;
492 }
493
494 inline friend multidual operator/(real a, const multidual& d) {
495 return a * d.inverse();
496 }
497
498
499#ifndef THEORETICA_NO_PRINT
500
503 inline std::string to_string(const std::string& epsilon = "ε") const {
504
505 std::stringstream res;
506 res << a << " + " << v << epsilon;
507
508 return res.str();
509 }
510
511
513 inline operator std::string() {
514 return to_string();
515 }
516
517
520 inline friend std::ostream& operator<<(std::ostream& out, const multidual& obj) {
521 return out << obj.to_string();
522 }
523
524#endif
525
526 };
527
528}
529
530#endif
A generic matrix with a fixed number of rows and columns.
Definition mat.h:136
mat< Type, N, K > resize(unsigned int n, unsigned int k)
Compatibility function to allow for allocation or resizing of dynamic matrices.
Definition mat.h:730
Multidual number algebra for functions of the form .
Definition multidual.h:26
multidual operator+(const multidual &other) const
Sum two multidual numbers.
Definition multidual.h:131
real & Dual(unsigned int i)
Access the i-th element of the multidual part, corresponding to the i-th independent variable in auto...
Definition multidual.h:101
multidual operator+() const
Identity (for consistency)
Definition multidual.h:125
multidual operator/(const multidual &other) const
Dual division.
Definition multidual.h:199
bool operator==(const multidual &other)
Check whether two multidual numbers have the same real and multidual parts.
Definition multidual.h:392
multidual & operator*=(real r)
Multiply this multidual number by a real number.
Definition multidual.h:321
multidual & operator-=(real r)
Subtract a real number from this multidual number.
Definition multidual.h:270
multidual & operator*=(const multidual &other)
Multiply this multidual number by another one.
Definition multidual.h:277
multidual & operator/=(const multidual &other)
Divide this multidual number by another one.
Definition multidual.h:329
multidual & operator+=(const multidual &other)
Sum a real number to this one.
Definition multidual.h:246
real Dual(unsigned int i) const
Get the i-th element of the multidual part, corresponding to the i-th independent variable in automat...
Definition multidual.h:93
vec< real, N > v
The dual part of the multidimensional dual number as a real vector.
Definition multidual.h:35
multidual & operator-=(const multidual &other)
Subtract a real number from this one.
Definition multidual.h:262
friend std::ostream & operator<<(std::ostream &out, const multidual &obj)
Stream the multidual number in string representation to an output stream (std::ostream)
Definition multidual.h:520
unsigned int size() const
Get the number of independent variables associated with the multidual number.
Definition multidual.h:467
multidual operator-(real r) const
Subtract a real number from a multidual number.
Definition multidual.h:155
multidual operator*(const multidual &other) const
Multiply two multidual numbers.
Definition multidual.h:161
multidual & operator+=(real r)
Sum a real number to this multidual number.
Definition multidual.h:255
multidual operator*(real r) const
Multiply a multidual number by a real number.
Definition multidual.h:193
multidual(real r, vec< real, N > u)
Construct a multidual number from a real number and an N dimensional vector.
Definition multidual.h:48
real a
The real part of the multidimensional dual number.
Definition multidual.h:31
multidual operator/(real r) const
Divide a multidual number by a real number.
Definition multidual.h:240
multidual & operator/=(real r)
Divide a multidual number by a real number.
Definition multidual.h:374
std::string to_string(const std::string &epsilon="ε") const
Convert the multidual number to string representation.
Definition multidual.h:503
vec< real, N > & Dual()
Access the multidual part.
Definition multidual.h:85
static vec< real, N > extract_real(const vec< multidual< N >, N > &v)
Extract the real vector from a vector of multidual numbers as a vec<real, N>
Definition multidual.h:417
vec< real, N > Dual() const
Get the multidual part.
Definition multidual.h:79
multidual(real r)
Construct a multidual number from a real number.
Definition multidual.h:53
static vec< multidual< N >, N > make_argument(const Vector &x)
Construct an N-dimensional vector of multidual numbers to be passed as argument to a multidual functi...
Definition multidual.h:401
real Re() const
Get the real part.
Definition multidual.h:67
static mat< real, N, N > extract_dual(const vec< multidual< N >, N > &v)
Extract the dual matrix (Jacobian) from a vector of multidual numbers as a mat<N, N>
Definition multidual.h:433
multidual inverse() const
Get the inverse of a multidual number.
Definition multidual.h:113
multidual operator+(real r) const
Sum a real number to a multidual number.
Definition multidual.h:137
multidual operator-() const
Get the opposite of a multidual number.
Definition multidual.h:143
static void extract(const vec< multidual< N >, N > &v, vec< real, N > &x, mat< real, N, N > &J)
Extract the real vector and dual matrix from a vector of multidual numbers as a vec<real,...
Definition multidual.h:450
void resize(unsigned int size)
Change the size of the dual part of the number (only for dynamically allocated vectors)
Definition multidual.h:474
multidual conjugate() const
Get the multidual conjugate.
Definition multidual.h:107
real & Re()
Access the real part.
Definition multidual.h:73
multidual()
Construct a multidual number as .
Definition multidual.h:43
multidual & operator=(real x)
Initialize a multidual number from a real number.
Definition multidual.h:59
multidual operator-(const multidual &other) const
Subtract two multidual numbers.
Definition multidual.h:149
A statically allocated N-dimensional vector with elements of the given type.
Definition vec.h:92
void resize(size_t n) const
Compatibility function to allow for allocation or resizing of dynamic vectors.
Definition vec.h:459
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compilation op...
Definition error.h:219
Main namespace of the library which contains all functions and objects.
Definition algebra.h:27
double real
A real number, defined as a floating point type.
Definition constants.h:207
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition dual2_functions.h:242
Vector make_error()
Create a vector representing an error state, with all NaN values.
Definition algebra.h:103
auto max(const Vector &X)
Finds the maximum value inside a dataset.
Definition dataset.h:326
TH_CONSTEXPR real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:74
@ DivByZero
Division by zero.
constexpr real MACH_EPSILON
Machine epsilon for the real type.
Definition constants.h:216