convolver 0.3.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4c3bcf13a230b62ed29260b84490f720af3408cc
4
- data.tar.gz: 3d00b5f4ece4078525b5d57fbe536d3dfcc6020e
2
+ SHA256:
3
+ metadata.gz: 4c27f2aa98b988627391d0a9812c6b8e0a59e65cf4a506592d95f43d1a02e3ae
4
+ data.tar.gz: ede25a5203ed707bd3ca726eb513ceb44746bc5a04c294396d368ab3785b2c4c
5
5
  SHA512:
6
- metadata.gz: 113c51e9233dabd6d94490b1906e31787f0fc9e7826bacf8b999c2c63e2722381baf417c616519735456f286c781e2597547b9851e77addd8267ec87c38947c2
7
- data.tar.gz: 2495231401448636a915562cf6ad09ba4351094a4af290b0d0a84ee5a7a313e57e1e2d8e07b70746b7ee60b1780ba6ed9e4e8c8c19518fa785d4c01e589b8258
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,66 +1,99 @@
1
1
  # Convolver
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/convolver.png)](http://badge.fury.io/rb/convolver)
4
- [![Build Status](https://travis-ci.org/neilslater/convolver.png?branch=master)](http://travis-ci.org/neilslater/convolver)
5
- [![Coverage Status](https://coveralls.io/repos/neilslater/convolver/badge.png?branch=master)](https://coveralls.io/r/neilslater/convolver?branch=master)
6
- [![Inline docs](http://inch-ci.org/github/neilslater/convolver.png?branch=master)](http://inch-ci.org/github/neilslater/convolver)
7
- [![Code Climate](https://codeclimate.com/github/neilslater/convolver.png)](https://codeclimate.com/github/neilslater/convolver)
3
+ [![Gem Version](https://badge.fury.io/rb/convolver.svg)](https://badge.fury.io/rb/convolver)
8
4
 
9
- Calculates discrete convolution between two multi-dimensional arrays of floats.
10
- See http://en.wikipedia.org/wiki/Convolution
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
+
11
+ Version 1.0 replaces the unmaintained `narray` and `fftw3` gems with
12
+ `numo-narray-alt` and `numo-pocketfft`.
11
13
 
12
14
  ## Installation
13
15
 
14
- ### Dependency: FFTW3
16
+ Add Convolver to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'convolver'
20
+ ```
15
21
 
16
- Before you install *convolver*, you should install the FFTW3 library on your system.
17
- See http://www.fftw.org/ for details.
22
+ Then run:
18
23
 
19
- ### Installing the gem
24
+ ```sh
25
+ bundle install
26
+ ```
20
27
 
21
- Add this line to your application's Gemfile:
28
+ Alternatively, install it directly:
22
29
 
23
- gem 'convolver'
30
+ ```sh
31
+ gem install convolver
32
+ ```
24
33
 
25
- And then execute:
34
+ No external FFT library is required; PocketFFT is bundled by its Ruby gem.
26
35
 
27
- $ bundle
36
+ ## Usage
28
37
 
29
- Or install it yourself as:
38
+ ```ruby
39
+ require 'convolver'
30
40
 
31
- $ gem install convolver
41
+ signal = Numo::SFloat[0.3, 0.4, 0.5]
42
+ kernel = Numo::SFloat[1.3, -0.5]
32
43
 
33
- ## Usage
44
+ Convolver.convolve(signal, kernel)
45
+ # => Numo::SFloat#shape=[2]
46
+ # [0.19, 0.27]
47
+ ```
34
48
 
35
- Basic convolution:
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:
36
52
 
37
- a = NArray[0.3,0.4,0.5]
38
- b = NArray[1.3, -0.5]
39
- c = Convolver.convolve( a, b )
40
- => NArray.float(2): [ 0.19, 0.27 ]
53
+ ```ruby
54
+ signal_size - kernel_size + 1
55
+ ```
41
56
 
42
- * Convolver only works on single-precision floats internally. It will cast NArray types to this, if
43
- possible, prior to calculating. For best speed, use NArray.sfloat arrays.
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.
44
60
 
45
- * The output is smaller than the input, it only contains fully-calculated values. The output size
46
- is the original size, minus the kernel size, plus 1, in each dimension.
61
+ `Convolver.convolve` normally chooses the implementation automatically. The
62
+ implementations can also be called directly for application-specific
63
+ benchmarking:
47
64
 
48
- * Convolver expects input a and kernel b to have the same rank, and for the kernel to be same size
49
- or smaller in all dimensions as the input.
65
+ ```ruby
66
+ Convolver.convolve_basic(signal, kernel)
67
+ Convolver.convolve_fft(signal, kernel)
68
+ ```
50
69
 
51
- * Convolver.convolve will try to choose the faster of two approaches it has coded. In general,
52
- small convolutions are processed directly by multiplying out all combinations and summing them,
53
- and large convolutions are processed using FFTW3 to convert to frequency space where convolution
54
- is simpler and faster to calculate, then convert back.
70
+ `Convolver.convolve_fftw3` remains as a deprecated alias for `convolve_fft` to
71
+ ease migration from Convolver 0.x.
55
72
 
56
73
  ## Contributing
57
74
 
58
- 1. Fork it
59
- 2. Create your feature branch (`git checkout -b my-new-feature`)
60
- 3. Commit your changes (`git commit -am 'Add some feature'`)
61
- 4. Push to the branch (`git push origin my-new-feature`)
62
- 5. Create new Pull Request
75
+ Install the development dependencies, then run the main suite:
76
+
77
+ ```sh
78
+ bundle install
79
+ bundle exec rake
80
+ bundle exec rubocop
81
+ bundle exec rake c:lint
82
+ ```
83
+
84
+ The Ruby specs exercise both the Ruby API and native extension. Additional
85
+ native-code checks are available:
86
+
87
+ ```sh
88
+ bundle exec rake c:coverage # Requires GCC and gcovr
89
+ bundle exec rake c:sanitize # Requires Linux and GCC
90
+ ```
91
+
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.
63
95
 
64
96
  ## Contributors
65
97
 
66
- * [Dima Ermilov](https://github.com/adworse) contributed fix to support compiling under Windows.
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, in_size, kernel_size, kernel_aligned, out_size, offset;
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 );
@@ -76,13 +76,16 @@ void convolve_raw(
76
76
 
77
77
  // Main convolve loop
78
78
  for ( i = 0; i < out_size; i++ ) {
79
+ #if CONVOLVER_USE_SSE
79
80
  __m128 simd_x, simd_y, simd_t;
80
- float t = 0.0;
81
81
  float v[4];
82
82
  simd_t = _mm_setzero_ps();
83
+ #endif
84
+ float t = 0.0;
83
85
 
84
86
  offset += out_co_incr[ corner_dec( out_rank, out_shape, out_q ) ];
85
87
 
88
+ #if CONVOLVER_USE_SSE
86
89
  // Use SIMD for all the aligned values in groups of 4
87
90
  for ( j = 0; j < kernel_aligned; j +=4 ) {
88
91
  simd_x = _mm_load_ps( kernel_ptr + j );
@@ -93,13 +96,24 @@ void convolve_raw(
93
96
  simd_t = _mm_add_ps( simd_x, simd_t );
94
97
  }
95
98
  _mm_store_ps( v, simd_t );
99
+ #else
100
+ // SSE is unavailable on architectures such as Apple Silicon.
101
+ // Use the same calculation without x86-specific intrinsics.
102
+ for ( j = 0; j < kernel_aligned; j++ ) {
103
+ t += in_ptr[ offset + kernel_co_incr_cache[j] ] * kernel_ptr[j];
104
+ }
105
+ #endif
96
106
 
97
107
  // Complete any remaining 1,2 or 3 items one at a time
98
108
  for ( j = kernel_aligned; j < kernel_size; j++ ) {
99
109
  t += in_ptr[ offset + kernel_co_incr_cache[j] ] * kernel_ptr[ j ];
100
110
  }
101
111
 
112
+ #if CONVOLVER_USE_SSE
102
113
  out_ptr[i] = v[0] + v[1] + v[2] + v[3] + t;
114
+ #else
115
+ out_ptr[i] = t;
116
+ #endif
103
117
  }
104
118
 
105
119
  xfree( kernel_co_incr_cache );
@@ -9,9 +9,12 @@
9
9
  #define CONVOLVE_RAW_H
10
10
 
11
11
  #include <ruby.h>
12
+ #if defined(__SSE__)
12
13
  #include <xmmintrin.h>
13
- #include "narray_shared.h"
14
-
14
+ #define CONVOLVER_USE_SSE 1
15
+ #else
16
+ #define CONVOLVER_USE_SSE 0
17
+ #endif
15
18
  #define LARGEST_RANK 16
16
19
 
17
20
  void convolve_raw(
@@ -1,119 +1,89 @@
1
- // ext/convolver/convolver.c
2
-
1
+ #include <limits.h>
3
2
  #include <ruby.h>
4
- #include "narray.h"
5
- #include <stdio.h>
6
- #include <xmmintrin.h>
3
+ #include <numo/narray.h>
4
+ #include <numo/intern.h>
7
5
 
8
- #include "narray_shared.h"
9
6
  #include "convolve_raw.h"
10
7
 
11
- ////////////////////////////////////////////////////////////////////////////////////////////////////
12
-
13
- // To hold the module object
14
- VALUE Convolver = Qnil;
15
-
16
- /* @overload fit_kernel_backwards( fft_temp_space, kernel )
17
- * @!visibility private
18
- * Over-writes fft_temp_space at edges with a reversed copy of kernel, in such a way that
19
- * an FFTW3-based convolve has a result set in an easy-to-extract position later. This is
20
- * implemented as a native extension for convenience and speed - to do this with methods provided
21
- * by narray gem would take several complex steps and be inefficient.
22
- * @param [NArray<sfloat>] fft_temp_space target array for pre-fft copy of kernel, is over-written
23
- * @param [NArray] kernel must be same size or smaller than fft_temp_space in each dimension
24
- * @return [nil]
25
- */
26
- static VALUE narray_fit_backwards( VALUE self, VALUE a, VALUE b ) {
27
- struct NARRAY *na_a, *na_b;
28
- volatile VALUE val_a, val_b;
29
- int target_rank, i;
30
- int shift_by[LARGEST_RANK];
31
-
32
- val_a = na_cast_object(a, NA_SFLOAT);
33
- GetNArray( val_a, na_a );
34
-
35
- val_b = na_cast_object(b, NA_SFLOAT);
36
- GetNArray( val_b, na_b );
37
-
38
- if ( na_a->rank != na_b->rank ) {
39
- 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 );
40
- }
41
-
42
- if ( na_a->rank > LARGEST_RANK ) {
43
- rb_raise( rb_eArgError, "exceeded maximum narray rank for convolve of %d", LARGEST_RANK );
44
- }
8
+ static VALUE mConvolver;
45
9
 
46
- target_rank = na_a->rank;
10
+ static void copy_shape(int rank, const size_t *source, int *target) {
11
+ int i;
47
12
 
48
- for ( i = 0; i < target_rank; i++ ) {
49
- if ( ( na_a->shape[i] - na_b->shape[i] ) < 0 ) {
50
- rb_raise( rb_eArgError, "no space for backward fit" );
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");
51
16
  }
52
- shift_by[i] = na_b->shape[i] >> 1;
17
+ target[i] = (int)source[rank - i - 1];
53
18
  }
54
-
55
- fit_backwards_raw(
56
- target_rank,
57
- na_a->shape, (float*) na_a->ptr,
58
- na_b->shape, (float*) na_b->ptr,
59
- shift_by );
60
-
61
- return Qnil;
62
19
  }
63
20
 
64
-
65
- /* @overload convolve_basic( signal, kernel )
66
- * Calculates convolution of an array of floats representing a signal, with a second array representing
67
- * a kernel. The two parameters must have the same rank. The output has same rank, its size in each dimension d is given by
68
- * signal.shape[d] - kernel.shape[d] + 1
69
- * @param [NArray] signal must be same size or larger than kernel in each dimension
70
- * @param [NArray] kernel must be same size or smaller than signal in each dimension
71
- * @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
72
28
  */
73
- static VALUE narray_convolve( VALUE self, VALUE a, VALUE b ) {
74
- struct NARRAY *na_a, *na_b, *na_c;
75
- volatile VALUE val_a, val_b, val_c;
76
- int target_rank, i;
77
- int target_shape[LARGEST_RANK];
78
-
79
- val_a = na_cast_object(a, NA_SFLOAT);
80
- GetNArray( val_a, na_a );
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
+ }
81
47
 
82
- val_b = na_cast_object(b, NA_SFLOAT);
83
- GetNArray( val_b, na_b );
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);
84
52
 
85
- if ( na_a->rank != na_b->rank ) {
86
- rb_raise( rb_eArgError, "narray a must have equal rank to narray b (a rack %d, b rank %d)", na_a->rank, na_b->rank );
53
+ if (signal_narray->size == 0 || kernel_narray->size == 0) {
54
+ rb_raise(rb_eArgError, "signal and kernel must not be empty");
87
55
  }
88
56
 
89
- if ( na_a->rank > LARGEST_RANK ) {
90
- rb_raise( rb_eArgError, "exceeded maximum narray rank for convolve of %d", LARGEST_RANK );
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);
91
62
  }
92
63
 
93
- target_rank = na_a->rank;
64
+ rank = signal_narray->ndim;
65
+ copy_shape(rank, signal_narray->shape, signal_shape);
66
+ copy_shape(rank, kernel_narray->shape, kernel_shape);
94
67
 
95
- for ( i = 0; i < target_rank; i++ ) {
96
- target_shape[i] = na_a->shape[i] - na_b->shape[i] + 1;
97
- if ( target_shape[i] < 1 ) {
98
- rb_raise( rb_eArgError, "narray b is bigger in one or more dimensions than narray a" );
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");
99
72
  }
73
+ numo_result_shape[rank - i - 1] = (size_t)result_shape[i];
100
74
  }
101
75
 
102
- val_c = na_make_object( NA_SFLOAT, target_rank, target_shape, CLASS_OF( val_a ) );
103
- GetNArray( val_c, na_c );
104
-
76
+ result_value = nary_new(numo_cSFloat, rank, numo_result_shape);
105
77
  convolve_raw(
106
- target_rank, na_a->shape, (float*) na_a->ptr,
107
- target_rank, na_b->shape, (float*) na_b->ptr,
108
- target_rank, target_shape, (float*) na_c->ptr );
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
+ );
109
82
 
110
- return val_c;
83
+ return result_value;
111
84
  }
112
85
 
113
- void Init_convolver() {
114
- Convolver = rb_define_module( "Convolver" );
115
- rb_define_singleton_method( Convolver, "convolve_basic", narray_convolve, 2 );
116
-
117
- // private method
118
- 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);
119
89
  }
@@ -1,31 +1,50 @@
1
- # ext/convolver/extconf.rb
2
- require "mkmf"
3
- require "rubygems"
4
-
5
- # Following code stolen shamelessly from fftw3 gem:
6
- narray_dir = File.dirname(Gem.find_files("narray.h").first) rescue $sitearchdir
7
- if /cygwin|mingw/ =~ RUBY_PLATFORM
8
- dir_config('narray', narray_dir, "#{narray_dir}/src")
9
- else
10
- dir_config('narray', narray_dir, narray_dir)
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+ require 'numo/narray/alt'
5
+
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
11
11
  end
12
12
 
13
- if ( ! ( have_header("narray.h") && have_header("narray_config.h") ) ) then
14
- print <<-EOS
15
- ** configure error **
16
- Header narray.h or narray_config.h is not found. If you have these files in
17
- /narraydir/include, try the following:
13
+ abort 'numo/narray.h not found' unless have_header('numo/narray.h')
18
14
 
19
- % ruby extconf.rb --with-narray-include=/narraydir/include
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'))
20
18
 
21
- EOS
22
- exit(-1)
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')
23
23
  end
24
24
 
25
- # This also stolen from fftw3 gem (and not confirmed for Windows platforms - please let me know if it works!)
26
- if /cygwin|mingw/ =~ RUBY_PLATFORM
27
- have_library("narray") || raise("ERROR: narray library is not found")
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)}"
28
48
  end
29
49
 
30
- $CFLAGS << ' -O3 -funroll-loops'
31
- create_makefile( 'convolver/convolver' )
50
+ create_makefile('convolver/convolver')
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Convolver
2
- VERSION = "0.3.2"
4
+ # Current gem version.
5
+ VERSION = '1.0.0'
3
6
  end