multiarray 0.11.3 → 0.11.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +61 -0
- data/Rakefile +1 -1
- data/lib/multiarray.rb +28 -0
- data/lib/multiarray/complex.rb +310 -13
- data/lib/multiarray/composite.rb +7 -0
- data/lib/multiarray/diagonal.rb +18 -3
- data/lib/multiarray/elementwise.rb +7 -2
- data/lib/multiarray/float.rb +43 -3
- data/lib/multiarray/gcccache.rb +4 -1
- data/lib/multiarray/gcccontext.rb +119 -21
- data/lib/multiarray/gccfunction.rb +92 -3
- data/lib/multiarray/gcctype.rb +26 -0
- data/lib/multiarray/gccvalue.rb +204 -2
- data/lib/multiarray/histogram.rb +65 -1
- data/lib/multiarray/index.rb +11 -0
- data/lib/multiarray/inject.rb +18 -1
- data/lib/multiarray/int.rb +49 -18
- data/lib/multiarray/integral.rb +65 -1
- data/lib/multiarray/lambda.rb +19 -5
- data/lib/multiarray/list.rb +8 -0
- data/lib/multiarray/lookup.rb +8 -1
- data/lib/multiarray/lut.rb +96 -2
- data/lib/multiarray/methods.rb +13 -3
- data/lib/multiarray/multiarray.rb +11 -0
- data/lib/multiarray/node.rb +52 -9
- data/lib/multiarray/operations.rb +118 -15
- data/lib/multiarray/pointer.rb +35 -1
- data/lib/multiarray/rgb.rb +139 -14
- data/lib/multiarray/sequence.rb +140 -2
- data/lib/multiarray/shortcuts.rb +76 -30
- data/lib/multiarray/store.rb +54 -0
- data/lib/multiarray/variable.rb +19 -0
- data/test/tc_lazy.rb +9 -0
- metadata +3 -3
data/lib/multiarray/methods.rb
CHANGED
@@ -17,11 +17,15 @@
|
|
17
17
|
# Namespace of Hornetseye computer vision library
|
18
18
|
module Hornetseye
|
19
19
|
|
20
|
+
# Module providing the methods to manipulate array expressions
|
20
21
|
module Methods
|
21
22
|
|
22
|
-
# Extend some methods in the specified module
|
23
|
+
# Extend some methods in the specified module
|
23
24
|
#
|
24
25
|
# @param [Module] mod The mathematics module.
|
26
|
+
# @return The return value should be ignored.
|
27
|
+
#
|
28
|
+
# @private
|
25
29
|
def Methods.included( mod )
|
26
30
|
define_unary_method mod, :sqrt , :float
|
27
31
|
define_unary_method mod, :log , :float
|
@@ -43,11 +47,14 @@ module Hornetseye
|
|
43
47
|
define_binary_method mod, :hypot, :floating
|
44
48
|
end
|
45
49
|
|
46
|
-
# Extend unary method with capability to handle arrays
|
50
|
+
# Extend unary method with capability to handle arrays
|
47
51
|
#
|
48
52
|
# @param [Module] mod The mathematics module.
|
49
53
|
# @param [Symbol,String] op The unary method to extend.
|
50
54
|
# @param [Symbol,String] conversion A method for doing the type conversion.
|
55
|
+
# @return [Proc] The new method.
|
56
|
+
#
|
57
|
+
# @private
|
51
58
|
def define_unary_method( mod, op, conversion = :contiguous )
|
52
59
|
mod.module_eval do
|
53
60
|
define_method( "#{op}_with_hornetseye" ) do |a|
|
@@ -73,11 +80,14 @@ module Hornetseye
|
|
73
80
|
|
74
81
|
module_function :define_unary_method
|
75
82
|
|
76
|
-
# Extend binary method with capability to handle arrays
|
83
|
+
# Extend binary method with capability to handle arrays
|
77
84
|
#
|
78
85
|
# @param [Module] mod The mathematics module.
|
79
86
|
# @param [Symbol,String] op The binary method to extend.
|
80
87
|
# @param [Symbol,String] conversion A method for doing the type balancing.
|
88
|
+
# @return [Proc] The new method.
|
89
|
+
#
|
90
|
+
# @private
|
81
91
|
def define_binary_method( mod, op, coercion = :coercion )
|
82
92
|
mod.module_eval do
|
83
93
|
define_method( "#{op}_with_hornetseye" ) do |a,b|
|
@@ -26,6 +26,8 @@ module Hornetseye
|
|
26
26
|
#
|
27
27
|
# @param [Class] typecode The type of elements
|
28
28
|
# @param [Array<Integer>] *shape The shape of the multi-dimensional array.
|
29
|
+
#
|
30
|
+
# @return [Node] Returns uninitialised native array.
|
29
31
|
def new( typecode, *shape )
|
30
32
|
options = shape.last.is_a?( Hash ) ? shape.pop : {}
|
31
33
|
count = options[ :count ] || 1
|
@@ -44,6 +46,15 @@ module Hornetseye
|
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
49
|
+
# Import array from string
|
50
|
+
#
|
51
|
+
# Create an array from raw data provided as a string.
|
52
|
+
#
|
53
|
+
# @param [Class] typecode Type of the elements in the string.
|
54
|
+
# @param [String] string String with raw data.
|
55
|
+
# @param [Array<Integer>] shape Array with dimensions of array.
|
56
|
+
#
|
57
|
+
# @return [Node] Multi-dimensional array with imported data.
|
47
58
|
def import( typecode, string, *shape )
|
48
59
|
t = Hornetseye::MultiArray typecode, *shape
|
49
60
|
if string.is_a? Malloc
|
data/lib/multiarray/node.rb
CHANGED
@@ -43,7 +43,7 @@ module Hornetseye
|
|
43
43
|
#
|
44
44
|
# @private
|
45
45
|
def descriptor( hash )
|
46
|
-
|
46
|
+
name
|
47
47
|
end
|
48
48
|
|
49
49
|
# Find matching native datatype to a Ruby value
|
@@ -117,10 +117,16 @@ module Hornetseye
|
|
117
117
|
[]
|
118
118
|
end
|
119
119
|
|
120
|
+
# Get width of two-dimensional array
|
121
|
+
#
|
122
|
+
# @return [Integer] Width of array.
|
120
123
|
def width
|
121
124
|
shape[0]
|
122
125
|
end
|
123
126
|
|
127
|
+
# Get height of two-dimensional array
|
128
|
+
#
|
129
|
+
# @return [Integer] Height of array.
|
124
130
|
def height
|
125
131
|
shape[1]
|
126
132
|
end
|
@@ -155,6 +161,9 @@ module Hornetseye
|
|
155
161
|
self
|
156
162
|
end
|
157
163
|
|
164
|
+
# Check whether this object is an RGB value
|
165
|
+
#
|
166
|
+
# @return [Boolean] Returns +false+.
|
158
167
|
def rgb?
|
159
168
|
false
|
160
169
|
end
|
@@ -237,6 +246,12 @@ module Hornetseye
|
|
237
246
|
coercion( other ).byte
|
238
247
|
end
|
239
248
|
|
249
|
+
# Get byte-based datatype for ternary operation
|
250
|
+
#
|
251
|
+
# @param [Class] a The second type.
|
252
|
+
# @param [Class] a The third type.
|
253
|
+
#
|
254
|
+
# @return [Class] Returns type based on bytes.
|
240
255
|
def cond( a, b )
|
241
256
|
t = a.coercion b
|
242
257
|
Hornetseye::MultiArray( t.typecode, *shape ).coercion t
|
@@ -336,6 +351,9 @@ module Hornetseye
|
|
336
351
|
array_type.typecode
|
337
352
|
end
|
338
353
|
|
354
|
+
# Base-type of this term
|
355
|
+
#
|
356
|
+
# @return [Class] Base-type of this datatype.
|
339
357
|
def basetype
|
340
358
|
array_type.basetype
|
341
359
|
end
|
@@ -347,10 +365,16 @@ module Hornetseye
|
|
347
365
|
array_type.shape
|
348
366
|
end
|
349
367
|
|
368
|
+
# Get width of two-dimensional array
|
369
|
+
#
|
370
|
+
# @return [Integer] Width of array.
|
350
371
|
def width
|
351
372
|
array_type.width
|
352
373
|
end
|
353
374
|
|
375
|
+
# Get height of two-dimensional array
|
376
|
+
#
|
377
|
+
# @return [Integer] Height of array.
|
354
378
|
def height
|
355
379
|
array_type.height
|
356
380
|
end
|
@@ -362,15 +386,21 @@ module Hornetseye
|
|
362
386
|
array_type.size
|
363
387
|
end
|
364
388
|
|
389
|
+
# Get memory size of object
|
390
|
+
#
|
391
|
+
# @return [Integer] Returns required storage size of this array.
|
365
392
|
def storage_size
|
366
393
|
array_type.storage_size
|
367
394
|
end
|
368
395
|
|
396
|
+
# Get memory object
|
397
|
+
#
|
398
|
+
# @return [Malloc,List,NilClass] This method will return +nil+.
|
369
399
|
def memory
|
370
400
|
nil
|
371
401
|
end
|
372
402
|
|
373
|
-
# Check whether this object is an empty array
|
403
|
+
# Check whether this object is an empty array
|
374
404
|
#
|
375
405
|
# @return [Boolean] Returns whether this object is an empty array.
|
376
406
|
def empty?
|
@@ -384,6 +414,9 @@ module Hornetseye
|
|
384
414
|
array_type.dimension
|
385
415
|
end
|
386
416
|
|
417
|
+
# Check whether this object is an RGB value
|
418
|
+
#
|
419
|
+
# @return [Boolean] Returns +false+.
|
387
420
|
def rgb?
|
388
421
|
array_type.rgb?
|
389
422
|
end
|
@@ -553,14 +586,24 @@ module Hornetseye
|
|
553
586
|
end
|
554
587
|
end
|
555
588
|
|
589
|
+
# Check arguments for compatible shape
|
590
|
+
#
|
591
|
+
# The method will throw an exception if one of the arguments has an incompatible
|
592
|
+
# shape.
|
593
|
+
#
|
594
|
+
# @param [Array<Node>] args Arguments to check for compatibility.
|
595
|
+
#
|
596
|
+
# @return [Object] The return value should be ignored.
|
556
597
|
def check_shape( *args )
|
598
|
+
_shape = shape
|
557
599
|
args.each do |arg|
|
558
|
-
|
600
|
+
_arg_shape = arg.shape
|
601
|
+
if _shape.size < _arg_shape.size
|
559
602
|
raise "#{arg.array_type.inspect} has #{arg.dimension} dimension(s) " +
|
560
603
|
"but should not have more than #{dimension}"
|
561
604
|
end
|
562
|
-
if (
|
563
|
-
if
|
605
|
+
if ( _shape + _arg_shape ).all? { |s| s.is_a? Integer }
|
606
|
+
if _shape.last( _arg_shape.size ) != _arg_shape
|
564
607
|
raise "#{arg.array_type.inspect} has shape #{arg.shape.inspect} " +
|
565
608
|
"(does not match last value(s) of #{shape.inspect})"
|
566
609
|
end
|
@@ -578,7 +621,7 @@ module Hornetseye
|
|
578
621
|
# @return [Object,Node] Returns the value.
|
579
622
|
def []=( *indices )
|
580
623
|
value = indices.pop
|
581
|
-
value =
|
624
|
+
value = typecode.new value unless value.is_a? Node
|
582
625
|
if indices.empty?
|
583
626
|
check_shape value
|
584
627
|
unless compilable? and value.compilable? and dimension > 0
|
@@ -638,10 +681,10 @@ module Hornetseye
|
|
638
681
|
#
|
639
682
|
# @private
|
640
683
|
def force
|
641
|
-
if
|
642
|
-
self
|
643
|
-
elsif finalised?
|
684
|
+
if finalised?
|
644
685
|
get
|
686
|
+
elsif ( dimension > 0 and Thread.current[ :lazy ] ) or not variables.empty?
|
687
|
+
self
|
645
688
|
elsif compilable?
|
646
689
|
retval = pointer_type.new
|
647
690
|
GCCFunction.run Store.new( retval, self )
|
@@ -17,8 +17,17 @@
|
|
17
17
|
# Namespace of Hornetseye computer vision library
|
18
18
|
module Hornetseye
|
19
19
|
|
20
|
+
# Module providing the operations to manipulate array expressions
|
20
21
|
module Operations
|
21
22
|
|
23
|
+
# Meta-programming method to define a unary operation
|
24
|
+
#
|
25
|
+
# @param [Symbol,String] op Name of unary operation.
|
26
|
+
# @param [Symbol,String] conversion Name of method for type conversion.
|
27
|
+
#
|
28
|
+
# @return [Proc] The new method.
|
29
|
+
#
|
30
|
+
# @private
|
22
31
|
def define_unary_op( op, conversion = :contiguous )
|
23
32
|
define_method( op ) do
|
24
33
|
if dimension == 0 and variables.empty?
|
@@ -34,6 +43,14 @@ module Hornetseye
|
|
34
43
|
|
35
44
|
module_function :define_unary_op
|
36
45
|
|
46
|
+
# Meta-programming method to define a binary operation
|
47
|
+
#
|
48
|
+
# @param [Symbol,String] op Name of binary operation.
|
49
|
+
# @param [Symbol,String] conversion Name of method for type conversion.
|
50
|
+
#
|
51
|
+
# @return [Proc] The new method.
|
52
|
+
#
|
53
|
+
# @private
|
37
54
|
def define_binary_op( op, coercion = :coercion )
|
38
55
|
define_method( op ) do |other|
|
39
56
|
unless other.is_a? Node
|
@@ -87,10 +104,20 @@ module Hornetseye
|
|
87
104
|
define_binary_op :minor
|
88
105
|
define_binary_op :major
|
89
106
|
|
107
|
+
# This operation has no effect
|
108
|
+
#
|
109
|
+
# @return [Node] Returns +self+.
|
110
|
+
#
|
111
|
+
# @private
|
90
112
|
def +@
|
91
113
|
self
|
92
114
|
end
|
93
115
|
|
116
|
+
# Convert array elements to different element type
|
117
|
+
#
|
118
|
+
# @param [Class] dest Element type to convert to.
|
119
|
+
#
|
120
|
+
# @return [Node] Array based on the different element type.
|
94
121
|
def to_type( dest )
|
95
122
|
if dimension == 0 and variables.empty?
|
96
123
|
target = typecode.to_type dest
|
@@ -102,6 +129,13 @@ module Hornetseye
|
|
102
129
|
end
|
103
130
|
end
|
104
131
|
|
132
|
+
# Convert RGB array to scalar array
|
133
|
+
#
|
134
|
+
# This operation is a special case handling colour to greyscale conversion.
|
135
|
+
#
|
136
|
+
# @param [Class] dest Element type to convert to.
|
137
|
+
#
|
138
|
+
# @return [Node] Array based on the different element type.
|
105
139
|
def to_type_with_rgb( dest )
|
106
140
|
if typecode < RGB_
|
107
141
|
if dest < FLOAT_
|
@@ -118,6 +152,12 @@ module Hornetseye
|
|
118
152
|
|
119
153
|
alias_method_chain :to_type, :rgb
|
120
154
|
|
155
|
+
# Element-wise conditional selection of values
|
156
|
+
#
|
157
|
+
# @param [Node] a First array of values.
|
158
|
+
# @param [Node] b Second array of values.
|
159
|
+
#
|
160
|
+
# @return [Node] Array with selected values.
|
121
161
|
def conditional( a, b )
|
122
162
|
unless a.is_a? Node
|
123
163
|
a = Node.match( a, b.is_a?( Node ) ? b : nil ).new a
|
@@ -137,6 +177,11 @@ module Hornetseye
|
|
137
177
|
end
|
138
178
|
end
|
139
179
|
|
180
|
+
# Element-wise comparison of values
|
181
|
+
#
|
182
|
+
# @param [Node] other Array with values to compare with.
|
183
|
+
#
|
184
|
+
# @return [Node] Array with results.
|
140
185
|
def <=>( other )
|
141
186
|
Hornetseye::lazy do
|
142
187
|
( self < other ).conditional -1, ( self > other ).conditional( 1, 0 )
|
@@ -162,6 +207,11 @@ module Hornetseye
|
|
162
207
|
inject( term ) { |retval,var| Lambda.new var, retval }
|
163
208
|
end
|
164
209
|
|
210
|
+
# Cycle indices of array
|
211
|
+
#
|
212
|
+
# @param [Integer] n Number of times to cycle indices of array.
|
213
|
+
#
|
214
|
+
# @return [Node] Resulting array expression with different order of indices.
|
165
215
|
def roll( n = 1 )
|
166
216
|
if n < 0
|
167
217
|
unroll -n
|
@@ -172,6 +222,11 @@ module Hornetseye
|
|
172
222
|
end
|
173
223
|
end
|
174
224
|
|
225
|
+
# Reverse-cycle indices of array
|
226
|
+
#
|
227
|
+
# @param [Integer] n Number of times to cycle back indices of array.
|
228
|
+
#
|
229
|
+
# @return [Node] Resulting array expression with different order of indices.
|
175
230
|
def unroll( n = 1 )
|
176
231
|
if n < 0
|
177
232
|
roll -n
|
@@ -182,6 +237,11 @@ module Hornetseye
|
|
182
237
|
end
|
183
238
|
end
|
184
239
|
|
240
|
+
# Perform element-wise operation on array
|
241
|
+
#
|
242
|
+
# @param [Proc] action Operation(s) to perform on elements.
|
243
|
+
#
|
244
|
+
# @return [Node] The resulting array.
|
185
245
|
def collect( &action )
|
186
246
|
var = Variable.new typecode
|
187
247
|
block = action.call var
|
@@ -189,8 +249,22 @@ module Hornetseye
|
|
189
249
|
Hornetseye::ElementWise( action, block.to_s, conversion ).new( self ).force
|
190
250
|
end
|
191
251
|
|
252
|
+
# Perform element-wise operation on array
|
253
|
+
#
|
254
|
+
# @param [Proc] action Operation(s) to perform on elements.
|
255
|
+
#
|
256
|
+
# @return [Node] The resulting array.
|
192
257
|
alias_method :map, :collect
|
193
258
|
|
259
|
+
# Perform cummulative operation on array
|
260
|
+
#
|
261
|
+
# @param [Object] initial Initial value for cummulative operation.
|
262
|
+
# @option options [Variable] :var1 First variable defining operation.
|
263
|
+
# @option options [Variable] :var1 Second variable defining operation.
|
264
|
+
# @option options [Variable] :block (yield( var1, var2 )) The operation to
|
265
|
+
# apply.
|
266
|
+
#
|
267
|
+
# @return [Object] Result of injection.
|
194
268
|
def inject( initial = nil, options = {} )
|
195
269
|
unless initial.nil?
|
196
270
|
initial = Node.match( initial ).new initial unless initial.is_a? Node
|
@@ -209,8 +283,9 @@ module Hornetseye
|
|
209
283
|
end
|
210
284
|
else
|
211
285
|
index = Variable.new Hornetseye::INDEX( nil )
|
212
|
-
value = element( index ).
|
213
|
-
|
286
|
+
value = element( index ).inject nil, :block => block,
|
287
|
+
:var1 => var1, :var2 => var2
|
288
|
+
value = typecode.new value unless value.is_a? Node
|
214
289
|
Inject.new( value, index, initial, block, var1, var2 ).force
|
215
290
|
end
|
216
291
|
end
|
@@ -236,22 +311,39 @@ module Hornetseye
|
|
236
311
|
|
237
312
|
alias_method_chain :==, :multiarray, :eq
|
238
313
|
|
314
|
+
# Find minimum value of array
|
315
|
+
#
|
316
|
+
# @return [Object] Minimum value of array.
|
239
317
|
def min
|
240
318
|
inject { |a,b| a.minor b }
|
241
319
|
end
|
242
320
|
|
321
|
+
# Find maximum value of array
|
322
|
+
#
|
323
|
+
# @return [Object] Maximum value of array.
|
243
324
|
def max
|
244
325
|
inject { |a,b| a.major b }
|
245
326
|
end
|
246
327
|
|
328
|
+
# Compute sum of array
|
329
|
+
#
|
330
|
+
# @return [Object] Sum of array.
|
247
331
|
def sum
|
248
332
|
inject { |a,b| a + b }
|
249
333
|
end
|
250
334
|
|
335
|
+
# Find range of values of array
|
336
|
+
#
|
337
|
+
# @return [Object] Range of values of array.
|
251
338
|
def range
|
252
339
|
min .. max
|
253
340
|
end
|
254
341
|
|
342
|
+
# Normalise values of array
|
343
|
+
#
|
344
|
+
# @param [Range] range Target range of normalisation.
|
345
|
+
#
|
346
|
+
# @return [Node] Array with normalised values.
|
255
347
|
def normalise( range = 0 .. 0xFF )
|
256
348
|
if range.exclude_end?
|
257
349
|
raise "Normalisation does not support ranges with end value " +
|
@@ -273,6 +365,11 @@ module Hornetseye
|
|
273
365
|
end
|
274
366
|
end
|
275
367
|
|
368
|
+
# Fill array with a value
|
369
|
+
#
|
370
|
+
# @param [Object] value Value to fill array with.
|
371
|
+
#
|
372
|
+
# @return [Node] Return +self+.
|
276
373
|
def fill!( value = typecode.default )
|
277
374
|
self[] = value
|
278
375
|
self
|
@@ -355,12 +452,20 @@ module Hornetseye
|
|
355
452
|
product( filter ).diagonal { |s,x| s + x }
|
356
453
|
end
|
357
454
|
|
455
|
+
# Compute histogram of this array
|
456
|
+
#
|
457
|
+
# @overload histogram( *ret_shape, options = {} )
|
458
|
+
# @param [Array<Integer>] ret_shape Dimensions of resulting histogram.
|
459
|
+
# @option options [Boolean] :safe (true) Do a boundary check before creating the
|
460
|
+
# histogram.
|
461
|
+
#
|
462
|
+
# @return [Node] The histogram.
|
358
463
|
def histogram( *ret_shape )
|
359
464
|
options = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {}
|
360
465
|
options = { :target => UINT, :safe => true }.merge options
|
361
466
|
if options[ :safe ]
|
362
467
|
if shape.first != 1 and ret_shape.size == 1
|
363
|
-
right = Hornetseye::lazy( 1 ) {
|
468
|
+
right = Hornetseye::lazy( 1 ) { self }.unroll
|
364
469
|
else
|
365
470
|
if shape.first != ret_shape.size
|
366
471
|
raise "First dimension of array (#{shape.first}) differs from number of " +
|
@@ -395,12 +500,13 @@ module Hornetseye
|
|
395
500
|
left
|
396
501
|
end
|
397
502
|
|
398
|
-
#
|
399
|
-
#
|
400
|
-
#
|
401
|
-
|
402
|
-
#
|
403
|
-
|
503
|
+
# Perform element-wise lookup
|
504
|
+
#
|
505
|
+
# @param [Node] table The lookup table (LUT).
|
506
|
+
# @option options [Boolean] :safe (true) Do a boundary check before creating the
|
507
|
+
# element-wise lookup.
|
508
|
+
#
|
509
|
+
# @return [Node] The result of the lookup operation.
|
404
510
|
def lut( table, options = {} )
|
405
511
|
options = { :safe => true }.merge options
|
406
512
|
if options[ :safe ]
|
@@ -441,12 +547,9 @@ module Hornetseye
|
|
441
547
|
end
|
442
548
|
end
|
443
549
|
|
444
|
-
#
|
445
|
-
#
|
446
|
-
#
|
447
|
-
|
448
|
-
#alias_method_chain :lut, :composite
|
449
|
-
|
550
|
+
# Compute integral image
|
551
|
+
#
|
552
|
+
# @return [Node] The integral image of this array.
|
450
553
|
def integral
|
451
554
|
left = pointer_type.new
|
452
555
|
block = Integral.new left, self
|