convolver 3.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e56b4c0d87d92abb3f8c79d3d11b8d41c8dcbb6d7055dce615eef07a363b0cc2
4
- data.tar.gz: 23c852764b162f082fa380e6932a8c5ad0c400c6d766579d7a087d32cd875825
3
+ metadata.gz: d27be8d916e59d307ddaef4f74bdb2d6be83fc10e8b12ee3931d5136e9f7457e
4
+ data.tar.gz: db067d222f36caa4311a2e557aad198a16514092264e2929f6ff7e4fd9005334
5
5
  SHA512:
6
- metadata.gz: 7eda50980613f1d03659465daa5b3ece647485ab38355664808497f966f232893de2133649c0e8cd9262606fde99ad3305552db27a5e719901aee6c095b2ac3d
7
- data.tar.gz: da94b103db3c1af9f735787584a757ed9683a12556879495f041a88a6f7eb178ef214d871f64e8a18aa498b090c9cec748c4c7d11c534a687099e9d2a3c15ff2
6
+ metadata.gz: 8a3f955a008e8af26f3cae3c00b25854c10497f55dac328db8b063fa4190360c6b7a0ea87e80e4ba1a5511e525108615a0ff2202b412b9b9f700cd992fa5ba1a
7
+ data.tar.gz: 810fc3b67314bb846ec8363c3fe9ae205e01eef5c10b003eaafa72a3623a27169d1667db07ec0badca20aca19ae0b233e2a0b7a7a2b4fd3a1cc0dccd29655e2c
data/CHANGELOG.md CHANGED
@@ -5,7 +5,58 @@ 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
- ## [Unreleased]
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
+
30
+ ## [4.0.0] - 2026-10-06
31
+
32
+ ### Added
33
+
34
+ - Optional `dtype: Numo::SFloat` or `dtype: Numo::DFloat` on all calculation
35
+ and estimator methods, with matching result types and genuine native double
36
+ arithmetic. Omitted or nil dtype selects precision from both operands.
37
+
38
+ ### Changed
39
+
40
+ - **Breaking, v4.0.0:** Automatically promote SFloat and 8/16-bit integer
41
+ inputs to SFloat, and DFloat and 32/64-bit integer inputs to DFloat; the
42
+ wider floating candidate wins independently of operand order.
43
+ - **Breaking:** Reject Bit, RObject, complex arrays and custom NArray subclasses,
44
+ including with an explicit floating dtype. Integer results are not supported.
45
+ - Reuse a single operation plan during automatic dispatch and account for
46
+ selected dtype and input conversion in cost estimates and buffer checks.
47
+ - Bound FFT shape search in native code and skip FFT planning when a cheap
48
+ cost bound already favors direct execution.
49
+ - Calibrate direct/FFT selection for ranks one through three on arm64 macOS
50
+ and x86_64/aarch64 Linux, including dtype, fixed setup, continuous kernel
51
+ costs, boundary indexing and periodic folding. Retain the existing heuristic
52
+ on other platforms and higher ranks.
53
+
54
+ ### Fixed
55
+
56
+ - Cast both inputs and fill to the resolved dtype before boundary preparation,
57
+ periodic folding and arithmetic, consistently across direct and FFT paths.
58
+ `dtype: Numo::SFloat` selects single-precision inputs/results, but does not
59
+ guarantee bit-for-bit version 3 results. FFT work remains double precision.
9
60
 
10
61
  ## [3.0.1] - 2026-10-04
11
62
 
@@ -133,8 +184,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
133
184
  - Updated the native extension to use the maintained Numo C API and removed the
134
185
  legacy untyped-data compatibility code.
135
186
 
136
- [Unreleased]: https://github.com/neilslater/convolver/compare/v3.0.0...HEAD
137
- [3.0.0]: https://github.com/neilslater/convolver/compare/v2.0.0...v3.0.0
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
138
191
  [2.0.0]: https://github.com/neilslater/convolver/compare/v1.0.1...v2.0.0
139
192
  [1.0.1]: https://github.com/neilslater/convolver/compare/v1.0.0...v1.0.1
