vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
restore_test.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/// restore_test - create b-splines from random data and restore the original
33/// data from the spline. This has grown to function as a unit test
34/// instantiating all sorts of splines and evaluators and using the evaluators
35/// with the functions in transform.h.
36///
37/// Ideally, this test should result in restored data which are identical to
38/// the initial random data, but several factors come into play:
39///
40/// the precision of the coefficient calculation is parametrizable in vspline,
41/// via the 'tolerance' parameter, or, in some places, the 'horizon' parameter.
42///
43/// the data type of the spline is important - single precision data are unfit
44/// to produce coefficients capable of reproducing the data very precisely
45///
46/// the spline degree is important. High degrees need wide horizons, but wide
47/// horizons also need many calculation steps, which may introduce errors.
48///
49/// The dimension of the spline is also important. Since higher-dimension
50/// splines need more calculations for prefiltering and evaluation, results are
51/// less precise. This test program can test up to 4D.
52///
53/// Please note that, since this program uses a good many different data types
54/// and tries to test as much of vspline's code as possible, compile times may
55/// be very long, especially if the higher-D tests are not commented out.
56///
57/// With dimensions > 2 running this program in full takes a long time, since
58/// it tries to be comprehensive to catch any corner cases which might have
59/// escaped scrutiny. Run time of this program is not a very good indicator
60/// of vspline's speed, since many operations (like statistics, array copy
61/// operations) are neither multithreaded nor vectorized. For speed tests,
62/// 'roundtrip' or 'grind' are better.
63///
64/// A quick way to test is to run only the 1D tests and only look at the
65/// maximum error for each data type, like:
66///
67/// ./hwy_restore_test_clang++ 1 | grep 'max err'
68///
69/// This should create output like:
70///
71/// test for type FfvE: max error = +0.000001370906829834
72/// test for type FdvE: max error = +0.000000000000002887
73/// test for type FevE: max error = +0.000000000000000001
74/// test for type FSt7complexIfEvE: max error = +0.000001788139343262
75/// test for type FSt7complexIdEvE: max error = +0.000000000000003442
76/// test for type FSt7complexIeEvE: max error = +0.000000000000000002
77/// test for type FN5vigra8RGBValueIfLj0ELj1ELj2EEEvE: max error = +0.000000963557215769
78/// test for type FN5vigra8RGBValueIdLj0ELj1ELj2EEEvE: max error = +0.000000000000001859
79/// test for type FN5vigra8RGBValueIeLj0ELj1ELj2EEEvE: max error = +0.000000000000000001
80/// test for type FN5vigra10TinyVectorIfLi3EEEvE: max error = +0.000001170033762005
81/// test for type FN5vigra10TinyVectorIdLi3EEEvE: max error = +0.000000000000001602
82/// test for type FN5vigra10TinyVectorIeLi3EEEvE: max error = +0.000000000000000001
83/// test for type FN5vigra10TinyVectorIfLi2EEEvE: max error = +0.000000927230667240
84/// test for type FN5vigra10TinyVectorIdLi2EEEvE: max error = +0.000000000000002355
85/// test for type FN5vigra10TinyVectorIfLi1EEEvE: max error = +0.000001609325408936
86/// test for type FN5vigra10TinyVectorIdLi1EEEvE: max error = +0.000000000000002776
87
88#include <vigra/multi_array.hxx>
89#include <vigra/accumulator.hxx>
90#include <vigra/multi_math.hxx>
91#include <iostream>
92#include <typeinfo>
93#include <random>
94
95#include <vspline/vspline.h>
96
97bool verbose = true ; // false ;
98
99// 'condense' aggregate types (TinyVectors etc.) into a single value
100
101template < typename T >
102double condense ( const T & t , std::true_type )
103{
104 return std::abs ( t ) ;
105}
106
107template < typename T >
108double condense ( const T & t , std::false_type )
109{
110 return sqrt ( sum ( t * t ) ) / t.size() ;
111}
112
113template < typename T >
114double condense ( const std::complex<T> & t , std::false_type )
115{
116 return std::abs ( t ) ;
117}
118
119template < class T >
120using is_singular = typename
121 std::conditional
122 < std::is_fundamental < T > :: value ,
123 std::true_type ,
124 std::false_type
125 > :: type ;
126
127template < typename T >
128double condense ( const T & t )
129{
130 return condense ( t , is_singular<T>() ) ;
131}
132
133// compare two arrays and calculate the mean and maximum difference
134
135template < int dim , typename T >
136double check_diff ( vigra::MultiArrayView < dim , T > & reference ,
137 vigra::MultiArrayView < dim , T > & candidate )
138{
139 using namespace vigra::multi_math ;
140 using namespace vigra::acc;
141
142 assert ( reference.shape() == candidate.shape() ) ;
143
144 vigra::MultiArray < 1 , double >
145 error_array ( vigra::Shape1(reference.size() ) ) ;
146
147 for ( int i = 0 ; i < reference.size() ; i++ )
148 {
149 auto help = candidate[i] - reference[i] ;
150// std::cerr << reference[i] << " <> " << candidate[i]
151// << " CFD " << help << std::endl ;
152 error_array [ i ] = condense ( help ) ;
153 }
154
155 AccumulatorChain < double , Select < Mean, Maximum > > ac ;
156 extractFeatures ( error_array.begin() , error_array.end() , ac ) ;
157 double mean = get<Mean>(ac) ;
158 double max = get<Maximum>(ac) ;
159 if ( verbose )
160 {
161 std::cout << "delta Mean: "
162 << mean << std::endl;
163 std::cout << "delta Maximum: "
164 << max << std::endl;
165 }
166 return max ;
167}
168
169/// do a restore test. This test fills the array that's
170/// passed in with small random data, constructs a b-spline with the requested
171/// parameters over the data, then calls vspline::restore(), which evaluates the
172/// spline at discrete locations.
173/// While this test fails to address several aspects (derivatives, behaviour
174/// at locations which aren't discrete), it does make sure that prefiltering
175/// has produced a correct result and reconstruction succeeds: If the spline
176/// coefficients were wrong, reconstruction would fail just as it would if
177/// the coefficients were right and the evaluation code was wrong. That both
178/// should be wrong and accidentally produce a correct result is highly unlikely.
179///
180/// This routine has grown to be more of a unit test for all of vspline,
181/// additional vspline functions are executed and the results are inspected.
182/// This way we can assure that the transform-type routines are usable with
183/// all supported data types and vectorized and unvectorized results are
184/// consistent.
185
186template < int dim , typename T >
187double restore_test ( vigra::MultiArrayView < dim , T > & arr ,
189 int spline_degree )
190{
191 if ( verbose )
192 std::cout << "**************************************" << std::endl
193 << "testing type " << typeid(T()).name() << std::endl ;
194
195 typedef vigra::MultiArray < dim , T > array_type ;
197 vigra::TinyVector < vspline::bc_code , dim > bcv { bc } ;
198
199 spline_type bsp ( arr.shape() , spline_degree , bcv , 0.0 ) ;
200
201 if ( verbose )
202 std::cout << "created b-spline:" << std::endl << bsp << std::endl ;
203
204 std::random_device rd ;
205 std::mt19937 gen ( rd() ) ;
206// gen.seed ( 765 ) ; // level playing field
207 std::uniform_real_distribution<> dis ( -1.0 , 1.0 ) ;
208 for ( auto & e : arr )
209 e = dis ( gen ) ;
210 array_type reference = arr ;
211
212 bsp.prefilter ( arr ) ;
213
214 vspline::restore < dim , T > ( bsp , arr ) ;
215
216 if ( verbose )
217 std::cout << "after restoration of original data:" << std::endl ;
218
219 double emax = check_diff < dim , T > ( reference , arr ) ;
220
221 if ( verbose )
222 {
223 // print a summary, can use '| grep CF' on cout
224 std::cout
225 << typeid(T()).name()
226 << " CF "
227 << " D " << dim
228 << " " << arr.shape()
229 << " BC " << vspline::bc_name[bc]
230 << " DG " << spline_degree
231 << " TOL " << bsp.tolerance
232 << " EMAX "
233 << emax << std::endl ;
234 }
235
236// // have: coeffs in bsp, original data in reference, restored data in arr
237//
238// the next bit of code implements a trial of 'spline polishing':
239// the coefficients are filtered with the reconstruction kernel, and
240// the original data are subtracted from resulting 'restored' data,
241// producing an array of errors. A spline is erected over the
242// errors and it's coefficents are subtracted from the coefficients
243// in the first spline, 'augmenting' it to better represent the
244// original data. Seems to squash the error pretty much to arithmetic
245// precision.
246
247 // difference original / restored
248 arr -= reference ;
249 // create another bspline
250 spline_type polish ( arr.shape() , spline_degree , bcv , 0.0 ) ;
251 // prefilter it, sucking in the difference
252 polish.prefilter ( arr ) ;
253 // and layer the resulting coeffs on top of the previous set
254 bsp.core -= polish.core ;
255 // brace the 'augmented' spline
256 bsp.brace() ;
257 // and check it's quality
258 vspline::restore < dim , T > ( bsp , arr ) ;
259
260 if ( verbose )
261 std::cout << "after polishing of spline:" << std::endl ;
262
263 double emax2 = check_diff < dim , T > ( reference , arr ) ;
264
265 if ( verbose )
266 {
267 // print a summary, can use '| grep CF' on cout
268 std::cout
269 << typeid(T()).name()
270 << " CF "
271 << " D " << dim
272 << " " << arr.shape()
273 << " BC " << vspline::bc_name[bc]
274 << " DG " << spline_degree
275 << " TOL " << bsp.tolerance
276 << " EMAX "
277 << emax2 << std::endl ;
278 }
279
280 // test the factory functions make_evaluator and make_safe_evaluator
281
282 auto raw_ev = vspline::make_evaluator
283 < spline_type , float > ( bsp ) ;
284
285 typedef typename decltype ( raw_ev ) :: in_type fc_type ;
286 typedef typename decltype ( raw_ev ) :: in_nd_ele_type nd_fc_type ;
287
288 // fc_type is what the evaluator expects as input type. This may be a plain
289 // fundamental, so we produce an nD view to it for uniform handling.
290
291 fc_type cs ( 0 ) ;
292 nd_fc_type & nd_cs ( reinterpret_cast < nd_fc_type & > ( cs ) ) ;
293
294 auto rs = raw_ev ( cs ) ;
295 raw_ev.eval ( cs , rs ) ;
296
297 // try evaluating the spline at it's lower and upper limit. We assign the
298 // spline's limit values for each dimension via the nD view to cs:
299
300 for ( int d = 0 ; d < dim ; d++ )
301 nd_cs[d] = bsp.lower_limit ( d ) ;
302
303 raw_ev.eval ( cs , rs ) ;
304
305 if ( verbose )
306 std::cout << cs << " -> " << rs << std::endl ;
307
308 for ( int d = 0 ; d < dim ; d++ )
309 nd_cs[d] = bsp.upper_limit ( d ) ;
310
311 raw_ev.eval ( cs , rs ) ;
312
313 if ( verbose )
314 std::cout << cs << " -> " << rs << std::endl ;
315
316 // additionally, we perform a test with a 'safe evaluator' and random
317 // coordinates. For a change we use double precision coordinates
318
320 < spline_type , double > ( bsp ) ;
321
322 enum { vsize = decltype ( _ev ) :: vsize } ;
323
324 typedef typename decltype ( _ev ) :: in_type coordinate_type ;
325 typedef typename decltype ( _ev ) :: in_ele_type rc_type ;
326 typedef typename decltype ( _ev ) :: out_ele_type ele_type ;
327
328 // throw a domain in to test that as well:
329
330 auto dom = vspline::domain
332 ( coordinate_type(-.3377) ,
333 coordinate_type(3.11) ,
334 bsp ) ;
335
336 auto ev = vspline::grok ( dom + _ev ) ;
337
339
340 vigra::MultiArray < 1 , coordinate_type > ca ( vigra::Shape1 ( 10003 ) ) ;
341 vigra::MultiArray < 1 , T > ra ( vigra::Shape1 ( 10003 ) ) ;
342 vigra::MultiArray < 1 , T > ra2 ( vigra::Shape1 ( 10003 ) ) ;
343
344 auto pc = (rc_type*) &c ;
345 // make sure we can evaluate at the lower and upper limit
346 int k = 0 ;
347 {
348 for ( int e = 0 ; e < dim ; e++ )
349 pc[e] = 0.0 ;
350 ra[k] = ev ( c ) ;
351 ca[k] = c ;
352 }
353 k = 1 ;
354 {
355 for ( int e = 0 ; e < dim ; e++ )
356 pc[e] = 1.0 ;
357 ra[k] = ev ( c ) ;
358 ca[k] = c ;
359 }
360 k = 2 ;
361 {
362 for ( int e = 0 ; e < dim ; e++ )
363 pc[e] = -2.0 ;
364 ra[k] = ev ( c ) ;
365 ca[k] = c ;
366 }
367 k = 3 ;
368 {
369 for ( int e = 2.0 ; e < dim ; e++ )
370 pc[e] = 1.0 ;
371 ra[k] = ev ( c ) ;
372 ca[k] = c ;
373 }
374
375 // the remaining coordinates are picked randomly
376
377 std::uniform_real_distribution<> dis2 ( -2.371 , 2.1113 ) ;
378 for ( k = 4 ; k < 10003 ; k++ )
379 {
380 for ( int e = 0 ; e < dim ; e++ )
381 pc[e] = dis2 ( gen ) ;
382 ra[k] = ev ( c ) ;
383 ca[k] = c ;
384 }
385
386 // run an index-based transform. With a domain in action, this
387 // does *not* recreate the original data
388
389 vspline::transform ( ev , arr ) ;
390
391 // run an array-based transform. result should be identical
392 // to single-value-eval above, within arithmetic precision limits
393 // given the specific optimization level.
394
395 // we can produce different views on the data to make sure feeding
396 // the coordinates still works correctly:
397
398 vigra::MultiArrayView < 2 , coordinate_type > ca2d
399 ( vigra::Shape2 ( 99 , 97 ) , ca.data() ) ;
400 vigra::MultiArrayView < 2 , T > ra2d
401 ( vigra::Shape2 ( 99 , 97 ) , ra2.data() ) ;
402
403 vigra::MultiArrayView < 2 , coordinate_type > ca2ds
404 ( vigra::Shape2 ( 49 , 49 ) , vigra::Shape2 ( 2 , 200 ) , ca.data() ) ;
405 vigra::MultiArrayView < 2 , T > ra2ds
406 ( vigra::Shape2 ( 49 , 49 ) , vigra::Shape2 ( 2 , 200 ) , ra2.data() ) ;
407
408 vigra::MultiArrayView < 3 , coordinate_type > ca3d
409 ( vigra::Shape3 ( 20 , 21 , 19 ) , ca.data() ) ;
410 vigra::MultiArrayView < 3 , T > ra3d
411 ( vigra::Shape3 ( 20 , 21 , 19 ) , ra2.data() ) ;
412
413 vspline::transform ( ev , ca , ra2 ) ;
414 vspline::transform ( ev , ca2d , ra2d ) ;
415 vspline::transform ( ev , ca2ds , ra2ds ) ;
416 vspline::transform ( ev , ca3d , ra3d ) ;
417
418 // vectorized and unvectorized operation may produce slightly
419 // different results in optimized code.
420 // usually assert ( ra == ra2 ) holds, but we don't consider
421 // it an error if it doesn't and allow for a small difference
422
423 auto dsv = check_diff < 1 , T > ( ra , ra2 ) ;
424 auto tolerance = 10 * std::numeric_limits<ele_type>::epsilon() ;
425
426 if ( dsv > tolerance )
427 std::cout << vspline::bc_name[bc]
428 << " - max difference single/vectorized eval "
429 << dsv << std::endl ;
430
431 if ( dsv > .0001 )
432 {
433 std::cout << vspline::bc_name[bc]
434 << " - excessive difference single/vectorized eval "
435 << dsv << std::endl ;
436 for ( int k = 0 ; k < 10003 ; k++ )
437 {
438 if ( ra[k] != ra2[k] )
439 {
440 std::cout << "excessive at k = " << k
441 << ": " << ca[k] << " -> "
442 << ra[k] << ", " << ra2[k] << std::endl ;
443 }
444 }
445 }
446
447 return emax ;
448}
449
450using namespace vspline ;
451
452template < class arr_t >
453double view_test ( arr_t & arr )
454{
455 double emax = 0.0 ;
456
457 enum { dimension = arr_t::actual_dimension } ;
458 typedef typename arr_t::value_type value_type ;
459 vspline::bc_code bc_seq[] { PERIODIC , MIRROR , REFLECT , NATURAL } ;
460
461 // TODO: for degree-1 splines, I sometimes get different results
462 // for unvectorized and vectorized operation. why?
463
464 for ( int spline_degree = 0 ; spline_degree < 8 ; spline_degree++ )
465 {
466 for ( auto bc : bc_seq )
467 {
468 auto e = restore_test < dimension , value_type >
469 ( arr , bc , spline_degree ) ;
470 if ( e > emax )
471 emax = e ;
472 }
473 }
474 return emax ;
475}
476
477int d0[] { 1 , 2 , 3 , 5 , 8 , 13 , 16 , 21 ,
478 34 , 55 , 123 , 128 , 289 , 500 , 1031 ,
479 2001 , 4999 } ;
480int d1[] { 1 , 2 , 3 , 5 , 8 , 13 , 16 , 21 ,
481 34 , 89 , 160 , 713 } ;
482int d2[] { 2 , 3 , 5 , 8 , 13 , 21 } ;
483int d3[] { 2 , 3 , 5 , 8 , 13 } ;
484
485int* dext[] { d0 , d1 , d2 , d3 } ;
486int dsz[] { sizeof(d0) / sizeof(int) ,
487 sizeof(d1) / sizeof(int) ,
488 sizeof(d2) / sizeof(int) ,
489 sizeof(d3) / sizeof(int) } ;
490
491template < int dim , typename T >
492struct test
493{
494 typedef vigra::TinyVector < int , dim > shape_type ;
495 double emax = 0.0 ;
496
497 double operator() ()
498 {
499 shape_type dshape ;
500 for ( int d = 0 ; d < dim ; d++ )
501 dshape[d] = dsz[d] ;
502
503 vigra::MultiCoordinateIterator<dim> i ( dshape ) ,
504 end = i.getEndIterator() ;
505
506 while ( i != end )
507 {
508 shape_type shape ;
509 for ( int d = 0 ; d < dim ; d++ )
510 shape[d] = * ( dext[d] + (*i)[d] ) ;
511
512 vigra::MultiArray < dim , T > _arr ( 2 * shape + 1 ) ;
513 auto stride = _arr.stride() * 2 ;
514 vigra::MultiArrayView < dim , T >
515 arr ( shape , stride , _arr.data() + long ( sum ( stride ) ) ) ;
516 auto e = view_test ( arr ) ;
517 if ( e > emax )
518 emax = e ;
519 ++i ;
520
521 // make sure that we have only written back to 'arr', leaving
522 // _arr untouched
523 for ( auto & e : arr )
524 e = T(0.0) ;
525 for ( auto e : _arr )
526 assert ( e == T(0.0) ) ;
527 }
528 return emax ;
529 }
530} ;
531
532template < typename T >
533struct test < 0 , T >
534{
535 double operator() ()
536 {
537 return 0.0 ;
538 } ;
539} ;
540
541template < int dim ,
542 typename tuple_type ,
543 int ntypes = std::tuple_size<tuple_type>::value >
545{
547 {
548 typedef typename std::tuple_element<ntypes-1,tuple_type>::type T ;
549 auto e = test < dim , T >() () ;
550 std::cout << "test for type " << typeid(T()).name()
551 << ": max error = " << e << std::endl ;
552 multitest < dim , tuple_type , ntypes - 1 >() () ;
553 }
554} ;
555
556template < int dim ,
557 typename tuple_type >
558struct multitest < dim , tuple_type , 0 >
559{
561 {
562 }
563} ;
564
565int main ( int argc , char * argv[] )
566{
567 std::cout << std::fixed << std::showpos << std::showpoint
568 << std::setprecision(18);
569 std::cerr << std::fixed << std::showpos << std::showpoint
570 << std::setprecision(18);
571
572 int test_dim = 2 ;
573 if ( argc > 1 )
574 test_dim = std::atoi ( argv[1] ) ;
575 if ( test_dim > 4 )
576 test_dim = 4 ;
577
578 std::cout << "testing with " << test_dim << " dimensions" << std::endl ;
579
580 typedef std::tuple <
581 vigra::TinyVector < double , 1 > ,
582 vigra::TinyVector < float , 1 > ,
583 vigra::TinyVector < double , 2 > ,
584 vigra::TinyVector < float , 2 > ,
585 vigra::TinyVector < long double , 3 > ,
586 vigra::TinyVector < double , 3 > ,
587 vigra::TinyVector < float , 3 > ,
588 vigra::RGBValue<long double> ,
589 vigra::RGBValue<double> ,
590 vigra::RGBValue<float,0,1,2> ,
591 std::complex < long double > ,
592 std::complex < double > ,
593 std::complex < float > ,
594 long double ,
595 double ,
596 float
597 > tuple_type ;
598
599 switch ( test_dim )
600 {
601 case 1:
603 break ;
604 case 2:
606 break ;
607// case 3:
608// multitest < 3 , tuple_type >() () ;
609// break ;
610// case 4:
611// multitest < 4 , tuple_type >() () ;
612// break ;
613 default:
614 break ;
615 }
616 std::cout << "terminating" << std::endl ;
617}
618
vigra::TinyVector< float, 2 > coordinate_type
Definition: ca_correct.cc:107
vspline::bspline< pixel_type, 2 > spline_type
Definition: ca_correct.cc:111
double rc_type
Definition: eval.cc:94
@ vsize
Definition: eval.cc:96
typename std::conditional< std::is_fundamental< T > ::value, std::true_type, std::false_type > ::type is_singular
Definition: grind.cc:88
Definition: basis.h:79
vspline::domain_type< coordinate_type, _vsize > domain(const coordinate_type &in_low, const coordinate_type &in_high, const coordinate_type &out_low, const coordinate_type &out_high)
factory function to create a domain_type type object from the desired lower and upper fix point for i...
Definition: domain.h:366
void transform(const unary_functor_type &functor, const vigra::MultiArrayView< dimension, typename unary_functor_type::in_type > &input, vigra::MultiArrayView< dimension, typename unary_functor_type::out_type > &output, int njobs=vspline::default_njobs, vspline::atomic< bool > *p_cancel=0)
implementation of two-array transform using wielding::coupled_wield.
Definition: transform.h:211
vspline::grok_type< typename grokkee_type::in_type, typename grokkee_type::out_type, grokkee_type::vsize > grok(const grokkee_type &grokkee)
grok() is the corresponding factory function, wrapping grokkee in a vspline::grok_type.
vspline::grok_type< bspl_coordinate_type< spline_type, rc_type >, result_type, _vsize > make_evaluator(const spline_type &bspl, vigra::TinyVector< int, spline_type::dimension > dspec=vigra::TinyVector< int, spline_type::dimension >(0), int shift=0)
make_evaluator is a factory function, producing a functor which provides access to an evaluator objec...
Definition: eval.h:2292
const std::string bc_name[]
bc_name is for diagnostic output of bc codes
Definition: common.h:84
vspline::grok_type< bspl_coordinate_type< spline_type, rc_type >, result_type, _vsize > make_safe_evaluator(const spline_type &bspl, vigra::TinyVector< int, spline_type::dimension > dspec=vigra::TinyVector< int, spline_type::dimension >(0), int shift=0)
make_safe_evaluator is a factory function, producing a functor which provides safe access to an evalu...
Definition: eval.h:2390
bc_code
This enumeration is used for codes connected to boundary conditions. There are two aspects to boundar...
Definition: common.h:71
@ NATURAL
Definition: common.h:75
@ REFLECT
Definition: common.h:74
@ PERIODIC
Definition: common.h:73
@ MIRROR
Definition: common.h:72
int d3[]
int main(int argc, char *argv[])
double restore_test(vigra::MultiArrayView< dim, T > &arr, vspline::bc_code bc, int spline_degree)
do a restore test. This test fills the array that's passed in with small random data,...
int d2[]
int * dext[]
int d1[]
double view_test(arr_t &arr)
bool verbose
restore_test - create b-splines from random data and restore the original data from the spline....
Definition: restore_test.cc:97
int dsz[]
double condense(const T &t, std::true_type)
int d0[]
double check_diff(vigra::MultiArrayView< dim, T > &reference, vigra::MultiArrayView< dim, T > &candidate)
void operator()()
double emax
double operator()()
vigra::TinyVector< int, dim > shape_type
class bspline now builds on class bspline_base, adding coefficient storage, while bspline_base provid...
Definition: bspline.h:499
view_type core
Definition: bspline.h:566
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
void brace(int axis=-1)
if the spline coefficients are already known, they obviously don't need to be prefiltered....
Definition: bspline.h:773
static xlf_type lower_limit(const bc_code &bc)
lower_limit returns the lower bound of the spline's defined range. This is usually 0....
Definition: bspline.h:226
static xlf_type upper_limit(const std::size_t &extent, const bc_code &bc)
upper_limit returns the upper bound of the spline's defined range. This is normally M - 1 if the shap...
Definition: bspline.h:255
const xlf_type tolerance
Definition: bspline.h:213
includes all headers from vspline (most of them indirectly)