Class: CABlockIterator
- Inherits:
-
CAIterator
- Object
- CAIterator
- CABlockIterator
- Defined in:
- lib/carray/block_iterator.rb
Overview
Non-overlapping tile reduction dispatcher — the Block member of the
iterator family (sibling of CASlabIterator / CAWindowIterator /
CACategoricalIterator). Where a window iterator folds an overlapping
window per anchor, a block iterator folds each non-overlapping tile of a
fixed per-axis size, so the result is a tile grid: pooling, downsampling,
block statistics.
Obtained from CArray#blocks, not constructed directly.
Instance Attribute Summary collapse
-
#source ⇒ CArray
readonly
Returns the array being tiled (with any leading offset already applied).
Attributes inherited from CAIterator
Instance Method Summary collapse
-
#accumulate(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sum kept in the source's own data type, wrapping at its width, as the core
accumulatedoes --sumanswers in the type the core promotes to (float64 for integers). -
#all(min_count: nil, fill_value: nil) ⇒ CArray
Whether every cell of each tile is true.
-
#any(min_count: nil, fill_value: nil) ⇒ CArray
Whether any cell of each tile is true.
-
#count(v = <none>) ⇒ CArray
Per-tile count.
-
#count_masked ⇒ CArray
Per-tile count of masked cells.
-
#count_not_masked ⇒ CArray
Per-tile count of present (non-masked) cells.
-
#cumcount ⇒ CArray
Per-tile running count of present cells (int64), source-shaped.
-
#cummax ⇒ CArray
Per-tile inclusive running maximum (value data type), source-shaped.
-
#cummin ⇒ CArray
Per-tile inclusive running minimum (value data type), source-shaped.
-
#cumprod ⇒ CArray
Per-tile inclusive running product (float64), source-shaped.
-
#cumsum ⇒ CArray
Per-tile inclusive running sum (float64), source-shaped.
-
#each({ |tile| ... }) {|tile| ... } ⇒ Enumerator, self
Yields each tile as a uniform
Π b_i-shaped CArray (partial edge tiles have their out-of-bounds cells masked). -
#elements ⇒ CArray
Tile cell count (structural, mask-independent): the constant tile size
Π b_i, shaped like the tile grid. -
#initialize(source, *blocks) ⇒ CABlockIterator
constructor
Builds a block iterator tiling
sourcewith a per-axis tile size. -
#map({ |tile| ... }) {|tile| ... } ⇒ CArray, Enumerator
Per-tile element-wise transform: the block receives each tile (a uniform
Π b_i-shaped CArray, masked at partial edges) and returns a same-shaped tile (or a scalar to broadcast). -
#max(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile maximum.
-
#max_addr ⇒ CArray
Per-tile flat source address of the maximum.
-
#max_index ⇒ CArray
Per-tile position of the maximum (tile-local flat index).
-
#mean(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile arithmetic mean.
-
#median ⇒ Object
Per-tile median.
-
#min(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile minimum.
-
#min_addr ⇒ CArray
Per-tile flat SOURCE address of the minimum — which cell of the source holds it, so
source.reshape(source.elements)[bi.min_addr]are the tile minima. -
#min_index ⇒ CArray
Per-tile position of the minimum, as a flat index within the tile (a partial edge tile indexes within its own present cells).
-
#minmax(min_count: nil, fill_value: nil) ⇒ Array<CArray>
Per-tile
[min, max](two tile-grid-shaped CArrays, a single fused pass). -
#percentile(*pers) ⇒ CArray+
Per-tile percentile(s).
-
#prod(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile product.
-
#quantile ⇒ Array<CArray>
Per-tile five-number summary
[min, Q1, median, Q3, max](five CArrays). - #reduce(*args, data_type: nil, &blk) ⇒ Object
-
#sort_addr ⇒ CArray
Per-tile sort by flat SOURCE address, source-shaped: each tile's cells hold that tile's source addresses in ascending-value order (reading the tile row-major gives the sorted addresses), so
source.reshape(source.elements)[bi.sort_addr]is the source sorted within each tile. -
#stddev(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sample standard deviation (divisor
n - 1). -
#stddevp(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile population standard deviation (divisor
n). -
#sum(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sum.
-
#variance(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sample variance (divisor
n - 1). -
#variancep(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile population variance (divisor
n). -
#wmean(weights) ⇒ CArray
Per-tile weighted mean;
weightsshaped like one full tile. -
#wsum(weights) ⇒ CArray
Per-tile weighted sum;
weightsis shaped like one full tile (Π b_i).
Constructor Details
#initialize(source, *blocks) ⇒ CABlockIterator
Returns a new instance of CABlockIterator.
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 |
# File 'lib/carray/block_iterator.rb', line 69 def initialize (source, *blocks) blocks = blocks[0] if blocks.size == 1 && blocks[0].is_a?(Array) unless blocks.size == source.ndim raise ArgumentError, "blocks: expected #{source.ndim} tile sizes (one per axis), " \ "got #{blocks.size}" end @sndim = source.ndim offsets = Array.new(@sndim, 0) @sizes = Array.new(@sndim) blocks.each_with_index do |b, i| if b.is_a?(Range) offsets[i] = b.begin @sizes[i] = b.end - b.begin + (b.exclude_end? ? 0 : 1) else @sizes[i] = Integer(b) end if @sizes[i] < 1 raise ArgumentError, "blocks: tile size on axis #{i} must be >= 1" end end # Absorb a leading offset with a zero-copy pre-slice, so the tile geometry # below always starts at index 0. @source = if offsets.all?(&:zero?) source else source[*offsets.map { |o| o..-1 }] end n = @source.shape @q = @sndim.times.map { |i| n[i] / @sizes[i] } # full tiles per axis @r = @sndim.times.map { |i| n[i] % @sizes[i] } # remainder per axis # Ceil tile grid: a partial edge tile adds one grid cell on that axis. @shape = @sndim.times.map { |i| @q[i] + (@r[i] > 0 ? 1 : 0) } @ndim = @shape.size # Trailing tile axes of a block_view: [ndim .. 2*ndim-1]. @tile_axes = (@sndim...(2 * @sndim)).to_a self end |
Instance Attribute Details
#source ⇒ CArray (readonly)
118 119 120 |
# File 'lib/carray/block_iterator.rb', line 118 def source @source end |
Instance Method Details
#accumulate(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sum kept in the source's own data type, wrapping at its
width, as the core accumulate does -- sum answers in the type
the core promotes to (float64 for integers).
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#all(min_count: nil, fill_value: nil) ⇒ CArray
Whether every cell of each tile is true.
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#any(min_count: nil, fill_value: nil) ⇒ CArray
Whether any cell of each tile is true.
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#count(v = <none>) ⇒ CArray
303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/carray/block_iterator.rb', line 303 def count (*args) return count_not_masked if args.empty? out = nil each_region do |strip_ranges, tiles, out_ranges| view = @source[*strip_ranges].block_view(*tiles) # block_view is a CAStride, so #count is not shadowed; dispatch # CArray#count explicitly anyway, matching the family regularity. red = CArray.instance_method(:count).bind_call(view, *args, axis: @tile_axes) out ||= CArray.new(red.data_type, @shape) out[*out_ranges] = red end out end |
#count_masked ⇒ CArray
329 330 331 |
# File 'lib/carray/block_iterator.rb', line 329 def count_masked elements - count_not_masked end |
#count_not_masked ⇒ CArray
321 322 323 |
# File 'lib/carray/block_iterator.rb', line 321 def count_not_masked fold(:count_not_masked) end |
#cumcount ⇒ CArray
Per-tile running count of present cells (int64), source-shaped.
624 625 626 |
# File 'lib/carray/block_iterator.rb', line 624 [:cumsum, :cumprod, :cummax, :cummin, :cumcount].each do |op| define_method(op) { block_scan(op) } end |
#cummax ⇒ CArray
Per-tile inclusive running maximum (value data type), source-shaped.
624 625 626 |
# File 'lib/carray/block_iterator.rb', line 624 [:cumsum, :cumprod, :cummax, :cummin, :cumcount].each do |op| define_method(op) { block_scan(op) } end |
#cummin ⇒ CArray
Per-tile inclusive running minimum (value data type), source-shaped.
624 625 626 |
# File 'lib/carray/block_iterator.rb', line 624 [:cumsum, :cumprod, :cummax, :cummin, :cumcount].each do |op| define_method(op) { block_scan(op) } end |
#cumprod ⇒ CArray
Per-tile inclusive running product (float64), source-shaped.
624 625 626 |
# File 'lib/carray/block_iterator.rb', line 624 [:cumsum, :cumprod, :cummax, :cummin, :cumcount].each do |op| define_method(op) { block_scan(op) } end |
#cumsum ⇒ CArray
Per-tile inclusive running sum (float64), source-shaped.
624 625 626 |
# File 'lib/carray/block_iterator.rb', line 624 [:cumsum, :cumprod, :cummax, :cummin, :cumcount].each do |op| define_method(op) { block_scan(op) } end |
#each({ |tile| ... }) {|tile| ... } ⇒ Enumerator, self
540 541 542 543 544 545 546 |
# File 'lib/carray/block_iterator.rb', line 540 def each return to_enum(:each) unless block_given? tgv = tile_grid_view nils = Array.new(@sndim, nil) CArray.each_index(*@shape) { |*g| yield tgv[*g, *nils] } self end |
#elements ⇒ CArray
339 340 341 342 343 344 |
# File 'lib/carray/block_iterator.rb', line 339 def elements sz = @sizes.inject(1) { |p, b| p * b } out = CArray.int64(*@shape) out[] = sz out end |
#map({ |tile| ... }) {|tile| ... } ⇒ CArray, Enumerator
586 587 588 589 590 591 592 593 594 |
# File 'lib/carray/block_iterator.rb', line 586 def map return to_enum(:map) unless block_given? pout = CArray.new(padded_source.data_type, padded_source.shape) pgv = pout.block_view(*@sizes) tgv = tile_grid_view nils = Array.new(@sndim, nil) CArray.each_index(*@shape) { |*g| pgv[*g, *nils] = yield(tgv[*g, *nils]) } pout[*@sndim.times.map { |i| 0...@source.shape[i] }].copy end |
#max(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile maximum.
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#max_addr ⇒ CArray
384 |
# File 'lib/carray/block_iterator.rb', line 384 def max_addr; winner_addr(:max_index); end |
#max_index ⇒ CArray
Per-tile position of the maximum (tile-local flat index).
365 366 367 368 369 370 371 |
# File 'lib/carray/block_iterator.rb', line 365 [:min_index, :max_index].each do |op| class_eval <<~RUBY, __FILE__, __LINE__ + 1 def #{op} assemble { |view, _| view.#{op}(axis: @tile_axes) } end RUBY end |
#mean(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile arithmetic mean.
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#median ⇒ Object
487 488 489 |
# File 'lib/carray/block_iterator.rb', line 487 def median order_stat { |v, axis| v.median(axis: axis) } end |
#min(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile minimum.
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#min_addr ⇒ CArray
379 |
# File 'lib/carray/block_iterator.rb', line 379 def min_addr; winner_addr(:min_index); end |
#min_index ⇒ CArray
Per-tile position of the minimum, as a flat index within the tile (a partial edge tile indexes within its own present cells).
365 366 367 368 369 370 371 |
# File 'lib/carray/block_iterator.rb', line 365 [:min_index, :max_index].each do |op| class_eval <<~RUBY, __FILE__, __LINE__ + 1 def #{op} assemble { |view, _| view.#{op}(axis: @tile_axes) } end RUBY end |
#minmax(min_count: nil, fill_value: nil) ⇒ Array<CArray>
351 352 353 354 355 356 |
# File 'lib/carray/block_iterator.rb', line 351 def minmax (min_count: nil, fill_value: nil) kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? assemble { |view, _| view.minmax(axis: @tile_axes, **kw) } end |
#percentile(*pers) ⇒ CArray+
495 496 497 |
# File 'lib/carray/block_iterator.rb', line 495 def percentile (*pers) order_stat { |v, axis| v.percentile(*pers, axis: axis) } end |
#prod(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile product.
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#quantile ⇒ Array<CArray>
502 503 504 |
# File 'lib/carray/block_iterator.rb', line 502 def quantile order_stat { |v, axis| v.quantile(axis: axis) } end |
#reduce({ |tile| ... }) {|tile| ... } ⇒ CArray #reduce(init) ⇒ CArray
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 |
# File 'lib/carray/block_iterator.rb', line 559 def reduce (*args, data_type: nil, &blk) raise LocalJumpError, "no block given (yield)" unless blk out = CArray.new(data_type || CA_OBJECT, @shape) tgv = tile_grid_view nils = Array.new(@sndim, nil) if args.empty? CArray.each_index(*@shape) { |*g| out[*g] = blk.call(tgv[*g, *nils]) } else init = args[0] CArray.each_index(*@shape) do |*g| acc = init tgv[*g, *nils].each { |e| acc = blk.call(acc, e) } out[*g] = acc end end out end |
#sort_addr ⇒ CArray
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
# File 'lib/carray/block_iterator.rb', line 424 def sort_addr saddr = CArray.int64(*@source.shape).seq! out = CArray.int64(*@source.shape) out[] = UNDEF each_region do |strip_ranges, tiles, _out_ranges| vview = @source[*strip_ranges].block_view(*tiles) sview = saddr[*strip_ranges].block_view(*tiles) grid = (0...@sndim).map { |i| vview.shape[i] } cells = tiles.inject(1) { |p, t| p * t } order = vview.copy.reshape(*(grid + [cells])).sort_addr(axis: @sndim) src_sorted = sview.reshape(*(grid + [cells])).take_along_axis(order, axis: @sndim) out[*strip_ranges].block_view(*tiles)[] = src_sorted.reshape(*(grid + tiles)) end out end |
#stddev(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sample standard deviation (divisor n - 1).
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#stddevp(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile population standard deviation (divisor n).
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#sum(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sum.
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#variance(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile sample variance (divisor n - 1).
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#variancep(min_count: nil, fill_value: nil) ⇒ CArray
Per-tile population variance (divisor n).
286 287 288 289 290 291 292 293 294 |
# File 'lib/carray/block_iterator.rb', line 286 [:sum, :accumulate, :prod, :mean, :min, :max, :variance, :stddev, :all, :any, :variancep, :stddevp].each do |op| define_method(op) do |min_count: nil, fill_value: nil| kw = {} kw[:min_count] = min_count unless min_count.nil? kw[:fill_value] = fill_value unless fill_value.nil? fold(op, **kw) end end |
#wmean(weights) ⇒ CArray
451 452 453 |
# File 'lib/carray/block_iterator.rb', line 451 def wmean (weights) weighted(weights) { |view, w| view.wmean(w, axis: @tile_axes) } end |
#wsum(weights) ⇒ CArray
444 445 446 |
# File 'lib/carray/block_iterator.rb', line 444 def wsum (weights) weighted(weights) { |view, w| view.wsum(w, axis: @tile_axes) } end |