140
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
  [![CI](https://github.com/neilslater/convolver/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/neilslater/convolver/actions/workflows/ci.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/convolver.svg)](https://badge.fury.io/rb/convolver)
5
5
 
6
- Convolver calculates mathematical convolution and cross-correlation between
7
- multidimensional
8
- [`Numo::NArray`](https://github.com/yoshoku/numo-narray-alt) values. Both
9
- operations support configurable output extents and signal boundary extensions.
10
- Convolver chooses between a direct native implementation for smaller inputs
11
- and a [`Numo::Pocketfft`](https://github.com/yoshoku/numo-pocketfft)-based
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,146 +18,106 @@ Add Convolver to your application's Gemfile:
19
18
  gem 'convolver'
20
19
  ```
21
20
 
22
- Then run `bundle install`, or install the gem directly with
23
- `gem install convolver`. No external FFT library is required; PocketFFT is
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
- ## Usage
25
+ ## Start with a small example
27
26
 
28
- `convolve` calculates mathematical discrete convolution. `correlate`
29
- calculates cross-correlation, following the public naming convention used by
30
- NumPy and SciPy:
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::SFloat[0.3, 0.4, 0.5]
36
- kernel = Numo::SFloat[1.3, -0.5]
34
+ signal = Numo::DFloat[1, 2, 4, 8, 16]
35
+ kernel = Numo::DFloat[1, 2, 3]
37
36
 
38
- Convolver.convolve(signal, kernel)
39
- # => Numo::SFloat#shape=[2]
40
- # [0.37, 0.45]
41
-
42
- Convolver.correlate(signal, kernel)
43
- # => Numo::SFloat#shape=[2]
44
- # [0.19, 0.27]
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]
45
39
  ```
46
40
 
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]
52
- ```
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.
53
43
 
54
- The formulas apply component-wise to multidimensional arrays. Correlation
55
- conventionally conjugates the second operand, although Convolver's current
56
- single-precision real input contract makes conjugation invisible.
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.
57
48
 
58
- With no keywords, the signal and kernel must have the same rank, the kernel
59
- must be no larger than the signal in any dimension, and only positions with
60
- complete overlap are returned. Inputs are converted to single-precision floats
61
- internally and results are returned as `Numo::SFloat`. Supplying
62
- `Numo::SFloat` inputs avoids conversion in the direct implementation.
49
+ ## Keep the input size or include the edges
63
50
 
64
- The automatic, direct, and FFT implementations are available for both
65
- operations:
66
-
67
- ```ruby
68
- Convolver.convolve(signal, kernel)
69
- Convolver.convolve_basic(signal, kernel)
70
- 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:
71
53
 
72
- Convolver.correlate(signal, kernel)
73
- Convolver.correlate_basic(signal, kernel)
74
- Convolver.correlate_fft(signal, kernel)
75
- ```
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` |
76
59
 
77
- Every calculation method accepts the same options:
60
+ For example, a centered moving average can keep the input size and reflect
61
+ values at the edges:
78
62
 
79
63
  ```ruby
80
- Convolver.convolve(signal, kernel,
81
- mode: :same,
82
- boundary: :reflect,
83
- origin: 0)
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]
84
69
  ```
85
70
 
86
- ### Output modes
87
-
88
- `mode:` controls the returned extent independently in each dimension:
89
-
90
- | Mode | Meaning | Result size |
91
- | --- | --- | --- |
92
- | `:valid` | Kernel overlaps the stored signal completely | `S - K + 1` |
93
- | `:same` | One result aligned with each stored signal position | `S` |
94
- | `:full` | Every kernel position with any stored-signal overlap | `S + K - 1` |
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.
95
75
 
96
- `:valid` is the default and accepts only the default `boundary: :constant`,
97
- `fill_value: 0.0`, and `origin: 0`. `:full` supports constant extension only.
98
- `:same` supports every boundary described below. Kernels larger than the signal
99
- are supported by `:same` and `:full`, but not by `:valid`. `mode:` and
100
- `boundary:` accept only the symbols listed here.
76
+ The [calculation rules](docs/rules.md) show each boundary, allowed option
77
+ combinations, and how `origin:` aligns odd- and even-length kernels.
101
78
 
102
- ### Boundary extension
79
+ ## Choose precision and calculation path
103
80
 
104
- For a one-dimensional signal `a b c d`, `boundary:` selects values outside the
105
- stored signal:
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:
106
84
 
107
- | Boundary | Extended sequence |
108
- | --- | --- |
109
- | `:constant` | `k k k k | a b c d | k k k k` |
110
- | `:nearest` | `a a a a | a b c d | d d d d` |
111
- | `:reflect` | `d c b a | a b c d | d c b a` |
112
- | `:mirror` | `d c b | a b c d | c b a` |
113
- | `:wrap` | `a b c d | a b c d | a b c d` |
114
-
115
- `fill_value:` sets `k` for `:constant` and defaults to zero. It must not be
116
- passed with another boundary. `:reflect` repeats the edge sample; `:mirror`
117
- does not. All boundary modes work across every dimension, including
118
- length-one axes and extensions wider than the stored signal.
119
-
120
- ### Kernel origin and alignment
121
-
122
- `origin:` shifts the stored-kernel anchor for `:same`. It accepts one integer
123
- applied to every dimension or an array with one integer per dimension. For a
124
- kernel dimension of length `K`:
125
-
126
- ```text
127
- anchor = floor(K / 2) + origin
128
-
129
- correlation[i] = sum_j extended_signal[i + j - anchor] * kernel[j]
130
- convolution[i] = sum_j extended_signal[i + anchor - j] * kernel[j]
85
+ ```ruby
86
+ signal = Numo::DFloat[1, 2, 4]
87
+ kernel = Numo::DFloat[1, 2]
88
+ Convolver.convolve(signal, kernel, dtype: Numo::SFloat).class # => Numo::SFloat
131
89
  ```
132
90
 
133
- The anchor must remain within the kernel. Correlation pads `anchor` samples
134
- before the signal and `K - 1 - anchor` after it; convolution swaps those
135
- widths. Odd centered kernels therefore align alike. For an even centered
136
- kernel, correlation puts the extra sample before the signal and convolution
137
- puts it after the signal. Positive origins move correlation toward lower signal
138
- indices and convolution toward higher signal indices.
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.
139
95
 
140
- Nonzero origins are supported only for `:same`; `:valid` and `:full` require
141
- zero.
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.
142
102
 
143
- ### Estimators
103
+ ## Reference documentation
144
104
 
145
- The estimator methods accept and validate the same options as their calculation
146
- families:
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.
147
108
 
148
- ```ruby
149
- Convolver.predict_convolve_basic_time(signal, kernel, mode: :same, boundary: :nearest)
150
- Convolver.predict_convolve_fft_time(signal, kernel, mode: :same, boundary: :wrap)
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`.
151
112
 
152
- Convolver.predict_correlate_basic_time(signal, kernel, mode: :same, boundary: :nearest)
153
- Convolver.predict_correlate_fft_time(signal, kernel, mode: :same, boundary: :wrap)
154
- ```
113
+ ### Migrating from version 3
155
114
 
156
- Calculations and estimators reject unrepresentable buffer sizes with `RangeError`
157
- before allocation. FFT planning also checks conservative PocketFFT integer and
158
- work-buffer limits, including full complex staging for real inverse transforms.
159
- Automatic selection uses direct calculation when FFT exceeds its limits and the
160
- direct path remains valid. These checks do not reserve memory; ordinary allocator
161
- exhaustion still raises `NoMemoryError`.
115
+ Version 4 changes default result types and values: DFloat and 32/64-bit integer
116
+ inputs now select DFloat. Pass `dtype: Numo::SFloat` to request single-precision
117
+ inputs and results. This retains the version 3 result type, but does not promise
118
+ identical numerical results: version 4 consistently casts both inputs before
119
+ processing, whereas version 3's direct and FFT paths could round differently.
120
+ The input-class restrictions listed above also apply with a dtype override.
162
121
 
163
122
  ### Migrating from version 2
164
123
 
@@ -198,8 +157,9 @@ bundle exec rake docs:check
198
157
  The Ruby specs exercise both the Ruby API and native extension and enforce 95%
199
158
  line and branch coverage for the Ruby library. Dependency auditing refreshes
200
159
  the advisory database and requires network access. The documentation check
201
- rejects YARD warnings and undocumented public API objects; private implementation
202
- classes are marked `@private`. Additional native-code checks are available:
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:
203
163
 
204
164
  ```sh
205
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.
@@ -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. |