vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
eval.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 eval.cc
33///
34/// \brief simple demonstration of creation and evaluation of a b-spline
35///
36/// takes a set of knot point values from std::cin, calculates a 1D b-spline
37/// over them, and evaluates it at coordinates taken from std::cin.
38/// The output shows how the coordinate is split into integral and real
39/// part and the result of evaluating the spline at this point.
40/// Note how the coordinate is automatically folded into the defined range.
41///
42/// Two evaluations are demonstrated, using unvectorized and vectorized
43/// input/output.
44///
45/// Since this is a convenient place to add code for testing evaluation
46/// speed, you may pass a number on the command line. eval.cc will then
47/// perform as many evaluations and print the time it took.
48/// The evaluations will be distributed to several threads, so there is
49/// quite a bit of overhead; pass numbers from 1000000 up to get realistic
50/// timings.
51///
52/// compile: ./examples.sh eval.cc
53///
54/// compare speed test results from different compilers/back-ends, using
55/// 'echo' to provide the arguments normally taken from cin. This invocation
56/// runs the test with a periodic degree-19 spline over knot points 0 and 1
57/// and only shows the name of the binary and the result of the speed test:
58///
59/// for f in *eval*++; do echo $f;echo 19 2 0 1 . .5 | ./$f 100000000 | grep took; done
60///
61/// this will produce output like:
62/// hwy_eval_clang++
63/// 100000000 evaluations took 2229 ms
64/// hwy_eval_g++
65/// 100000000 evaluations took 2527 ms
66/// stds_eval_clang++
67/// 100000000 evaluations took 3401 ms
68/// stds_eval_g++
69/// 100000000 evaluations took 2351 ms
70/// vc_eval_clang++
71/// 100000000 evaluations took 3281 ms
72/// vc_eval_g++
73/// 100000000 evaluations took 3385 ms
74/// vs_eval_clang++
75/// 100000000 evaluations took 3883 ms
76/// vs_eval_g++
77/// 100000000 evaluations took 5479 ms
78///
79/// note how both the back-end and the compiler make a difference, highway
80/// and clang++ currently coming out on top on my system. This is a moving
81/// target, as both the back-ends and the compilers evolve.
82
83#include <iostream>
84#include <iomanip>
85#include <ctime>
86#include <chrono>
87
88#include <vspline/vspline.h>
89
90// you can use float, but then can't use very high spline degrees.
91// If you use long double, the code won't be vectorized in hardware.
92
93typedef double dtype ;
94typedef double rc_type ;
95
97
98// speed_test will perform as many vectorized evaluations as the
99// range it receives spans. The evaluation is always at the same place,
100// trying to lower all memory access effects to the minimum.
101
102template < class ev_type >
103void speed_test ( ev_type & ev , std::size_t nr_ev )
104{
105 typename ev_type::in_v in = dtype(.111) ;
106 typename ev_type::out_v out ;
107
108 while ( nr_ev-- )
109 ev.eval ( in , out ) ;
110}
111
112int main ( int argc , char * argv[] )
113{
114 long TIMES = 0 ;
115
116 if ( argc > 1 )
117 TIMES = std::atoi ( argv[1] ) ;
118
119 // get the spline degree and boundary conditions from the console
120
121 std::cout << "enter spline degree: " ;
122 int spline_degree ;
123 std::cin >> spline_degree ;
124
125 int bci = -1 ;
127
128 while ( bci < 1 || bci > 4 )
129 {
130 std::cout << "choose boundary condition" << std::endl ;
131 std::cout << "1) MIRROR" << std::endl ;
132 std::cout << "2) PERIODIC" << std::endl ;
133 std::cout << "3) REFLECT" << std::endl ;
134 std::cout << "4) NATURAL" << std::endl ;
135 std::cin >> bci ;
136 }
137
138 switch ( bci )
139 {
140 case 1 :
141 bc = vspline::MIRROR ;
142 break ;
143 case 2 :
144 bc = vspline::PERIODIC ;
145 break ;
146 case 3 :
147 bc = vspline::REFLECT ;
148 break ;
149 case 4 :
150 bc = vspline::NATURAL ;
151 break ;
152 }
153
154 // obtain knot point values
155
156 dtype v ;
157 std::vector<dtype> dv ;
158 std::cout << "enter knot point values (end with single '.')" << std::endl ;
159 while ( std::cin >> v )
160 dv.push_back ( v ) ;
161
162 std::cin.clear() ;
163 std::cin.ignore() ;
164
165 // fix the type for the bspline object
166
168 spline_type bsp ( dv.size() , spline_degree , bc ) ;
169
170 std::cout << "created bspline object:" << std::endl << bsp << std::endl ;
171
172 // fill the data into the spline's 'core' area
173
174 for ( size_t i = 0 ; i < dv.size() ; i++ )
175 bsp.core[i] = dv[i] ;
176
177 // prefilter the data
178
179 bsp.prefilter() ;
180
181 std::cout << std::fixed << std::showpoint << std::setprecision(12) ;
182 std::cout << "spline coefficients (with frame)" << std::endl ;
183 for ( auto& coeff : bsp.container )
184 std::cout << " " << coeff << std::endl ;
185
186 // obtain a 'safe' evaluator which folds incoming coordinates
187 // into the defined range
188
189 auto ev = vspline::make_safe_evaluator ( bsp ) ;
191 auto iev = iev_t ( bsp ) ;
192
193 int ic ;
194 rc_type rc ;
195 dtype res ;
196
197 std::cout << "enter coordinates to evaluate (end with EOF)"
198 << std::endl ;
199 while ( std::cin >> rc )
200 {
201 if ( rc < bsp.lower_limit(0) || rc > bsp.upper_limit(0) )
202 {
203 std::cout << "warning: " << rc
204 << " is outside the spline's defined range."
205 << std::endl ;
206 std::cout << "using automatic folding to process this value."
207 << std::endl ;
208 }
209
210 // evaluate the spline at this location
211
212 ev.eval ( rc , res ) ;
213
214 std::cout << rc << " -> " << res << std::endl ;
215
216 if ( TIMES )
217 {
218 std::chrono::system_clock::time_point start
219 = std::chrono::system_clock::now() ;
220
221 // for the speed test we build a plain evaluator; we'll
222 // only be evaluating the spline near 0.0 repeatedly, so
223 // we don't need folding into the safe range. We're not
224 // fixing 'specialize', so evaluation will be general
225 // b-spline evaluation, even for degree 0 and 1 splines.
226
228
229 std::size_t share = ( TIMES / vsize ) / vspline::default_njobs ;
230
231 std::function < void() > payload =
232 [&]() { speed_test ( ev , share ) ; } ;
233
235
236 std::chrono::system_clock::time_point end
237 = std::chrono::system_clock::now() ;
238
239 std::cout << TIMES << " evaluations took "
240 << std::chrono::duration_cast<std::chrono::milliseconds>
241 ( end - start ) . count()
242 << " ms" << std::endl ;
243 }
244 }
245}
vspline::bspline< pixel_type, 2 > spline_type
Definition: ca_correct.cc:111
void eval(const typename base_type::in_type &_coordinate, typename base_type::out_type &_result) const
unvectorized evaluation function. this is delegated to 'feed' above, which reinterprets the arguments...
Definition: eval.h:1822
int main(int argc, char *argv[])
Definition: eval.cc:112
double dtype
Definition: eval.cc:93
double rc_type
Definition: eval.cc:94
@ vsize
Definition: eval.cc:96
void speed_test(ev_type &ev, std::size_t nr_ev)
Definition: eval.cc:103
const int default_njobs
Definition: multithread.h:220
int multithread(std::function< void() > payload, std::size_t nr_workers=default_njobs)
multithread uses a thread pool of worker threads to perform a multithreaded operation....
Definition: multithread.h:412
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
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
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
view_type container
Definition: bspline.h:565
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
vector_traits< coordinate_type, vsize >::type in_v
vectorized in_type and out_type. vspline::vector_traits supplies these types so that multidimensional...
with the definition of 'simd_traits', we can proceed to implement 'vector_traits': struct vector_trai...
Definition: vector.h:344
includes all headers from vspline (most of them indirectly)