File indexing completed on 2024-05-12 15:27:08

0001 /***************************************************************************
0002     File                 : nsl_int.c
0003     Project              : LabPlot
0004     Description          : NSL numerical integration functions
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2016 by Stefan Gerlach (stefan.gerlach@uni.kn)
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *  This program is free software; you can redistribute it and/or modify   *
0012  *  it under the terms of the GNU General Public License as published by   *
0013  *  the Free Software Foundation; either version 2 of the License, or      *
0014  *  (at your option) any later version.                                    *
0015  *                                                                         *
0016  *  This program is distributed in the hope that it will be useful,        *
0017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0019  *  GNU General Public License for more details.                           *
0020  *                                                                         *
0021  *   You should have received a copy of the GNU General Public License     *
0022  *   along with this program; if not, write to the Free Software           *
0023  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0024  *   Boston, MA  02110-1301  USA                                           *
0025  *                                                                         *
0026  ***************************************************************************/
0027 
0028 /* TODO:
0029     * absolute area for Simpson/Simpson-3/8 rules (needs more numerics)
0030 */
0031 
0032 #include "nsl_int.h"
0033 #include "nsl_common.h"
0034 #include "nsl_sf_poly.h"
0035 
0036 
0037 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)")};
0038 
0039 int nsl_int_rectangle(const double *x, double *y, const size_t n, int abs) {
0040     if (n == 0)
0041         return -1;
0042 
0043     size_t i, j;
0044     double sum = 0, xdata[2];
0045     for (i = 0; i < n-1; i++) {
0046         for (j=0; j < 2; j++)
0047             xdata[j] = x[i+j];
0048         double s = nsl_sf_poly_interp_lagrange_0_int(xdata, y[i]);
0049         if (abs)
0050             s = fabs(s);
0051         y[i] = sum;
0052         sum += s;
0053     }
0054     y[n-1] = sum;
0055 
0056     return 0;
0057 }
0058 
0059 int nsl_int_trapezoid(const double *x, double *y, const size_t n, int abs) {
0060     if (n < 2)
0061         return -1;
0062 
0063     size_t i, j;
0064     double sum = 0, xdata[2], ydata[2];
0065     for (i = 0; i < n-1; i++) {
0066         for (j = 0; j < 2; j++)
0067             xdata[j] = x[i+j], ydata[j] = y[i+j];
0068         y[i] = sum;
0069         if (abs)
0070             sum += nsl_sf_poly_interp_lagrange_1_absint(xdata, ydata);
0071         else
0072             sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata);
0073     }
0074     y[n-1] = sum;
0075 
0076     return 0;
0077 }
0078 
0079 size_t nsl_int_simpson(double *x, double *y, const size_t n, int abs) {
0080     if (n < 3)
0081         return 0;
0082     if (abs != 0) {
0083         printf("absolute area Simpson rule not implemented yet.\n");
0084         return 0;
0085     }
0086 
0087     size_t i, j, np=1;
0088     double sum=0, xdata[3], ydata[3];
0089     for (i = 0; i < n-2; i+=2) {
0090         for (j=0; j < 3; j++)
0091             xdata[j] = x[i+j], ydata[j] = y[i+j];
0092 
0093         sum += nsl_sf_poly_interp_lagrange_2_int(xdata, ydata);
0094         y[np] = sum;
0095         x[np++] = (x[i]+x[i+1]+x[i+2])/3.;
0096         /*printf("i/sum: %zu-%zu %g\n", i, i+2, sum);*/
0097     }
0098 
0099     /* handle possible last point: use trapezoid rule */
0100     if (i == n-2) {
0101         for (j=0; j < 2; j++)
0102             xdata[j] = x[i+j], ydata[j] = y[i+j];
0103         sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata);
0104         y[np] = sum;
0105         x[np++] = x[i];
0106     }
0107 
0108     /* first point */
0109     y[0]=0;
0110 
0111     return np;
0112 }
0113 
0114 size_t nsl_int_simpson_3_8(double *x, double *y, const size_t n, int abs) {
0115     if (n < 4) {
0116         printf("minimum number of points is 4 (given %d).\n", (int)n);
0117         return 0;
0118     }
0119     if (abs != 0) {
0120         printf("absolute area Simpson 3/8 rule not implemented yet.\n");
0121         return 0;
0122     }
0123 
0124     size_t i, j, np=1;
0125     double sum=0, xdata[4], ydata[4];
0126     for (i = 0; i < n-3; i+=3) {
0127         for (j=0; j < 4; j++)
0128             xdata[j] = x[i+j], ydata[j] = y[i+j];
0129 
0130         sum += nsl_sf_poly_interp_lagrange_3_int(xdata, ydata);
0131         y[np] = sum;
0132         x[np++] = (x[i]+x[i+1]+x[i+2]+x[i+3])/4.;
0133         /*printf("i/sum: %zu-%zu %g\n", i, i+3, sum);*/
0134     }
0135 
0136     /* handle possible last point(s): use trapezoid (one point) or simpson rule (two points) */
0137     if (i == n-2) {
0138         for (j=0; j < 2; j++)
0139             xdata[j] = x[i+j], ydata[j] = y[i+j];
0140         sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata);
0141         y[np] = sum;
0142         x[np++] = x[i];
0143     } else if ( i == n-3) {
0144         for (j=0; j < 3; j++)
0145             xdata[j] = x[i+j], ydata[j] = y[i+j];
0146         sum += nsl_sf_poly_interp_lagrange_2_int(xdata, ydata);
0147         y[np] = sum;
0148         x[np++] = (x[i]+x[i+1]+x[i+2])/3.;
0149     }
0150 
0151     /* first point */
0152     y[0]=0;
0153 
0154     return np;
0155 }