deriv.cc 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // Numerical differentiation
  3. // Adapted from blitz++/examples/deriv.cpp
  4. // Daniel Llorens - 2015
  5. #include "ra/ra.hh"
  6. #include <iostream>
  7. using std::cout, std::endl, std::flush;
  8. using Array1D = ra::Big<double, 1>;
  9. // "index placeholder" which represents the array index for the first axis in a multidimensional expression.
  10. ra::TensorIndex<0> i;
  11. int main()
  12. {
  13. // In this example, the function cos(x)^2 and its second derivative
  14. // 2 (sin(x)^2 - cos(x)^2) are sampled over the range [0,1).
  15. // The second derivative is approximated numerically using a
  16. // [ 1 -2 1 ] mask, and the approximation error is computed.
  17. const int numSamples = 100; // Number of samples
  18. double delta = 1. / numSamples; // Spacing of samples
  19. ra::Iota<int> R(numSamples); // Index set 0 .. (numSamples-1)
  20. cout << "R... " << R << endl;
  21. // Sample the function y = cos(x)^2 over [0,1)
  22. //
  23. // The initialization for y (below) will be translated via expression
  24. // templates into something of the flavour
  25. //
  26. // for (unsigned i=0; i < 99; ++i)
  27. // {
  28. // double _t1 = cos(i * delta);
  29. // y[i] = _t1 * _t1;
  30. // }
  31. // [ra] You need to give a size at construction because 'i' doesn't provide one; you could do instead
  32. // Array1D y = sqr(cos(R * delta));
  33. // since R does have a defined size.
  34. Array1D y({numSamples}, sqr(cos(i * delta)));
  35. // Sample the exact second derivative
  36. Array1D y2exact({numSamples}, 2.0 * (sqr(sin(i * delta)) - sqr(cos(i * delta))));
  37. // Approximate the 2nd derivative using a [ 1 -2 1 ] mask
  38. // We can only apply this mask to the elements 1 .. 98, since
  39. // we need one element on either side to apply the mask.
  40. // I-1 etc. are beatable if RA_DO_OPT is true.
  41. ra::Iota<int> I(numSamples-2, 1);
  42. Array1D y2({numSamples}, ra::none);
  43. y2(I) = (y(I-1) - 2 * y(I) + y(I+1)) / (delta*delta);
  44. // The above difference equation will be transformed into
  45. // something along the lines of
  46. //
  47. // double _t2 = delta*delta;
  48. // for (int i=1; i < 99; ++i)
  49. // y2[i] = (y[i-1] - 2 * y[i] + y[i+1]) / _t2;
  50. // Now calculate the root mean square approximation error:
  51. // [ra] TODO don't have mean() yet
  52. double error = sqrt(sum(sqr(y2(I) - y2exact(I)))/size(I));
  53. // Display a few elements from the vectors.
  54. // This range constructor means elements 1 to 91 in increments
  55. // of 15.
  56. ra::Iota<int> displayRange(7, 1, 15);
  57. cout << "Exact derivative:" << y2exact(displayRange) << endl
  58. << "Approximation: " << y2(displayRange) << endl
  59. << "RMS Error: " << error << endl;
  60. return 0;
  61. }