Ruby Numerical Library - RNum

by Olaf Trygve Berglihn <olafb@pvv.org>

7. June, 2006

Ruby Numerical Library is a linear algebra package using Blas and Lapack.

See also the project page. As there is rapid development for the moment, I urge people to get the latest version by using git.

I have a working set of most Blas functions for non-packed matrices (i.e. not banded/sparse). Also basic Lapack factorization and backsubstitution is ready. In practice, you gain access to the same functionality what you find in Atlas. But I did not use the clapack stuff due to that most other lapack implementations do not have a c-api (and that was another reason I went with internal Fortran style column-major memory layout). Work is being done to cover the complete Lapack library. There is a ruby class to handle high-level access, so that you can do things like this (borrowed from NArray):

require 'rnum'
n = 500
m = RNum::zeros(n,n).indgen!.rem!(n+1).add!(1).t
x = RNum::zeros(n,n).indgen!.t
printf "solving  y=x/m ...\n",n,n
t1 = Process.times.utime
x.solve!(m)
# or y = x/m
t2 = Process.times.utime
puts "Time: %.4f sec\n\n" % [t2-t1]

Speed

The above code runs about the same speed as Matlab-R2006a or faster on a pentium 2.8 GHz.

Solve
        AX = B, A (nxn), B(nxn)

Ranking after least cpu-time (sec).
Linux 2.6.16.19, Intel(R) Pentium(R) 4 - CPU 2.80GHz
                                  n = 500   n = 1000
----------------------------------------------------
1) Ruby RNum:                       0.15      0.97
2) Matlab R2006a:                   0.16      0.97
3) Octave 2.1.69:                   0.17      1.07
4) Python NumPy/SciPy:              0.19      1.12
5) Python Numeric:                  1.86     14.09
6) Ruby Narray:                     1.98     15.27
----------------------------------------------------

Example of what I use RNum for

I use the code for doing termodynamic calculations and writing/running dynamic process simulators for chemical engineering tasks and process control.

Some example of what RNum can do is given in the files naturalgas.rb, flash.rb and flashex.rb. The file naturalgas.rb implements the first and second order derivatives of Helmholz energy for a SRK equation of state. The file flash.rb is a simple two-phase equilibrium calculation routine, and the flashex.rb is an example of how to initialize and calculate the two-phase equilibrium. Download all three files and run ruby flashex.rb

Some implementation details

The lower level RAtlas, Blas and Lapack modules written in c-code are typically like this:

VALUE ratlas_getrs_bang(VALUE self, VALUE trans, VALUE astor, VALUE rowperm, VALUE bstor)

and accessed in the ruby classes like this:

def getrs!(a, piv, t = RAtlas::NOTRANS)
	info, stor = Lapack::getrs!(t, a.storage, piv, @storage)
	if info > 0
		raise RNum::SingularError, 
			"Element (#{info-1}, #{info-1}) is exactly singular."
	end
	return self
end

I.e. all c-module methods are singleton. That leaves the object orientation to the higher level ruby interface written i Ruby that holds a @storage object for the matrix/vector struct in c.

The way I built it, you can swap with any blas that has a c-api (atlas, mkl, etc.), and any lapack that conforms to the reference at netlib. Though some config changes must be done (small change in include-file and extconf.rb). I have looked at this, but found mkl to be significantly slower than atlas on uniprocessor. Have not tested atlas smp-version against mkl. Ruby Numeric links against ptcblas if it is found. Btw: the module name RAtlas came from that I initially intended to just wrap the whole Atlas library c-interface (clapack, cblas).

Help wanted

What would be great, was if I or someone else got time to wrap the Sundials suite and/or a SQP-optimizer, and make it work with RNum.

I would be most interested in people willing to participate in this project. Both for fixing bugs and adding all ruby stuff for the complex case. The Lapack and Blas interface + my utility functions handles complex case already.

How to get the source, modify and commit changes

I prefer using bzr (bazaar-ng) for revision control, so I will possibly not use the svn at rubyforge. I will just upload tarballs there.

You can get a development snapshot at the project page, or by using GIT. See the Filesgroup and SCM-sections for details.