Class: NMatrix::FFTW::Plan

Inherits:
Object show all
Defined in:
lib/nmatrix/fftw.rb

Constant Summary collapse

REAL_REAL_FFT_KINDS_HASH =

Hash which holds the numerical values of constants that determine the kind of transform that will be computed for a real input/real output instance. These are one-one mappings to the respective constants specified in FFTW. For example, for specifying the FFTW_R2HC constant as the 'kind', pass the symbol :r2hc.

{
  r2hc:    0,
  hc2r:    1,
  dht:     2,
  redft00: 3,
  redft01: 4,
  redft10: 5,
  redft11: 6,
  rodft00: 7,
  rodft01: 9,
  rodft10: 8,
  rodft11: 10
}
FLAG_VALUE_HASH =

Hash holding the numerical values of the flags that are passed in the `flags` argument of a FFTW planner routine. Multiple flags can be passed to one instance of the planner. Their values are OR'd ('|') and then passed. For example, for passing the FFTW_ESTIMATE constant, use :estimate.

nmatrix-fftw supports the following flags into the planning routine:

  • :estimate - Equivalent to FFTW_ESTIMATE. Specifies that, instead of actual measurements of different algorithms, a simple heuristic is used to pick a (probably sub-optimal) plan quickly. With this flag, the input/output arrays are not overwritten during planning.

  • :measure - Equivalent to FFTW_MEASURE. Tells FFTW to find an optimized plan by actually computing several FFTs and measuring their execution time. Depending on your machine, this can take some time (often a few seconds).

  • :patient - Equivalent to FFTW_PATIENT. Like FFTW_MEASURE, but considers a wider range of algorithms and often produces a “more optimal” plan (especially for large transforms), but at the expense of several times longer planning time (especially for large transforms).

  • :exhaustive - Equivalent to FFTW_EXHAUSTIVE. Like FFTW_PATIENT, but considers an even wider range of algorithms, including many that we think are unlikely to be fast, to produce the most optimal plan but with a substantially increased planning time.

{
  estimate: 64,
  measure: 0,
  exhaustive: 8,
  patient: 32
}
FFT_DIRECTION_HASH =

Hash holding numerical values of the direction in which a :complex_complex type FFT should be performed.

(The fourth argument, sign, can be either FFTW_FORWARD (-1) or FFTW_BACKWARD (+1), and indicates the direction of the transform you are interested in; technically, it is the sign of the exponent in the transform)

{
  forward: -1,
  backward: 1
}
DATA_TYPE_HASH =

Hash holding numerical equivalents of the DFT type. Used for determining DFT type in C level.

{
  complex_complex: 0,
  real_complex:    1,
  complex_real:    2,
  real_real:       3
}
VALID_OPTS =

Array holding valid options that can be passed into NMatrix::FFTW::Plan so that invalid options aren't passed.

[:dim, :type, :direction, :flags, :real_real_kind]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(shape, opts = {}) ⇒ Plan

Create a plan for a DFT. The FFTW library requires that you first create a plan for performing a DFT, so that FFTW can optimize its algorithms according to your computer's hardware and various user supplied options.

Examples:

Create a plan for a basic 1D FFT and execute it.

input = NMatrix.new([10],
  [
    Complex(9.32,0), Complex(44,0), Complex(125,0), Complex(34,0),
    Complex(31,0),   Complex(44,0), Complex(12,0),  Complex(1,0),
    Complex(53.23,0),Complex(-23.23,0),
  ], dtype: :complex128)
plan = NMatrix::FFTW::Plan.new(10)
plan.set_input input
plan.execute
print plan.output

Parameters:

  • shape (Array, Fixnum)

    Specify the shape of the plan. For 1D fourier transforms this can be a single number specifying the length of the input. For multi-dimensional transforms, specify an Array containing the length of each dimension.

  • opts (Hash) (defaults to: {})

    the options to create a message with.

Options Hash (opts):

  • :dim (Fixnum) — default: 1

    The number of dimensions of the Fourier transform. If 'shape' has more numbers than :dim, the number of dimensions specified by :dim will be considered when making the plan.

  • :type (Symbol) — default: :complex_complex

    The type of transform to perform based on the input and output data desired. The default value indicates that a transform is being planned that uses complex numbers as input and generates complex numbers as output. Similarly you can use :complex_real, :real_complex or :real_real to specify the kind of input and output that you will be supplying to the plan. @see DATA_TYPE_HASH

  • :flags (Symbol, Array) — default: :estimate

    Specify one or more flags which denote the methodology that is used for deciding the algorithm used when planning the fourier transform. Use one or more of :estimate, :measure, :exhaustive and :patient. These flags map to the planner flags specified at www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags. @see REAL_REAL_FFT_KINDS_HASH

  • :direction (Symbol) — default: :forward

    The direction of a DFT of type :complex_complex. Technically, it is the sign of the exponent in the transform. :forward corresponds to -1 and :backward to +1. @see FFT_DIRECTION_HASH

  • :real_real_kind (Array)

    When the type of transform is :real_real, specify the kind of transform that should be performed FOR EACH AXIS of input. The position of the symbol in the Array corresponds to the axis of the input. The number of elements in :real_real_kind must be equal to :dim. Can accept one of the inputs specified in REAL_REAL_FFT_KINDS_HASH. @see REAL_REAL_FFT_KINDS_HASH @see www.fftw.org/fftw3_doc/Real_002dto_002dReal-Transform-Kinds.html#Real_002dto_002dReal-Transform-Kinds

