File indexing completed on 2024-05-12 15:27:09
0001 /*************************************************************************** 0002 File : nsl_sf_poly.c 0003 Project : LabPlot 0004 Description : NSL special polynomial functions 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2016 by Stefan Gerlach (stefan.gerlach@uni.kn) 0007 0008 ***************************************************************************/ 0009 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program; if not, write to the Free Software * 0024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0025 * Boston, MA 02110-1301 USA * 0026 * * 0027 ***************************************************************************/ 0028 0029 #include "nsl_sf_poly.h" 0030 #include <stdio.h> // debugging 0031 #include <math.h> 0032 #include <gsl/gsl_math.h> 0033 #include <gsl/gsl_sf_pow_int.h> 0034 0035 /* see https://en.wikipedia.org/wiki/Chebyshev_polynomials */ 0036 double nsl_sf_poly_chebyshev_T(int n, double x) { 0037 if (fabs(x) <= 1) 0038 return cos(n * acos(x)); 0039 else if (x > 1) 0040 return cosh(n * gsl_acosh(x)); 0041 else 0042 return pow(-1., n)*cosh(n * gsl_acosh(-x)); 0043 } 0044 0045 double nsl_sf_poly_chebyshev_U(int n, double x) { 0046 double sq = sqrt(x*x - 1); 0047 return (pow(x + sq, n + 1) - pow(x - sq, n + 1))/2./sq; 0048 } 0049 0050 /* from http://www.crbond.com/papers/lopt.pdf */ 0051 double nsl_sf_poly_optimal_legendre_L(int n, double x) { 0052 if (n < 1 || n > 10) 0053 return 0.0; 0054 0055 switch (n) { 0056 case 1: 0057 return x; 0058 case 2: 0059 return x*x; 0060 case 3: 0061 return (1. + (-3. + 3.*x)*x)*x; 0062 case 4: 0063 return (3. + (-8. + 6*x)*x)*x*x; 0064 case 5: 0065 return (1. + (-8. + (28. + (-40. + 20*x)*x)*x)*x)*x; 0066 case 6: 0067 return (6. + (-40. + (105. + (-120. + 50.*x)*x)*x)*x)*x*x; 0068 case 7: 0069 return (1. + (-15. + (105. + (-355. + (615. + (-525. + 175.*x)*x)*x)*x)*x)*x)*x; 0070 case 8: 0071 return (10. + (-120. + (615. + (-1624. + (2310. + (-1680. + 490.*x)*x)*x)*x)*x)*x)*x*x; 0072 case 9: 0073 return (1. + (-24. + (276. + (-1624. + (5376. + (-10416. + (11704. + (-7056. + 1764*x)*x)*x)*x)*x)*x)*x)*x)*x; 0074 case 10: 0075 return (15. + (-280. + (2310. + (-10416. + (27860. + (-45360. + (44100. + (23520. + 5292.*x)*x)*x)*x)*x)*x)*x)*x)*x*x; 0076 } 0077 0078 return 0.0; 0079 } 0080 0081 /* 0082 * https://en.wikipedia.org/wiki/Bessel_polynomials 0083 * using recursion 0084 */ 0085 gsl_complex nsl_sf_poly_bessel_y(int n, gsl_complex x) { 0086 if (n == 0) 0087 return gsl_complex_rect(1.0, 0.0); 0088 if (n == 1) 0089 return gsl_complex_add_real(x, 1.0); 0090 0091 gsl_complex z1 = gsl_complex_mul(x, gsl_complex_mul_real(nsl_sf_poly_bessel_y(n - 1, x), 2.*n-1.)); 0092 gsl_complex z2 = nsl_sf_poly_bessel_y(n - 2, x); 0093 return gsl_complex_add(z1, z2); 0094 } 0095 0096 gsl_complex nsl_sf_poly_reversed_bessel_theta(int n, gsl_complex x) { 0097 if (n == 0) 0098 return gsl_complex_rect(1.0, 0.0); 0099 if (n == 1) 0100 return gsl_complex_add_real(x, 1.0); 0101 0102 gsl_complex z1 = gsl_complex_mul_real(nsl_sf_poly_reversed_bessel_theta(n - 1, x), 2.*n-1.); 0103 gsl_complex z2 = gsl_complex_mul(gsl_complex_mul(x, x), nsl_sf_poly_reversed_bessel_theta(n - 2, x)); 0104 return gsl_complex_add(z1, z2); 0105 } 0106 0107 /***************** interpolating polynomials *************/ 0108 0109 double nsl_sf_poly_interp_lagrange_0_int(double *x, double y) { 0110 /* rectangle rule */ 0111 return (x[1]-x[0])*y; 0112 } 0113 0114 double nsl_sf_poly_interp_lagrange_1(double v, double *x, double *y) { 0115 return (y[0]*(x[1]-v) + y[1]*(v-x[0]))/(x[1]-x[0]); 0116 } 0117 double nsl_sf_poly_interp_lagrange_1_deriv(double *x, double *y) { 0118 return (y[0]-y[1])/(x[1]-x[0]); 0119 } 0120 double nsl_sf_poly_interp_lagrange_1_int(double *x, double *y) { 0121 /* trapezoid rule (2-point) */ 0122 return (x[1]-x[0])*(y[0]+y[1])/2.; 0123 } 0124 double nsl_sf_poly_interp_lagrange_1_absint(double *x, double *y) { 0125 double dx = x[1]-x[0]; 0126 if (y[0]*y[1] < 0) /* sign change */ 0127 return dx*( (fabs(y[0])-fabs(y[1]))/(fabs(y[1]/y[0])+1) + fabs(y[1]) )/2.; 0128 if (y[0] < 0 && y[1] < 0) 0129 return dx*(fabs(y[0])+fabs(y[1]))/2.; 0130 else 0131 return dx*(y[0]+y[1])/2.; 0132 } 0133 0134 double nsl_sf_poly_interp_lagrange_2(double v, double *x, double *y) { 0135 double h1 = x[1]-x[0], h2 = x[2]-x[1]; 0136 double h12 = h1+h2; 0137 0138 return y[0]*(v-x[1])*(v-x[2])/(h1*h12) + y[1]*(x[0]-v)*(v-x[2])/(h1*h2) + y[2]*(x[0]-v)*(x[1]-v)/(h12*h2); 0139 } 0140 double nsl_sf_poly_interp_lagrange_2_deriv(double v, double *x, double *y) { 0141 double h1 = x[1]-x[0], h2 = x[2]-x[1]; 0142 double h12 = h1+h2; 0143 0144 return y[0]*(2.*v-x[1]-x[2])/(h1*h12) + y[1]*(x[0]-2.*v+x[2])/(h1*h2) + y[2]*(2.*v-x[0]-x[1])/(h12*h2); 0145 } 0146 double nsl_sf_poly_interp_lagrange_2_deriv2(double *x, double *y) { 0147 double h1 = x[1]-x[0], h2 = x[2]-x[1]; 0148 double h12 = h1+h2; 0149 0150 return 2.*( y[0]/(h1*h12) - y[1]/(h1*h2) + y[2]/(h12*h2) ); 0151 } 0152 double nsl_sf_poly_interp_lagrange_2_int(double *x, double *y) { 0153 /* Simpson's 1/3 rule for non-uniform grid (3-point) */ 0154 double h1 = x[1]-x[0], h2 = x[2]-x[1]; 0155 double h12 = h1+h2, h1_2 = h1/h2; 0156 0157 return h12/6.*( (2.-1./h1_2)*y[0] + (2.+h1_2+1./h1_2)*y[1] + (2.-h1_2)*y[2] ); 0158 } 0159 0160 double nsl_sf_poly_interp_lagrange_3(double v, double *x, double *y) { 0161 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2]; 0162 double h12 = h1+h2, h23 = h2+h3, h13=h12+h3; 0163 0164 return y[0]*(v-x[1])*(v-x[2])*(v-x[3])/(h1*h12*h13) + y[1]*(v-x[0])*(v-x[2])*(v-x[3])/(h1*h2*h23) 0165 - y[2]*(v-x[0])*(v-x[1])*(v-x[3])/(h12*h2*h3) + y[3]*(v-x[0])*(v-x[1])*(v-x[2])/(h13*h23*h3); 0166 } 0167 double nsl_sf_poly_interp_lagrange_3_deriv(double v, double *x, double *y) { 0168 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], S = x[0]+x[1]+x[2]+x[3]; 0169 double h12 = h1+h2, h23 = h2+h3, h13=h12+h3; 0170 0171 return -y[0]*(3*v*v-2.*v*(S-x[0])+x[1]*x[2]+(S-x[0]-x[3])*x[3])/(h1*h12*h13) 0172 + y[1]*(3*v*v-2.*v*(S-x[1])+(x[0]+x[2])*x[3])/(h1*h2*h23) 0173 + y[2]*(3*v*v+x[0]*x[1]-2.*v*(S-x[2])+(x[0]+x[1])*x[3])/(h12*h2*h3) 0174 + y[3]*(3*v*v+x[0]*x[1]+(x[0]+x[1])*x[2]-2.*v*(S-x[3]))/(h13*h23*h3); 0175 } 0176 double nsl_sf_poly_interp_lagrange_3_deriv2(double v, double *x, double *y) { 0177 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], S = x[0]+x[1]+x[2]+x[3]; 0178 double h12 = h1+h2, h23 = h2+h3, h13=h12+h3; 0179 0180 return 2.*( y[0]*(S-3.*v-x[0])/(h1*h12*h13) + y[1]*(3.*v-S+x[1])/(h1*h2*h23) 0181 + y[2]*(S-3.*v-x[2])/(h12*h2*h3) + y[3]*(3.*v-S+x[3])/(h13*h23*h3) ); 0182 } 0183 double nsl_sf_poly_interp_lagrange_3_deriv3(double *x, double *y) { 0184 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2]; 0185 double h12 = h1+h2, h23 = h2+h3, h13=h12+h3; 0186 0187 return 6.*( -y[0]/(h1*h12*h13) + y[1]/(h1*h2*h23) - y[2]/(h12*h2*h3) +y[3]/(h13*h23*h3) ); 0188 } 0189 double nsl_sf_poly_interp_lagrange_3_int(double *x, double *y) { 0190 /* Simpson's 3/8 rule for non-uniform grid (4-point) */ 0191 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2]; 0192 double h12 = h1+h2, h23 = h2+h3, h13 = h12+h3; 0193 0194 return h13/12.*( (3.*x[0]*x[0]-4.*x[0]*(x[1]+x[2])+6.*x[1]*x[2]+2.*x[0]*x[3]-2.*(x[1]+x[2])*x[3]+x[3]*x[3])/(h1*h12)*y[0] 0195 + h13*h13*(h12-h3)/(h1*h2*h23)*y[1] + h13*h13*(h23-h1)/(h12*h2*h3)*y[2] 0196 + (x[0]*x[0]-2.*x[0]*(x[1]+x[2])+6.*x[1]*x[2]+2.*x[0]*x[3]-4.*(x[1]+x[2])*x[3]+3.*x[3]*x[3])/(h23*h3)*y[3] ); 0197 } 0198 0199 /* 1/2 sum_{i != j}^n (x_i x_j) for n=4 */ 0200 double sum_of_2product_combinations_4_2(double a, double b, double c, double d) { 0201 return a*(b+c+d) + b*(c+d) + c*d; 0202 } 0203 /* 1/6 sum_{i != j, j != k, i != k}^n (x_i x_j x_k) for n=4 */ 0204 double sum_of_3product_combinations_4_6(double a, double b, double c, double d) { 0205 return a*(b*(c+d) + c*d) + b*c*d; 0206 } 0207 0208 double nsl_sf_poly_interp_lagrange_4(double v, double *x, double *y) { 0209 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3]; 0210 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h13=h12+h3, h24 = h23+h4, h14 = h12+h34; 0211 0212 return y[0]*(v-x[1])*(v-x[2])*(v-x[3])*(v-x[4])/(h1*h12*h13*h14) 0213 - y[1]*(v-x[0])*(v-x[2])*(v-x[3])*(v-x[4])/(h1*h2*h23*h24) 0214 + y[2]*(v-x[0])*(v-x[1])*(v-x[3])*(v-x[4])/(h12*h2*h3*h34) 0215 - y[3]*(v-x[0])*(v-x[1])*(v-x[2])*(v-x[4])/(h13*h23*h3*h4) 0216 + y[4]*(v-x[0])*(v-x[1])*(v-x[2])*(v-x[3])/(h14*h24*h34*h4); 0217 } 0218 double nsl_sf_poly_interp_lagrange_4_deriv(double v, double *x, double *y) { 0219 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3], S = x[0]+x[1]+x[2]+x[3]+x[4]; 0220 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h13=h12+h3, h24 = h23+h4, h14 = h12+h34; 0221 0222 return y[0]*(4.*v*v*v - 3.*v*v*(S-x[0]) - sum_of_3product_combinations_4_6(x[1],x[2],x[3],x[4]) 0223 + 2.*v*sum_of_2product_combinations_4_2(x[1],x[2],x[3],x[4]) )/(h1*h12*h13*h14) 0224 - y[1]*(4.*v*v*v - 3.*v*v*(S-x[1]) - sum_of_3product_combinations_4_6(x[0],x[2],x[3],x[4]) 0225 + 2.*v*sum_of_2product_combinations_4_2(x[0],x[2],x[3],x[4]) )/(h1*h2*h23*h24) 0226 + y[2]*(4.*v*v*v - 3.*v*v*(S-x[2]) - sum_of_3product_combinations_4_6(x[0],x[1],x[3],x[4]) 0227 + 2.*v*sum_of_2product_combinations_4_2(x[0],x[1],x[3],x[4]) )/(h12*h2*h3*h34) 0228 - y[3]*(4.*v*v*v - 3.*v*v*(S-x[3]) - sum_of_3product_combinations_4_6(x[0],x[1],x[2],x[4]) 0229 + 2.*v*sum_of_2product_combinations_4_2(x[0],x[1],x[2],x[4]) )/(h13*h23*h3*h4) 0230 + y[4]*(4.*v*v*v - 3.*v*v*(S-x[4]) - sum_of_3product_combinations_4_6(x[0],x[1],x[2],x[3]) 0231 + 2.*v*sum_of_2product_combinations_4_2(x[0],x[1],x[2],x[3]) )/(h14*h24*h34*h4); 0232 } 0233 double nsl_sf_poly_interp_lagrange_4_deriv2(double v, double *x, double *y) { 0234 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3], S = x[0]+x[1]+x[2]+x[3]+x[4]; 0235 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h13=h12+h3, h24 = h23+h4, h14 = h12+h34; 0236 0237 return 2.*( 0238 y[0]*(6.*v*v-3.*v*(S-x[0]) + sum_of_2product_combinations_4_2(x[1],x[2],x[3],x[4]))/(h1*h12*h13*h14) 0239 - y[1]*(6.*v*v-3.*v*(S-x[1]) + sum_of_2product_combinations_4_2(x[0],x[2],x[3],x[4]))/(h1*h2*h23*h24) 0240 + y[2]*(6.*v*v-3.*v*(S-x[2]) + sum_of_2product_combinations_4_2(x[0],x[1],x[3],x[4]))/(h12*h2*h3*h34) 0241 - y[3]*(6.*v*v-3.*v*(S-x[3]) + sum_of_2product_combinations_4_2(x[0],x[1],x[2],x[4]))/(h13*h23*h3*h4) 0242 + y[4]*(6.*v*v-3.*v*(S-x[4]) + sum_of_2product_combinations_4_2(x[0],x[1],x[2],x[3]))/(h14*h24*h34*h4) ); 0243 } 0244 double nsl_sf_poly_interp_lagrange_4_deriv3(double v, double *x, double *y) { 0245 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3], S = x[0]+x[1]+x[2]+x[3]+x[4]; 0246 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h13=h12+h3, h24 = h23+h4, h14 = h12+h34; 0247 0248 return 6.*( y[0]*(4.*v-S+x[0])/(h1*h12*h13*h14) + y[1]*(S-4.*v-x[1])/(h1*h2*h23*h24) + y[2]*(4.*v-S+x[2])/(h12*h2*h3*h34) 0249 + y[3]*(S-4.*v-x[3])/(h13*h23*h3*h4) + y[4]*(4.*v-S+x[4])/(h14*h24*h34*h4) ); 0250 } 0251 double nsl_sf_poly_interp_lagrange_4_deriv4(double *x, double *y) { 0252 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3]; 0253 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h13=h12+h3, h24 = h23+h4, h14 = h12+h34; 0254 0255 return 24.*( y[0]/(h1*h12*h13*h14) - y[1]/(h1*h2*h23*h24) + y[2]/(h12*h2*h3*h34)- y[3]/(h13*h23*h3*h4) + y[4]/(h14*h24*h34*h4) ); 0256 } 0257 0258 /* 1/2 sum_{i != j}^n (x_i x_j) for n=6 */ 0259 double sum_of_product_combinations_6_2(double a, double b, double c, double d, double e, double f) { 0260 return a*(b+c+d+e+f) + b*(c+d+e+f) + c*(d+e+f) + d*(e+f) + e*f; 0261 } 0262 0263 double nsl_sf_poly_interp_lagrange_6_deriv4(double v, double *x, double *y) { 0264 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3], h5 = x[5]-x[4], h6 = x[6]-x[5]; 0265 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h45 = h4+h5, h56 = h5+h6; 0266 double h13 = h12+h3, h24 = h23+h4, h35 = h34+h5, h46 = h45+h6, h14 = h13+h4, h25 = h24+h5, h36 = h35+h6; 0267 double h15 = h14+h5, h26 = h25 + h6, h16 = h15+h6, S = x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]; 0268 0269 return 24.*( 0270 y[0]*(15.*v*v-5.*v*(S-x[0]) + sum_of_product_combinations_6_2(x[1],x[2],x[3],x[4],x[5],x[6]))/(h1*h12*h13*h14*h15*h16) 0271 - y[1]*(15.*v*v-5.*v*(S-x[1]) + sum_of_product_combinations_6_2(x[0],x[2],x[3],x[4],x[5],x[6]))/(h1*h2*h23*h24*h25*h26) 0272 + y[2]*(15.*v*v-5.*v*(S-x[2]) + sum_of_product_combinations_6_2(x[0],x[1],x[3],x[4],x[5],x[6]))/(h12*h2*h3*h34*h35*h36) 0273 - y[3]*(15.*v*v-5.*v*(S-x[3]) + sum_of_product_combinations_6_2(x[0],x[1],x[2],x[4],x[5],x[6]))/(h13*h23*h3*h4*h45*h46) 0274 + y[4]*(15.*v*v-5.*v*(S-x[4]) + sum_of_product_combinations_6_2(x[0],x[1],x[2],x[3],x[5],x[6]))/(h14*h24*h34*h4*h5*h56) 0275 - y[5]*(15.*v*v-5.*v*(S-x[5]) + sum_of_product_combinations_6_2(x[0],x[1],x[2],x[3],x[4],x[6]))/(h15*h25*h35*h45*h5*h6) 0276 + y[6]*(15.*v*v-5.*v*(S-x[6]) + sum_of_product_combinations_6_2(x[0],x[1],x[2],x[3],x[4],x[5]))/(h16*h26*h36*h46*h56*h6) ); 0277 } 0278 double nsl_sf_poly_interp_lagrange_6_deriv5(double v, double *x, double *y) { 0279 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3], h5 = x[5]-x[4], h6 = x[6]-x[5]; 0280 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h45 = h4+h5, h56 = h5+h6; 0281 double h13 = h12+h3, h24 = h23+h4, h35 = h34+h5, h46 = h45+h6, h14 = h13+h4, h25 = h24+h5, h36 = h35+h6; 0282 double h15 = h14+h5, h26 = h25 + h6, h16 = h15+h6, S = x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]; 0283 0284 return 120.*( y[0]*(6.*v-S+x[0])/(h1*h12*h13*h14*h15*h16) - y[1]*(6.*v-S+x[1])/(h1*h2*h23*h24*h25*h26) 0285 + y[2]*(6.*v-S+x[2])/(h12*h2*h3*h34*h35*h36) - y[3]*(6.*v-S+x[3])/(h13*h23*h3*h4*h45*h46) 0286 + y[4]*(6.*v-S+x[4])/(h14*h24*h34*h4*h5*h56) - y[5]*(6.*v-S+x[5])/(h15*h25*h35*h45*h5*h6) 0287 + y[6]*(6.*v-S+x[6])/(h16*h26*h36*h46*h56*h6) ); 0288 } 0289 double nsl_sf_poly_interp_lagrange_6_deriv6(double *x, double *y) { 0290 double h1 = x[1]-x[0], h2 = x[2]-x[1], h3 = x[3]-x[2], h4 = x[4]-x[3], h5 = x[5]-x[4], h6 = x[6]-x[5]; 0291 double h12 = h1+h2, h23 = h2+h3, h34 = h3+h4, h45 = h4+h5, h56 = h5+h6; 0292 double h13 = h12+h3, h24 = h23+h4, h35 = h34+h5, h46 = h45+h6, h14 = h13+h4, h25 = h24+h5, h36 = h35+h6; 0293 double h15 = h14+h5, h26 = h25 + h6, h16 = h15+h6; 0294 0295 return 720.*( y[0]/(h1*h12*h13*h14*h15*h16) - y[1]/(h1*h2*h23*h24*h25*h26) 0296 + y[2]/(h12*h2*h3*h34*h35*h36) - y[3]/(h13*h23*h3*h4*h45*h46) 0297 + y[4]/(h14*h24*h34*h4*h5*h56) - y[5]/(h15*h25*h35*h45*h5*h6) 0298 + y[6]/(h16*h26*h36*h46*h56*h6) ); 0299 }