multiarray 0.5.1 → 0.5.2
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/Rakefile +3 -3
- data/TODO +7 -31
- data/lib/multiarray.rb +8 -4
- data/lib/multiarray/complex.rb +360 -0
- data/lib/multiarray/composite.rb +65 -0
- data/lib/multiarray/diagonal.rb +8 -0
- data/lib/multiarray/element.rb +3 -3
- data/lib/multiarray/{unarymethod.rb → elementwise.rb} +66 -44
- data/lib/multiarray/gccfunction.rb +14 -20
- data/lib/multiarray/gcctype.rb +8 -8
- data/lib/multiarray/gccvalue.rb +57 -15
- data/lib/multiarray/inject.rb +10 -2
- data/lib/multiarray/lambda.rb +21 -3
- data/lib/multiarray/lookup.rb +8 -0
- data/lib/multiarray/methods.rb +10 -4
- data/lib/multiarray/node.rb +80 -15
- data/lib/multiarray/operations.rb +193 -12
- data/lib/multiarray/pointer.rb +19 -0
- data/lib/multiarray/rgb.rb +15 -45
- data/lib/multiarray/sequence.rb +34 -5
- data/test/tc_float.rb +20 -41
- data/test/tc_int.rb +10 -0
- data/test/tc_multiarray.rb +225 -49
- data/test/tc_object.rb +11 -0
- data/test/tc_rgb.rb +15 -0
- data/test/tc_sequence.rb +224 -11
- metadata +13 -9
- data/lib/multiarray/binarymethod.rb +0 -195
- data/lib/multiarray/binaryop.rb +0 -189
- data/lib/multiarray/unaryop.rb +0 -179
@@ -0,0 +1,65 @@
|
|
1
|
+
# multiarray - Lazy multi-dimensional arrays for Ruby
|
2
|
+
# Copyright (C) 2010 Jan Wedekind
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Namespace of Hornetseye computer vision library
|
18
|
+
module Hornetseye
|
19
|
+
|
20
|
+
class Composite < Element
|
21
|
+
|
22
|
+
class << self
|
23
|
+
|
24
|
+
attr_accessor :element_type
|
25
|
+
|
26
|
+
attr_accessor :num_elements
|
27
|
+
|
28
|
+
def memory
|
29
|
+
element_type.memory
|
30
|
+
end
|
31
|
+
|
32
|
+
def storage_size
|
33
|
+
element_type.storage_size * num_elements
|
34
|
+
end
|
35
|
+
|
36
|
+
def directive
|
37
|
+
element_type.directive * num_elements
|
38
|
+
end
|
39
|
+
|
40
|
+
def descriptor( hash )
|
41
|
+
unless element_type.nil?
|
42
|
+
inspect
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def basetype
|
49
|
+
element_type
|
50
|
+
end
|
51
|
+
|
52
|
+
def typecodes
|
53
|
+
[ element_type ] * num_elements
|
54
|
+
end
|
55
|
+
|
56
|
+
def scalar
|
57
|
+
element_type
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
data/lib/multiarray/diagonal.rb
CHANGED
data/lib/multiarray/element.rb
CHANGED
@@ -56,7 +56,7 @@ module Hornetseye
|
|
56
56
|
#
|
57
57
|
# @param [Object] value Initial value for element.
|
58
58
|
def initialize( value = self.class.default )
|
59
|
-
if Thread.current[ :function ].nil?
|
59
|
+
if Thread.current[ :function ].nil?
|
60
60
|
@value = value
|
61
61
|
else
|
62
62
|
@value = GCCValue.new Thread.current[ :function ], value.to_s
|
@@ -84,8 +84,8 @@ module Hornetseye
|
|
84
84
|
def dup
|
85
85
|
if Thread.current[ :function ]
|
86
86
|
value = Thread.current[ :function ].variable self.class, 'v'
|
87
|
-
value.
|
88
|
-
value
|
87
|
+
value.store get
|
88
|
+
self.class.new value
|
89
89
|
else
|
90
90
|
self.class.new get
|
91
91
|
end
|
@@ -17,31 +17,30 @@
|
|
17
17
|
# Namespace of Hornetseye computer vision library
|
18
18
|
module Hornetseye
|
19
19
|
|
20
|
-
|
21
|
-
class UnaryMethod_ < Node
|
20
|
+
class ElementWise_ < Node
|
22
21
|
|
23
22
|
class << self
|
24
23
|
|
25
|
-
# Name of module
|
26
|
-
#
|
27
|
-
# @return [Module] The module with the method.
|
28
|
-
attr_accessor :mod
|
29
|
-
|
30
24
|
# Name of operation
|
31
25
|
#
|
32
|
-
# @return [
|
26
|
+
# @return [Proc] A closure with the operation.
|
33
27
|
attr_accessor :operation
|
34
28
|
|
29
|
+
# Unique key to identify operation.
|
30
|
+
#
|
31
|
+
# @return [Symbol,String] A unique key to identify this operation.
|
32
|
+
attr_accessor :key
|
33
|
+
|
35
34
|
# Name of method for type conversion
|
36
35
|
#
|
37
|
-
# @return [
|
36
|
+
# @return [Proc] A closure for doing the type conversion.
|
38
37
|
attr_accessor :conversion
|
39
38
|
|
40
39
|
# Get string with information about this class
|
41
40
|
#
|
42
41
|
# @return [String] Return string with information about this class.
|
43
42
|
def inspect
|
44
|
-
|
43
|
+
key.to_s
|
45
44
|
end
|
46
45
|
|
47
46
|
# Get unique descriptor of this class
|
@@ -55,13 +54,18 @@ module Hornetseye
|
|
55
54
|
inspect
|
56
55
|
end
|
57
56
|
|
57
|
+
def finalised?
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
58
61
|
end
|
59
62
|
|
60
63
|
# Initialise unary operation
|
61
64
|
#
|
62
65
|
# @param [Node] value Value to apply operation to.
|
63
|
-
def initialize(
|
64
|
-
@
|
66
|
+
def initialize( *values )
|
67
|
+
@values = values
|
68
|
+
check_shape *values
|
65
69
|
end
|
66
70
|
|
67
71
|
# Get unique descriptor of this object
|
@@ -72,7 +76,8 @@ module Hornetseye
|
|
72
76
|
#
|
73
77
|
# @private
|
74
78
|
def descriptor( hash )
|
75
|
-
"#{self.class.descriptor( hash )}
|
79
|
+
"#{self.class.descriptor( hash )}" +
|
80
|
+
"(#{@values.collect { |value| value.descriptor( hash ) }.join ','})"
|
76
81
|
end
|
77
82
|
|
78
83
|
# Array type of this term
|
@@ -81,7 +86,19 @@ module Hornetseye
|
|
81
86
|
#
|
82
87
|
# @private
|
83
88
|
def array_type
|
84
|
-
@value.array_type
|
89
|
+
array_types = @values.collect { |value| value.array_type }
|
90
|
+
self.class.conversion.call *array_types
|
91
|
+
end
|
92
|
+
|
93
|
+
# Reevaluate computation
|
94
|
+
#
|
95
|
+
# @return [Node,Object] Result of computation
|
96
|
+
#
|
97
|
+
# @see #force
|
98
|
+
#
|
99
|
+
# @private
|
100
|
+
def demand
|
101
|
+
self.class.operation.call *@values
|
85
102
|
end
|
86
103
|
|
87
104
|
# Substitute variables
|
@@ -94,7 +111,7 @@ module Hornetseye
|
|
94
111
|
#
|
95
112
|
# @private
|
96
113
|
def subst( hash )
|
97
|
-
self.class.new
|
114
|
+
self.class.new *@values.collect { |value| value.subst( hash ) }
|
98
115
|
end
|
99
116
|
|
100
117
|
# Get variables contained in this term
|
@@ -103,7 +120,7 @@ module Hornetseye
|
|
103
120
|
#
|
104
121
|
# @private
|
105
122
|
def variables
|
106
|
-
@value.variables
|
123
|
+
@values.inject( Set[] ) { |vars,value| vars + value.variables }
|
107
124
|
end
|
108
125
|
|
109
126
|
# Strip of all values
|
@@ -116,23 +133,15 @@ module Hornetseye
|
|
116
133
|
#
|
117
134
|
# @private
|
118
135
|
def strip
|
119
|
-
|
120
|
-
return vars,
|
121
|
-
|
122
|
-
|
123
|
-
# Reevaluate computation
|
124
|
-
#
|
125
|
-
# @return [Node,Object] Result of computation
|
126
|
-
#
|
127
|
-
# @see #force
|
128
|
-
#
|
129
|
-
# @private
|
130
|
-
def demand
|
131
|
-
self.class.mod.send self.class.operation, @value
|
136
|
+
stripped = @values.collect { |value| value.strip }
|
137
|
+
return stripped.inject( [] ) { |vars,elem| vars + elem[ 0 ] },
|
138
|
+
stripped.inject( [] ) { |values,elem| values + elem[ 1 ] },
|
139
|
+
self.class.new( *stripped.collect { |elem| elem[ 2 ] } )
|
132
140
|
end
|
133
141
|
|
134
142
|
def skip( index, start )
|
135
|
-
|
143
|
+
skipped = *@values.collect { |value| value.skip( index, start ) }
|
144
|
+
self.class.new( *skipped ).demand
|
136
145
|
end
|
137
146
|
|
138
147
|
# Get element of unary operation
|
@@ -141,11 +150,22 @@ module Hornetseye
|
|
141
150
|
#
|
142
151
|
# @return [Node,Object] Element of unary operation.
|
143
152
|
def element( i )
|
144
|
-
|
153
|
+
values = @values.collect do |value|
|
154
|
+
value.dimension == 0 ? value : value.element( i )
|
155
|
+
end
|
156
|
+
self.class.new( *values ).demand
|
145
157
|
end
|
146
158
|
|
147
159
|
def slice( start, length )
|
148
|
-
|
160
|
+
values = @values.collect do |value|
|
161
|
+
value.dimension == 0 ? value : value.slice( start, length )
|
162
|
+
end
|
163
|
+
self.class.new( *values ).demand
|
164
|
+
end
|
165
|
+
|
166
|
+
def decompose
|
167
|
+
values = @values.collect { |value| value.decompose }
|
168
|
+
self.class.new( *values ).demand
|
149
169
|
end
|
150
170
|
|
151
171
|
# Check whether this term is compilable
|
@@ -154,32 +174,34 @@ module Hornetseye
|
|
154
174
|
#
|
155
175
|
# @private
|
156
176
|
def compilable?
|
157
|
-
@value.compilable?
|
177
|
+
array_type.compilable? and @values.all? { |value| value.compilable? }
|
158
178
|
end
|
159
179
|
|
160
180
|
end
|
161
181
|
|
162
|
-
# Create a class deriving from +
|
182
|
+
# Create a class deriving from +ElementWise_+
|
163
183
|
#
|
164
|
-
# @param [
|
165
|
-
# @param [Symbol,String]
|
184
|
+
# @param [Proc] operation A closure with the operation to perform.
|
185
|
+
# @param [Symbol,String] key A unique descriptor to identify this operation.
|
186
|
+
# @param [Proc] conversion A closure for performing the type conversion.
|
166
187
|
#
|
167
|
-
# @return [Class] A class deriving from +
|
188
|
+
# @return [Class] A class deriving from +ElementWise_+.
|
168
189
|
#
|
169
|
-
# @see
|
170
|
-
# @see
|
171
|
-
# @see
|
190
|
+
# @see ElementWise_
|
191
|
+
# @see ElementWise_.operation
|
192
|
+
# @see ElementWise_.key
|
193
|
+
# @see ElementWise_.conversion
|
172
194
|
#
|
173
195
|
# @private
|
174
|
-
def
|
175
|
-
retval = Class.new
|
176
|
-
retval.mod = mod
|
196
|
+
def ElementWise( operation, key, conversion = lambda { |t| t.send :contiguous } )
|
197
|
+
retval = Class.new ElementWise_
|
177
198
|
retval.operation = operation
|
199
|
+
retval.key = key
|
178
200
|
retval.conversion = conversion
|
179
201
|
retval
|
180
202
|
end
|
181
203
|
|
182
|
-
module_function :
|
204
|
+
module_function :ElementWise
|
183
205
|
|
184
206
|
end
|
185
207
|
|
@@ -21,25 +21,29 @@ module Hornetseye
|
|
21
21
|
|
22
22
|
class << self
|
23
23
|
|
24
|
-
def run( block )
|
24
|
+
def run( retval, block )
|
25
25
|
keys, values, term = block.strip
|
26
|
-
labels = Hash[ *keys.
|
27
|
-
|
26
|
+
labels = Hash[ *keys.
|
27
|
+
zip( ( 0 ... keys.size ).to_a ).flatten ]
|
28
28
|
retval_keys, retval_values, retval_term = retval.strip
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
retval_labels = Hash[ *retval_keys.
|
30
|
+
zip( ( 0 ... retval_keys.size ).to_a ).flatten ]
|
31
|
+
method_name = ( '_' + retval_term.descriptor( retval_labels ) +
|
32
|
+
'_' + term.descriptor( labels ) ).
|
33
|
+
tr( '(),+\-*/%.@?~&|^<=>',
|
34
|
+
'0123\456789ABCDEFGH' )
|
32
35
|
unless GCCCache.respond_to? method_name
|
33
36
|
GCCContext.build do |context|
|
34
37
|
function = new context, method_name,
|
35
38
|
*( retval_keys + keys ).collect { |var| var.meta }
|
39
|
+
Thread.current[ :function ] = function
|
36
40
|
term_subst = ( 0 ... keys.size ).collect do |i|
|
37
41
|
{ keys[i] => function.param( i + retval_keys.size ) }
|
38
42
|
end.inject( {} ) { |a,b| a.merge b }
|
39
43
|
retval_subst = ( 0 ... retval_keys.size ).collect do |i|
|
40
44
|
{ retval_keys[ i ] => function.param( i ) }
|
41
45
|
end.inject( {} ) { |a,b| a.merge b }
|
42
|
-
Thread.current[ :function ] = function
|
46
|
+
# Thread.current[ :function ] = function
|
43
47
|
Hornetseye::lazy do
|
44
48
|
retval_term.subst( retval_subst ).store term.subst( term_subst )
|
45
49
|
end
|
@@ -76,19 +80,9 @@ module Hornetseye
|
|
76
80
|
end
|
77
81
|
|
78
82
|
def variable( typecode, prefix )
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# b = GCCValue.new( self, id( prefix ) )
|
83
|
-
# self << "#{indent}#{GCCType.new( INT ).identifier} #{r};\n"
|
84
|
-
# self << "#{indent}#{GCCType.new( INT ).identifier} #{g};\n"
|
85
|
-
# self << "#{indent}#{GCCType.new( INT ).identifier} #{b};\n"
|
86
|
-
# INTRGB.new RGB.new( r, g, b )
|
87
|
-
#else
|
88
|
-
retval = typecode.new GCCValue.new( self, id( prefix ) )
|
89
|
-
self << "#{indent}#{GCCType.new( typecode ).identifiers.first} #{retval.get};\n" # !!!
|
90
|
-
retval
|
91
|
-
#end
|
83
|
+
retval = GCCValue.new( self, id( prefix ) )
|
84
|
+
self << "#{indent}#{GCCType.new( typecode ).identifiers.first} #{retval};\n" # !!!
|
85
|
+
retval
|
92
86
|
end
|
93
87
|
|
94
88
|
def indent
|
data/lib/multiarray/gcctype.rb
CHANGED
@@ -50,8 +50,8 @@ module Hornetseye
|
|
50
50
|
[ 'void *' ]
|
51
51
|
elsif @typecode < INDEX_
|
52
52
|
[ 'int' ]
|
53
|
-
elsif @typecode <
|
54
|
-
GCCType.new( @typecode.element_type ).identifiers *
|
53
|
+
elsif @typecode < Composite
|
54
|
+
GCCType.new( @typecode.element_type ).identifiers * @typecode.num_elements
|
55
55
|
else
|
56
56
|
raise "No identifier available for #{@typecode.inspect}"
|
57
57
|
end
|
@@ -61,16 +61,16 @@ module Hornetseye
|
|
61
61
|
def r2c
|
62
62
|
case @typecode
|
63
63
|
when BOOL
|
64
|
-
[
|
64
|
+
[ lambda { |expr| "( #{expr} ) != Qfalse" } ]
|
65
65
|
when BYTE, UBYTE, SINT, USINT, INT, UINT
|
66
|
-
[
|
66
|
+
[ lambda { |expr| "NUM2INT( #{expr} )" } ]
|
67
67
|
when SFLOAT, DFLOAT
|
68
|
-
[
|
68
|
+
[ lambda { |expr| "NUM2DBL( #{expr} )" } ]
|
69
69
|
else
|
70
70
|
if @typecode < Pointer_
|
71
|
-
[
|
72
|
-
elsif @typecode <
|
73
|
-
GCCType.new( @typecode.element_type ).r2c *
|
71
|
+
[ lambda { |expr| "(#{identifiers.first})mallocToPtr( #{expr} )" } ] # !!!
|
72
|
+
elsif @typecode < Composite
|
73
|
+
GCCType.new( @typecode.element_type ).r2c * @typecode.num_elements
|
74
74
|
else
|
75
75
|
raise "No conversion available for #{@typecode.inspect}"
|
76
76
|
end
|
data/lib/multiarray/gccvalue.rb
CHANGED
@@ -62,7 +62,8 @@ module Hornetseye
|
|
62
62
|
mod.module_eval do
|
63
63
|
define_method( "#{op}_with_gcc" ) do |a,b|
|
64
64
|
if a.is_a? GCCValue or b.is_a? GCCValue
|
65
|
-
|
65
|
+
function = a.is_a?( GCCValue ) ? a.function : b.function
|
66
|
+
GCCValue.new function, "#{opcode}( #{a}, #{b} )"
|
66
67
|
else
|
67
68
|
send "#{op}_without_gcc", a, b
|
68
69
|
end
|
@@ -117,6 +118,18 @@ module Hornetseye
|
|
117
118
|
end
|
118
119
|
end
|
119
120
|
|
121
|
+
def conj
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
def abs
|
126
|
+
( self >= 0 ).conditional self, -self
|
127
|
+
end
|
128
|
+
|
129
|
+
def arg
|
130
|
+
( self >= 0 ).conditional 0, Math::PI
|
131
|
+
end
|
132
|
+
|
120
133
|
def r
|
121
134
|
self
|
122
135
|
end
|
@@ -129,6 +142,14 @@ module Hornetseye
|
|
129
142
|
self
|
130
143
|
end
|
131
144
|
|
145
|
+
def real
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
def imag
|
150
|
+
0
|
151
|
+
end
|
152
|
+
|
132
153
|
def conditional( a, b )
|
133
154
|
GCCValue.new @function, "( #{self} ) ? ( #{a} ) : ( #{b} )"
|
134
155
|
end
|
@@ -147,6 +168,7 @@ module Hornetseye
|
|
147
168
|
define_binary_op :-
|
148
169
|
define_binary_op :*
|
149
170
|
define_binary_op :/
|
171
|
+
define_binary_op :%
|
150
172
|
define_binary_op :eq, :==
|
151
173
|
define_binary_op :ne, '!='
|
152
174
|
define_binary_op :<
|
@@ -168,6 +190,34 @@ module Hornetseye
|
|
168
190
|
define_binary_method Math, :atan2
|
169
191
|
define_binary_method Math, :hypot
|
170
192
|
|
193
|
+
def zero?
|
194
|
+
GCCValue.new @function, "( #{self} ) == 0"
|
195
|
+
end
|
196
|
+
|
197
|
+
def nonzero?
|
198
|
+
GCCValue.new @function, "( #{self} ) != 0"
|
199
|
+
end
|
200
|
+
|
201
|
+
def floor
|
202
|
+
GCCValue.new @function, "floor( #{self} )"
|
203
|
+
end
|
204
|
+
|
205
|
+
def ceil
|
206
|
+
GCCValue.new @function, "ceil( #{self} )"
|
207
|
+
end
|
208
|
+
|
209
|
+
def round
|
210
|
+
GCCValue.new @function, "round( #{self} )"
|
211
|
+
end
|
212
|
+
|
213
|
+
def **( other )
|
214
|
+
if GCCValue.generic? other
|
215
|
+
GCCValue.new @function, "pow( #{self}, #{other} )"
|
216
|
+
else
|
217
|
+
x, y = other.coerce self
|
218
|
+
x ** y
|
219
|
+
end
|
220
|
+
end
|
171
221
|
|
172
222
|
def major( other )
|
173
223
|
GCCValue.new @function,
|
@@ -179,20 +229,12 @@ module Hornetseye
|
|
179
229
|
"( ( #{self} ) <= ( #{other} ) ) ? ( #{self} ) : ( #{other} )"
|
180
230
|
end
|
181
231
|
|
182
|
-
def zero?
|
183
|
-
GCCValue.new @function, "( #{self} ) == 0"
|
184
|
-
end
|
185
|
-
|
186
|
-
def nonzero?
|
187
|
-
GCCValue.new @function, "( #{self} ) != 0"
|
188
|
-
end
|
189
|
-
|
190
232
|
def times( &action )
|
191
233
|
i = @function.variable INT, 'i'
|
192
|
-
@function << "#{@function.indent}for ( #{i
|
193
|
-
"#{i
|
234
|
+
@function << "#{@function.indent}for ( #{i} = 0; " +
|
235
|
+
"#{i} != #{self}; #{i}++ ) {\n"
|
194
236
|
@function.indent_offset +1
|
195
|
-
action.call i
|
237
|
+
action.call i
|
196
238
|
@function.indent_offset -1
|
197
239
|
@function << "#{@function.indent}};\n"
|
198
240
|
self
|
@@ -200,10 +242,10 @@ module Hornetseye
|
|
200
242
|
|
201
243
|
def upto( other, &action )
|
202
244
|
i = @function.variable INT, 'i'
|
203
|
-
@function << "#{@function.indent}for ( #{i
|
204
|
-
"#{i
|
245
|
+
@function << "#{@function.indent}for ( #{i} = #{self}; " +
|
246
|
+
"#{i} != #{ other + 1 }; #{i}++ ) {\n"
|
205
247
|
@function.indent_offset +1
|
206
|
-
action.call i
|
248
|
+
action.call i
|
207
249
|
@function.indent_offset -1
|
208
250
|
@function << "#{@function.indent}};\n"
|
209
251
|
self
|