convolver 4.0.0 → 4.0.1
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 +26 -2
- data/README.md +71 -162
- data/docs/rules.md +206 -0
- data/docs/terminology.md +30 -0
- data/lib/convolver/fft_limits.rb +1 -1
- data/lib/convolver/operation_plan.rb +1 -1
- data/lib/convolver/version.rb +1 -1
- data/lib/convolver.rb +160 -49
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d27be8d916e59d307ddaef4f74bdb2d6be83fc10e8b12ee3931d5136e9f7457e
|
|
4
|
+
data.tar.gz: db067d222f36caa4311a2e557aad198a16514092264e2929f6ff7e4fd9005334
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a3f955a008e8af26f3cae3c00b25854c10497f55dac328db8b063fa4190360c6b7a0ea87e80e4ba1a5511e525108615a0ff2202b412b9b9f700cd992fa5ba1a
|
|
7
|
+
data.tar.gz: 810fc3b67314bb846ec8363c3fe9ae205e01eef5c10b003eaafa72a3623a27169d1667db07ec0badca20aca19ae0b233e2a0b7a7a2b4fd3a1cc0dccd29655e2c
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.0.1] - 2026-10-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Packaged Markdown references for calculation rules and terminology.
|
|
13
|
+
- `rake docs:build` to generate linked API and reference pages; the existing
|
|
14
|
+
documentation gate also builds the pages and checks local links and anchors.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Explain public methods through purpose and worked examples, with shared
|
|
19
|
+
option rules and clear precision, alignment and memory-limit descriptions.
|
|
20
|
+
- Shorten README around common usage and preserve detailed rules in the reference.
|
|
21
|
+
Calculation behavior, supported inputs and method signatures are unchanged.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Preserve the public module overview in generated documentation, clarify valid
|
|
26
|
+
convolution indexing, and correct inherited method/error descriptions.
|
|
27
|
+
- Repair changelog comparison links, using the original source commit for the
|
|
28
|
+
untagged 3.0.0 version.
|
|
29
|
+
|
|
8
30
|
## [4.0.0] - 2026-10-06
|
|
9
31
|
|
|
10
32
|
### Added
|
|
@@ -162,8 +184,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
162
184
|
- Updated the native extension to use the maintained Numo C API and removed the
|
|
163
185
|
legacy untyped-data compatibility code.
|
|
164
186
|
|
|
165
|
-
[
|
|
166
|
-
[
|
|
187
|
+
[4.0.1]: https://github.com/neilslater/convolver/compare/v4.0.0...v4.0.1
|
|
188
|
+
[4.0.0]: https://github.com/neilslater/convolver/compare/v3.0.1...v4.0.0
|
|
189
|
+
[3.0.1]: https://github.com/neilslater/convolver/compare/9c12a003b3b8675c9cbde0556c586da6635d872e...v3.0.1
|
|
190
|
+
[3.0.0]: https://github.com/neilslater/convolver/compare/v2.0.0...9c12a003b3b8675c9cbde0556c586da6635d872e
|
|
167
191
|
[2.0.0]: https://github.com/neilslater/convolver/compare/v1.0.1...v2.0.0
|
|
168
192
|
[1.0.1]: https://github.com/neilslater/convolver/compare/v1.0.0...v1.0.1
|
|
169
193
|
[1.0.0]: https://github.com/neilslater/convolver/compare/v0.3.2...v1.0.0
|
data/README.md
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
[](https://github.com/neilslater/convolver/actions/workflows/ci.yml)
|
|
4
4
|
[](https://badge.fury.io/rb/convolver)
|
|
5
5
|
|
|
6
|
-
Convolver
|
|
7
|
-
|
|
8
|
-
[`Numo::NArray`](https://github.com/yoshoku/numo-narray-alt)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
implementation for larger inputs.
|
|
6
|
+
Convolver combines numeric sequences or grids with a kernel of weights. Use it
|
|
7
|
+
for operations such as smoothing readings, applying an image filter or matching
|
|
8
|
+
a pattern. Inputs are [`Numo::NArray`](https://github.com/yoshoku/numo-narray-alt)
|
|
9
|
+
arrays. Convolver chooses between direct calculation and
|
|
10
|
+
[`PocketFFT`](https://github.com/yoshoku/numo-pocketfft) transforms using estimates
|
|
11
|
+
of their cost.
|
|
13
12
|
|
|
14
13
|
## Installation
|
|
15
14
|
|
|
@@ -19,188 +18,97 @@ Add Convolver to your application's Gemfile:
|
|
|
19
18
|
gem 'convolver'
|
|
20
19
|
```
|
|
21
20
|
|
|
22
|
-
Then run `bundle install`, or install
|
|
23
|
-
|
|
24
|
-
bundled by its Ruby gem.
|
|
21
|
+
Then run `bundle install`, or install it directly with `gem install convolver`.
|
|
22
|
+
Ruby 3.3 or newer and a toolchain able to build native extensions are required.
|
|
23
|
+
No external FFT library is needed; PocketFFT is bundled by its Ruby gem.
|
|
25
24
|
|
|
26
|
-
##
|
|
25
|
+
## Start with a small example
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
A kernel assigns a weight to each value in a moving window. Convolution reverses
|
|
28
|
+
those weights within the window; cross-correlation keeps their stored order.
|
|
29
|
+
Pass the original kernel to either method.
|
|
31
30
|
|
|
32
31
|
```ruby
|
|
33
32
|
require 'convolver'
|
|
34
33
|
|
|
35
|
-
signal = Numo::
|
|
36
|
-
kernel = Numo::
|
|
34
|
+
signal = Numo::DFloat[1, 2, 4, 8, 16]
|
|
35
|
+
kernel = Numo::DFloat[1, 2, 3]
|
|
37
36
|
|
|
38
|
-
Convolver.convolve(signal, kernel)
|
|
39
|
-
# =>
|
|
40
|
-
# [0.37, 0.45]
|
|
41
|
-
|
|
42
|
-
Convolver.correlate(signal, kernel)
|
|
43
|
-
# => Numo::SFloat#shape=[2]
|
|
44
|
-
# [0.19, 0.27]
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
For real one-dimensional inputs, the two valid operations are:
|
|
48
|
-
|
|
49
|
-
```text
|
|
50
|
-
correlate(signal, kernel)[p] = sum_j signal[p + j] * conjugate(kernel[j])
|
|
51
|
-
convolve(signal, kernel)[n] = sum_j signal[n - j] * kernel[j]
|
|
37
|
+
Convolver.convolve(signal, kernel).to_a # => [11.0, 22.0, 44.0]
|
|
38
|
+
Convolver.correlate(signal, kernel).to_a # => [17.0, 34.0, 68.0]
|
|
52
39
|
```
|
|
53
40
|
|
|
54
|
-
The
|
|
55
|
-
|
|
56
|
-
real input contract makes conjugation invisible.
|
|
41
|
+
The first convolution result is `1*3 + 2*2 + 4*1 = 11`. The corresponding
|
|
42
|
+
correlation result is `1*1 + 2*2 + 4*3 = 17`. Neither method modifies its inputs.
|
|
57
43
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
Use `convolve` for mathematical convolution, such as applying a smoothing kernel
|
|
45
|
+
or combining independent probability distributions. Use `correlate` to compare
|
|
46
|
+
windows with a pattern. Correlation here is a sum of products, not a normalized
|
|
47
|
+
correlation coefficient.
|
|
62
48
|
|
|
63
|
-
|
|
64
|
-
operations:
|
|
49
|
+
## Keep the input size or include the edges
|
|
65
50
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Convolver.convolve_basic(signal, kernel)
|
|
69
|
-
Convolver.convolve_fft(signal, kernel)
|
|
51
|
+
By default, Convolver returns only complete windows. `mode:` changes the output
|
|
52
|
+
size along each dimension, where `S` is the signal size and `K` the kernel size:
|
|
70
53
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
| Mode | Positions included | Result size |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `:valid` (default) | Complete windows inside the signal | `S - K + 1` |
|
|
57
|
+
| `:same` | One output for each signal position | `S` |
|
|
58
|
+
| `:full` | All positions with any signal overlap | `S + K - 1` |
|
|
75
59
|
|
|
76
|
-
|
|
60
|
+
For example, a centered moving average can keep the input size and reflect
|
|
61
|
+
values at the edges:
|
|
77
62
|
|
|
78
63
|
```ruby
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
64
|
+
signal = Numo::DFloat[1, 2, 4, 8, 16]
|
|
65
|
+
kernel = Numo::DFloat.ones(3) / 3
|
|
66
|
+
smoothed = Convolver.convolve(signal, kernel, mode: :same, boundary: :reflect)
|
|
67
|
+
smoothed.shape # => [5]
|
|
68
|
+
smoothed.to_a.map { |value| value.round(3) } # => [1.333, 2.333, 4.667, 9.333, 13.333]
|
|
83
69
|
```
|
|
84
70
|
|
|
85
|
-
|
|
71
|
+
Boundary choices are constant fill, nearest value, reflection with or without
|
|
72
|
+
repeating the endpoint, and periodic wrap. `:same` supports all of them;
|
|
73
|
+
`:full` supports constant fill only. For nonconstant boundaries, omit
|
|
74
|
+
`fill_value:` entirely, even when its value would be zero.
|
|
86
75
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
chooses DFloat if either input maps to DFloat, otherwise SFloat:
|
|
76
|
+
The [calculation rules](docs/rules.md) show each boundary, allowed option
|
|
77
|
+
combinations, and how `origin:` aligns odd- and even-length kernels.
|
|
90
78
|
|
|
91
|
-
|
|
92
|
-
| --- | --- |
|
|
93
|
-
| `SFloat`, `Int8`, `UInt8`, `Int16`, `UInt16` | `Numo::SFloat` |
|
|
94
|
-
| `DFloat`, `Int32`, `UInt32`, `Int64`, `UInt64` | `Numo::DFloat` |
|
|
79
|
+
## Choose precision and calculation path
|
|
95
80
|
|
|
96
|
-
The
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
results and complex arithmetic are not supported.
|
|
81
|
+
The result is `Numo::SFloat` or `Numo::DFloat`, chosen from both inputs.
|
|
82
|
+
`dtype: nil` means automatic selection; either floating class can be requested
|
|
83
|
+
explicitly:
|
|
100
84
|
|
|
101
85
|
```ruby
|
|
102
|
-
signal = Numo::
|
|
103
|
-
kernel = Numo::DFloat[
|
|
104
|
-
Convolver.convolve(signal, kernel)
|
|
105
|
-
Convolver.convolve(signal, kernel, dtype: Numo::SFloat) # SFloat result
|
|
86
|
+
signal = Numo::DFloat[1, 2, 4]
|
|
87
|
+
kernel = Numo::DFloat[1, 2]
|
|
88
|
+
Convolver.convolve(signal, kernel, dtype: Numo::SFloat).class # => Numo::SFloat
|
|
106
89
|
```
|
|
107
90
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
Non-finite propagation and rounding can differ between algorithms.
|
|
91
|
+
Integer inputs are accepted according to the supported-class table in the
|
|
92
|
+
rules, but results and arithmetic are floating-point. Convert to a floating
|
|
93
|
+
array before dividing to make kernel weights. A later `dtype:` override cannot
|
|
94
|
+
recover information already lost to integer division or rounding.
|
|
113
95
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
96
|
+
Start with `convolve` or `correlate` for automatic selection. To request a
|
|
97
|
+
particular path, use `convolve_basic` / `correlate_basic` for direct calculation
|
|
98
|
+
or `convolve_fft` / `correlate_fft` for FFT calculation. Both return the same
|
|
99
|
+
shape and class; rounding can differ, so compare values with suitable tolerances.
|
|
100
|
+
Neither automatic selection nor the `predict_*_time` estimates guarantee the
|
|
101
|
+
fastest method or a measured running time.
|
|
119
102
|
|
|
120
|
-
|
|
103
|
+
## Reference documentation
|
|
121
104
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
| --- | --- | --- |
|
|
126
|
-
| `:valid` | Kernel overlaps the stored signal completely | `S - K + 1` |
|
|
127
|
-
| `:same` | One result aligned with each stored signal position | `S` |
|
|
128
|
-
| `:full` | Every kernel position with any stored-signal overlap | `S + K - 1` |
|
|
129
|
-
|
|
130
|
-
`:valid` is the default and accepts only the default `boundary: :constant`,
|
|
131
|
-
`fill_value: 0.0`, and `origin: 0`. `:full` supports constant extension only.
|
|
132
|
-
`:same` supports every boundary described below. Kernels larger than the signal
|
|
133
|
-
are supported by `:same` and `:full`, but not by `:valid`. `mode:` and
|
|
134
|
-
`boundary:` accept only the symbols listed here.
|
|
135
|
-
|
|
136
|
-
### Boundary extension
|
|
137
|
-
|
|
138
|
-
For a one-dimensional signal `a b c d`, `boundary:` selects values outside the
|
|
139
|
-
stored signal:
|
|
140
|
-
|
|
141
|
-
| Boundary | Extended sequence |
|
|
142
|
-
| --- | --- |
|
|
143
|
-
| `:constant` | `k k k k | a b c d | k k k k` |
|
|
144
|
-
| `:nearest` | `a a a a | a b c d | d d d d` |
|
|
145
|
-
| `:reflect` | `d c b a | a b c d | d c b a` |
|
|
146
|
-
| `:mirror` | `d c b | a b c d | c b a` |
|
|
147
|
-
| `:wrap` | `a b c d | a b c d | a b c d` |
|
|
148
|
-
|
|
149
|
-
`fill_value:` sets `k` for `:constant` and defaults to zero. It must not be
|
|
150
|
-
passed with another boundary. `:reflect` repeats the edge sample; `:mirror`
|
|
151
|
-
does not. All boundary modes work across every dimension, including
|
|
152
|
-
length-one axes and extensions wider than the stored signal.
|
|
153
|
-
|
|
154
|
-
### Kernel origin and alignment
|
|
155
|
-
|
|
156
|
-
`origin:` shifts the stored-kernel anchor for `:same`. It accepts one integer
|
|
157
|
-
applied to every dimension or an array with one integer per dimension. For a
|
|
158
|
-
kernel dimension of length `K`:
|
|
159
|
-
|
|
160
|
-
```text
|
|
161
|
-
anchor = floor(K / 2) + origin
|
|
162
|
-
|
|
163
|
-
correlation[i] = sum_j extended_signal[i + j - anchor] * kernel[j]
|
|
164
|
-
convolution[i] = sum_j extended_signal[i + anchor - j] * kernel[j]
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
The anchor must remain within the kernel. Correlation pads `anchor` samples
|
|
168
|
-
before the signal and `K - 1 - anchor` after it; convolution swaps those
|
|
169
|
-
widths. Odd centered kernels therefore align alike. For an even centered
|
|
170
|
-
kernel, correlation puts the extra sample before the signal and convolution
|
|
171
|
-
puts it after the signal. Positive origins move correlation toward lower signal
|
|
172
|
-
indices and convolution toward higher signal indices.
|
|
173
|
-
|
|
174
|
-
Nonzero origins are supported only for `:same`; `:valid` and `:full` require
|
|
175
|
-
zero.
|
|
176
|
-
|
|
177
|
-
### Estimators
|
|
178
|
-
|
|
179
|
-
The estimator methods accept and validate the same options as their calculation
|
|
180
|
-
families:
|
|
181
|
-
|
|
182
|
-
```ruby
|
|
183
|
-
Convolver.predict_convolve_basic_time(signal, kernel, mode: :same, boundary: :nearest)
|
|
184
|
-
Convolver.predict_convolve_fft_time(signal, kernel, mode: :same, boundary: :wrap)
|
|
185
|
-
|
|
186
|
-
Convolver.predict_correlate_basic_time(signal, kernel, mode: :same, boundary: :nearest)
|
|
187
|
-
Convolver.predict_correlate_fft_time(signal, kernel, mode: :same, boundary: :wrap)
|
|
188
|
-
```
|
|
105
|
+
- [Input and calculation rules](docs/rules.md): exact supported classes,
|
|
106
|
+
precision, output formulas, boundaries, alignment, estimates and memory limits.
|
|
107
|
+
- [Terminology](docs/terminology.md): explanations of the words used in the API.
|
|
189
108
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
three use calibrated profiles on arm64 macOS and x86_64/aarch64 Linux; other
|
|
194
|
-
platforms and higher ranks retain the general heuristic. Algorithm choices
|
|
195
|
-
can change as estimates improve; benchmark the explicit methods for workloads
|
|
196
|
-
where the choice matters.
|
|
197
|
-
|
|
198
|
-
Calculations and estimators reject unrepresentable buffer sizes with `RangeError`
|
|
199
|
-
before allocation. FFT planning also checks conservative PocketFFT integer and
|
|
200
|
-
work-buffer limits, including full complex staging for real inverse transforms.
|
|
201
|
-
Automatic selection uses direct calculation when FFT exceeds its limits and the
|
|
202
|
-
direct path remains valid. These checks do not reserve memory; ordinary allocator
|
|
203
|
-
exhaustion still raises `NoMemoryError`.
|
|
109
|
+
These reference files are included in the gem. From a development checkout,
|
|
110
|
+
`bundle exec rake docs:build` builds the API reference and these pages together
|
|
111
|
+
in `doc/index.html`.
|
|
204
112
|
|
|
205
113
|
### Migrating from version 3
|
|
206
114
|
|
|
@@ -249,8 +157,9 @@ bundle exec rake docs:check
|
|
|
249
157
|
The Ruby specs exercise both the Ruby API and native extension and enforce 95%
|
|
250
158
|
line and branch coverage for the Ruby library. Dependency auditing refreshes
|
|
251
159
|
the advisory database and requires network access. The documentation check
|
|
252
|
-
|
|
253
|
-
|
|
160
|
+
builds the linked pages in `doc/`, checks local link destinations and anchors,
|
|
161
|
+
and rejects YARD warnings and undocumented public API objects. Private
|
|
162
|
+
implementation classes are marked `@private`. Additional native-code checks are available:
|
|
254
163
|
|
|
255
164
|
```sh
|
|
256
165
|
bundle exec rake c:coverage # Requires GCC and gcovr
|
data/docs/rules.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Convolver input and calculation rules
|
|
2
|
+
|
|
3
|
+
These rules describe Convolver 4. They apply to both convolution and
|
|
4
|
+
cross-correlation. See the [terminology](terminology.md) for unfamiliar words,
|
|
5
|
+
or [README](../README.md) for installation and a quick example.
|
|
6
|
+
|
|
7
|
+
## Choose an operation
|
|
8
|
+
|
|
9
|
+
Use `Convolver.convolve` for mathematical convolution and `Convolver.correlate`
|
|
10
|
+
for cross-correlation. Both slide a kernel over a signal, multiply paired values
|
|
11
|
+
and add the products. Convolution reverses the kernel within each window;
|
|
12
|
+
correlation keeps its stored order. Pass the kernel in its original order in
|
|
13
|
+
either case: Convolver performs the named operation itself.
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
require 'convolver'
|
|
17
|
+
|
|
18
|
+
signal = Numo::DFloat[1, 2, 4, 8, 16]
|
|
19
|
+
kernel = Numo::DFloat[1, 2, 3]
|
|
20
|
+
|
|
21
|
+
Convolver.convolve(signal, kernel).to_a # => [11.0, 22.0, 44.0]
|
|
22
|
+
Convolver.correlate(signal, kernel).to_a # => [17.0, 34.0, 68.0]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For the first window, convolution calculates `1*3 + 2*2 + 4*1 = 11`.
|
|
26
|
+
Correlation calculates `1*1 + 2*2 + 4*3 = 17`.
|
|
27
|
+
|
|
28
|
+
Each operation has three entry points:
|
|
29
|
+
|
|
30
|
+
| Choice | Convolution | Cross-correlation |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| Automatic choice | `convolve` | `correlate` |
|
|
33
|
+
| Direct calculation | `convolve_basic` | `correlate_basic` |
|
|
34
|
+
| FFT calculation | `convolve_fft` | `correlate_fft` |
|
|
35
|
+
|
|
36
|
+
Start with the automatic methods. They estimate which implementation is likely
|
|
37
|
+
to be faster; they do not guarantee the fastest choice for every machine or
|
|
38
|
+
input. Explicit methods are useful for measurements or when a workload needs a
|
|
39
|
+
particular calculation path.
|
|
40
|
+
|
|
41
|
+
## Supply compatible arrays
|
|
42
|
+
|
|
43
|
+
Both inputs must be nonempty Numo arrays with the same number of dimensions,
|
|
44
|
+
up to `Convolver::MAX_RANK` (16). Their sizes may differ. Two zero-dimensional
|
|
45
|
+
arrays are supported and their scalar values are multiplied.
|
|
46
|
+
|
|
47
|
+
The supported input classes and their automatic floating types are:
|
|
48
|
+
|
|
49
|
+
| Input class in `Numo` | Automatic floating type |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `SFloat`, `Int8`, `UInt8`, `Int16`, `UInt16` | `Numo::SFloat` |
|
|
52
|
+
| `DFloat`, `Int32`, `UInt32`, `Int64`, `UInt64` | `Numo::DFloat` |
|
|
53
|
+
|
|
54
|
+
Inputs must be instances of these concrete classes. Ordinary Ruby arrays,
|
|
55
|
+
`Numo::Bit`, complex arrays, `Numo::RObject` and custom subclasses are rejected,
|
|
56
|
+
even when `dtype:` is supplied. Supported array views, including slices and
|
|
57
|
+
reversed views, are accepted. Neither input is modified.
|
|
58
|
+
|
|
59
|
+
## Choose precision
|
|
60
|
+
|
|
61
|
+
By default, Convolver maps each input using the table above. If either maps to
|
|
62
|
+
`Numo::DFloat`, the result is DFloat; otherwise it is SFloat. Swapping the input
|
|
63
|
+
types does not change this choice. `dtype: nil` means the same as omitting it.
|
|
64
|
+
|
|
65
|
+
Use `dtype: Numo::SFloat` or `dtype: Numo::DFloat` to choose explicitly. These
|
|
66
|
+
classes and `nil` are the only accepted dtype values. Both inputs and any
|
|
67
|
+
constant fill are converted to the chosen type before preparing boundary
|
|
68
|
+
values or calculating. The fill value does not influence the choice of dtype.
|
|
69
|
+
|
|
70
|
+
Choose floating inputs before dividing to make kernel weights. Integer division
|
|
71
|
+
can discard fractions before Convolver sees them:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
Numo::Int16.ones(3) / 3 # => integer weights [0, 0, 0]
|
|
75
|
+
Numo::DFloat.ones(3) / 3 # => floating weights, each approximately one third
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A later dtype override cannot recover information already lost to integer
|
|
79
|
+
division or floating-point rounding. Integer inputs produce approximate floating
|
|
80
|
+
calculations, not integer results. DFloat can represent every 32-bit integer,
|
|
81
|
+
but not every 64-bit integer. Neither result type guarantees exact integer
|
|
82
|
+
convolution.
|
|
83
|
+
|
|
84
|
+
The direct path multiplies and adds in the chosen precision. The FFT path uses
|
|
85
|
+
double-precision working buffers, then returns the chosen result type. Shapes
|
|
86
|
+
and result classes agree across paths, but rounding can differ. Compare numeric
|
|
87
|
+
results with a tolerance appropriate to the data and precision.
|
|
88
|
+
|
|
89
|
+
Normal floating conversion applies, including overflow to infinity and
|
|
90
|
+
underflow. NaN and infinity are accepted, but their propagation can differ
|
|
91
|
+
between calculation paths.
|
|
92
|
+
|
|
93
|
+
## Choose output size
|
|
94
|
+
|
|
95
|
+
`mode:` controls the size of the result. In this table, `S` is the signal size
|
|
96
|
+
and `K` the kernel size along one dimension. Apply the rule to each dimension.
|
|
97
|
+
|
|
98
|
+
| Mode | Positions included | Result size |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `:valid` (default) | Only windows fully inside the stored signal | `S - K + 1` |
|
|
101
|
+
| `:same` | One output aligned with each stored signal position | `S` |
|
|
102
|
+
| `:full` | All positions with any stored-signal overlap | `S + K - 1` |
|
|
103
|
+
|
|
104
|
+
In valid mode, the kernel must fit inside the signal in every dimension. Larger
|
|
105
|
+
kernels are permitted in same and full modes. Equal numbers of dimensions are
|
|
106
|
+
still required; a one-dimensional kernel is not automatically applied to each
|
|
107
|
+
row of a two-dimensional signal.
|
|
108
|
+
|
|
109
|
+
For one-dimensional valid results, returned index `p` starts at zero:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
convolve(signal, kernel)[p] = sum_j signal[p + K - 1 - j] * kernel[j]
|
|
113
|
+
correlate(signal, kernel)[p] = sum_j signal[p + j] * kernel[j]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Here `j` runs from zero to `K - 1`. For multiple dimensions, apply the index
|
|
117
|
+
rule along every dimension and sum over all kernel positions. Convolver accepts
|
|
118
|
+
real inputs only, so correlation has no visible complex-conjugation step.
|
|
119
|
+
|
|
120
|
+
## Choose values beyond the edges
|
|
121
|
+
|
|
122
|
+
`boundary:` supplies values outside the stored signal. For a signal `a b c d`,
|
|
123
|
+
the following table shows examples immediately before and after it:
|
|
124
|
+
|
|
125
|
+
| Boundary | Before | Stored signal | After |
|
|
126
|
+
| --- | --- | --- | --- |
|
|
127
|
+
| `:constant` (default) | `k k k k` | `a b c d` | `k k k k` |
|
|
128
|
+
| `:nearest` | `a a a a` | `a b c d` | `d d d d` |
|
|
129
|
+
| `:reflect` | `d c b a` | `a b c d` | `d c b a` |
|
|
130
|
+
| `:mirror` | `d c b` | `a b c d` | `c b a` |
|
|
131
|
+
| `:wrap` | `a b c d` | `a b c d` | `a b c d` |
|
|
132
|
+
|
|
133
|
+
Reflect repeats the edge sample; mirror does not. Wrap treats the signal as
|
|
134
|
+
repeating. These rules work along every dimension, including dimensions of
|
|
135
|
+
length one and extensions wider than the stored signal.
|
|
136
|
+
|
|
137
|
+
For constant boundaries, `fill_value:` sets `k` and must be a real numeric
|
|
138
|
+
value. Omitting it uses zero. For all other boundaries, omit `fill_value:`
|
|
139
|
+
entirely: even an explicit `fill_value: 0` is rejected.
|
|
140
|
+
|
|
141
|
+
Some generated method signatures show `UNSPECIFIED_FILL`. This is Convolver's
|
|
142
|
+
internal marker for an omitted argument, not a value callers should pass. It
|
|
143
|
+
lets Convolver distinguish omission from an explicitly supplied zero.
|
|
144
|
+
|
|
145
|
+
The permitted combinations are:
|
|
146
|
+
|
|
147
|
+
| Mode | Boundary | Fill | Origin |
|
|
148
|
+
| --- | --- | --- | --- |
|
|
149
|
+
| `:valid` | `:constant` only | Omitted or zero | Zero |
|
|
150
|
+
| `:same` | Any listed boundary | Real numeric for constant; omit for others | Within the range below |
|
|
151
|
+
| `:full` | `:constant` only | Omitted or real numeric | Zero |
|
|
152
|
+
|
|
153
|
+
Mode and boundary names must be the symbols shown, not strings.
|
|
154
|
+
|
|
155
|
+
## Align the kernel
|
|
156
|
+
|
|
157
|
+
`origin:` adjusts kernel alignment in same mode. Supply an integer for all
|
|
158
|
+
dimensions, or an array containing one integer per dimension. The default is
|
|
159
|
+
zero. For a kernel dimension of length `K`:
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
anchor = floor(K / 2) + origin
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The anchor must be a kernel index: `0 <= anchor < K`. For example, a kernel of
|
|
166
|
+
length three allows origins -1, 0 and 1; length four allows -2, -1, 0 and 1.
|
|
167
|
+
Valid and full modes require zero origins.
|
|
168
|
+
|
|
169
|
+
For a same-mode output at position `i`, with boundary values supplied as above:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
convolution[i] = sum_j extended_signal[i + anchor - j] * kernel[j]
|
|
173
|
+
correlation[i] = sum_j extended_signal[i + j - anchor] * kernel[j]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
With origin zero, odd-length kernels use the same alignment for both operations.
|
|
177
|
+
For even-length kernels, correlation needs the extra boundary sample before the
|
|
178
|
+
signal, and convolution needs it after. Increasing the origin moves convolution
|
|
179
|
+
windows toward higher signal indices and correlation windows toward lower ones.
|
|
180
|
+
|
|
181
|
+
## Interpret estimates and failures
|
|
182
|
+
|
|
183
|
+
`predict_convolve_basic_time`, `predict_convolve_fft_time`,
|
|
184
|
+
`predict_correlate_basic_time` and `predict_correlate_fft_time` accept the same
|
|
185
|
+
inputs and options as the calculation methods. They return comparative cost
|
|
186
|
+
estimates, not measured elapsed times. Smaller estimates suggest less work.
|
|
187
|
+
They do not execute the convolution or allocate its result array.
|
|
188
|
+
|
|
189
|
+
The estimates account for input conversion, boundary preparation and periodic
|
|
190
|
+
kernel folding. Ranks one through three use calibrated profiles for arm64 macOS
|
|
191
|
+
and x86_64/aarch64 Linux. Other platforms and higher ranks use a general
|
|
192
|
+
heuristic. These profiles describe broad platform families, not measurements
|
|
193
|
+
of the caller's particular CPU. Automatic selection can change as estimates
|
|
194
|
+
improve.
|
|
195
|
+
|
|
196
|
+
Invalid inputs or option combinations raise `ArgumentError`. Calculations and
|
|
197
|
+
estimators reject unrepresentable planned dimensions or buffers with
|
|
198
|
+
`RangeError`. FFT checks include conservative native integer and working-buffer
|
|
199
|
+
limits. Automatic calculation can use direct execution if FFT exceeds its
|
|
200
|
+
limits and the direct path is still valid.
|
|
201
|
+
|
|
202
|
+
These checks do not reserve RAM or guarantee enough memory is available.
|
|
203
|
+
Ordinary allocation failures still raise `NoMemoryError`.
|
|
204
|
+
|
|
205
|
+
For older applications, see the [README](../README.md) sections on the version 3
|
|
206
|
+
precision migration and version 2 operation-name migration.
|
data/docs/terminology.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Convolver terminology
|
|
2
|
+
|
|
3
|
+
This glossary explains the words used in the [calculation rules](rules.md) and
|
|
4
|
+
API reference. See [README](../README.md) for installation and usage.
|
|
5
|
+
|
|
6
|
+
| Term | Meaning in Convolver |
|
|
7
|
+
| --- | --- |
|
|
8
|
+
| Signal | The input data being processed: for example, a sequence of readings or a grid of pixel values. It is the first argument. |
|
|
9
|
+
| Kernel | The second input array. Its values supply the weights multiplied with a window of signal values. |
|
|
10
|
+
| Window | The signal positions paired with the kernel to calculate one output value. A window can include values supplied by a boundary rule. |
|
|
11
|
+
| Convolution | Sliding multiplication and addition with the kernel reversed within each window. Call `convolve`; do not reverse the supplied kernel yourself. |
|
|
12
|
+
| Cross-correlation | Sliding multiplication and addition with the kernel in its stored order. Call `correlate`. It can measure agreement with a pattern; this is not a normalized correlation coefficient. |
|
|
13
|
+
| Dimension, axis, rank | A sequence has one dimension; a grid has two. An axis is one of those dimensions, and rank is their count. Rank here is not matrix rank from linear algebra. |
|
|
14
|
+
| Shape | The size along each dimension. Shape `[3, 5]` describes a grid with three rows and five columns, containing 15 values. |
|
|
15
|
+
| Scalar | A single value held in a zero-dimensional Numo array. Its shape is `[]`, unlike a one-element sequence with shape `[1]`. |
|
|
16
|
+
| Output extent | The size of the returned array along each dimension. `mode:` selects valid, same or full output. |
|
|
17
|
+
| Boundary, extension | A rule supplying values beyond the stored signal's edges. Extension does not modify the input array. |
|
|
18
|
+
| Fill value | The value supplied outside the signal for `boundary: :constant`. It defaults to zero and must be omitted for other boundaries. |
|
|
19
|
+
| Anchor, origin | The anchor is the kernel index used for same-mode alignment. The origin shifts that index from `floor(kernel_size / 2)` along each dimension. |
|
|
20
|
+
| Dtype | The class describing how array values are stored. Convolver returns `Numo::SFloat` (single precision) or `Numo::DFloat` (double precision). |
|
|
21
|
+
| Promotion | Automatic selection of a floating type from both inputs. DFloat wins if either input maps to it; otherwise SFloat is used. |
|
|
22
|
+
| Precision, rounding | Floating types retain a limited number of significant digits. Rounding replaces a value with a nearby representable value; double precision retains more digits than single precision. |
|
|
23
|
+
| Tolerance | An allowed numerical difference when comparing results. It accounts for rounding; suitable values depend on the scale of the data and the precision used. |
|
|
24
|
+
| View | An array referring to selected or rearranged values of another array, such as a slice or reversed sequence. Convolver uses the view's logical order. |
|
|
25
|
+
| Direct calculation | Computing the sliding products and sums directly. Convolver implements this path in its native extension. |
|
|
26
|
+
| FFT | Fast Fourier transform: a way to express data in frequency components. The FFT path uses transforms to calculate the same convolution or correlation, with potentially different rounding and memory use. |
|
|
27
|
+
| Working buffer | Temporary storage used during calculation. Its size and precision can differ from the returned array. |
|
|
28
|
+
| Folding | Adding kernel values that land on the same periodic position. This is preparation used for wrap boundaries, not a change to the stored input. |
|
|
29
|
+
| Relative cost, heuristic | An approximate comparison used to choose a calculation path. It is not a measured duration or a guarantee of which path will be fastest. |
|
|
30
|
+
| Native limit | A size or arithmetic limit of the underlying native implementation. Passing these checks does not guarantee that physical memory is available. |
|
data/lib/convolver/fft_limits.rb
CHANGED
|
@@ -8,7 +8,7 @@ require 'convolver/operation_shapes'
|
|
|
8
8
|
require 'convolver/signal_extension'
|
|
9
9
|
require 'convolver/fft_buffer_plan'
|
|
10
10
|
|
|
11
|
-
#
|
|
11
|
+
# @!macro convolver_overview
|
|
12
12
|
module Convolver
|
|
13
13
|
# Distinguishes an omitted fill_value keyword from an explicitly supplied
|
|
14
14
|
# value. This lets non-constant boundaries reject even an explicit zero.
|
data/lib/convolver/version.rb
CHANGED
data/lib/convolver.rb
CHANGED
|
@@ -5,7 +5,26 @@ require 'numo/pocketfft'
|
|
|
5
5
|
require 'convolver/convolver'
|
|
6
6
|
require 'convolver/version'
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# @!macro [new] convolver_overview
|
|
9
|
+
# Combine numeric sequences or grids with a kernel of weights.
|
|
10
|
+
#
|
|
11
|
+
# Start with {.convolve} for mathematical convolution or {.correlate} for
|
|
12
|
+
# cross-correlation. Both slide a window over the signal, multiply paired
|
|
13
|
+
# values and add the products. Convolution reverses the kernel within each
|
|
14
|
+
# window; correlation keeps its stored order. Pass the original kernel to
|
|
15
|
+
# either method: Convolver handles the orientation.
|
|
16
|
+
#
|
|
17
|
+
# All calculation methods return a new Numo::SFloat or Numo::DFloat array.
|
|
18
|
+
# Inputs are not modified. The automatic methods choose a calculation path;
|
|
19
|
+
# explicit direct and FFT methods are available for comparing performance.
|
|
20
|
+
#
|
|
21
|
+
# @example Compare the first complete window
|
|
22
|
+
# signal = Numo::DFloat[1, 2, 4, 8, 16]
|
|
23
|
+
# kernel = Numo::DFloat[1, 2, 3]
|
|
24
|
+
# Convolver.convolve(signal, kernel).to_a # => [11.0, 22.0, 44.0]
|
|
25
|
+
# Convolver.correlate(signal, kernel).to_a # => [17.0, 34.0, 68.0]
|
|
26
|
+
# @see file:docs/rules.md Complete input and calculation rules
|
|
27
|
+
# @see file:docs/terminology.md Terminology
|
|
9
28
|
module Convolver
|
|
10
29
|
# Maximum number of dimensions supported by the implementations.
|
|
11
30
|
MAX_RANK = 16
|
|
@@ -17,117 +36,209 @@ module Convolver
|
|
|
17
36
|
require 'convolver/operation_execution'
|
|
18
37
|
|
|
19
38
|
class << self
|
|
20
|
-
#
|
|
39
|
+
# Calculate mathematical convolution, choosing a likely faster calculation path.
|
|
21
40
|
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# Full mode permits only constant boundaries; nonconstant boundaries and
|
|
27
|
-
# nonzero origins are supported only in same mode.
|
|
41
|
+
# Each result adds the products from one signal window, with the kernel
|
|
42
|
+
# reversed within that window. By default, only complete windows are returned.
|
|
43
|
+
# Use mode: :same to keep the signal's shape, or mode: :full to include
|
|
44
|
+
# partly overlapping positions at both ends of each dimension.
|
|
28
45
|
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
46
|
+
# Inputs must be nonempty supported Numo arrays with equal numbers of
|
|
47
|
+
# dimensions, up to {MAX_RANK}. Two zero-dimensional arrays multiply directly.
|
|
48
|
+
# Both input types determine the floating result type unless dtype overrides
|
|
49
|
+
# it. See the rules below for the exact supported classes and combinations.
|
|
50
|
+
#
|
|
51
|
+
# UNSPECIFIED_FILL in the signature means the keyword was omitted. For a
|
|
52
|
+
# constant boundary this uses zero; other boundaries require omission and
|
|
53
|
+
# reject even an explicit fill_value: 0. Do not pass the internal marker.
|
|
54
|
+
#
|
|
55
|
+
# @param signal [Numo::NArray] sequence or grid to process
|
|
56
|
+
# @param kernel [Numo::NArray] weights, supplied in their original order
|
|
57
|
+
# @param mode [:valid, :same, :full] which output positions to return
|
|
32
58
|
# @param boundary [:constant, :nearest, :reflect, :mirror, :wrap]
|
|
33
|
-
#
|
|
34
|
-
# @param fill_value [Numeric]
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# @param
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# @
|
|
59
|
+
# how to supply values beyond the signal's edges
|
|
60
|
+
# @param fill_value [Numeric] real value outside a constant boundary;
|
|
61
|
+
# omission uses zero. Valid mode requires zero; other boundaries reject
|
|
62
|
+
# this keyword even when explicitly zero. The internal default marker
|
|
63
|
+
# denotes omission and is not a caller-supplied value.
|
|
64
|
+
# @param origin [Integer, Array<Integer>] shift from the kernel midpoint,
|
|
65
|
+
# shared across dimensions or one integer per dimension; same mode only
|
|
66
|
+
# permits a nonzero shift, within the kernel's index range
|
|
67
|
+
# @param dtype [Class, nil] Numo::SFloat or Numo::DFloat; nil chooses from
|
|
68
|
+
# both inputs. SFloat and 8/16-bit integers select SFloat; DFloat and
|
|
69
|
+
# 32/64-bit integers select DFloat. The wider candidate wins.
|
|
70
|
+
# @return [Numo::SFloat, Numo::DFloat] a new mathematical convolution result
|
|
42
71
|
# @raise [ArgumentError] if inputs or options are invalid
|
|
43
|
-
# @raise [RangeError] if
|
|
72
|
+
# @raise [RangeError] if no usable calculation path fits native size limits
|
|
73
|
+
# @raise [NoMemoryError] if memory allocation fails despite passing size checks
|
|
74
|
+
# @example Keep the signal size and reflect at its edges
|
|
75
|
+
# signal = Numo::DFloat[1, 2, 4, 8, 16]
|
|
76
|
+
# kernel = Numo::DFloat.ones(3) / 3
|
|
77
|
+
# result = Convolver.convolve(signal, kernel, mode: :same, boundary: :reflect)
|
|
78
|
+
# result.shape # => [5]
|
|
79
|
+
# result.to_a.map { |value| value.round(3) } # => [1.333, 2.333, 4.667, 9.333, 13.333]
|
|
80
|
+
# @see file:docs/rules.md Supported arrays, precision, modes and alignment
|
|
44
81
|
def convolve(signal, kernel, mode: :valid, boundary: :constant,
|
|
45
82
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
46
83
|
execution(:convolution, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).automatic
|
|
47
84
|
end
|
|
48
85
|
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# the
|
|
86
|
+
# Compare a signal with a kernel in its stored order using cross-correlation.
|
|
87
|
+
#
|
|
88
|
+
# Each result is the sum of paired products from one window. This is useful
|
|
89
|
+
# for matching a pattern; it is not a normalized correlation coefficient.
|
|
90
|
+
# Chooses a likely faster path, using the same input/option rules as {.convolve}.
|
|
91
|
+
# Even-length kernels have different same-mode alignment for the two operations;
|
|
92
|
+
# see the reference rules before comparing their output positions.
|
|
52
93
|
# @param (see convolve)
|
|
53
|
-
# @return [Numo::SFloat, Numo::DFloat] cross-correlation result
|
|
94
|
+
# @return [Numo::SFloat, Numo::DFloat] a new cross-correlation result
|
|
54
95
|
# @raise (see convolve)
|
|
96
|
+
# @example Compare three complete windows with an asymmetric pattern
|
|
97
|
+
# signal = Numo::DFloat[1, 2, 4, 8, 16]
|
|
98
|
+
# kernel = Numo::DFloat[1, 2, 3]
|
|
99
|
+
# Convolver.correlate(signal, kernel).to_a # => [17.0, 34.0, 68.0]
|
|
100
|
+
# @see file:docs/rules.md Complete input and calculation rules
|
|
55
101
|
def correlate(signal, kernel, mode: :valid, boundary: :constant,
|
|
56
102
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
57
103
|
execution(:correlation, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).automatic
|
|
58
104
|
end
|
|
59
105
|
|
|
60
|
-
#
|
|
106
|
+
# Calculate convolution directly from the sliding products and sums.
|
|
107
|
+
#
|
|
108
|
+
# Products and accumulation use the selected result precision. This method
|
|
109
|
+
# always uses the native direct path. For automatic selection use {.convolve}.
|
|
61
110
|
# @param (see convolve)
|
|
62
|
-
# @return [Numo::SFloat, Numo::DFloat] mathematical convolution result
|
|
63
|
-
# @raise
|
|
111
|
+
# @return [Numo::SFloat, Numo::DFloat] a new mathematical convolution result
|
|
112
|
+
# @raise [ArgumentError] if inputs or options are invalid
|
|
113
|
+
# @raise [RangeError] if direct dimensions or buffers exceed native limits
|
|
114
|
+
# @raise [NoMemoryError] if memory allocation fails despite passing size checks
|
|
115
|
+
# @example Request single-precision input conversion and results
|
|
116
|
+
# signal = Numo::DFloat[1, 2, 4]
|
|
117
|
+
# result = Convolver.convolve_basic(signal, Numo::DFloat[1, 2], dtype: Numo::SFloat)
|
|
118
|
+
# result.to_a # => [4.0, 8.0]
|
|
119
|
+
# @see file:docs/rules.md Shared options and precision rules
|
|
64
120
|
def convolve_basic(signal, kernel, mode: :valid, boundary: :constant,
|
|
65
121
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
66
122
|
execution(:convolution, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).basic
|
|
67
123
|
end
|
|
68
124
|
|
|
69
|
-
#
|
|
125
|
+
# Calculate cross-correlation directly from the sliding products and sums.
|
|
126
|
+
#
|
|
127
|
+
# Keeps the kernel in stored order and uses the selected precision for
|
|
128
|
+
# products and accumulation. For automatic selection use {.correlate}.
|
|
70
129
|
# @param (see convolve)
|
|
71
|
-
# @return [Numo::SFloat, Numo::DFloat] cross-correlation result
|
|
72
|
-
# @raise (see
|
|
130
|
+
# @return [Numo::SFloat, Numo::DFloat] a new cross-correlation result
|
|
131
|
+
# @raise (see convolve_basic)
|
|
132
|
+
# @example Use an asymmetric kernel without reversing it
|
|
133
|
+
# Convolver.correlate_basic(Numo::DFloat[1, 2, 4], Numo::DFloat[1, 2]).to_a
|
|
134
|
+
# # => [5.0, 10.0]
|
|
135
|
+
# @see file:docs/rules.md Shared options and alignment rules
|
|
73
136
|
def correlate_basic(signal, kernel, mode: :valid, boundary: :constant,
|
|
74
137
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
75
138
|
execution(:correlation, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).basic
|
|
76
139
|
end
|
|
77
140
|
|
|
78
|
-
#
|
|
141
|
+
# Calculate convolution using PocketFFT transforms.
|
|
142
|
+
#
|
|
143
|
+
# FFT working buffers use double precision for either result dtype. The
|
|
144
|
+
# returned shape and class follow the same rules as {.convolve}; rounding
|
|
145
|
+
# and propagation of non-finite values can differ from the direct path.
|
|
79
146
|
# @param (see convolve)
|
|
80
|
-
# @return [Numo::SFloat, Numo::DFloat] mathematical convolution result
|
|
81
|
-
# @raise
|
|
147
|
+
# @return [Numo::SFloat, Numo::DFloat] a new mathematical convolution result
|
|
148
|
+
# @raise [ArgumentError] if inputs or options are invalid
|
|
149
|
+
# @raise [RangeError] if FFT dimensions, buffers or arithmetic exceed native limits
|
|
150
|
+
# @raise [NoMemoryError] if memory allocation fails despite passing size checks
|
|
151
|
+
# @example Include every partly overlapping position
|
|
152
|
+
# result = Convolver.convolve_fft(Numo::DFloat[1, 2, 3], Numo::DFloat[1, 2], mode: :full)
|
|
153
|
+
# expected = Numo::DFloat[1, 4, 7, 6]
|
|
154
|
+
# (result - expected).abs.max < 1e-12 # => true
|
|
155
|
+
# @see file:docs/rules.md Shared options, precision and memory limits
|
|
82
156
|
def convolve_fft(signal, kernel, mode: :valid, boundary: :constant,
|
|
83
157
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
84
158
|
execution(:convolution, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).fft
|
|
85
159
|
end
|
|
86
160
|
|
|
87
|
-
#
|
|
161
|
+
# Calculate cross-correlation using PocketFFT transforms.
|
|
162
|
+
#
|
|
163
|
+
# Keeps the kernel in stored order. Working buffers use double precision;
|
|
164
|
+
# the returned dtype is selected from the inputs or the explicit override.
|
|
165
|
+
# Compare results with a tolerance, as for {.convolve_fft}.
|
|
88
166
|
# @param (see convolve)
|
|
89
|
-
# @return [Numo::SFloat, Numo::DFloat] cross-correlation result
|
|
90
|
-
# @raise (see
|
|
167
|
+
# @return [Numo::SFloat, Numo::DFloat] a new cross-correlation result
|
|
168
|
+
# @raise (see convolve_fft)
|
|
169
|
+
# @example Check the result with a floating-point tolerance
|
|
170
|
+
# result = Convolver.correlate_fft(Numo::DFloat[1, 2, 4], Numo::DFloat[1, 2])
|
|
171
|
+
# (result - Numo::DFloat[5, 10]).abs.max < 1e-12 # => true
|
|
172
|
+
# @see file:docs/rules.md Shared options, precision and memory limits
|
|
91
173
|
def correlate_fft(signal, kernel, mode: :valid, boundary: :constant,
|
|
92
174
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
93
175
|
execution(:correlation, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).fft
|
|
94
176
|
end
|
|
95
177
|
|
|
96
178
|
# Estimates the relative cost of {.convolve_fft}.
|
|
97
|
-
#
|
|
179
|
+
#
|
|
180
|
+
# Returns a rough comparative cost, not elapsed seconds. Includes input
|
|
181
|
+
# conversion and boundary preparation without running convolution or
|
|
182
|
+
# allocating its result. Profiles describe platform families, not a measured
|
|
183
|
+
# speed for this particular CPU. Compare with {.predict_convolve_basic_time}.
|
|
98
184
|
# @param (see convolve)
|
|
99
|
-
# @return [Float]
|
|
100
|
-
# @raise
|
|
185
|
+
# @return [Float] estimated relative cost on the selected platform profile
|
|
186
|
+
# @raise [ArgumentError] if inputs or options are invalid
|
|
187
|
+
# @raise [RangeError] if the planned FFT path exceeds native limits
|
|
188
|
+
# @example Obtain an estimate without calculating a result array
|
|
189
|
+
# cost = Convolver.predict_convolve_fft_time(Numo::DFloat.ones(32), Numo::DFloat.ones(3))
|
|
190
|
+
# cost.finite? && cost >= 0 # => true
|
|
191
|
+
# @see file:docs/rules.md Interpretation and limits of estimates
|
|
101
192
|
def predict_convolve_fft_time(signal, kernel, mode: :valid, boundary: :constant,
|
|
102
193
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
103
194
|
execution(:convolution, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).fft_time
|
|
104
195
|
end
|
|
105
196
|
|
|
106
197
|
# Estimates the relative cost of {.correlate_fft}.
|
|
107
|
-
#
|
|
198
|
+
# Returns a comparative cost without executing correlation or allocating its
|
|
199
|
+
# result. The estimate includes preparation and is not a timing measurement.
|
|
200
|
+
# Compare with {.predict_correlate_basic_time} for the same inputs/options.
|
|
108
201
|
# @param (see convolve)
|
|
109
|
-
# @return [Float]
|
|
110
|
-
# @raise (see
|
|
202
|
+
# @return [Float] estimated relative cost on the selected platform profile
|
|
203
|
+
# @raise (see predict_convolve_fft_time)
|
|
204
|
+
# @example Estimate periodic correlation work
|
|
205
|
+
# cost = Convolver.predict_correlate_fft_time(Numo::DFloat.ones(32), Numo::DFloat.ones(3),
|
|
206
|
+
# mode: :same, boundary: :wrap)
|
|
207
|
+
# cost.finite? && cost >= 0 # => true
|
|
208
|
+
# @see file:docs/rules.md Interpretation and limits of estimates
|
|
111
209
|
def predict_correlate_fft_time(signal, kernel, mode: :valid, boundary: :constant,
|
|
112
210
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
113
211
|
execution(:correlation, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).fft_time
|
|
114
212
|
end
|
|
115
213
|
|
|
116
214
|
# Estimates the relative cost of {.convolve_basic}.
|
|
117
|
-
#
|
|
215
|
+
# Returns a comparative cost without executing convolution or allocating its
|
|
216
|
+
# result. Smaller costs suggest less work, not a guaranteed elapsed time.
|
|
217
|
+
# Compare with {.predict_convolve_fft_time} for the same inputs/options.
|
|
118
218
|
# @param (see convolve)
|
|
119
|
-
# @return [Float]
|
|
120
|
-
# @raise
|
|
219
|
+
# @return [Float] estimated relative cost on the selected platform profile
|
|
220
|
+
# @raise [ArgumentError] if inputs or options are invalid
|
|
221
|
+
# @raise [RangeError] if the planned direct path exceeds native limits
|
|
222
|
+
# @example Estimate direct convolution work
|
|
223
|
+
# cost = Convolver.predict_convolve_basic_time(Numo::DFloat.ones(32), Numo::DFloat.ones(3))
|
|
224
|
+
# cost.finite? && cost >= 0 # => true
|
|
225
|
+
# @see file:docs/rules.md Interpretation and limits of estimates
|
|
121
226
|
def predict_convolve_basic_time(signal, kernel, mode: :valid, boundary: :constant,
|
|
122
227
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
123
228
|
execution(:convolution, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).basic_time
|
|
124
229
|
end
|
|
125
230
|
|
|
126
231
|
# Estimates the relative cost of {.correlate_basic}.
|
|
127
|
-
#
|
|
232
|
+
# Returns a comparative cost without executing correlation or allocating its
|
|
233
|
+
# result. The estimate includes preparation and is not a timing measurement.
|
|
234
|
+
# Compare with {.predict_correlate_fft_time} for the same inputs/options.
|
|
128
235
|
# @param (see convolve)
|
|
129
|
-
# @return [Float]
|
|
130
|
-
# @raise (see
|
|
236
|
+
# @return [Float] estimated relative cost on the selected platform profile
|
|
237
|
+
# @raise (see predict_convolve_basic_time)
|
|
238
|
+
# @example Estimate direct correlation work
|
|
239
|
+
# cost = Convolver.predict_correlate_basic_time(Numo::DFloat.ones(32), Numo::DFloat.ones(3))
|
|
240
|
+
# cost.finite? && cost >= 0 # => true
|
|
241
|
+
# @see file:docs/rules.md Interpretation and limits of estimates
|
|
131
242
|
def predict_correlate_basic_time(signal, kernel, mode: :valid, boundary: :constant,
|
|
132
243
|
fill_value: UNSPECIFIED_FILL, origin: 0, dtype: nil)
|
|
133
244
|
execution(:correlation, signal, kernel, mode:, boundary:, fill_value:, origin:, dtype:).basic_time
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: convolver
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Neil Slater
|
|
@@ -61,6 +61,8 @@ files:
|
|
|
61
61
|
- CHANGELOG.md
|
|
62
62
|
- LICENSE.txt
|
|
63
63
|
- README.md
|
|
64
|
+
- docs/rules.md
|
|
65
|
+
- docs/terminology.md
|
|
64
66
|
- ext/convolver/convolve_raw.c
|
|
65
67
|
- ext/convolver/convolve_raw.h
|
|
66
68
|
- ext/convolver/convolver.c
|