tensor- A completely type-safe library for linear algebra

MaintainerNicola Squartini <tensor5@gmail.com>
Safe HaskellSafe-Inferred



This library defines data types and classes for fixed dimension vectors and tensors. The main objects are:

A totally ordered set with fixed size. The Ordinal type One contains 1 element, Succ One contains 2 elements, Succ Succ One contains 3 elements, and so on (see Data.Ordinal for more details). The type Two is an alias for Succ One, Three is an alias for Succ Succ One, and so on.
The index set. It can be linear, rectangular, parallelepipedal, etc. The dimensions of the sides are expressed using Ordinal types and the type constructor :|:, e.g. (Two :|: (Three :|: Nil)) is a rectangular index set with 2 rows and 3 columns. The index set also contains elements, for example (Two :|: (Three :|: Nil)) contains all the pairs (i :|: (j :|: Nil)) where i is in Two and j is in Three. See Data.TypeList.MultiIndex for more details.
It is an assignment of elements to each element of its MultiIndex.

Objects like vectors and matrices are special cases of tensors. Most of the functions to manipulate tensors are grouped into type classes. This allow the possibility of having different internal representations (backends) of a tensor, and act on these with the same functions. At the moment we provide two backends: one in Data.Tensor.Pure (not complete) that uses a recursive definition, and another in Data.Tensor.Vector that is based on http://hackage.haskell.org/package/vector and is faster. More backends (e.g. one based on http://hackage.haskell.org/package/repa) are planned for future releases.

Here is a usage example (start ghci with the option -XTypeOperators):

>>> import Data.Tensor.Vector
>>> fromList [2,3,5,1,3,6,0,5,4,2,1,3] :: Tensor (Four :|: Three :|: Nil) Int

The above defines a tensor with 4 rows and 3 columns (a matrix) and Int coefficients. The entries of this matrix are taken from a list using fromList which is a method of the class FromList. Notice the output: the Show instance is defined in such a way to give a readable representation as list of lists. The is equivalent but slightly more readable code:

>>> fromList [2,3,5,1,3,6,0,5,4,2,1,3] :: Matrix Four Three Int


>>> fromList [7,3,-6] :: Tensor (Three :|: Nil) Int


>>> fromList [7,3,-6] :: Vector Three Int

are the same. In order to access an entry of a Tensor we use the ! operator, which takes the same MultiIndex of the Tensor as its second argument:

>>> let a = fromList [2,3,5,1,3,6,0,5,4,2,1,3] :: Matrix Four Three Int
>>> let b = fromList [7,3,-6] :: Vector Three Int
>>> a ! (toMultiIndex [1,3] :: (Four :|: Three :|: Nil))
>>> b ! (toMultiIndex [2] :: (Three :|: Nil))

it returns the element at the coordinate (1,3) of the matrix a, and the element at the coordinate 2 of the vector b. In fact, thanks to type inference, we could simply write

>>> a ! toMultiIndex [1,3]
>>> b ! toMultiIndex [2]

And now a couple of examples of algebraic operations (requires adding Data.Tensor.LinearAlgebra to the import list):

>>> import Data.Tensor.Vector
>>> import Data.Tensor.LinearAlgebra hiding (Matrix)
>>> let a = fromList [2,3,5,1,3,6,0,5,4,2,1,3] :: Matrix Four Three Int
>>> let b = fromList [7,3,-6] :: Vector Three Int
>>> a .*. b

is the product of matrix a and vector b, while

>>> let c = fromList [3,4,0,-1,4,5,6,2,1] :: Matrix Three Three Int
>>> c
>>> charPoly c

gives the coefficients of the characteristic polynomial of the matrix c.