Theoretica
A C++ numerical and automatic mathematical library
autodiff.h
Go to the documentation of this file.
1 
5 
6 #ifndef THEORETICA_AUTODIFF_H
7 #define THEORETICA_AUTODIFF_H
8 
9 #include "dual.h"
10 #include "dual2.h"
11 #include "multidual.h"
12 #include "../algebra/vec.h"
13 #include "../algebra/mat.h"
14 #include "../core/error.h"
15 #include "../core/core_traits.h"
16 #include "./autodiff_types.h"
17 
18 #include <functional>
19 
20 
21 namespace theoretica {
22 
24  namespace autodiff {
25 
26 
27  // Univariate automatic differentiation
28 
29 
37  template <
38  typename DualFunction = std::function<dual(dual)>,
39  enable_dual_func<DualFunction> = true
40  >
41  inline real deriv(DualFunction f, real x) {
42  return f(dual(x, 1.0)).Dual();
43  }
44 
45 
54  template <
55  typename DualFunction = std::function<dual(dual)>,
56  enable_dual_func<DualFunction> = true
57  >
58  inline auto deriv(DualFunction f) {
59 
60  return [f](real x) -> real {
61  return autodiff::deriv(f, x);
62  };
63  }
64 
65 
73  template <
74  typename Dual2Function = std::function<dual2(dual2)>,
75  enable_dual2_func<Dual2Function> = true
76  >
77  inline real deriv2(Dual2Function f, real x) {
78  return f(dual2(x, 1.0, 0.0)).Dual2();
79  }
80 
81 
90  template <
91  typename Dual2Function = std::function<dual2(dual2)>,
92  enable_dual2_func<Dual2Function> = true
93  >
94  inline auto deriv2(Dual2Function f) {
95 
96  return [f](real x) -> real {
97  return autodiff::deriv2(f, x);
98  };
99  }
100 
101 
102  // Differential operators
103 
104 
109  template <
110  typename MultidualType,
111  typename Vector = vec<real>
112  >
113  inline auto make_autodiff_arg(const Vector& x) {
114 
115  constexpr size_t N = MultidualType::vector_argument;
117  arg.resize(x.size());
118 
119  // Iterate over each element, setting the dual part to
120  // the i-th element of the canonical base
121  for (unsigned int i = 0; i < x.size(); ++i) {
122  arg[i] = MultidualType(
123  x[i], vec<real, N>::euclidean_base(i, x.size())
124  );
125  }
126 
127  return arg;
128  }
129 
130 
143  template <
144  typename Function, typename Vector = vec<real>,
145  enable_scalar_field<Function> = true,
146  enable_vector<Vector> = true
147  >
148  inline auto gradient(Function f, const Vector& x) {
149 
150  // Extract the return type of the function
151  using R = return_type_t<Function>;
152 
153  return f(make_autodiff_arg<R>(x)).Dual();
154  }
155 
156 
168  template <
169  typename Function,
170  enable_scalar_field<Function> = true
171  >
172  inline auto gradient(Function f) {
173 
174  constexpr size_t N = return_type_t<Function>::vector_argument;
175 
176  return [f](vec<real, N> x) {
177  return gradient(f, x);
178  };
179  }
180 
181 
193  template <
194  typename Function, typename Vector = vec<real>,
195  enable_scalar_field<Function> = true,
196  enable_vector<Vector> = true
197  >
198  inline real divergence(Function f, const Vector& x) {
199 
200  using MultidualT = return_type_t<Function>;
201  MultidualT d = f(MultidualT::make_argument(x));
202 
203  real div = 0;
204  for (unsigned int i = 0; i < d.v.size(); ++i)
205  div += d.v[i];
206 
207  return div;
208  }
209 
210 
221  template <
222  typename Function,
223  enable_scalar_field<Function> = true
224  >
225  inline auto divergence(Function f) {
226 
227  constexpr size_t N = return_type_t<Function>::vector_argument;
228 
229  return [f](vec<real, N> x) {
230  return divergence(f, x);
231  };
232  }
233 
234 
242  template<unsigned int N = 0, unsigned int M = 0>
244  vec<multidual<N>, M>(*f)(vec<multidual<N>, N>), const vec<real, N>& x) {
245 
247 
248  // Construct the jacobian matrix
249  mat<real, M, N> J;
250  J.resize(res.size(), x.size());
251 
252  for (unsigned int j = 0; j < J.rows(); ++j)
253  for (unsigned int i = 0; i < res[j].v.size(); ++i)
254  J(j, i) = res[j].v[i];
255 
256  return J;
257  }
258 
259 
267  template<unsigned int N = 0, unsigned int M = 0>
268  inline auto jacobian(
269  vec<multidual<N>, M>(*f)(vec<multidual<N>, N>)) {
270 
271  return [f](vec<real, N> x) {
272  return jacobian(f, x);
273  };
274  }
275 
276 
285  template<unsigned int N = 0>
287  vec<multidual<N>, N>(*f)(vec<multidual<N>, N>), const vec<real, N>& x) {
288 
289  if(x.size() != 3) {
290  TH_MATH_ERROR("th::curl", x.size(), INVALID_ARGUMENT);
291  return vec<real, N>(nan(), x.size());
292  }
293 
294  mat<real, N, N> J = jacobian<N, N>(f, x);
295  J.resize(3, 3);
296 
297  vec<real, N> res;
298  res.resize(3);
299 
300  res[0] = J(2, 1) - J(1, 2);
301  res[1] = J(0, 2) - J(2, 0);
302  res[2] = J(1, 0) - J(0, 1);
303 
304  return res;
305  }
306 
307 
316  template<unsigned int N = 0>
317  inline auto curl(vec<multidual<N>, N>(*f)(vec<multidual<N>, N>)) {
318 
319  return [f](vec<real, N> x) {
320  return curl(f, x);
321  };
322  }
323 
324 
340  template<unsigned int N = 0>
342  const vec<real, N>& x, const vec<real, N>& v) {
343 
344  return v * dot(v, gradient(f, x));
345  }
346 
347 
364  template<unsigned int N = 0>
366  multidual<N>(*f)(vec<multidual<N>, N>), const vec<real, N>& v) {
367 
368  return [f, v](vec<real, N> x) {
369  return directional_derivative(f, x, v);
370  };
371  }
372 
373 
382  template<unsigned int N = 0>
383  inline real laplacian(dual2(*f)(vec<dual2, N>), const vec<real, N>& x) {
384 
385  real res = 0;
386  vec<dual2, N> d;
387  d.resize(x.size());
388 
389  for (unsigned int i = 0; i < x.size(); ++i)
390  d[i].a = x[i];
391 
392  for (unsigned int i = 0; i < x.size(); ++i) {
393  d[i].b = 1;
394  res += f(d).Dual2();
395  d[i].b = 0;
396  }
397 
398  return res;
399  }
400 
401 
410  template<unsigned int N = 0>
411  inline auto laplacian(dual2(*f)(vec<dual2, N>)) {
412 
413  return [f](vec<real, N> x) {
414  return laplacian(f, x);
415  };
416  }
417 
418 
433  template<unsigned int N = 0>
435  multidual<N>(*f)(vec<multidual<N>, N>),
436  multidual<N>(*H)(vec<multidual<N>, N>),
437  vec<real, N> eta) {
438 
439  return gradient(f, eta)
440  * mat<real, N, N>::symplectic(eta.size(), eta.size())
441  * gradient(H, eta);
442  }
443 
444  }
445 }
446 
447 #endif
Types and traits for automatic differentiation.
Second order dual number class.
Definition: dual2.h:29
Dual number class.
Definition: dual.h:28
A generic matrix with a fixed number of rows and columns.
Definition: mat.h:132
mat< Type, N, K > resize(unsigned int n, unsigned int k) const
Compatibility function to allow for allocation or resizing of dynamic matrices.
Definition: mat.h:579
TH_CONSTEXPR unsigned int rows() const
Get the number of rows of the matrix.
Definition: mat.h:465
static mat< Type, N, K > symplectic(unsigned int n=0, unsigned int k=0)
A symplectic NxN matrix, where for some natural K.
Definition: mat.h:684
Multidual number algebra for functions of the form .
Definition: multidual.h:26
void resize(size_t n) const
Compatibility function to allow for allocation or resizing of dynamic vectors.
Definition: vec.h:412
TH_CONSTEXPR unsigned int size() const
Returns the size of the vector (N)
Definition: vec.h:402
Second order dual number class.
Dual number class.
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compiling opti...
Definition: error.h:219
Multidual numbers.
auto dot(const Vector1 &v, const Vector2 &w)
Computes the dot product between two vectors, using the Hermitian form if needed.
Definition: algebra.h:351
vec< real, N > curl(vec< multidual< N >, N >(*f)(vec< multidual< N >, N >), const vec< real, N > &x)
Compute the curl for a given of a vector field defined by using automatic differentiation.
Definition: autodiff.h:286
real sturm_liouville(multidual< N >(*f)(vec< multidual< N >, N >), multidual< N >(*H)(vec< multidual< N >, N >), vec< real, N > eta)
Compute the Sturm-Liouville operator on a generic function of the form with respect to a given Hamil...
Definition: autodiff.h:434
real deriv(DualFunction f, real x)
Compute the derivative of a function at the given point using univariate automatic differentiation.
Definition: autodiff.h:41
real laplacian(dual2(*f)(vec< dual2, N >), const vec< real, N > &x)
Compute the Laplacian differential operator for a generic function of the form at a given $\vec x$.
Definition: autodiff.h:383
mat< real, M, N > jacobian(vec< multidual< N >, M >(*f)(vec< multidual< N >, N >), const vec< real, N > &x)
Compute the jacobian of a vector field of the form .
Definition: autodiff.h:243
real deriv2(Dual2Function f, real x)
Compute the second derivative of a function at the given point using univariate automatic differentia...
Definition: autodiff.h:77
auto gradient(Function f, const Vector &x)
Compute the gradient for a given of a scalar field of the form using automatic differentiation.
Definition: autodiff.h:148
auto make_autodiff_arg(const Vector &x)
Prepare a vector of multidual numbers in "canonical" form, where the i-th element of the vector has a...
Definition: autodiff.h:113
real divergence(Function f, const Vector &x)
Compute the divergence for a given of a scalar field of the form using automatic differentiation.
Definition: autodiff.h:198
vec< real, N > directional_derivative(multidual< N >(*f)(vec< multidual< N >, N >), const vec< real, N > &x, const vec< real, N > &v)
Compute the directional derivative of a generic function of the form .
Definition: autodiff.h:341
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:188
typename _internal::func_helper< Function >::return_type return_type_t
Extract the return type of a Callable object, such as a function pointer or lambda function.
Definition: core_traits.h:246
std::enable_if_t< is_vector< Structure >::value, T > enable_vector
Enable a function overload if the template typename is considerable a vector.
Definition: core_traits.h:167
real nan()
Return a quiet NaN number in floating point representation.
Definition: error.h:54