module NumRu::Misc::MD_Iterators

A Mixin. To be included in a class with multi-dimension indexing support (such as NArray).

Public Instance Methods

each_subary_at_dims( *dims ) { |self| ... } click to toggle source

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 <tt>na>/tt> 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.

# File lib/numru/misc/md_iterators.rb, line 62
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
each_subary_at_dims_with_index( *dims ) { |self, false| ... } click to toggle source

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).

# File lib/numru/misc/md_iterators.rb, line 110
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