File indexing completed on 2024-05-12 03:47:52

0001 /*
0002     File                 : nsl_int.c
0003     Project              : LabPlot
0004     Description          : NSL numerical integration functions
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2016 Stefan Gerlach <stefan.gerlach@uni.kn>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 /* TODO:
0012  * absolute area for Simpson/Simpson-3/8 rules (needs more numerics)
0013  */
0014 
0015 #include "nsl_int.h"
0016 #include "nsl_common.h"
0017 #include "nsl_sf_poly.h"
0018 
0019 const char* nsl_int_method_name[] = {i18n("Rectangle (1-point)"), i18n("Trapezoid (2-point)"), i18n("Simpson's (3-point)"), i18n("Simpson's 3/8 (4-point)")};
0020 
0021 int nsl_int_rectangle(const double* x, double* y, const size_t n, int abs) {
0022     if (n == 0)
0023         return -1;
0024 
0025     size_t i, j;
0026     double sum = 0, xdata[2];
0027     for (i = 0; i < n - 1; i++) {
0028         for (j = 0; j < 2; j++)
0029             xdata[j] = x[i + j];
0030         double s = nsl_sf_poly_interp_lagrange_0_int(xdata, y[i]);
0031         if (abs)
0032             s = fabs(s);
0033         y[i] = sum;
0034         sum += s;
0035     }
0036     y[n - 1] = sum;
0037 
0038     return 0;
0039 }
0040 
0041 int nsl_int_trapezoid(const double* x, double* y, const size_t n, int abs) {
0042     if (n < 2)
0043         return -1;
0044 
0045     size_t i, j;
0046     double sum = 0, xdata[2], ydata[2];
0047     for (i = 0; i < n - 1; i++) {
0048         for (j = 0; j < 2; j++)
0049             xdata[j] = x[i + j], ydata[j] = y[i + j];
0050         y[i] = sum;
0051         if (abs)
0052             sum += nsl_sf_poly_interp_lagrange_1_absint(xdata, ydata);
0053         else
0054             sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata);
0055     }
0056     y[n - 1] = sum;
0057 
0058     return 0;
0059 }
0060 
0061 size_t nsl_int_simpson(double* x, double* y, const size_t n, int abs) {
0062     if (n < 3)
0063         return 0;
0064     if (abs != 0) {
0065         printf("absolute area Simpson rule not implemented yet.\n");
0066         return 0;
0067     }
0068 
0069     size_t i, j, np = 1;
0070     double sum = 0, xdata[3], ydata[3];
0071     for (i = 0; i < n - 2; i += 2) {
0072         for (j = 0; j < 3; j++)
0073             xdata[j] = x[i + j], ydata[j] = y[i + j];
0074 
0075         sum += nsl_sf_poly_interp_lagrange_2_int(xdata, ydata);
0076         y[np] = sum;
0077         x[np++] = (x[i] + x[i + 1] + x[i + 2]) / 3.;
0078         /*printf("i/sum: %zu-%zu %g\n", i, i+2, sum);*/
0079     }
0080 
0081     /* handle possible last point: use trapezoid rule */
0082     if (i == n - 2) {
0083         for (j = 0; j < 2; j++)
0084             xdata[j] = x[i + j], ydata[j] = y[i + j];
0085         sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata);
0086         y[np] = sum;
0087         x[np++] = x[i];
0088     }
0089 
0090     /* first point */
0091     y[0] = 0;
0092 
0093     return np;
0094 }
0095 
0096 size_t nsl_int_simpson_3_8(double* x, double* y, const size_t n, int abs) {
0097     if (n < 4) {
0098         printf("minimum number of points is 4 (given %d).\n", (int)n);
0099         return 0;
0100     }
0101     if (abs != 0) {
0102         printf("absolute area Simpson 3/8 rule not implemented yet.\n");
0103         return 0;
0104     }
0105 
0106     size_t i, j, np = 1;
0107     double sum = 0, xdata[4], ydata[4];
0108     for (i = 0; i < n - 3; i += 3) {
0109         for (j = 0; j < 4; j++)
0110             xdata[j] = x[i + j], ydata[j] = y[i + j];
0111 
0112         sum += nsl_sf_poly_interp_lagrange_3_int(xdata, ydata);
0113         y[np] = sum;
0114         x[np++] = (x[i] + x[i + 1] + x[i + 2] + x[i + 3]) / 4.;
0115         /*printf("i/sum: %zu-%zu %g\n", i, i+3, sum);*/
0116     }
0117 
0118     /* handle possible last point(s): use trapezoid (one point) or simpson rule (two points) */
0119     if (i == n - 2) {
0120         for (j = 0; j < 2; j++)
0121             xdata[j] = x[i + j], ydata[j] = y[i + j];
0122         sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata);
0123         y[np] = sum;
0124         x[np++] = x[i];
0125     } else if (i == n - 3) {
0126         for (j = 0; j < 3; j++)
0127             xdata[j] = x[i + j], ydata[j] = y[i + j];
0128         sum += nsl_sf_poly_interp_lagrange_2_int(xdata, ydata);
0129         y[np] = sum;
0130         x[np++] = (x[i] + x[i + 1] + x[i + 2]) / 3.;
0131     }
0132 
0133     /* first point */
0134     y[0] = 0;
0135 
0136     return np;
0137 }