3
0
mirror of https://github.com/triqs/dft_tools synced 2024-11-01 19:53:45 +01:00
dft_tools/doc/reference/c++/arrays/map.rst
Olivier Parcollet a730f093d6 arrays: fix fold and update documentation
- fold was not correct in e.g. passing an int as init instead of a
  double (was leading to narrowing in return).
- better return type deduction.
- there was an error in the doc (order of argument in the lambda !)
- add a more complex example (Frobenius norm of matrices).
2014-04-09 21:24:03 +02:00

154 lines
3.8 KiB
ReStructuredText

.. highlight:: c
.. _arr_map_fold:
Functional constructs : map & fold
###########################################
Two standard functional constructs are provided :
* *map* that promotes a function acting on the array element to an array function, acting
element by element.
* *fold* is the reduction of a function on the array.
.. _map:
map
========================================================
* **Purpose** :
map promotes any function into an `array function`, acting term by term.
* **Synopsis** ::
template<class F> auto map (F f);
If `f` is a function, or a function object ::
T2 f(T1)
Then map(f) is a function::
template<ImmutableCuboidArray A> auto map(f) (A const &)
with :
* A::value_type == T1
* The returned type of map(f) models the :ref:`ImmutableCuboidArray` concept
* with the same domain as A
* with value_type == T2
* **Example** :
.. compileblock::
#include <triqs/arrays.hpp>
using namespace triqs;
int main() {
// declare and init a matrix
clef::placeholder<0> i_; clef::placeholder<1> j_;
arrays::matrix<int> A (2,2); A(i_,j_) << i_ + j_ ;
// the mapped function
auto F = arrays::map([](int i) { return i*2.5;});
std::cout<< "A = " << A << std::endl;
std::cout<< "F(A) = " << F(A) << std::endl; // oops no computation done
std::cout<< "F(A) = " << make_matrix(F(A)) << std::endl;
std::cout<< "3*F(2*A) = " << make_matrix(3*F(2*A)) << std::endl;
}
fold
========================================================
* **Purpose** :
fold implements the folding (or reduction) on the array.
* **Syntax** :
If `f` is a function, or a function object of synopsis (T, R being 2 types) ::
R f (R , T)
then ::
auto F = fold(f);
is a callable object which can fold any array of value_type T.
So, if
* A is a type which models the :ref:`ImmutableCuboidArray` concept
(e.g. an array , a matrix, a vector, an expression, ...)
* A::value_type is T
then ::
fold (f) ( A, R init = R() ) = f(f(f(f(init, a(0,0)), a(0,1)),a(0,2)),a(0,3), ....)
Note that :
* The order of traversal is the same as foreach.
* The precise return type of fold is an implementation detail, depending on the precise type of f,
use auto to keep it.
* The function f will be inlined if possible, leading to efficient algorithms.
* fold is implemented using a foreach loop, hence it is efficient.
* **Example** :
Many algorithms can be written in form of map/fold.
The function :ref:`arr_fnt_sum` which returns the sum of all the elements of the array is implemented as ::
template <class A>
typename A::value_type sum(A const & a) { return fold ( std::plus<>()) (a); }
or the Frobenius norm of a matrix,
.. math::
\sum_{i=0}^{N-1} \sum_{j=0}^{N-1} | a_{ij} | ^2
reads :
.. compileblock::
#include <triqs/arrays.hpp>
#include <triqs/arrays/functional/fold.hpp>
using namespace triqs;
double frobenius_norm (arrays::matrix<double> const& a) {
auto l= [](double r, double x) {
auto ab = std::abs(x);
return r + ab * ab;
};
return std::sqrt(arrays::fold(l)(a,0));
}
int main() {
// declare and init a matrix
clef::placeholder<0> i_; clef::placeholder<1> j_;
arrays::matrix<double> A (2,2); A(i_,j_) << i_ + j_/2.0;
std::cout<< "A = " << A << std::endl;
std::cout<< "||A|| = " << frobenius_norm(A) << std::endl;
}
Note in this example :
* the simplicity of the code
* the genericity : it is valid for any dimension of array.
* internally, the library will rewrite it as a series of for loop, ordered in the TraversalOrder of the array
and inline the lambda.