1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
=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
|