Chebyshev
Unit testing for scientific software
estimator.h
Go to the documentation of this file.
1 
5 
6 #ifndef CHEBYSHEV_ESTIMATOR
7 #define CHEBYSHEV_ESTIMATOR
8 
9 
10 #include <functional>
11 #include <cmath>
12 
13 #include "../core/common.h"
14 #include "../core/random.h"
15 #include "./prec_structures.h"
16 
17 
18 namespace chebyshev {
19 namespace prec {
20 
21 
23  namespace estimator {
24 
25 
29  template<typename FloatType = double>
30  inline auto quadrature1D() {
31 
32  return [](
33  EndoFunction<FloatType> funcApprox,
34  EndoFunction<FloatType> funcExpected,
36 
37  if(options.domain.size() != 1)
38  throw std::runtime_error(
39  "estimator::quadrature1D only works on mono-dimensional domains");
40 
41  interval domain = options.domain[0];
42 
43  FloatType sum = 0;
44  FloatType sumSqr = 0;
45  FloatType sumAbs = 0;
46  FloatType max = 0;
47 
48  const FloatType length = domain.length();
49  const FloatType dx = length / options.iterations;
50  FloatType x;
51  FloatType coeff;
52 
53  FloatType diff = std::abs(funcApprox(domain.a) - funcExpected(domain.a));
54 
55  sum += diff;
56  sumSqr += diff * diff;
57  sumAbs += std::abs(funcExpected(domain.a));
58  max = diff;
59 
60  for (unsigned int i = 1; i < options.iterations; ++i) {
61 
62  x = domain.a + i * dx;
63  diff = std::abs(funcApprox(x) - funcExpected(x));
64 
65  if(diff > max)
66  max = diff;
67 
68  if(i % 2 == 0)
69  coeff = 2;
70  else
71  coeff = 4;
72 
73  sum += coeff * diff;
74  sumSqr += coeff * diff * diff;
75  sumAbs += coeff * funcExpected(x);
76  }
77 
78  diff = std::abs(funcApprox(domain.b) - funcExpected(domain.b));
79 
80  sum += diff;
81  sumSqr += diff * diff;
82  sumAbs += std::abs(funcExpected(domain.b));
83 
84  if(diff > max)
85  max = diff;
86 
87  estimate_result res {};
88  res.absErr = sum;
89  res.maxErr = max;
90  res.meanErr = (sum * dx / 3.0) / length;
91  res.rmsErr = std::sqrt((sumSqr * dx / 3.0) / length);
92  res.relErr = std::abs((sum * dx / 3.0) / (sumAbs * dx / 3.0));
93 
94  return res;
95  };
96  }
97 
98 
107  template<typename IntType = int, typename ReturnType = IntType>
108  inline auto discrete1D() {
109 
110  // Return a one-dimensional discrete estimator
111  // as a lambda function
112  return [](
113  std::function<IntType(ReturnType)> funcApprox,
114  std::function<IntType(ReturnType)> funcExpected,
116 
117  if(options.domain.size() != 1)
118  throw std::runtime_error(
119  "estimator::discrete1D only works on mono-dimensional domains");
120 
121  IntType extreme1 = IntType(std::ceil(options.domain[0].a));
122  IntType extreme2 = IntType(std::floor(options.domain[0].b));
123 
124  IntType lower = extreme1 < extreme2 ? extreme1 : extreme2;
125  IntType upper = extreme1 > extreme2 ? extreme1 : extreme2;
126 
127  long double maxErr = 0;
128  long double sumDiff = 0;
129  long double sumSqr = 0;
130  long double sumAbs = 0;
131  uint64_t totalPoints = 0;
132 
133  for (IntType n = lower; n <= upper; ++n) {
134 
135  const ReturnType resExpected = funcExpected(n);
136  const ReturnType resApprox = funcApprox(n);
137 
138  const long double diff = (long double) resExpected > resApprox ?
139  (resExpected - resApprox) : (resApprox - resExpected);
140 
141  maxErr = std::max(maxErr, diff);
142  sumDiff += diff;
143  sumSqr += diff * diff;
144  sumAbs += std::abs((long double) funcExpected(n));
145  totalPoints++;
146  }
147 
148  estimate_result res {};
149  res.absErr = sumAbs;
150  res.maxErr = maxErr;
151  res.meanErr = totalPoints > 0 ? (sumDiff / totalPoints) : 0;
152  res.rmsErr = totalPoints > 0 ? (std::sqrt(sumSqr) / totalPoints) : 0;
153  res.relErr = sumDiff / sumAbs;
154  return res;
155  };
156  }
157 
158 
162  template<typename FloatType = double>
163  inline auto montecarlo1D() {
164 
165  // Return a one-dimensional Monte Carlo estimator
166  // as a lambda function
167  return [](
168  EndoFunction<FloatType> funcApprox,
169  EndoFunction<FloatType> fExpected,
171 
172  if(options.domain.size() != 1)
173  throw std::runtime_error(
174  "estimator::montecarlo1D only works on mono-dimensional domains");
175 
176  FloatType sum = 0;
177  FloatType sumSqr = 0;
178  FloatType sumAbs = 0;
179  FloatType max = 0;
180  const FloatType length = options.domain[0].length();
181 
182  for (int i = 0; i < options.iterations; ++i) {
183 
184  FloatType x = random::uniform(options.domain[0].a, options.domain[0].b);
185  const FloatType diff = std::abs(funcApprox(x) - funcExpected(x));
186 
187  max = std::max(max, diff);
188  sum += diff;
189  sumSqr += diff * diff;
190  sumAbs += std::abs(funcExpected(x));
191  }
192 
193  estimate_result res {};
194  res.maxErr = max;
195  res.meanErr = sum / options.iterations;
196  res.absErr = sum * (length / options.iterations);
197  res.rmsErr = sumSqr * (length / options.iterations);
198  res.relErr = sum / sumAbs;
199 
200  return res;
201  };
202  }
203 
204 
211  template<typename FloatType = double, typename Vector = std::vector<FloatType>>
212  inline auto montecarlo(unsigned int dimensions) {
213 
214  // Return an n-dimensional Monte Carlo estimator
215  // as a lambda function
216  return [dimensions](
217  std::function<FloatType(Vector)> funcApprox,
218  std::function<FloatType(Vector)> fExpected,
220 
221  if(options.domain.size() != dimensions)
222  throw std::runtime_error(
223  "The estimation domain's dimension does not match "
224  "the instantiated number of dimensions "
225  "in estimator::montecarlo");
226 
227  FloatType sum = 0;
228  FloatType sumSqr = 0;
229  FloatType sumAbs = 0;
230  FloatType max = 0;
231 
232  // Compute the measure of a multi-interval
233  FloatType volume = 1;
234  for (interval k : options.domain)
235  volume *= k.length();
236 
237  Vector x (dimensions);
238 
239  for (int i = 0; i < options.iterations; ++i) {
240 
241  random::sample_uniform(x, options.domain);
242 
243  const FloatType diff = std::abs(funcApprox(x) - funcExpected(x));
244 
245  if(max < diff)
246  max = diff;
247 
248  sum += diff;
249  sumSqr += diff * diff;
250  sumAbs += std::abs(funcExpected(x));
251  }
252 
253  estimate_result res {};
254  res.maxErr = max;
255  res.meanErr = sum / options.iterations;
256  res.absErr = sum * (volume / options.iterations);
257  res.rmsErr = sumSqr * (volume / options.iterations);
258  res.relErr = sum / sumAbs;
259 
260  return res;
261  };
262  }
263 
264 
265  }
266 
267 }}
268 
269 
270 #endif
auto quadrature1D()
Use Simpson's quadrature scheme to approximate error integrals for univariate real functions (endofun...
Definition: estimator.h:30
auto discrete1D()
Use a discrete estimator over a lattice of points, here implemented in one dimension,...
Definition: estimator.h:108
auto montecarlo1D()
Use crude Monte Carlo integration to approximate error integrals for univariate real functions.
Definition: estimator.h:163
auto montecarlo(unsigned int dimensions)
Use crude Monte Carlo integration to approximate error integrals for multivariate real functions.
Definition: estimator.h:212
long double uniform(long double a, long double b)
Generate a uniformly distributed random number.
Definition: random.h:54
Vector & sample_uniform(Vector &x, const std::vector< prec::interval > intervals)
Fill an already allocated vector with uniformly distributed numbers over different intervals.
Definition: random.h:66
General namespace of the framework.
Definition: benchmark_structures.h:16
std::function< Type(Type)> EndoFunction
An endofunction is a function which has the same type of input and output (e.g.
Definition: common.h:50
Structures for precision testing.
A structure holding the options for precision estimation.
Definition: prec_structures.h:77
A structure holding the result of precision estimation.
Definition: prec_structures.h:25
long double maxErr
Estimated maximum absolute error on interval.
Definition: prec_structures.h:37
long double absErr
Estimated absolute error on interval.
Definition: prec_structures.h:49
An interval on the real numbers.
Definition: interval.h:16
long double length() const
Returns the length of the interval.
Definition: interval.h:33
long double a
Lower extreme of the interval.
Definition: interval.h:19
long double b
Upper extreme of the interval.
Definition: interval.h:22