# How to create an NMatrix

## OBSERVATION

This tutorial was written for an older version of NMatrix. While most of it still works fine, remember to read the documentation or consult the mailing list if any problem happens.

We should really think merge this document with the Tentative NMatrix Tutorial!

Let's start with the simplest thing possible: to create a NMatrix from an array of values, without any options:

``````>> m = N[ [2, 3, 4], [7, 8, 9] ]
=> #<NMatrix:0x007f8e121b6cf8shape:[2,3] dtype:int32 stype:dense>
[2, 3, 4]
[7, 8, 9]
=> nil
``````

## The type of a matrix's elements

Each `NMatrix` object has what's called a `dtype`. It's a `Symbol` that says what each element of the matrix is: if it's an integer, a floating-point, a complex or a rational number and the number of bits used to store it. These are defined in ext/nmatrix/nmatrix.h. Below is the complete list.

• `:byte` (unsigned 8bit integer)
• `:int8` (signed 8bit integer, a char)
• `:int16`
• `:int32`
• `:int64`
• `:float32`
• `:float64`
• `:complex64`
• `:complex128`
• `:rational32` # likely to be removed soon
• `:rational64` # likely to be removed soon
• `:rational128`
• `:object` (a ruby object, simply a VALUE)

They're very valuable when you know the kind of data you're going to use beforehand. If you're simply doing some experiments and have no idea what you're going to encounter, stick to the defaults - it's probably int64 or float64.

To create a matrix with a specific `dtype`, you can use `#new` or one of the various shortcuts that I've already talked about. Some examples:

``````>> NMatrix.new([2, 3], [0, 1, 2, 3, 4, 5], dtype: :int64)
[0, 1, 2]
[3, 4, 5]
=> nil
``````

Here the first parameter is an array representing the dimension of the matrix (2-by-3 in this case), the second parameter are the values used and the third one is the `dtype`. If you're creating a square matrix, you can simply pass an integer as the first parameter.

If there are less values than the number of element in the matrix, they will be repeated as much as necessary.

``````>> NMatrix.new([2, 3], [1, 7])
[1, 7, 1]
[7, 1, 7]
=> nil
``````

For complex and rational matrices, you must use Ruby's `Complex` and `Rational` classes.

``````>> values = []
>> 6.times { |i| values << Rational(i, 7) }
>> values
=> [(0/1), (1/7), (2/7), (3/7), (4/7), (5/7)]

>> NMatrix.new([2, 3], values, :rational128)
[(0/1), (1/7), (2/7)]
[(3/7), (4/7), (5/7)]
=> nil

>> values = []
>> 6.times { |i| values << Complex(i, 2*i) }
>> values
=> [(0+0i), (1+2i), (2+4i), (3+6i), (4+8i), (5+10i)]

>> NMatrix.new([2, 3], values, :complex64)
[(0.0+0.0i), (1.0+2.0i), (2.0+4.0i)]
[(3.0+6.0i), (4.0+8.0i), (5.0+10.0i)]
=> nil
``````

If you don't specify a `dtype`, `NMatrix` will try to guess based on the first entry in the array you give it.

``````>> q = []
>> 4.times {|i| q << Rational(2, i+1)}
>> q
=> [(2/1), (1/1), (2/3), (1/2)]

>> NMatrix.new(2, q).dtype
=> :rational64
``````

And that's it for `dtypes`. As I said, most of the time we're dealing with integers and floating-point numbers, but it's very good to have this kind of machinery for the times when we need it - complex for lots of tasks in signal processing, rationals for number fields (e.g. [Q-lattices in quantum statistical mechanics][2]), uint8 for logical matrices (incidence matrices in graph theory), etc.

## The storage of a matrix

The `stype` is a much less used parameter of NMatrix. It controls how the data of the matrix is stored on memory. It's defined as an `enum` in ext/nmatrix/nmatrix.h.

There are only 3 options:

• `:dense`
• `:list`
• `:yale`

The first one is what you should use most of the time. It is the standard when creating a new matrix with `#new` or the shortcuts.

Yale is a standard format for sparse matrices. There are two versions of it: old Yale and new Yale, the difference being that the diagonal values are stored separately in the latter. There's a lot of information about it on Wikipedia.

NMatrix uses new Yale, which is defined in ext/nmatrix/storage/yale/. In general, it costs O(1) to look up a row in a Yale matrix, and O(log(n)) to look up an entry within a row (if there are n entries in the row). Inserting or removing values from the matrix causes a resize of the underlying storage, so modifying Yale matrices is expensive. They also lack the generalizability to exist in more (or less) than two dimensions.

Tall Yale matrices have less efficient storage but more efficient access; short Yale matrices have more efficient storage but less efficient access.

To avoid modifying Yale matrices, it's recommended that you use `:list`. List matrices store data in linked-lists, and may exist in any number of dimensions. They are defined in ext/nmatrix/storage/list.cpp.

There's also an experimental module called `NMatrix::YaleFunctions` with a lot of methods for reflection of Yale matrices: `#yale_ija`, `#yale_ia`, `#yale_ja`, `#yale_d`, `#yale_lu`, `#yale_a`, etc. These functions do not work on slices, but they're useful for debugging and understanding the space usage. You can add them to an NMatrix using `n.extend NMatrix::YaleFunctions`.

## Conclusion

Understanding data and storage types makes it really simple to create new matrices:

``````NMatrix.new(shape, [initial_values, dtype: d, stype: s, capacity: c, default: d])
``````

Only `shape` is required. `capacity` is useful if you want to pre-reserve space for a Yale matrix. The `default` keyword is there for sparse matrices, which prefer to not store zeros (but may alternatively store zeros instead of some other value, which is `d`).

Instead of providing an array for `initial_values`, you may provide a single value. If you go that route, that single value will be used as the `default` for Yale and List.

I hope this is all the information necessary for the most common use cases. If you have a suggestion, please post on SciRuby's mailing list.

##### Clone this wiki locally
You can’t perform that action at this time.
Press h to open a hovercard with more details.