numo-gsl-integration 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/README.md +20 -19
- data/docs/routines.md +66 -16
- data/ext/numo/gsl/integration/callback.c +15 -0
- data/ext/numo/gsl/integration/cquad.c +1 -0
- data/ext/numo/gsl/integration/fixed.c +163 -0
- data/ext/numo/gsl/integration/glfixed.c +21 -0
- data/ext/numo/gsl/integration/integration.c +7 -0
- data/ext/numo/gsl/integration/integration_internal.h +9 -0
- data/ext/numo/gsl/integration/qagi.c +1 -0
- data/ext/numo/gsl/integration/qagil.c +8 -0
- data/ext/numo/gsl/integration/qagiu.c +8 -0
- data/ext/numo/gsl/integration/qagp.c +34 -0
- data/ext/numo/gsl/integration/qags.c +1 -0
- data/ext/numo/gsl/integration/qawc.c +8 -0
- data/ext/numo/gsl/integration/qawf.c +3 -0
- data/ext/numo/gsl/integration/qawo.c +3 -0
- data/ext/numo/gsl/integration/qaws.c +6 -0
- data/ext/numo/gsl/integration/romberg.c +1 -0
- data/lib/numo/gsl/integration/version.rb +1 -1
- data/sig/numo/gsl/integration.rbs +8 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0ed1ccbd179314a5925c135faa809ff255bb9acf626c475af39237c8e397f89a
|
|
4
|
+
data.tar.gz: 891a0e74db19f6d5c5b40aeff66a2610dbf063c5d2ccd3b9dfdae0a730a880fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 86207b0346bcff38a8892e36c8721d2327010b7367a74b91344db9c799ae2ea0390203572ce275efad201a47bc480f66e26b1daad753cfd63c878c7b78575793
|
|
7
|
+
data.tar.gz: 532c33c4e35c701e901cf10d771a9c982533b927353dbbe0d53173684dc2ab66a90231e617906a10cc3d530aa05f364ea83735982e3721b421e06e1cbb2b983a
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.3.0] - 2026-11-05
|
|
6
|
+
|
|
7
|
+
### Added in 0.3.0
|
|
8
|
+
|
|
9
|
+
- Added fixed point quadrature with Legendre, first- and second-kind Chebyshev, Gegenbauer, Jacobi, Laguerre, Hermite, exponential, and rational rules.
|
|
10
|
+
|
|
5
11
|
## [0.2.0] - 2026-11-05
|
|
6
12
|
|
|
7
13
|
### Changed in 0.2.0
|
|
@@ -22,7 +28,7 @@
|
|
|
22
28
|
|
|
23
29
|
### Added in 0.1.0
|
|
24
30
|
|
|
25
|
-
- Added fixed-order Gauss
|
|
31
|
+
- Added fixed-order Gauss-Legendre integration for smooth functions.
|
|
26
32
|
- Added Romberg integration for smooth functions with function-evaluation counts.
|
|
27
33
|
- Added CQUAD doubly-adaptive integration with function-evaluation counts.
|
|
28
34
|
- Added QAWF adaptive integration for sine- and cosine-weighted Fourier integrals over a semi-infinite interval.
|
data/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Numo::GSL::Integration
|
|
2
2
|
|
|
3
|
-
`numo-gsl-integration` provides numerical integration routines from the [GNU Scientific Library (GSL)](https://www.gnu.org/software/gsl/) under the `Numo::GSL::Integration` namespace. It can be installed and loaded without `numo-gsl` or `numo-gsl-alt
|
|
3
|
+
`numo-gsl-integration` provides numerical integration routines from the [GNU Scientific Library (GSL)](https://www.gnu.org/software/gsl/) under the `Numo::GSL::Integration` namespace. It can be installed and loaded without [`numo-gsl`](https://github.com/ruby-numo/numo-gsl) or [`numo-gsl-alt`](https://github.com/mvz/numo-gsl-alt).
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- [Ruby](https://www.ruby-lang.org/) 3.2 or later
|
|
8
8
|
- GNU Scientific Library (GSL)
|
|
9
|
-
- `gsl-config` available in `PATH`
|
|
9
|
+
- `gsl-config` available in `PATH`
|
|
10
|
+
|
|
10
11
|
GSL itself must be installed separately.
|
|
11
12
|
|
|
12
13
|
## Installation
|
|
@@ -33,7 +34,6 @@ Load the library:
|
|
|
33
34
|
require "numo/gsl/integration"
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
The native extension defines `Numo::GSL::GslError` and installs a process-wide GSL error handler when it is loaded.
|
|
37
37
|
For example, use `qag` to integrate a function over a finite interval:
|
|
38
38
|
|
|
39
39
|
```ruby
|
|
@@ -44,22 +44,23 @@ end
|
|
|
44
44
|
|
|
45
45
|
## Supported routines
|
|
46
46
|
|
|
47
|
-
| Method | Interval
|
|
48
|
-
| --------- |
|
|
49
|
-
| `qng` | Finite
|
|
50
|
-
| `qag` | Finite
|
|
51
|
-
| `qags` | Finite
|
|
52
|
-
| `qagp` | Finite
|
|
53
|
-
| `qagi` | Infinite
|
|
54
|
-
| `qagiu` | Semi-infinite
|
|
55
|
-
| `qagil` | Semi-infinite
|
|
56
|
-
| `qawc` | Finite
|
|
57
|
-
| `qaws` | Finite
|
|
58
|
-
| `qawo` | Finite
|
|
59
|
-
| `qawf` | Semi-infinite
|
|
60
|
-
| `cquad` | Finite
|
|
61
|
-
| `romberg` | Finite
|
|
62
|
-
| `glfixed` | Finite
|
|
47
|
+
| Method | Interval | Intended use |
|
|
48
|
+
| --------- | -------------- | ---------------------------------------------------------------- |
|
|
49
|
+
| `qng` | Finite | Non-adaptive integration of smooth functions |
|
|
50
|
+
| `qag` | Finite | General-purpose adaptive integration |
|
|
51
|
+
| `qags` | Finite | Functions with integrable singularities or discontinuities |
|
|
52
|
+
| `qagp` | Finite | Known singular or discontinuity points |
|
|
53
|
+
| `qagi` | Infinite | Integration over the entire real line |
|
|
54
|
+
| `qagiu` | Semi-infinite | Integration from a finite lower bound to positive infinity |
|
|
55
|
+
| `qagil` | Semi-infinite | Integration from negative infinity to a finite upper bound |
|
|
56
|
+
| `qawc` | Finite | Cauchy principal value with a known singular point |
|
|
57
|
+
| `qaws` | Finite | Algebraic and logarithmic endpoint singularities |
|
|
58
|
+
| `qawo` | Finite | Sine- or cosine-weighted oscillatory integrals |
|
|
59
|
+
| `qawf` | Semi-infinite | Sine- or cosine-weighted Fourier integrals |
|
|
60
|
+
| `cquad` | Finite | Difficult integrands and endpoint singularities |
|
|
61
|
+
| `romberg` | Finite | Smooth functions with extrapolated trapezoidal integration |
|
|
62
|
+
| `glfixed` | Finite | Fixed-order Gauss-Legendre integration of smooth functions |
|
|
63
|
+
| `fixed` | Rule-dependent | Fixed-order Gaussian quadrature with selectable weight functions |
|
|
63
64
|
|
|
64
65
|
See [Integration routines](docs/routines.md) for parameters and examples.
|
|
65
66
|
|
data/docs/routines.md
CHANGED
|
@@ -94,7 +94,7 @@ result, error = Numo::GSL::Integration.qagp(
|
|
|
94
94
|
end
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
The points must be finite numeric values in strictly increasing order. The array must contain at least two values. A non-array argument or a non-numeric element raises `TypeError`. Too few points, non-finite values, or values that are not strictly increasing raise `ArgumentError` before GSL is called.
|
|
97
|
+
The points must be finite numeric values in strictly increasing order. The array must contain at least two values. A non-array argument or a non-numeric element raises `TypeError`. Too few points, non-finite values, or values that are not strictly increasing raise `ArgumentError` before GSL is called.
|
|
98
98
|
The `epsabs`, `epsrel`, and `limit` keyword arguments control the requested error limits and maximum number of subintervals:
|
|
99
99
|
|
|
100
100
|
```ruby
|
|
@@ -181,17 +181,17 @@ end
|
|
|
181
181
|
GSL [QAWC](https://www.gnu.org/software/gsl/doc/html/integration.html#qawc-adaptive-integration-for-cauchy-principal-values) computes the Cauchy principal value (PV) of an integral over a finite interval with a singularity at $c$:
|
|
182
182
|
|
|
183
183
|
```math
|
|
184
|
-
PV
|
|
184
|
+
PV \\int_a^b \\frac{f(x)}{x-c}\\,dx
|
|
185
185
|
=
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
\\lim_{\\varepsilon\\to 0^+}
|
|
187
|
+
\\left(
|
|
188
|
+
\\int_a^{c-\\varepsilon}\\frac{f(x)}{x-c}\\,dx
|
|
189
|
+
\+
|
|
190
|
+
\\int_{c+\\varepsilon}^b\\frac{f(x)}{x-c}\\,dx
|
|
191
|
+
\\right)
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
-
The block passed to `Numo::GSL::Integration.qawc` returns $f(x)$. Do not divide the block result by $x - c$; QAWC applies that weight internally.
|
|
194
|
+
The block passed to `Numo::GSL::Integration.qawc` returns $f(x)$. Do not divide the block result by $x - c$; QAWC applies that weight internally.
|
|
195
195
|
The following example uses the default integration options and computes the principal value of `x / (x - 1.0)` over the interval from `0.0` to `2.0`, whose exact value is `2.0`:
|
|
196
196
|
|
|
197
197
|
```ruby
|
|
@@ -220,15 +220,15 @@ end
|
|
|
220
220
|
GSL [QAWS](https://www.gnu.org/software/gsl/doc/html/integration.html#qaws-adaptive-integration-for-singular-functions) provides adaptive integration for functions with algebraic or logarithmic singularities at the endpoints of a finite interval. It computes an integral with the weight
|
|
221
221
|
|
|
222
222
|
```math
|
|
223
|
-
(x-a)
|
|
224
|
-
|
|
223
|
+
(x-a)^\\alpha (b-x)^\\beta
|
|
224
|
+
\\log^\\mu(x-a) \\log^\\nu(b-x).
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
-
Call `Numo::GSL::Integration.qaws` with the endpoints `a` and `b`, followed by `alpha`, `beta`, `mu`, and `nu`. The exponents `alpha` and `beta` must be greater than `-1.0`. The logarithmic powers `mu` and `nu` must each be `0` or `1`.
|
|
227
|
+
Call `Numo::GSL::Integration.qaws` with the endpoints `a` and `b`, followed by `alpha`, `beta`, `mu`, and `nu`. The exponents `alpha` and `beta` must be greater than `-1.0`. The logarithmic powers `mu` and `nu` must each be `0` or `1`.
|
|
228
228
|
The block returns the unweighted function $f(x)$. QAWS applies the endpoint weight internally. The following example integrates
|
|
229
229
|
|
|
230
230
|
```math
|
|
231
|
-
|
|
231
|
+
\\frac{1}{\\sqrt{x(1-x)}}
|
|
232
232
|
```
|
|
233
233
|
|
|
234
234
|
over the interval from `0.0` to `1.0`. Its exact value is `Math::PI`:
|
|
@@ -321,12 +321,12 @@ result, evaluations = Numo::GSL::Integration.romberg(0.0, Math::PI) do |x|
|
|
|
321
321
|
end
|
|
322
322
|
```
|
|
323
323
|
|
|
324
|
-
The example integral has an exact value of `2.0`. The `epsabs` and `epsrel` keyword arguments control the requested error limits. The `limit` keyword controls the maximum number of Romberg levels and defaults to `20`. GSL requires at least one level and limits the effective workspace to 30 levels.
|
|
324
|
+
The example integral has an exact value of `2.0`. The `epsabs` and `epsrel` keyword arguments control the requested error limits. The `limit` keyword controls the maximum number of Romberg levels and defaults to `20`. GSL requires at least one level and limits the effective workspace to 30 levels.
|
|
325
325
|
Romberg integration does not return an estimated absolute error. Use CQUAD, QAG, QAGS, or another routine that returns an error estimate when the caller needs one.
|
|
326
326
|
|
|
327
327
|
## GLFIXED integration
|
|
328
328
|
|
|
329
|
-
GSL [fixed-order Gauss
|
|
329
|
+
GSL [fixed-order Gauss-Legendre integration](https://www.gnu.org/software/gsl/doc/html/integration.html#gauss-legendre-integration) provides fast integration of smooth functions when an appropriate polynomial order is known. An `n`-point rule integrates polynomials of degree `2 * n - 1` or less exactly, subject to floating-point precision.
|
|
330
330
|
|
|
331
331
|
```ruby
|
|
332
332
|
result = Numo::GSL::Integration.glfixed(
|
|
@@ -338,5 +338,55 @@ result = Numo::GSL::Integration.glfixed(
|
|
|
338
338
|
end
|
|
339
339
|
```
|
|
340
340
|
|
|
341
|
-
The example integral has an exact value of `1.0 / 5.0`. The `order` keyword controls the number of Gauss
|
|
341
|
+
The example integral has an exact value of `1.0 / 5.0`. The `order` keyword controls the number of Gauss-Legendre points and defaults to `10`. It must be a positive integer.
|
|
342
342
|
GLFIXED returns only the integral. It does not accept absolute or relative error bounds and does not return an error estimate. Use an adaptive routine when the required fixed order is not known in advance.
|
|
343
|
+
|
|
344
|
+
## Fixed point quadratures
|
|
345
|
+
|
|
346
|
+
GSL [fixed point quadratures](https://www.gnu.org/software/gsl/doc/html/integration.html#fixed-point-quadratures) provide fixed-order Gaussian quadrature rules for several weight functions. `Numo::GSL::Integration.fixed` takes a quadrature type, the number of points, and the GSL rule parameters:
|
|
347
|
+
|
|
348
|
+
```ruby
|
|
349
|
+
result = Numo::GSL::Integration.fixed(
|
|
350
|
+
:legendre,
|
|
351
|
+
order: 3,
|
|
352
|
+
a: 0.0,
|
|
353
|
+
b: 1.0
|
|
354
|
+
) do |x|
|
|
355
|
+
x ** 4
|
|
356
|
+
end
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
The example has an exact value of `1.0 / 5.0`. The block returns the unweighted function. For weighted rules, GSL applies the selected weight internally.
|
|
360
|
+
|
|
361
|
+
The supported types and required keyword arguments are:
|
|
362
|
+
|
|
363
|
+
| Type | Required rule parameters | Description |
|
|
364
|
+
| -------------- | ------------------------ | ------------------------------------------------------------ |
|
|
365
|
+
| `:legendre` | — | Gauss-Legendre rule over the finite interval from `a` to `b` |
|
|
366
|
+
| `:chebyshev` | — | First-kind Chebyshev rule over the finite interval |
|
|
367
|
+
| `:chebyshev2` | — | Second-kind Chebyshev rule over the finite interval |
|
|
368
|
+
| `:gegenbauer` | `alpha` | Gegenbauer rule |
|
|
369
|
+
| `:jacobi` | `alpha`, `beta` | Jacobi rule |
|
|
370
|
+
| `:laguerre` | `alpha` | Generalized Laguerre rule |
|
|
371
|
+
| `:hermite` | `alpha` | Generalized Hermite rule |
|
|
372
|
+
| `:exponential` | `alpha` | Exponential rule over a finite interval |
|
|
373
|
+
| `:rational` | `alpha`, `beta` | Rational rule |
|
|
374
|
+
|
|
375
|
+
`order` must be a positive integer. The keywords `a` and `b` are required for every type because they are passed to `gsl_integration_fixed_alloc`; their exact role and valid range depend on the selected GSL rule. The `alpha` and `beta` values must also satisfy the constraints imposed by that rule. Invalid numerical parameters are reported as `Numo::GSL::GslError` by GSL.
|
|
376
|
+
|
|
377
|
+
The following example uses the rational rule. Its parameters satisfy the rule's order-dependent constraints for `order: 3`:
|
|
378
|
+
|
|
379
|
+
```ruby
|
|
380
|
+
result = Numo::GSL::Integration.fixed(
|
|
381
|
+
:rational,
|
|
382
|
+
order: 3,
|
|
383
|
+
a: 0.0,
|
|
384
|
+
b: 1.0,
|
|
385
|
+
alpha: 0.0,
|
|
386
|
+
beta: -7.0
|
|
387
|
+
) do |_x|
|
|
388
|
+
1.0
|
|
389
|
+
end
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
The example result is `1.0 / 6.0`. Fixed point quadratures return only the integral. They do not accept absolute or relative error bounds and do not return an error estimate. Use an adaptive routine when the required order is not known in advance.
|
|
@@ -1,44 +1,59 @@
|
|
|
1
1
|
#include "integration_internal.h"
|
|
2
|
+
|
|
2
3
|
static VALUE integration_call_block(VALUE data) {
|
|
3
4
|
integration_callback_params *params = (integration_callback_params *)data;
|
|
4
5
|
VALUE value;
|
|
6
|
+
|
|
5
7
|
value = rb_funcall(params->block, rb_intern("call"), 1, params->x);
|
|
8
|
+
|
|
6
9
|
return rb_Float(value);
|
|
7
10
|
}
|
|
11
|
+
|
|
8
12
|
void integration_callback_params_init(integration_callback_params *params) {
|
|
9
13
|
params->block = rb_block_proc();
|
|
10
14
|
params->x = Qnil;
|
|
11
15
|
params->exception = Qnil;
|
|
12
16
|
params->state = 0;
|
|
13
17
|
}
|
|
18
|
+
|
|
14
19
|
void integration_function_init(gsl_function *function,
|
|
15
20
|
integration_callback_params *params) {
|
|
16
21
|
integration_callback_params_init(params);
|
|
22
|
+
|
|
17
23
|
function->function = integration_callback;
|
|
18
24
|
function->params = params;
|
|
19
25
|
}
|
|
26
|
+
|
|
20
27
|
double integration_callback(double x, void *data) {
|
|
21
28
|
integration_callback_params *params = data;
|
|
22
29
|
VALUE value;
|
|
30
|
+
|
|
23
31
|
if (params->state != 0) {
|
|
24
32
|
return 0.0;
|
|
25
33
|
}
|
|
34
|
+
|
|
26
35
|
params->x = DBL2NUM(x);
|
|
36
|
+
|
|
27
37
|
value = rb_protect(integration_call_block, (VALUE)params, ¶ms->state);
|
|
38
|
+
|
|
28
39
|
if (params->state != 0) {
|
|
29
40
|
params->exception = rb_errinfo();
|
|
30
41
|
return 0.0;
|
|
31
42
|
}
|
|
43
|
+
|
|
32
44
|
return NUM2DBL(value);
|
|
33
45
|
}
|
|
46
|
+
|
|
34
47
|
void integration_raise_callback_exception(integration_callback_params *params) {
|
|
35
48
|
if (params->state != 0) {
|
|
36
49
|
rb_exc_raise(params->exception);
|
|
37
50
|
}
|
|
38
51
|
}
|
|
52
|
+
|
|
39
53
|
void integration_finish_callback(integration_callback_params *params,
|
|
40
54
|
int state) {
|
|
41
55
|
integration_raise_callback_exception(params);
|
|
56
|
+
|
|
42
57
|
if (state != 0) {
|
|
43
58
|
rb_jump_tag(state);
|
|
44
59
|
}
|
|
@@ -52,6 +52,7 @@ VALUE integration_cquad(int argc, VALUE *argv, VALUE self) {
|
|
|
52
52
|
rb_scan_args(argc, argv, "2:", &a, &b, &options);
|
|
53
53
|
|
|
54
54
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 100);
|
|
55
|
+
|
|
55
56
|
epsabs = parsed_options.epsabs;
|
|
56
57
|
epsrel = parsed_options.epsrel;
|
|
57
58
|
limit = parsed_options.limit;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#include "integration_internal.h"
|
|
2
|
+
typedef struct {
|
|
3
|
+
gsl_function *function;
|
|
4
|
+
const gsl_integration_fixed_type *type;
|
|
5
|
+
size_t order;
|
|
6
|
+
double a;
|
|
7
|
+
double b;
|
|
8
|
+
double alpha;
|
|
9
|
+
double beta;
|
|
10
|
+
gsl_integration_fixed_workspace *workspace;
|
|
11
|
+
double *result;
|
|
12
|
+
} integration_fixed_params;
|
|
13
|
+
static const gsl_integration_fixed_type *integration_fixed_type(VALUE type) {
|
|
14
|
+
ID type_id;
|
|
15
|
+
if (!RB_TYPE_P(type, T_SYMBOL)) {
|
|
16
|
+
rb_raise(rb_eTypeError, "type must be a Symbol");
|
|
17
|
+
}
|
|
18
|
+
type_id = SYM2ID(type);
|
|
19
|
+
if (type_id == rb_intern("legendre")) {
|
|
20
|
+
return gsl_integration_fixed_legendre;
|
|
21
|
+
}
|
|
22
|
+
if (type_id == rb_intern("chebyshev")) {
|
|
23
|
+
return gsl_integration_fixed_chebyshev;
|
|
24
|
+
}
|
|
25
|
+
if (type_id == rb_intern("chebyshev2")) {
|
|
26
|
+
return gsl_integration_fixed_chebyshev2;
|
|
27
|
+
}
|
|
28
|
+
if (type_id == rb_intern("gegenbauer")) {
|
|
29
|
+
return gsl_integration_fixed_gegenbauer;
|
|
30
|
+
}
|
|
31
|
+
if (type_id == rb_intern("jacobi")) {
|
|
32
|
+
return gsl_integration_fixed_jacobi;
|
|
33
|
+
}
|
|
34
|
+
if (type_id == rb_intern("laguerre")) {
|
|
35
|
+
return gsl_integration_fixed_laguerre;
|
|
36
|
+
}
|
|
37
|
+
if (type_id == rb_intern("hermite")) {
|
|
38
|
+
return gsl_integration_fixed_hermite;
|
|
39
|
+
}
|
|
40
|
+
if (type_id == rb_intern("exponential")) {
|
|
41
|
+
return gsl_integration_fixed_exponential;
|
|
42
|
+
}
|
|
43
|
+
if (type_id == rb_intern("rational")) {
|
|
44
|
+
return gsl_integration_fixed_rational;
|
|
45
|
+
}
|
|
46
|
+
rb_raise(rb_eArgError, "unsupported fixed quadrature type: %s",
|
|
47
|
+
rb_id2name(type_id));
|
|
48
|
+
}
|
|
49
|
+
static VALUE integration_free_fixed_workspace(VALUE data) {
|
|
50
|
+
integration_fixed_params *params = (integration_fixed_params *)data;
|
|
51
|
+
if (params->workspace != NULL) {
|
|
52
|
+
gsl_integration_fixed_free(params->workspace);
|
|
53
|
+
}
|
|
54
|
+
return Qnil;
|
|
55
|
+
}
|
|
56
|
+
static VALUE integration_run_fixed(VALUE data) {
|
|
57
|
+
integration_fixed_params *params = (integration_fixed_params *)data;
|
|
58
|
+
params->workspace =
|
|
59
|
+
gsl_integration_fixed_alloc(params->type, params->order, params->a,
|
|
60
|
+
params->b, params->alpha, params->beta);
|
|
61
|
+
if (params->workspace == NULL) {
|
|
62
|
+
rb_memerror();
|
|
63
|
+
}
|
|
64
|
+
(void)gsl_integration_fixed(params->function, params->result,
|
|
65
|
+
params->workspace);
|
|
66
|
+
return Qnil;
|
|
67
|
+
}
|
|
68
|
+
static VALUE integration_run_fixed_with_workspace(VALUE data) {
|
|
69
|
+
return rb_ensure(integration_run_fixed, data,
|
|
70
|
+
integration_free_fixed_workspace, data);
|
|
71
|
+
}
|
|
72
|
+
VALUE integration_fixed(int argc, VALUE *argv, VALUE self) {
|
|
73
|
+
VALUE type;
|
|
74
|
+
VALUE options;
|
|
75
|
+
ID keywords[] = {rb_intern("order"), rb_intern("a"), rb_intern("b"),
|
|
76
|
+
rb_intern("alpha"), rb_intern("beta")};
|
|
77
|
+
VALUE keyword_values[5];
|
|
78
|
+
VALUE order_value;
|
|
79
|
+
VALUE alpha_value;
|
|
80
|
+
VALUE beta_value;
|
|
81
|
+
size_t order;
|
|
82
|
+
gsl_function function;
|
|
83
|
+
integration_callback_params params;
|
|
84
|
+
integration_fixed_params fixed_params;
|
|
85
|
+
double result;
|
|
86
|
+
int state = 0;
|
|
87
|
+
(void)self;
|
|
88
|
+
rb_scan_args(argc, argv, "1:", &type, &options);
|
|
89
|
+
fixed_params.type = integration_fixed_type(type);
|
|
90
|
+
if (NIL_P(options)) {
|
|
91
|
+
options = rb_hash_new();
|
|
92
|
+
}
|
|
93
|
+
rb_get_kwargs(options, keywords, 3, 2, keyword_values);
|
|
94
|
+
order_value = keyword_values[0];
|
|
95
|
+
alpha_value = keyword_values[3];
|
|
96
|
+
beta_value = keyword_values[4];
|
|
97
|
+
if (!RB_INTEGER_TYPE_P(order_value)) {
|
|
98
|
+
rb_raise(rb_eTypeError, "order must be an Integer");
|
|
99
|
+
}
|
|
100
|
+
if (RTEST(rb_funcall(order_value, rb_intern("<="), 1, INT2FIX(0)))) {
|
|
101
|
+
rb_raise(rb_eArgError, "order must be positive");
|
|
102
|
+
}
|
|
103
|
+
order = NUM2SIZET(order_value);
|
|
104
|
+
integration_function_init(&function, ¶ms);
|
|
105
|
+
fixed_params.function = &function;
|
|
106
|
+
fixed_params.order = order;
|
|
107
|
+
fixed_params.a = NUM2DBL(keyword_values[1]);
|
|
108
|
+
fixed_params.b = NUM2DBL(keyword_values[2]);
|
|
109
|
+
if (fixed_params.type == gsl_integration_fixed_gegenbauer) {
|
|
110
|
+
if (alpha_value == Qundef) {
|
|
111
|
+
rb_raise(rb_eArgError, "alpha is required for gegenbauer");
|
|
112
|
+
}
|
|
113
|
+
fixed_params.alpha = NUM2DBL(alpha_value);
|
|
114
|
+
fixed_params.beta = 0.0;
|
|
115
|
+
} else if (fixed_params.type == gsl_integration_fixed_jacobi) {
|
|
116
|
+
if (alpha_value == Qundef) {
|
|
117
|
+
rb_raise(rb_eArgError, "alpha is required for jacobi");
|
|
118
|
+
}
|
|
119
|
+
if (beta_value == Qundef) {
|
|
120
|
+
rb_raise(rb_eArgError, "beta is required for jacobi");
|
|
121
|
+
}
|
|
122
|
+
fixed_params.alpha = NUM2DBL(alpha_value);
|
|
123
|
+
fixed_params.beta = NUM2DBL(beta_value);
|
|
124
|
+
} else if (fixed_params.type == gsl_integration_fixed_laguerre) {
|
|
125
|
+
if (alpha_value == Qundef) {
|
|
126
|
+
rb_raise(rb_eArgError, "alpha is required for laguerre");
|
|
127
|
+
}
|
|
128
|
+
fixed_params.alpha = NUM2DBL(alpha_value);
|
|
129
|
+
fixed_params.beta = 0.0;
|
|
130
|
+
} else if (fixed_params.type == gsl_integration_fixed_hermite) {
|
|
131
|
+
if (alpha_value == Qundef) {
|
|
132
|
+
rb_raise(rb_eArgError, "alpha is required for hermite");
|
|
133
|
+
}
|
|
134
|
+
fixed_params.alpha = NUM2DBL(alpha_value);
|
|
135
|
+
fixed_params.beta = 0.0;
|
|
136
|
+
} else if (fixed_params.type == gsl_integration_fixed_exponential) {
|
|
137
|
+
if (alpha_value == Qundef) {
|
|
138
|
+
rb_raise(rb_eArgError, "alpha is required for exponential");
|
|
139
|
+
}
|
|
140
|
+
fixed_params.alpha = NUM2DBL(alpha_value);
|
|
141
|
+
fixed_params.beta = 0.0;
|
|
142
|
+
} else if (fixed_params.type == gsl_integration_fixed_rational) {
|
|
143
|
+
if (alpha_value == Qundef) {
|
|
144
|
+
rb_raise(rb_eArgError, "alpha is required for rational");
|
|
145
|
+
}
|
|
146
|
+
if (beta_value == Qundef) {
|
|
147
|
+
rb_raise(rb_eArgError, "beta is required for rational");
|
|
148
|
+
}
|
|
149
|
+
fixed_params.alpha = NUM2DBL(alpha_value);
|
|
150
|
+
fixed_params.beta = NUM2DBL(beta_value);
|
|
151
|
+
} else {
|
|
152
|
+
fixed_params.alpha = 0.0;
|
|
153
|
+
fixed_params.beta = 0.0;
|
|
154
|
+
}
|
|
155
|
+
fixed_params.workspace = NULL;
|
|
156
|
+
fixed_params.result = &result;
|
|
157
|
+
rb_protect(integration_run_fixed_with_workspace, (VALUE)&fixed_params,
|
|
158
|
+
&state);
|
|
159
|
+
RB_GC_GUARD(params.block);
|
|
160
|
+
RB_GC_GUARD(params.exception);
|
|
161
|
+
integration_finish_callback(¶ms, state);
|
|
162
|
+
return DBL2NUM(result);
|
|
163
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "integration_internal.h"
|
|
2
|
+
|
|
2
3
|
typedef struct {
|
|
3
4
|
gsl_function *function;
|
|
4
5
|
double a;
|
|
@@ -7,17 +8,23 @@ typedef struct {
|
|
|
7
8
|
gsl_integration_glfixed_table *table;
|
|
8
9
|
double *result;
|
|
9
10
|
} integration_glfixed_params;
|
|
11
|
+
|
|
10
12
|
static VALUE integration_run_glfixed(VALUE data) {
|
|
11
13
|
integration_glfixed_params *params = (integration_glfixed_params *)data;
|
|
14
|
+
|
|
12
15
|
*(params->result) = gsl_integration_glfixed(params->function, params->a,
|
|
13
16
|
params->b, params->table);
|
|
17
|
+
|
|
14
18
|
return Qnil;
|
|
15
19
|
}
|
|
20
|
+
|
|
16
21
|
static VALUE integration_run_glfixed_with_table(VALUE data) {
|
|
17
22
|
integration_glfixed_params *params = (integration_glfixed_params *)data;
|
|
23
|
+
|
|
18
24
|
return rb_ensure(integration_run_glfixed, data,
|
|
19
25
|
integration_free_glfixed_table, (VALUE)params->table);
|
|
20
26
|
}
|
|
27
|
+
|
|
21
28
|
VALUE integration_glfixed(int argc, VALUE *argv, VALUE self) {
|
|
22
29
|
VALUE a;
|
|
23
30
|
VALUE b;
|
|
@@ -31,34 +38,48 @@ VALUE integration_glfixed(int argc, VALUE *argv, VALUE self) {
|
|
|
31
38
|
integration_glfixed_params glfixed_params;
|
|
32
39
|
double result;
|
|
33
40
|
int state = 0;
|
|
41
|
+
|
|
34
42
|
(void)self;
|
|
43
|
+
|
|
35
44
|
rb_scan_args(argc, argv, "2:", &a, &b, &options);
|
|
45
|
+
|
|
36
46
|
if (!NIL_P(options)) {
|
|
37
47
|
rb_get_kwargs(options, keywords, 0, 1, keyword_values);
|
|
38
48
|
order_value = keyword_values[0];
|
|
39
49
|
}
|
|
50
|
+
|
|
40
51
|
if (order_value == Qundef) {
|
|
41
52
|
order = 10;
|
|
42
53
|
} else {
|
|
43
54
|
if (!RB_INTEGER_TYPE_P(order_value)) {
|
|
44
55
|
rb_raise(rb_eTypeError, "order must be an Integer");
|
|
45
56
|
}
|
|
57
|
+
|
|
46
58
|
if (RTEST(rb_funcall(order_value, rb_intern("<="), 1, INT2FIX(0)))) {
|
|
47
59
|
rb_raise(rb_eArgError, "order must be positive");
|
|
48
60
|
}
|
|
61
|
+
|
|
49
62
|
order = NUM2SIZET(order_value);
|
|
50
63
|
}
|
|
64
|
+
|
|
51
65
|
integration_function_init(&function, ¶ms);
|
|
66
|
+
|
|
52
67
|
glfixed_params.function = &function;
|
|
53
68
|
glfixed_params.a = NUM2DBL(a);
|
|
54
69
|
glfixed_params.b = NUM2DBL(b);
|
|
55
70
|
glfixed_params.order = order;
|
|
71
|
+
|
|
56
72
|
glfixed_params.table = gsl_integration_glfixed_table_alloc(order);
|
|
73
|
+
|
|
57
74
|
glfixed_params.result = &result;
|
|
75
|
+
|
|
58
76
|
rb_protect(integration_run_glfixed_with_table, (VALUE)&glfixed_params,
|
|
59
77
|
&state);
|
|
78
|
+
|
|
60
79
|
RB_GC_GUARD(params.block);
|
|
61
80
|
RB_GC_GUARD(params.exception);
|
|
81
|
+
|
|
62
82
|
integration_finish_callback(¶ms, state);
|
|
83
|
+
|
|
63
84
|
return DBL2NUM(result);
|
|
64
85
|
}
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
#include "integration_internal.h"
|
|
2
|
+
|
|
2
3
|
static VALUE numo_eGslError;
|
|
4
|
+
|
|
3
5
|
static _Noreturn void integration_gsl_error_handler(const char *reason,
|
|
4
6
|
const char *file, int line,
|
|
5
7
|
int gsl_errno) {
|
|
6
8
|
rb_raise(numo_eGslError, "%s:%d: %s (GSL error %d)", file, line, reason,
|
|
7
9
|
gsl_errno);
|
|
8
10
|
}
|
|
11
|
+
|
|
9
12
|
void Init_integration(void) {
|
|
10
13
|
VALUE mNumo;
|
|
11
14
|
VALUE mGSL;
|
|
12
15
|
VALUE mIntegration;
|
|
16
|
+
|
|
13
17
|
mNumo = rb_define_module("Numo");
|
|
14
18
|
mGSL = rb_define_module_under(mNumo, "GSL");
|
|
15
19
|
mIntegration = rb_define_module_under(mGSL, "Integration");
|
|
16
20
|
numo_eGslError = rb_define_class_under(mGSL, "GslError", rb_eStandardError);
|
|
17
21
|
gsl_set_error_handler(&integration_gsl_error_handler);
|
|
22
|
+
|
|
18
23
|
rb_define_const(mIntegration, "GAUSS15", INT2NUM(GSL_INTEG_GAUSS15));
|
|
19
24
|
rb_define_const(mIntegration, "GAUSS21", INT2NUM(GSL_INTEG_GAUSS21));
|
|
20
25
|
rb_define_const(mIntegration, "GAUSS31", INT2NUM(GSL_INTEG_GAUSS31));
|
|
@@ -23,6 +28,7 @@ void Init_integration(void) {
|
|
|
23
28
|
rb_define_const(mIntegration, "GAUSS61", INT2NUM(GSL_INTEG_GAUSS61));
|
|
24
29
|
rb_define_const(mIntegration, "COSINE", INT2NUM(GSL_INTEG_COSINE));
|
|
25
30
|
rb_define_const(mIntegration, "SINE", INT2NUM(GSL_INTEG_SINE));
|
|
31
|
+
|
|
26
32
|
rb_define_singleton_method(mIntegration, "qag", integration_qag, -1);
|
|
27
33
|
rb_define_singleton_method(mIntegration, "qng", integration_qng, -1);
|
|
28
34
|
rb_define_singleton_method(mIntegration, "qags", integration_qags, -1);
|
|
@@ -37,4 +43,5 @@ void Init_integration(void) {
|
|
|
37
43
|
rb_define_singleton_method(mIntegration, "cquad", integration_cquad, -1);
|
|
38
44
|
rb_define_singleton_method(mIntegration, "romberg", integration_romberg, -1);
|
|
39
45
|
rb_define_singleton_method(mIntegration, "glfixed", integration_glfixed, -1);
|
|
46
|
+
rb_define_singleton_method(mIntegration, "fixed", integration_fixed, -1);
|
|
40
47
|
}
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
#ifndef NUMO_GSL_INTEGRATION_INTERNAL_H
|
|
2
2
|
#define NUMO_GSL_INTEGRATION_INTERNAL_H
|
|
3
|
+
|
|
3
4
|
#include <gsl/gsl_errno.h>
|
|
4
5
|
#include <gsl/gsl_integration.h>
|
|
5
6
|
#include <ruby.h>
|
|
7
|
+
|
|
6
8
|
typedef struct {
|
|
7
9
|
double epsabs;
|
|
8
10
|
double epsrel;
|
|
9
11
|
size_t limit;
|
|
10
12
|
} integration_options;
|
|
13
|
+
|
|
11
14
|
void integration_options_parse(VALUE options, integration_options *parsed,
|
|
12
15
|
double default_epsabs, double default_epsrel,
|
|
13
16
|
size_t default_limit);
|
|
17
|
+
|
|
14
18
|
typedef struct {
|
|
15
19
|
VALUE block;
|
|
16
20
|
VALUE x;
|
|
17
21
|
VALUE exception;
|
|
18
22
|
int state;
|
|
19
23
|
} integration_callback_params;
|
|
24
|
+
|
|
20
25
|
void integration_callback_params_init(integration_callback_params *params);
|
|
21
26
|
void integration_function_init(gsl_function *function,
|
|
22
27
|
integration_callback_params *params);
|
|
@@ -24,10 +29,12 @@ double integration_callback(double x, void *data);
|
|
|
24
29
|
void integration_raise_callback_exception(integration_callback_params *params);
|
|
25
30
|
void integration_finish_callback(integration_callback_params *params,
|
|
26
31
|
int state);
|
|
32
|
+
|
|
27
33
|
VALUE integration_free_workspace(VALUE data);
|
|
28
34
|
VALUE integration_free_cquad_workspace(VALUE data);
|
|
29
35
|
VALUE integration_free_romberg_workspace(VALUE data);
|
|
30
36
|
VALUE integration_free_glfixed_table(VALUE data);
|
|
37
|
+
|
|
31
38
|
VALUE integration_qag(int argc, VALUE *argv, VALUE self);
|
|
32
39
|
VALUE integration_qng(int argc, VALUE *argv, VALUE self);
|
|
33
40
|
VALUE integration_qags(int argc, VALUE *argv, VALUE self);
|
|
@@ -42,4 +49,6 @@ VALUE integration_qawf(int argc, VALUE *argv, VALUE self);
|
|
|
42
49
|
VALUE integration_cquad(int argc, VALUE *argv, VALUE self);
|
|
43
50
|
VALUE integration_romberg(int argc, VALUE *argv, VALUE self);
|
|
44
51
|
VALUE integration_glfixed(int argc, VALUE *argv, VALUE self);
|
|
52
|
+
VALUE integration_fixed(int argc, VALUE *argv, VALUE self);
|
|
53
|
+
|
|
45
54
|
#endif
|
|
@@ -46,6 +46,7 @@ VALUE integration_qagi(int argc, VALUE *argv, VALUE self) {
|
|
|
46
46
|
rb_scan_args(argc, argv, "0:", &options);
|
|
47
47
|
|
|
48
48
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
49
|
+
|
|
49
50
|
epsabs = parsed_options.epsabs;
|
|
50
51
|
epsrel = parsed_options.epsrel;
|
|
51
52
|
limit = parsed_options.limit;
|
|
@@ -13,14 +13,17 @@ typedef struct {
|
|
|
13
13
|
|
|
14
14
|
static VALUE integration_run_qagil(VALUE data) {
|
|
15
15
|
integration_qagil_params *params = (integration_qagil_params *)data;
|
|
16
|
+
|
|
16
17
|
(void)gsl_integration_qagil(params->function, params->b, params->epsabs,
|
|
17
18
|
params->epsrel, params->limit, params->workspace,
|
|
18
19
|
params->result, params->error);
|
|
20
|
+
|
|
19
21
|
return Qnil;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
static VALUE integration_run_qagil_with_workspace(VALUE data) {
|
|
23
25
|
integration_qagil_params *params = (integration_qagil_params *)data;
|
|
26
|
+
|
|
24
27
|
return rb_ensure(integration_run_qagil, data, integration_free_workspace,
|
|
25
28
|
(VALUE)params->workspace);
|
|
26
29
|
}
|
|
@@ -39,11 +42,13 @@ VALUE integration_qagil(int argc, VALUE *argv, VALUE self) {
|
|
|
39
42
|
double result;
|
|
40
43
|
double error;
|
|
41
44
|
int state = 0;
|
|
45
|
+
|
|
42
46
|
(void)self;
|
|
43
47
|
|
|
44
48
|
rb_scan_args(argc, argv, "1:", &b, &options);
|
|
45
49
|
|
|
46
50
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
51
|
+
|
|
47
52
|
epsabs = parsed_options.epsabs;
|
|
48
53
|
epsrel = parsed_options.epsrel;
|
|
49
54
|
limit = parsed_options.limit;
|
|
@@ -51,6 +56,7 @@ VALUE integration_qagil(int argc, VALUE *argv, VALUE self) {
|
|
|
51
56
|
integration_function_init(&function, ¶ms);
|
|
52
57
|
|
|
53
58
|
workspace = gsl_integration_workspace_alloc(limit);
|
|
59
|
+
|
|
54
60
|
qagil_params.function = &function;
|
|
55
61
|
qagil_params.b = NUM2DBL(b);
|
|
56
62
|
qagil_params.epsabs = epsabs;
|
|
@@ -62,8 +68,10 @@ VALUE integration_qagil(int argc, VALUE *argv, VALUE self) {
|
|
|
62
68
|
|
|
63
69
|
rb_protect(integration_run_qagil_with_workspace, (VALUE)&qagil_params,
|
|
64
70
|
&state);
|
|
71
|
+
|
|
65
72
|
RB_GC_GUARD(params.block);
|
|
66
73
|
RB_GC_GUARD(params.exception);
|
|
74
|
+
|
|
67
75
|
integration_finish_callback(¶ms, state);
|
|
68
76
|
|
|
69
77
|
return rb_ary_new_from_args(2, DBL2NUM(result), DBL2NUM(error));
|
|
@@ -13,14 +13,17 @@ typedef struct {
|
|
|
13
13
|
|
|
14
14
|
static VALUE integration_run_qagiu(VALUE data) {
|
|
15
15
|
integration_qagiu_params *params = (integration_qagiu_params *)data;
|
|
16
|
+
|
|
16
17
|
(void)gsl_integration_qagiu(params->function, params->a, params->epsabs,
|
|
17
18
|
params->epsrel, params->limit, params->workspace,
|
|
18
19
|
params->result, params->error);
|
|
20
|
+
|
|
19
21
|
return Qnil;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
static VALUE integration_run_qagiu_with_workspace(VALUE data) {
|
|
23
25
|
integration_qagiu_params *params = (integration_qagiu_params *)data;
|
|
26
|
+
|
|
24
27
|
return rb_ensure(integration_run_qagiu, data, integration_free_workspace,
|
|
25
28
|
(VALUE)params->workspace);
|
|
26
29
|
}
|
|
@@ -39,11 +42,13 @@ VALUE integration_qagiu(int argc, VALUE *argv, VALUE self) {
|
|
|
39
42
|
double result;
|
|
40
43
|
double error;
|
|
41
44
|
int state = 0;
|
|
45
|
+
|
|
42
46
|
(void)self;
|
|
43
47
|
|
|
44
48
|
rb_scan_args(argc, argv, "1:", &a, &options);
|
|
45
49
|
|
|
46
50
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
51
|
+
|
|
47
52
|
epsabs = parsed_options.epsabs;
|
|
48
53
|
epsrel = parsed_options.epsrel;
|
|
49
54
|
limit = parsed_options.limit;
|
|
@@ -51,6 +56,7 @@ VALUE integration_qagiu(int argc, VALUE *argv, VALUE self) {
|
|
|
51
56
|
integration_function_init(&function, ¶ms);
|
|
52
57
|
|
|
53
58
|
workspace = gsl_integration_workspace_alloc(limit);
|
|
59
|
+
|
|
54
60
|
qagiu_params.function = &function;
|
|
55
61
|
qagiu_params.a = NUM2DBL(a);
|
|
56
62
|
qagiu_params.epsabs = epsabs;
|
|
@@ -62,8 +68,10 @@ VALUE integration_qagiu(int argc, VALUE *argv, VALUE self) {
|
|
|
62
68
|
|
|
63
69
|
rb_protect(integration_run_qagiu_with_workspace, (VALUE)&qagiu_params,
|
|
64
70
|
&state);
|
|
71
|
+
|
|
65
72
|
RB_GC_GUARD(params.block);
|
|
66
73
|
RB_GC_GUARD(params.exception);
|
|
74
|
+
|
|
67
75
|
integration_finish_callback(¶ms, state);
|
|
68
76
|
|
|
69
77
|
return rb_ary_new_from_args(2, DBL2NUM(result), DBL2NUM(error));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "integration_internal.h"
|
|
2
2
|
#include <math.h>
|
|
3
|
+
|
|
3
4
|
typedef struct {
|
|
4
5
|
VALUE points_array;
|
|
5
6
|
gsl_function *function;
|
|
@@ -12,62 +13,84 @@ typedef struct {
|
|
|
12
13
|
double *result;
|
|
13
14
|
double *error;
|
|
14
15
|
} integration_qagp_params;
|
|
16
|
+
|
|
15
17
|
static void integration_validate_qagp_points(VALUE points) {
|
|
16
18
|
long point_count;
|
|
17
19
|
long index;
|
|
18
20
|
double previous = 0.0;
|
|
21
|
+
|
|
19
22
|
if (!RB_TYPE_P(points, T_ARRAY)) {
|
|
20
23
|
rb_raise(rb_eTypeError, "points must be an Array");
|
|
21
24
|
}
|
|
25
|
+
|
|
22
26
|
point_count = RARRAY_LEN(points);
|
|
27
|
+
|
|
23
28
|
if (point_count < 2) {
|
|
24
29
|
rb_raise(rb_eArgError, "points must contain at least two values");
|
|
25
30
|
}
|
|
31
|
+
|
|
26
32
|
for (index = 0; index < point_count; index++) {
|
|
27
33
|
VALUE point = rb_ary_entry(points, index);
|
|
28
34
|
double current;
|
|
35
|
+
|
|
29
36
|
if (!rb_obj_is_kind_of(point, rb_cNumeric)) {
|
|
30
37
|
rb_raise(rb_eTypeError, "points must contain only numeric values");
|
|
31
38
|
}
|
|
39
|
+
|
|
32
40
|
current = NUM2DBL(point);
|
|
41
|
+
|
|
33
42
|
if (!isfinite(current)) {
|
|
34
43
|
rb_raise(rb_eArgError, "points must contain only finite values");
|
|
35
44
|
}
|
|
45
|
+
|
|
36
46
|
if (index > 0 && !(previous < current)) {
|
|
37
47
|
rb_raise(rb_eArgError, "points must be strictly increasing");
|
|
38
48
|
}
|
|
49
|
+
|
|
39
50
|
previous = current;
|
|
40
51
|
}
|
|
41
52
|
}
|
|
53
|
+
|
|
42
54
|
static VALUE integration_run_qagp(VALUE data) {
|
|
43
55
|
integration_qagp_params *params = (integration_qagp_params *)data;
|
|
44
56
|
size_t index;
|
|
57
|
+
|
|
45
58
|
params->points = ALLOC_N(double, params->point_count);
|
|
59
|
+
|
|
46
60
|
for (index = 0; index < params->point_count; index++) {
|
|
47
61
|
params->points[index] =
|
|
48
62
|
NUM2DBL(rb_ary_entry(params->points_array, (long)index));
|
|
49
63
|
}
|
|
64
|
+
|
|
50
65
|
params->workspace = gsl_integration_workspace_alloc(params->limit);
|
|
66
|
+
|
|
51
67
|
(void)gsl_integration_qagp(params->function, params->points,
|
|
52
68
|
params->point_count, params->epsabs,
|
|
53
69
|
params->epsrel, params->limit, params->workspace,
|
|
54
70
|
params->result, params->error);
|
|
71
|
+
|
|
55
72
|
return Qnil;
|
|
56
73
|
}
|
|
74
|
+
|
|
57
75
|
static VALUE integration_free_qagp_resources(VALUE data) {
|
|
58
76
|
integration_qagp_params *params = (integration_qagp_params *)data;
|
|
77
|
+
|
|
59
78
|
if (params->workspace != NULL) {
|
|
60
79
|
gsl_integration_workspace_free(params->workspace);
|
|
61
80
|
}
|
|
81
|
+
|
|
62
82
|
if (params->points != NULL) {
|
|
63
83
|
xfree(params->points);
|
|
64
84
|
}
|
|
85
|
+
|
|
65
86
|
return Qnil;
|
|
66
87
|
}
|
|
88
|
+
|
|
67
89
|
static VALUE integration_run_qagp_with_resources(VALUE data) {
|
|
68
90
|
return rb_ensure(integration_run_qagp, data, integration_free_qagp_resources,
|
|
69
91
|
data);
|
|
70
92
|
}
|
|
93
|
+
|
|
71
94
|
VALUE integration_qagp(int argc, VALUE *argv, VALUE self) {
|
|
72
95
|
VALUE points;
|
|
73
96
|
VALUE options;
|
|
@@ -81,14 +104,21 @@ VALUE integration_qagp(int argc, VALUE *argv, VALUE self) {
|
|
|
81
104
|
double result;
|
|
82
105
|
double error;
|
|
83
106
|
int state = 0;
|
|
107
|
+
|
|
84
108
|
(void)self;
|
|
109
|
+
|
|
85
110
|
rb_scan_args(argc, argv, "1:", &points, &options);
|
|
111
|
+
|
|
86
112
|
integration_validate_qagp_points(points);
|
|
113
|
+
|
|
87
114
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
115
|
+
|
|
88
116
|
epsabs = parsed_options.epsabs;
|
|
89
117
|
epsrel = parsed_options.epsrel;
|
|
90
118
|
limit = parsed_options.limit;
|
|
119
|
+
|
|
91
120
|
integration_function_init(&function, ¶ms);
|
|
121
|
+
|
|
92
122
|
qagp_params.points_array = points;
|
|
93
123
|
qagp_params.function = &function;
|
|
94
124
|
qagp_params.points = NULL;
|
|
@@ -99,10 +129,14 @@ VALUE integration_qagp(int argc, VALUE *argv, VALUE self) {
|
|
|
99
129
|
qagp_params.workspace = NULL;
|
|
100
130
|
qagp_params.result = &result;
|
|
101
131
|
qagp_params.error = &error;
|
|
132
|
+
|
|
102
133
|
rb_protect(integration_run_qagp_with_resources, (VALUE)&qagp_params, &state);
|
|
134
|
+
|
|
103
135
|
RB_GC_GUARD(points);
|
|
104
136
|
RB_GC_GUARD(params.block);
|
|
105
137
|
RB_GC_GUARD(params.exception);
|
|
138
|
+
|
|
106
139
|
integration_finish_callback(¶ms, state);
|
|
140
|
+
|
|
107
141
|
return rb_ary_new_from_args(2, DBL2NUM(result), DBL2NUM(error));
|
|
108
142
|
}
|
|
@@ -50,6 +50,7 @@ VALUE integration_qags(int argc, VALUE *argv, VALUE self) {
|
|
|
50
50
|
rb_scan_args(argc, argv, "2:", &a, &b, &options);
|
|
51
51
|
|
|
52
52
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
53
|
+
|
|
53
54
|
epsabs = parsed_options.epsabs;
|
|
54
55
|
epsrel = parsed_options.epsrel;
|
|
55
56
|
limit = parsed_options.limit;
|
|
@@ -15,14 +15,17 @@ typedef struct {
|
|
|
15
15
|
|
|
16
16
|
static VALUE integration_run_qawc(VALUE data) {
|
|
17
17
|
integration_qawc_params *params = (integration_qawc_params *)data;
|
|
18
|
+
|
|
18
19
|
(void)gsl_integration_qawc(params->function, params->a, params->b, params->c,
|
|
19
20
|
params->epsabs, params->epsrel, params->limit,
|
|
20
21
|
params->workspace, params->result, params->error);
|
|
22
|
+
|
|
21
23
|
return Qnil;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
static VALUE integration_run_qawc_with_workspace(VALUE data) {
|
|
25
27
|
integration_qawc_params *params = (integration_qawc_params *)data;
|
|
28
|
+
|
|
26
29
|
return rb_ensure(integration_run_qawc, data, integration_free_workspace,
|
|
27
30
|
(VALUE)params->workspace);
|
|
28
31
|
}
|
|
@@ -43,11 +46,13 @@ VALUE integration_qawc(int argc, VALUE *argv, VALUE self) {
|
|
|
43
46
|
double result;
|
|
44
47
|
double error;
|
|
45
48
|
int state = 0;
|
|
49
|
+
|
|
46
50
|
(void)self;
|
|
47
51
|
|
|
48
52
|
rb_scan_args(argc, argv, "3:", &a, &b, &c, &options);
|
|
49
53
|
|
|
50
54
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
55
|
+
|
|
51
56
|
epsabs = parsed_options.epsabs;
|
|
52
57
|
epsrel = parsed_options.epsrel;
|
|
53
58
|
limit = parsed_options.limit;
|
|
@@ -55,6 +60,7 @@ VALUE integration_qawc(int argc, VALUE *argv, VALUE self) {
|
|
|
55
60
|
integration_function_init(&function, ¶ms);
|
|
56
61
|
|
|
57
62
|
workspace = gsl_integration_workspace_alloc(limit);
|
|
63
|
+
|
|
58
64
|
qawc_params.function = &function;
|
|
59
65
|
qawc_params.a = NUM2DBL(a);
|
|
60
66
|
qawc_params.b = NUM2DBL(b);
|
|
@@ -67,8 +73,10 @@ VALUE integration_qawc(int argc, VALUE *argv, VALUE self) {
|
|
|
67
73
|
qawc_params.error = &error;
|
|
68
74
|
|
|
69
75
|
rb_protect(integration_run_qawc_with_workspace, (VALUE)&qawc_params, &state);
|
|
76
|
+
|
|
70
77
|
RB_GC_GUARD(params.block);
|
|
71
78
|
RB_GC_GUARD(params.exception);
|
|
79
|
+
|
|
72
80
|
integration_finish_callback(¶ms, state);
|
|
73
81
|
|
|
74
82
|
return rb_ary_new_from_args(2, DBL2NUM(result), DBL2NUM(error));
|
|
@@ -4,6 +4,7 @@ typedef struct {
|
|
|
4
4
|
gsl_function *function;
|
|
5
5
|
double a;
|
|
6
6
|
double omega;
|
|
7
|
+
|
|
7
8
|
enum gsl_integration_qawo_enum sine;
|
|
8
9
|
double epsabs;
|
|
9
10
|
size_t limit;
|
|
@@ -20,9 +21,11 @@ static VALUE integration_free_qawf_resources(VALUE data) {
|
|
|
20
21
|
if (params->table != NULL) {
|
|
21
22
|
gsl_integration_qawo_table_free(params->table);
|
|
22
23
|
}
|
|
24
|
+
|
|
23
25
|
if (params->cycle_workspace != NULL) {
|
|
24
26
|
gsl_integration_workspace_free(params->cycle_workspace);
|
|
25
27
|
}
|
|
28
|
+
|
|
26
29
|
if (params->workspace != NULL) {
|
|
27
30
|
gsl_integration_workspace_free(params->workspace);
|
|
28
31
|
}
|
|
@@ -5,6 +5,7 @@ typedef struct {
|
|
|
5
5
|
double a;
|
|
6
6
|
double b;
|
|
7
7
|
double omega;
|
|
8
|
+
|
|
8
9
|
enum gsl_integration_qawo_enum sine;
|
|
9
10
|
double epsabs;
|
|
10
11
|
double epsrel;
|
|
@@ -21,6 +22,7 @@ static VALUE integration_free_qawo_resources(VALUE data) {
|
|
|
21
22
|
if (params->table != NULL) {
|
|
22
23
|
gsl_integration_qawo_table_free(params->table);
|
|
23
24
|
}
|
|
25
|
+
|
|
24
26
|
if (params->workspace != NULL) {
|
|
25
27
|
gsl_integration_workspace_free(params->workspace);
|
|
26
28
|
}
|
|
@@ -69,6 +71,7 @@ VALUE integration_qawo(int argc, VALUE *argv, VALUE self) {
|
|
|
69
71
|
rb_scan_args(argc, argv, "4:", &a, &b, &omega, &sine, &options);
|
|
70
72
|
|
|
71
73
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
74
|
+
|
|
72
75
|
epsabs = parsed_options.epsabs;
|
|
73
76
|
epsrel = parsed_options.epsrel;
|
|
74
77
|
limit = parsed_options.limit;
|
|
@@ -23,6 +23,7 @@ static VALUE integration_free_qaws_resources(VALUE data) {
|
|
|
23
23
|
if (params->table != NULL) {
|
|
24
24
|
gsl_integration_qaws_table_free(params->table);
|
|
25
25
|
}
|
|
26
|
+
|
|
26
27
|
if (params->workspace != NULL) {
|
|
27
28
|
gsl_integration_workspace_free(params->workspace);
|
|
28
29
|
}
|
|
@@ -36,6 +37,7 @@ static VALUE integration_run_qaws(VALUE data) {
|
|
|
36
37
|
params->table = gsl_integration_qaws_table_alloc(params->alpha, params->beta,
|
|
37
38
|
params->mu, params->nu);
|
|
38
39
|
params->workspace = gsl_integration_workspace_alloc(params->limit);
|
|
40
|
+
|
|
39
41
|
(void)gsl_integration_qaws(params->function, params->a, params->b,
|
|
40
42
|
params->table, params->epsabs, params->epsrel,
|
|
41
43
|
params->limit, params->workspace, params->result,
|
|
@@ -69,9 +71,11 @@ VALUE integration_qaws(int argc, VALUE *argv, VALUE self) {
|
|
|
69
71
|
int state = 0;
|
|
70
72
|
|
|
71
73
|
(void)self;
|
|
74
|
+
|
|
72
75
|
rb_scan_args(argc, argv, "6:", &a, &b, &alpha, &beta, &mu, &nu, &options);
|
|
73
76
|
|
|
74
77
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 1000);
|
|
78
|
+
|
|
75
79
|
epsabs = parsed_options.epsabs;
|
|
76
80
|
epsrel = parsed_options.epsrel;
|
|
77
81
|
limit = parsed_options.limit;
|
|
@@ -94,8 +98,10 @@ VALUE integration_qaws(int argc, VALUE *argv, VALUE self) {
|
|
|
94
98
|
qaws_params.error = &error;
|
|
95
99
|
|
|
96
100
|
rb_protect(integration_run_qaws_with_resources, (VALUE)&qaws_params, &state);
|
|
101
|
+
|
|
97
102
|
RB_GC_GUARD(params.block);
|
|
98
103
|
RB_GC_GUARD(params.exception);
|
|
104
|
+
|
|
99
105
|
integration_finish_callback(¶ms, state);
|
|
100
106
|
|
|
101
107
|
return rb_ary_new_from_args(2, DBL2NUM(result), DBL2NUM(error));
|
|
@@ -50,6 +50,7 @@ VALUE integration_romberg(int argc, VALUE *argv, VALUE self) {
|
|
|
50
50
|
rb_scan_args(argc, argv, "2:", &a, &b, &options);
|
|
51
51
|
|
|
52
52
|
integration_options_parse(options, &parsed_options, 0.0, 1e-8, 20);
|
|
53
|
+
|
|
53
54
|
epsabs = parsed_options.epsabs;
|
|
54
55
|
epsrel = parsed_options.epsrel;
|
|
55
56
|
limit = parsed_options.limit;
|
|
@@ -108,6 +108,14 @@ module Numo
|
|
|
108
108
|
Numeric b,
|
|
109
109
|
?order: Integer
|
|
110
110
|
) { (Float) -> Numeric } -> Float
|
|
111
|
+
def self.fixed: (
|
|
112
|
+
(:legendre | :chebyshev | :chebyshev2 | :gegenbauer | :jacobi | :laguerre | :hermite | :exponential | :rational) type,
|
|
113
|
+
order: Integer,
|
|
114
|
+
a: Numeric,
|
|
115
|
+
b: Numeric,
|
|
116
|
+
?alpha: Numeric,
|
|
117
|
+
?beta: Numeric
|
|
118
|
+
) { (Float) -> Numeric } -> Float
|
|
111
119
|
end
|
|
112
120
|
end
|
|
113
121
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: numo-gsl-integration
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Takahiro SATOH
|
|
@@ -27,6 +27,7 @@ files:
|
|
|
27
27
|
- ext/numo/gsl/integration/callback.c
|
|
28
28
|
- ext/numo/gsl/integration/cquad.c
|
|
29
29
|
- ext/numo/gsl/integration/extconf.rb
|
|
30
|
+
- ext/numo/gsl/integration/fixed.c
|
|
30
31
|
- ext/numo/gsl/integration/glfixed.c
|
|
31
32
|
- ext/numo/gsl/integration/integration.c
|
|
32
33
|
- ext/numo/gsl/integration/integration_internal.h
|