multiarray 0.11.4 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/multiarray.rb +1 -1
- data/lib/multiarray/gccfunction.rb +12 -13
- data/lib/multiarray/histogram.rb +22 -15
- data/lib/multiarray/lut.rb +31 -23
- data/lib/multiarray/node.rb +27 -14
- data/lib/multiarray/operations.rb +100 -69
- data/lib/multiarray/rgb.rb +21 -0
- data/lib/multiarray/sequence.rb +25 -0
- data/test/tc_multiarray.rb +19 -2
- data/test/tc_sequence.rb +4 -0
- metadata +4 -4
data/Rakefile
CHANGED
data/lib/multiarray.rb
CHANGED
@@ -56,9 +56,7 @@ module Hornetseye
|
|
56
56
|
function = GCCFunction.new context, method_name,
|
57
57
|
*keys.collect { |var| var.meta }
|
58
58
|
Thread.current[ :function ] = function
|
59
|
-
term_subst =
|
60
|
-
{ keys[i] => function.param( i ) }
|
61
|
-
end.inject( {} ) { |a,b| a.merge b }
|
59
|
+
term_subst = Hash[ *keys.zip( function.params ).flatten ]
|
62
60
|
Hornetseye::lazy do
|
63
61
|
term.subst( term_subst ).demand
|
64
62
|
end
|
@@ -144,20 +142,21 @@ module Hornetseye
|
|
144
142
|
@indent += offset
|
145
143
|
end
|
146
144
|
|
147
|
-
# Retrieve
|
145
|
+
# Retrieve all parameters
|
148
146
|
#
|
149
|
-
# @
|
150
|
-
#
|
151
|
-
# @return [Node] Object for handling the parameter.
|
147
|
+
# @return [Array<Node>] Objects for handling the parameters.
|
152
148
|
#
|
153
149
|
# @private
|
154
|
-
def
|
155
|
-
|
156
|
-
|
150
|
+
def params
|
151
|
+
idx = 0
|
152
|
+
@param_types.collect do |param_type|
|
153
|
+
args = GCCType.new( param_type ).identifiers.collect do
|
154
|
+
arg = GCCValue.new self, "param#{idx}"
|
155
|
+
idx += 1
|
156
|
+
arg
|
157
|
+
end
|
158
|
+
param_type.construct *args
|
157
159
|
end
|
158
|
-
args = ( 0 ... GCCType.new( @param_types[ i ] ).identifiers.size ).
|
159
|
-
collect { |idx| GCCValue.new self, "param#{ offset + idx }" }
|
160
|
-
@param_types[ i ].construct *args
|
161
160
|
end
|
162
161
|
|
163
162
|
# Call the native method
|
data/lib/multiarray/histogram.rb
CHANGED
@@ -36,11 +36,11 @@ module Hornetseye
|
|
36
36
|
# Constructor
|
37
37
|
#
|
38
38
|
# @param [Node] dest Target array to write histogram to.
|
39
|
-
# @param [Node]
|
39
|
+
# @param [Array<Node>] sources Arrays with elements to compute histogram of.
|
40
40
|
#
|
41
41
|
# @private
|
42
|
-
def initialize( dest,
|
43
|
-
@dest, @
|
42
|
+
def initialize( dest, *sources )
|
43
|
+
@dest, @sources = dest, sources
|
44
44
|
end
|
45
45
|
|
46
46
|
# Get unique descriptor of this object
|
@@ -51,7 +51,8 @@ module Hornetseye
|
|
51
51
|
#
|
52
52
|
# @private
|
53
53
|
def descriptor( hash )
|
54
|
-
"Histogram(#{@dest.descriptor( hash )}
|
54
|
+
"Histogram(#{@dest.descriptor( hash )}," +
|
55
|
+
"#{@sources.collect { |source| source.descriptor( hash ) }.join ','})"
|
55
56
|
end
|
56
57
|
|
57
58
|
# Get type of result of delayed operation
|
@@ -76,15 +77,19 @@ module Hornetseye
|
|
76
77
|
# @private
|
77
78
|
def demand
|
78
79
|
if variables.empty?
|
79
|
-
if @source.dimension >
|
80
|
-
@
|
81
|
-
|
82
|
-
|
80
|
+
if @sources.any? { |source| source.dimension > 0 }
|
81
|
+
source_type = @sources.collect { |source| source.array_type }.
|
82
|
+
inject { |a,b| a.coercion b }
|
83
|
+
source_type.shape.last.times do |i|
|
84
|
+
sources = @sources.collect do |source|
|
85
|
+
source.dimension > 0 ? source.element( INT.new( i ) ) : source
|
86
|
+
end
|
87
|
+
Histogram.new( @dest, *sources ).demand
|
83
88
|
end
|
84
89
|
else
|
85
90
|
dest = @dest
|
86
91
|
( @dest.dimension - 1 ).downto( 0 ) do |i|
|
87
|
-
dest = dest.element @
|
92
|
+
dest = dest.element @sources[ i ].demand
|
88
93
|
end
|
89
94
|
dest.store dest + 1
|
90
95
|
end
|
@@ -104,7 +109,8 @@ module Hornetseye
|
|
104
109
|
#
|
105
110
|
# @private
|
106
111
|
def subst( hash )
|
107
|
-
self.class.new @dest.subst( hash ),
|
112
|
+
self.class.new @dest.subst( hash ),
|
113
|
+
*@sources.collect { |source| source.subst hash }
|
108
114
|
end
|
109
115
|
|
110
116
|
# Get variables contained in this term
|
@@ -113,7 +119,7 @@ module Hornetseye
|
|
113
119
|
#
|
114
120
|
# @private
|
115
121
|
def variables
|
116
|
-
@dest.variables +
|
122
|
+
@sources.inject( @dest.variables ) { |a,b| a + b.variables }
|
117
123
|
end
|
118
124
|
|
119
125
|
# Strip of all values
|
@@ -126,9 +132,10 @@ module Hornetseye
|
|
126
132
|
#
|
127
133
|
# @private
|
128
134
|
def strip
|
129
|
-
|
130
|
-
|
131
|
-
|
135
|
+
stripped = ( [ @dest ] + @sources ).collect { |source| source.strip }
|
136
|
+
return stripped.inject( [] ) { |vars,elem| vars + elem[ 0 ] },
|
137
|
+
stripped.inject( [] ) { |values,elem| values + elem[ 1 ] },
|
138
|
+
self.class.new( *stripped.collect { |elem| elem[ 2 ] } )
|
132
139
|
end
|
133
140
|
|
134
141
|
# Check whether this term is compilable
|
@@ -137,7 +144,7 @@ module Hornetseye
|
|
137
144
|
#
|
138
145
|
# @private
|
139
146
|
def compilable?
|
140
|
-
@dest.compilable? and @source.compilable?
|
147
|
+
@dest.compilable? and @sources.all? { |source| source.compilable? }
|
141
148
|
end
|
142
149
|
|
143
150
|
end
|
data/lib/multiarray/lut.rb
CHANGED
@@ -35,14 +35,13 @@ module Hornetseye
|
|
35
35
|
|
36
36
|
# Constructor
|
37
37
|
#
|
38
|
-
# @
|
39
|
-
#
|
40
|
-
#
|
38
|
+
# @overload initialize( *sources, table )
|
39
|
+
# @param [Array<Node>] sources Arrays with elements for lookup
|
40
|
+
# @param [Node] table Lookup table
|
41
41
|
#
|
42
42
|
# @private
|
43
|
-
def initialize(
|
44
|
-
@
|
45
|
-
@n = n || @source.shape.first
|
43
|
+
def initialize( *args )
|
44
|
+
@sources, @table = args[ 0 ... -1 ], args.last
|
46
45
|
end
|
47
46
|
|
48
47
|
# Get unique descriptor of this object
|
@@ -53,7 +52,8 @@ module Hornetseye
|
|
53
52
|
#
|
54
53
|
# @private
|
55
54
|
def descriptor( hash )
|
56
|
-
"Lut(#{@source.descriptor( hash )}
|
55
|
+
"Lut(#{@sources.collect { |source| source.descriptor( hash ) }.join ','}," +
|
56
|
+
"#{@table.descriptor( hash )})"
|
57
57
|
end
|
58
58
|
|
59
59
|
# Get type of result of delayed operation
|
@@ -62,7 +62,10 @@ module Hornetseye
|
|
62
62
|
#
|
63
63
|
# @private
|
64
64
|
def array_type
|
65
|
-
|
65
|
+
source_type = @sources.collect { |source| source.array_type }.
|
66
|
+
inject { |a,b| a.coercion b }
|
67
|
+
shape = @table.shape.first( @table.dimension - @sources.size ) +
|
68
|
+
source_type.shape
|
66
69
|
retval = Hornetseye::MultiArray @table.typecode, *shape
|
67
70
|
( class << self; self; end ).instance_eval do
|
68
71
|
define_method( :array_type ) { retval }
|
@@ -78,7 +81,7 @@ module Hornetseye
|
|
78
81
|
#
|
79
82
|
# @private
|
80
83
|
def demand
|
81
|
-
@
|
84
|
+
@sources.lut @table, :safe => false
|
82
85
|
end
|
83
86
|
|
84
87
|
# Substitute variables
|
@@ -91,7 +94,8 @@ module Hornetseye
|
|
91
94
|
#
|
92
95
|
# @private
|
93
96
|
def subst( hash )
|
94
|
-
self.class.new @
|
97
|
+
self.class.new *( @sources.collect { |source| source.subst hash } +
|
98
|
+
[ @table.subst( hash ) ] )
|
95
99
|
end
|
96
100
|
|
97
101
|
# Get variables contained in this term
|
@@ -100,7 +104,7 @@ module Hornetseye
|
|
100
104
|
#
|
101
105
|
# @private
|
102
106
|
def variables
|
103
|
-
@
|
107
|
+
@sources.inject( @table.variables ) { |a,b| a + b.variables }
|
104
108
|
end
|
105
109
|
|
106
110
|
# Strip of all values
|
@@ -113,9 +117,10 @@ module Hornetseye
|
|
113
117
|
#
|
114
118
|
# @private
|
115
119
|
def strip
|
116
|
-
|
117
|
-
|
118
|
-
|
120
|
+
stripped = ( @sources + [ @table ] ).collect { |source| source.strip }
|
121
|
+
return stripped.inject( [] ) { |vars,elem| vars + elem[ 0 ] },
|
122
|
+
stripped.inject( [] ) { |values,elem| values + elem[ 1 ] },
|
123
|
+
self.class.new( *stripped.collect { |elem| elem[ 2 ] } )
|
119
124
|
end
|
120
125
|
|
121
126
|
# Skip elements of an array
|
@@ -128,7 +133,8 @@ module Hornetseye
|
|
128
133
|
#
|
129
134
|
# @private
|
130
135
|
def skip( index, start )
|
131
|
-
self.class.new
|
136
|
+
self.class.new *( @sources.skip( index, start ) +
|
137
|
+
[ @table.skip( index, start ) ] )
|
132
138
|
end
|
133
139
|
|
134
140
|
# Get element of unary operation
|
@@ -139,12 +145,14 @@ module Hornetseye
|
|
139
145
|
#
|
140
146
|
# @private
|
141
147
|
def element( i )
|
142
|
-
|
143
|
-
if source.dimension >
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
+
sources, table = @sources, @table
|
149
|
+
if sources.any? { |source| source.dimension > 0 }
|
150
|
+
sources = sources.
|
151
|
+
collect { |source| source.dimension > 0 ? source.element( i ) : source }
|
152
|
+
self.class.new *( sources + [ table ] )
|
153
|
+
elsif table.dimension > sources.size
|
154
|
+
n = sources.size
|
155
|
+
self.class.new *( sources + [ table.unroll( n ).element( i ).roll( n ) ] )
|
148
156
|
else
|
149
157
|
super i
|
150
158
|
end
|
@@ -178,7 +186,7 @@ module Hornetseye
|
|
178
186
|
#
|
179
187
|
# @return [Node] Result of decomposition.
|
180
188
|
def decompose( i )
|
181
|
-
self.class.new @
|
189
|
+
self.class.new *( @sources + [ @table.decompose( i ) ] )
|
182
190
|
end
|
183
191
|
|
184
192
|
# Check whether this term is compilable
|
@@ -187,7 +195,7 @@ module Hornetseye
|
|
187
195
|
#
|
188
196
|
# @private
|
189
197
|
def compilable?
|
190
|
-
@source.compilable? and @table.compilable?
|
198
|
+
@sources.all? { |source| source.compilable? } and @table.compilable?
|
191
199
|
end
|
192
200
|
|
193
201
|
end
|
data/lib/multiarray/node.rb
CHANGED
@@ -308,6 +308,31 @@ module Hornetseye
|
|
308
308
|
hash[ self ] || self
|
309
309
|
end
|
310
310
|
|
311
|
+
# Check arguments for compatible shape
|
312
|
+
#
|
313
|
+
# The method will throw an exception if one of the arguments has an incompatible
|
314
|
+
# shape.
|
315
|
+
#
|
316
|
+
# @param [Array<Class>] args Arguments to check for compatibility.
|
317
|
+
#
|
318
|
+
# @return [Object] The return value should be ignored.
|
319
|
+
def check_shape( *args )
|
320
|
+
_shape = shape
|
321
|
+
args.each do |arg|
|
322
|
+
_arg_shape = arg.shape
|
323
|
+
if _shape.size < _arg_shape.size
|
324
|
+
raise "#{arg.inspect} has #{arg.dimension} dimension(s) " +
|
325
|
+
"but should not have more than #{dimension}"
|
326
|
+
end
|
327
|
+
if ( _shape + _arg_shape ).all? { |s| s.is_a? Integer }
|
328
|
+
if _shape.last( _arg_shape.size ) != _arg_shape
|
329
|
+
raise "#{arg.inspect} has shape #{arg.shape.inspect} " +
|
330
|
+
"(does not match last value(s) of #{shape.inspect})"
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
311
336
|
# Check whether this term is compilable
|
312
337
|
#
|
313
338
|
# @return [Boolean] Returns +true+.
|
@@ -595,22 +620,10 @@ module Hornetseye
|
|
595
620
|
#
|
596
621
|
# @return [Object] The return value should be ignored.
|
597
622
|
def check_shape( *args )
|
598
|
-
|
599
|
-
args.each do |arg|
|
600
|
-
_arg_shape = arg.shape
|
601
|
-
if _shape.size < _arg_shape.size
|
602
|
-
raise "#{arg.array_type.inspect} has #{arg.dimension} dimension(s) " +
|
603
|
-
"but should not have more than #{dimension}"
|
604
|
-
end
|
605
|
-
if ( _shape + _arg_shape ).all? { |s| s.is_a? Integer }
|
606
|
-
if _shape.last( _arg_shape.size ) != _arg_shape
|
607
|
-
raise "#{arg.array_type.inspect} has shape #{arg.shape.inspect} " +
|
608
|
-
"(does not match last value(s) of #{shape.inspect})"
|
609
|
-
end
|
610
|
-
end
|
611
|
-
end
|
623
|
+
array_type.check_shape *args.collect { |arg| arg.array_type }
|
612
624
|
end
|
613
625
|
|
626
|
+
|
614
627
|
# Assign value to array element(s)
|
615
628
|
#
|
616
629
|
# @overload []=( *indices, value )
|
@@ -121,7 +121,7 @@ module Hornetseye
|
|
121
121
|
def to_type( dest )
|
122
122
|
if dimension == 0 and variables.empty?
|
123
123
|
target = typecode.to_type dest
|
124
|
-
target.new simplify.get
|
124
|
+
target.new( simplify.get ).simplify
|
125
125
|
else
|
126
126
|
key = "to_#{dest.to_s.downcase}"
|
127
127
|
Hornetseye::ElementWise( lambda { |x| x.to_type dest }, key,
|
@@ -456,6 +456,7 @@ module Hornetseye
|
|
456
456
|
#
|
457
457
|
# @overload histogram( *ret_shape, options = {} )
|
458
458
|
# @param [Array<Integer>] ret_shape Dimensions of resulting histogram.
|
459
|
+
# @option options [Class] :target (UINT) Element-type of resulting histogram.
|
459
460
|
# @option options [Boolean] :safe (true) Do a boundary check before creating the
|
460
461
|
# histogram.
|
461
462
|
#
|
@@ -463,41 +464,12 @@ module Hornetseye
|
|
463
464
|
def histogram( *ret_shape )
|
464
465
|
options = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {}
|
465
466
|
options = { :target => UINT, :safe => true }.merge options
|
466
|
-
if
|
467
|
-
|
468
|
-
right = Hornetseye::lazy( 1 ) { self }.unroll
|
469
|
-
else
|
470
|
-
if shape.first != ret_shape.size
|
471
|
-
raise "First dimension of array (#{shape.first}) differs from number of " +
|
472
|
-
"dimensions of histogram (#{ret_shape.size})"
|
473
|
-
end
|
474
|
-
right = self
|
475
|
-
end
|
476
|
-
else
|
477
|
-
right = self
|
478
|
-
end
|
479
|
-
if options[ :safe ]
|
480
|
-
for i in 0 ... right.shape.first
|
481
|
-
range = right.roll[ i ].range
|
482
|
-
if range.begin < 0
|
483
|
-
raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " +
|
484
|
-
"(but was #{range.begin})"
|
485
|
-
end
|
486
|
-
if range.end >= ret_shape[ i ]
|
487
|
-
raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " +
|
488
|
-
"(but was #{range.end})"
|
489
|
-
end
|
490
|
-
end
|
491
|
-
end
|
492
|
-
left = MultiArray.new options[ :target ], *ret_shape
|
493
|
-
left[] = 0
|
494
|
-
block = Histogram.new left, right
|
495
|
-
if block.compilable?
|
496
|
-
GCCFunction.run block
|
467
|
+
if shape.first != 1 and ret_shape.size == 1
|
468
|
+
[ self ].histogram *( ret_shape + [ options ] )
|
497
469
|
else
|
498
|
-
|
470
|
+
( 0 ... shape.first ).collect { |i| unroll[i] }.
|
471
|
+
histogram *( ret_shape + [ options ] )
|
499
472
|
end
|
500
|
-
left
|
501
473
|
end
|
502
474
|
|
503
475
|
# Perform element-wise lookup
|
@@ -508,42 +480,10 @@ module Hornetseye
|
|
508
480
|
#
|
509
481
|
# @return [Node] The result of the lookup operation.
|
510
482
|
def lut( table, options = {} )
|
511
|
-
|
512
|
-
|
513
|
-
if shape.first != 1 and table.dimension == 1
|
514
|
-
source = Hornetseye::lazy( 1 ) { |i| self }.unroll
|
515
|
-
else
|
516
|
-
if shape.first > table.dimension
|
517
|
-
raise "First dimension of array (#{shape.first}) is greater than the " +
|
518
|
-
" number of dimensions of LUT (#{table.dimension})"
|
519
|
-
end
|
520
|
-
source = self
|
521
|
-
end
|
483
|
+
if shape.first != 1 and table.dimension == 1
|
484
|
+
[ self ].lut table, options
|
522
485
|
else
|
523
|
-
|
524
|
-
end
|
525
|
-
if options[ :safe ]
|
526
|
-
for i in 0 ... source.shape.first
|
527
|
-
range = source.roll[ i ].range
|
528
|
-
if range.begin < 0
|
529
|
-
raise "#{i+1}th dimension of index must be in 0 ... #{table.shape[i]} " +
|
530
|
-
"(but was #{range.begin})"
|
531
|
-
end
|
532
|
-
offset = table.dimension - source.shape.first
|
533
|
-
if range.end >= table.shape[ i + offset ]
|
534
|
-
raise "#{i+1}th dimension of index must be in 0 ... " +
|
535
|
-
"#{table.shape[ i + offset ]} (but was #{range.end})"
|
536
|
-
end
|
537
|
-
end
|
538
|
-
end
|
539
|
-
if source.dimension <= 1 and variables.empty?
|
540
|
-
result = table
|
541
|
-
( table.dimension - 1 ).downto( 0 ) do |i|
|
542
|
-
result = result.element source.element( INT.new( i ) ).demand
|
543
|
-
end
|
544
|
-
result
|
545
|
-
else
|
546
|
-
Lut.new( source, table, options[ :n ] ).force
|
486
|
+
( 0 ... shape.first ).collect { |i| unroll[i] }.lut table, options
|
547
487
|
end
|
548
488
|
end
|
549
489
|
|
@@ -570,3 +510,94 @@ module Hornetseye
|
|
570
510
|
end
|
571
511
|
|
572
512
|
end
|
513
|
+
|
514
|
+
# The +Array+ class is extended with a few methods
|
515
|
+
class Array
|
516
|
+
|
517
|
+
# Compute histogram of this array
|
518
|
+
#
|
519
|
+
# @overload histogram( *ret_shape, options = {} )
|
520
|
+
# @param [Array<Integer>] ret_shape Dimensions of resulting histogram.
|
521
|
+
# @option options [Class] :target (Hornetseye::UINT) Element-type of resulting
|
522
|
+
# histogram.
|
523
|
+
# @option options [Boolean] :safe (true) Do a boundary check before creating the
|
524
|
+
# histogram.
|
525
|
+
#
|
526
|
+
# @return [Node] The histogram.
|
527
|
+
def histogram( *ret_shape )
|
528
|
+
options = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {}
|
529
|
+
options = { :target => Hornetseye::UINT, :safe => true }.merge options
|
530
|
+
if options[ :safe ]
|
531
|
+
if size != ret_shape.size
|
532
|
+
raise "Number of arrays for histogram (#{size}) differs from number of " +
|
533
|
+
"dimensions of histogram (#{ret_shape.size})"
|
534
|
+
end
|
535
|
+
array_types = collect { |source| source.array_type }
|
536
|
+
source_type = array_types.inject { |a,b| a.coercion b }
|
537
|
+
source_type.check_shape *array_types
|
538
|
+
for i in 0 ... size
|
539
|
+
range = self[ i ].range
|
540
|
+
if range.begin < 0
|
541
|
+
raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " +
|
542
|
+
"(but was #{range.begin})"
|
543
|
+
end
|
544
|
+
if range.end >= ret_shape[ i ]
|
545
|
+
raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " +
|
546
|
+
"(but was #{range.end})"
|
547
|
+
end
|
548
|
+
end
|
549
|
+
end
|
550
|
+
left = Hornetseye::MultiArray.new options[ :target ], *ret_shape
|
551
|
+
left[] = 0
|
552
|
+
block = Hornetseye::Histogram.new left, *self
|
553
|
+
if block.compilable?
|
554
|
+
Hornetseye::GCCFunction.run block
|
555
|
+
else
|
556
|
+
block.demand
|
557
|
+
end
|
558
|
+
left
|
559
|
+
end
|
560
|
+
|
561
|
+
# Perform element-wise lookup
|
562
|
+
#
|
563
|
+
# @param [Node] table The lookup table (LUT).
|
564
|
+
# @option options [Boolean] :safe (true) Do a boundary check before creating the
|
565
|
+
# element-wise lookup.
|
566
|
+
#
|
567
|
+
# @return [Node] The result of the lookup operation.
|
568
|
+
def lut( table, options = {} )
|
569
|
+
options = { :safe => true }.merge options
|
570
|
+
if options[ :safe ]
|
571
|
+
if size > table.dimension
|
572
|
+
raise "Number of arrays for lookup (#{size}) is greater than the " +
|
573
|
+
" number of dimensions of LUT (#{table.dimension})"
|
574
|
+
end
|
575
|
+
array_types = collect { |source| source.array_type }
|
576
|
+
source_type = array_types.inject { |a,b| a.coercion b }
|
577
|
+
source_type.check_shape *array_types
|
578
|
+
for i in 0 ... size
|
579
|
+
range = self[ i ].range
|
580
|
+
if range.begin < 0
|
581
|
+
raise "#{i+1}th index must be in 0 ... #{table.shape[i]} " +
|
582
|
+
"(but was #{range.begin})"
|
583
|
+
end
|
584
|
+
offset = table.dimension - size
|
585
|
+
if range.end >= table.shape[ i + offset ]
|
586
|
+
raise "#{i+1}th index must be in 0 ... " +
|
587
|
+
"#{table.shape[ i + offset ]} (but was #{range.end})"
|
588
|
+
end
|
589
|
+
end
|
590
|
+
end
|
591
|
+
if all? { |source| source.dimension == 0 and source.variables.empty? }
|
592
|
+
result = table
|
593
|
+
( table.dimension - 1 ).downto( 0 ) do |i|
|
594
|
+
result = result.element self[ i ].demand
|
595
|
+
end
|
596
|
+
result
|
597
|
+
else
|
598
|
+
Hornetseye::Lut.new( *( self + [ table ] ) ).force
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
end
|
603
|
+
|
data/lib/multiarray/rgb.rb
CHANGED
@@ -617,6 +617,27 @@ module Hornetseye
|
|
617
617
|
end
|
618
618
|
end
|
619
619
|
|
620
|
+
# Histograms
|
621
|
+
def histogram_with_rgb( *ret_shape )
|
622
|
+
if typecode < RGB_
|
623
|
+
[ r, g, b ].histogram *ret_shape
|
624
|
+
else
|
625
|
+
histogram_without_rgb *ret_shape
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
alias_method_chain :histogram, :rgb
|
630
|
+
|
631
|
+
def lut_with_rgb( table, options = {} )
|
632
|
+
if typecode < RGB_
|
633
|
+
[ r, g, b ].lut table, options
|
634
|
+
else
|
635
|
+
lut_without_rgb table, options
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
alias_method_chain :lut, :rgb
|
640
|
+
|
620
641
|
end
|
621
642
|
|
622
643
|
# Create a class deriving from +RGB_+ or instantiate an +RGB+ object
|
data/lib/multiarray/sequence.rb
CHANGED
@@ -220,6 +220,31 @@ module Hornetseye
|
|
220
220
|
element_type.dimension + 1
|
221
221
|
end
|
222
222
|
|
223
|
+
# Check arguments for compatible shape
|
224
|
+
#
|
225
|
+
# The method will throw an exception if one of the arguments has an incompatible
|
226
|
+
# shape.
|
227
|
+
#
|
228
|
+
# @param [Array<Class>] args Arguments to check for compatibility.
|
229
|
+
#
|
230
|
+
# @return [Object] The return value should be ignored.
|
231
|
+
def check_shape( *args )
|
232
|
+
_shape = shape
|
233
|
+
args.each do |arg|
|
234
|
+
_arg_shape = arg.shape
|
235
|
+
if _shape.size < _arg_shape.size
|
236
|
+
raise "#{arg.inspect} has #{arg.dimension} dimension(s) " +
|
237
|
+
"but should not have more than #{dimension}"
|
238
|
+
end
|
239
|
+
if ( _shape + _arg_shape ).all? { |s| s.is_a? Integer }
|
240
|
+
if _shape.last( _arg_shape.size ) != _arg_shape
|
241
|
+
raise "#{arg.inspect} has shape #{arg.shape.inspect} " +
|
242
|
+
"(does not match last value(s) of #{shape.inspect})"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
223
248
|
# Check whether delayed operation will have colour
|
224
249
|
#
|
225
250
|
# @return [Boolean] Boolean indicating whether the array has elements of type
|
data/test/tc_multiarray.rb
CHANGED
@@ -432,13 +432,19 @@ class TC_MultiArray < Test::Unit::TestCase
|
|
432
432
|
M[ [ 1, 2 ], [ 3, 3 ] ].histogram( 5, :target => I )
|
433
433
|
assert_equal M( I, 2, 2 )[ [ 1, 0 ], [ 1, 1 ] ],
|
434
434
|
M[ [ 0, 0 ], [ 0, 1 ], [ 1, 1 ] ].histogram( 2, 2, :target => I )
|
435
|
-
|
436
|
-
|
435
|
+
assert_equal M( I, 2, 2 )[ [ 1, 0 ], [ 1, 1 ] ],
|
436
|
+
[ S[ 0, 0, 1 ], S[ 0, 1, 1 ] ].histogram( 2, 2, :target => I )
|
437
|
+
assert_equal M( I, 2, 2, 1 )[ [ [ 0, 1 ], [ 1, 0 ] ] ],
|
438
|
+
S[ C( 1, 0, 0 ), C( 0, 1, 0 ) ].histogram( 2, 2, 1, :target => I )
|
437
439
|
assert_raise( RuntimeError ) { S[ 1, 2, 3 ].histogram 4, 4 }
|
438
440
|
assert_raise( RuntimeError ) { M[ [ -1, 0 ] ].histogram 3, 2 }
|
439
441
|
assert_raise( RuntimeError ) { M[ [ 0, -1 ] ].histogram 3, 2 }
|
440
442
|
assert_raise( RuntimeError ) { M[ [ 3, 0 ] ].histogram 3, 2 }
|
441
443
|
assert_raise( RuntimeError ) { M[ [ 0, 2 ] ].histogram 3, 2 }
|
444
|
+
assert_raise( RuntimeError ) { [ S[ -1, 0 ], S[ 0, 1 ] ].histogram 3, 2 }
|
445
|
+
assert_raise( RuntimeError ) { [ S[ 0, 3 ], S[ 0, 1 ] ].histogram 3, 2 }
|
446
|
+
assert_raise( RuntimeError ) { [ S[ 0, 0, 1 ], S[ 0, 1 ] ].histogram 3, 2 }
|
447
|
+
assert_raise( RuntimeError ) { [ S[ 0, 1 ], S[ 0, 1 ] ].histogram 3 }
|
442
448
|
end
|
443
449
|
|
444
450
|
def test_lut
|
@@ -446,14 +452,25 @@ class TC_MultiArray < Test::Unit::TestCase
|
|
446
452
|
M[ [ 0, 1 ], [ 2, 0 ] ].lut( S[ 1, 2, 3, 4 ] )
|
447
453
|
assert_equal M[ 1, 3, 4 ],
|
448
454
|
M[ [ 0, 0 ], [ 0, 1 ], [ 1, 1 ] ].lut( M[ [ 1, 2 ], [ 3, 4 ] ] )
|
455
|
+
assert_equal M[ 1, 3, 4 ],
|
456
|
+
[ S[ 0, 0, 1 ], S[ 0, 1, 1 ] ].lut( M[ [ 1, 2 ], [ 3, 4 ] ] )
|
449
457
|
assert_equal M[ [ 3, 4 ], [ 1, 2 ] ],
|
450
458
|
M[ [ 1 ], [ 0 ] ].lut( M[ [ 1, 2 ], [ 3, 4 ] ] )
|
459
|
+
assert_equal S[ 2, 3 ], S[ C( 1, 0, 0 ), C( 0, 1, 0 ) ].
|
460
|
+
lut( M[ [ [ 1, 2 ], [ 3, 4 ] ] ] )
|
451
461
|
assert_raise( RuntimeError ) { S[ 0, 1, 2 ].lut M[ [ 1, 2 ], [ 3, 4 ] ] }
|
452
462
|
assert_raise( RuntimeError ) { M[ [ -1, 0 ] ].lut M[ [ 1, 2 ] ] }
|
453
463
|
assert_raise( RuntimeError ) { M[ [ 0, -1 ] ].lut M[ [ 1, 2 ] ] }
|
454
464
|
assert_raise( RuntimeError ) { M[ [ 2, 0 ] ].lut M[ [ 1, 2 ] ] }
|
455
465
|
assert_raise( RuntimeError ) { M[ [ 0, 1 ] ].lut M[ [ 1, 2 ] ] }
|
456
466
|
assert_raise( RuntimeError ) { M[ [ 1 ], [ 2 ] ].lut M[ [ 1, 2 ], [ 3, 4 ] ] }
|
467
|
+
assert_raise( RuntimeError ) { [ S[ -1, 0 ], S[ 0, 1 ] ].
|
468
|
+
lut M[ [ 1, 2 ], [ 3, 4 ] ] }
|
469
|
+
assert_raise( RuntimeError ) { [ S[ 0, 0 ], S[ 0, 2 ] ].
|
470
|
+
lut M[ [ 1, 2 ], [ 3, 4 ] ] }
|
471
|
+
assert_raise( RuntimeError ) { [ S[ 0, 0, 1 ], S[ 0, 1 ] ].
|
472
|
+
lut M[ [ 1, 2 ], [ 3, 4 ] ] }
|
473
|
+
assert_raise( RuntimeError ) { [ S[ 0, 1 ], S[ 0, 1 ] ].lut S[ 1, 2 ] }
|
457
474
|
end
|
458
475
|
|
459
476
|
def test_zero
|
data/test/tc_sequence.rb
CHANGED
@@ -345,6 +345,8 @@ class TC_Sequence < Test::Unit::TestCase
|
|
345
345
|
[ O, I ].each do |t|
|
346
346
|
assert_equal S( t, 5 )[ 0, 1, 2, 1, 1 ],
|
347
347
|
S( t, 5 )[ 1, 2, 2, 3, 4 ].histogram( 5, :target => t )
|
348
|
+
assert_equal S( t, 4 )[ 0, 1, 1, 0 ],
|
349
|
+
S( t, 2 )[ 1.0, 2.0 ].histogram( 4, :target => t )
|
348
350
|
end
|
349
351
|
assert_raise( RuntimeError ) { S[ -1, 0, 1 ].histogram 3 }
|
350
352
|
assert_raise( RuntimeError ) { S[ 1, 2, 3 ].histogram 3 }
|
@@ -355,6 +357,8 @@ class TC_Sequence < Test::Unit::TestCase
|
|
355
357
|
[ O, I ].each do |t|
|
356
358
|
assert_equal S( t, 4 )[ 3, 1, 2, 1 ],
|
357
359
|
S( t, 4 )[ 0, 2, 1, 2 ].lut( S( t, 3 )[ 3, 2, 1 ] )
|
360
|
+
assert_equal S( t, 2 )[ 2, 1 ],
|
361
|
+
S( t, 2 )[ 1.0, 2.0 ].lut( S( t, 3 )[ 3, 2, 1 ] )
|
358
362
|
end
|
359
363
|
assert_raise( RuntimeError ) { S[ -1, 0 ].lut S[ 0, 1 ] }
|
360
364
|
assert_raise( RuntimeError ) { S[ 1, 2 ].lut S[ 0, 1 ] }
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 12
|
8
|
+
- 0
|
9
|
+
version: 0.12.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jan Wedekind
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-12-05 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|