Skip to content
Rodrigo Botafogo edited this page May 1, 2013 · 17 revisions

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

Method linspace returns evenly spaced numbers over a specified interval.

arr = MDArray.linspace("double", 0, 2, 9) # [0.0, 0.5, 1.0, 1.5, 2.0]

Initializes an array with ones:

ones = MDArray.ones("byte", [2, 2, 2, 2])

Initializes an array with the given value. In this case, all elements of MDArray are equal to 5.34:

arr = MDArray.init_with("double", [3, 3], 5.34)

Fill an existing array with the given value. In the example bellow, array b that was already created will have all values equal to 5.47.

b = MDArray.double([2, 3], [0, 1, 2, 3, 4, 5])
b.fill(5.47)

An array can be reshaped with method reshape!. Method fill can also be used to fill an array with data from another array. Both arrays need to be of the same shape.

g = MDArray.typed_arange("double", 6)
g.reshape!([2, 3])
b.fill(g)

Crates a boolean array:

bool = MDArray.boolean([2, 2])
bool[0, 0] = true
bool[0, 1] = false

createS string arrays:

sarray = MDArray.string([2, 3], ["hello", "this", "is", "a", "string", "array"])

createS struct arrays:

m = Hash.new
m[:hello] = "world"
m[:test] = 1.23

struct = MDArray.structure([10])
struct[0] = m
struct.print
Clone this wiki locally