multiarray 0.11.3 → 0.11.4
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/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
|