vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
verify.cc
Go to the documentation of this file.
1/************************************************************************/
2/* */
3/* vspline - a set of generic tools for creation and evaluation */
4/* of uniform b-splines */
5/* */
6/* Copyright 2015 - 2023 by Kay F. Jahnke */
7/* */
8/* Permission is hereby granted, free of charge, to any person */
9/* obtaining a copy of this software and associated documentation */
10/* files (the "Software"), to deal in the Software without */
11/* restriction, including without limitation the rights to use, */
12/* copy, modify, merge, publish, distribute, sublicense, and/or */
13/* sell copies of the Software, and to permit persons to whom the */
14/* Software is furnished to do so, subject to the following */
15/* conditions: */
16/* */
17/* The above copyright notice and this permission notice shall be */
18/* included in all copies or substantial portions of the */
19/* Software. */
20/* */
21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
23/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
24/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
25/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
26/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
27/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
28/* OTHER DEALINGS IN THE SOFTWARE. */
29/* */
30/************************************************************************/
31
32/*! \file verify.cc
33
34 \brief verify bspline interpolation against polynomial
35
36 A b-spline is a piecewise polynomial function. Therefore, it should
37 model a polynomial of the same degree precisely. This program tests
38 this assumption.
39
40 While the test should hold throughout, we have to limit it to
41 'reasonable' degrees, because we have to create the spline over
42 a range sufficiently large to make margin errors disappear,
43 so even if we want to, say, only look at the spline's values
44 between 0 and 1, we have to have a few ten or even 100 values
45 to the left and right of this interval, because the polynomial
46 does not exhibit convenient features like periodicity or
47 mirroring on the bounds. But since a polynomial, outside
48 [-1,1], grows with the power of it's degree, the values around
49 the test interval become very large very quickly with high
50 degrees. We can't reasonable expect to calculate a meaningful
51 spline over such data. The test shows how the measured fidelity
52 degrades with higher degrees due to this effect.
53
54 still , with 'reasonable' degrees, we see that the spline fits the
55 signal very well indeed, demonstrating that the spline can
56 faithfully represent a polynomial of equal degree.
57*/
58
59#include <iostream>
60#include <typeinfo>
61#include <random>
62
63#include <vigra/multi_array.hxx>
64#include <vigra/accumulator.hxx>
65#include <vigra/multi_math.hxx>
66
67#include <vspline/vspline.h>
68
69template < class dtype >
71{
72 int degree ;
73 std::vector < dtype > coefficient ;
74
75 // set up a polynomial with random coefficients in [0,1]
76
77 random_polynomial ( int _degree )
78 : degree ( _degree ) ,
79 coefficient ( _degree + 1 )
80 {
81 std::random_device rd ;
82 std::mt19937 gen ( rd() ) ;
83 std::uniform_real_distribution<> dis ( -1.0 , 1.0 ) ;
84 for ( auto & e : coefficient )
85 e = dis ( gen ) ;
86 }
87
88 // evaluate the polynomial at x
89
91 {
92 dtype power = 1 ;
93 dtype result = 0 ;
94 for ( auto e : coefficient )
95 {
96 result += e * power ;
97 power *= x ;
98 }
99 return result ;
100 }
101} ;
102
103template < class dtype >
104void polynominal_test ( int degree , const char * type_name )
105{
106 // this is the function we want to model:
107
109
110 // we evaluate this function in the range [-200,200[
111 // note that for high degrees, the signal will grow very
112 // large outside [-1,1], 'spoiling' the test
113
114 vigra::MultiArray < 1 , dtype > data ( vigra::Shape1 ( 400 ) ) ;
115
116 for ( int i = 0 ; i < 400 ; i++ )
117 {
118 dtype x = ( i - 200 ) ;
119 data[i] = rp ( x ) ;
120 }
121
122 // we create a b-spline over these data
123
124 vspline::bspline < dtype , 1 > bspl ( 400 , degree , vspline::NATURAL , 0.0 ) ;
125 bspl.prefilter ( data ) ;
126
127 auto ev = vspline::make_evaluator < decltype(bspl), dtype > ( bspl ) ;
128
129 // to test the spline against the polynomial, we generate random
130 // arguments in [-2,2]
131
132 std::random_device rd ;
133 std::mt19937 gen ( rd() ) ;
134 std::uniform_real_distribution<long double> dis ( -2.0 , 2.0 ) ;
135
136 long double signal = 0 ;
137 long double spline = 0 ;
138 long double noise = 0 ;
139 long double error ;
140 long double max_error = 0 ;
141
142 // now we evaluate the spline and the polynomial at equal arguments
143 // and do the statistics
144
145 for ( int i = 0 ; i < 10000 ; i++ )
146 {
147 long double x = dis ( gen ) ;
148 long double p = rp ( dtype ( x ) ) ;
149 // note how we have to translate x to spline coordinates here
150 long double s = ev ( dtype ( x + 200 ) ) ;
151 error = std::fabs ( p - s ) ;
152 if ( error > max_error )
153 max_error = error ;
154 signal += std::fabs ( p ) ;
155 spline += std::fabs ( s ) ;
156 noise += error ;
157 }
158
159 // note: with optimized code, this does not work:
160
161 if ( std::isnan ( noise ) || std::isnan ( noise ) )
162 {
163 std::cout << type_name << " aborted due to numeric overflow" << std::endl ;
164 return ;
165 }
166
167 long double mean_error = noise / 10000.0L ;
168
169 // finally we echo the results of the test
170
171 std::cout << type_name
172 << " Mean error: "
173 << mean_error
174 << " Maximum error: "
175 << max_error
176 << " SNR "
177 << int ( 20 * std::log10 ( signal / noise ) )
178 << "dB"
179 << std::endl ;
180}
181
182int main ( int argc , char * argv[] )
183{
184 std::cout << std::fixed << std::showpos << std::showpoint
185 << std::setprecision(18) ;
186
187 for ( int degree = 1 ; degree < 15 ; degree++ )
188 {
189 std::cout << "testing spline against polynomial, degree " << degree << std::endl ;
190 polynominal_test < float > ( degree , "using float........" ) ;
191 polynominal_test < double > ( degree , "using double......." ) ;
192 polynominal_test < long double > ( degree , "using long double.." ) ;
193 }
194}
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
double dtype
Definition: eval.cc:93
@ NATURAL
Definition: common.h:75
std::vector< dtype > coefficient
Definition: verify.cc:73
random_polynomial(int _degree)
Definition: verify.cc:77
dtype operator()(dtype x)
Definition: verify.cc:90
class bspline now builds on class bspline_base, adding coefficient storage, while bspline_base provid...
Definition: bspline.h:499
void prefilter(vspline::xlf_type boost=vspline::xlf_type(1), int njobs=vspline::default_njobs)
prefilter converts the knot point data in the 'core' area into b-spline coefficients....
Definition: bspline.h:815
int main(int argc, char *argv[])
Definition: verify.cc:182
void polynominal_test(int degree, const char *type_name)
Definition: verify.cc:104
includes all headers from vspline (most of them indirectly)