I wrote about this earlier to the mailing list haskel-cafe and I was advised to post it here. In the meantime, I added some more not so important functions and fixed a few bugs.
Hatlab is supposed to be a library which works with multi-dimensional arrays in the similar fashion as Matlab or NumPy. I like these frameworks a lot because it allows to concatenate matrices, replace parts of matrices, update matrices and even perform simple queries in one line without the need of writing any kind of loops. Given that, the execution can be accelerated a lot because the executor/compiler does not need to interpret any kind of complicated nested loops. And it is also more convenient for the programmer because the code is more clean and therefore less buggy. So I decided to write a similar framework for Haskell.
The matrices can have arbitrary dimensions, starting from 0D matrices, which are basically scalars. Operations like +
-
*
/
are element-wise. I also implemented broadcasting of these operations.
The core of this framework is indexing. It is a bit more complicated here because the syntax differs based on what we need the index for. If we want to retrieve a single element, we use the !#
operator. If we want to retrieve a slice (submatrix), we use the !$
operator (remember $ like Slice). Examples:
a = matrix2D [[1,2,3],[4,5,6],[7,8,9]]
a !# [2,2] -- element at index [2,2]
a !$ [At 1, All] -- 1st row
a !$ [To (-1), All] -- all rows except the last one
a !$ [Where $ a ># 5] -- all elements bigger than 5 (The ># operator returns a matrix of bools, I will come to that later.)
The matrix cannot be changed but it is possible to make a new matrix with certain elements updated. It is done using the !:
operator. This operator is followed by the slice index and then the way how the slice shall be updated. Some examples:
a = eye 5
b = matrix2D [[1,2,3],[4,5,6],[7,8,9]]
a !:[FromTo 1 4, FromTo 1 4]:= b -- replace the middle square by a different matrix
a !:[FromTo 1 4, FromTo 1 4]:= 1 -- set all values in the middle square to 1
a !:[FromTo 1 4, FromTo 1 4]:+= 1 -- add one to all values in the middle square
a !:[FromTo 1 4, FromTo 1 4]:$= cos -- replace all values in the middle square by their cosine
Operators are broadcasted the same way as in Matlab or NumPy. If one operand has size 1 and the other one has size N or vice-versa in given dimension, the operator acts as if the thinner matrix was repeated in the given dimension N times. Example:
a = matrix1D [10, 20, 30] -- row vector
b = matrix2D [[1], [2], [3]] -- column vector
a + b -- returns [[11, 21, 31], [12, 22, 32], [13, 23, 33]]
Matlab and NumPy also allow adding a scalar to a matrix, which is then interpreted as element-wise addition of that scalar. Something similar can be done in Hatlab too. There is a function scalar
which creates a 0D matrix out of any value, so we can do:
a + (scalar 5) -- returns [15, 25, 35]
a * (scalar 2) -- returns [20, 40, 60]
If a
type is in the class Num
, Fractional
or Floating,
the matrix of the given type is also in the given class. Conversions are performed using the function scalar
, so we can write:
a + 5
a * 2
because the 5
and 2
are then interpreted as 0D matrices. However, this does not work for example in the case a + b
where a
is a matrix and b
is a variable of type Int
, because addition of Matrix Int
and Int
is not defined. In such case, the syntax a + (scalar b)
must be used.
Operator *
is interpreted as element-wise multiplication. To do matrix multiplication, use the ×
operator. It can be also used to multiply matrices with vectors. Examples:
v = matrix1D [1,2,3]
m = matrix2D [[1,0,1],[2,-1,1],[0,1,-1]]
v × m -- multiply row vector v with matrix m
m × v -- multiply matrix m with column vector v
m × m -- multiply matrix m by itself
There are also functions for element-wise boolean operations. They work similarly and they have the #
suffix. Examples:
a = matrix2D [[True, True], [False, False]]
b = matrix2D [[True, False], [True, False]]
a &# b -- element-wise and
a |# b -- element-wise or
There are also element-wise comparison functions in a similar fashion. Examples:
a = eye 3
b = ones [3,3]
a ==# b -- returns a matrix of bools saying where the element of matrix a is equal to the corresponding element in matrix b.
a <# b -- similar as above except that it tests for being less than instead of equality.
a ==# 1 -- Broadcasting works for these operators too, so this syntax is valid also.
This thread is not supposed to serve as a documentation, so I listed only some of the functions.
What I’m going to add:
- linear equation solving (at least using Gaussian elimination)
- inverse matrices, determinants
- SVD decomposition, QR decomposition, eigenvalue decomposition, …
- maybe more fancy functions to operate with matrices
Do you have any other idea what this library shall be able to do? Don’t hesitate to share it.