convolver 0.3.2 → 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.
data/lib/convolver.rb CHANGED
@@ -1,112 +1,109 @@
1
- require 'narray'
2
- require "convolver/convolver"
3
- require "convolver/version"
4
- require 'fftw3'
1
+ # frozen_string_literal: true
5
2
 
3
+ require 'numo/narray/alt'
4
+ require 'numo/pocketfft'
5
+ require 'convolver/convolver'
6
+ require 'convolver/version'
7
+
8
+ # Valid cross-correlation operations for Numo::NArray values.
6
9
  module Convolver
7
- # Chooses and calls likely fastest method from #convolve_basic and #convolve_fftw3.
8
- # The two parameters must have the same rank. The output has same rank, its size in each
9
- # dimension d is given by
10
- # signal.shape[d] - kernel.shape[d] + 1
11
- # If you always perform convolutions of the same size, you may be better off benchmarking your
12
- # own code using either #convolve_basic or #convolve_fftw3, and have your code use the fastest.
13
- # @param [NArray] signal must be same size or larger than kernel in each dimension
14
- # @param [NArray] kernel must be same size or smaller than signal in each dimension
15
- # @return [NArray] result of convolving signal with kernel
16
- def self.convolve signal, kernel
17
- # For small signals or kernels, just go straight to basic
18
- if signal.size < 1000 || kernel.size < 100
19
- return convolve_basic( signal, kernel )
10
+ # Maximum number of dimensions supported by the direct native implementation.
11
+ MAX_RANK = 16
12
+
13
+ class << self
14
+ # Chooses the likely fastest implementation for a valid cross-correlation.
15
+ #
16
+ # The inputs must have the same rank, and the kernel must not be larger than
17
+ # the signal in any dimension. The result shape is:
18
+ #
19
+ # signal.shape.zip(kernel.shape).map { |signal_size, kernel_size| signal_size - kernel_size + 1 }
20
+ #
21
+ # @param signal [Numo::NArray] input values
22
+ # @param kernel [Numo::NArray] correlation kernel
23
+ # @return [Numo::SFloat] valid cross-correlation result
24
+ # @raise [ArgumentError] if the inputs have incompatible ranks or shapes
25
+ def convolve(signal, kernel)
26
+ validate_inputs!(signal, kernel)
27
+ return convolve_basic(signal, kernel) if signal.size < 1000 || kernel.size < 100
28
+
29
+ basic_time_predicted = predict_convolve_basic_time(signal, kernel)
30
+ return convolve_basic(signal, kernel) if basic_time_predicted < 0.1
31
+
32
+ fft_time_predicted = predict_convolve_fft_time(signal, kernel)
33
+ return convolve_fft(signal, kernel) if fft_time_predicted < 2 * basic_time_predicted
34
+
35
+ convolve_basic(signal, kernel)
20
36
  end
21
37
 
22
- # If predicted time is less than a millisecond, just do a basic convolve
23
- basic_time_predicted = predict_convolve_basic_time( signal, kernel )
24
- if basic_time_predicted < 0.1
25
- return convolve_basic( signal, kernel )
38
+ # Uses PocketFFT to calculate a valid cross-correlation.
39
+ #
40
+ # @param signal [Numo::NArray] input values
41
+ # @param kernel [Numo::NArray] correlation kernel
42
+ # @return [Numo::SFloat] valid cross-correlation result
43
+ # @raise [ArgumentError] if the inputs have incompatible ranks or shapes
44
+ def convolve_fft(signal, kernel)
45
+ validate_inputs!(signal, kernel)
46
+ ranges = kernel.shape.zip(signal.shape).map { |kernel_size, signal_size| (kernel_size - 1)...signal_size }
47
+ full_convolution = Numo::Pocketfft.fftconvolve(signal, kernel.reverse)
48
+
49
+ Numo::SFloat.cast(full_convolution[*ranges])
26
50
  end
27
51
 
28
- # Factor of two to allow for large uncertainty in predictions for FFTW3
29
- fft_time_predicted = predict_convolve_fft_time( signal, kernel )
30
- if fft_time_predicted < 2 * basic_time_predicted
31
- return convolve_fftw3( signal, kernel )
52
+ # Compatibility alias for the former FFTW3-backed implementation.
53
+ #
54
+ # @deprecated Use {.convolve_fft}; Convolver no longer uses FFTW3.
55
+ # @return [Numo::SFloat] valid cross-correlation result
56
+ def convolve_fftw3(signal, kernel)
57
+ warn 'Convolver.convolve_fftw3 is deprecated; use .convolve_fft instead', uplevel: 1
58
+ convolve_fft(signal, kernel)
32
59
  end
