78#include <gsl/gsl_poly.h>
89#define degree_limit 46
121 throw std::invalid_argument (
"access with degree out of bounds" ) ;
129 if ( x2 == -1 || x2 == 0 )
136 column = x2 >= 0 ? x2 : -x2 ;
152 mpq_class & f1 (
access_table ( degree - 1 , x2 + 1 ) ) ;
153 mpq_class & f2 (
access_table ( degree - 1 , x2 - 1 ) ) ;
159 = ( f1 * ( degree + 1 + x2 )
160 + f2 * ( degree + 1 - x2 ) )
171 for (
int degree = 1 ; degree <
degree_limit ; degree++ )
173 for (
int x2 = 0 ; x2 <= degree ; x2++ )
185template <
typename dtype >
188 dtype * pk = pcoeff + ncoeff - 1 ;
203 dfx += power * xd * *pk ;
210 result = x - fx / dfx ;
234 const int r = degree / 2 ;
240 double coeffs [ 2 * r + 1 ] ;
241 mpf_class mpf_coeffs [ 2 * r + 1 ] ;
245 double roots [ 4 * r + 2 ] ;
250 double * pcoeffs = coeffs ;
251 mpf_class * pmpf_coeffs = mpf_coeffs ;
253 for (
int x2 = -r * 2 ;
255 x2 += 2 , pcoeffs++ , pmpf_coeffs++ )
263 gsl_poly_complex_workspace * w
264 = gsl_poly_complex_workspace_alloc ( 2 * r + 1 ) ;
268 gsl_poly_complex_solve ( coeffs , 2 * r + 1 , w , roots ) ;
272 gsl_poly_complex_workspace_free ( w ) ;
311 for (
int i = 2 * r - 2 ; i >= 0 ; i -= 2 )
313 if ( std::abs ( roots[i] ) < 1.0 )
318 mpf_class root ( roots[i] ) ;
332 while ( ( pa - pb ) * ( pa - pb ) >= pdelta )
340 newton ( pa , pa , 2*r+1 , mpf_coeffs ) ;
346 res.push_back ( root ) ;
355void forward ( mpf_class * x ,
int size , mpf_class pole )
359 for (
int n = 1 ; n < size ; n++ )
361 x[n] = X = x[n] + pole * X ;
369void backward ( mpf_class * x ,
int size , mpf_class pole )
373 for (
int n = size - 2 ; n >= 0 ; n-- )
375 x[n] = X = pole * ( X - x[n] );
389 const std::vector<mpf_class> & poles ,
392 mpf_class buffer [ size ] ;
393 for (
int k = 0 ; k < size ; k++ )
400 mpf_class lambda = 1 ;
402 for (
int k = 0 ; k < poles.size() ; k++ )
404 lambda = lambda * ( 1 - poles[k] ) * ( 1 - 1 / poles[k] ) ;
406 int center = size / 2 ;
410 for (
int x2 = 0 ; x2 <= degree ; x2 += 2 )
411 buffer [ center - x2/2 ]
412 = buffer [ center + x2/2 ]
417 for (
int k = 0 ; k < poles.size() ; k++ )
419 forward ( buffer , size , poles[k] ) ;
420 backward ( buffer , size , poles[k] ) ;
425 mpf_class error = 0 ;
426 mpf_class max_error = 0 ;
428 for (
int x2 = 0 ; x2 <= degree ; x2 += 2 )
430 error = abs ( buffer [ center - x2/2 ] - ( x2 == 0 ? 1 : 0 ) ) ;
431 if ( error > max_error )
433 error = abs ( buffer [ center + x2/2 ] - ( x2 == 0 ? 1 : 0 ) ) ;
434 if ( error > max_error )
437 mpf_class limit = 1e-150 ;
438 if ( max_error > limit )
439 std::cerr <<
"WARNING: degree " << degree
440 <<
" error exceeds limit 1e-150: "
441 << max_error << std::endl ;
450 std::string sign (
"+" ) ;
456 sign = std::string (
"-" ) ;
459 auto str = x.get_str ( exp , 10 , 64 ) ;
461 std::string res = sign + std::string (
"." ) + str
462 + std::string (
"e" ) + std::to_string ( exp )
463 + std::string (
"l" ) ;
476 for (
int n = 1 ; n < size ; n++ )
478 x[n] = X = x[n] + pole * X ;
488 for (
int n = size - 2 ; n >= 0 ; n-- )
490 x[n] = X = pole * ( X - x[n] );
497 const std::vector<mpf_class> & poles ,
500 int nbpoles = degree / 2 ;
503 for (
int k = 0 ; k < size ; k++ )
512 for (
int k = 0 ; k < nbpoles ; k++ )
514 auto ldp =
get_xlf ( poles[k] ) ;
515 lambda = lambda * ( 1 - ldp ) * ( 1 - 1 / ldp ) ;
518 int center = size / 2 ;
522 for (
int x2 = 0 ; x2 <= degree ; x2 += 2 )
526 buffer [ center - x2/2 ]
527 = buffer [ center + x2/2 ]
533 for (
int k = 0 ; k < nbpoles ; k++ )
535 auto ldp =
get_xlf ( poles[k] ) ;
545 for (
int x2 = 0 ; x2 <= degree ; x2 += 2 )
547 error = std::abs ( buffer [ center - x2/2 ] - ( x2 == 0 ? 1 : 0 ) ) ;
548 if ( error > max_error )
550 error = std::abs ( buffer [ center + x2/2 ] - ( x2 == 0 ? 1 : 0 ) ) ;
551 if ( error > max_error )
556 if ( max_error > limit )
557 std::cerr <<
"WARNING: degree " << degree
558 <<
" ld error exceeds limit 1e-12: "
559 << max_error << std::endl ;
564int main (
int argc ,
char * argv[] )
568 bool print_basis_function = true ;
569 bool print_prefilter_poles = true ;
570 bool print_umbrella_structures = true ;
572 std::cout << std::setprecision ( 64 ) ;
577 if ( print_basis_function )
579 for (
int degree = 0 ; degree <
degree_limit ; degree++ )
581 std::cout <<
"const vspline::xlf_type K"
585 for (
int x2 = 0 ; x2 <= degree ; x2++ )
599 for (
int degree = 2 ; degree <
degree_limit ; degree++ )
601 std::vector<mpf_class> res ;
604 if ( res.size() != degree / 2 )
606 std::cerr <<
"not enough poles for degree " << degree << std::endl ;
610 if ( print_prefilter_poles )
612 std::cout <<
"const vspline::xlf_type Poles_"
617 for (
int p = 0 ; p < degree / 2 ; p++ )
629 test ( 10000 , res , degree ) ;
631 ldtest ( 10000 , res , degree ) ;
634 if ( print_umbrella_structures )
636 std::cout << std::noshowpos ;
637 std::cout <<
"const vspline::xlf_type* const precomputed_poles[] = {"
639 std::cout <<
" 0, " << std::endl ;
640 std::cout <<
" 0, " << std::endl ;
642 std::cout <<
" Poles_" << i <<
", " << std::endl ;
643 std::cout <<
"} ;" << std::endl ;
644 std::cout <<
"const vspline::xlf_type* const precomputed_basis_function_values[] = {"
647 std::cout <<
" K" << i <<
", " << std::endl ;
648 std::cout <<
"} ;" << std::endl ;
int main(int argc, char *argv[])
void _fill_basis_table(int x2, int degree)
void ldbackward(vspline::xlf_type *x, int size, vspline::xlf_type pole)
mpq_class & access_table(int degree, int x2)
void forward(mpf_class *x, int size, mpf_class pole)
void ldtest(int size, const std::vector< mpf_class > &poles, int degree)
mpq_class basis_table[degree_limit][degree_limit+1]
void backward(mpf_class *x, int size, mpf_class pole)
void ldforward(vspline::xlf_type *x, int size, vspline::xlf_type pole)
void calculate_prefilter_poles(std::vector< mpf_class > &res, int degree)
void newton(dtype &result, dtype x, int ncoeff, dtype *pcoeff)
void test(int size, const std::vector< mpf_class > &poles, int degree)
vspline::xlf_type get_xlf(const mpf_class &_x)
includes all headers from vspline (most of them indirectly)