mirror of
https://github.com/boostorg/math.git
synced 2026-01-19 04:22:09 +00:00
* Interpolate a uniform grid with a bilinear function. * Typo removal. * Invalid syntax in Jamfile. * Do domain verification before computation. * Fix OOB access on print. * pimpl the class so it can be shared between threads. * Add google/benchmark file to measure the performance of the bilinear interpolation. * Fix up docs. * Remove non-ASCII characters from print statements. Add a float128 test. * Improve the documentation of the bilinear uniform class. * Remove float128 as it doesn't support to_string. * Don't use decltype(fieldData.size()) as the indexer; that makes MSVC 14.2 choke. Use RandomAccessContainer::size_type. * Use ADL for to_string for compatibility with multiprecision. * Improve error message which rows*cols != fieldData.size().
110 lines
3.2 KiB
C++
110 lines
3.2 KiB
C++
/*
|
|
* Copyright Nick Thompson, 2021
|
|
* Use, modification and distribution are subject to the
|
|
* Boost Software License, Version 1.0. (See accompanying file
|
|
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
|
|
#include "math_unit_test.hpp"
|
|
#include <numeric>
|
|
#include <random>
|
|
#include <array>
|
|
#include <boost/core/demangle.hpp>
|
|
#include <boost/math/interpolators/bilinear_uniform.hpp>
|
|
#ifdef BOOST_HAS_FLOAT128
|
|
#include <boost/multiprecision/float128.hpp>
|
|
using boost::multiprecision::float128;
|
|
#endif
|
|
|
|
using boost::math::interpolators::bilinear_uniform;
|
|
|
|
template<class Real>
|
|
void test_four_values()
|
|
{
|
|
Real x0 = 0;
|
|
Real y0 = 0;
|
|
Real dx = 1;
|
|
Real dy = 1;
|
|
Real value = 1.5;
|
|
std::vector<Real> v(2*2, value);
|
|
auto v_copy = v;
|
|
auto ub = bilinear_uniform<decltype(v)>(std::move(v_copy), 2, 2, dx, dy, x0, y0);
|
|
for (Real x = x0; x <= x0 + dx; x += dx/8) {
|
|
for (Real y = y0; y <= y0 + dx; y += dy/8) {
|
|
CHECK_ULP_CLOSE(value, ub(x, y), 1);
|
|
}
|
|
}
|
|
|
|
// Now we test the unit square:
|
|
std::random_device rd;
|
|
std::uniform_real_distribution<Real> dis(1,2);
|
|
|
|
int i = 0;
|
|
while (i++ < 300) {
|
|
v[0] = dis(rd);
|
|
v[1] = dis(rd);
|
|
v[2] = dis(rd);
|
|
v[3] = dis(rd);
|
|
|
|
// See https://en.wikipedia.org/wiki/Bilinear_interpolation, section: Unit square
|
|
auto f = [&v](Real x, Real y) {
|
|
return v[0]*(1-x)*(1-y) + v[1]*x*(1-y) + v[2]*(1-x)*y + v[3]*x*y;
|
|
};
|
|
|
|
v_copy = v;
|
|
ub = bilinear_uniform<decltype(v_copy)>(std::move(v_copy), 2, 2, dx, dy, x0, y0);
|
|
for (Real x = x0; x <= x0 + dx; x += dx/16) {
|
|
for (Real y = y0; y <= y0 + dx; y += dy/16) {
|
|
CHECK_ULP_CLOSE(f(x,y), ub(x, y), 3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename Real>
|
|
void test_linear()
|
|
{
|
|
std::random_device rd;
|
|
std::uniform_real_distribution<Real> dis(1,2);
|
|
std::array<Real, 4> a{dis(rd), dis(rd), dis(rd), dis(rd)};
|
|
auto f = [&a](Real x, Real y) {
|
|
return a[0] + a[1]*x + a[2]*y + a[3]*x*y;
|
|
};
|
|
|
|
for (int rows = 2; rows < 20; ++rows) {
|
|
for (int cols = 2; cols < 20; ++cols) {
|
|
Real dx = dis(rd);
|
|
Real dy = dis(rd);
|
|
Real x0 = dis(rd);
|
|
Real y0 = dis(rd);
|
|
std::vector<Real> v(rows*cols, std::numeric_limits<Real>::quiet_NaN());
|
|
for (int i = 0; i < cols; ++i) {
|
|
for (int j = 0; j < rows; ++j) {
|
|
v[j*cols + i] = f(x0 + i*dx, y0 + j*dy);
|
|
}
|
|
}
|
|
auto ub = bilinear_uniform<decltype(v)>(std::move(v), rows, cols, dx, dy, x0, y0);
|
|
|
|
for (Real x = x0; x < x0 + (cols-1)*dx; x += dx/8) {
|
|
for (Real y = y0; y < y0 + (rows-1)*dy; y += dy/8) {
|
|
if (!CHECK_ULP_CLOSE(f(x,y), ub(x, y), 13)) {
|
|
std::cerr << " f(" << x << ", " << y << ") = " << f(x,y) << "\n";
|
|
std::cerr << "ub(" << x << ", " << y << ") = " << ub(x,y) << "\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int main()
|
|
{
|
|
test_four_values<float>();
|
|
test_four_values<double>();
|
|
test_four_values<long double>();
|
|
test_linear<double>();
|
|
return boost::math::test::report_errors();
|
|
}
|