**Warning:** Code in this blog post is very old and likely will not work with the current version of NMatrix. Please check the NMatrix wiki for the most recent information.

Two months ago, I mentioned the existence of a prototype Ruby linear algebra library, written in C.

I am pleased to announce that yesterday we released our first alpha of said library, NMatrix v0.0.1.

## Creating Matrices

There are lots of different ways to create matrices. The first and easiest is to supply dimensions and initial data:

```
>> n = NMatrix.new(4, 0) # a square 4x4 dense zero matrix
=> #<NMatrix:0x9a57e14shape:[4,4] dtype:int32 stype:dense>
>> n.pretty_print
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
=> nil
```

## Data Types

You may notice that this first matrix defaulted to `dtype=:int32`. NMatrix will try to guess the *dtype* based on the
first initial value you provide (e.g., `NMatrix.new(4, [0.0, 1])` will be :float32), but you can choose to provide
a *dtype* in addition to or in lieu of initial values:

```
>> n = NMatrix.new(4, [0,1], :rational128)
=> #<NMatrix:0x9959e04shape:[4,4] dtype:rational128 stype:dense>
>> n.pretty_print
0/1 1/1 0/1 1/1
0/1 1/1 0/1 1/1
0/1 1/1 0/1 1/1
0/1 1/1 0/1 1/1
>> m = NMatrix.new(4, :int64) # no initialization of values
=> #<NMatrix:0x99fad68shape:[4,4] dtype:int64 stype:dense>
>> m.pretty_print
-1217641248 161386160 161386100 161385680
161385640 161385520 161385420 161384180
161384120 161381060 161381020 161412140
161411940 161411880 161411840 160879240
=> nil
```

## Storage Formats

The storage type (*stype*) can also be specified, prior to the dimension argument. However, with sparse storage formats, initial values don’t make sense, and these matrices will contain zeros by default.

```
# empty list-of-lists-of-lists 4x3x4 matrix
n = NMatrix.new(:list, [4,3,4], :int64)
# Ruby objects in a 'Yale' sparse matrix
m = NMatrix.new(:yale, [5,4], :object)
# A byte matrix containing a gradient
o = NMatrix.new(:dense, 5, [0,1,2,3,4], :byte)
```

The matrix `m` created above is a Yale-format sparse matrix, or more specifically, “new Yale,” which differs from “old Yale” in that the diagonal is stored separately from the non-diagonal elements. Thus, diagonals can be accessed and set in constant time.

Currently, all storage is row-based.

### Conversion

You can also convert between any of these three stypes using `cast`, e.g.,

```
n = NMatrix.new(:list, 4, :int64)
n[0,0] = 5
n[0,3] = -2
dense = n.cast(:dense, :int64)
```

## Vectors

Currently, only dense vectors are implemented as a child class of `NMatrix`, and creation is similar:

```
>> nv = NVector.new(5, :int64)
=> #<NVector:0x9a62328shape:[5,1] dtype:int64 stype:dense orientation:column>
```

## Math Operations

Most element-wise mathematical operations are supported for Yale and dense types. These use the basic operators (e.g., +, -, /, *, ==).

For non-element-wise matrix multiplication, use the `dot` instance method of NMatrix. Whole-matrix comparison (returning a single boolean value) is the `equal?` or `eql?` method.

## Road Map

Much more remains to be written than has been completed. Here are some of our key priorities:

- determinants
- matrix-vector multiplication for Yale
- adaptation of SciRuby Matlab file reader to support NMatrix
- in-place transposition

If you want to get involved, I suggest visiting the NMatrix issue tracker. It will contain not only bugs, but also features that need to be implemented.

## Conclusion

We’re all pretty excited about NMatrix. But we couldn’t have gotten this far without Masahiro Tanaka’s NArray, which has served as a model for our library.

And we can’t do it without your help. A numerical library in Ruby is no small endeavour, and probably requires at least one full-time programmer (which we do not have). Please consider contributing, even if it’s just by letting us know what you think.

Happy coding!