ALPSCore reference
binning_analysis.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3  * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4  * For use in publications, see ACKNOWLEDGE.TXT
5  */
6 
9 #include <alps/hdf5/vector.hpp>
10 
11 
12 #include <boost/preprocessor/tuple/to_seq.hpp>
13 #include <boost/preprocessor/seq/for_each.hpp>
14 
15 #define ALPS_ACCUMULATOR_VALUE_TYPES_SEQ BOOST_PP_TUPLE_TO_SEQ(ALPS_ACCUMULATOR_VALUE_TYPES_SIZE, (ALPS_ACCUMULATOR_VALUE_TYPES))
16 
17 // DEBUG: to force boost assertion to be an exception, to work nicely with google test
18 #define BOOST_ENABLE_ASSERT_HANDLER
19 #include "boost/assert.hpp"
20 
21 namespace boost {
22  inline void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line)
23  {
24  std::ostringstream errmsg;
25  errmsg << "Boost assertion " << expr << " failed in "
26  << function << ":\n"
27  << file << "(" << line << "): "
28  << msg;
29  throw std::logic_error(errmsg.str());
30  }
31 
32  inline void assertion_failed(char const * expr, char const * function, char const * file, long line)
33  {
34  std::ostringstream errmsg;
35  errmsg << "Boost assertion " << expr << " failed in "
36  << function << ":\n"
37  << file << "(" << line << ")";
38  throw std::logic_error(errmsg.str());
39  }
40 }
41 
42 namespace alps {
43  namespace accumulators {
44  namespace impl {
45 
46  //
47  // Accumulator<T, binning_analysis_tag, B>
48  //
49 
50  template<typename T, typename B>
52  : B()
53  , m_ac_sum()
54  , m_ac_sum2()
55  , m_ac_partial()
56  , m_ac_count()
57  {}
58 
59  template<typename T, typename B>
61  : B(arg)
62  , m_ac_sum(arg.m_ac_sum)
63  , m_ac_sum2(arg.m_ac_sum2)
64  , m_ac_partial(arg.m_ac_partial)
65  , m_ac_count(arg.m_ac_count)
66  {}
67 
68  // This method is broken and does not compile
69  // Apparently, it has never been instantiated before...
70  /*
71  template<typename T, typename B>
72  typename alps::accumulators::convergence_type<B>::type Accumulator<T, binning_analysis_tag, B>::converged_errors() const {
73  typedef typename alps::numeric::scalar<typename convergence_type<T>::type>::type convergence_scalar_type;
74 
75  typename alps::accumulators::convergence_type<B>::type conv;
76  typename alps::accumulators::error_type<B>::type err = error();
77  check_size(conv, err);
78  const unsigned int range = 4;
79  const unsigned int depth = (m_ac_sum2.size() < 8 ? 1 : m_ac_sum2.size() - 7);
80  if (depth < range)
81  conv = 0 * conv + (convergence_scalar_type)MAYBE_CONVERGED;
82  else {
83  conv = 0 * conv + (convergence_scalar_type)CONVERGED;
84  // TODO: how to we iterate over the datatype?
85  for (unsigned int i = depth - range; i < depth - 1; ++i) {
86  typename slice_index<typename alps::accumulators::convergence_type<B>::type>::type it;
87  result_type this_err(error(i));
88  for (it = slices(conv).first; it != slices(conv).second; ++it)
89  if (std::abs(slice_value(this_err, it)) >= std::abs(slice_value(err,it)))
90  slice_value(conv,it) = CONVERGED;
91  else if (std::abs(slice_value(this_err, it)) < 0.824 * std::abs(slice_value(err,it)))
92  slice_value(conv,it) = NOT_CONVERGED;
93  else if (std::abs(slice_value(this_err, it)) < 0.9 * std::abs(slice_value(err,it)) && slice_value(conv, it) != NOT_CONVERGED)
94  slice_value(conv,it) = MAYBE_CONVERGED;
95  }
96  }
97  return conv;
98  }*/
99 
100  template<typename T, typename B>
102  Accumulator<T, binning_analysis_tag, B>::error(std::size_t bin_level) const {
103  using alps::numeric::operator*;
104  using alps::numeric::operator-;
105  using alps::numeric::operator/;
106  using std::sqrt;
107  using alps::numeric::sqrt;
108 
109  // Basically, we try to estimate the integrated
110  // autocorrelation time as
111  //
112  // tau_int = s^2(n) / s^2(1),
113  //
114  // where s^2(n) is the sample variance when grouping
115  // n measurements together in a bin. In the above
116  // approximation, there is a tradeoff to be had between
117  //
118  // (1) formal validity, which improves with n,
119  // (2) statistical uncertainty, which improves with N/n,
120  //
121  // where N is the total number of steps. Here, 8 means
122  // N/n = 2**8 = 256, which from the \chi^2 distribution
123  // can be worked out to be a ~90% confidence interval
124  // for an accuracy of 10%.
125  if (m_ac_sum2.size()<8) {
126  bin_level = 0;
127  } else if (bin_level > m_ac_sum2.size() - 8) {
128  bin_level = m_ac_sum2.size() - 8;
129  }
130 
132  typedef typename alps::numeric::scalar<error_type>::type error_scalar_type;
133 
134  // if not enough bins are available, return infinity
135  if (m_ac_sum2.size() < 2)
136  return alps::numeric::inf<error_type>(B::error()); // FIXME: we call error() only to know the data size
137 
138  // TODO: make library for scalar type
139  error_scalar_type one = 1;
140 
141  error_scalar_type binlen = 1ll << bin_level;
142  BOOST_ASSERT_MSG(bin_level<m_ac_count.size(),"bin_level within the range of m_ac_count");
143  error_scalar_type N_i = m_ac_count[bin_level];
144  BOOST_ASSERT_MSG(bin_level<m_ac_sum.size(),"bin_level within the range of m_ac_sum");
145  error_type sum_i = m_ac_sum[bin_level];
146  BOOST_ASSERT_MSG(bin_level<m_ac_sum2.size(),"bin_level within the range of m_ac_sum2");
147  error_type sum2_i = m_ac_sum2[bin_level];
148  error_type var_i = (sum2_i / binlen - sum_i * sum_i / (N_i * binlen)) / (N_i * binlen);
149  return sqrt(var_i / (N_i - one));
150  }
151 
152  template<typename T, typename B>
154  using alps::numeric::operator*;
155  using alps::numeric::operator-;
156  using alps::numeric::operator/;
157 
158  typedef typename mean_type<B>::type mean_type;
159 
160  // TODO: make library for scalar type
161  typedef typename alps::numeric::scalar<mean_type>::type mean_scalar_type;
162 
163  mean_type err = error();
164 
165  // if not enoght bins are available, return infinity
166  if (m_ac_sum2.size() < 2)
167  return alps::numeric::inf<mean_type>(err);
168 
169  mean_scalar_type one = 1;
170  mean_scalar_type two = 2;
171 
172  mean_scalar_type N_0 = m_ac_count[0];
173  mean_type sum_0 = m_ac_sum[0];
174  mean_type sum2_0 = m_ac_sum2[0];
175  mean_type var_0 = (sum2_0 - sum_0 * sum_0 / N_0) / N_0;
177  mean_scalar_type fac = B::count() - 1;
178  return (err * err * fac / var_0 - one) / two;
179  }
180 
181  template<typename T, typename B>
183  using alps::numeric::operator+=;
184  using alps::numeric::operator*;
186 
187  B::operator()(val);
188  if(B::count() == (1UL << m_ac_sum2.size())) {
189  m_ac_sum2.push_back(T());
190  check_size(m_ac_sum2.back(), val);
191  m_ac_sum.push_back(T());
192  check_size(m_ac_sum.back(), val);
193  m_ac_partial.push_back(m_ac_sum[0]);
194  check_size(m_ac_partial.back(), val);
195  m_ac_count.push_back(typename count_type<B>::type());
196  }
197  BOOST_ASSERT_MSG(m_ac_partial.size() >= m_ac_sum2.size(), "m_ac_partial is as large as m_ac_sum2");
198  BOOST_ASSERT_MSG(m_ac_count.size() >= m_ac_sum2.size(), "m_ac_count is as large as m_ac_sum2");
199  BOOST_ASSERT_MSG(m_ac_sum.size() >= m_ac_sum2.size(), "m_ac_sum is as large as m_ac_sum2");
200  for (unsigned i = 0; i < m_ac_sum2.size(); ++i) {
201  m_ac_partial[i] += val;
202 
203  // in other words: (B::count() % (1L << i) == 0)
204  if (!(B::count() & ((1ll << i) - 1))) {
205  m_ac_sum2[i] += m_ac_partial[i] * m_ac_partial[i];
206  m_ac_sum[i] += m_ac_partial[i];
207  m_ac_count[i]++;
208  m_ac_partial[i] = T();
209  check_size(m_ac_partial[i], val);
210  }
211  }
212  }
213 
214  template<typename T, typename B>
216  B::save(ar);
217  if (B::count())
218  ar["tau/partialbin"] = m_ac_sum;
219  ar["tau/data"] = m_ac_sum2;
220  ar["tau/ac_count"] = m_ac_count; // FIXME: proper dataset name? to be saved always?
221  ar["tau/ac_partial"] = m_ac_partial; // FIXME: proper dataset name? to be saved always?
222  }
223 
224  template<typename T, typename B>
225  void Accumulator<T, binning_analysis_tag, B>::load(hdf5::archive & ar) { // TODO: make archive const
226  B::load(ar);
227  if (ar.is_data("tau/partialbin"))
228  ar["tau/partialbin"] >> m_ac_sum;
229  ar["tau/data"] >> m_ac_sum2;
230  if (ar.is_data("tau/ac_count"))
231  ar["tau/ac_count"] >> m_ac_count; // FIXME: proper dataset name?
232  if (ar.is_data("tau/ac_partial"))
233  ar["tau/ac_partial"] >> m_ac_partial; // FIXME: proper dataset name?
234  }
235 
236  template<typename T, typename B>
237  bool Accumulator<T, binning_analysis_tag, B>::can_load(hdf5::archive & ar) { // TODO: make archive const
239  const char name[]="tau/data";
240  const std::size_t ndim=get_extent(T()).size()+1;
241  return B::can_load(ar) &&
242  detail::archive_trait<T>::can_load(ar, name, ndim); // FIXME: `T` should rather be `error_type`, defined at class level
243  }
244 
245  template<typename T, typename B>
247  B::reset();
248  m_ac_sum = std::vector<T>();
249  m_ac_sum2 = std::vector<T>();
250  m_ac_partial = std::vector<T>();
251  m_ac_count = std::vector<typename count_type<B>::type>();
252  }
253 
254 #ifdef ALPS_HAVE_MPI
255  template<typename T, typename B>
257  alps::mpi::communicator const & comm
258  , int root
259  ) {
260 
261  if (comm.rank() == root) {
262  B::collective_merge(comm, root);
263  typedef typename alps::hdf5::scalar_type<typename mean_type<B>::type>::type mean_scalar_type;
264  std::size_t size = alps::mpi::all_reduce(comm, m_ac_count.size(), alps::mpi::maximum<std::size_t>());
265 
266  m_ac_count.resize(size);
267  B::reduce_if(comm, std::vector<typename count_type<B>::type>(m_ac_count), m_ac_count, std::plus<typename count_type<B>::type>(), root);
268 
269  m_ac_sum.resize(size);
271  B::reduce_if(comm, std::vector<T>(m_ac_sum), m_ac_sum, std::plus<mean_scalar_type>(), root);
272 
273  m_ac_sum2.resize(size);
275  B::reduce_if(comm, std::vector<T>(m_ac_sum2), m_ac_sum2, std::plus<mean_scalar_type>(), root);
276 
277  } else
278  const_cast<Accumulator<T, binning_analysis_tag, B> const *>(this)->collective_merge(comm, root);
279  }
280 
281  template<typename T, typename B>
283  alps::mpi::communicator const & comm
284  , int root
285  ) const {
286  B::collective_merge(comm, root);
287  if (comm.rank() == root)
288  throw std::runtime_error("A const object cannot be root" + ALPS_STACKTRACE);
289  else {
290  typedef typename alps::hdf5::scalar_type<typename mean_type<B>::type>::type mean_scalar_type;
291 
292  std::size_t size = alps::mpi::all_reduce(comm, m_ac_count.size(), alps::mpi::maximum<std::size_t>());
293  {
294  std::vector<typename count_type<B>::type> count(m_ac_count);
295  count.resize(size);
296  B::reduce_if(comm, count, std::plus<typename count_type<B>::type>(), root);
297  }
298  {
299  std::vector<T> sum(m_ac_sum);
300  sum.resize(size);
302  B::reduce_if(comm, sum, std::plus<mean_scalar_type>(), root);
303  }
304  {
305  std::vector<T> sum2(m_ac_sum2);
306  sum2.resize(size);
308  B::reduce_if(comm, sum2, std::plus<mean_scalar_type>(), root);
309  }
310  }
311  }
312 #endif
313 
314  #define ALPS_ACCUMULATOR_INST_BINNING_ANALYSIS_ACC(r, data, T) \
315  template class Accumulator<T, binning_analysis_tag, \
316  Accumulator<T, error_tag, \
317  Accumulator<T, mean_tag, \
318  Accumulator<T, count_tag, \
319  AccumulatorBase<T>>>>>;
320 
322 
323  //
324  // Result<T, binning_analysis_tag, B>
325  //
326 
327  template<typename T, typename B>
328  Result<T, binning_analysis_tag, B>::Result()
329  : B()
330  , m_ac_autocorrelation()
331  , m_ac_errors()
332  {}
333 
334  template<typename T, typename B>
335  auto Result<T, binning_analysis_tag, B>::error(std::size_t bin_level) const -> error_type const {
336  if (m_ac_errors.size() < 2)
337  return alps::numeric::inf<error_type>(B::error()); // FIXME: we call error() only to know the data size
338  // AG: Seems to be wrong? (see [https://github.com/ALPSCore/ALPSCore/issues/184])
339  // return m_ac_errors[bin_level >= m_ac_errors.size() ? 0 : bin_level];
340  return m_ac_errors[std::min(m_ac_errors.size()-1, bin_level)];
341  }
342 
343  template<typename T, typename B>
345  B::save(ar);
346  ar["error_bins"]=m_ac_errors;
347  ar["tau"] = m_ac_autocorrelation;
348  }
349 
350  template<typename T, typename B>
352  B::load(ar);
353  ar["error_bins"] >> m_ac_errors;
354  ar["tau"] >> m_ac_autocorrelation;
355  }
356 
357  template<typename T, typename B>
358  bool Result<T, binning_analysis_tag, B>::can_load(hdf5::archive & ar) { // TODO: make archive const
360  const char name[]="tau";
361  const std::size_t ndim=get_extent(T()).size();
362  return B::can_load(ar) &&
363  detail::archive_trait<T>::can_load(ar, name, ndim); // FIXME: `T` should rather be `error_type`, defined at class level
364  }
365 
366  template<typename T, typename B>
368  // using alps::numeric::operator-;
369  // for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
370  // *it = -*it;
371  B::negate();
372  }
373 
374  template<typename T, typename B>
376  using alps::numeric::operator*;
377  using alps::numeric::operator/;
378  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
379  *it = dynamic_cast<self_type &>(*this).error(it - m_ac_errors.begin()) / (this->mean() * this->mean());
380  B::inverse();
381  }
382 
383  #define NUMERIC_FUNCTION_USING \
384  using alps::numeric::sq; \
385  using alps::numeric::cbrt; \
386  using alps::numeric::cb; \
387  using std::sqrt; \
388  using alps::numeric::sqrt; \
389  using std::exp; \
390  using alps::numeric::exp; \
391  using std::log; \
392  using alps::numeric::log; \
393  using std::abs; \
394  using alps::numeric::abs; \
395  using std::pow; \
396  using alps::numeric::pow; \
397  using std::sin; \
398  using alps::numeric::sin; \
399  using std::cos; \
400  using alps::numeric::cos; \
401  using std::tan; \
402  using alps::numeric::tan; \
403  using std::sinh; \
404  using alps::numeric::sinh; \
405  using std::cosh; \
406  using alps::numeric::cosh; \
407  using std::tanh; \
408  using alps::numeric::tanh; \
409  using std::asin; \
410  using alps::numeric::asin; \
411  using std::acos; \
412  using alps::numeric::acos; \
413  using std::atan; \
414  using alps::numeric::atan; \
415  using alps::numeric::operator+; \
416  using alps::numeric::operator-; \
417  using alps::numeric::operator*; \
418  using alps::numeric::operator/;
419 
420  #define NUMERIC_FUNCTION_DECL(FUNCTION_NAME) \
421  template<typename T, typename B> \
422  void Result<T, binning_analysis_tag, B>:: FUNCTION_NAME()
423 
425  B::sin();
427  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
428  *it = abs(cos(this->mean()) * *it);
429  }
430 
432  B::cos();
434  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
435  *it = abs(-sin(this->mean()) * *it);
436  }
437 
439  B::tan();
441  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
442  *it = abs(error_scalar_type(1) / (cos(this->mean()) * cos(this->mean())) * *it);
443  }
444 
446  B::sinh();
448  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
449  *it = abs(cosh(this->mean()) * *it);
450  }
451 
453  B::cosh();
455  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
456  *it = abs(sinh(this->mean()) * *it);
457  }
458 
460  B::tanh();
462  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
463  *it = abs(error_scalar_type(1) / (cosh(this->mean()) * cosh(this->mean())) * *it);
464  }
465 
467  B::asin();
469  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
470  *it = abs(error_scalar_type(1) / sqrt( -this->mean() * this->mean() + error_scalar_type(1) ) * *it);
471  }
472 
474  B::acos();
476  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
477  *it = abs(error_scalar_type(-1) / sqrt( -this->mean() * this->mean() + error_scalar_type(1) ) * *it);
478  }
479 
481  B::atan();
483  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
484  *it = abs(error_scalar_type(1) / (this->mean() * this->mean() + error_scalar_type(1)) * *it);
485  }
486 
487  // abs does not change the error, so nothing has to be done ...
488 
490  B::sq();
492  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
493  *it = abs( this->mean() * (*it) * error_scalar_type(2) );
494  }
495 
497  B::sqrt();
499  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
500  *it = abs(*it / ( sqrt(this->mean()) * error_scalar_type(2) ));
501  }
502 
504  B::cb();
506  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
507  *it = abs( sq(this->mean()) * (*it) * error_scalar_type(3) );
508  }
509 
511  B::cbrt();
513  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
514  *it = abs(*it / ( sq(cbrt(this->mean())) * error_scalar_type(3) ));
515  }
516 
518  B::exp();
520  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
521  *it = exp(this->mean()) * *it;
522  }
523 
525  B::log();
527  for (error_iterator it = m_ac_errors.begin(); it != m_ac_errors.end(); ++it)
528  *it = abs(*it / this->mean());
529  }
530 
531  #define ALPS_ACCUMULATOR_INST_BINNING_ANALYSIS_RESULT(r, data, T) \
532  template class Result<T, binning_analysis_tag, \
533  Result<T, error_tag, \
534  Result<T, mean_tag, \
535  Result<T, count_tag, \
536  ResultBase<T>>>>>;
537 
539  }
540  }
541 }
boost::array< T, N > sinh(boost::array< T, N > arg)
result_wrapper cbrt(result_wrapper const &arg)
void check_size(T &, U const &)
Definition: check_size.hpp:40
boost::array< T, N > tanh(boost::array< T, N > arg)
boost::array< T, N > cbrt(boost::array< T, N > arg)
boost::array< T, N > atan(boost::array< T, N > arg)
boost::array< T, N > log(boost::array< T, N > arg)
void load(archive &ar, std::string const &path, T &value, std::vector< std::size_t > chunk=std::vector< std::size_t >(), std::vector< std::size_t >=std::vector< std::size_t >())
Definition: archive.hpp:309
int size() const
Returns the number of processes in this communicator.
Definition: mpi.hpp:163
boost::array< T, N > sqrt(boost::array< T, N > arg)
result_wrapper cos(result_wrapper const &arg)
void all_reduce(const alps::mpi::communicator &comm, const T *val, int n, T *out_val, const OP &)
Performs MPI_Allreduce for array of a primitive type, T[n].
Definition: mpi.hpp:366
std::enable_if<!is_sequence< T >::value, std::size_t >::type size(T const &)
Definition: size.hpp:20
boost::array< T, N > cos(boost::array< T, N > arg)
bool is_data(std::string path) const
Definition: archive.cpp:170
result_wrapper sqrt(result_wrapper const &arg)
#define ALPS_ACCUMULATOR_INST_BINNING_ANALYSIS_RESULT(r, data, T)
result_wrapper cb(result_wrapper const &arg)
result_wrapper sq(result_wrapper const &arg)
#define ALPS_ACCUMULATOR_VALUE_TYPES_SEQ
std::vector< std::size_t > get_extent(T const &value)
Definition: archive.hpp:280
#define NUMERIC_FUNCTION_USING
Encapsulation of an MPI communicator and some communicator-related operations.
Definition: mpi.hpp:111
std::enable_if<!is_sequence< T >::value, void >::type set_negative_0(T &x)
Metafunction returning "mathematical scalar" type for type T.
Definition: scalar.hpp:28
mean_type< T >::type mean(T const &arg)
Definition: mean.hpp:47
boost::array< T, N > cosh(boost::array< T, N > arg)
result_wrapper log(result_wrapper const &arg)
#define ALPS_ACCUMULATOR_INST_BINNING_ANALYSIS_ACC(r, data, T)
void assertion_failed_msg(char const *expr, char const *msg, char const *function, char const *file, long line)
void reset(accumulator_wrapper &arg)
boost::array< T, N > exp(boost::array< T, N > arg)
void rectangularize(const T &)
Make sure that vector-of-vectors is a rectangular matrix (generic dummy template) ...
result_wrapper tanh(result_wrapper const &arg)
error_type< T >::type error(T const &arg)
Definition: error.hpp:47
#define NUMERIC_FUNCTION_DECL(FUNCTION_NAME)
result_wrapper acos(result_wrapper const &arg)
boost::array< T, N > asin(boost::array< T, N > arg)
boost::array< T, N > sin(boost::array< T, N > arg)
Class-holder for reduction operations (and a functor) for type T.
Definition: mpi.hpp:258
#define ALPS_STACKTRACE
Definition: stacktrace.hpp:37
autocorrelation_type< T >::type autocorrelation(T const &arg)
result_wrapper sin(result_wrapper const &arg)
result_wrapper asin(result_wrapper const &arg)
int rank() const
Returns process rank in this communicator.
Definition: mpi.hpp:156
boost::array< T, N > acos(boost::array< T, N > arg)
result_wrapper tan(result_wrapper const &arg)
result_wrapper abs(result_wrapper const &arg)
void assertion_failed(char const *expr, char const *function, char const *file, long line)
boost::array< T, N > cb(boost::array< T, N > arg)
boost::array< T, N > tan(boost::array< T, N > arg)
result_wrapper sinh(result_wrapper const &arg)
boost::array< T, N > sq(boost::array< T, N > arg)
result_wrapper cosh(result_wrapper const &arg)
count_type< T >::type count(T const &arg)
Definition: count.hpp:39
result_wrapper atan(result_wrapper const &arg)
void save(archive &ar, std::string const &path, T const &value, std::vector< std::size_t >=std::vector< std::size_t >(), std::vector< std::size_t > chunk=std::vector< std::size_t >(), std::vector< std::size_t >=std::vector< std::size_t >())
Definition: archive.hpp:292