33
60
 
34
- convolve_basic( signal, kernel )
35
- end
36
-
37
- # Uses FFTW3 library to calculate convolution of an array of floats representing a signal,
38
- # with a second array representing a kernel. The two parameters must have the same rank.
39
- # The output has same rank, its size in each dimension d is given by
40
- # signal.shape[d] - kernel.shape[d] + 1
41
- # @param [NArray] signal must be same size or larger than kernel in each dimension
42
- # @param [NArray] kernel must be same size or smaller than signal in each dimension
43
- # @return [NArray] result of convolving signal with kernel
44
- def self.convolve_fftw3 signal, kernel
45
- combined_shape, shift_by, ranges = fft_offsets( signal.shape, kernel.shape )
46
-
47
- mod_a = NArray.sfloat(*combined_shape)
48
- mod_a[*shift_by] = signal
49
-
50
- mod_b = NArray.sfloat(*combined_shape)
51
-
52
- Convolver.fit_kernel_backwards( mod_b, kernel )
53
-
54
- afreqs = FFTW3.fft(mod_a)
55
- bfreqs = FFTW3.fft(mod_b)
56
- cfreqs = afreqs * bfreqs
57
-
58
- (FFTW3.ifft( cfreqs ).real * (1.0/mod_a.size))[*ranges]
59
- end
61
+ # Estimates the relative cost of {.convolve_fft}.
62
+ #
63
+ # @param signal [Numo::NArray] input values
64
+ # @param kernel [Numo::NArray] correlation kernel
65
+ # @return [Float] machine-specific relative cost estimate
66
+ def predict_convolve_fft_time(signal, kernel)
67
+ validate_inputs!(signal, kernel)
68
+ output_size = result_shape(signal.shape, kernel.shape).inject(:*)
69
+ 16 * 4.55e-08 * output_size * Math.log(output_size)
70
+ end
60
71
 
61
- # A rough estimate of time that #convolve_fftw3 will take, based on complexity
62
- # of its operations, and some rough benchmarking. A value of 1.0 corresponds to results
63
- # varying between 1 and 12 milliseconds on the test computer.
64
- # @param [NArray] signal must be same size or larger than kernel in each dimension
65
- # @param [NArray] kernel must be same size or smaller than signal in each dimension
66
- # @return [Float] rough estimate of time for convolution compared to baseline
67
- def self.predict_convolve_fft_time signal, kernel
68
- 16 * 4.55e-08 * result_shape(signal.shape,kernel.shape).inject(1) { |t,x| t * x * Math.log(x) }
69
- end
72
+ # Estimates the relative cost of {.convolve_basic}.
73
+ #
74
+ # @param signal [Numo::NArray] input values
75
+ # @param kernel [Numo::NArray] correlation kernel
76
+ # @return [Float] machine-specific relative cost estimate
77
+ def predict_convolve_basic_time(signal, kernel)
78
+ validate_inputs!(signal, kernel)
79
+ outputs = result_shape(signal.shape, kernel.shape).inject(:*)
80
+ 4.54e-12 * (outputs * signal.size * kernel.size)
81
+ end
70
82
 
71
- # A rough estimate of time that #convolve will take, based on complexity
72
- # of its operations, and some rough benchmarking. A value of 1.0 corresponds to results
73
- # varying bewteen 2 and 8 milliseconds on the test computer.
74
- # @param [NArray] signal must be same size or larger than kernel in each dimension
75
- # @param [NArray] kernel must be same size or smaller than signal in each dimension
76
- # @return [Float] rough estimate of time for convolution compared to baseline
77
- def self.predict_convolve_basic_time signal, kernel
78
- outputs = shape_to_size( result_shape( signal.shape, kernel.shape ) )
79
- 4.54e-12 * (outputs * shape_to_size( signal.shape ) * shape_to_size( kernel.shape ))
80
- end
83
+ private
81
84
 
82
- private
85
+ def result_shape(signal_shape, kernel_shape)
86
+ signal_shape.zip(kernel_shape).map { |signal_size, kernel_size| signal_size - kernel_size + 1 }
87
+ end
83
88
 
