convolver 0.4.0 → 1.0.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 +47 -0
- data/README.md +68 -55
- data/ext/convolver/convolve_raw.c +6 -6
- data/ext/convolver/convolve_raw.h +0 -2
- data/ext/convolver/convolver.c +63 -92
- data/ext/convolver/extconf.rb +37 -24
- data/lib/convolver/version.rb +2 -1
- data/lib/convolver.rb +92 -83
- metadata +26 -23
- data/.github/workflows/ci.yml +0 -40
- data/.gitignore +0 -19
- data/.rubocop.yml +0 -16
- data/Gemfile +0 -15
- data/Rakefile +0 -22
- data/convolver.gemspec +0 -27
- data/ext/convolver/narray_shared.c +0 -61
- data/ext/convolver/narray_shared.h +0 -22
- data/spec/convolver_basic_spec.rb +0 -89
- data/spec/convolver_fftw3_spec.rb +0 -166
- data/spec/convolver_spec.rb +0 -53
- data/spec/helpers.rb +0 -43
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c27f2aa98b988627391d0a9812c6b8e0a59e65cf4a506592d95f43d1a02e3ae
|
|
4
|
+
data.tar.gz: ede25a5203ed707bd3ca726eb513ceb44746bc5a04c294396d368ab3785b2c4c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aaf0fc6ab38eedbe06c2082b8ffaa2cdbfab45b3340aadf7c87839d28aa97dbb3be1e22a99c3aef25207b656741c69763bb177003d74e440ce7d6653be22aff8
|
|
7
|
+
data.tar.gz: 20b127fa09a8c6b449e74183da3fa91a93603bc17701b4991543de6095ae64023ef217c166d5a7ef999a241de125c7278e6f1e2b3d895f5ec0d0fe2665188bd5
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2026-07-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Native C quality tasks for strict compiler warnings (`c:lint`), GCC/gcovr
|
|
13
|
+
coverage (`c:coverage`), and ASan/UBSan checks (`c:sanitize`).
|
|
14
|
+
- GitHub Actions reporting and downloadable HTML and Cobertura artifacts for C
|
|
15
|
+
coverage.
|
|
16
|
+
- RuboCop checks with Rake and RSpec plugins.
|
|
17
|
+
- SimpleCov reporting for the Ruby test suite.
|
|
18
|
+
- Support for Ruby 4.0 in the CI test matrix.
|
|
19
|
+
- Monthly scheduled CI runs to detect dependency and toolchain regressions.
|
|
20
|
+
- Ruby branch-coverage reporting and additional coverage of native input
|
|
21
|
+
validation.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **Breaking:** Replaced the unmaintained `narray` dependency with
|
|
26
|
+
`numo-narray-alt`. Public methods now accept `Numo::NArray` values and return
|
|
27
|
+
`Numo::SFloat` results instead of legacy `NArray` values.
|
|
28
|
+
- **Breaking:** Raised the minimum supported Ruby version to 3.2.
|
|
29
|
+
- Replaced the `fftw3` gem and external FFTW library with `numo-pocketfft`,
|
|
30
|
+
removing the system FFTW installation requirement.
|
|
31
|
+
- Renamed the FFT-backed implementation from `convolve_fftw3` to
|
|
32
|
+
`convolve_fft`. The old name remains as a deprecated compatibility alias.
|
|
33
|
+
- Clarified that the operations calculate valid cross-correlation and expanded
|
|
34
|
+
the README and YARD documentation for input, output, and shape behaviour.
|
|
35
|
+
- Replaced the retired Travis CI configuration with GitHub Actions.
|
|
36
|
+
- Improved gem metadata and limited packaged files to the library, native
|
|
37
|
+
extension, documentation, and licence.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- Reject non-Numo inputs, empty arrays, unequal ranks, kernels larger than their
|
|
42
|
+
signals, and ranks unsupported by the native implementation with descriptive
|
|
43
|
+
`ArgumentError` messages.
|
|
44
|
+
- Updated the native extension to use the maintained Numo C API and removed the
|
|
45
|
+
legacy untyped-data compatibility code.
|
|
46
|
+
|
|
47
|
+
[1.0.0]: https://github.com/neilslater/convolver/compare/v0.3.2...v1.0.0
|
data/README.md
CHANGED
|
@@ -1,86 +1,99 @@
|
|
|
1
1
|
# Convolver
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.com/github/neilslater/convolver)
|
|
5
|
-
[](https://coveralls.io/r/neilslater/convolver?branch=master)
|
|
6
|
-
[](https://codeclimate.com/github/neilslater/convolver)
|
|
3
|
+
[](https://badge.fury.io/rb/convolver)
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
Convolver calculates valid cross-correlations between multidimensional
|
|
6
|
+
[`Numo::NArray`](https://github.com/yoshoku/numo-narray-alt) values. It chooses
|
|
7
|
+
between a direct native implementation for smaller inputs and a
|
|
8
|
+
[`Numo::Pocketfft`](https://github.com/yoshoku/numo-pocketfft)-based
|
|
9
|
+
implementation for larger inputs.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Version 1.0 replaces the unmaintained `narray` and `fftw3` gems with
|
|
12
|
+
`numo-narray-alt` and `numo-pocketfft`.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
## Installation
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
See http://www.fftw.org/ for details.
|
|
16
|
+
Add Convolver to your application's Gemfile:
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
```ruby
|
|
19
|
+
gem 'convolver'
|
|
20
|
+
```
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
bundle config set --local build.fftw3 "--with-fftw3-dir=$(brew --prefix fftw)"
|
|
23
|
-
bundle install
|
|
22
|
+
Then run:
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
```sh
|
|
25
|
+
bundle install
|
|
26
|
+
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Alternatively, install it directly:
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
```sh
|
|
31
|
+
gem install convolver
|
|
32
|
+
```
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
No external FFT library is required; PocketFFT is bundled by its Ruby gem.
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
disables the inherited allocator when the first native NArray object is created.
|
|
36
|
-
The warning does not affect convolver's results; removing it properly requires a
|
|
37
|
-
fix in `narray` or a future migration to a maintained NArray implementation.
|
|
36
|
+
## Usage
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
```ruby
|
|
39
|
+
require 'convolver'
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
signal = Numo::SFloat[0.3, 0.4, 0.5]
|
|
42
|
+
kernel = Numo::SFloat[1.3, -0.5]
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
Convolver.convolve(signal, kernel)
|
|
45
|
+
# => Numo::SFloat#shape=[2]
|
|
46
|
+
# [0.19, 0.27]
|
|
47
|
+
```
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
The signal and kernel must have the same rank, and the kernel must be no larger
|
|
50
|
+
than the signal in any dimension. Convolver returns only positions at which the
|
|
51
|
+
kernel overlaps the signal completely. The result size in each dimension is:
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
```ruby
|
|
54
|
+
signal_size - kernel_size + 1
|
|
55
|
+
```
|
|
48
56
|
|
|
49
|
-
|
|
57
|
+
Inputs are converted to single-precision floats internally, and results are
|
|
58
|
+
returned as `Numo::SFloat`. Supplying `Numo::SFloat` inputs avoids conversion in
|
|
59
|
+
the direct implementation.
|
|
50
60
|
|
|
51
|
-
|
|
61
|
+
`Convolver.convolve` normally chooses the implementation automatically. The
|
|
62
|
+
implementations can also be called directly for application-specific
|
|
63
|
+
benchmarking:
|
|
52
64
|
|
|
53
|
-
|
|
65
|
+
```ruby
|
|
66
|
+
Convolver.convolve_basic(signal, kernel)
|
|
67
|
+
Convolver.convolve_fft(signal, kernel)
|
|
68
|
+
```
|
|
54
69
|
|
|
55
|
-
|
|
70
|
+
`Convolver.convolve_fftw3` remains as a deprecated alias for `convolve_fft` to
|
|
71
|
+
ease migration from Convolver 0.x.
|
|
56
72
|
|
|
57
|
-
|
|
58
|
-
b = NArray[1.3, -0.5]
|
|
59
|
-
c = Convolver.convolve( a, b )
|
|
60
|
-
=> NArray.float(2): [ 0.19, 0.27 ]
|
|
61
|
-
|
|
62
|
-
* Convolver only works on single-precision floats internally. It will cast NArray types to this, if
|
|
63
|
-
possible, prior to calculating. For best speed, use NArray.sfloat arrays.
|
|
73
|
+
## Contributing
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
is the original size, minus the kernel size, plus 1, in each dimension.
|
|
75
|
+
Install the development dependencies, then run the main suite:
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
```sh
|
|
78
|
+
bundle install
|
|
79
|
+
bundle exec rake
|
|
80
|
+
bundle exec rubocop
|
|
81
|
+
bundle exec rake c:lint
|
|
82
|
+
```
|
|
70
83
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
and large convolutions are processed using FFTW3 to convert to frequency space where convolution
|
|
74
|
-
is simpler and faster to calculate, then convert back.
|
|
84
|
+
The Ruby specs exercise both the Ruby API and native extension. Additional
|
|
85
|
+
native-code checks are available:
|
|
75
86
|
|
|
76
|
-
|
|
87
|
+
```sh
|
|
88
|
+
bundle exec rake c:coverage # Requires GCC and gcovr
|
|
89
|
+
bundle exec rake c:sanitize # Requires Linux and GCC
|
|
90
|
+
```
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
|
82
|
-
5. Create new Pull Request
|
|
92
|
+
`c:coverage` writes HTML and Cobertura reports under `coverage/c`. CI uploads
|
|
93
|
+
the reports as a `c-coverage` artifact. The sanitizer task uses AddressSanitizer
|
|
94
|
+
and UndefinedBehaviorSanitizer.
|
|
83
95
|
|
|
84
96
|
## Contributors
|
|
85
97
|
|
|
86
|
-
|
|
98
|
+
- [Dima Ermilov](https://github.com/adworse) contributed the original Windows
|
|
99
|
+
compilation support.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include "convolve_raw.h"
|
|
4
4
|
|
|
5
|
-
inline int size_from_shape( int rank, int *shape ) {
|
|
5
|
+
static inline int size_from_shape( int rank, int *shape ) {
|
|
6
6
|
int size = 1;
|
|
7
7
|
int i;
|
|
8
8
|
for ( i = 0; i < rank; i++ ) { size *= shape[i]; }
|
|
@@ -10,15 +10,16 @@ inline int size_from_shape( int rank, int *shape ) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// Sets reverse indices
|
|
13
|
-
inline void corner_reset( int rank, int *shape, int *rev_indices ) {
|
|
13
|
+
static inline void corner_reset( int rank, int *shape, int *rev_indices ) {
|
|
14
14
|
int i;
|
|
15
15
|
for ( i = 0; i < rank; i++ ) { rev_indices[i] = shape[i] - 1; }
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// Counts indices down, returns number of ranks that reset
|
|
20
|
-
inline int corner_dec( int rank, int *shape, int *rev_indices ) {
|
|
20
|
+
static inline int corner_dec( int rank, int *shape, int *rev_indices ) {
|
|
21
21
|
int i = 0;
|
|
22
|
+
(void) rank;
|
|
22
23
|
while ( ! rev_indices[i]-- ) {
|
|
23
24
|
rev_indices[i] = shape[i] - 1;
|
|
24
25
|
i++;
|
|
@@ -27,7 +28,7 @@ inline int corner_dec( int rank, int *shape, int *rev_indices ) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
// Generates co-increment steps by rank boundaries crossed, for the outer position as inner position is incremented by 1
|
|
30
|
-
inline void calc_co_increment( int rank, int *outer_shape, int *inner_shape, int *co_increment ) {
|
|
31
|
+
static inline void calc_co_increment( int rank, int *outer_shape, int *inner_shape, int *co_increment ) {
|
|
31
32
|
int i, factor;
|
|
32
33
|
co_increment[0] = 1; // co-increment is always 1 in lowest rank
|
|
33
34
|
factor = 1;
|
|
@@ -48,12 +49,11 @@ void convolve_raw(
|
|
|
48
49
|
int in_rank, int *in_shape, float *in_ptr,
|
|
49
50
|
int kernel_rank, int *kernel_shape, float *kernel_ptr,
|
|
50
51
|
int out_rank, int *out_shape, float *out_ptr ) {
|
|
51
|
-
int i, j,
|
|
52
|
+
int i, j, kernel_size, kernel_aligned, out_size, offset;
|
|
52
53
|
int out_co_incr[LARGEST_RANK], kernel_co_incr[LARGEST_RANK];
|
|
53
54
|
int ker_q[LARGEST_RANK], out_q[LARGEST_RANK];
|
|
54
55
|
int *kernel_co_incr_cache;
|
|
55
56
|
|
|
56
|
-
in_size = size_from_shape( in_rank, in_shape );
|
|
57
57
|
kernel_size = size_from_shape( kernel_rank, kernel_shape );
|
|
58
58
|
kernel_aligned = 4 * (kernel_size/4);
|
|
59
59
|
out_size = size_from_shape( out_rank, out_shape );
|
data/ext/convolver/convolver.c
CHANGED
|
@@ -1,118 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
#include <limits.h>
|
|
3
2
|
#include <ruby.h>
|
|
4
|
-
#include
|
|
5
|
-
#include <
|
|
3
|
+
#include <numo/narray.h>
|
|
4
|
+
#include <numo/intern.h>
|
|
6
5
|
|
|
7
|
-
#include "narray_shared.h"
|
|
8
6
|
#include "convolve_raw.h"
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// To hold the module object
|
|
13
|
-
VALUE Convolver = Qnil;
|
|
14
|
-
|
|
15
|
-
/* @overload fit_kernel_backwards( fft_temp_space, kernel )
|
|
16
|
-
* @!visibility private
|
|
17
|
-
* Over-writes fft_temp_space at edges with a reversed copy of kernel, in such a way that
|
|
18
|
-
* an FFTW3-based convolve has a result set in an easy-to-extract position later. This is
|
|
19
|
-
* implemented as a native extension for convenience and speed - to do this with methods provided
|
|
20
|
-
* by narray gem would take several complex steps and be inefficient.
|
|
21
|
-
* @param [NArray<sfloat>] fft_temp_space target array for pre-fft copy of kernel, is over-written
|
|
22
|
-
* @param [NArray] kernel must be same size or smaller than fft_temp_space in each dimension
|
|
23
|
-
* @return [nil]
|
|
24
|
-
*/
|
|
25
|
-
static VALUE narray_fit_backwards( VALUE self, VALUE a, VALUE b ) {
|
|
26
|
-
struct NARRAY *na_a, *na_b;
|
|
27
|
-
volatile VALUE val_a, val_b;
|
|
28
|
-
int target_rank, i;
|
|
29
|
-
int shift_by[LARGEST_RANK];
|
|
30
|
-
|
|
31
|
-
val_a = na_cast_object(a, NA_SFLOAT);
|
|
32
|
-
GetNArray( val_a, na_a );
|
|
33
|
-
|
|
34
|
-
val_b = na_cast_object(b, NA_SFLOAT);
|
|
35
|
-
GetNArray( val_b, na_b );
|
|
36
|
-
|
|
37
|
-
if ( na_a->rank != na_b->rank ) {
|
|
38
|
-
rb_raise( rb_eArgError, "narray a must have equal rank to narray b (a rank %d, b rank %d)", na_a->rank, na_b->rank );
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if ( na_a->rank > LARGEST_RANK ) {
|
|
42
|
-
rb_raise( rb_eArgError, "exceeded maximum narray rank for convolve of %d", LARGEST_RANK );
|
|
43
|
-
}
|
|
8
|
+
static VALUE mConvolver;
|
|
44
9
|
|
|
45
|
-
|
|
10
|
+
static void copy_shape(int rank, const size_t *source, int *target) {
|
|
11
|
+
int i;
|
|
46
12
|
|
|
47
|
-
for (
|
|
48
|
-
if (
|
|
49
|
-
rb_raise(
|
|
13
|
+
for (i = 0; i < rank; i++) {
|
|
14
|
+
if (source[rank - i - 1] > INT_MAX) {
|
|
15
|
+
rb_raise(rb_eArgError, "array dimension exceeds native implementation limit");
|
|
50
16
|
}
|
|
51
|
-
|
|
17
|
+
target[i] = (int)source[rank - i - 1];
|
|
52
18
|
}
|
|
53
|
-
|
|
54
|
-
fit_backwards_raw(
|
|
55
|
-
target_rank,
|
|
56
|
-
na_a->shape, (float*) na_a->ptr,
|
|
57
|
-
na_b->shape, (float*) na_b->ptr,
|
|
58
|
-
shift_by );
|
|
59
|
-
|
|
60
|
-
return Qnil;
|
|
61
19
|
}
|
|
62
20
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @return [NArray] result of convolving signal with kernel
|
|
21
|
+
/*
|
|
22
|
+
* Calculates a valid cross-correlation using the direct native implementation.
|
|
23
|
+
*
|
|
24
|
+
* @overload convolve_basic(signal, kernel)
|
|
25
|
+
* @param signal [Numo::NArray] input values
|
|
26
|
+
* @param kernel [Numo::NArray] correlation kernel
|
|
27
|
+
* @return [Numo::SFloat] valid cross-correlation result
|
|
71
28
|
*/
|
|
72
|
-
static VALUE
|
|
73
|
-
|
|
74
|
-
volatile VALUE
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
29
|
+
static VALUE convolver_convolve_basic(VALUE self, VALUE signal, VALUE kernel) {
|
|
30
|
+
volatile VALUE signal_value;
|
|
31
|
+
volatile VALUE kernel_value;
|
|
32
|
+
volatile VALUE result_value;
|
|
33
|
+
narray_t *signal_narray;
|
|
34
|
+
narray_t *kernel_narray;
|
|
35
|
+
int rank;
|
|
36
|
+
int i;
|
|
37
|
+
int signal_shape[LARGEST_RANK];
|
|
38
|
+
int kernel_shape[LARGEST_RANK];
|
|
39
|
+
int result_shape[LARGEST_RANK];
|
|
40
|
+
size_t numo_result_shape[LARGEST_RANK];
|
|
41
|
+
|
|
42
|
+
(void)self;
|
|
43
|
+
|
|
44
|
+
if (!rb_obj_is_kind_of(signal, numo_cNArray) || !rb_obj_is_kind_of(kernel, numo_cNArray)) {
|
|
45
|
+
rb_raise(rb_eArgError, "signal and kernel must be Numo::NArray values");
|
|
46
|
+
}
|
|
80
47
|
|
|
81
|
-
|
|
82
|
-
|
|
48
|
+
signal_value = rb_funcall(numo_cSFloat, rb_intern("cast"), 1, signal);
|
|
49
|
+
kernel_value = rb_funcall(numo_cSFloat, rb_intern("cast"), 1, kernel);
|
|
50
|
+
GetNArray(signal_value, signal_narray);
|
|
51
|
+
GetNArray(kernel_value, kernel_narray);
|
|
83
52
|
|
|
84
|
-
if (
|
|
85
|
-
rb_raise(
|
|
53
|
+
if (signal_narray->size == 0 || kernel_narray->size == 0) {
|
|
54
|
+
rb_raise(rb_eArgError, "signal and kernel must not be empty");
|
|
86
55
|
}
|
|
87
56
|
|
|
88
|
-
if (
|
|
89
|
-
rb_raise(
|
|
57
|
+
if (signal_narray->ndim != kernel_narray->ndim) {
|
|
58
|
+
rb_raise(rb_eArgError, "signal and kernel must have equal rank");
|
|
59
|
+
}
|
|
60
|
+
if (signal_narray->ndim > LARGEST_RANK) {
|
|
61
|
+
rb_raise(rb_eArgError, "maximum supported rank is %d", LARGEST_RANK);
|
|
90
62
|
}
|
|
91
63
|
|
|
92
|
-
|
|
64
|
+
rank = signal_narray->ndim;
|
|
65
|
+
copy_shape(rank, signal_narray->shape, signal_shape);
|
|
66
|
+
copy_shape(rank, kernel_narray->shape, kernel_shape);
|
|
93
67
|
|
|
94
|
-
for (
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
rb_raise(
|
|
68
|
+
for (i = 0; i < rank; i++) {
|
|
69
|
+
result_shape[i] = signal_shape[i] - kernel_shape[i] + 1;
|
|
70
|
+
if (result_shape[i] < 1) {
|
|
71
|
+
rb_raise(rb_eArgError, "kernel must not be larger than signal in any dimension");
|
|
98
72
|
}
|
|
73
|
+
numo_result_shape[rank - i - 1] = (size_t)result_shape[i];
|
|
99
74
|
}
|
|
100
75
|
|
|
101
|
-
|
|
102
|
-
GetNArray( val_c, na_c );
|
|
103
|
-
|
|
76
|
+
result_value = nary_new(numo_cSFloat, rank, numo_result_shape);
|
|
104
77
|
convolve_raw(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
78
|
+
rank, signal_shape, (float *)na_get_pointer_for_read(signal_value),
|
|
79
|
+
rank, kernel_shape, (float *)na_get_pointer_for_read(kernel_value),
|
|
80
|
+
rank, result_shape, (float *)na_get_pointer_for_write(result_value)
|
|
81
|
+
);
|
|
108
82
|
|
|
109
|
-
return
|
|
83
|
+
return result_value;
|
|
110
84
|
}
|
|
111
85
|
|
|
112
|
-
void Init_convolver() {
|
|
113
|
-
|
|
114
|
-
rb_define_singleton_method(
|
|
115
|
-
|
|
116
|
-
// private method
|
|
117
|
-
rb_define_singleton_method( Convolver, "fit_kernel_backwards", narray_fit_backwards, 2 );
|
|
86
|
+
void Init_convolver(void) {
|
|
87
|
+
mConvolver = rb_define_module("Convolver");
|
|
88
|
+
rb_define_singleton_method(mConvolver, "convolve_basic", convolver_convolve_basic, 2);
|
|
118
89
|
}
|
data/ext/convolver/extconf.rb
CHANGED
|
@@ -1,37 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# ext/convolver/extconf.rb
|
|
4
3
|
require 'mkmf'
|
|
5
|
-
require '
|
|
4
|
+
require 'numo/narray/alt'
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
end
|
|
13
|
-
if /cygwin|mingw/ =~ RUBY_PLATFORM
|
|
14
|
-
dir_config('narray', narray_dir, "#{narray_dir}/src")
|
|
15
|
-
else
|
|
16
|
-
dir_config('narray', narray_dir, narray_dir)
|
|
6
|
+
$LOAD_PATH.each do |load_path|
|
|
7
|
+
next unless File.exist?(File.join(load_path, 'numo/numo/narray.h'))
|
|
8
|
+
|
|
9
|
+
$INCFLAGS = "-I#{File.join(load_path, 'numo')} #{$INCFLAGS}"
|
|
10
|
+
break
|
|
17
11
|
end
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
print <<-ERROR_MESSAGE
|
|
21
|
-
** configure error **
|
|
22
|
-
Header narray.h or narray_config.h is not found. If you have these files in
|
|
23
|
-
/narraydir/include, try the following:
|
|
13
|
+
abort 'numo/narray.h not found' unless have_header('numo/narray.h')
|
|
24
14
|
|
|
25
|
-
|
|
15
|
+
if RUBY_PLATFORM.match?(/mswin|cygwin|mingw/)
|
|
16
|
+
$LOAD_PATH.each do |load_path|
|
|
17
|
+
next unless File.exist?(File.join(load_path, 'numo/narray/libnarray.a'))
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
$LDFLAGS = "-L#{File.join(load_path, 'numo/narray')} #{$LDFLAGS}"
|
|
20
|
+
break
|
|
21
|
+
end
|
|
22
|
+
abort 'libnarray.a not found' unless have_library('narray', 'nary_new')
|
|
29
23
|
end
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
if RUBY_PLATFORM.include?('darwin') && Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1') &&
|
|
26
|
+
try_link('int main(void) { return 0; }', '-Wl,-undefined,dynamic_lookup')
|
|
27
|
+
$LDFLAGS << ' -Wl,-undefined,dynamic_lookup'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
case ENV.fetch('CONVOLVER_NATIVE_MODE', 'release')
|
|
31
|
+
when 'release'
|
|
32
|
+
$CFLAGS << ' -O3 -funroll-loops'
|
|
33
|
+
when 'lint'
|
|
34
|
+
$CFLAGS << ' -std=gnu2x -O0 -g -Wall -Wextra -Wpedantic -Wformat=2 -Werror'
|
|
35
|
+
if RbConfig::CONFIG.fetch('CC').match?(/clang/) || RbConfig::CONFIG.fetch('host_os').match?(/darwin/)
|
|
36
|
+
$CFLAGS << ' -Wno-c23-extensions -Wno-strict-prototypes -Wno-unused-parameter'
|
|
37
|
+
$CFLAGS << ' -Wno-default-const-init-field-unsafe'
|
|
38
|
+
end
|
|
39
|
+
when 'coverage'
|
|
40
|
+
$CFLAGS << ' -O0 -g --coverage'
|
|
41
|
+
$LDFLAGS << ' --coverage'
|
|
42
|
+
when 'sanitize'
|
|
43
|
+
sanitizer_flags = ' -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer'
|
|
44
|
+
$CFLAGS << sanitizer_flags
|
|
45
|
+
$LDFLAGS << ' -fsanitize=address,undefined'
|
|
46
|
+
else
|
|
47
|
+
abort "Unknown CONVOLVER_NATIVE_MODE: #{ENV.fetch('CONVOLVER_NATIVE_MODE', nil)}"
|
|
34
48
|
end
|
|
35
49
|
|
|
36
|
-
$CFLAGS << ' -O3 -funroll-loops'
|
|
37
50
|
create_makefile('convolver/convolver')
|