multiarray 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -1
- data/TODO +7 -36
- data/lib/multiarray/bool.rb +14 -4
- data/lib/multiarray/complex.rb +467 -38
- data/lib/multiarray/composite.rb +44 -0
- data/lib/multiarray/diagonal.rb +10 -3
- data/lib/multiarray/element.rb +29 -3
- data/lib/multiarray/elementwise.rb +32 -3
- data/lib/multiarray/float.rb +120 -18
- data/lib/multiarray/gccfunction.rb +11 -21
- data/lib/multiarray/gcctype.rb +23 -17
- data/lib/multiarray/gccvalue.rb +25 -2
- data/lib/multiarray/histogram.rb +82 -0
- data/lib/multiarray/index.rb +23 -0
- data/lib/multiarray/inject.rb +13 -1
- data/lib/multiarray/int.rb +105 -9
- data/lib/multiarray/integral.rb +82 -0
- data/lib/multiarray/lambda.rb +58 -8
- data/lib/multiarray/list.rb +27 -1
- data/lib/multiarray/lookup.rb +60 -0
- data/lib/multiarray/lut.rb +102 -0
- data/lib/multiarray/malloc.rb +16 -0
- data/lib/multiarray/methods.rb +17 -0
- data/lib/multiarray/multiarray.rb +24 -2
- data/lib/multiarray/node.rb +115 -21
- data/lib/multiarray/object.rb +34 -4
- data/lib/multiarray/operations.rb +92 -100
- data/lib/multiarray/pointer.rb +74 -1
- data/lib/multiarray/rgb.rb +324 -2
- data/lib/multiarray/sequence.rb +69 -4
- data/lib/multiarray/shortcuts.rb +71 -0
- data/lib/multiarray/store.rb +72 -0
- data/lib/multiarray/variable.rb +25 -0
- data/lib/multiarray.rb +47 -5
- data/test/tc_int.rb +10 -0
- data/test/tc_multiarray.rb +47 -1
- data/test/tc_object.rb +10 -0
- data/test/tc_sequence.rb +237 -8
- metadata +9 -9
data/lib/multiarray/object.rb
CHANGED
@@ -24,7 +24,7 @@ module Hornetseye
|
|
24
24
|
|
25
25
|
# Get string with information about this class
|
26
26
|
#
|
27
|
-
# @return [String] Returns
|
27
|
+
# @return [String] Returns 'OBJECT'.
|
28
28
|
def inspect
|
29
29
|
'OBJECT'
|
30
30
|
end
|
@@ -69,6 +69,13 @@ module Hornetseye
|
|
69
69
|
nil
|
70
70
|
end
|
71
71
|
|
72
|
+
# Compute balanced type for binary operation
|
73
|
+
#
|
74
|
+
# @param [Class] other Other type to coerce with.
|
75
|
+
#
|
76
|
+
# @return [Class] Result of coercion.
|
77
|
+
#
|
78
|
+
# @private
|
72
79
|
def coercion( other )
|
73
80
|
if other < Sequence_
|
74
81
|
other.coercion self
|
@@ -77,7 +84,7 @@ module Hornetseye
|
|
77
84
|
end
|
78
85
|
end
|
79
86
|
|
80
|
-
#
|
87
|
+
# Type coercion for native elements
|
81
88
|
#
|
82
89
|
# @param [Node,Object] other Other object.
|
83
90
|
#
|
@@ -86,17 +93,25 @@ module Hornetseye
|
|
86
93
|
return self, self
|
87
94
|
end
|
88
95
|
|
96
|
+
# Get corresponding boolean-based datatype
|
97
|
+
#
|
98
|
+
# @return [Class] Returns +self+.
|
89
99
|
def bool
|
90
100
|
self
|
91
101
|
end
|
92
102
|
|
103
|
+
# Convert to type based on floating point numbers
|
104
|
+
#
|
105
|
+
# @return [Class] Corresponding type based on floating point numbers.
|
106
|
+
#
|
107
|
+
# @private
|
93
108
|
def float
|
94
109
|
OBJECT
|
95
110
|
end
|
96
111
|
|
97
112
|
# Check whether this term is compilable
|
98
113
|
#
|
99
|
-
# @return [
|
114
|
+
# @return [Boolean] Returns +false+.
|
100
115
|
#
|
101
116
|
# @private
|
102
117
|
def compilable?
|
@@ -115,7 +130,7 @@ module Hornetseye
|
|
115
130
|
# Method for matching elements of type OBJECT
|
116
131
|
#
|
117
132
|
# @param [Array<Object>] *values Values to find matching native element
|
118
|
-
#
|
133
|
+
# type for.
|
119
134
|
#
|
120
135
|
# @return [Class] Native type fitting all values.
|
121
136
|
#
|
@@ -126,6 +141,14 @@ module Hornetseye
|
|
126
141
|
OBJECT
|
127
142
|
end
|
128
143
|
|
144
|
+
# Perform type alignment
|
145
|
+
#
|
146
|
+
# Align this type to another. This is used to prefer single-precision
|
147
|
+
# floating point in certain cases.
|
148
|
+
#
|
149
|
+
# @param [Class] context Other type to align with.
|
150
|
+
#
|
151
|
+
# @private
|
129
152
|
def align( context )
|
130
153
|
self
|
131
154
|
end
|
@@ -136,6 +159,13 @@ module Hornetseye
|
|
136
159
|
|
137
160
|
end
|
138
161
|
|
162
|
+
# Shortcut for constructor
|
163
|
+
#
|
164
|
+
# The method calls +OBJECT.new+.
|
165
|
+
#
|
166
|
+
# @param [Object] value Ruby object.
|
167
|
+
#
|
168
|
+
# @return [OBJECT] The wrapped Ruby object.
|
139
169
|
def OBJECT( value )
|
140
170
|
OBJECT.new value
|
141
171
|
end
|
@@ -64,11 +64,6 @@ module Hornetseye
|
|
64
64
|
define_unary_op :floor
|
65
65
|
define_unary_op :ceil
|
66
66
|
define_unary_op :round
|
67
|
-
define_unary_op :r, :scalar
|
68
|
-
define_unary_op :g, :scalar
|
69
|
-
define_unary_op :b, :scalar
|
70
|
-
define_unary_op :real, :scalar
|
71
|
-
define_unary_op :imag, :scalar
|
72
67
|
define_binary_op :+
|
73
68
|
define_binary_op :-
|
74
69
|
define_binary_op :*
|
@@ -178,6 +173,8 @@ module Hornetseye
|
|
178
173
|
Hornetseye::ElementWise( action, block.to_s, conversion ).new( self ).force
|
179
174
|
end
|
180
175
|
|
176
|
+
alias_method :map, :collect
|
177
|
+
|
181
178
|
def inject( initial = nil, options = {} )
|
182
179
|
unless initial.nil?
|
183
180
|
initial = Node.match( initial ).new initial unless initial.is_a? Node
|
@@ -204,7 +201,7 @@ module Hornetseye
|
|
204
201
|
|
205
202
|
# Equality operator
|
206
203
|
#
|
207
|
-
# @return [
|
204
|
+
# @return [Boolean] Returns result of comparison.
|
208
205
|
def eq_with_multiarray( other )
|
209
206
|
if other.is_a? Node
|
210
207
|
if variables.empty?
|
@@ -231,6 +228,19 @@ module Hornetseye
|
|
231
228
|
inject { |a,b| a.major b }
|
232
229
|
end
|
233
230
|
|
231
|
+
def sum
|
232
|
+
inject { |a,b| a + b }
|
233
|
+
end
|
234
|
+
|
235
|
+
def range
|
236
|
+
min .. max
|
237
|
+
end
|
238
|
+
|
239
|
+
def fill!( value = typecode.default )
|
240
|
+
self[] = value
|
241
|
+
self
|
242
|
+
end
|
243
|
+
|
234
244
|
# Apply accumulative operation over elements diagonally
|
235
245
|
#
|
236
246
|
# This method is used internally to implement convolutions.
|
@@ -239,7 +249,7 @@ module Hornetseye
|
|
239
249
|
# @option options [Variable] :var1 First variable defining operation.
|
240
250
|
# @option options [Variable] :var2 Second variable defining operation.
|
241
251
|
# @option options [Variable] :block (yield( var1, var2 )) The operation to
|
242
|
-
#
|
252
|
+
# apply diagonally.
|
243
253
|
# @yield Optional operation to apply diagonally.
|
244
254
|
#
|
245
255
|
# @return [Node] Result of operation.
|
@@ -308,124 +318,106 @@ module Hornetseye
|
|
308
318
|
product( filter ).diagonal { |s,x| s + x }
|
309
319
|
end
|
310
320
|
|
311
|
-
def
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
def r=( value )
|
324
|
-
if typecode < RGB_
|
325
|
-
decompose.roll[ 0 ] = value
|
326
|
-
elsif typecode == OBJECT
|
327
|
-
self[] = Hornetseye::lazy do
|
328
|
-
value * RGB.new( 1, 0, 0 ) + g * RGB.new( 0, 1, 0 ) + b * RGB.new( 0, 0, 1 )
|
321
|
+
def histogram( *ret_shape )
|
322
|
+
options = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {}
|
323
|
+
options = { :target => UINT, :safe => true }.merge options
|
324
|
+
if options[ :safe ]
|
325
|
+
if shape.first != 1 and ret_shape.size == 1
|
326
|
+
right = Hornetseye::lazy( 1 ) { |i| self }.unroll
|
327
|
+
else
|
328
|
+
if shape.first != ret_shape.size
|
329
|
+
raise "First dimension of array (#{shape.first}) differs from number of " +
|
330
|
+
"dimensions of histogram (#{ret_shape.size})"
|
331
|
+
end
|
332
|
+
right = self
|
329
333
|
end
|
330
334
|
else
|
331
|
-
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
def g_with_decompose
|
336
|
-
if typecode < RGB_
|
337
|
-
decompose.roll.element 1
|
338
|
-
elsif typecode == OBJECT
|
339
|
-
g_without_decompose
|
340
|
-
else
|
341
|
-
self
|
335
|
+
right = self
|
342
336
|
end
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
337
|
+
if options[ :safe ]
|
338
|
+
for i in 0 ... right.shape.first
|
339
|
+
range = right.roll[ i ].range
|
340
|
+
if range.begin < 0
|
341
|
+
raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " +
|
342
|
+
"(but was #{range.begin})"
|
343
|
+
end
|
344
|
+
if range.end >= ret_shape[ i ]
|
345
|
+
raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " +
|
346
|
+
"(but was #{range.end})"
|
347
|
+
end
|
353
348
|
end
|
349
|
+
end
|
350
|
+
left = MultiArray.new options[ :target ], *ret_shape
|
351
|
+
left[] = 0
|
352
|
+
block = Histogram.new left, right
|
353
|
+
if block.compilable?
|
354
|
+
GCCFunction.run block
|
354
355
|
else
|
355
|
-
|
356
|
+
block.demand
|
356
357
|
end
|
358
|
+
left
|
357
359
|
end
|
358
360
|
|
359
|
-
def
|
360
|
-
|
361
|
-
decompose.roll.element 2
|
362
|
-
elsif typecode == OBJECT
|
363
|
-
b_without_decompose
|
364
|
-
else
|
365
|
-
self
|
366
|
-
end
|
361
|
+
def histogram_with_composite( *ret_shape )
|
362
|
+
decompose.histogram_without_composite *ret_shape
|
367
363
|
end
|
368
364
|
|
369
|
-
alias_method_chain :
|
365
|
+
alias_method_chain :histogram, :composite
|
370
366
|
|
371
|
-
def
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
367
|
+
def lut( table, options = {} )
|
368
|
+
options = { :safe => true }.merge options
|
369
|
+
if options[ :safe ]
|
370
|
+
if shape.first != 1 and table.dimension == 1
|
371
|
+
source = Hornetseye::lazy( 1 ) { |i| self }.unroll
|
372
|
+
else
|
373
|
+
if shape.first > table.dimension
|
374
|
+
raise "First dimension of array (#{shape.first}) is greater than the " +
|
375
|
+
" number of dimensions of LUT (#{table.dimension})"
|
376
|
+
end
|
377
|
+
source = self
|
377
378
|
end
|
378
379
|
else
|
379
|
-
|
380
|
+
source = self
|
380
381
|
end
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
382
|
+
if options[ :safe ]
|
383
|
+
for i in 0 ... source.shape.first
|
384
|
+
range = source.roll[ i ].range
|
385
|
+
if range.begin < 0
|
386
|
+
raise "#{i+1}th dimension of index must be in 0 ... #{table.shape[i]} " +
|
387
|
+
"(but was #{range.begin})"
|
388
|
+
end
|
389
|
+
if range.end >= table.shape[ i ]
|
390
|
+
raise "#{i+1}th dimension of index must be in 0 ... #{table.shape[i]} " +
|
391
|
+
"(but was #{range.end})"
|
392
|
+
end
|
393
|
+
end
|
390
394
|
end
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
def real=( value )
|
396
|
-
if typecode < COMPLEX_
|
397
|
-
decompose.roll[ 0 ] = value
|
398
|
-
elsif typecode == OBJECT
|
399
|
-
self[] = Hornetseye::lazy do
|
400
|
-
value + imag * ::Complex::I
|
395
|
+
if source.dimension <= 1 and variables.empty?
|
396
|
+
result = table
|
397
|
+
( table.dimension - 1 ).downto( 0 ) do |i|
|
398
|
+
result = result.element source.element( INT.new( i ) ).demand
|
401
399
|
end
|
400
|
+
result
|
402
401
|
else
|
403
|
-
|
402
|
+
Lut.new( source, table, options[ :n ] ).force
|
404
403
|
end
|
405
404
|
end
|
406
405
|
|
407
|
-
def
|
408
|
-
|
409
|
-
decompose.roll.element 1
|
410
|
-
elsif typecode == OBJECT
|
411
|
-
imag_without_decompose
|
412
|
-
else
|
413
|
-
Hornetseye::lazy( *shape ) { typecode.new( 0 ) }
|
414
|
-
end
|
406
|
+
def lut_with_composite( table, options = {} )
|
407
|
+
decompose.lut_without_composite table, options
|
415
408
|
end
|
416
409
|
|
417
|
-
alias_method_chain :
|
410
|
+
alias_method_chain :lut, :composite
|
418
411
|
|
419
|
-
def
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
real + value * ::Complex::I
|
425
|
-
end
|
412
|
+
def integral
|
413
|
+
left = pointer_type.new
|
414
|
+
block = Integral.new left, self
|
415
|
+
if block.compilable?
|
416
|
+
GCCFunction.run block
|
426
417
|
else
|
427
|
-
|
418
|
+
block.demand
|
428
419
|
end
|
420
|
+
left
|
429
421
|
end
|
430
422
|
|
431
423
|
end
|
data/lib/multiarray/pointer.rb
CHANGED
@@ -25,10 +25,20 @@ module Hornetseye
|
|
25
25
|
# @return [Node] Type of object the pointer is pointing at.
|
26
26
|
attr_accessor :target
|
27
27
|
|
28
|
+
# Construct new object from arguments
|
29
|
+
#
|
30
|
+
# @param [Array<Object>] *args Arguments for constructor.
|
31
|
+
#
|
32
|
+
# @return [Element] New object of this type.
|
33
|
+
#
|
34
|
+
# @private
|
28
35
|
def construct( *args )
|
29
36
|
new *args
|
30
37
|
end
|
31
38
|
|
39
|
+
# Display string with information about this class
|
40
|
+
#
|
41
|
+
# @return [String] String with information about this class (e.g. '*(UBYTE)').
|
32
42
|
def inspect
|
33
43
|
"*(#{target.inspect})"
|
34
44
|
end
|
@@ -46,40 +56,78 @@ module Hornetseye
|
|
46
56
|
|
47
57
|
# Get default value for elements of this type
|
48
58
|
#
|
49
|
-
# @return [Memory,List] Memory for storing object of type +target+.
|
59
|
+
# @return [Memory,List] Memory for storing one object of type +target+.
|
50
60
|
def default
|
51
61
|
target.memory.new target.storage_size
|
52
62
|
end
|
53
63
|
|
64
|
+
# Test equality of classes
|
65
|
+
#
|
66
|
+
# @param [Object] other Object to compare with.
|
67
|
+
#
|
68
|
+
# @return [Boolean] Boolean indicating whether classes are equal.
|
54
69
|
def ==( other )
|
55
70
|
other.is_a? Class and other < Pointer_ and
|
56
71
|
target == other.target
|
57
72
|
end
|
58
73
|
|
74
|
+
# Compute hash value for this class.
|
75
|
+
#
|
76
|
+
# @return [Fixnum] Hash value
|
77
|
+
#
|
78
|
+
# @private
|
59
79
|
def hash
|
60
80
|
[ :Pointer_, target ].hash
|
61
81
|
end
|
62
82
|
|
83
|
+
# Equality for hash operations
|
84
|
+
#
|
85
|
+
# @param [Object] other Object to compare with.
|
86
|
+
#
|
87
|
+
# @return [Boolean] Returns +true+ if objects are equal.
|
88
|
+
#
|
89
|
+
# @private
|
63
90
|
def eql?
|
64
91
|
self == other
|
65
92
|
end
|
66
93
|
|
94
|
+
# Get element type
|
95
|
+
#
|
96
|
+
# @return [Class] Returns the corresponding element type.
|
67
97
|
def typecode
|
68
98
|
target
|
69
99
|
end
|
70
100
|
|
101
|
+
# Base type of this data type
|
102
|
+
#
|
103
|
+
# @return [Class] Returns +element_type+.
|
104
|
+
#
|
105
|
+
# @private
|
71
106
|
def basetype
|
72
107
|
target.basetype
|
73
108
|
end
|
74
109
|
|
110
|
+
# Get type of result of delayed operation
|
111
|
+
#
|
112
|
+
# @return [Class] Type of result.
|
113
|
+
#
|
114
|
+
# @private
|
75
115
|
def array_type
|
76
116
|
target
|
77
117
|
end
|
78
118
|
|
119
|
+
# Get corresponding pointer type
|
120
|
+
#
|
121
|
+
# @return [Class] Returns +self+.
|
79
122
|
def pointer_type
|
80
123
|
self
|
81
124
|
end
|
82
125
|
|
126
|
+
# Check whether objects of this class are finalised computations
|
127
|
+
#
|
128
|
+
# @return [Boolean] Returns +false+.
|
129
|
+
#
|
130
|
+
# @private
|
83
131
|
def finalised?
|
84
132
|
false
|
85
133
|
end
|
@@ -90,6 +138,10 @@ module Hornetseye
|
|
90
138
|
@value = value
|
91
139
|
end
|
92
140
|
|
141
|
+
def memory
|
142
|
+
@value
|
143
|
+
end
|
144
|
+
|
93
145
|
# Strip of all values
|
94
146
|
#
|
95
147
|
# Split up into variables, values, and a term where all values have been
|
@@ -108,6 +160,13 @@ module Hornetseye
|
|
108
160
|
"#{self.class.to_s}(#{@value.to_s})"
|
109
161
|
end
|
110
162
|
|
163
|
+
# Store new value in this pointer
|
164
|
+
#
|
165
|
+
# @param [Object] value New value for this pointer object.
|
166
|
+
#
|
167
|
+
# @return [Object] Returns +value+.
|
168
|
+
#
|
169
|
+
# @private
|
111
170
|
def store( value )
|
112
171
|
result = value.simplify
|
113
172
|
self.class.target.new( result.get ).write @value
|
@@ -140,6 +199,15 @@ module Hornetseye
|
|
140
199
|
end
|
141
200
|
end
|
142
201
|
|
202
|
+
def skip( index, start )
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
# Decompose composite elements
|
207
|
+
#
|
208
|
+
# This method decomposes composite elements into array.
|
209
|
+
#
|
210
|
+
# @return [Node] Result of decomposition.
|
143
211
|
def decompose
|
144
212
|
if self.class.target < Composite
|
145
213
|
pointer = Hornetseye::Pointer( self.class.target.element_type ).new @value
|
@@ -151,6 +219,11 @@ module Hornetseye
|
|
151
219
|
end
|
152
220
|
end
|
153
221
|
|
222
|
+
# Get array with components of this value
|
223
|
+
#
|
224
|
+
# @return [Array<Object>] Get array with value of this object as single element.
|
225
|
+
#
|
226
|
+
# @private
|
154
227
|
def values
|
155
228
|
[ @value ]
|
156
229
|
end
|