Creating a new NMatrix

As I’ve been working with NMatrix documentation lately, I thought that a good explanation of how to create a new NMatrix object and all the options would be useful.

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

When I started playing with this project, I had problems myself about poor documentation: how the hell do I use it? My first doubt was about stypes and dtypes. I’ll explain what they are and show examples of some patterns to create new matrices along the way.

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
  • :rational64
  • :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:

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.

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

If you don’t specify a dtype, NMatrix will try to guess (and it’ll probably be right).

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), 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 uses row-major order and is the standard when creating a new matrix with #new or the shortcuts.

List matrices are used for sparse storage, but they’re generally only used when converting between stypes. It’s not very useful from an user’s point of view, so you should stick with dense or yale. Defined in ext/nmatrix/storage/list.cpp.

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/list.h.

There’s a 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.

Conclusion

Understanding dtypes and stypes makes it really simple to create new matrices:

  • stype defines the storage used for the data.
  • dimension can be an integer for square matrices or an array of arbitrary size.
  • values is the initial value. If it’s an integer, it’ll be repeated for the size of the matrix. If it’s an array and there are less elements than in the matrix, they’ll be repeated as much as necessary, and if there are more elements, some will be ignored.
  • dtype is used to force how the data is to be stored. If it isn’t given, a guess will be made using values.

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

I’ll update this post as possible.

Leave a Reply