-
Notifications
You must be signed in to change notification settings - Fork 5
MDArray Creation
MDArrays can be of the following types:
- boolean, byte, short, int, long, float, double, string, structure.
To create a new MDArray one needs to inform at least the type and shape of the array. It is also possible to pass to the array factory initialization data, but this is not required. When no initialization data is provided, the array is initialized with 0. For instance, to create a byte array of shape [2, 2, 3] and all values equal to 0 (zero). No initialization data is given:
> require `mdarray`
> @a = MDArray.byte([2, 2, 3])
We can now check some basic informatin about array a:
Shape of the array:
> puts @a.shape
[2, 2, 3]
Number of dimensions:
> puts @a.ndim
3
Size of the array, the number of elements in it:
> puts @a.size
12
The type of the array:
> puts @a.dtype
"byte"
Accessing elements of an array is done by using [] to index the element.
> puts @a[0, 0, 0]
0
> puts @a[1, 1, 2]
0
Unlike Ruby arrays, an MDArray has a uniform and fixed type, so trying to add values from a different type in an MDArray will raise an exception. In this case a RuntimeError.
> a[0, 0, 0] = true
RuntimeError
Writing a double value on byte array will cast double to byte:
> a[0, 0, 0] = 10.25
> puts a[0, 0, 0]
10
> a[0, 0, 0] = 200
> puts a[0, 0, 0]
-56
Now, lets build a "short" array. Both MDArray.build("short", <dimension>) or MDArray.short(<dimension>) can be used:
> short = MDArray.build("short", [2, 2, 3])
All other types can be build the same way:
> int = MDArray.int([5,5,5,5])
Now lets create a float array with some initialization data:
> float = MDArray.float([2, 3], [0, 1, 2, 3, 4, 5, 6])
Note that the data is shaped according to the given shape, so, in this case the array is:
[[0.0 1.0 2.0]
[3.0 4.0 5.0]]
Note also that although the initialization data is in "int" format, the resulting array is of type float
> puts float.dtype
"float"
> puts float[0, 1]
1.0
An array can be create with method arange. Method arange generates all values in the given range. If only one argument is given to arange, then all values up to the given value minus 1 are generated. for instance arange(15) will generate: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
> d = MDArray.arange(15)
The following method should return true.
def compare
counter = 0
d.each do |elmt|
if (counter != elmt)
false
end
counter += 1
end
true
end
With 2 arguments we have the begining and ending values for arange
e = MDArray.arange(5, 15) # e = [5 6 7 8 9 10 11 12 13 14]
With 3 arguments we have the begining, ending and step arguments
f = MDArray.arange(10, 30, 5) # f = [10 15 20 25]
Method typed_arange does the same as arange but for arrays of other type
g = MDArray.typed_arange("double", 10, 30)
h = MDArray.typed_arange("double", 10, 30, 2.5) # h = [10.0 12.5 15.0 17.5 20.0 22.5 25.0 27.5]
MDArrays can be creat from method fromfunction. We use method name "fromfunction" to be consistent with numpy although we do not pass a function but rather a block in Ruby. The block is called with N parameters, where N is the rank of shape. Each parameter represents the coordinates of the array varying along a specific axis. For example, if shape were [2, 2], then the parameters in turn be (0, 0), (0, 1), (1, 0), (1, 1).
# arr = [0, 1, 2, 3, 4]
arr = MDArray.fromfunction("double", [5]) do |x|
x
end
# Parameters passed will be (0, 0), (0, 1), (0, 2)... (0, 4), (1, 0), (1, 1), (1, 2)... (4, 4)
arr = MDArray.fromfunction("double", [5, 5]) do |x, y|
x + y
end
# Anything can be inside the block
arr = MDArray.fromfunction("double", [2, 3, 4]) do |x, y, z|
3.21 * x + y + z
end
Up to 7 dimensions, we need to receive parameters independently for efficiency reasons. After 7 dimensions, fromfunction receives an array.
arr = MDArray.fromfunction("double", [5, 5, 5, 5, 5, 5, 5]) do |x, y, z, k, w, i, l|
x + y + z + k + w + i + l
end
MDArrays with dimension larger than 7, the data is treated as an array, and we cannot use the same notation as before.
arr = MDArray.fromfunction("double", [5, 5, 5, 5, 5, 5, 5, 5]) do |x|
x.inject(:+)
end
A similar notation as the array notation above can be used for lower dimensions using ruby operator '*'. This is a little less efficient though.
arr = MDArray.fromfunction("double", [5, 5, 5, 5, 5]) do |*x|
x.inject(:+)
end
#-------------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------------
should "create array from linspace" do
arr = MDArray.linspace("double", 0, 2, 9)
assert_equal(0.0, arr[0])
assert_equal(0.5, arr[2])
assert_equal(1.0, arr[4])
assert_equal(1.5, arr[6])
assert_equal(2.0, arr[8])
end
#-------------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------------
should "create array with ones" do
# creates an array with all 1's
ones = MDArray.ones("byte", [2, 2, 2, 2])
assert_equal(1, ones[1, 1, 1, 1])
assert_equal(1, ones[1, 0, 1, 0])
end
#-------------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------------
should "create array with given value" do
# creates an array with a given value and type
fives = MDArray.init_with("double", [3, 3], 5.34)
assert_equal(5.34, fives[2, 1])
assert_equal(5.34, fives[0, 2])
end
#-------------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------------
should "allow filling the array with data" do
# fill b with a given value
b = MDArray.double([2, 3], [0, 1, 2, 3, 4, 5])
b.fill(5.47)
b.each do |elmt|
assert_equal(5.47, elmt)
end
# typed_arange does the same as arange but for arrays of other type
g = MDArray.typed_arange("double", 6)
g.reshape!([2, 3])
b.fill(g)
assert_equal(b.to_string, g.to_string)
end
#-------------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------------
should "create boolean arrays" do
bool = MDArray.boolean([2, 2])
bool[0, 0] = true
assert_raise ( RuntimeError ) { bool[0, 1] = 10.0 }
assert_equal(bool[0, 0], true)
bool[0, 1] = false
assert_equal(bool[0, 1], false)
end
#-------------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------------
should "create string arrays" do
sarray = MDArray.string([2, 3], ["hello", "this", "is", "a", "string", "array"])
assert_equal(6, sarray.size)
assert_equal("hello", sarray.get([0, 0]))
assert_equal("hello this is a string array ", sarray.to_string)
end
#-------------------------------------------------------------------------------------
# A struct array is an array of pointers to structures
#-------------------------------------------------------------------------------------
should "create struct arrays" do
m = Hash.new
m[:hello] = "world"
m[:test] = 1.23
struct = MDArray.structure([10])
struct[0] = m
struct.print
end