vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
grind.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/* The git repository for this software is at */
9/* */
10/* https://bitbucket.org/kfj/vspline */
11/* */
12/* Please direct questions, bug reports, and contributions to */
13/* */
14/* kfjahnke+vspline@gmail.com */
15/* */
16/* Permission is hereby granted, free of charge, to any person */
17/* obtaining a copy of this software and associated documentation */
18/* files (the "Software"), to deal in the Software without */
19/* restriction, including without limitation the rights to use, */
20/* copy, modify, merge, publish, distribute, sublicense, and/or */
21/* sell copies of the Software, and to permit persons to whom the */
22/* Software is furnished to do so, subject to the following */
23/* conditions: */
24/* */
25/* The above copyright notice and this permission notice shall be */
26/* included in all copies or substantial portions of the */
27/* Software. */
28/* */
29/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
30/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
31/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
32/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
33/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
34/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
35/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
36/* OTHER DEALINGS IN THE SOFTWARE. */
37/* */
38/************************************************************************/
39
40/*! \file grind.cc
41
42 \brief performance test. The test is twofold: one aspect is the
43 'fidelity' of the filtering operations: if we repeatedly prefilter
44 and restore the data, how badly do they suffer, given different data
45 types? The second question is, how long does a prefilter-restore
46 cycle take (roughly)?
47*/
48
49#include <vigra/multi_array.hxx>
50#include <vigra/accumulator.hxx>
51#include <vigra/multi_math.hxx>
52#include <iostream>
53#include <typeinfo>
54#include <random>
55#include <ctime>
56#include <chrono>
57
58#include <vspline/vspline.h>
59
60bool verbose = true ; // false ;
61
62// 'condense' aggregate types (TinyVectors etc.) into a single value
63
64template < typename T >
65double condense ( const T & t , std::true_type )
66{
67 return std::abs ( t ) ;
68}
69
70template < typename T >
71double condense ( const T & t , std::false_type )
72{
73 return sqrt ( sum ( t * t ) ) / t.size() ;
74}
75
76template < typename T >
77double condense ( const std::complex<T> & t , std::false_type )
78{
79 return std::abs ( t ) ;
80}
81
82template < class T >
83using is_singular = typename
84 std::conditional
85 < std::is_fundamental < T > :: value ,
86 std::true_type ,
87 std::false_type
88 > :: type ;
89
90template < typename T >
91double condense ( const T & t )
92{
93 return condense ( t , is_singular<T>() ) ;
94}
95
96template < int dim , typename T >
97double check_diff ( vigra::MultiArrayView < dim , T > & reference ,
98 vigra::MultiArrayView < dim , T > & candidate )
99{
100 using namespace vigra::multi_math ;
101 using namespace vigra::acc;
102
103 assert ( reference.shape() == candidate.shape() ) ;
104
105 vigra::MultiArray < 1 , double >
106 error_array ( vigra::Shape1(reference.size() ) ) ;
107
108 for ( int i = 0 ; i < reference.size() ; i++ )
109 {
110 auto help = candidate[i] - reference[i] ;
111// std::cerr << reference[i] << " <> " << candidate[i]
112// << " CFD " << help << std::endl ;
113 error_array [ i ] = condense ( help ) ;
114 }
115
116 AccumulatorChain < double , Select < Mean, Maximum > > ac ;
117 extractFeatures ( error_array.begin() , error_array.end() , ac ) ;
118 double mean = get<Mean>(ac) ;
119 double max = get<Maximum>(ac) ;
120 if ( verbose )
121 {
122 std::cout << "delta Mean: "
123 << mean << std::endl;
124 std::cout << "delta Maximum: "
125 << max << std::endl;
126 }
127 return max ;
128}
129
130/// create an array of random data ditributed between -1 and 1.
131/// Then repeatedly prefilter and restore the data, and check the
132/// difference between the restored and original data, plus the
133/// time needed to do the processing.
134/// This test shows that for higher-degree splines, arithmetic
135/// precision becomes an issue, and using floats becomes futile.
136/// But it also shows that using double data and operating in
137/// double precision does not cost too much more processing time.
138/// keeping the data in float and using double maths does not
139/// help.
140
141template < int dim , typename T , typename math_ele_type > void
142grind_test ( vigra::TinyVector < int , dim > shape ,
144 int spline_degree )
145{
146 typedef vigra::MultiArray < dim , T > array_type ;
148
149 vigra::TinyVector < vspline::bc_code , dim > bcv { bc } ;
150 spline_type bsp ( shape , spline_degree , bcv ) ; // , 0.0 ) ;
151
152// if ( verbose )
153// std::cout << "grind: created b-spline:" << std::endl << bsp << std::endl ;
154
155 std::random_device rd ;
156 std::mt19937 gen ( rd() ) ;
157// gen.seed ( 765 ) ; // level playing field
158 std::uniform_real_distribution<> dis ( -1.0 , 1.0 ) ;
159 for ( auto & e : bsp.core )
160 e = dis ( gen ) ; // fill core with random data
161
162 array_type reference = bsp.core ; // hold a copy of these data
163
164 int times ;
165
166 std::chrono::system_clock::time_point start
167 = std::chrono::system_clock::now() ;
168
169 for ( times = 0 ; times < 1000 ; )
170 {
171 bsp.prefilter() ;
172 vspline::restore < dim , T , math_ele_type > ( bsp ) ;
173 times++ ;
174 if ( times == 1 || times == 10 || times == 100 || times == 1000 )
175 {
176 std::cout << "after " << times
177 << " prefilter-restore cycles" << std::endl ;
178 double emax = check_diff < dim , T > ( reference , bsp.core ) ;
179 if ( verbose )
180 {
181 // print a summary, can use '| grep CF' on cout
182 std::cout
183 << typeid(T()).name()
184 << " CF "
185 << " D " << dim
186 << " " << bsp.core.shape()
187 << " BC " << vspline::bc_name[bc]
188 << " DG " << spline_degree
189 << " TOL " << bsp.tolerance
190 << " EMAX "
191 << emax << std::endl ;
192 }
193 }
194 }
195
196 std::chrono::system_clock::time_point end
197 = std::chrono::system_clock::now() ;
198
199 std::cout << "average cycle duration: "
200 << std::chrono::duration_cast<std::chrono::milliseconds>
201 ( end - start ) . count() / float ( times )
202 << " ms" << std::endl ;
203
204
205 std::cout << "---------------------------------------------------" << std::endl ;
206 std::cout << std::endl ;
207
208}
209
210int main ( int argc , char * argv[] )
211{
212 if ( argc < 2 )
213 {
214 std::cerr << "pass the spline degree as parameter" << std::endl ;
215 exit ( -1 ) ;
216 }
217
218 int degree = std::atoi ( argv[1] ) ;
219
220 std::cout << "performing arithmetics in single precision" << std::endl ;
221 grind_test < 2 , float , float > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
222 grind_test < 2 , double , float > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
223 grind_test < 2 , long double , float > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
224 std::cout << "performing arithmetics in double precision" << std::endl ;
225 grind_test < 2 , float , double > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
226 grind_test < 2 , double , double > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
227 grind_test < 2 , long double , double > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
228 std::cout << "performing arithmetics in long double precision" << std::endl ;
229 grind_test < 2 , float , long double > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
230 grind_test < 2 , double , long double > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
231 grind_test < 2 , long double , long double > ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
232}
vspline::bspline< pixel_type, 2 > spline_type
Definition: ca_correct.cc:111
typename std::conditional< std::is_fundamental< T > ::value, std::true_type, std::false_type > ::type is_singular
Definition: grind.cc:88
int main(int argc, char *argv[])
Definition: grind.cc:210
void grind_test(vigra::TinyVector< int, dim > shape, vspline::bc_code bc, int spline_degree)
create an array of random data ditributed between -1 and 1. Then repeatedly prefilter and restore the...
Definition: grind.cc:142
bool verbose
Definition: grind.cc:60
double condense(const T &t, std::true_type)
Definition: grind.cc:65
double check_diff(vigra::MultiArrayView< dim, T > &reference, vigra::MultiArrayView< dim, T > &candidate)
Definition: grind.cc:97
const std::string bc_name[]
bc_name is for diagnostic output of bc codes
Definition: common.h:84
bc_code
This enumeration is used for codes connected to boundary conditions. There are two aspects to boundar...
Definition: common.h:71
@ PERIODIC
Definition: common.h:73
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
const xlf_type tolerance
Definition: bspline.h:213
includes all headers from vspline (most of them indirectly)