numo-gsl-integration 0.3.1 → 0.4.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 +10 -0
- data/README.md +2 -1
- data/docs/development.md +8 -0
- data/docs/routines.md +25 -0
- data/ext/numo/gsl/integration/extconf.rb +8 -1
- data/ext/numo/gsl/integration/integration.c +1 -0
- data/ext/numo/gsl/integration/integration_internal.h +2 -0
- data/ext/numo/gsl/integration/lebedev.c +103 -0
- data/lib/numo/gsl/integration/version.rb +1 -1
- data/sig/numo/gsl/integration.rbs +3 -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: 57503e38512a38ad357142981868d2e2aea1a47743f27aee55d80625715eb794
|
|
4
|
+
data.tar.gz: d87dadfb371056e006cb1a914c6cebe81131cfa21c1e5f4daa35f72f377a98bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ad109b9e20ce13a6eeb8b34b919c49a353eb5b27b158e74d1f9d149219fc200ca9a567417a12a4ea6dc66f247caf68bfe864d5cbaaf811b58fdacd8c8ef6ffbb
|
|
7
|
+
data.tar.gz: 6cab24c8607e941ab66eaa7f44db5492836c117649956979f148755df73792fd66c0baa794177276c02dd90e1e931d071cd0b19a174dd8d6dbb2c864da08e0cf
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.4.0] - 2026-11-06
|
|
6
|
+
|
|
7
|
+
### Added in 0.4.0
|
|
8
|
+
|
|
9
|
+
- Added Lebedev quadrature for surface integration over the unit sphere.
|
|
10
|
+
|
|
11
|
+
### Changed in 0.4.0
|
|
12
|
+
|
|
13
|
+
- Required GNU Scientific Library 2.8 or later.
|
|
14
|
+
|
|
5
15
|
## [0.3.1] - 2026-11-06
|
|
6
16
|
|
|
7
17
|
### Changed in 0.3.1
|
data/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- [Ruby](https://www.ruby-lang.org/) 3.2 or later
|
|
8
|
-
- GNU Scientific Library (GSL)
|
|
8
|
+
- GNU Scientific Library (GSL) 2.8 or later
|
|
9
9
|
- `gsl-config` available in `PATH`
|
|
10
10
|
|
|
11
11
|
GSL itself must be installed separately.
|
|
@@ -61,6 +61,7 @@ end
|
|
|
61
61
|
| `romberg` | Finite | Smooth functions with extrapolated trapezoidal integration |
|
|
62
62
|
| `glfixed` | Finite | Fixed-order Gauss-Legendre integration of smooth functions |
|
|
63
63
|
| `fixed` | Rule-dependent | Fixed-order Gaussian quadrature with selectable weight functions |
|
|
64
|
+
| `lebedev` | Unit sphere | Lebedev quadrature over the surface of the unit sphere |
|
|
64
65
|
|
|
65
66
|
See [Integration routines](docs/routines.md) for parameters and examples.
|
|
66
67
|
|
data/docs/development.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Development
|
|
2
2
|
|
|
3
|
+
Development and builds require GSL 2.8 or later. Confirm the installed version before building:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
gsl-config --version
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The extension configuration stops with an error if `gsl-config` reports an older version or if the Lebedev integration API is unavailable.
|
|
10
|
+
|
|
3
11
|
After checking out the repository, install the dependencies:
|
|
4
12
|
|
|
5
13
|
```bash
|
data/docs/routines.md
CHANGED
|
@@ -383,3 +383,28 @@ end
|
|
|
383
383
|
```
|
|
384
384
|
|
|
385
385
|
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.
|
|
386
|
+
|
|
387
|
+
## Lebedev integration on the unit sphere
|
|
388
|
+
|
|
389
|
+
GSL [Lebedev quadrature](https://www.gnu.org/software/gsl/doc/html/integration.html#integrating-on-the-unit-sphere) approximates a surface integral over the unit sphere. `Numo::GSL::Integration.lebedev` passes the Cartesian coordinates of each quadrature point to the block:
|
|
390
|
+
|
|
391
|
+
```ruby
|
|
392
|
+
result = Numo::GSL::Integration.lebedev(26) do |x, y, z|
|
|
393
|
+
(x * x) + (y * y) + (z * z)
|
|
394
|
+
end
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Every point satisfies `x * x + y * y + z * z == 1` within floating-point precision, so the example integral has an exact value of `4.0 * Math::PI`.
|
|
398
|
+
|
|
399
|
+
The argument is the number of Lebedev nodes. GSL 2.8 provides the following node counts:
|
|
400
|
+
|
|
401
|
+
```text
|
|
402
|
+
6, 14, 26, 38, 50, 74, 86, 110,
|
|
403
|
+
146, 170, 194, 230, 266, 302, 350, 434,
|
|
404
|
+
590, 770, 974, 1202, 1454, 1730, 2030, 2354,
|
|
405
|
+
2702, 3074, 3470, 3890, 4334, 4802, 5294, 5810
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
The node count must be a positive integer and must identify one of the rules supplied by GSL. Unsupported node counts are reported as `Numo::GSL::GslError`.
|
|
409
|
+
|
|
410
|
+
Lebedev integration returns only the surface integral. It does not accept an error tolerance and does not return an error estimate. Increasing the node count selects a rule that integrates spherical harmonics to a higher degree exactly.
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "mkmf"
|
|
4
|
+
require "rubygems/version"
|
|
4
5
|
|
|
5
6
|
gsl_config = find_executable("gsl-config")
|
|
6
7
|
abort("gsl-config is required") unless gsl_config
|
|
7
8
|
|
|
9
|
+
minimum_gsl_version = Gem::Version.new("2.8")
|
|
10
|
+
gsl_version = Gem::Version.new(`#{gsl_config} --version`.strip)
|
|
11
|
+
abort("GSL 2.8 or later is required (found #{gsl_version})") if gsl_version < minimum_gsl_version
|
|
12
|
+
|
|
8
13
|
$CFLAGS << " #{`#{gsl_config} --cflags`.strip}"
|
|
9
14
|
$libs = "#{`#{gsl_config} --libs`.strip} #{$libs}"
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
header = "gsl/gsl_integration.h"
|
|
17
|
+
abort("#{header} is required") unless have_header(header)
|
|
18
|
+
abort("GSL Lebedev integration support is required") unless have_func("gsl_integration_lebedev_alloc", header)
|
|
12
19
|
|
|
13
20
|
create_makefile("numo/gsl/integration/integration")
|
|
@@ -45,4 +45,5 @@ void Init_integration(void) {
|
|
|
45
45
|
rb_define_singleton_method(mIntegration, "romberg", integration_romberg, -1);
|
|
46
46
|
rb_define_singleton_method(mIntegration, "glfixed", integration_glfixed, -1);
|
|
47
47
|
rb_define_singleton_method(mIntegration, "fixed", integration_fixed, -1);
|
|
48
|
+
rb_define_singleton_method(mIntegration, "lebedev", integration_lebedev, 1);
|
|
48
49
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
#include <gsl/gsl_errno.h>
|
|
5
5
|
#include <gsl/gsl_integration.h>
|
|
6
|
+
#include <gsl/gsl_math.h>
|
|
6
7
|
#include <ruby.h>
|
|
7
8
|
|
|
8
9
|
typedef struct {
|
|
@@ -52,5 +53,6 @@ VALUE integration_cquad(int argc, VALUE *argv, VALUE self);
|
|
|
52
53
|
VALUE integration_romberg(int argc, VALUE *argv, VALUE self);
|
|
53
54
|
VALUE integration_glfixed(int argc, VALUE *argv, VALUE self);
|
|
54
55
|
VALUE integration_fixed(int argc, VALUE *argv, VALUE self);
|
|
56
|
+
VALUE integration_lebedev(VALUE self, VALUE n_value);
|
|
55
57
|
|
|
56
58
|
#endif
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#include "integration_internal.h"
|
|
2
|
+
|
|
3
|
+
typedef struct {
|
|
4
|
+
VALUE block;
|
|
5
|
+
VALUE x;
|
|
6
|
+
VALUE y;
|
|
7
|
+
VALUE z;
|
|
8
|
+
VALUE exception;
|
|
9
|
+
gsl_integration_lebedev_workspace *workspace;
|
|
10
|
+
double result;
|
|
11
|
+
int state;
|
|
12
|
+
} integration_lebedev_params;
|
|
13
|
+
|
|
14
|
+
static VALUE integration_call_lebedev_block(VALUE data) {
|
|
15
|
+
integration_lebedev_params *params = (integration_lebedev_params *)data;
|
|
16
|
+
VALUE arguments[3] = {params->x, params->y, params->z};
|
|
17
|
+
VALUE value;
|
|
18
|
+
|
|
19
|
+
value = rb_funcallv(params->block, rb_intern("call"), 3, arguments);
|
|
20
|
+
return rb_Float(value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static VALUE integration_free_lebedev_workspace(VALUE data) {
|
|
24
|
+
integration_lebedev_params *params = (integration_lebedev_params *)data;
|
|
25
|
+
|
|
26
|
+
if (params->workspace != NULL) {
|
|
27
|
+
gsl_integration_lebedev_free(params->workspace);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return Qnil;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static VALUE integration_run_lebedev(VALUE data) {
|
|
34
|
+
integration_lebedev_params *params = (integration_lebedev_params *)data;
|
|
35
|
+
double result = 0.0;
|
|
36
|
+
size_t i;
|
|
37
|
+
|
|
38
|
+
for (i = 0; i < params->workspace->n; ++i) {
|
|
39
|
+
VALUE value;
|
|
40
|
+
|
|
41
|
+
params->x = DBL2NUM(params->workspace->x[i]);
|
|
42
|
+
params->y = DBL2NUM(params->workspace->y[i]);
|
|
43
|
+
params->z = DBL2NUM(params->workspace->z[i]);
|
|
44
|
+
value = rb_protect(integration_call_lebedev_block, (VALUE)params,
|
|
45
|
+
¶ms->state);
|
|
46
|
+
|
|
47
|
+
if (params->state != 0) {
|
|
48
|
+
params->exception = rb_errinfo();
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
result += params->workspace->weights[i] * NUM2DBL(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
params->result = 4.0 * M_PI * result;
|
|
56
|
+
return Qnil;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static VALUE integration_run_lebedev_with_workspace(VALUE data) {
|
|
60
|
+
integration_lebedev_params *params = (integration_lebedev_params *)data;
|
|
61
|
+
|
|
62
|
+
return rb_ensure(integration_run_lebedev, data,
|
|
63
|
+
integration_free_lebedev_workspace, data);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
VALUE integration_lebedev(VALUE self, VALUE n_value) {
|
|
67
|
+
integration_lebedev_params params = {0};
|
|
68
|
+
size_t n;
|
|
69
|
+
int state = 0;
|
|
70
|
+
|
|
71
|
+
(void)self;
|
|
72
|
+
|
|
73
|
+
if (!RB_INTEGER_TYPE_P(n_value)) {
|
|
74
|
+
rb_raise(rb_eTypeError, "n must be an Integer");
|
|
75
|
+
}
|
|
76
|
+
if (RTEST(rb_funcall(n_value, rb_intern("<="), 1, INT2FIX(0)))) {
|
|
77
|
+
rb_raise(rb_eArgError, "n must be positive");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
n = NUM2SIZET(n_value);
|
|
81
|
+
params.block = rb_block_proc();
|
|
82
|
+
params.workspace = gsl_integration_lebedev_alloc(n);
|
|
83
|
+
if (params.workspace == NULL) {
|
|
84
|
+
rb_memerror();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
rb_protect(integration_run_lebedev_with_workspace, (VALUE)¶ms, &state);
|
|
88
|
+
|
|
89
|
+
RB_GC_GUARD(params.block);
|
|
90
|
+
RB_GC_GUARD(params.x);
|
|
91
|
+
RB_GC_GUARD(params.y);
|
|
92
|
+
RB_GC_GUARD(params.z);
|
|
93
|
+
RB_GC_GUARD(params.exception);
|
|
94
|
+
|
|
95
|
+
if (params.state != 0) {
|
|
96
|
+
rb_exc_raise(params.exception);
|
|
97
|
+
}
|
|
98
|
+
if (state != 0) {
|
|
99
|
+
rb_jump_tag(state);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return DBL2NUM(params.result);
|
|
103
|
+
}
|
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.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Takahiro SATOH
|
|
@@ -31,6 +31,7 @@ files:
|
|
|
31
31
|
- ext/numo/gsl/integration/glfixed.c
|
|
32
32
|
- ext/numo/gsl/integration/integration.c
|
|
33
33
|
- ext/numo/gsl/integration/integration_internal.h
|
|
34
|
+
- ext/numo/gsl/integration/lebedev.c
|
|
34
35
|
- ext/numo/gsl/integration/options.c
|
|
35
36
|
- ext/numo/gsl/integration/qag.c
|
|
36
37
|
- ext/numo/gsl/integration/qagi.c
|