convolver 0.4.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,166 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'helpers'
4
-
5
- describe Convolver do
6
- describe '#convolve_fftw3' do
7
- it 'works like the example in the README' do
8
- a = NArray[0.3, 0.4, 0.5]
9
- b = NArray[1.3, -0.5]
10
- c = described_class.convolve_fftw3(a, b)
11
- expect(c).to be_narray_like NArray[0.19, 0.27]
12
- end
13
-
14
- it 'convolves 1D arrays with a variety of signal and kernel lengths' do
15
- a = NArray[0.3]
16
- b = NArray[-0.7]
17
- c = described_class.convolve_fftw3(a, b)
18
- expect(c).to be_narray_like NArray[-0.21]
19
-
20
- a = NArray[0.3, 0.4, 0.5, 0.2]
21
- b = NArray[-0.7]
22
- c = described_class.convolve_fftw3(a, b)
23
- expect(c).to be_narray_like NArray[-0.21, -0.28, -0.35, -0.14]
24
-
25
- a = NArray[0.3, 0.4, 0.5, 0.2]
26
- b = NArray[1.1, -0.7]
27
- c = described_class.convolve_fftw3(a, b)
28
- expect(c).to be_narray_like NArray[0.05, 0.09, 0.41]
29
-
30
- a = NArray[0.3, 0.4, 0.5, 0.2]
31
- b = NArray[1.1, -0.7, -0.2]
32
- c = described_class.convolve_fftw3(a, b)
33
- expect(c).to be_narray_like NArray[-0.05, 0.05]
34
-
35
- a = NArray[0.3, 0.4, 0.5, 0.2, 0.6]
36
- b = NArray[1.1, -0.7]
37
- c = described_class.convolve_fftw3(a, b)
38
- expect(c).to be_narray_like NArray[0.05, 0.09, 0.41, -0.2]
39
-
40
- a = NArray[0.3, 0.4, 0.5, 0.2, 0.6]
41
- b = NArray[1.1, -0.7, 2.1]
42
- c = described_class.convolve_fftw3(a, b)
43
- expect(c).to be_narray_like NArray[1.1, 0.51, 1.67]
44
-
45
- a = NArray[0.3, 0.4, 0.5, 0.2, 0.6]
46
- b = NArray[0.6, -0.5, -0.4, 0.7]
47
- c = described_class.convolve_fftw3(a, b)
48
- expect(c).to be_narray_like NArray[-0.08, 0.33]
49
- end
50
-
51
- it 'calculates a 2D convolution' do
52
- a = NArray[[0.3, 0.4, 0.5], [0.6, 0.8, 0.2], [0.9, 1.0, 0.1]]
53
- b = NArray[[1.2, -0.5], [0.5, -1.3]]
54
- c = described_class.convolve_fftw3(a, b)
55
- expect(c).to be_narray_like NArray[[-0.58, 0.37], [-0.53, 1.23]]
56
- end
57
-
58
- it 'calculates a 3D convolution' do
59
- # 5x4x3
60
- a = NArray[
61
- [[1.0, 0.6, 1.1, 0.2, 0.9], [1.0, 0.7, 0.8, 1.0, 1.0], [0.2, 0.6, 0.1, 0.2, 0.5],
62
- [0.5, 0.9, 0.2, 0.1, 0.6]],
63
- [[0.4, 0.9, 0.4, 0.0, 0.6], [0.2, 1.1, 0.2, 0.4, 0.1], [0.4, 0.2, 0.5, 0.8, 0.7],
64
- [0.1, 0.9, 0.7, 0.1, 0.3]],
65
- [[0.8, 0.6, 1.0, 0.1, 0.4], [0.3, 0.8, 0.6, 0.7, 1.1], [0.9, 1.0, 0.3, 0.4, 0.6],
66
- [0.2, 0.5, 0.4, 0.7, 0.2]]
67
- ]
68
-
69
- # 3x3x3
70
- b = NArray[
71
- [[-0.9, 1.2, 0.8], [0.9, 0.1, -0.5], [1.1, 0.1, -1.1]],
72
- [[-0.2, -1.0, 1.4], [-1.4, 0.0, 1.3], [0.3, 1.0, -0.5]],
73
- [[0.6, 0.0, 0.7], [-0.7, 1.1, 1.2], [1.3, 0.7, 0.0]]
74
- ]
75
-
76
- # Should be 3x2x1
77
- c = described_class.convolve_fftw3(a, b)
78
- expect(c).to be_narray_like NArray[[[5.51, 3.04, 4.3], [3.04, 6.31, 3.87]]]
79
- end
80
-
81
- it 'calculates a 4D convolution' do
82
- # 3x4x5x3
83
- a = NArray[
84
- [[[0.5, 0.4, 0.9], [0.1, 0.9, 0.8], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]],
85
- [[0.0, 0.4, 0.0], [0.2, 0.3, 0.8], [0.6, 0.3, 0.2], [0.7, 0.4, 0.3]],
86
- [[0.3, 0.3, 0.1], [0.6, 0.9, 0.4], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]],
87
- [[0.0, 0.4, 0.0], [0.2, 0.3, 0.8], [0.6, 0.3, 0.2], [0.7, 0.4, 0.3]],
88
- [[0.3, 0.3, 0.1], [0.6, 0.9, 0.4], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]]],
89
- [[[0.5, 0.4, 0.9], [0.1, 0.9, 0.8], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]],
90
- [[0.0, 0.4, 0.0], [0.2, 0.3, 0.8], [0.6, 0.3, 0.2], [0.7, 0.4, 0.3]],
91
- [[0.3, 0.3, 0.1], [0.6, 0.9, 0.4], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]],
92
- [[0.0, 0.4, 0.0], [0.2, 0.3, 0.8], [0.6, 0.3, 0.2], [0.7, 0.4, 0.3]],
93
- [[0.3, 0.3, 0.1], [0.6, 0.9, 0.4], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]]],
94
- [[[0.5, 0.4, 0.9], [0.1, 0.9, 0.8], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]],
95
- [[0.0, 0.4, 0.0], [0.2, 0.3, 0.8], [0.6, 0.3, 0.2], [0.7, 0.4, 0.3]],
96
- [[0.3, 0.3, 0.1], [0.6, 0.9, 0.4], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]],
97
- [[0.0, 0.4, 0.0], [0.2, 0.3, 0.8], [0.6, 0.3, 0.2], [0.7, 0.4, 0.3]],
98
- [[0.3, 0.3, 0.1], [0.6, 0.9, 0.4], [0.4, 0.0, 0.1], [0.8, 0.3, 0.4]]] ]
99
-
100
- # 2x3x3x2
101
- b = NArray[ [
102
- [[1.1, 0.6], [1.2, 0.6], [0.8, 0.1]], [[-0.4, 0.8], [0.5, 0.4], [1.2, 0.2]],
103
- [[0.8, 0.2], [0.5, 0.0], [1.4, 1.3]]
104
- ],
105
- [[[1.1, 0.6], [1.2, 0.6], [0.8, 0.1]], [[-0.4, 0.8], [0.5, 0.4], [1.2, 0.2]],
106
- [[0.8, 0.2], [0.5, 0.0], [1.4, 1.3]]] ]
107
-
108
- # Should be 2x2x3x2
109
- c = described_class.convolve_fftw3(a, b)
110
- expect(c).to be_narray_like NArray[
111
- [[[8.5, 8.2], [11.34, 9.68]], [[7.68, 6.56], [11.24, 7.16]], [[9.14, 6.54], [12.44, 9.2]]],
112
- [[[8.5, 8.2], [11.34, 9.68]], [[7.68, 6.56], [11.24, 7.16]], [[9.14, 6.54], [12.44, 9.2]]]
113
- ]
114
- end
115
-
116
- describe 'compared with #convolve' do
117
- it 'produces same results for 1D arrays' do
118
- (1..30).each do |signal_length|
119
- (1..signal_length).each do |kernel_length|
120
- signal = NArray.sfloat(signal_length).random
121
- kernel = NArray.sfloat(kernel_length).random
122
- expect_result = described_class.convolve_basic(signal, kernel)
123
- got_result = described_class.convolve_fftw3(signal, kernel)
124
- expect(got_result).to be_narray_like expect_result
125
- end
126
- end
127
- end
128
-
129
- it 'produces same results for 2D arrays' do
130
- (3..10).each do |signal_x|
131
- ((signal_x - 2)..(signal_x + 2)).each do |signal_y|
132
- (1..signal_x).each do |kernel_x|
133
- (1..signal_y).each do |kernel_y|
134
- signal = NArray.sfloat(signal_x, signal_y).random
135
- kernel = NArray.sfloat(kernel_x, kernel_y).random
136
- expect_result = described_class.convolve_basic(signal, kernel)
137
- got_result = described_class.convolve_fftw3(signal, kernel)
138
- expect(got_result).to be_narray_like expect_result
139
- end
140
- end
141
- end
142
- end
143
- end
144
-
145
- it 'produces same results for 3D arrays' do
146
- (3..5).each do |signal_x|
147
- ((signal_x - 2)..(signal_x + 2)).each do |signal_y|
148
- ((signal_x - 2)..(signal_x + 2)).each do |signal_z|
149
- (1..signal_x).each do |kernel_x|
150
- (1..signal_y).each do |kernel_y|
151
- (1..signal_z).each do |kernel_z|
152
- signal = NArray.sfloat(signal_x, signal_y, signal_z).random
153
- kernel = NArray.sfloat(kernel_x, kernel_y, kernel_z).random
154
- expect_result = described_class.convolve_basic(signal, kernel)
155
- got_result = described_class.convolve_fftw3(signal, kernel)
156
- expect(got_result).to be_narray_like expect_result
157
- end
158
- end
159
- end
160
- end
161
- end
162
- end
163
- end
164
- end
165
- end
166
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'helpers'
4
-
5
- describe Convolver do
6
- describe '#convolve' do
7
- it 'works like the example in the README' do
8
- a = NArray[0.3, 0.4, 0.5]
9
- b = NArray[1.3, -0.5]
10
- c = described_class.convolve(a, b)
11
- expect(c).to be_narray_like NArray[0.19, 0.27]
12
- end
13
-
14
- it 'processes convolutions of different sizes' do
15
- # The variety here is to ensure all branches of optimisation algorithm
16
- # are covered
17
- [10, 30, 60, 90, 100, 120, 130, 150, 175, 200].each do |asize|
18
- [5, 10, 12, 15, 20, 30, 40, 50].each do |bsize|
19
- next unless bsize < asize
20
-
21
- a = NArray.sfloat(asize, asize).random
22
- b = NArray.sfloat(bsize, bsize).random
23
- c = described_class.convolve(a, b)
24
-
25
- # We should always match output of convolve_basic irrespective
26
- # of what the optimal choice of algorithm is (larger error allowed here due to rounding)
27
- expect_result = described_class.convolve_basic(a, b)
28
- expect(c).to be_narray_like(expect_result, 1e-6)
29
- end
30
- end
31
- end
32
-
33
- it 'chooses #convolve_basic for small inputs' do
34
- a = NArray.sfloat(50, 50).random
35
- b = NArray.sfloat(10, 10).random
36
- allow(described_class).to receive(:convolve_basic)
37
- allow(described_class).to receive(:convolve_fftw3)
38
- described_class.convolve(a, b)
39
- expect(described_class).to have_received(:convolve_basic).once
40
- expect(described_class).not_to have_received(:convolve_fftw3)
41
- end
42
-
43
- it 'chooses #convolve_fftw3 for large inputs' do
44
- a = NArray.sfloat(500, 500).random
45
- b = NArray.sfloat(100, 100).random
46
- allow(described_class).to receive(:convolve_fftw3)
47
- allow(described_class).to receive(:convolve_basic)
48
- described_class.convolve(a, b)
49
- expect(described_class).to have_received(:convolve_fftw3).once
50
- expect(described_class).not_to have_received(:convolve_basic)
51
- end
52
- end
53
- end
data/spec/helpers.rb DELETED
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # convolver/spec/helpers.rb
4
- require 'simplecov'
5
- SimpleCov.start
6
-
7
- require 'convolver'
8
-
9
- # Matcher compares NArrays numerically
10
- RSpec::Matchers.define :be_narray_like do |expected_narray, mse = 1e-9|
11
- match do |given|
12
- @error = nil
13
- if !given.is_a?(NArray)
14
- @error = 'Wrong class.'
15
- elsif given.shape != expected_narray.shape
16
- @error = 'Shapes are different.'
17
- else
18
- d = given - expected_narray
19
- difference = (d * d).sum / d.size
20
- @error = "Numerical difference with mean square error #{difference}" if difference > mse
21
- end
22
- @given = given.clone
23
-
24
- @expected = expected_narray.clone if @error
25
-
26
- !@error
27
- end
28
-
29
- failure_message do
30
- "NArray does not match supplied example. #{@error}
31
- Expected: #{@expected.inspect}
32
- Got: #{@given.inspect}"
33
- end
34
-
35
- failure_message_when_negated do
36
- "NArray is too close to unwanted example.
37
- Unwanted: #{@given.inspect}"
38
- end
39
-
40
- description do |_given, _expected|
41
- 'numerically very close to example'
42
- end
43
- end