multiarray 0.20.0 → 0.21.0
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 +1 -1
- data/lib/multiarray.rb +14 -0
- data/lib/multiarray/complex.rb +8 -8
- data/lib/multiarray/components.rb +236 -0
- data/lib/multiarray/diagonal.rb +1 -1
- data/lib/multiarray/element.rb +4 -4
- data/lib/multiarray/gccfunction.rb +29 -0
- data/lib/multiarray/gccvalue.rb +1 -2
- data/lib/multiarray/inject.rb +4 -4
- data/lib/multiarray/mask.rb +7 -3
- data/lib/multiarray/operations.rb +67 -3
- data/lib/multiarray/pointer.rb +16 -0
- data/lib/multiarray/rgb.rb +27 -11
- data/lib/multiarray/store.rb +3 -1
- data/lib/multiarray/unmask.rb +7 -3
- data/test/tc_multiarray.rb +5 -0
- data/test/tc_sequence.rb +15 -0
- metadata +4 -3
data/Rakefile
CHANGED
data/lib/multiarray.rb
CHANGED
@@ -66,6 +66,18 @@ class Proc
|
|
66
66
|
|
67
67
|
end
|
68
68
|
|
69
|
+
# An overloadable while loop
|
70
|
+
#
|
71
|
+
# @param [Proc] action The loop body
|
72
|
+
#
|
73
|
+
# @return [NilClass] Returns +nil+.
|
74
|
+
#
|
75
|
+
# @private
|
76
|
+
def while( &action )
|
77
|
+
action.call while call.get
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
69
81
|
end
|
70
82
|
|
71
83
|
# +Object+ is extended with a few methods
|
@@ -698,6 +710,7 @@ require 'multiarray/lut'
|
|
698
710
|
require 'multiarray/integral'
|
699
711
|
require 'multiarray/mask'
|
700
712
|
require 'multiarray/unmask'
|
713
|
+
require 'multiarray/components'
|
701
714
|
require 'multiarray/operations'
|
702
715
|
require 'multiarray/methods'
|
703
716
|
require 'multiarray/rgb'
|
@@ -793,3 +806,4 @@ module Hornetseye
|
|
793
806
|
module_function :sum
|
794
807
|
|
795
808
|
end
|
809
|
+
|
data/lib/multiarray/complex.rb
CHANGED
@@ -98,7 +98,7 @@ module Hornetseye
|
|
98
98
|
# @return [Object] Returns +value+.
|
99
99
|
#
|
100
100
|
# @private
|
101
|
-
def
|
101
|
+
def assign( value )
|
102
102
|
@real, @imag = value.real, value.imag
|
103
103
|
end
|
104
104
|
|
@@ -862,8 +862,8 @@ module Hornetseye
|
|
862
862
|
if Thread.current[ :function ]
|
863
863
|
real = Thread.current[ :function ].variable self.class.element_type, 'v'
|
864
864
|
imag = Thread.current[ :function ].variable self.class.element_type, 'v'
|
865
|
-
real.
|
866
|
-
imag.
|
865
|
+
real.assign @value.real
|
866
|
+
imag.assign @value.imag
|
867
867
|
self.class.new InternalComplex.new( real, imag )
|
868
868
|
else
|
869
869
|
self.class.new get
|
@@ -877,15 +877,15 @@ module Hornetseye
|
|
877
877
|
# @return [Object] Returns +value+.
|
878
878
|
#
|
879
879
|
# @private
|
880
|
-
def
|
880
|
+
def assign( value )
|
881
881
|
value = value.simplify
|
882
|
-
if @value.real.respond_to? :
|
883
|
-
@value.real.
|
882
|
+
if @value.real.respond_to? :assign
|
883
|
+
@value.real.assign value.get.real
|
884
884
|
else
|
885
885
|
@value.real = value.get.real
|
886
886
|
end
|
887
|
-
if @value.imag.respond_to? :
|
888
|
-
@value.imag.
|
887
|
+
if @value.imag.respond_to? :assign
|
888
|
+
@value.imag.assign value.get.imag
|
889
889
|
else
|
890
890
|
@value.imag = value.get.imag
|
891
891
|
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# multiarray - Lazy multi-dimensional arrays for Ruby
|
2
|
+
# Copyright (C) 2010, 2011 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 for representing connected component analysis
|
21
|
+
class Components < Node
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Check whether objects of this class are finalised computations
|
26
|
+
#
|
27
|
+
# @return [Boolean] Returns +false+.
|
28
|
+
#
|
29
|
+
# @private
|
30
|
+
def finalised?
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# Constructor
|
37
|
+
#
|
38
|
+
# @param [Node] dest Target array to write component labels to.
|
39
|
+
# @param [Node] source Array to extract components from.
|
40
|
+
# @param [Node] default Value of background pixel.
|
41
|
+
# @param [Node] zero Zero is used to aid compilation.
|
42
|
+
# @param [Node] labels Array to store label correspondences.
|
43
|
+
# @param [Node] rank Array to store number of indirections for each label.
|
44
|
+
# @param [Node] n Pointer to return number of components.
|
45
|
+
def initialize( dest, source, default, zero, labels, rank, n )
|
46
|
+
@dest, @source, @default, @zero, @labels, @rank, @n =
|
47
|
+
dest, source, default, zero, labels, rank, n
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get unique descriptor of this object
|
51
|
+
#
|
52
|
+
# @param [Hash] hash Labels for any variables.
|
53
|
+
#
|
54
|
+
# @return [String] Descriptor of this object,
|
55
|
+
#
|
56
|
+
# @private
|
57
|
+
def descriptor( hash )
|
58
|
+
"Components(#{@dest.descriptor( hash )},#{@source.descriptor( hash )}," +
|
59
|
+
"#{@default.descriptor( hash )},#{@zero.descriptor( hash )}," +
|
60
|
+
"#{@labels.descriptor( hash )},#{@rank.descriptor( hash )}," +
|
61
|
+
"#{@n.descriptor( hash )})"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get type of result of delayed operation
|
65
|
+
#
|
66
|
+
# @return [Class] Type of result.
|
67
|
+
def array_type
|
68
|
+
retval = @dest.array_type
|
69
|
+
( class << self; self; end ).instance_eval do
|
70
|
+
define_method( :array_type ) { retval }
|
71
|
+
end
|
72
|
+
retval
|
73
|
+
end
|
74
|
+
|
75
|
+
# Reevaluate computation
|
76
|
+
#
|
77
|
+
# @return [Node,Object] Result of computation
|
78
|
+
#
|
79
|
+
# @see #force
|
80
|
+
#
|
81
|
+
# @private
|
82
|
+
def demand
|
83
|
+
knot [], []
|
84
|
+
@dest
|
85
|
+
end
|
86
|
+
|
87
|
+
# Recursive function to perform connected component labelling
|
88
|
+
#
|
89
|
+
# @param [Array<Proc>] args Array with functions for locating neighbouring elements.
|
90
|
+
# @param [Array<Proc>] comp Array with functions for locating neighbouring labels.
|
91
|
+
#
|
92
|
+
# @private
|
93
|
+
def knot( args, comp )
|
94
|
+
n = @n.simplify
|
95
|
+
if dimension > 0
|
96
|
+
subargs1, subargs2, subargs3 = [], [], []
|
97
|
+
subcomp1, subcomp2, subcomp3 = [], [], []
|
98
|
+
args.each do |arg|
|
99
|
+
subargs1.push proc { |i| arg.element( i - 1 ).demand }
|
100
|
+
subargs2.push proc { |i| arg.element( i ).demand }
|
101
|
+
subargs3.push proc { |i| arg.element( i + 1 ).demand }
|
102
|
+
end
|
103
|
+
comp.each do |c|
|
104
|
+
subcomp1.push proc { |i| c.element( i - 1 ) }
|
105
|
+
subcomp2.push proc { |i| c.element( i ) }
|
106
|
+
subcomp3.push proc { |i| c.element( i + 1 ) }
|
107
|
+
end
|
108
|
+
self.class.new( @dest.element( INT.new( 0 ) ),
|
109
|
+
@source.element( INT.new( 0 ) ).demand, @default, @zero,
|
110
|
+
@labels, @rank, n ).
|
111
|
+
knot( ( subargs2 + subargs3 ).collect { |p| p.call INT.new( 0 ) },
|
112
|
+
( subcomp2 + subcomp3 ).collect { |p| p.call INT.new( 0 ) } )
|
113
|
+
INT.new( 1 ).upto INT.new( @source.shape.last ) - 2 do |i|
|
114
|
+
self.class.new( @dest.element( INT.new( i ) ),
|
115
|
+
@source.element( INT.new( i ) ).demand, @default, @zero,
|
116
|
+
@labels, @rank, n ).
|
117
|
+
knot( ( subargs1 + subargs2 + subargs3 ).collect { |p| p.call INT.new( i ) } +
|
118
|
+
[ @source.element( INT.new( i ) - 1 ) ],
|
119
|
+
( subcomp1 + subcomp2 + subcomp3 ).collect { |p| p.call INT.new( i ) } +
|
120
|
+
[ @dest.element( INT.new( i ) - 1 ) ] )
|
121
|
+
end
|
122
|
+
i = @source.shape.last - 1
|
123
|
+
self.class.new( @dest.element( INT.new( i ) ),
|
124
|
+
@source.element( INT.new( i ) ).demand, @default, @zero,
|
125
|
+
@labels, @rank, n ).
|
126
|
+
knot( ( subargs1 + subargs2 ).collect { |p| p.call INT.new( i ) } +
|
127
|
+
[ @source.element( INT.new( i ) - 1 ) ],
|
128
|
+
( subcomp1 + subcomp2 ).collect { |p| p.call INT.new( i ) } +
|
129
|
+
[ @dest.element( INT.new( i ) - 1 ) ] )
|
130
|
+
else
|
131
|
+
@source.ne( @default ).if_else( proc do
|
132
|
+
label = @zero.simplify
|
133
|
+
args.zip( comp ).each do |arg,other|
|
134
|
+
@source.eq( arg ).if do
|
135
|
+
other = other.simplify
|
136
|
+
proc { other.ne( @labels.element( other ).demand ) }.while do
|
137
|
+
other.assign @labels.element( other ).demand
|
138
|
+
end
|
139
|
+
label.eq( @zero ).if_else( proc do
|
140
|
+
label.assign other
|
141
|
+
end, proc do
|
142
|
+
label.ne( other ).if do
|
143
|
+
( @rank.element( label ).demand <= @rank.element( other ).demand ).if_else( proc do
|
144
|
+
@labels[ other ] = label
|
145
|
+
@rank.element( label ).demand.eq( @rank.element( other ).demand ).if do
|
146
|
+
@rank[ label ] = @rank.element( other ).demand + 1
|
147
|
+
end
|
148
|
+
end, proc do
|
149
|
+
@labels[ label ] = other
|
150
|
+
label.assign other
|
151
|
+
end )
|
152
|
+
end
|
153
|
+
end )
|
154
|
+
end
|
155
|
+
end
|
156
|
+
label.eq( @zero ).if do
|
157
|
+
n.assign n + 1
|
158
|
+
@labels[ n ] = n
|
159
|
+
@rank[ n ] = 0
|
160
|
+
label.assign n
|
161
|
+
end
|
162
|
+
@dest.store label
|
163
|
+
end, proc do
|
164
|
+
@dest.store INT.new( 0 )
|
165
|
+
end )
|
166
|
+
end
|
167
|
+
if @n.is_a? Pointer_
|
168
|
+
INT.new( 0 ).upto n do |i|
|
169
|
+
l = UINT.new( i ).simplify
|
170
|
+
proc { l.ne( @labels.element( l ).demand ) }.while do
|
171
|
+
l.assign @labels.element( l ).demand
|
172
|
+
end
|
173
|
+
@labels[ INT.new( i ) ] = l
|
174
|
+
end
|
175
|
+
@n.store n
|
176
|
+
else
|
177
|
+
@n.assign n
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Substitute variables
|
182
|
+
#
|
183
|
+
# Substitute the variables with the values given in the hash.
|
184
|
+
#
|
185
|
+
# @param [Hash] hash Substitutions to apply.
|
186
|
+
#
|
187
|
+
# @return [Node] Term with substitutions applied.
|
188
|
+
#
|
189
|
+
# @private
|
190
|
+
def subst( hash )
|
191
|
+
self.class.new @dest.subst( hash ), @source.subst( hash ), @default.subst( hash ),
|
192
|
+
@zero.subst( hash ), @labels.subst( hash ), @rank.subst( hash ), @n.subst( hash )
|
193
|
+
end
|
194
|
+
|
195
|
+
# Get variables contained in this term
|
196
|
+
#
|
197
|
+
# @return [Set] Returns list of variables.
|
198
|
+
#
|
199
|
+
# @private
|
200
|
+
def variables
|
201
|
+
@dest.variables + @source.variables + @default.variables + @zero.variables +
|
202
|
+
@labels.variables + @rank.variables + @n.variables
|
203
|
+
end
|
204
|
+
|
205
|
+
# Strip of all values
|
206
|
+
#
|
207
|
+
# Split up into variables, values, and a term where all values have been
|
208
|
+
# replaced with variables.
|
209
|
+
#
|
210
|
+
# @return [Array<Array,Node>] Returns an array of variables, an array of
|
211
|
+
# values, and the term based on variables.
|
212
|
+
#
|
213
|
+
# @private
|
214
|
+
def strip
|
215
|
+
stripped = [ @dest, @source, @default, @zero, @labels, @rank, @n ].
|
216
|
+
collect { |value| value.strip }
|
217
|
+
return stripped.inject( [] ) { |vars,elem| vars + elem[ 0 ] },
|
218
|
+
stripped.inject( [] ) { |values,elem| values + elem[ 1 ] },
|
219
|
+
self.class.new( *stripped.collect { |elem| elem[ 2 ] } )
|
220
|
+
end
|
221
|
+
|
222
|
+
# Get variables contained in this term
|
223
|
+
#
|
224
|
+
# @return [Set] Returns list of variables.
|
225
|
+
#
|
226
|
+
# @private
|
227
|
+
def compilable?
|
228
|
+
[ @dest, @source, @default, @zero, @labels, @rank, @n ].all? do |value|
|
229
|
+
value.compilable?
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
data/lib/multiarray/diagonal.rb
CHANGED
@@ -106,7 +106,7 @@ module Hornetseye
|
|
106
106
|
j0.upto( ( @index2.size - 1 ).minor( @index0 + s1 ) ) do |j|
|
107
107
|
i = @index0.get + s1.get - j
|
108
108
|
sub = @value.subst @index1 => INT.new( i ), @index2 => INT.new( j )
|
109
|
-
retval.
|
109
|
+
retval.assign @block.subst( @var1 => retval, @var2 => sub )
|
110
110
|
end
|
111
111
|
retval
|
112
112
|
end
|
data/lib/multiarray/element.rb
CHANGED
@@ -93,7 +93,7 @@ module Hornetseye
|
|
93
93
|
def dup
|
94
94
|
if Thread.current[ :function ]
|
95
95
|
value = Thread.current[ :function ].variable self.class, 'v'
|
96
|
-
value.
|
96
|
+
value.assign get
|
97
97
|
self.class.new value
|
98
98
|
else
|
99
99
|
self.class.new get
|
@@ -155,9 +155,9 @@ module Hornetseye
|
|
155
155
|
# @return [Object] Returns +value+.
|
156
156
|
#
|
157
157
|
# @private
|
158
|
-
def
|
159
|
-
if @value.respond_to? :
|
160
|
-
@value.
|
158
|
+
def assign( value )
|
159
|
+
if @value.respond_to? :assign
|
160
|
+
@value.assign value.simplify.get
|
161
161
|
else
|
162
162
|
@value = value.simplify.get
|
163
163
|
end
|
@@ -196,3 +196,32 @@ module Hornetseye
|
|
196
196
|
end
|
197
197
|
|
198
198
|
end
|
199
|
+
|
200
|
+
class Proc
|
201
|
+
|
202
|
+
# Overloaded while loop for handling compilation
|
203
|
+
#
|
204
|
+
# @param [Proc] action The loop body
|
205
|
+
#
|
206
|
+
# @return [NilClass] Returns +nil+.
|
207
|
+
#
|
208
|
+
# @private
|
209
|
+
def while_with_gcc( &action )
|
210
|
+
function = Thread.current[ :function ]
|
211
|
+
if function
|
212
|
+
function << "#{function.indent}while ( 1 ) {\n"
|
213
|
+
function.indent_offset +1
|
214
|
+
function << "#{function.indent}if ( !( #{call.get}) ) break;\n"
|
215
|
+
action.call
|
216
|
+
function.indent_offset -1
|
217
|
+
function << "#{function.indent}}\n"
|
218
|
+
nil
|
219
|
+
else
|
220
|
+
while_without_gcc &action
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
alias_method_chain :while, :gcc
|
225
|
+
|
226
|
+
end
|
227
|
+
|
data/lib/multiarray/gccvalue.rb
CHANGED
@@ -163,7 +163,7 @@ module Hornetseye
|
|
163
163
|
# @return [Object] Returns +value+.
|
164
164
|
#
|
165
165
|
# @private
|
166
|
-
def
|
166
|
+
def assign( value )
|
167
167
|
@function << "#{@function.indent}#{self} = #{value};\n"
|
168
168
|
value
|
169
169
|
end
|
@@ -370,7 +370,6 @@ module Hornetseye
|
|
370
370
|
self
|
371
371
|
end
|
372
372
|
|
373
|
-
|
374
373
|
define_unary_op :not, '!'
|
375
374
|
define_unary_op :~
|
376
375
|
define_unary_op :-@, :-
|
data/lib/multiarray/inject.rb
CHANGED
@@ -96,7 +96,7 @@ module Hornetseye
|
|
96
96
|
end
|
97
97
|
offset.upto @index.size - 1 do |i|
|
98
98
|
sub = @value.subst @index => INT.new( i )
|
99
|
-
retval.
|
99
|
+
retval.assign @block.subst( @var1 => retval, @var2 => sub )
|
100
100
|
end
|
101
101
|
retval
|
102
102
|
end
|
@@ -109,7 +109,7 @@ module Hornetseye
|
|
109
109
|
#
|
110
110
|
# @private
|
111
111
|
def element( i )
|
112
|
-
|
112
|
+
self.class.new @value.element( i ), @index, @initial, @block, @var1, @var2
|
113
113
|
end
|
114
114
|
|
115
115
|
# Get variables contained in this term
|
@@ -142,7 +142,7 @@ module Hornetseye
|
|
142
142
|
vars3, values3, term3 = @block.strip
|
143
143
|
return vars1 + vars2 + vars3 + meta_vars,
|
144
144
|
values1 + values2 + values3 + meta_values,
|
145
|
-
|
145
|
+
self.class.new( term1, var, term2, term3, @var1, @var2 )
|
146
146
|
end
|
147
147
|
|
148
148
|
# Substitute variables
|
@@ -159,7 +159,7 @@ module Hornetseye
|
|
159
159
|
value = @value.subst( @index => subst_var ).subst hash
|
160
160
|
initial = @initial ? @initial.subst( hash ) : nil
|
161
161
|
block = @block.subst hash
|
162
|
-
|
162
|
+
self.class.new value, subst_var, initial, block, @var1, @var2
|
163
163
|
end
|
164
164
|
|
165
165
|
# Check whether this term is compilable
|
data/lib/multiarray/mask.rb
CHANGED
@@ -81,12 +81,16 @@ module Hornetseye
|
|
81
81
|
Mask.new( @dest, source, m, index ).demand
|
82
82
|
end
|
83
83
|
else
|
84
|
-
@m.
|
84
|
+
@m.if do
|
85
85
|
Store.new( @dest.element( index ), @source ).demand
|
86
|
-
index.
|
86
|
+
index.assign index + 1
|
87
87
|
end
|
88
88
|
end
|
89
|
-
@index.
|
89
|
+
if @index.is_a? Pointer_
|
90
|
+
@index.store index
|
91
|
+
else
|
92
|
+
@index.assign index
|
93
|
+
end
|
90
94
|
@dest
|
91
95
|
else
|
92
96
|
super
|
@@ -213,6 +213,34 @@ module Hornetseye
|
|
213
213
|
end
|
214
214
|
end
|
215
215
|
|
216
|
+
# Generate code for memory allocation
|
217
|
+
#
|
218
|
+
# @return [GCCValue] C value referring to result.
|
219
|
+
#
|
220
|
+
# @private
|
221
|
+
def malloc
|
222
|
+
get.malloc
|
223
|
+
end
|
224
|
+
|
225
|
+
# Conditional operation
|
226
|
+
#
|
227
|
+
# @param [Proc] action Action to perform if condition is +true+.
|
228
|
+
#
|
229
|
+
# @return [Object] The return value should be ignored.
|
230
|
+
def if( &action )
|
231
|
+
simplify.get.if &action
|
232
|
+
end
|
233
|
+
|
234
|
+
# Conditional operation
|
235
|
+
#
|
236
|
+
# @param [Proc] action1 Action to perform if condition is +true+.
|
237
|
+
# @param [Proc] action2 Action to perform if condition is +false+.
|
238
|
+
#
|
239
|
+
# @return [Object] The return value should be ignored.
|
240
|
+
def if_else( action1, action2 )
|
241
|
+
simplify.get.if_else action1, action2
|
242
|
+
end
|
243
|
+
|
216
244
|
# Element-wise comparison of values
|
217
245
|
#
|
218
246
|
# @param [Node] other Array with values to compare with.
|
@@ -390,6 +418,13 @@ module Hornetseye
|
|
390
418
|
min( initial ? initial.min : nil ) .. max( initial ? initial.max : nil )
|
391
419
|
end
|
392
420
|
|
421
|
+
# Check values against boundaries
|
422
|
+
#
|
423
|
+
# @return [Node] Boolean array with result.
|
424
|
+
def between?( a, b )
|
425
|
+
Hornetseye::lazy { ( self >= a ).and self <= b }.force
|
426
|
+
end
|
427
|
+
|
393
428
|
# Normalise values of array
|
394
429
|
#
|
395
430
|
# @param [Range] range Target range of normalisation.
|
@@ -621,12 +656,12 @@ module Hornetseye
|
|
621
656
|
# @return [Node] The histogram.
|
622
657
|
def histogram( *ret_shape )
|
623
658
|
options = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {}
|
624
|
-
options = { :weight => UINT.
|
659
|
+
options = { :weight => UINT.new( 1 ), :safe => true }.merge options
|
625
660
|
unless options[ :weight ].is_a? Node
|
626
661
|
options[ :weight ] =
|
627
662
|
Node.match( options[ :weight ] ).maxint.new options[ :weight ]
|
628
663
|
end
|
629
|
-
if shape.first != 1 and ret_shape.size == 1
|
664
|
+
if ( shape.first != 1 or dimension == 1 ) and ret_shape.size == 1
|
630
665
|
[ self ].histogram *( ret_shape + [ options ] )
|
631
666
|
else
|
632
667
|
( 0 ... shape.first ).collect { |i| unroll[i] }.
|
@@ -642,7 +677,7 @@ module Hornetseye
|
|
642
677
|
#
|
643
678
|
# @return [Node] The result of the lookup operation.
|
644
679
|
def lut( table, options = {} )
|
645
|
-
if shape.first != 1 and table.dimension == 1
|
680
|
+
if ( shape.first != 1 or dimension == 1 ) and table.dimension == 1
|
646
681
|
[ self ].lut table, options
|
647
682
|
else
|
648
683
|
( 0 ... shape.first ).collect { |i| unroll[i] }.lut table, options
|
@@ -690,6 +725,35 @@ module Hornetseye
|
|
690
725
|
left
|
691
726
|
end
|
692
727
|
|
728
|
+
# Perform connected component labelling
|
729
|
+
#
|
730
|
+
# @option options [Object] :default (typecode.default) Value of background elements.
|
731
|
+
# @option options [Class] :target (UINT) Typecode of labels.
|
732
|
+
#
|
733
|
+
# @return [Node] Array with labels of connected components.
|
734
|
+
def components( options = {} )
|
735
|
+
if shape.any? { |x| x <= 1 }
|
736
|
+
raise "Every dimension must be greater than 1 (shape was #{shape})"
|
737
|
+
end
|
738
|
+
options = { :target => UINT, :default => typecode.default }.merge options
|
739
|
+
target = options[ :target ]
|
740
|
+
default = options[ :default ]
|
741
|
+
default = typecode.new default unless default.is_a? Node
|
742
|
+
left = Hornetseye::MultiArray( target, *shape ).new
|
743
|
+
labels = Sequence.new target, size; labels[0] = 0
|
744
|
+
rank = Sequence.uint size; rank[0] = 0
|
745
|
+
n = Hornetseye::Pointer( INT ).new; n.store INT.new( 0 )
|
746
|
+
block = Components.new left, self, default, target.new( 0 ), labels, rank, n
|
747
|
+
if block.compilable?
|
748
|
+
Hornetseye::GCCFunction.run block
|
749
|
+
else
|
750
|
+
block.demand
|
751
|
+
end
|
752
|
+
labels = labels[ 0 .. n.demand.get ]
|
753
|
+
left.lut labels.lut( labels.histogram( labels.size, :weight => target.new( 1 ) ).
|
754
|
+
minor( 1 ).integral - 1 )
|
755
|
+
end
|
756
|
+
|
693
757
|
# Select values from array using a mask
|
694
758
|
#
|
695
759
|
# @param [Node] m Mask to apply to this array.
|
data/lib/multiarray/pointer.rb
CHANGED
@@ -184,6 +184,22 @@ module Hornetseye
|
|
184
184
|
"#{self.class.to_s}(#{@value.to_s})"
|
185
185
|
end
|
186
186
|
|
187
|
+
# Store a value in this native element
|
188
|
+
#
|
189
|
+
# @param [Object] value New value for native element.
|
190
|
+
#
|
191
|
+
# @return [Object] Returns +value+.
|
192
|
+
#
|
193
|
+
# @private
|
194
|
+
def assign( value )
|
195
|
+
if @value.respond_to? :assign
|
196
|
+
@value.assign value.simplify.get
|
197
|
+
else
|
198
|
+
@value = value.simplify.get
|
199
|
+
end
|
200
|
+
value
|
201
|
+
end
|
202
|
+
|
187
203
|
# Store new value in this pointer
|
188
204
|
#
|
189
205
|
# @param [Object] value New value for this pointer object.
|
data/lib/multiarray/rgb.rb
CHANGED
@@ -125,7 +125,7 @@ module Hornetseye
|
|
125
125
|
# @return [Object] Returns +value+.
|
126
126
|
#
|
127
127
|
# @private
|
128
|
-
def
|
128
|
+
def assign( value )
|
129
129
|
@r, @g, @b = value.r, value.g, value.b
|
130
130
|
end
|
131
131
|
|
@@ -407,9 +407,9 @@ module Hornetseye
|
|
407
407
|
r = Thread.current[ :function ].variable self.class.element_type, 'v'
|
408
408
|
g = Thread.current[ :function ].variable self.class.element_type, 'v'
|
409
409
|
b = Thread.current[ :function ].variable self.class.element_type, 'v'
|
410
|
-
r.
|
411
|
-
g.
|
412
|
-
b.
|
410
|
+
r.assign @value.r
|
411
|
+
g.assign @value.g
|
412
|
+
b.assign @value.b
|
413
413
|
self.class.new RGB.new( r, g, b )
|
414
414
|
else
|
415
415
|
self.class.new get
|
@@ -423,20 +423,20 @@ module Hornetseye
|
|
423
423
|
# @return [Object] Returns +value+.
|
424
424
|
#
|
425
425
|
# @private
|
426
|
-
def
|
426
|
+
def assign( value )
|
427
427
|
value = value.simplify
|
428
|
-
if @value.r.respond_to? :
|
429
|
-
@value.r.
|
428
|
+
if @value.r.respond_to? :assign
|
429
|
+
@value.r.assign value.get.r
|
430
430
|
else
|
431
431
|
@value.r = value.get.r
|
432
432
|
end
|
433
|
-
if @value.g.respond_to? :
|
434
|
-
@value.g.
|
433
|
+
if @value.g.respond_to? :assign
|
434
|
+
@value.g.assign value.get.g
|
435
435
|
else
|
436
436
|
@value.g = value.get.g
|
437
437
|
end
|
438
|
-
if @value.b.respond_to? :
|
439
|
-
@value.b.
|
438
|
+
if @value.b.respond_to? :assign
|
439
|
+
@value.b.assign value.get.b
|
440
440
|
else
|
441
441
|
@value.b = value.get.b
|
442
442
|
end
|
@@ -935,3 +935,19 @@ class Fixnum
|
|
935
935
|
|
936
936
|
end
|
937
937
|
|
938
|
+
module Math
|
939
|
+
|
940
|
+
def sqrt_with_rgb( c )
|
941
|
+
if c.is_a? Hornetseye::RGB
|
942
|
+
Hornetseye::RGB.new sqrt( c.r ), sqrt( c.g ), sqrt( c.b )
|
943
|
+
else
|
944
|
+
sqrt_without_rgb c
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
alias_method_chain :sqrt, :rgb
|
949
|
+
module_function :sqrt_without_rgb
|
950
|
+
module_function :sqrt
|
951
|
+
|
952
|
+
end
|
953
|
+
|
data/lib/multiarray/store.rb
CHANGED
data/lib/multiarray/unmask.rb
CHANGED
@@ -84,14 +84,18 @@ module Hornetseye
|
|
84
84
|
Unmask.new( dest, @source, m, index, default ).demand
|
85
85
|
end
|
86
86
|
else
|
87
|
-
@m.
|
87
|
+
@m.if_else( proc do
|
88
88
|
Store.new( @dest, @source.element( index ) ).demand
|
89
|
-
index.
|
89
|
+
index.assign index + 1
|
90
90
|
end, proc do
|
91
91
|
Store.new( @dest, @default ).demand
|
92
92
|
end )
|
93
93
|
end
|
94
|
-
@index.
|
94
|
+
if @index.is_a? Pointer_
|
95
|
+
@index.store index
|
96
|
+
else
|
97
|
+
@index.assign index
|
98
|
+
end
|
95
99
|
@dest
|
96
100
|
else
|
97
101
|
super
|
data/test/tc_multiarray.rb
CHANGED
@@ -731,6 +731,11 @@ class TC_MultiArray < Test::Unit::TestCase
|
|
731
731
|
M( I, 3, 2 )[ [ 1, 2, 3 ], [ 4, 5, 6 ] ].integral
|
732
732
|
end
|
733
733
|
|
734
|
+
def test_components
|
735
|
+
assert_equal [ [ 1, 0, 2 ], [ 0, 0, 2 ], [ 2, 2, 2 ] ],
|
736
|
+
M[ [ 1, 0, 1 ], [ 0, 0, 1 ], [ 1, 1, 1 ] ].components.to_a
|
737
|
+
end
|
738
|
+
|
734
739
|
def test_mask
|
735
740
|
[ O, I ].each do |t|
|
736
741
|
assert_equal M( O, 2, 2 )[ [ 1, 2 ], [ 5, 7 ] ],
|
data/test/tc_sequence.rb
CHANGED
@@ -334,6 +334,10 @@ class TC_Sequence < Test::Unit::TestCase
|
|
334
334
|
assert_equal C( 3, 2, 3 ), S[ C( 1, 2, 3 ), C( 3, 2, 1 ) ].max
|
335
335
|
end
|
336
336
|
|
337
|
+
def test_between
|
338
|
+
assert_equal S[ false, true, true, false ], S[ 1, 2, 3, 4 ].between?( 2, 3 )
|
339
|
+
end
|
340
|
+
|
337
341
|
def test_normalise
|
338
342
|
assert_equal [ 0.0, 85.0, 255.0 ], S[ 1, 2, 4 ].normalise.to_a
|
339
343
|
assert_equal [ C( 0.0, 85.0, 255.0 ) ], S[ C( 1, 2, 4 ) ].normalise.to_a
|
@@ -713,6 +717,12 @@ class TC_Sequence < Test::Unit::TestCase
|
|
713
717
|
assert_in_delta x.real, y.real, 1.0e-5
|
714
718
|
assert_in_delta x.imag, y.imag, 1.0e-5
|
715
719
|
end
|
720
|
+
[ Math.sqrt( C( 1, 2, 3 ) ), Math.sqrt( C( 2, 4, 6 ) ) ].
|
721
|
+
zip( Math.sqrt( S[ C( 1, 2, 3 ), C( 2, 4, 6 ) ] ).to_a ).each do |x,y|
|
722
|
+
assert_in_delta x.r, y.r, 1.0e-5
|
723
|
+
assert_in_delta x.g, y.g, 1.0e-5
|
724
|
+
assert_in_delta x.b, y.b, 1.0e-5
|
725
|
+
end
|
716
726
|
end
|
717
727
|
|
718
728
|
def test_exp
|
@@ -928,6 +938,11 @@ class TC_Sequence < Test::Unit::TestCase
|
|
928
938
|
assert_equal S( I, 3 )[ 1, 3, 6 ], S( I, 3 )[ 1, 2, 3 ].integral
|
929
939
|
end
|
930
940
|
|
941
|
+
def test_components
|
942
|
+
assert_equal [ 0, 1, 1, 0, 2 ], S[ 0, 1, 1, 0, 1 ].components.to_a
|
943
|
+
assert_equal [ 0, 1, 1, 0, 2 ], S[ nil, 1, 1, nil, 1 ].components.to_a
|
944
|
+
end
|
945
|
+
|
931
946
|
def test_mask
|
932
947
|
assert_equal S( O, 2 )[ 2, 5 ], S( O, 3 )[ 2, 3, 5 ].
|
933
948
|
mask( S[ true, false, true ] )
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 21
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.21.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: 2011-
|
17
|
+
date: 2011-02-27 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- lib/multiarray/gcccontext.rb
|
67
67
|
- lib/multiarray/unmask.rb
|
68
68
|
- lib/multiarray/elementwise.rb
|
69
|
+
- lib/multiarray/components.rb
|
69
70
|
- lib/multiarray/diagonal.rb
|
70
71
|
- lib/multiarray/index.rb
|
71
72
|
- lib/multiarray/variable.rb
|