convolver-light 0.3.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 +7 -0
- data/.gitignore +23 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +34 -0
- data/Rakefile +20 -0
- data/convolver-light.gemspec +30 -0
- data/ext/convolver/convolve_raw.c +107 -0
- data/ext/convolver/convolve_raw.h +22 -0
- data/ext/convolver/convolver.c +119 -0
- data/ext/convolver/extconf.rb +27 -0
- data/ext/convolver/narray_shared.c +61 -0
- data/ext/convolver/narray_shared.h +22 -0
- data/lib/convolver-light.rb +15 -0
- data/lib/convolver/version.rb +3 -0
- data/spec/convolve_basic_spec.rb +84 -0
- data/spec/convolve_spec.rb +49 -0
- data/spec/helpers.rb +46 -0
- metadata +165 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e80f99f8aa860c6a95429b390c2d3915319ec1ce740ec29c4bbf3d60253ee2ee
|
4
|
+
data.tar.gz: 47337ccc67b933083cd3cdaf517171c63477773917c2a9fa19b0584d3e35da5c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bc24eadf42dc390dbd7ef993fab2bbffb1648b9a51619d40dc41232b760beb6f67342e5dd9b5f477ca1c9909c0b9afb588cb753a7d7d0ff350b1b5567485e04c
|
7
|
+
data.tar.gz: 12be9439142f8e25a7f69541faa5ae94f524d53da839892af4fac3af88f42261453410245bc5bfb3684595f5bcdaf8941214948c9cf890fb359be30f3821cfa1
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
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
|
20
|
+
.DS_Store
|
21
|
+
._.DS_Store
|
22
|
+
**/.DS_Store
|
23
|
+
**/._.DS_Store
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Neil Slater
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Convolver-Light
|
2
|
+
|
3
|
+
This is native-only version of [neilslater's](https://github.com/neilslater) [Convolver Gem](https://github.com/neilslater/convolver)
|
4
|
+
|
5
|
+
FFTW3 dependency is removed, so calculations would be slow on big matrices. Use it only if you need to make a convolution with a small kernel.
|
6
|
+
|
7
|
+
All the credits to the [author](https://github.com/neilslater)
|
8
|
+
|
9
|
+
### Installing the gem
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'convolver-light'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install convolver-light
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
require 'convolver-light
|
26
|
+
|
27
|
+
Usage is exactly the same as of original gem, please refer to the [author's page](https://github.com/neilslater/convolver)
|
28
|
+
|
29
|
+
```
|
30
|
+
a = NArray[0.3,0.4,0.5]
|
31
|
+
b = NArray[1.3, -0.5]
|
32
|
+
c = Convolver.convolve( a, b )
|
33
|
+
=> NArray.float(2): [ 0.19, 0.27 ]
|
34
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
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-light.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]
|
@@ -0,0 +1,30 @@
|
|
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-light'
|
8
|
+
spec.version = Convolver::VERSION
|
9
|
+
spec.authors = ['Dima Ermilov']
|
10
|
+
spec.email = ['dima@scriptangle.com']
|
11
|
+
spec.description = 'Simplification of convolver gem, FFTW removed, suitable only for smaller kernels. Convolver gem author is Neil Slater, slobo777@gmail.com, https://github.com/neilslater'
|
12
|
+
spec.summary = 'Convolution for NArray simplified.'
|
13
|
+
spec.homepage = 'http://github.com/adworse/convolver-light'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.add_dependency "narray", ">= 0.6.0.8"
|
17
|
+
|
18
|
+
spec.add_development_dependency "yard", ">= 0.8.7.2"
|
19
|
+
spec.add_development_dependency "bundler", ">= 1.3"
|
20
|
+
spec.add_development_dependency "rspec", ">= 2.13.0"
|
21
|
+
spec.add_development_dependency "rake", ">= 1.9.1"
|
22
|
+
spec.add_development_dependency "rake-compiler", ">= 0.8.3"
|
23
|
+
spec.add_development_dependency "coveralls", ">= 0.6.7"
|
24
|
+
|
25
|
+
spec.files = `git ls-files`.split($/)
|
26
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
27
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
28
|
+
spec.extensions = spec.files.grep(%r{/extconf\.rb$})
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
// ext/convolver/convolve_raw.c
|
2
|
+
|
3
|
+
#include "convolve_raw.h"
|
4
|
+
|
5
|
+
inline int size_from_shape( int rank, int *shape ) {
|
6
|
+
int size = 1;
|
7
|
+
int i;
|
8
|
+
for ( i = 0; i < rank; i++ ) { size *= shape[i]; }
|
9
|
+
return size;
|
10
|
+
}
|
11
|
+
|
12
|
+
// Sets reverse indices
|
13
|
+
inline void corner_reset( int rank, int *shape, int *rev_indices ) {
|
14
|
+
int i;
|
15
|
+
for ( i = 0; i < rank; i++ ) { rev_indices[i] = shape[i] - 1; }
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
|
19
|
+
// Counts indices down, returns number of ranks that reset
|
20
|
+
inline int corner_dec( int rank, int *shape, int *rev_indices ) {
|
21
|
+
int i = 0;
|
22
|
+
while ( ! rev_indices[i]-- ) {
|
23
|
+
rev_indices[i] = shape[i] - 1;
|
24
|
+
i++;
|
25
|
+
}
|
26
|
+
return i;
|
27
|
+
}
|
28
|
+
|
29
|
+
// Generates co-increment steps by rank boundaries crossed, for the outer position as inner position is incremented by 1
|
30
|
+
inline void calc_co_increment( int rank, int *outer_shape, int *inner_shape, int *co_increment ) {
|
31
|
+
int i, factor;
|
32
|
+
co_increment[0] = 1; // co-increment is always 1 in lowest rank
|
33
|
+
factor = 1;
|
34
|
+
for ( i = 0; i < rank; i++ ) {
|
35
|
+
co_increment[i+1] = co_increment[i] + factor * ( outer_shape[i] - inner_shape[i] );
|
36
|
+
factor *= outer_shape[i];
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
41
|
+
//
|
42
|
+
// Convolve
|
43
|
+
//
|
44
|
+
// Benchmark: 640x480 image, 8x8 kernel, 1000 iterations. 12.3 seconds.
|
45
|
+
//
|
46
|
+
|
47
|
+
void convolve_raw(
|
48
|
+
int in_rank, int *in_shape, float *in_ptr,
|
49
|
+
int kernel_rank, int *kernel_shape, float *kernel_ptr,
|
50
|
+
int out_rank, int *out_shape, float *out_ptr ) {
|
51
|
+
int i, j, in_size, kernel_size, kernel_aligned, out_size, offset;
|
52
|
+
int out_co_incr[LARGEST_RANK], kernel_co_incr[LARGEST_RANK];
|
53
|
+
int ker_q[LARGEST_RANK], out_q[LARGEST_RANK];
|
54
|
+
int *kernel_co_incr_cache;
|
55
|
+
|
56
|
+
in_size = size_from_shape( in_rank, in_shape );
|
57
|
+
kernel_size = size_from_shape( kernel_rank, kernel_shape );
|
58
|
+
kernel_aligned = 4 * (kernel_size/4);
|
59
|
+
out_size = size_from_shape( out_rank, out_shape );
|
60
|
+
|
61
|
+
calc_co_increment( in_rank, in_shape, out_shape, out_co_incr );
|
62
|
+
calc_co_increment( in_rank, in_shape, kernel_shape, kernel_co_incr );
|
63
|
+
|
64
|
+
kernel_co_incr_cache = ALLOC_N( int, kernel_size );
|
65
|
+
kernel_co_incr_cache[0] = 0;
|
66
|
+
|
67
|
+
corner_reset( kernel_rank, kernel_shape, ker_q );
|
68
|
+
for ( i = 1; i < kernel_size; i++ ) {
|
69
|
+
kernel_co_incr_cache[i] = kernel_co_incr_cache[i-1] + kernel_co_incr[ corner_dec( kernel_rank, kernel_shape, ker_q ) ];
|
70
|
+
}
|
71
|
+
|
72
|
+
// For convenience of flow, we set offset to -1 and adjust countdown 1 higher to compensate
|
73
|
+
offset = -1;
|
74
|
+
corner_reset( out_rank, out_shape, out_q );
|
75
|
+
out_q[0]++;
|
76
|
+
|
77
|
+
// Main convolve loop
|
78
|
+
for ( i = 0; i < out_size; i++ ) {
|
79
|
+
__m128 simd_x, simd_y, simd_t;
|
80
|
+
float t = 0.0;
|
81
|
+
float v[4];
|
82
|
+
simd_t = _mm_setzero_ps();
|
83
|
+
|
84
|
+
offset += out_co_incr[ corner_dec( out_rank, out_shape, out_q ) ];
|
85
|
+
|
86
|
+
// Use SIMD for all the aligned values in groups of 4
|
87
|
+
for ( j = 0; j < kernel_aligned; j +=4 ) {
|
88
|
+
simd_x = _mm_load_ps( kernel_ptr + j );
|
89
|
+
// Yes the backwards alignment is correct
|
90
|
+
simd_y = _mm_set_ps( in_ptr[ offset + kernel_co_incr_cache[j+3] ], in_ptr[ offset + kernel_co_incr_cache[j+2] ],
|
91
|
+
in_ptr[ offset + kernel_co_incr_cache[j+1] ], in_ptr[ offset + kernel_co_incr_cache[j] ] );
|
92
|
+
simd_x = _mm_mul_ps( simd_x, simd_y );
|
93
|
+
simd_t = _mm_add_ps( simd_x, simd_t );
|
94
|
+
}
|
95
|
+
_mm_store_ps( v, simd_t );
|
96
|
+
|
97
|
+
// Complete any remaining 1,2 or 3 items one at a time
|
98
|
+
for ( j = kernel_aligned; j < kernel_size; j++ ) {
|
99
|
+
t += in_ptr[ offset + kernel_co_incr_cache[j] ] * kernel_ptr[ j ];
|
100
|
+
}
|
101
|
+
|
102
|
+
out_ptr[i] = v[0] + v[1] + v[2] + v[3] + t;
|
103
|
+
}
|
104
|
+
|
105
|
+
xfree( kernel_co_incr_cache );
|
106
|
+
return;
|
107
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// ext/convolver/convolve_raw.h
|
2
|
+
|
3
|
+
////////////////////////////////////////////////////////////////////////////////////////////////
|
4
|
+
//
|
5
|
+
// Declarations of narray helper functions
|
6
|
+
//
|
7
|
+
|
8
|
+
#ifndef CONVOLVE_RAW_H
|
9
|
+
#define CONVOLVE_RAW_H
|
10
|
+
|
11
|
+
#include <ruby.h>
|
12
|
+
#include <xmmintrin.h>
|
13
|
+
#include "narray_shared.h"
|
14
|
+
|
15
|
+
#define LARGEST_RANK 16
|
16
|
+
|
17
|
+
void convolve_raw(
|
18
|
+
int in_rank, int *in_shape, float *in_ptr,
|
19
|
+
int kernel_rank, int *kernel_shape, float *kernel_ptr,
|
20
|
+
int out_rank, int *out_shape, float *out_ptr );
|
21
|
+
|
22
|
+
#endif
|
@@ -0,0 +1,119 @@
|
|
1
|
+
// ext/convolver/convolver.c
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
#include "narray.h"
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <xmmintrin.h>
|
7
|
+
|
8
|
+
#include "narray_shared.h"
|
9
|
+
#include "convolve_raw.h"
|
10
|
+
|
11
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
12
|
+
|
13
|
+
// To hold the module object
|
14
|
+
VALUE Convolver = Qnil;
|
15
|
+
|
16
|
+
/* @overload fit_kernel_backwards( fft_temp_space, kernel )
|
17
|
+
* @!visibility private
|
18
|
+
* Over-writes fft_temp_space at edges with a reversed copy of kernel, in such a way that
|
19
|
+
* an FFTW3-based convolve has a result set in an easy-to-extract position later. This is
|
20
|
+
* implemented as a native extension for convenience and speed - to do this with methods provided
|
21
|
+
* by narray gem would take several complex steps and be inefficient.
|
22
|
+
* @param [NArray<sfloat>] fft_temp_space target array for pre-fft copy of kernel, is over-written
|
23
|
+
* @param [NArray] kernel must be same size or smaller than fft_temp_space in each dimension
|
24
|
+
* @return [nil]
|
25
|
+
*/
|
26
|
+
static VALUE narray_fit_backwards( VALUE self, VALUE a, VALUE b ) {
|
27
|
+
struct NARRAY *na_a, *na_b;
|
28
|
+
volatile VALUE val_a, val_b;
|
29
|
+
int target_rank, i;
|
30
|
+
int shift_by[LARGEST_RANK];
|
31
|
+
|
32
|
+
val_a = na_cast_object(a, NA_SFLOAT);
|
33
|
+
GetNArray( val_a, na_a );
|
34
|
+
|
35
|
+
val_b = na_cast_object(b, NA_SFLOAT);
|
36
|
+
GetNArray( val_b, na_b );
|
37
|
+
|
38
|
+
if ( na_a->rank != na_b->rank ) {
|
39
|
+
rb_raise( rb_eArgError, "narray a must have equal rank to narray b (a rank %d, b rank %d)", na_a->rank, na_b->rank );
|
40
|
+
}
|
41
|
+
|
42
|
+
if ( na_a->rank > LARGEST_RANK ) {
|
43
|
+
rb_raise( rb_eArgError, "exceeded maximum narray rank for convolve of %d", LARGEST_RANK );
|
44
|
+
}
|
45
|
+
|
46
|
+
target_rank = na_a->rank;
|
47
|
+
|
48
|
+
for ( i = 0; i < target_rank; i++ ) {
|
49
|
+
if ( ( na_a->shape[i] - na_b->shape[i] ) < 0 ) {
|
50
|
+
rb_raise( rb_eArgError, "no space for backward fit" );
|
51
|
+
}
|
52
|
+
shift_by[i] = na_b->shape[i] >> 1;
|
53
|
+
}
|
54
|
+
|
55
|
+
fit_backwards_raw(
|
56
|
+
target_rank,
|
57
|
+
na_a->shape, (float*) na_a->ptr,
|
58
|
+
na_b->shape, (float*) na_b->ptr,
|
59
|
+
shift_by );
|
60
|
+
|
61
|
+
return Qnil;
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
/* @overload convolve_basic( signal, kernel )
|
66
|
+
* Calculates convolution of an array of floats representing a signal, with a second array representing
|
67
|
+
* a kernel. The two parameters must have the same rank. The output has same rank, its size in each dimension d is given by
|
68
|
+
* signal.shape[d] - kernel.shape[d] + 1
|
69
|
+
* @param [NArray] signal must be same size or larger than kernel in each dimension
|
70
|
+
* @param [NArray] kernel must be same size or smaller than signal in each dimension
|
71
|
+
* @return [NArray] result of convolving signal with kernel
|
72
|
+
*/
|
73
|
+
static VALUE narray_convolve( VALUE self, VALUE a, VALUE b ) {
|
74
|
+
struct NARRAY *na_a, *na_b, *na_c;
|
75
|
+
volatile VALUE val_a, val_b, val_c;
|
76
|
+
int target_rank, i;
|
77
|
+
int target_shape[LARGEST_RANK];
|
78
|
+
|
79
|
+
val_a = na_cast_object(a, NA_SFLOAT);
|
80
|
+
GetNArray( val_a, na_a );
|
81
|
+
|
82
|
+
val_b = na_cast_object(b, NA_SFLOAT);
|
83
|
+
GetNArray( val_b, na_b );
|
84
|
+
|
85
|
+
if ( na_a->rank != na_b->rank ) {
|
86
|
+
rb_raise( rb_eArgError, "narray a must have equal rank to narray b (a rack %d, b rank %d)", na_a->rank, na_b->rank );
|
87
|
+
}
|
88
|
+
|
89
|
+
if ( na_a->rank > LARGEST_RANK ) {
|
90
|
+
rb_raise( rb_eArgError, "exceeded maximum narray rank for convolve of %d", LARGEST_RANK );
|
91
|
+
}
|
92
|
+
|
93
|
+
target_rank = na_a->rank;
|
94
|
+
|
95
|
+
for ( i = 0; i < target_rank; i++ ) {
|
96
|
+
target_shape[i] = na_a->shape[i] - na_b->shape[i] + 1;
|
97
|
+
if ( target_shape[i] < 1 ) {
|
98
|
+
rb_raise( rb_eArgError, "narray b is bigger in one or more dimensions than narray a" );
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
val_c = na_make_object( NA_SFLOAT, target_rank, target_shape, CLASS_OF( val_a ) );
|
103
|
+
GetNArray( val_c, na_c );
|
104
|
+
|
105
|
+
convolve_raw(
|
106
|
+
target_rank, na_a->shape, (float*) na_a->ptr,
|
107
|
+
target_rank, na_b->shape, (float*) na_b->ptr,
|
108
|
+
target_rank, target_shape, (float*) na_c->ptr );
|
109
|
+
|
110
|
+
return val_c;
|
111
|
+
}
|
112
|
+
|
113
|
+
void Init_convolver() {
|
114
|
+
Convolver = rb_define_module( "Convolver" );
|
115
|
+
rb_define_singleton_method( Convolver, "convolve_basic", narray_convolve, 2 );
|
116
|
+
|
117
|
+
// private method
|
118
|
+
rb_define_singleton_method( Convolver, "fit_kernel_backwards", narray_fit_backwards, 2 );
|
119
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# ext/convolver/extconf.rb
|
2
|
+
require "mkmf"
|
3
|
+
require "rubygems"
|
4
|
+
|
5
|
+
# Following code stolen shamelessly from fftw3 gem:
|
6
|
+
narray_dir = File.dirname(Gem.find_files("narray.h").first) rescue $sitearchdir
|
7
|
+
dir_config('narray', narray_dir, narray_dir)
|
8
|
+
|
9
|
+
if ( ! ( have_header("narray.h") && have_header("narray_config.h") ) ) then
|
10
|
+
print <<-EOS
|
11
|
+
** configure error **
|
12
|
+
Header narray.h or narray_config.h is not found. If you have these files in
|
13
|
+
/narraydir/include, try the following:
|
14
|
+
|
15
|
+
% ruby extconf.rb --with-narray-include=/narraydir/include
|
16
|
+
|
17
|
+
EOS
|
18
|
+
exit(-1)
|
19
|
+
end
|
20
|
+
|
21
|
+
# This also stolen from fftw3 gem (and not confirmed for Windows platforms - please let me know if it works!)
|
22
|
+
if /cygwin|mingw/ =~ RUBY_PLATFORM
|
23
|
+
have_library("narray") || raise("ERROR: narray library is not found")
|
24
|
+
end
|
25
|
+
|
26
|
+
$CFLAGS << ' -O3 -funroll-loops'
|
27
|
+
create_makefile( 'convolver/convolver' )
|
@@ -0,0 +1,61 @@
|
|
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
|
+
}
|
@@ -0,0 +1,22 @@
|
|
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
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'narray'
|
2
|
+
require "convolver/convolver"
|
3
|
+
require "convolver/version"
|
4
|
+
|
5
|
+
module Convolver
|
6
|
+
# The two parameters must have the same rank. The output has same rank, its size in each
|
7
|
+
# dimension d is given by
|
8
|
+
# signal.shape[d] - kernel.shape[d] + 1
|
9
|
+
# @param [NArray] signal must be same size or larger than kernel in each dimension
|
10
|
+
# @param [NArray] kernel must be same size or smaller than signal in each dimension
|
11
|
+
# @return [NArray] result of convolving signal with kernel
|
12
|
+
def self.convolve(signal, kernel)
|
13
|
+
convolve_basic signal, kernel
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'helpers'
|
2
|
+
|
3
|
+
describe Convolver do
|
4
|
+
describe "#convolve_basic" do
|
5
|
+
|
6
|
+
it "should work like the example in the README" do
|
7
|
+
a = NArray[ 0.3, 0.4, 0.5 ]
|
8
|
+
b = NArray[ 1.3, -0.5 ]
|
9
|
+
c = Convolver.convolve_basic( a, b )
|
10
|
+
expect( c ).to be_narray_like NArray[ 0.19, 0.27 ]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should calculate a 2D convolution" do
|
14
|
+
a = NArray[ [ 0.3, 0.4, 0.5 ], [ 0.6, 0.8, 0.2 ], [ 0.9, 1.0, 0.1 ] ]
|
15
|
+
b = NArray[ [ 1.2, -0.5 ], [ 0.5, -1.3 ] ]
|
16
|
+
c = Convolver.convolve_basic( a, b )
|
17
|
+
expect( c ).to be_narray_like NArray[ [ -0.58, 0.37 ], [ -0.53, 1.23 ] ]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should calculate a 2D convolution with rectangular arrays" do
|
21
|
+
a = NArray[ [ 0.3, 0.4, 0.5, 0.3, 0.4 ], [ 0.6, 0.8, 0.2, 0.8, 0.2 ],
|
22
|
+
[ 0.9, 1.0, 0.1, 0.9, 1.0 ], [ 0.5, 0.9, 0.3, 0.2, 0.8 ], [ 0.7, 0.1, 0.3, 0.0, 0.1 ],
|
23
|
+
[ 0.4, 0.5, 0.6, 0.7, 0.8 ], [ 0.5, 0.4, 0.3, 0.2, 0.1 ] ]
|
24
|
+
b = NArray[ [ 1.2, -0.5, 0.2 ], [ 1.8, 0.5, -1.3 ] ]
|
25
|
+
c = Convolver.convolve_basic( a, b )
|
26
|
+
expect( c ).to be_narray_like NArray[ [ 1.48, 0.79, 1.03 ], [ 2.35, 1.7, -0.79 ], [ 1.56, 2.84, -0.53 ],
|
27
|
+
[ 1.13, 1.3, 0.83 ], [ 1.04, 0.26, 0.77 ], [ 1.06, 1.05, 1.04 ] ]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should calculate a 3D convolution" do
|
31
|
+
# 5x4x3
|
32
|
+
a = NArray[
|
33
|
+
[ [ 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 ], [ 0.5, 0.9, 0.2, 0.1, 0.6 ] ],
|
34
|
+
[ [ 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 ], [ 0.1, 0.9, 0.7, 0.1, 0.3 ] ],
|
35
|
+
[ [ 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 ], [ 0.2, 0.5, 0.4, 0.7, 0.2 ] ]
|
36
|
+
]
|
37
|
+
|
38
|
+
# 3x3x3
|
39
|
+
b = NArray[
|
40
|
+
[ [ -0.9, 1.2, 0.8 ], [ 0.9, 0.1, -0.5 ], [ 1.1, 0.1, -1.1 ] ],
|
41
|
+
[ [ -0.2, -1.0, 1.4 ], [ -1.4, 0.0, 1.3 ], [ 0.3, 1.0, -0.5 ] ],
|
42
|
+
[ [ 0.6, 0.0, 0.7 ], [ -0.7, 1.1, 1.2 ], [ 1.3, 0.7, 0.0 ] ]
|
43
|
+
]
|
44
|
+
|
45
|
+
# Should be 3x2x1
|
46
|
+
c = Convolver.convolve_basic( a, b )
|
47
|
+
expect( c ).to be_narray_like NArray[ [ [ 5.51, 3.04, 4.3 ], [ 3.04, 6.31, 3.87 ] ] ]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should calculate a 4D convolution" do
|
51
|
+
# 3x4x5x3
|
52
|
+
a = NArray[
|
53
|
+
[ [ [ 0.5, 0.4, 0.9 ], [ 0.1, 0.9, 0.8 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ],
|
54
|
+
[ [ 0.0, 0.4, 0.0 ], [ 0.2, 0.3, 0.8 ], [ 0.6, 0.3, 0.2 ], [ 0.7, 0.4, 0.3 ] ],
|
55
|
+
[ [ 0.3, 0.3, 0.1 ], [ 0.6, 0.9, 0.4 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ],
|
56
|
+
[ [ 0.0, 0.4, 0.0 ], [ 0.2, 0.3, 0.8 ], [ 0.6, 0.3, 0.2 ], [ 0.7, 0.4, 0.3 ] ],
|
57
|
+
[ [ 0.3, 0.3, 0.1 ], [ 0.6, 0.9, 0.4 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ] ],
|
58
|
+
[ [ [ 0.5, 0.4, 0.9 ], [ 0.1, 0.9, 0.8 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ],
|
59
|
+
[ [ 0.0, 0.4, 0.0 ], [ 0.2, 0.3, 0.8 ], [ 0.6, 0.3, 0.2 ], [ 0.7, 0.4, 0.3 ] ],
|
60
|
+
[ [ 0.3, 0.3, 0.1 ], [ 0.6, 0.9, 0.4 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ],
|
61
|
+
[ [ 0.0, 0.4, 0.0 ], [ 0.2, 0.3, 0.8 ], [ 0.6, 0.3, 0.2 ], [ 0.7, 0.4, 0.3 ] ],
|
62
|
+
[ [ 0.3, 0.3, 0.1 ], [ 0.6, 0.9, 0.4 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ] ],
|
63
|
+
[ [ [ 0.5, 0.4, 0.9 ], [ 0.1, 0.9, 0.8 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ],
|
64
|
+
[ [ 0.0, 0.4, 0.0 ], [ 0.2, 0.3, 0.8 ], [ 0.6, 0.3, 0.2 ], [ 0.7, 0.4, 0.3 ] ],
|
65
|
+
[ [ 0.3, 0.3, 0.1 ], [ 0.6, 0.9, 0.4 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ],
|
66
|
+
[ [ 0.0, 0.4, 0.0 ], [ 0.2, 0.3, 0.8 ], [ 0.6, 0.3, 0.2 ], [ 0.7, 0.4, 0.3 ] ],
|
67
|
+
[ [ 0.3, 0.3, 0.1 ], [ 0.6, 0.9, 0.4 ], [ 0.4, 0.0, 0.1 ], [ 0.8, 0.3, 0.4 ] ] ] ]
|
68
|
+
|
69
|
+
# 2x3x3x2
|
70
|
+
b = NArray[ [
|
71
|
+
[ [ 1.1, 0.6 ], [ 1.2, 0.6 ], [ 0.8, 0.1 ] ], [ [ -0.4, 0.8 ], [ 0.5, 0.4 ], [ 1.2, 0.2 ] ],
|
72
|
+
[ [ 0.8, 0.2 ], [ 0.5, 0.0 ], [ 1.4, 1.3 ] ] ],
|
73
|
+
[ [ [ 1.1, 0.6 ], [ 1.2, 0.6 ], [ 0.8, 0.1 ] ], [ [ -0.4, 0.8 ], [ 0.5, 0.4 ], [ 1.2, 0.2 ] ],
|
74
|
+
[ [ 0.8, 0.2 ], [ 0.5, 0.0 ], [ 1.4, 1.3 ] ] ] ]
|
75
|
+
|
76
|
+
# Should be 2x2x3x2
|
77
|
+
c = Convolver.convolve_basic( a, b )
|
78
|
+
expect( c ).to be_narray_like NArray[
|
79
|
+
[ [ [ 8.5, 8.2 ], [ 11.34, 9.68 ] ], [ [ 7.68, 6.56 ], [ 11.24, 7.16 ] ], [ [ 9.14, 6.54 ], [ 12.44, 9.2 ] ] ],
|
80
|
+
[ [ [ 8.5, 8.2 ], [ 11.34, 9.68 ] ], [ [ 7.68, 6.56 ], [ 11.24, 7.16 ] ], [ [ 9.14, 6.54 ], [ 12.44, 9.2 ] ] ]
|
81
|
+
]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'helpers'
|
2
|
+
|
3
|
+
describe Convolver do
|
4
|
+
describe "#convolve" do
|
5
|
+
|
6
|
+
it "should work like the example in the README" do
|
7
|
+
a = NArray[ 0.3, 0.4, 0.5 ]
|
8
|
+
b = NArray[ 1.3, -0.5 ]
|
9
|
+
c = Convolver.convolve( a, b )
|
10
|
+
expect( c ).to be_narray_like NArray[ 0.19, 0.27 ]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should process convolutions of different sizes" do
|
14
|
+
# The variety here is to ensure all branches of optimisation algorithm
|
15
|
+
# are covered
|
16
|
+
[10,30,60,90,100,120,130,150,175,200].each do |asize|
|
17
|
+
[5,10,12,15,20,30,40,50].each do |bsize|
|
18
|
+
next unless bsize < asize
|
19
|
+
a = NArray.sfloat(asize,asize).random()
|
20
|
+
b = NArray.sfloat(bsize,bsize).random()
|
21
|
+
c = Convolver.convolve( a, b )
|
22
|
+
|
23
|
+
# We should always match output of convolve_basic irrespective
|
24
|
+
# of what the optimal choice of algorithm is (larger error allowed here due to rounding)
|
25
|
+
expect_result = Convolver.convolve_basic( a, b )
|
26
|
+
expect( c ).to be_narray_like( expect_result, 1e-6 )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should choose #convolve_basic for small inputs" do
|
32
|
+
a = NArray.sfloat(50,50).random()
|
33
|
+
b = NArray.sfloat(10,10).random()
|
34
|
+
expect(Convolver).to receive(:convolve_basic).once
|
35
|
+
expect(Convolver).to_not receive(:convolve_fftw3)
|
36
|
+
c = Convolver.convolve( a, b )
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should choose #convolve_fftw3 for large inputs" do
|
40
|
+
a = NArray.sfloat(500,500).random()
|
41
|
+
b = NArray.sfloat(100,100).random()
|
42
|
+
expect(Convolver).to receive(:convolve_fftw3).once
|
43
|
+
expect(Convolver).to_not receive(:convolve_basic)
|
44
|
+
c = Convolver.convolve( a, b )
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/spec/helpers.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# convolver/spec/helpers.rb
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
Coveralls.wear!
|
5
|
+
|
6
|
+
require 'convolver'
|
7
|
+
|
8
|
+
# Matcher compares NArrays numerically
|
9
|
+
RSpec::Matchers.define :be_narray_like do |expected_narray, mse = 1e-9|
|
10
|
+
match do |given|
|
11
|
+
@error = nil
|
12
|
+
if ! given.is_a?(NArray)
|
13
|
+
@error = "Wrong class."
|
14
|
+
elsif given.shape != expected_narray.shape
|
15
|
+
@error = "Shapes are different."
|
16
|
+
else
|
17
|
+
d = given - expected_narray
|
18
|
+
difference = ( d * d ).sum / d.size
|
19
|
+
if difference > mse
|
20
|
+
@error = "Numerical difference with mean square error #{difference}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
@given = given.clone
|
24
|
+
|
25
|
+
if @error
|
26
|
+
@expected = expected_narray.clone
|
27
|
+
end
|
28
|
+
|
29
|
+
! @error
|
30
|
+
end
|
31
|
+
|
32
|
+
failure_message do
|
33
|
+
"NArray does not match supplied example. #{@error}
|
34
|
+
Expected: #{@expected.inspect}
|
35
|
+
Got: #{@given.inspect}"
|
36
|
+
end
|
37
|
+
|
38
|
+
failure_message_when_negated do
|
39
|
+
"NArray is too close to unwanted example.
|
40
|
+
Unwanted: #{@given.inspect}"
|
41
|
+
end
|
42
|
+
|
43
|
+
description do |given, expected|
|
44
|
+
"numerically very close to example"
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: convolver-light
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dima Ermilov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-11-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: narray
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !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
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.6.0.8
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: yard
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.8.7.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.8.7.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.13.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.13.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.9.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.9.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake-compiler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.8.3
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.8.3
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: coveralls
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.6.7
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.6.7
|
111
|
+
description: Simplification of convolver gem, FFTW removed, suitable only for smaller
|
112
|
+
kernels. Convolver gem author is Neil Slater, slobo777@gmail.com, https://github.com/neilslater
|
113
|
+
email:
|
114
|
+
- dima@scriptangle.com
|
115
|
+
executables: []
|
116
|
+
extensions:
|
117
|
+
- ext/convolver/extconf.rb
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- ".gitignore"
|
121
|
+
- ".travis.yml"
|
122
|
+
- Gemfile
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- convolver-light.gemspec
|
127
|
+
- ext/convolver/convolve_raw.c
|
128
|
+
- ext/convolver/convolve_raw.h
|
129
|
+
- ext/convolver/convolver.c
|
130
|
+
- ext/convolver/extconf.rb
|
131
|
+
- ext/convolver/narray_shared.c
|
132
|
+
- ext/convolver/narray_shared.h
|
133
|
+
- lib/convolver-light.rb
|
134
|
+
- lib/convolver/version.rb
|
135
|
+
- spec/convolve_basic_spec.rb
|
136
|
+
- spec/convolve_spec.rb
|
137
|
+
- spec/helpers.rb
|
138
|
+
homepage: http://github.com/adworse/convolver-light
|
139
|
+
licenses:
|
140
|
+
- MIT
|
141
|
+
metadata: {}
|
142
|
+
post_install_message:
|
143
|
+
rdoc_options: []
|
144
|
+
require_paths:
|
145
|
+
- lib
|
146
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
requirements: []
|
157
|
+
rubyforge_project:
|
158
|
+
rubygems_version: 2.7.6
|
159
|
+
signing_key:
|
160
|
+
specification_version: 4
|
161
|
+
summary: Convolution for NArray simplified.
|
162
|
+
test_files:
|
163
|
+
- spec/convolve_basic_spec.rb
|
164
|
+
- spec/convolve_spec.rb
|
165
|
+
- spec/helpers.rb
|