fftw3-ruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 50798c6924b8398dfcd52f1dfe1ee43531fa523b3e15ae4d72ab06c07d90121d
4
+ data.tar.gz: a7d75f44a6066629ea627b166137e1043871abb65479687685777d18ab3e58bc
5
+ SHA512:
6
+ metadata.gz: 98ecc76de7b79206228b602070453d7b8db76c523e55ab633a74028c403f079ab79ec54d1128c8e71b236c15cb09a0233b91d8afcdd790dfb1b2a7d8373bf66f
7
+ data.tar.gz: 8526e3eeec9352cccb66149fd57156903c510e6bbd7e372320c711d16e40de99bb81a17fc199cb8afae8103ed654e311a5f06628fe4101fb6c6a1e8e56363f89
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Yudai Takada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,399 @@
1
+ # FFTW3-Ruby
2
+
3
+ Ruby FFI bindings for [FFTW3](http://www.fftw.org/) (Fastest Fourier Transform in the West).
4
+
5
+ The gem exposes the FFTW planning and execution APIs for complex DFT, real-to-complex and complex-to-real transforms, real-to-real transforms, the advanced "many" interface, guru and guru64 planners, wisdom import/export, thread control, and runtime metadata.
6
+
7
+ ## Requirements
8
+
9
+ - Ruby 3.1+
10
+ - FFTW 3.3.x shared libraries installed on the system
11
+
12
+ ### Installing FFTW3
13
+
14
+ Ubuntu / Debian:
15
+
16
+ ```bash
17
+ sudo apt-get install libfftw3-dev
18
+ ```
19
+
20
+ macOS (Homebrew):
21
+
22
+ ```bash
23
+ brew install fftw
24
+ ```
25
+
26
+ ## Installation
27
+
28
+ Add the gem to your Gemfile:
29
+
30
+ ```ruby
31
+ gem "fftw3-ruby"
32
+ ```
33
+
34
+ Then install dependencies:
35
+
36
+ ```bash
37
+ bundle install
38
+ ```
39
+
40
+ ## Precision Support
41
+
42
+ Runtime precision support depends on which FFTW libraries are installed.
43
+
44
+ ```ruby
45
+ require "fftw3"
46
+
47
+ FFTW3.available_precisions
48
+ FFTW3.double_available?
49
+ FFTW3.float_available?
50
+ FFTW3.long_double_available?
51
+ FFTW3.quad_available?
52
+ ```
53
+
54
+ Notes:
55
+
56
+ - Plan creation is available for any precision whose FFTW library can be loaded.
57
+ - `FFTW3::AlignedMemory#read` and `#write` currently support `:double`, `:float`, and `:long_double`.
58
+ - `:quad` library availability can be detected with `FFTW3.quad_available?`, but high-level buffer read/write helpers are not currently provided for quad buffers.
59
+
60
+ ## Core Types
61
+
62
+ ### `FFTW3::AlignedMemory`
63
+
64
+ Aligned buffers allocated with FFTW's allocator.
65
+
66
+ ```ruby
67
+ require "fftw3"
68
+
69
+ input = FFTW3::AlignedMemory.new(8, type: :complex, precision: :double)
70
+ input.write(Array.new(8) { |i| Complex(i, -i) })
71
+
72
+ input.pointer
73
+ input.read
74
+ input.free!
75
+ ```
76
+
77
+ Options:
78
+
79
+ - `type:` accepts `:complex` or `:real`
80
+ - `precision:` accepts `:double`, `:float`, `:long_double`, or `:quad`
81
+
82
+ ### `FFTW3::Plan`
83
+
84
+ Factory methods return `FFTW3::Plan` instances. A plan can be executed in-place with the buffers it was created with, or with compatible alternate buffers via the new-array execute helpers.
85
+
86
+ ### `FFTW3::Threads`
87
+
88
+ Wrapper around FFTW thread initialization, planner thread count, optional planner locking, and the runtime thread callback hook.
89
+
90
+ ### `FFTW3::Wisdom`
91
+
92
+ Import and export FFTW wisdom through strings, files, and IO callbacks.
93
+
94
+ ### `FFTW3::Utils`
95
+
96
+ Small wrappers for FFTW global utility functions such as `cleanup`, `set_timelimit`, and `alignment_of`.
97
+
98
+ ## Quick Start
99
+
100
+ ### Basic 1D Complex DFT
101
+
102
+ ```ruby
103
+ require "fftw3"
104
+
105
+ n = 8
106
+ input = FFTW3::AlignedMemory.new(n, type: :complex, precision: :double)
107
+ output = FFTW3::AlignedMemory.new(n, type: :complex, precision: :double)
108
+
109
+ data = (0...n).map { |i| Complex(Math.sin(2 * Math::PI * i / n), 0.0) }
110
+ input.write(data)
111
+
112
+ plan = FFTW3::Plan.dft_1d(
113
+ n,
114
+ input,
115
+ output,
116
+ direction: :forward,
117
+ flags: [:estimate]
118
+ )
119
+
120
+ plan.execute
121
+ result = output.read
122
+
123
+ puts result.map { |c| "(%.4f, %.4f)" % [c.real, c.imaginary] }
124
+
125
+ plan.destroy!
126
+ input.free!
127
+ output.free!
128
+ ```
129
+
130
+ ### Real-to-Complex
131
+
132
+ ```ruby
133
+ require "fftw3"
134
+
135
+ n = 16
136
+ input = FFTW3::AlignedMemory.new(n, type: :real)
137
+ output = FFTW3::AlignedMemory.new((n / 2) + 1, type: :complex)
138
+
139
+ input.write(n.times.map { |i| Math.sin(2 * Math::PI * i / n) })
140
+
141
+ plan = FFTW3::Plan.dft_r2c_1d(n, input, output)
142
+ plan.execute
143
+
144
+ result = output.read
145
+ ```
146
+
147
+ ### New-array Execute
148
+
149
+ ```ruby
150
+ require "fftw3"
151
+
152
+ n = 8
153
+ input_a = FFTW3::AlignedMemory.new(n, type: :complex)
154
+ output_a = FFTW3::AlignedMemory.new(n, type: :complex)
155
+ input_b = FFTW3::AlignedMemory.new(n, type: :complex)
156
+ output_b = FFTW3::AlignedMemory.new(n, type: :complex)
157
+
158
+ input_a.write(Array.new(n) { |i| Complex(i, 0.0) })
159
+ input_b.write(Array.new(n) { |i| Complex(0.0, i) })
160
+
161
+ plan = FFTW3::Plan.dft_1d(n, input_a, output_a, direction: :forward)
162
+
163
+ # Reuse the same plan with different buffers of the same shape.
164
+ plan.execute_dft(input_b, output_b)
165
+
166
+ plan.destroy!
167
+ input_a.free!
168
+ output_a.free!
169
+ input_b.free!
170
+ output_b.free!
171
+ ```
172
+
173
+ ## Threading
174
+
175
+ ### Planner Thread Count
176
+
177
+ ```ruby
178
+ require "fftw3"
179
+
180
+ n = 1024
181
+ input = FFTW3::AlignedMemory.new(n, type: :complex)
182
+ output = FFTW3::AlignedMemory.new(n, type: :complex)
183
+
184
+ FFTW3::Threads.init
185
+ FFTW3::Threads.plan_with_nthreads(4)
186
+
187
+ plan = FFTW3::Plan.dft_1d(n, input, output, direction: :forward, flags: [:measure])
188
+ plan.execute
189
+
190
+ FFTW3::Threads.planner_nthreads
191
+ plan.destroy!
192
+ input.free!
193
+ output.free!
194
+ FFTW3::Threads.cleanup
195
+ ```
196
+
197
+ ### Planner Locking
198
+
199
+ ```ruby
200
+ require "fftw3"
201
+
202
+ FFTW3::Threads.init
203
+ FFTW3::Threads.make_planner_thread_safe
204
+ FFTW3::Threads.cleanup
205
+ ```
206
+
207
+ `make_planner_thread_safe` returns `nil` when the linked FFTW build does not expose that function.
208
+
209
+ ### Custom Thread Backend Callback
210
+
211
+ `threads_set_callback` is optional in FFTW. Check support before using it, and set it before creating plans.
212
+
213
+ ```ruby
214
+ require "fftw3"
215
+
216
+ if FFTW3::Threads.set_callback_supported?
217
+ marker = FFI::MemoryPointer.new(:int)
218
+ marker.write_int(7)
219
+
220
+ FFTW3::Threads.set_callback(data: marker) do |work, jobdata, elsize, njobs, data_ptr|
221
+ njobs.times do |index|
222
+ work.call(jobdata + (elsize * index))
223
+ end
224
+ end
225
+
226
+ # Reset to the default FFTW backend.
227
+ FFTW3::Threads.set_callback(nil)
228
+ end
229
+ ```
230
+
231
+ ## Wisdom
232
+
233
+ ### String and File APIs
234
+
235
+ ```ruby
236
+ require "fftw3"
237
+
238
+ wisdom = FFTW3::Wisdom.export_to_string
239
+ FFTW3::Wisdom.import_from_string(wisdom)
240
+
241
+ FFTW3::Wisdom.export_to_file("wisdom.fftw")
242
+ FFTW3::Wisdom.import_from_file("wisdom.fftw")
243
+ ```
244
+
245
+ ### IO Callback APIs
246
+
247
+ ```ruby
248
+ require "fftw3"
249
+ require "stringio"
250
+
251
+ io = StringIO.new
252
+ FFTW3::Wisdom.export_to_io(io)
253
+ FFTW3::Wisdom.import_from_io(StringIO.new(io.string))
254
+ ```
255
+
256
+ ### System Wisdom
257
+
258
+ ```ruby
259
+ require "fftw3"
260
+
261
+ FFTW3::Wisdom.import_system
262
+ FFTW3::Wisdom.forget!
263
+ ```
264
+
265
+ ## Runtime Metadata and Utilities
266
+
267
+ ```ruby
268
+ require "fftw3"
269
+
270
+ input = FFTW3::AlignedMemory.new(8, type: :complex)
271
+
272
+ FFTW3.version
273
+ FFTW3.compiler
274
+ FFTW3.codelet_optimizations
275
+
276
+ FFTW3::Utils.set_timelimit(0.25)
277
+ FFTW3::Utils.alignment_of(input.pointer)
278
+ FFTW3::Utils.cleanup
279
+ input.free!
280
+ ```
281
+
282
+ ## API Reference
283
+
284
+ ### Top-level `FFTW3`
285
+
286
+ | Method | Description |
287
+ |--------|-------------|
288
+ | `available_precisions` | Returns the precisions whose FFTW libraries can be loaded |
289
+ | `double_available?` / `float_available?` / `long_double_available?` / `quad_available?` | Per-precision availability checks |
290
+ | `version` | Linked FFTW version string |
291
+ | `compiler` | Linked FFTW compiler string |
292
+ | `codelet_optimizations` | Linked FFTW codelet optimization string |
293
+
294
+ ### `FFTW3::Plan` Factory Methods
295
+
296
+ | Method group | Methods |
297
+ |-------------|---------|
298
+ | Complex DFT | `dft_1d`, `dft_2d`, `dft_3d`, `dft` |
299
+ | Real-to-complex | `dft_r2c_1d`, `dft_r2c_2d`, `dft_r2c_3d`, `dft_r2c` |
300
+ | Complex-to-real | `dft_c2r_1d`, `dft_c2r_2d`, `dft_c2r_3d`, `dft_c2r` |
301
+ | Real-to-real | `r2r_1d`, `r2r_2d`, `r2r_3d`, `r2r` |
302
+ | Advanced / batched | `many_dft`, `many_dft_r2c`, `many_dft_c2r`, `many_r2r` |
303
+ | Guru | `guru_dft`, `guru_split_dft`, `guru_dft_r2c`, `guru_split_dft_r2c`, `guru_dft_c2r`, `guru_split_dft_c2r`, `guru_r2r` |
304
+ | Guru64 | `guru64_dft`, `guru64_split_dft`, `guru64_dft_r2c`, `guru64_split_dft_r2c`, `guru64_dft_c2r`, `guru64_split_dft_c2r`, `guru64_r2r` |
305
+
306
+ Notes:
307
+
308
+ - `dft_*` and `many_dft` use `direction:`.
309
+ - `guru_dft` and `guru64_dft` use `sign:`.
310
+ - Guru and guru64 dimension arrays use hashes shaped like `{ n:, is:, os: }`.
311
+
312
+ ### `FFTW3::Plan` Instance Methods
313
+
314
+ | Method | Description |
315
+ |--------|-------------|
316
+ | `execute` | Execute with the buffers used to create the plan |
317
+ | `execute_dft` | New-array execute for complex DFT |
318
+ | `execute_dft_r2c` | New-array execute for real-to-complex DFT |
319
+ | `execute_dft_c2r` | New-array execute for complex-to-real DFT |
320
+ | `execute_r2r` | New-array execute for real-to-real transforms |
321
+ | `execute_split_dft` | New-array execute for split-complex guru DFT |
322
+ | `execute_split_dft_r2c` | New-array execute for split real-to-complex guru DFT |
323
+ | `execute_split_dft_c2r` | New-array execute for split complex-to-real guru DFT |
324
+ | `flops` | Returns `{ add:, mul:, fma: }` |
325
+ | `cost` | FFTW plan cost |
326
+ | `estimate_cost` | FFTW estimated plan cost |
327
+ | `to_s` / `description` | String representation of the plan |
328
+ | `print(io = $stdout)` | Write the plan description to an IO object |
329
+ | `destroy!` | Destroy the underlying FFTW plan |
330
+
331
+ ### `FFTW3::Threads`
332
+
333
+ | Method | Description |
334
+ |--------|-------------|
335
+ | `init` | Initialize FFTW thread support |
336
+ | `plan_with_nthreads(n)` | Set planner and execution thread count |
337
+ | `cleanup` | Release FFTW thread state |
338
+ | `planner_nthreads` | Read configured thread count when supported |
339
+ | `make_planner_thread_safe` | Enable FFTW's optional planner lock when supported |
340
+ | `set_callback_supported?` | Check whether `threads_set_callback` is available |
341
+ | `set_callback(callback = nil, data: nil, &block)` | Install or clear FFTW's runtime threading callback |
342
+
343
+ ### `FFTW3::Wisdom`
344
+
345
+ | Method | Description |
346
+ |--------|-------------|
347
+ | `export_to_string` / `import_from_string` | Wisdom through Ruby strings |
348
+ | `export_to_file` / `import_from_file` | Wisdom through filesystem paths |
349
+ | `export_to_io` / `import_from_io` | Wisdom through Ruby IO callbacks |
350
+ | `import_system` | Best-effort import from the system wisdom store |
351
+ | `forget!` | Clear loaded wisdom |
352
+
353
+ ### `FFTW3::Utils`
354
+
355
+ | Method | Description |
356
+ |--------|-------------|
357
+ | `cleanup` | Call FFTW global cleanup |
358
+ | `set_timelimit(seconds)` | Set the FFTW planner time limit |
359
+ | `alignment_of(pointer)` | Query FFTW's alignment classification for a pointer |
360
+
361
+ ### Constants
362
+
363
+ Planner flags:
364
+
365
+ - `FFTW3::ESTIMATE`
366
+ - `FFTW3::MEASURE`
367
+ - `FFTW3::PATIENT`
368
+ - `FFTW3::EXHAUSTIVE`
369
+ - `FFTW3::PRESERVE_INPUT`
370
+ - `FFTW3::DESTROY_INPUT`
371
+ - `FFTW3::WISDOM_ONLY`
372
+ - Additional exported flags such as `FFTW3::ESTIMATE_PATIENT`, `FFTW3::ALLOW_PRUNING`, and `FFTW3::NO_SIMD`
373
+
374
+ Direction constants:
375
+
376
+ - `FFTW3::FORWARD`
377
+ - `FFTW3::BACKWARD`
378
+ - `:forward` and `:backward` are also accepted where direction symbols are supported
379
+
380
+ R2R kinds:
381
+
382
+ - `FFTW3::R2HC`
383
+ - `FFTW3::HC2R`
384
+ - `FFTW3::DHT`
385
+ - `FFTW3::REDFT00`, `REDFT01`, `REDFT10`, `REDFT11`
386
+ - `FFTW3::RODFT00`, `RODFT01`, `RODFT10`, `RODFT11`
387
+
388
+ ## Development
389
+
390
+ ```bash
391
+ bundle install
392
+ bundle exec rake spec
393
+ ```
394
+
395
+ ## License
396
+
397
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
398
+
399
+ FFTW3 itself is licensed under GPLv2+. Using this gem requires an installed FFTW3 library.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+
5
+ module FFTW3
6
+ class AlignedMemory
7
+ attr_reader :pointer, :size, :precision, :type
8
+
9
+ REAL_SIZES = {
10
+ double: 8, float: 4, long_double: 16, quad: 16
11
+ }.freeze
12
+
13
+ COMPLEX_SIZES = REAL_SIZES.transform_values { |v| v * 2 }.freeze
14
+
15
+ def initialize(count, type: :complex, precision: :double)
16
+ @precision = precision
17
+ @type = type
18
+ @count = count
19
+
20
+ sizes = (type == :complex) ? COMPLEX_SIZES : REAL_SIZES
21
+ @element_size = sizes.fetch(precision)
22
+ @size = count * @element_size
23
+
24
+ ffi = FFTW3::FFI.module_for(precision)
25
+ pfx = FFTW3::FFI.prefix_for(precision)
26
+
27
+ @pointer = case type
28
+ when :complex
29
+ ffi.send(:"#{pfx}alloc_complex", count)
30
+ when :real
31
+ ffi.send(:"#{pfx}alloc_real", count)
32
+ else
33
+ ffi.send(:"#{pfx}malloc", @size)
34
+ end
35
+
36
+ raise FFTW3::Error::PlanError, "fftw_malloc returned NULL" if @pointer.null?
37
+
38
+ @freed_flag = [false]
39
+ @free_func = ffi.method(:"#{pfx}free")
40
+ ObjectSpace.define_finalizer(self, self.class.release(@pointer, @free_func, @freed_flag))
41
+ end
42
+
43
+ def write(data)
44
+ case @type
45
+ when :real then write_real(data)
46
+ when :complex then write_complex(data)
47
+ end
48
+ end
49
+
50
+ def read
51
+ case @type
52
+ when :real then read_real
53
+ when :complex then read_complex
54
+ end
55
+ end
56
+
57
+ def free!
58
+ return if @freed_flag[0]
59
+
60
+ @free_func.call(@pointer)
61
+ @freed_flag[0] = true
62
+ end
63
+
64
+ private
65
+
66
+ def write_real(data)
67
+ write_numeric_values(data)
68
+ end
69
+
70
+ def read_real
71
+ read_numeric_values(@count)
72
+ end
73
+
74
+ def write_complex(data)
75
+ flat = data.flat_map { |c|
76
+ c.is_a?(Complex) ? [c.real, c.imaginary] : c
77
+ }
78
+ write_numeric_values(flat)
79
+ end
80
+
81
+ def read_complex
82
+ flat = read_numeric_values(@count * 2)
83
+ flat.each_slice(2).map { |re, im| Complex(re, im) }
84
+ end
85
+
86
+ def write_numeric_values(data)
87
+ case @precision
88
+ when :double
89
+ @pointer.put_array_of_double(0, data)
90
+ when :float
91
+ @pointer.put_array_of_float(0, data)
92
+ when :long_double
93
+ write_generic_values(data, type: :long_double)
94
+ else
95
+ raise_unsupported_precision!(:write)
96
+ end
97
+ end
98
+
99
+ def read_numeric_values(count)
100
+ case @precision
101
+ when :double
102
+ @pointer.get_array_of_double(0, count)
103
+ when :float
104
+ @pointer.get_array_of_float(0, count)
105
+ when :long_double
106
+ read_generic_values(count, type: :long_double)
107
+ else
108
+ raise_unsupported_precision!(:read)
109
+ end
110
+ end
111
+
112
+ def write_generic_values(data, type:)
113
+ value_size = ::FFI.type_size(type)
114
+ data.each_with_index do |value, index|
115
+ @pointer.put(type, index * value_size, value)
116
+ end
117
+ rescue TypeError
118
+ raise_unsupported_precision!(:write)
119
+ end
120
+
121
+ def read_generic_values(count, type:)
122
+ value_size = ::FFI.type_size(type)
123
+ Array.new(count) do |index|
124
+ @pointer.get(type, index * value_size)
125
+ end
126
+ rescue LoadError, TypeError
127
+ raise_unsupported_precision!(:read)
128
+ end
129
+
130
+ def raise_unsupported_precision!(action)
131
+ raise FFTW3::Error::InvalidArgument,
132
+ "FFI does not support #{action}ing #{@precision} buffers on this platform"
133
+ end
134
+
135
+ def self.release(ptr, free_func, freed_flag)
136
+ proc {
137
+ unless freed_flag[0] || ptr.null?
138
+ free_func.call(ptr)
139
+ freed_flag[0] = true
140
+ end
141
+ }
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FFTW3
4
+ NO_TIMELIMIT = -1.0
5
+
6
+ # Planner flags
7
+ MEASURE = 0
8
+ DESTROY_INPUT = 1 << 0
9
+ UNALIGNED = 1 << 1
10
+ CONSERVE_MEMORY = 1 << 2
11
+ EXHAUSTIVE = 1 << 3
12
+ PRESERVE_INPUT = 1 << 4
13
+ PATIENT = 1 << 5
14
+ ESTIMATE = 1 << 6
15
+ ESTIMATE_PATIENT = 1 << 7
16
+ BELIEVE_PCOST = 1 << 8
17
+ NO_DFT_R2HC = 1 << 9
18
+ NO_NONTHREADED = 1 << 10
19
+ NO_BUFFERING = 1 << 11
20
+ NO_INDIRECT_OP = 1 << 12
21
+ ALLOW_LARGE_GENERIC = 1 << 13
22
+ NO_RANK_SPLITS = 1 << 14
23
+ NO_VRANK_SPLITS = 1 << 15
24
+ NO_VRECURSE = 1 << 16
25
+ NO_SIMD = 1 << 17
26
+ NO_SLOW = 1 << 18
27
+ NO_FIXED_RADIX_LARGE_N = 1 << 19
28
+ ALLOW_PRUNING = 1 << 20
29
+ WISDOM_ONLY = 1 << 21
30
+
31
+ # Direction
32
+ FORWARD = -1
33
+ BACKWARD = 1
34
+
35
+ # R2R kinds
36
+ R2HC = 0
37
+ HC2R = 1
38
+ DHT = 2
39
+ REDFT00 = 3
40
+ REDFT01 = 4
41
+ REDFT10 = 5
42
+ REDFT11 = 6
43
+ RODFT00 = 7
44
+ RODFT01 = 8
45
+ RODFT10 = 9
46
+ RODFT11 = 10
47
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FFTW3
4
+ module Error
5
+ class PlanError < StandardError; end
6
+ class LibraryNotFound < StandardError; end
7
+ class InvalidArgument < StandardError; end
8
+ end
9
+ end