class Phase::NArray(T)

Overview

An {{@type}} is a multidimensional array for any arbitrary type. It is the most general implementation of Abstract{{@type}}, and as a result only implements primitive data operations (construction, data reading, data writing, and region sampling / slicing).

Included Modules

Defined in:

n_array.cr

Constructors

Class Method Summary

Instance Method Summary

Instance methods inherited from module Phase::Buffered(T)

buffer : Indexable buffer, coord_to_index(coord) : Int coord_to_index, index_to_coord(index) : Array index_to_coord

Class methods inherited from module Phase::Buffered(T)

axis_strides(shape) axis_strides, coord_to_index(coord, shape) : Int coord_to_index, coord_to_index_fast(coord, shape, axis_strides) : Int coord_to_index_fast, index_to_coord(index, shape) : Array index_to_coord

Instance methods inherited from module Phase::MultiIndexable(T)

%(other : MultiIndexable(U)) forall U
%(other)
%
, &(other : MultiIndexable(U)) forall U
&(other)
&
, &*(other : MultiIndexable(U)) forall U
&*(other)
&*
, &**(other : MultiIndexable(U)) forall U
&**(other)
&**
, &+(other : MultiIndexable(U)) forall U
&+(other)
&+
, &-(other : MultiIndexable(U)) forall U
&-(other)
&-
, *(other : MultiIndexable(U)) forall U
*(other)
*
, **(other : MultiIndexable(U)) forall U
**(other)
**
, +(other : MultiIndexable(U)) forall U
+(other)
+
+
, -(other : MultiIndexable(U)) forall U
-(other)
-
-
, /(other : MultiIndexable(U)) forall U
/(other)
/
, //(other : MultiIndexable(U)) forall U
//(other)
//
, <(other : MultiIndexable(U)) forall U
<(other)
<
, <=(other : MultiIndexable(U)) forall U
<=(other)
<=
, <=>(other : MultiIndexable(U)) forall U
<=>(other)
<=>
, ==(other : self) : Bool ==, =~(value) : MultiIndexable(Bool) =~, >(other : MultiIndexable(U)) forall U
>(other)
>
, >=(other : MultiIndexable(U)) forall U
>=(other)
>=
, [](region_literal : Indexable, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
[](region : IndexRegion)
[](*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
[]
, []?(bool_mask : MultiIndexable(Bool)) : MultiIndexable(T | Nil)
[]?(region : Indexable, drop : Bool = MultiIndexable::DROP_BY_DEFAULT) : MultiIndexable(T) | Nil
[]?(region : IndexRegion) : MultiIndexable(T) | Nil
[]?(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
[]?
, ^(other : MultiIndexable(U)) forall U
^(other)
^
, |(other : MultiIndexable(U)) forall U
|(other)
|
, ~ ~, apply : ApplyProxy apply, apply! : InPlaceApplyProxy apply!, colex_each : ElemIterator
colex_each(&) : Nil
colex_each
, colex_each_coord : ColexIterator
colex_each_coord(&) : Nil
colex_each_coord
, dimensions : Int dimensions, each : ElemIterator
each(&) : Nil
each
, each_coord : LexIterator
each_coord(&) : Nil
each_coord
, each_slice(axis = 0) : Iterator
each_slice(axis = 0, &)
each_slice
, each_with(*args, &) each_with, each_with_coord : ElemAndCoordIterator
each_with_coord(&) : Nil
each_with_coord
, empty? : Bool empty?, ensure_writable ensure_writable, eq(other : MultiIndexable(U)) : MultiIndexable(Bool) forall U
eq(value) : MultiIndexable(Bool)
eq
, equals?(other : MultiIndexable, &) : Bool equals?, fast_each : Iterator(T)
fast_each(&) : Nil
fast_each
, first : T first, get(coord : Indexable) : T
get(*coord : Int)
get
, get_available(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT)
get_available(region : IndexRegion, drop : Bool = DROP_BY_DEFAULT)
get_available(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
get_available
, get_chunk(coord : Indexable, region_shape : Indexable(I)) forall I
get_chunk(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT)
get_chunk(region : IndexRegion) : MultiIndexable(T)
get_chunk(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
get_chunk
, get_element(coord : Indexable) : T
get_element(*coord : Int)
get_element
, has_coord?(coord : Indexable) : Bool
has_coord?(*coord : Int)
has_coord?
, has_region?(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT) : Bool
has_region?(region : IndexRegion) : Bool
has_region?(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
has_region?
, hash(hasher) hash, last : T last, map(&block : T -> R) : MultiIndexable(R) forall R map, map!(&block : T -> T | MultiIndexable(T)) : MultiIndexable(T) map!, map_with(*args : *U, &) forall U
map_with(*args, &)
map_with
, map_with!(*args : *U, &) forall U map_with!, map_with_coord(&) map_with_coord, map_with_coord!(&block : T -> MultiIndexable(T)) map_with_coord!, permute(*args) : MultiIndexable(T) permute, process(&block : T -> R) : ProcView(self, T, R) forall R
process(proc : Proc(T, R)) : ProcView(self, T, R) forall R
process
, reshape(*args) : MultiIndexable(T) reshape, reverse(*args) : MultiIndexable(T) reverse, sample(n : Int, random = Random::DEFAULT) : Enumerable(T)
sample(random = Random::DEFAULT) : T
sample
, scalar? : Bool scalar?, shape : Array shape, size size, slices(axis = 0) : Indexable slices, tile(counts : Enumerable(Int)) : MultiIndexable
tile(*counts : Int)
tile
, to_f : Float to_f, to_literal_s(io : IO) : Nil to_literal_s, to_narr : NArray(T) to_narr, to_s(io : IO, settings = Formatter::Settings.new) : Nil
to_s(settings = Formatter::Settings.new) : String
to_s
, to_scalar : T to_scalar, to_scalar? : T | Nil to_scalar?, unsafe_fetch_chunk(region : IndexRegion) : MultiIndexable(T) unsafe_fetch_chunk, unsafe_fetch_element(coord : Indexable) : T unsafe_fetch_element, view(region : Indexable | Nil | IndexRegion = nil) : View(self, T)
view(*region) : View(self, T)
view

Class methods inherited from module Phase::MultiIndexable(T)

each_with(*args : *U, &) forall U each_with

Macros inherited from module Phase::MultiIndexable(T)

coord_splat_overload(name) coord_splat_overload, def_elementwise_binary(name) def_elementwise_binary, def_elementwise_unary(name) def_elementwise_unary, region_splat_overload(name) region_splat_overload

Instance methods inherited from module Phase::MultiWritable(T)

[]=(region : Indexable | IndexRegion, value)
[]=(bool_mask : MultiIndexable(Bool), value)
[]=(*args)
[]=
, set_available(region : Indexable, value : T) set_available, set_chunk(region_literal : Indexable, src : MultiIndexable(T))
set_chunk(region : Indexable | IndexRegion, value : T)
set_chunk
, set_element(coord : Indexable, value : T) set_element, set_mask(bool_mask, src : MultiIndexable(T))
set_mask(bool_mask, value)
set_mask(bool_mask : MultiIndexable(Bool), &)
set_mask
, shape : Shape shape, size size, unsafe_set_chunk(region : IndexRegion, src : MultiIndexable(T))
unsafe_set_chunk(region : IndexRegion, value : T)
unsafe_set_chunk
, unsafe_set_element(coord : Coord, value : T) unsafe_set_element

Instance methods inherited from module Phase::MultiIndexable(T)

%(other : MultiIndexable(U)) forall U
%(other)
%
, &(other : MultiIndexable(U)) forall U
&(other)
&
, &*(other : MultiIndexable(U)) forall U
&*(other)
&*
, &**(other : MultiIndexable(U)) forall U
&**(other)
&**
, &+(other : MultiIndexable(U)) forall U
&+(other)
&+
, &-(other : MultiIndexable(U)) forall U
&-(other)
&-
, *(other : MultiIndexable(U)) forall U
*(other)
*
, **(other : MultiIndexable(U)) forall U
**(other)
**
, +(other : MultiIndexable(U)) forall U
+(other)
+
+
, -(other : MultiIndexable(U)) forall U
-(other)
-
-
, /(other : MultiIndexable(U)) forall U
/(other)
/
, //(other : MultiIndexable(U)) forall U
//(other)
//
, <(other : MultiIndexable(U)) forall U
<(other)
<
, <=(other : MultiIndexable(U)) forall U
<=(other)
<=
, <=>(other : MultiIndexable(U)) forall U
<=>(other)
<=>
, ==(other : self) : Bool ==, =~(value) : MultiIndexable(Bool) =~, >(other : MultiIndexable(U)) forall U
>(other)
>
, >=(other : MultiIndexable(U)) forall U
>=(other)
>=
, [](region_literal : Indexable, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
[](region : IndexRegion)
[](*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
[]
, []?(bool_mask : MultiIndexable(Bool)) : MultiIndexable(T | Nil)
[]?(region : Indexable, drop : Bool = MultiIndexable::DROP_BY_DEFAULT) : MultiIndexable(T) | Nil
[]?(region : IndexRegion) : MultiIndexable(T) | Nil
[]?(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
[]?
, ^(other : MultiIndexable(U)) forall U
^(other)
^
, |(other : MultiIndexable(U)) forall U
|(other)
|
, ~ ~, apply : ApplyProxy apply, apply! : InPlaceApplyProxy apply!, colex_each : ElemIterator
colex_each(&) : Nil
colex_each
, colex_each_coord : ColexIterator
colex_each_coord(&) : Nil
colex_each_coord
, dimensions : Int dimensions, each : ElemIterator
each(&) : Nil
each
, each_coord : LexIterator
each_coord(&) : Nil
each_coord
, each_slice(axis = 0) : Iterator
each_slice(axis = 0, &)
each_slice
, each_with(*args, &) each_with, each_with_coord : ElemAndCoordIterator
each_with_coord(&) : Nil
each_with_coord
, empty? : Bool empty?, ensure_writable ensure_writable, eq(other : MultiIndexable(U)) : MultiIndexable(Bool) forall U
eq(value) : MultiIndexable(Bool)
eq
, equals?(other : MultiIndexable, &) : Bool equals?, fast_each : Iterator(T)
fast_each(&) : Nil
fast_each
, first : T first, get(coord : Indexable) : T
get(*coord : Int)
get
, get_available(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT)
get_available(region : IndexRegion, drop : Bool = DROP_BY_DEFAULT)
get_available(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
get_available
, get_chunk(coord : Indexable, region_shape : Indexable(I)) forall I
get_chunk(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT)
get_chunk(region : IndexRegion) : MultiIndexable(T)
get_chunk(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
get_chunk
, get_element(coord : Indexable) : T
get_element(*coord : Int)
get_element
, has_coord?(coord : Indexable) : Bool
has_coord?(*coord : Int)
has_coord?
, has_region?(region_literal : Indexable, drop : Bool = DROP_BY_DEFAULT) : Bool
has_region?(region : IndexRegion) : Bool
has_region?(*region_literal, drop : Bool = MultiIndexable::DROP_BY_DEFAULT)
has_region?
, hash(hasher) hash, last : T last, map(&block : T -> R) : MultiIndexable(R) forall R map, map!(&block : T -> T | MultiIndexable(T)) : MultiIndexable(T) map!, map_with(*args : *U, &) forall U
map_with(*args, &)
map_with
, map_with!(*args : *U, &) forall U map_with!, map_with_coord(&) map_with_coord, map_with_coord!(&block : T -> MultiIndexable(T)) map_with_coord!, permute(*args) : MultiIndexable(T) permute, process(&block : T -> R) : ProcView(self, T, R) forall R
process(proc : Proc(T, R)) : ProcView(self, T, R) forall R
process
, reshape(*args) : MultiIndexable(T) reshape, reverse(*args) : MultiIndexable(T) reverse, sample(n : Int, random = Random::DEFAULT) : Enumerable(T)
sample(random = Random::DEFAULT) : T
sample
, scalar? : Bool scalar?, shape : Array shape, size size, slices(axis = 0) : Indexable slices, tile(counts : Enumerable(Int)) : MultiIndexable
tile(*counts : Int)
tile
, to_f : Float to_f, to_literal_s(io : IO) : Nil to_literal_s, to_narr : NArray(T) to_narr, to_s(io : IO, settings = Formatter::Settings.new) : Nil
to_s(settings = Formatter::Settings.new) : String
to_s
, to_scalar : T to_scalar, to_scalar? : T | Nil to_scalar?, unsafe_fetch_chunk(region : IndexRegion) : MultiIndexable(T) unsafe_fetch_chunk, unsafe_fetch_element(coord : Indexable) : T unsafe_fetch_element, view(region : Indexable | Nil | IndexRegion = nil) : View(self, T)
view(*region) : View(self, T)
view

Class methods inherited from module Phase::MultiIndexable(T)

each_with(*args : *U, &) forall U each_with

Macros inherited from module Phase::MultiIndexable(T)

coord_splat_overload(name) coord_splat_overload, def_elementwise_binary(name) def_elementwise_binary, def_elementwise_unary(name) def_elementwise_unary, region_splat_overload(name) region_splat_overload

Constructor Detail

def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node) #

[View source]
def self.new(data : Enumerable) #

Creates an {{@type}} from a nested array with uniform dimensions. For example:

{{@type}}.new([[1, 0, 0], [0, 1, 0], [0, 0, 1]])

Would create the 3x3 identity matrix of type {{@type}}(Int32).

This constructor will figure out the types of the scalars at the bottom of the nested array at compile time, which allows mixing datatypes effortlessly. For example, to create a matrix with 0.5 on the diagonals:

{{@type}}.new([[0.5, 0, 0], [0, 0.5, 0], [0, 0, 0.5]])

This may seem trivial, but note that the 0.5s are implicit Float32 literals, whereas the 0s are implicit Int32 literals. So, the type returned by that example will actually be an {{@type}}(Float32 | Int32). This also works for more disorganized examples:

{{@type}}.new([["We can mix types", 2, :do], ["C", 0.0, "l stuff."]])

The above line will create an {{@type}}(String | Int32 | Symbol | Float32).

When a nested array with non-uniform dimensions is passed, this method will raise a DimensionError. For example:

{{@type}}.new([[1], [1, 2]]) # => DimensionError

[View source]
def self.new(pull : JSON::PullParser) #

[View source]
def self.wrap(*objects : AbstractNArray(T), pad = false) : NArray #

Adds a dimension at highest level, where each "row" is an input {{@type}}. If pad is false, then throw error if shapes of objects do not match; otherwise, pad subarrays along each axis to match whichever is largest in that axis


[View source]

Class Method Detail

def self.[](*contents) #

NArray[1, 2, 3] == NArray.new([1, 2, 3]) NArray[[1, 2, 3]] == NArray.new([[1, 2, 3]])


[View source]
def self.build(shape : Enumerable, &block : ReadonlyWrapper(Array(Int32), Int32), Int32 -> T) #

Constructs an {{@type}} using a user-provided shape (see shape) and a callback. The provided callback should map a multidimensional index, coord, (and an optional packed index) to the value you wish to store at that position. For example, to create the 2x2 identity matrix:

Phase::{{@type}}.build([2, 2]) do |coord|
  if coord[0] == coord[1]
    1
  else
    0
  end
end

Which will create:

[[1, 0, 0],
  0, 1, 0],
  0, 0, 1]]

The buffer index allows you to easily index elements in lexicographic order. For example:

{{@type}}.build([5, 1]) { |coord, index| index }

Will create:

[[0],
 [1],
 [2],
 [3],
 [4]]

[View source]
def self.build(*shape : Int, &block : ReadonlyWrapper(Array(Int32), Int32), Int32 -> T) #

[View source]
def self.common_container(*objects) #

Given a list of {{@type}}s, returns the smallest shape array in which any one of those {{@type}}s can be contained.

TODO Example


[View source]
def self.compatible?(*narrs : MultiIndexable, axis = -1) : Bool #

Checks that the shape of this and other match in every dimension (except axis, if it is specified)


[View source]
def self.concatenate(*narrs : MultiIndexable(T), axis = 0) : NArray(T) #

[View source]
def self.fill(shape, value : T) #

Fills an {{@type}} of given shape with a specified value. For example, to create a zero vector:

{{@type}}.fill([3, 1], 0)

Will produce

[[0],
 [0],
 [0]]

Note that this method makes no effort to duplicate value, so this should only be used for Structs. If you want to populate an {{@type}} with Objects, see .new(shape, &block).


[View source]
def self.of_buffer(shape : Array(Int32), buffer : Slice(T)) #

[View source]
def self.tile(narr : MultiIndexable(T), counts : Enumerable) #

[View source]
def self.wrap(*objects) #

creates an {{@type}}-type vector from a tuple of scalars.


[View source]

Instance Method Detail

def <<(other : self) : self #

[View source]
def ==(other : NArray) : Bool #

Checks for elementwise equality between self and other.


[View source]
def []=(bool_mask : NArray(Bool), value : T) #

replaces all values in a boolean mask with a given value


[View source]
def buffer : Slice(T) #

Stores the elements of an {{@type}} in lexicographic (row-major) order.


[View source]
def clone : self #

Creates a deep copy of this {{@type}}; Allocates a new buffer of the same shape, and calls #clone on every item in the buffer.


[View source]
def compatible?(*others : MultiIndexable, axis = -1) : Bool #

Checks that the shape of this and other match in every dimension (except axis, if it is specified)


[View source]
def concatenate(*others, axis = 0) : self #

[View source]
def concatenate!(*others, axis = 0) : self #

[View source]
def dup : self #

Creates a shallow copy of this {{@type}}; Allocates a new buffer of the same shape, and duplicates every item in the buffer.


[View source]
def each #

The default "each" with no iterator type passed is lexicographic. For other orders, default to MultiIndexable's implementation.


[View source]
def each_coord #
Description copied from module Phase::MultiIndexable(T)

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

[View source]
def each_with_coord(iter : IndexedStrideIterator(I)) forall I #

[View source]
def each_with_index(&block : T, Int32 -> ) #
Description copied from module Enumerable(T)

Iterates over the collection, yielding both the elements and their index.

["Alice", "Bob"].each_with_index do |user, i|
  puts "User ##{i}: #{user}"
end

Prints:

User # 0: Alice
User # 1: Bob

Accepts an optional offset parameter, which tells it to start counting from there. So, a more human friendly version of the previous snippet would be:

["Alice", "Bob"].each_with_index(1) do |user, i|
  puts "User ##{i}: #{user}"
end

Which would print:

User # 1: Alice
User # 2: Bob

[View source]
def fast_each #
Description copied from module Phase::MultiIndexable(T)

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

[View source]
def fit(new_shape, *, align : Hash(Int32, NArray::Alignment | Int32)) #

This version requires you are only <= on each axis; cannot pad


[View source]
def fit(new_shape, *, align : Hash(Int32, NArray::Alignment | Int32) | Nil = nil, pad_with value = nil) #

[View source]
def fit! #

[View source]
def flatten : self #

[View source]
def map(&block : T -> U) forall U #
Description copied from module Phase::MultiIndexable(T)

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"]]

[View source]
def map!(&block : T -> T) : self #
Description copied from module Phase::MultiIndexable(T)

TODO docs, test


[View source]
def map_with_coord(&block : T, Indexable(Int32), Int32 -> U) forall U #
Description copied from module Phase::MultiIndexable(T)

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]]

[View source]
def map_with_coord!(&block : T, Indexable(Int32), Int32 -> T) : self #
Description copied from module Phase::MultiIndexable(T)

TODO docs DISCUSS is this good behaviour?


[View source]
def map_with_index(&block : T, Int32 -> U) forall U #
Description copied from module Enumerable(T)

Like #map, but the block gets passed both the element and its index.

["Alice", "Bob"].map_with_index { |name, i| "User ##{i}: #{name}" }
# => ["User #0: Alice", "User #1: Bob"]

Accepts an optional offset parameter, which tells it to start counting from there.


[View source]
def map_with_index!(&block : T, Int32 -> T) : self #

[View source]
def pad(value, amounts : Hash(Int32, Tuple(Int32, Int32))) #

core pad(0, {0 => {2, 2}, 1 => {3, 4}, -1 => {0, 5}})


[View source]
def pad! #

[View source]
def push(*others : self, axis = 0) : self #

optimization for pushing other NArrays on axis 0, in-place

TODO axis = 0 should not be a user modifiable parameter and never should have been


[View source]
def reshape(new_shape : Enumerable) #

[View source]
def reshape(*splat) #

[View source]
def size : Int32 #
Description copied from module Phase::MultiIndexable(T)

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

[View source]
def to_json(json : JSON::Builder) #

[View source]
def to_yaml(yaml : YAML::Nodes::Builder) #

[View source]
def unsafe_fetch_chunk(region : IndexRegion) #

Copies the elements in region to a new {{@type}}, assuming that region is in canonical form and in-bounds for this {{@type}}. For full specification of canonical form see IndexRegion documentation.


[View source]
def unsafe_fetch_element(coord) : T #

Retrieves the element specified by coord, assuming that coord is in canonical form and in-bounds for this {{@type}}. For full specification of canonical form see IndexRegion documentation.


[View source]
def unsafe_set_chunk(region : IndexRegion, src : MultiIndexable(T)) #

Copies the elements from a MultiIndexable src into region, assuming that region is in canonical form and in-bounds for this {{type}} and the shape of region matches the shape of src.


[View source]
def unsafe_set_chunk(region : IndexRegion, value : T) #

Sets each element in region to value, assuming that region is in canonical form and in-bounds for this {{type}}


[View source]
def unsafe_set_element(coord : Enumerable, value : T) #

[View source]