84
- def self.shape_to_size shape
85
- shape.inject(1) { |t,x| t * x }
86
- end
89
+ def validate_inputs!(signal, kernel)
90
+ validate_types!(signal, kernel)
91
+ validate_shapes!(signal, kernel)
92
+ end
87
93
 
88
- def self.result_shape signal_shape, kernel_shape
89
- result_shape = [ ]
90
- signal_shape.each_with_index do |signal_size, i|
91
- kernel_size = kernel_shape[i]
92
- result_shape[i] = signal_size - kernel_size + 1
94
+ def validate_types!(signal, kernel)
95
+ unless signal.is_a?(Numo::NArray) && kernel.is_a?(Numo::NArray)
96
+ raise ArgumentError, 'signal and kernel must be Numo::NArray values'
97
+ end
98
+ raise ArgumentError, 'signal and kernel must not be empty' if signal.empty? || kernel.empty?
93
99
  end
94
- result_shape
95
- end
96
100
 
97
- def self.fft_offsets signal_shape, kernel_shape
98
- combined_shape = []
99
- shift_by = []
100
- ranges = []
101
- signal_shape.each_with_index do |signal_size, i|
102
- kernel_size = kernel_shape[i]
103
-
104
- combined_shape[i] = signal_size + kernel_size - 1
105
- output_size = signal_size - kernel_size + 1
106
- output_offset = kernel_size - 1
107
- shift_by[i] = kernel_size / 2
108
- ranges[i] = (output_offset...(output_offset + output_size))
101
+ def validate_shapes!(signal, kernel)
102
+ raise ArgumentError, 'signal and kernel must have equal rank' unless signal.ndim == kernel.ndim
103
+ raise ArgumentError, "maximum supported rank is #{MAX_RANK}" if signal.ndim > MAX_RANK
104
+ return if signal.shape.zip(kernel.shape).all? { |signal_size, kernel_size| signal_size >= kernel_size }
105
+
106
+ raise ArgumentError, 'kernel must not be larger than signal in any dimension'
109
107
  end
110
- [ combined_shape, shift_by, ranges ]
111
108
  end
112
109
  end
metadata CHANGED
@@ -1,128 +1,56 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convolver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Slater
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2018-11-19 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: narray
13
+ name: numo-narray-alt
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 0.6.0.8
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
18
+ version: 0.9.9
19
+ - - "<"
25
20
  - !ruby/object:Gem::Version
26
- version: 0.6.0.8
27
- - !ruby/object:Gem::Dependency
28
- name: fftw3
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0.3'
21
+ version: '0.11'
34
22
  type: :runtime
35
23
  prerelease: false
36
24
  version_requirements: !ruby/object:Gem::Requirement
37
25
  requirements:
38
26
  - - ">="
39
27
  - !ruby/object:Gem::Version
40
- version: '0.3'
41
- - !ruby/object:Gem::Dependency
42
- name: yard
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: 0.8.7.2
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
28
+ version: 0.9.9
29
+ - - "<"
53
30
  - !ruby/object:Gem::Version
54
- version: 0.8.7.2
31
+ version: '0.11'
55
32
  - !ruby/object:Gem::Dependency
56
- name: bundler
33
+ name: numo-pocketfft
57
34
  requirement: !ruby/object:Gem::Requirement
58
35
  requirements:
59
36
  - - ">="
60
37
  - !ruby/object:Gem::Version
61
- version: '1.3'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
38
+ version: '0.6'
39
+ - - "<"
67
40
  - !ruby/object:Gem::Version
68
- version: '1.3'
69
- - !ruby/object:Gem::Dependency
70
- name: rspec
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: 2.13.0
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: 2.13.0
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: 1.9.1
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: 1.9.1
97
- - !ruby/object:Gem::Dependency
98
- name: rake-compiler
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 0.8.3
104
- type: :development
41
+ version: '0.8'
42
+ type: :runtime
105
43
  prerelease: false
106
44
  version_requirements: !ruby/object:Gem::Requirement
107
45
  requirements:
108
46
  - - ">="
109
47
  - !ruby/object:Gem::Version
110
- version: 0.8.3
111
- - !ruby/object:Gem::Dependency
112
- name: coveralls
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: 0.6.7
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
48
+ version: '0.6'
49
+ - - "<"
123
50
  - !ruby/object:Gem::Version
124
- version: 0.6.7
125
- description: Convolution for NArray
51
+ version: '0.8'
52
+ description: Fast valid cross-correlation for multidimensional Numo::NArray values,
53
+ with native and FFT implementations.
126
54
  email:
