module
Phase::MultiIndexable(T)
Overview
The MultiIndexable module provides a unified interface for
multidimensional array types, much like how Indexable provides a standard
corpus of methods for one-dimensional collections.
How to Implement a MultiIndexable
Implementing MultiIndexable will require that you provide a #shape and
#unsafe_fetch_element method, however this is the bare minimum. For a
performant implementation, you should consider overriding
#unsafe_fetch_chunk, #fast_each, and #size in that order of importance
(and more as you see fit).
Included Modules
- Enumerable(T)
- Iterable(T)
Direct including types
Defined in:
multi_indexable.crmulti_indexable/chunk_iterator.cr
multi_indexable/chunk_region_iterator.cr
multi_indexable/elem_coord_iterator.cr
multi_indexable/elem_iterator.cr
multi_indexable/formatter/formatter.cr
multi_indexable/formatter/settings.cr
multi_indexable/tiling_lex_iterator.cr
Class Method Summary
Macro Summary
- coord_splat_overload(name)
- def_elementwise_binary(name)
- def_elementwise_unary(name)
-
region_splat_overload(name)
TODO rename these? These primarily exist for user clarity (could easily have all these methods forward all their args to a single funciton to handle tuple-packaging, but would leave a rather opaque method signature behind)
Instance Method Summary
-
#%(other : MultiIndexable(U)) forall U
Invokes
#%element-wise betweenselfand other, returning anNArraythat contains the results. -
#%(other)
Invokes
#%(other)on each element inself, returning anNArraythat contains the results. -
#&(other : MultiIndexable(U)) forall U
Invokes
#&element-wise betweenselfand other, returning anNArraythat contains the results. -
#&(other)
Invokes
#&(other)on each element inself, returning anNArraythat contains the results. -
#&*(other : MultiIndexable(U)) forall U
Invokes
#&*element-wise betweenselfand other, returning anNArraythat contains the results. -
#&*(other)
Invokes
#&*(other)on each element inself, returning anNArraythat contains the results. -
#&**(other : MultiIndexable(U)) forall U
Invokes
#&**element-wise betweenselfand other, returning anNArraythat contains the results. -
#&**(other)
Invokes
#&**(other)on each element inself, returning anNArraythat contains the results. -
#&+(other : MultiIndexable(U)) forall U
Invokes
#&+element-wise betweenselfand other, returning anNArraythat contains the results. -
#&+(other)
Invokes
#&+(other)on each element inself, returning anNArraythat contains the results. -
#&-(other : MultiIndexable(U)) forall U
Invokes
#&-element-wise betweenselfand other, returning anNArraythat contains the results. -
#&-(other)
Invokes
#&-(other)on each element inself, returning anNArraythat contains the results. - #*(other : MultiIndexable(U)) forall U
- #*(other)
- #**(other : MultiIndexable(U)) forall U
-
#**(other)
Invokes
#**(other)on each element inself, returning anNArraythat contains the results. - #+(other : MultiIndexable(U)) forall U
- #+(other)
- #+
- #-(other : MultiIndexable(U)) forall U
- #-(other)
- #-
- #/(other : MultiIndexable(U)) forall U
- #/(other)
- #//(other : MultiIndexable(U)) forall U
-
#//(other)
Invokes
#//(other)on each element inself, returning anNArraythat contains the results. -
#<(other : MultiIndexable(U)) forall U
Invokes
#<element-wise betweenselfand other, returning anNArraythat contains the results. -
#<(other)
Invokes
#<(other)on each element inself, returning anNArraythat contains the results. -
#<=(other : MultiIndexable(U)) forall U
Invokes
#<=element-wise betweenselfand other, returning anNArraythat contains the results. -
#<=(other)
Invokes
#<=(other)on each element inself, returning anNArraythat contains the results. -
#<=>(other : MultiIndexable(U)) forall U
Invokes
#<=>element-wise betweenselfand other, returning anNArraythat contains the results. -
#<=>(other)
Invokes
#<=>(other)on each element inself, returning anNArraythat contains the results. -
#==(other : self) : Bool
Returns true if both the shape and elements of
selfand other are equal. -
#=~(value) : MultiIndexable(Bool)
TODO DISCUSS this syntax as an alternative or supplement to elem_eq
-
#>(other : MultiIndexable(U)) forall U
Invokes
#>element-wise betweenselfand other, returning anNArraythat contains the results. -
#>(other)
Invokes
#>(other)on each element inself, returning anNArraythat contains the results. -
#>=(other : MultiIndexable(U)) forall U
Invokes
#>=element-wise betweenselfand other, returning anNArraythat contains the results. -
#>=(other)
Invokes
#>=(other)on each element inself, returning anNArraythat contains the results. -
#[](region_literal : Indexable, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
Copies the elements described by region into a new
MultiIndexable. -
#[](region : IndexRegion)
IndexRegionaccepting form of#[](region_literal : Indexable, drop : Bool). -
#[](*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
Tuple-accepting overload of
#[](region_literal : Indexable, drop : Bool). -
#[]?(bool_mask : MultiIndexable(Bool)) : MultiIndexable(T | Nil)
Returns a
MultiIndexablethat draws fromselfwhere bool_mask is true, but containsnilwhere bool_mask is false. -
#[]?(region : Indexable, drop : Bool = MultiIndexable::DROP_BY_DEFAULT) : MultiIndexable(T) | Nil
Copies the elements in region to a new
MultiIndexableif#has_region?(region)is true, and returnsnilotherwise. -
#[]?(region : IndexRegion) : MultiIndexable(T) | Nil
IndexRegionaccepting overload of#[]?(region : Indexable, drop : Bool). -
#[]?(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
Tuple-accepting overload of
#[]?(region_literal : Indexable, drop : Bool). - #^(other : MultiIndexable(U)) forall U
- #^(other)
- #|(other : MultiIndexable(U)) forall U
- #|(other)
- #~
- #apply : ApplyProxy
- #apply! : InPlaceApplyProxy
-
#colex_each : ElemIterator
Returns an iterator that will yield each element of
selfin colexicographic (column-major) order. -
#colex_each(&) : Nil
Block accepting form of
#colex_each. -
#colex_each_coord : ColexIterator
Returns an iterator that will yield each coordinate of
selfin colexicographic (column-major) order. -
#colex_each_coord(&) : Nil
Block accepting form of
#colex_each_coord. -
#dimensions : Int
Returns the number of dimensions that this MultiIndexable is embedded in.
-
#each : ElemIterator
Returns an iterator that will yield each element of
selfin lexicographic (row-major) order. -
#each(&) : Nil
Block accepting form of
#each. -
#each_coord : LexIterator
Returns an iterator that will yield each coordinate of
selfin lexicographic (row-major) order. -
#each_coord(&) : Nil
Block accepting form of
#each_coord. -
#each_slice(axis = 0) : Iterator
Returns an Iterator equivalent to the method
#each_slice(axis, &block). -
#each_slice(axis = 0, &)
Yields the slices of this
MultiIndexablealong a given axis to the provided block. -
#each_with(*args, &)
Iterates over tuples of elements drawn from
selfand args, where args contains otherMultiIndexables you wish to access. -
#each_with_coord : ElemAndCoordIterator
Returns an iterator that will yield tuples of the elements and coords comprising
selfin lexicographic (row-major) order. -
#each_with_coord(&) : Nil
Block accepting form of
#each_with_coord. -
#empty? : Bool
Returns
trueif and only if thisMultiIndexablespans no elements. - #ensure_writable
-
#eq(other : MultiIndexable(U)) : MultiIndexable(Bool) forall U
TODO rename to elem_eq Produces an NArray(Bool) (by default) describing which elements of self and other are equal.
- #eq(value) : MultiIndexable(Bool)
-
#equals?(other : MultiIndexable, &) : Bool
Returns true if the block returns true for each pair of elements (that share a coordinate) from
selfandother. -
#fast_each : Iterator(T)
Returns an Iterator over the elements in this
MultiIndexablethat will iterate in the fastest order possible. -
#fast_each(&) : Nil
Block accepting form of
#fast_each. -
#first : T
Returns the element at the zero coordinate (position
0along every axis). -
#get(coord : Indexable) : T
Shorthand for
#get_element. -
#get(*coord : Int)
Tuple-accepting overload of
#get. -
#get_available(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT)
Returns a
MultiIndexablecontaining elements whose coordinates belong both to#shapeand region_literal. -
#get_available(region : IndexRegion, drop : Bool = DROP_BY_DEFAULT)
IndexRegionaccepting overload of#get_available(region : Indexable, drop : Bool) -
#get_available(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
Tuple-accepting overload of
#get_available(region_literal : Indexable, drop : Bool). -
#get_chunk(coord : Indexable, region_shape : Indexable(I)) forall I
TEST Extracts a chunk given a shape (region_shape) and the coord in that region with the smallest value in each axis.
-
#get_chunk(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT)
A more verbose overload of
#[](region_literal : Indexable, drop : Bool). -
#get_chunk(region : IndexRegion) : MultiIndexable(T)
IndexRegionaccepting form of#get_chunk(region_literal : Indexable, drop : Bool). -
#get_chunk(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
Tuple-accepting overload of
#get_chunk(region_literal : Indexable, drop : Bool). -
#get_element(coord : Indexable) : T
Retrieves the element specified by coord, throwing an error if coord is out-of-bounds for
self. -
#get_element(*coord : Int)
Tuple-accepting overload of
#get_element. -
#has_coord?(coord : Indexable) : Bool
Returns true if coord is a valid coordinate in this
MultiIndexable. -
#has_coord?(*coord : Int)
Tuple-accepting overload of
#has_coord?. -
#has_region?(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT) : Bool
Returns true if all the coordinates spanned by region_literal are valid coordiantes in this
MultiIndexable. -
#has_region?(region : IndexRegion) : Bool
IndexRegion accepting form of
#has_region?(region_literal) -
#has_region?(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
Tuple-accepting overload of
#has_region?(region_literal : Indexable, drop : Bool). - #hash(hasher)
-
#last : T
Returns the element with the largest ordinate in each axis (the element at the largest coordinate).
-
#map(&block : T -> R) : MultiIndexable(R) forall R
Returns a
MultiIndexablewith the results of running the block against each element ofself. -
#map!(&block : T -> T | MultiIndexable(T)) : MultiIndexable(T)
TODO docs, test
- #map_with(*args : *U, &) forall U
-
#map_with(*args, &)
Iterates over tuples of elements from
selfand args, and creating aMultiIndexablecontaining the output of the block to which those tuples are provided. - #map_with!(*args : *U, &) forall U
-
#map_with_coord(&)
Returns a
MultiIndexablewith the results of running the block against each element and coordinate comprisingself. -
#map_with_coord!(&block : T -> MultiIndexable(T))
TODO docs DISCUSS is this good behaviour?
- #permute(*args) : MultiIndexable(T)
- #process(&block : T -> R) : ProcView(self, T, R) forall R
- #process(proc : Proc(T, R)) : ProcView(self, T, R) forall R
- #reshape(*args) : MultiIndexable(T)
- #reverse(*args) : MultiIndexable(T)
-
#sample(n : Int, random = Random::DEFAULT) : Enumerable(T)
Returns a collection of n elements picked at random from this MultiIndexable.
-
#sample(random = Random::DEFAULT) : T
Returns an element picked at random from this
MultiIndexable. -
#scalar? : Bool
Returns
trueif thisMultiIndexablecontains only a single element. -
#shape : Array
Returns the capacity of each axis spanned by
self. -
#size
Returns the total number of elements in this
MultiIndexable. -
#slices(axis = 0) : Indexable
Returns an Indexable collection of the slices returned by
#each_slice. -
#tile(counts : Enumerable(Int)) : MultiIndexable
counts specifies how many times to copy the tile in each axis.
-
#tile(*counts : Int)
Tuple-accepting overload of
#tile(counts : Enumerable). -
#to_f : Float
TEST Returns
to_scalar.to_f. - #to_literal_s(io : IO) : Nil
-
#to_narr : NArray(T)
Creates an
NArrayduplicate of thisMultiIndexable. -
#to_s(io : IO, settings = Formatter::Settings.new) : Nil
FIXME NArrayFormatter depends on buffer indices.
-
#to_s(settings = Formatter::Settings.new) : String
FIXME NArrayFormatter depends on buffer indices.
-
#to_scalar : T
If this
MultiIndexableis a scalar (see#scalar?),#to_scalarwill return the sole element that it contains. -
#to_scalar? : T | Nil
Identical to
#to_scalar, but returnsnilin case of an error. -
#unsafe_fetch_chunk(region : IndexRegion) : MultiIndexable(T)
Copies the elements described by region into a new
MultiIndexablewithout performing any bounds checking. -
#unsafe_fetch_element(coord : Indexable) : T
Returns the element at the provided coord, possibly mutating coord, without performing canonicalization or bounds-checking.
- #view(region : Indexable | Nil | IndexRegion = nil) : View(self, T)
- #view(*region) : View(self, T)
Class Method Detail
Macro Detail
TODO rename these? These primarily exist for user clarity (could easily have all these methods forward all their args to a single funciton to handle tuple-packaging, but would leave a rather opaque method signature behind)
Instance Method Detail
Invokes #% element-wise between self and other, returning
an NArray that contains the results.
Invokes #%(other) on each element in self, returning an
NArray that contains the results.
Invokes #& element-wise between self and other, returning
an NArray that contains the results.
Invokes #&(other) on each element in self, returning an
NArray that contains the results.
Invokes #&* element-wise between self and other, returning
an NArray that contains the results.
Invokes #&*(other) on each element in self, returning an
NArray that contains the results.
Invokes #&** element-wise between self and other, returning
an NArray that contains the results.
Invokes #&**(other) on each element in self, returning an
NArray that contains the results.
Invokes #&+ element-wise between self and other, returning
an NArray that contains the results.
Invokes #&+(other) on each element in self, returning an
NArray that contains the results.
Invokes #&- element-wise between self and other, returning
an NArray that contains the results.
Invokes #&-(other) on each element in self, returning an
NArray that contains the results.
Invokes #**(other) on each element in self, returning an
NArray that contains the results.
Invokes #//(other) on each element in self, returning an
NArray that contains the results.
Invokes #< element-wise between self and other, returning
an NArray that contains the results.
Invokes #<(other) on each element in self, returning an
NArray that contains the results.
Invokes #<= element-wise between self and other, returning
an NArray that contains the results.
Invokes #<=(other) on each element in self, returning an
NArray that contains the results.
Invokes #<=> element-wise between self and other, returning
an NArray that contains the results.
Invokes #<=>(other) on each element in self, returning an
NArray that contains the results.
Returns true if both the shape and elements of self and other are equal.
NArray.new([1, 2]) == NArray.new([1, 2]) # => true
NArray.new([[1], [2]]) == NArray.new([1, 2]) # => false
NArray.new([8, 2]) == NArray.new([1, 2]) # => false
TODO DISCUSS this syntax as an alternative or supplement to elem_eq
Invokes #> element-wise between self and other, returning
an NArray that contains the results.
Invokes #>(other) on each element in self, returning an
NArray that contains the results.
Invokes #>= element-wise between self and other, returning
an NArray that contains the results.
Invokes #>=(other) on each element in self, returning an
NArray that contains the results.
Copies the elements described by region into a new MultiIndexable.
If region does not describe a valid region of this MultiIndexable,
this method will raise either a DimensionError (in the case of
an improper number of dimensions) or a ShapeError (in the case where
the number of dimensions is correct, but the region is not meaningful
for this MultiIndexable's shape.
Note: this method has a tuple accepting overload, as well, which makes the syntax much more intuitive. The following example contains both versions, but please note the difference.
narr = NArray.new([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Select only the first row:
narr[[0], drop: true] # => NArray[1, 2, 3]
# Unless you need to explicitly disable dropping, use the tuple overload:
narr[0] # => NArray[1, 2, 3] (drop is true by default)
# Select only the first column:
narr[.., 0] # => NArray[1, 2, 3]
# Select only the first column, without dropping dimensions:
# (in this case, we can't use the tuple accepting overload, hence the extra brackets)
narr[[.., 0], drop: false] # => NArray[[1], [2], [3]]
# Equivalently to the above, using anything other than an integer will bypass
# dropping:
narr[.., 0..0] # => NArray[[1], [2], [3]]
# Select only elements from both even-numbered rows and columns:
narr[0..2.., 0..2..] # => NArray[[1, 3], [7, 9]]
# This method raises a DimensionError when there is a dimensions mismatch:
narr[0, 1, 2, 3] # => DimensionError
# This method raises a ShapeError when there is a shape mismatch:
narr[1..100, 2..30] # => ShapeError
IndexRegion accepting form of #[](region_literal : Indexable, drop : Bool).
Note that region is what controls the dimension dropping behaviour, here.
Tuple-accepting overload of #[](region_literal : Indexable, drop : Bool).
Returns a MultiIndexable that draws from self where bool_mask is true, but contains nil where bool_mask is false.
If bool_mask has a different shape than self, this method will raise
a ShapeError.
narr = NArray[3, 4, 5]
mask = NArray[false, true, true]
narr[mask]? # => NArray[nil, 4, 5]
oversized_mask = NArray[false, true, true, false]
narr[oversized_mask]? # => ShapeError
Copies the elements in region to a new MultiIndexable if #has_region?(region) is true, and returns nil otherwise.
narr = NArray[[1, 2, 3], [4, 5, 6]]
narr[1.., 10..12]? # => nil
narr[0.., 1..2]? # => NArray[[2, 3], [5, 6]]
IndexRegion accepting overload of #[]?(region : Indexable, drop : Bool).
Tuple-accepting overload of #[]?(region_literal : Indexable, drop : Bool).
Returns an iterator that will yield each element of self in colexicographic (column-major) order.
narr = NArray[[1, 2, 3], [4, 5, 6]]
iter = narr.each
iter.next # => 1
iter.next # => 4
iter.next # => 2
iter.next # => 5
iter.next # => 3
iter.next # => 6
iter.next # => Iterator::Stop
#colex_each can be manipulated the same ways as #each. See #each
or MultiIndexable::ElemIterator for more information.
Returns an iterator that will yield each coordinate of self in colexicographic (column-major) order.
narr = NArray[[1, 2, 3], [4, 5, 6]]
iter = narr.each_coord
iter.next # => [0, 0]
iter.next # => [0, 1]
iter.next # => [0, 2]
iter.next # => [1, 0]
iter.next # => [1, 1]
iter.next # => [1, 2]
iter.next # => Iterator::Stop
Returns the number of dimensions that this MultiIndexable is embedded in.
This can equally be seen by the number of indices required to uniquely
specify a coordinate into this MultiIndexable, and is always equal to
shape.size
NArray.new([1, 2]).dimensions # => 1
NArray.new([[1, 2], [3, 4]]).dimensions # => 2
NArray.new([[[1]]]).dimensions # => 3
Returns an iterator that will yield each element of self in lexicographic (row-major) order.
narr = NArray[[1, 2, 3], [4, 5, 6]]
iter = narr.each
iter.next # => 1
iter.next # => 2
iter.next # => 3
iter.next # => 4
iter.next # => 5
iter.next # => 6
iter.next # => Iterator::Stop
#each can also be chained with other calls to manipulate its behaviour -
for example each.with_coord.reverse_each. See MultiIndexable::ElemIterator
for more information.
Returns an iterator that will yield each coordinate of self in lexicographic (row-major) order.
narr = NArray[[1, 2, 3], [4, 5, 6]]
iter = narr.each_coord
iter.next # => [0, 0]
iter.next # => [0, 1]
iter.next # => [0, 2]
iter.next # => [1, 0]
iter.next # => [1, 1]
iter.next # => [1, 2]
iter.next # => Iterator::Stop
Returns an Iterator equivalent to the method #each_slice(axis, &block).
Yields the slices of this MultiIndexable along a given axis to the provided block.
The elements returned in each slice are the ones with a constant index
along the specified axis.
narr = NArray[[1, 2, 3], [4, 5, 6]]
# axis one ->
#
# axis 0 1 2
# zero 0 [1 2 3]
# | 1 [4 5 6]
# v
# defaults to axis = 0, so the slices will be the rows.
narr.each_slice do |slice|
# in loop 0, slice will be NArray[1, 2, 3], because those elements have coords [0, ...]
# in loop 1, slice will be NArray[4, 5, 6], because those elements have coords [1, ...]
end
# here we pick axis = 1, so the slices will be the columns.
narr.each_slice(axis: 1) do |slice|
# in loop 0, slice will be NArray[1, 4], because those elements have coords [..., 0]
# in loop 1, slice will be NArray[2, 5], because those elements have coords [..., 1]
# in loop 0, slice will be NArray[3, 6], because those elements have coords [..., 2]
end
Iterates over tuples of elements drawn from self and args, where args contains other MultiIndexables you wish to access.
This is effectively an n-dimensional analogue of Enumerable#zip.
narr_1 = NArray[[1, 2], [3, 4]]
narr_2 = NArray[[:a, :b], [:c, :d]]
narr_1.each_with(narr_2) { |el_1, el_2| print el_1, el_2 }
print "\n"
# Output: 1a2b3c4d
# When an argument that is not a MultiIndexable is passed,
# #each_with behaves like Object#tap, passing the value into the block.
narr_1.each_with(narr_2, "some other value I want in the block") do |*els|
puts els
end
# Output:
# {1, :a, "some other value I want in the block"}
# {2, :b, "some other value I want in the block"}
# {3, :c, "some other value I want in the block"}
# {4, :d, "some other value I want in the block"}
narr_3 = NArray[[1, 2]] # This has a different shape than narr_1!
narr_1.each_with(narr_3) {} # ShapeError
Returns an iterator that will yield tuples of the elements and coords comprising self in lexicographic (row-major) order.
narr = NArray[[1, 2, 3], [4, 5, 6]]
iter = narr.each_with_coord
iter.next # => {1, [0, 0]}
iter.next # => {2, [0, 1]}
iter.next # => {3, [0, 2]}
iter.next # => {4, [1, 0]}
iter.next # => {5, [1, 1]}
iter.next # => {6, [1, 2]}
iter.next # => Iterator::Stop
This method is a convenience included to mirror Indexable#each_with_index.
If you're looking for a colexicographic version, use #colex_each.with_coord.
Returns true if and only if this MultiIndexable spans no elements.
NArray.new([1, 2, 3]).empty? # => false
NArray.new([]).empty? # => true
TODO rename to elem_eq Produces an NArray(Bool) (by default) describing which elements of self and other are equal.
Returns true if the block returns true for each pair of elements (that share a coordinate) from self and other.
narr_1 = NArray[[1, 2], [3, 4]]
narr_2 = NArray[[2, 3], [4, 5]]
narr_1.equals?(narr_1.clone) { |a, b| a == b } # => true
narr_1.equals?(narr_2) { |a, b| a == b } # => false
# The block doesn't neccessarily have to involve equality,
# just any pairwise comparison you want to evaluate globally.
narr_1.equals?(narr_2) { |a, b| a < b } # => true
Returns an Iterator over the elements in this MultiIndexable that will iterate in the fastest order possible.
For most implementations, it is very likely that #each will be just as fast.
However, certain implementations of MultiIndexable may have substantial
performance differences. As a rule of thumb, this method is only worth using
if the MultiIndexable you call it on explicitly mentions that you should.
NArray[1, 2, 3].fast_each.each do |el|
# ...
end
Returns the element at the zero coordinate (position 0 along every axis).
For example:
# create the following matrix:
# [5 2]
# [8 3]
narr = NArray.new([[5, 2], [8, 3]])
# extract the top-left element (coordinate [0, 0])
narr.first # => 5
Returns a MultiIndexable containing elements whose coordinates belong both to #shape and region_literal.
This method is very similar to #get_chunk(region_literal : Indexable, drop : Bool),
except that it trims the region_literal down to a valid size automatically.
narr = NArray.new([[1, 2, 3], [4, 5, 6]])
narr.get_chunk(1..5, 1) # => ShapeError (this chunk is not contained in a 2x3 MultiIndexable
narr.get_available(1..5, 1) # => NArray[5]
IndexRegion accepting overload of #get_available(region : Indexable, drop : Bool)
Tuple-accepting overload of #get_available(region_literal : Indexable, drop : Bool).
TEST Extracts a chunk given a shape (region_shape) and the coord in that region with the smallest value in each axis.
narr = NArray.new([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
narr.get_chunk([1, 1], [2, 2]) # => NArray[[5, 6], [8, 9]]
narr.get_chunk([1, 0], [1, 3]) # => NArray[[4, 5, 6]]
narr.get_chunk([1, 0], [10, 10]) # => ShapeError
narr.get_chunk([0], [1]) # => DimensionError
A more verbose overload of #[](region_literal : Indexable, drop : Bool).
This is just syntactic sugar, and can be more readable in certain
applications.
IndexRegion accepting form of #get_chunk(region_literal : Indexable, drop : Bool).
Note that region is what controls the dimension dropping behaviour, here.
Tuple-accepting overload of #get_chunk(region_literal : Indexable, drop : Bool).
Retrieves the element specified by coord, throwing an error if coord is out-of-bounds for self.
narr = NArray[['a', 'b'], ['c', 'd']]
narr.get_element([0, 1]) # => 'b'
narr.get_element([1, 0]) # => 'c'
narr.get_element([0]) # => DimensionError
narr.get_element([0, 10]) # => IndexError
Returns true if coord is a valid coordinate in this MultiIndexable.
Any coordinate for which #has_coord? returns true can be used in
#get. A coordinate for which #has_coord? returns false is out of
bounds.
# creates the following matrix:
# [1 2 3]
# [4 5 6]
narr = NArray.build([2, 3]) { |_, idx| idx + 1 }
narr.has_coord?([0, 0]) # => true
narr.get([0, 0]) # => 1
narr.has_coord?([-2, 1]) # => true
narr.get(-2, 1) # => 2
narr.has_coord?([-2]) # => true
narr.get(-2) # => DimensionError
Returns true if all the coordinates spanned by region_literal are valid coordiantes in this MultiIndexable.
In a more geometric sense, an IndexRegion can be considered as a lattice
of points (coordinates), and #shape can be considered as a bounding box
for those coordinates. If every coordinate within region (each point
on that lattice) is inside of the bounding box, then #has_region will
return true.
narr = NArray.build([10, 3]) { |_, idx| idx }
# First, we'll make an IndexRegion that fits in the above. This IndexRegion
# contains all coordinates with a row equal to 2, 3, or 4, and a column
# equal to 0, 1, or 2.
valid = [2..4, 0...3]
# narr has 10 rows and 3 columns, so that region is definitely
# contained in it.
narr.has_region?(valid) # => true
# now, we can use that IndexRegion safely.
LexIterator(Int32).new(valid).each do |coord|
narr.unsafe_fetch_element(coord) # this is definitely defined!
end
# Now we'll create an IndexRegion that's way too big for narr:
invalid = [100, 2..8]
narr.has_region?(invalid) # => false
# The region doesn't fit - so:
narr.get_chunk(invalid) # => raises an IndexError
IndexRegion accepting form of #has_region?(region_literal)
Tuple-accepting overload of #has_region?(region_literal : Indexable, drop : Bool).
Returns the element with the largest ordinate in each axis (the element at the largest coordinate). For example:
# create the following matrix:
# [5 2]
# [8 3]
narr = NArray.new([[5, 2, 1], [8, 3, 4]])
# extract the bottom-right element (coordinate [1, 2])
narr.last # => 4
Returns a MultiIndexable with the results of running the block against each element of self.
narr = NArray[[1, 2, 3], [4, 5, 6]]
res = narr.map { |el| el.to_s } # => NArray[["1", "2", "3"], ["4", "5", "6"]]
Iterates over tuples of elements from self and args, and creating a MultiIndexable containing the output of the block to which those tuples are provided.
Returns a MultiIndexable with the results of running the block against each element and coordinate comprising self.
narr = NArray[[1, 2, 3], [4, 5, 6]]
narr.map_with_coord do |el, coord|
el + coord.sum
end # => NArray[[1, 3, 5], [5, 7, 9]]
Returns a collection of n elements picked at random from this MultiIndexable. This method works by randomly generating coordinates and returning the elements at those coordinates. There is no guarantee that the coordinates generated will be distinct from one another.
NArray.new([[1, 2], [3, 4]]).sample(5) # => Enumerable(Int32)
NArray.new([[1, 2], [3, 4]]).sample(5).to_a # => [4, 2, 4, 3, 2]
NArray.new([[1, 2], [3, 4]]).sample(5).to_a # => [1, 3, 2, 4, 1]
NArray.new([[1, 2], [3, 4]]).sample(5).to_a # => [2, 3, 1, 1, 3]
Returns an element picked at random from this MultiIndexable.
NArray.new([[1, 2], [3, 4]]).sample # => 3
NArray.new([[1, 2], [3, 4]]).sample # => 1
NArray.new([[1, 2], [3, 4]]).sample # => 2
Returns true if this MultiIndexable contains only a single element.
NArray.new([1]).scalar? # => true
NArray.new([1, 2]).scalar? # => false
NArray.new([[1]]).scalar? # => true
NArray.new([]).scalar? # => false
Returns the capacity of each axis spanned by self.
For example, a matrix with 4 rows and 2 columns will have the shape
[4, 2]. This must always return a clone of the actual shape, and is
safe to mutate without affecting the MultiIndexable.
Returns the total number of elements in this MultiIndexable.
This quantity is always equal to shape.product. However, this method is
almost always more performant than computing the product directly.
NArray.new(['a', 'b', 'c']).size # => 3
NArray.new([[0, 1], [1, 0]]).size # => 4
Returns an Indexable collection of the slices returned by #each_slice.
counts specifies how many times to copy the tile in each axis. If it is the wrong
size, #tile will return a DimensionError.
unit = NArray[[1, 2], [3, 4]]
puts unit.tile([2, 3])
# 4x6 Phase::NArray(Int32)
# [[1, 2, 1, 2, 1, 2],
# [3, 4, 3, 4, 3, 4],
# [1, 2, 1, 2, 1, 2],
# [3, 4, 3, 4, 3, 4]]
Tuple-accepting overload of #tile(counts : Enumerable).
unit = NArray[[1, 2], [3, 4]]
puts unit.tile(2, 3)
# 4x6 Phase::NArray(Int32)
# [[1, 2, 1, 2, 1, 2],
# [3, 4, 3, 4, 3, 4],
# [1, 2, 1, 2, 1, 2],
# [3, 4, 3, 4, 3, 4]]
TEST
Returns to_scalar.to_f.
This method allows single-element MultiIndexables to be treated like
numerics in many cases.
NArray.new([[0.5f32]]).to_f # => 0.5
NArray.new([[1], [2]]).to_f # raises ShapeError
NArray.new(["test"]).to_f # will not compile, as String has no #to_f method.
Creates an NArray duplicate of this MultiIndexable.
# not_an_narray : MultiIndexable
narr = not_an_narray.to_narr # => NArray
not_an_narray.equals?(narr) { |el_1, el_2| el_1 == el_2 } # => true
FIXME NArrayFormatter depends on buffer indices.
FIXME NArrayFormatter depends on buffer indices.
If this MultiIndexable is a scalar (see #scalar?), #to_scalar will
return the sole element that it contains. This method will raise a
ShapeError if self.scalar? returns false.
NArray.new(['a']).to_scalar # => 'a'
NArray.new([['a', 'b'], ['c', 'd']]).to_scalar # raises ShapeError
Identical to #to_scalar, but returns nil in case of an error.
NArray.new(['a']).to_scalar # => 'a'
NArray.new([['a', 'b'], ['c', 'd']]).to_scalar # => nil
Copies the elements described by region into a new MultiIndexable without performing any bounds checking.
Unless you are sure that your region will fit inside of this
MultiIndexable, you should opt to use #get_chunk instead.
This method may return any MultiIndexable - the default implementation
will return an NArray, however implementers of other MultiIndexables
are encouraged to override this method where it makes sense to do so.
This method's usage is identical to #get_chunk(region : IndexRegion),
but it is slightly faster.
Returns the element at the provided coord, possibly mutating coord, without performing canonicalization or bounds-checking. This method cannot be used with negative coordinates, and is not safe unless you are certain your coordinate is already canonicalized.