Raises:

  • (ArgumentError)

See Also:


240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/nmatrix/fftw.rb', line 240

def initialize shape, opts={}
  verify_opts opts
  opts = {
    dim: 1,
    flags: :estimate,
    direction: :forward,
    type: :complex_complex
  }.merge(opts)

  @type      = opts[:type]
  @dim       = opts[:dim]
  @direction = opts[:direction]
  @shape     = shape.is_a?(Array) ? shape : [shape]
  @size      = @shape[0...@dim].inject(:*)
  @flags     = opts[:flags].is_a?(Array) ? opts[:flags] : [opts[:flags]]
  @real_real_kind    = opts[:real_real_kind]

  raise ArgumentError, ":real_real_kind option must be specified for :real_real type transforms" if
    @real_real_kind.nil? and @type == :real_real

  raise ArgumentError, "Specify kind of transform of each axis of input." if
    @real_real_kind and @real_real_kind.size != @dim

  raise ArgumentError, "dim (#{@dim}) cannot be more than size of shape #{@shape.size}" if
    @dim > @shape.size

  @plan_data = c_create_plan(@shape, @size, @dim, 
    combine_flags(@flags), FFT_DIRECTION_HASH[@direction], 
    DATA_TYPE_HASH[@type], encoded_rr_kind)
end

Instance Attribute Details

#dimObject (readonly)

Returns the value of attribute dim


171
172
173
# File 'lib/nmatrix/fftw.rb', line 171

def dim
  @dim
end

#directionObject (readonly)

Returns the value of attribute direction


160
161
162
# File 'lib/nmatrix/fftw.rb', line 160

def direction
  @direction
end

#flagsObject (readonly)

Returns the value of attribute flags


166
167
168
# File 'lib/nmatrix/fftw.rb', line 166

def flags
  @flags
end

#inputObject (readonly)

Returns the value of attribute input


176
177
178
# File 'lib/nmatrix/fftw.rb', line 176

def input
  @input
end

#outputObject (readonly)

Returns the value of attribute output


181
182
183
# File 'lib/nmatrix/fftw.rb', line 181

def output
  @output
end

#real_real_kindObject (readonly)

Returns the value of attribute real_real_kind


189
190
191
# File 'lib/nmatrix/fftw.rb', line 189

def real_real_kind
  @real_real_kind
end

#shapeObject (readonly)

Returns the value of attribute shape


145
146
147
# File 'lib/nmatrix/fftw.rb', line 145

def shape
  @shape
end

#sizeObject (readonly)

Returns the value of attribute size


149
150
151
# File 'lib/nmatrix/fftw.rb', line 149

def size
  @size
end

#typeObject (readonly)

Returns the value of attribute type


154
155
156
# File 'lib/nmatrix/fftw.rb', line 154

def type
  @type
end

Instance Method Details

#executeTrueClass

Execute the DFT with the set plan.

Returns:

  • (TrueClass)

    If all goes well and the fourier transform has been sucessfully computed, 'true' will be returned and you can access the computed output from the NMatrix::FFTW::Plan#output accessor.


301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/nmatrix/fftw.rb', line 301

def execute
  @output = 
  case @type
  when :complex_complex
    @input.clone_structure        
  when :real_complex
    NMatrix.new([@input.size/2 + 1], dtype: :complex128)
  when :complex_real, :real_real
    NMatrix.new([@input.size], dtype: :float64)
  else
    raise TypeError, "Invalid type #{@type}"
  end

  c_execute(@output, @plan_data, DATA_TYPE_HASH[@type])
end

#set_input(ip) ⇒ Object

Set input for the planned DFT.

Parameters:

  • ip (NMatrix)

    An NMatrix specifying the input to the FFT routine. The data type of the NMatrix must be either :complex128 or :float64 depending on the type of FFT that has been planned. Size must be same as the size of the planned routine.

Raises:

  • (ArgumentError)

    if the input has any storage apart from :dense or if size/data type of the planned transform and the input matrix don't match.


279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/nmatrix/fftw.rb', line 279

def set_input ip
  raise ArgumentError, "stype must be dense." if ip.stype != :dense
  raise ArgumentError, "size of input (#{ip.size}) cannot be greater than planned input size #{@size}" if
    ip.size != @size
  
  case @type
  when :complex_complex, :complex_real
    raise ArgumentError, "dtype must be complex128." if ip.dtype != :complex128
  when :real_complex, :real_real
    raise ArgumentError, "dtype must be float64." if ip.dtype != :float64
  else
    raise "Invalid type #{@type}"
  end

  @input = ip
  c_set_input(ip, @plan_data, DATA_TYPE_HASH[@type])
end