Module: Convolver
- Defined in:
- lib/convolver.rb,
lib/convolver/version.rb,
lib/convolver/operation_plan.rb,
lib/convolver/operation_shapes.rb,
lib/convolver/signal_extension.rb,
lib/convolver/operation_options.rb,
ext/convolver/convolver.c
Overview
Internal planning and extension support for Convolver's public operations.
Constant Summary collapse
- MAX_RANK =
Maximum number of dimensions supported by the implementations.
16- VERSION =
Current gem version.
'2.0.0'
Class Method Summary collapse
-
.convolve(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
Chooses the likely fastest cross-correlation implementation.
-
.convolve_basic(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
Uses the direct native valid primitive after applying the requested signal extension in Ruby.
-
.convolve_basic_valid(signal, kernel) ⇒ Numo::SFloat
Calculates a valid cross-correlation using the direct native implementation.
-
.convolve_fft(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
Uses PocketFFT to calculate the requested cross-correlation.
-
.convolve_fftw3(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
deprecated
Deprecated.
Use Convolver.convolve_fft; Convolver no longer uses FFTW3.
-
.predict_convolve_basic_time(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Float
Estimates the relative cost of Convolver.convolve_basic for the requested options.
-
.predict_convolve_fft_time(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Float
Estimates the relative cost of Convolver.convolve_fft for the requested options.
Class Method Details
.convolve(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
Chooses the likely fastest cross-correlation implementation.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/convolver.rb', line 26 def convolve(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) plan = operation_plan(signal, kernel, mode:, boundary:, fill_value:, origin:) = (mode, boundary, fill_value, origin) return convolve_basic(signal, kernel, **) if plan.extended_size < 1000 || kernel.size < 100 basic_time_predicted = predict_convolve_basic_time(signal, kernel, **) return convolve_basic(signal, kernel, **) if basic_time_predicted < 0.1 fft_time_predicted = predict_convolve_fft_time(signal, kernel, **) return convolve_fft(signal, kernel, **) if fft_time_predicted < 2 * basic_time_predicted convolve_basic(signal, kernel, **) end |
.convolve_basic(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
Uses the direct native valid primitive after applying the requested signal extension in Ruby.
46 47 48 49 50 |
# File 'lib/convolver.rb', line 46 def convolve_basic(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) plan = operation_plan(signal, kernel, mode:, boundary:, fill_value:, origin:) convolve_basic_valid(plan.extend_signal(signal), kernel) end |
.convolve_basic_valid(signal, kernel) ⇒ Numo::SFloat
Calculates a valid cross-correlation using the direct native implementation.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'ext/convolver/convolver.c', line 25 static VALUE convolver_convolve_basic_valid(VALUE self, VALUE signal, VALUE kernel) { volatile VALUE signal_value; volatile VALUE kernel_value; volatile VALUE result_value; narray_t *signal_narray; narray_t *kernel_narray; int rank; int i; size_t signal_shape[LARGEST_RANK]; size_t kernel_shape[LARGEST_RANK]; size_t result_shape[LARGEST_RANK]; size_t numo_result_shape[LARGEST_RANK]; (void)self; if (!rb_obj_is_kind_of(signal, numo_cNArray) || !rb_obj_is_kind_of(kernel, numo_cNArray)) { rb_raise(rb_eArgError, "signal and kernel must be Numo::NArray values"); } signal_value = rb_funcall(numo_cSFloat, rb_intern("cast"), 1, signal); kernel_value = rb_funcall(numo_cSFloat, rb_intern("cast"), 1, kernel); if (!RTEST(na_check_contiguous(signal_value))) { signal_value = na_copy(signal_value); } if (!RTEST(na_check_contiguous(kernel_value))) { kernel_value = na_copy(kernel_value); } GetNArray(signal_value, signal_narray); GetNArray(kernel_value, kernel_narray); if (signal_narray->size == 0 || kernel_narray->size == 0) { rb_raise(rb_eArgError, "signal and kernel must not be empty"); } if (signal_narray->ndim != kernel_narray->ndim) { rb_raise(rb_eArgError, "signal and kernel must have equal rank"); } if (signal_narray->ndim > LARGEST_RANK) { rb_raise(rb_eArgError, "maximum supported rank is %d", LARGEST_RANK); } rank = signal_narray->ndim; copy_shape(rank, signal_narray->shape, signal_shape); copy_shape(rank, kernel_narray->shape, kernel_shape); for (i = 0; i < rank; i++) { if (signal_shape[i] < kernel_shape[i]) { rb_raise(rb_eArgError, "kernel must not be larger than signal in any dimension"); } result_shape[i] = signal_shape[i] - kernel_shape[i] + 1; numo_result_shape[rank - i - 1] = (size_t)result_shape[i]; } result_value = nary_new(numo_cSFloat, rank, numo_result_shape); convolve_raw( rank, signal_shape, (float *)na_get_pointer_for_read(signal_value), rank, kernel_shape, (float *)na_get_pointer_for_read(kernel_value), rank, result_shape, (float *)na_get_pointer_for_write(result_value) ); return result_value; } |
.convolve_fft(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
Uses PocketFFT to calculate the requested cross-correlation.
Periodic same-sized results use a circular transform. Other combinations use the shared extension plan and PocketFFT's linear convolution.
58 59 60 61 62 63 64 |
# File 'lib/convolver.rb', line 58 def convolve_fft(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) plan = operation_plan(signal, kernel, mode:, boundary:, fill_value:, origin:) return convolve_fft_wrap(signal, kernel, plan) if plan.wrap? convolve_fft_valid(plan.extend_signal(signal), kernel) end |
.convolve_fftw3(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Numo::SFloat
Use convolve_fft; Convolver no longer uses FFTW3.
Compatibility alias for the former FFTW3-backed implementation.
70 71 72 73 74 75 |
# File 'lib/convolver.rb', line 70 def convolve_fftw3(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) warn 'Convolver.convolve_fftw3 is deprecated; use .convolve_fft instead', uplevel: 1 = (mode, boundary, fill_value, origin) convolve_fft(signal, kernel, **) end |
.predict_convolve_basic_time(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Float
Estimates the relative cost of convolve_basic for the requested options.
91 92 93 94 95 96 97 |
# File 'lib/convolver.rb', line 91 def predict_convolve_basic_time(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) plan = operation_plan(signal, kernel, mode:, boundary:, fill_value:, origin:) operations = plan.result_size * plan.extended_size * kernel.size operations += plan.extended_size unless plan.valid? 4.54e-12 * operations end |
.predict_convolve_fft_time(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) ⇒ Float
Estimates the relative cost of convolve_fft for the requested options.
80 81 82 83 84 85 86 |
# File 'lib/convolver.rb', line 80 def predict_convolve_fft_time(signal, kernel, mode: :valid, boundary: :constant, fill_value: UNSPECIFIED_FILL, origin: 0) plan = operation_plan(signal, kernel, mode:, boundary:, fill_value:, origin:) transform_size = plan.wrap? ? signal.size : plan.linear_fft_size(kernel.shape) transform_cost = 16 * 4.55e-08 * transform_size * Math.log(transform_size) transform_cost + (4.55e-08 * fft_preparation_size(plan, signal, kernel)) end |