=begin
=module NumRu::Misc::MD_Iterators
A Mixin.
To be included in a class with multi-dimension indexing support
(such as NArray).
==Index
* ((<each_subary_at_dims>))
* ((<each_subary_at_dims_with_index>))
==Methods
---each_subary_at_dims( *dims )
Iterator for each sub-array (not each element) specified by dimensions.
ARGUMENT
* ((|dims|)) (integers) : specifies subsets at dimensions
specified here with the beginning-to-end selection.
For example, [0, 1] to specify the first 2 dimensions
(subsets will be 2D then), and [2] to specify the 3rd
dimension (subsets will be 1D). Duplication has no effect,
so [0,0] and [0] are the same. Also, its order has no effect.
See EXAMPLE below for more.
RETURN VALUE
* self
POSSIBLE EXCEPTIONS
* exception is raised if ( dims.min<0 || dims.max>=self.rank ).
EXAMPLE
* Suppose that you want to do something with 2D sub-arrays in a
multi-dimension NArray. First, you include this module as follows:
require "narray"
class NArray
include NumRu::Misc::MD_Iterators
end
And prepare the array if you have not (here, it is 4D):
na = NArray.int(10,2,5,2).indgen!
Then you do the job like this:
na.each_subary_at_dims(0,2){ |sub|
... # do whatever with sub
}
This is equivalent to the following:
(0...na.shape[3]).each{|j|
(0...na.shape[1]).each{|i|
sub = na[0..-1, i, 0..-1, j]
... # do whatever with sub
}
}
Note that the loop must be nested 3 times when (('na')) is a 5D array,
if the latter approach is used. On the other hand, it will still
require the same single loop with the former.
---each_subary_at_dims_with_index( *dims )
Like ((<each_subary_at_dims>)) but the block takes two arguments:
subset and the subset specifier (index).
EXAMPLE
* Suppose the example above in ((<each_subary_at_dims>)) (EXAMPLE).
And suppose that you want to overwrite (('na')) with the result
you get. You can do it like this:
na.each_subary_at_dims_with_index(0,2){ |sub,idx|
result = (sub + 10) / 2
na[*idx] = result
}
Here, (('idx')) is an Array to be fed in the []= or [] methods
with asterisk (ungrouping).
=end
module NumRu
module Misc
module MD_Iterators
def each_subary_at_dims( *dims )
if dims.min<0 || dims.max>=rank
raise ArguemntError,"Invalid dims #{dims.inspect} for #{rank}D array"
end
loopdims = Array.new
sh = Array.new
len = 1
(0...rank).each{|i|
if !dims.include?(i)
loopdims.push(i)
sh.push(shape[i])
len *= shape[i]
end
}
if loopdims.length == 0
yield(self)
return self
end
cs = [1]
(1...sh.length).each{|i| cs[i] = sh[i-1]*cs[i-1]}
idx = Array.new
all = 0..-1
for i in 0...len do
loopdims.each_with_index{|d,j| idx[d] = ( (i/cs[j])%sh[j] )}
dims.each{|d| idx[d] = all}
sub = self[ *idx ]
yield(sub)
end
self
end
def each_subary_at_dims_with_index( *dims )
if dims.min<0 || dims.max>=rank
raise ArguemntError,"Invalid dims #{dims.inspect} for #{rank}D array"
end
loopdims = Array.new
sh = Array.new
len = 1
(0...rank).each{|i|
if !dims.include?(i)
loopdims.push(i)
sh.push(shape[i])
len *= shape[i]
end
}
if loopdims.length == 0
yield(self, false)
return self
end
cs = [1]
(1...sh.length).each{|i| cs[i] = sh[i-1]*cs[i-1]}
idx = Array.new
all = 0..-1
for i in 0...len do
loopdims.each_with_index{|d,j| idx[d] = ( (i/cs[j])%sh[j] )}
dims.each{|d| idx[d] = all}
sub = self[ *idx ]
yield(sub, idx)
end
self
end
end
end
end
##################################
if __FILE__ == $0
require "narray"
class NArray
include NumRu::Misc::MD_Iterators
end
na = NArray.int(10,2,2,2).indgen!
puts "** test A **"
na.each_subary_at_dims(0,1){ |sub|
p sub
}
puts "** test B **"
na.each_subary_at_dims(0,3){ |sub|
p sub
}
puts "** test C **"
na.each_subary_at_dims(2,1,0){ |sub| # same as (0,1,2)
p sub
}
puts "** test C **"
na.each_subary_at_dims(0,1,2,3){ |sub|
p sub
}
end
syntax highlighted by Code2HTML, v. 0.9.1