127
55
  - slobo777@gmail.com
128
56
  executables: []
@@ -130,30 +58,21 @@ extensions:
130
58
  - ext/convolver/extconf.rb
131
59
  extra_rdoc_files: []
132
60
  files:
133
- - ".gitignore"
134
- - ".travis.yml"
135
- - Gemfile
61
+ - CHANGELOG.md
136
62
  - LICENSE.txt
137
63
  - README.md
138
- - Rakefile
139
- - convolver.gemspec
140
64
  - ext/convolver/convolve_raw.c
141
65
  - ext/convolver/convolve_raw.h
142
66
  - ext/convolver/convolver.c
143
67
  - ext/convolver/extconf.rb
144
- - ext/convolver/narray_shared.c
145
- - ext/convolver/narray_shared.h
146
68
  - lib/convolver.rb
147
69
  - lib/convolver/version.rb
148
- - spec/convolve_basic_spec.rb
149
- - spec/convolve_fftw3_spec.rb
150
- - spec/convolve_spec.rb
151
- - spec/helpers.rb
152
- homepage: http://github.com/neilslater/convolver
70
+ homepage: https://github.com/neilslater/convolver
153
71
  licenses:
154
72
  - MIT
155
- metadata: {}
156
- post_install_message:
73
+ metadata:
74
+ rubygems_mfa_required: 'true'
75
+ source_code_uri: https://github.com/neilslater/convolver
157
76
  rdoc_options: []
158
77
  require_paths:
159
78
  - lib
@@ -161,20 +80,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
80
  requirements:
162
81
  - - ">="
163
82
  - !ruby/object:Gem::Version
164
- version: '0'
83
+ version: '3.2'
165
84
  required_rubygems_version: !ruby/object:Gem::Requirement
166
85
  requirements:
167
86
  - - ">="
168
87
  - !ruby/object:Gem::Version
169
88
  version: '0'
170
89
  requirements: []
171
- rubyforge_project:
172
- rubygems_version: 2.6.12
173
- signing_key:
90
+ rubygems_version: 4.0.16
174
91
  specification_version: 4
175
- summary: Convolution for NArray
176
- test_files:
177
- - spec/convolve_basic_spec.rb
178
- - spec/convolve_fftw3_spec.rb
179
- - spec/convolve_spec.rb
180
- - spec/helpers.rb
92
+ summary: Fast cross-correlation for Numo::NArray
93
+ test_files: []
data/.gitignore DELETED
@@ -1,19 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- lib/convolver/*.bundle
5
- .config
6
- .yardoc
7
- Gemfile.lock
8
- InstalledFiles
9
- _yardoc
10
- coverage
11
- doc/
12
- lib/bundler/man
13
- pkg
14
- rdoc
15
- spec/reports
16
- test/tmp
17
- test/version_tmp
18
- tmp
19
- benchmarks
data/.travis.yml DELETED
@@ -1,19 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
-
4
- os:
5
- - linux
6
- - osx
7
-
8
- addons:
9
- apt:
10
- update: true
11
- packages: libfftw3-dev
12
- homebrew:
13
- packages: fftw
14
-
15
- rvm:
16
- - "2.2.10"
17
- - "2.3.8"
18
- - "2.4.5"
19
- - "2.5.3"
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in convolver.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1,20 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
- require 'rake/extensiontask'
4
-
5
- desc "Convolver unit tests"
6
- RSpec::Core::RakeTask.new(:test) do |t|
7
- t.pattern = "spec/*_spec.rb"
8
- t.verbose = true
9
- end
10
-
11
- gemspec = Gem::Specification.load('convolver.gemspec')
12
- Rake::ExtensionTask.new do |ext|
13
- ext.name = 'convolver'
14
- ext.source_pattern = "*.{c,h}"
15
- ext.ext_dir = 'ext/convolver'
16
- ext.lib_dir = 'lib/convolver'
17
- ext.gem_spec = gemspec
18
- end
19
-
20
- task :default => [:compile, :test]
data/convolver.gemspec DELETED
@@ -1,31 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'convolver/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "convolver"
8
- spec.version = Convolver::VERSION
9
- spec.authors = ["Neil Slater"]
10
- spec.email = ["slobo777@gmail.com"]
11
- spec.description = %q{Convolution for NArray}
12
- spec.summary = %q{Convolution for NArray}
13
- spec.homepage = "http://github.com/neilslater/convolver"
14
- spec.license = "MIT"
15
-
16
- spec.add_dependency "narray", ">= 0.6.0.8"
17
- spec.add_dependency "fftw3", ">= 0.3"
18
-
19
- spec.add_development_dependency "yard", ">= 0.8.7.2"
20
- spec.add_development_dependency "bundler", ">= 1.3"
21
- spec.add_development_dependency "rspec", ">= 2.13.0"
22
- spec.add_development_dependency "rake", ">= 1.9.1"
23
- spec.add_development_dependency "rake-compiler", ">= 0.8.3"
24
- spec.add_development_dependency "coveralls", ">= 0.6.7"
25
-
26
- spec.files = `git ls-files`.split($/)
27
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
28
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
29
- spec.extensions = spec.files.grep(%r{/extconf\.rb$})
30
- spec.require_paths = ["lib"]
31
- end
@@ -1,61 +0,0 @@
1
- // ext/convolver/narray_shared.c
2
-
3
- #include "narray_shared.h"
4
-
5
- // This is copied from na_array.c, with safety checks and temp vars removed
6
- int na_quick_idxs_to_pos( int rank, int *shape, int *idxs ) {
7
- int i, pos = 0;
8
- for ( i = rank - 1; i >= 0; i-- ) {
9
- pos = pos * shape[i] + idxs[i];
10
- }
11
- return pos;
12
- }
13
-
14
- // This is inverse of above
15
- void na_quick_pos_to_idxs( int rank, int *shape, int pos, int *idxs ) {
16
- int i;
17
- for ( i = 0; i < rank; i++ ) {
18
- idxs[ i ] = pos % shape[i];
19
- pos /= shape[i];
20
- }
21
- return;
22
- }
23
-
24
- // This is copied from na_array.c, with safety checks and temp vars removed
25
- inline int na_inline_idxs_to_pos( int rank, int *shape, int *idxs ) {
26
- int i, pos = 0;
27
- for ( i = rank - 1; i >= 0; i-- ) {
28
- pos = pos * shape[i] + idxs[i];
29
- }
30
- return pos;
31
- }
32
-
33
- // This is inverse of above
34
- inline void na_inline_pos_to_idxs( int rank, int *shape, int pos, int *idxs ) {
35
- int i;
36
- for ( i = 0; i < rank; i++ ) {
37
- idxs[ i ] = pos % shape[i];
38
- pos /= shape[i];
39
- }
40
- return;
41
- }
42
-
43
- // used to place kernel data into array for FFTW3 processing
44
- void fit_backwards_raw( int rank, int *dst_shape, float *dst, int *src_shape, float *src, int *shift_shape ) {
45
- int i, j, size, x;
46
- int k_idx[16], dst_idx[16];
47
-
48
- size = 1;
49
- for ( j = 0; j < rank; j++ ) { size *= src_shape[j]; }
50
-
51
- for ( i = 0; i < size; i++ ) {
52
- na_inline_pos_to_idxs( rank, src_shape, i, k_idx );
53
- for ( j = 0; j < rank; j++ ) {
54
- x = src_shape[j] - shift_shape[j] - k_idx[j] - 1;
55
- if ( x < 0 ) x = x + dst_shape[j];
56
- dst_idx[j] = x;
57
- }
58
- dst[ na_inline_idxs_to_pos( rank, dst_shape, dst_idx ) ] = src[i];
59
- }
60
- return;
61
- }
@@ -1,22 +0,0 @@
1
- // ext/convolver/narray_shared.h
2
-
3
- ////////////////////////////////////////////////////////////////////////////////////////////////
4
- //
5
- // Declarations of narray helper functions
6
- //
7
-
8
- #ifndef CONVOLVER_NARRAY_SHARED_H
9
- #define CONVOLVER_NARRAY_SHARED_H
10
-
11
- #include <ruby.h>
12
- #include "narray.h"
13
-
14
- // This is copied from na_array.c, with safety checks and temp vars removed
15
- int na_quick_idxs_to_pos( int rank, int *shape, int *idxs );
16
-
17
- // This is inverse of above
18
- void na_quick_pos_to_idxs( int rank, int *shape, int pos, int *idxs );
19
-
20
- void fit_backwards_raw( int rank, int *dst_shape, float *dst, int *src_shape, float *src, int *shift_shape );
21
-
22
- #endif