Sept 2015

introduction to hmatrix

main features

This library works with two types of numeric arrays: Matrix and Vector. (General multidimensional arrays are provided by other packages like repa or hTensor.)

The Matrix type is a 2-dimensional array with an internal representation suitable for the standard linear algebra BLAS/LAPACK libraries.

The Vector type is just the Data.Vector.Storable.Vector from the standard vector package.

These arrays are dense, immutable and strict in all elements (unboxed), and are usually manipulated as whole blocks by high-level, indexless functions.

All functions admit double precision real and complex elements (R=Double and C=Complex Double). Single precision (Float and Complex Float) and machine integers (I=Int32 and Z=Int64) are also supported in arithmetic operations and matrix products. There is experimental support for modular arithmetic in selected functions. Conversion between arrays of different element is explicit.

The instances of the Haskell numeric classes are defined in the element-by-element sense. The matrix product is (<>), the matrix-vector product is (#>), the dot product is (<.>), and the (conjugate) transpose is tr. The general linear system solver is (<\>).

Most operations are "autoconformable": a single row or column is replicated as needed to match the other operand.

The rest of this page is an introduction to the standard interface, which uses run-time dimension checking. See this page for information about the alternative statically checked interface.

simple examples

To get a quick idea of library usage we first show a couple of simple examples. The following code solves a small overdetermined linear system.

import Numeric.LinearAlgebra

-- coefficient matrix of a linear system
a = (4><3)
 [ 1, 2, 3
 , 4, 0, 5
 , 7, 7, 2
 , 3, 3, 1 ] :: Matrix R

-- multiple right-hand sides
b = (4><2)
 [ 10, 1
 , 20, 2
 , 30, 3
 , 15, 1 ] :: Matrix R

-- least squares solution
x = linearSolveLS a b

residual = norm_Frob (a <> x - b)
λ> x
(3><2)
 [  2.862124248496993, 0.2739078156312625
 , 1.0300601202404813, 8.7374749498998e-2
 , 1.7134268537074153, 0.1803607214428857 ]
λ> residual
1.7692315735147401

The obtained right-hand sides:

λ> disp 3 (a <> x)
4x2
10.063  0.990
20.016  1.997
30.672  2.890
13.390  1.264

The residual of each column:

λ> map norm_2 $ toColumns (a <> x - b)
[1.7458797760397966,0.28650334786294096]

The above solver is very fast but the coefficient matrix must have full rank. For rank-deficient systems we must use the operator <\> (resembling the backslash of Matlab/Octave), based on the SVD. Examples of different types of linear systems can be found in this page.

The library provides all common matrix decompositions. For example, we can check the SVD on the coefficient matrix of the above system.

λ> let (u,s,v) = thinSVD a
λ> disp 3 u
4x3
-0.251   0.265  -0.930
-0.390   0.852   0.348
-0.812  -0.423   0.114
-0.353  -0.158   0.015
λ> disp 3 (asRow s)
1x3
12.153  4.991  1.842
λ> disp 3 v
3x3
-0.704   0.048   0.708
-0.596  -0.582  -0.553
-0.385   0.812  -0.438
λ> disp 5 (u <> diag s <> tr v)
4x3
1.00000  2.00000  3.00000
4.00000  0.00000  5.00000
7.00000  7.00000  2.00000
3.00000  3.00000  1.00000

The singular values of $A$ are the eigenvalues of $A^TA$:

λ> singularValues a
fromList [12.153316359624688,4.9905623542834805,1.8415180832366043]
λ> sqrt $ eigenvalues (tr a <> a)
fromList [12.153316359624688 :+ 0.0,1.8415180832366078 :+ 0.0,4.9905623542834805 :+ 0.0]

We have a more efficient eigendecomposition specialized for symmetric matrices:

λ> sqrt $ fst $ eigSH (mTm a)
fromList [12.153316359624691,4.990562354283482,1.8415180832366058]

Detailed information about the available matrix decompositions can be found in the Haddock documentation of the package.

Other common linear algebra functions are readily available:

λ> rank a
3
λ> rcond a
0.15152391567411425
λ> nullspace (tr a)
(4><1)
 [ -3.581291848286757e-2
 ,  -8.95322962071691e-3
 ,  -0.38498887369082685
 ,    0.9221826509338411 ]
λ> orth a
(4><3)
 [  -0.2511962379361302,   0.2646741385060122,    -0.930357719010583
 , -0.39028183686836193,   0.8522734562693702,   0.34818081973118137
 ,  -0.8124981271267512, -0.42266466628276006,   0.11395148277171996
 , -0.35274258500061345, -0.15789913242587644, 1.4821977697794364e-2 ]
λ> det (takeRows 3 a)
103.0
λ> pinv a
(3><4)
 [ -0.34076152304609214,  0.16480961923847692, 8.681362725450899e-2, 2.460921843687378e-2
 ,  0.26092184368737475,  -0.1847695390781563, 5.490981963927855e-2, 3.126252505010018e-2
 ,   0.2725450901803607, 6.813627254509018e-2, -7.01402805611222e-2, -1.80360721442886e-2 ]

basic operations

u = vector [1..5]

v = vector [10,-3,0,4,5]
λ> u + v
fromList [11.0,-1.0,3.0,8.0,10.0]
λ> u * v
fromList [10.0,-6.0,0.0,16.0,25.0]
λ> u <.> v
45.0
λ> u - 10
fromList [-9.0,-8.0,-7.0,-6.0,-5.0]
λ> let w = vector [1,0,1,0,1,0,1]
λ> norm_2 w
2.0
λ> unitary w
fromList [0.5,0.0,0.5,0.0,0.5,0.0,0.5]
λ> w / scalar (sqrt (w <.> w))
fromList [0.5,0.0,0.5,0.0,0.5,0.0,0.5]
a = (5><3) [1..] ::  Matrix R

b = matrix 5
    [ 1, 2,  3, 0, -2
    , 0, 7, -2, 4,  1 ]
λ> a
(5><3)
 [  1.0,  2.0,  3.0
 ,  4.0,  5.0,  6.0
 ,  7.0,  8.0,  9.0
 , 10.0, 11.0, 12.0
 , 13.0, 14.0, 15.0 ]
λ> b
(2><5)
 [ 1.0, 2.0,  3.0, 0.0, -2.0
 , 0.0, 7.0, -2.0, 4.0,  1.0 ]
λ> tr b
(5><2)
 [  1.0,  0.0
 ,  2.0,  7.0
 ,  3.0, -2.0
 ,  0.0,  4.0
 , -2.0,  1.0 ]
λ> b <> a
(2><3)
 [  4.0,  8.0, 12.0
 , 67.0, 77.0, 87.0 ]
λ> b #> u
fromList [4.0,29.0]
λ> a * 2
(5><3)
 [  2.0,  4.0,  6.0
 ,  8.0, 10.0, 12.0
 , 14.0, 16.0, 18.0
 , 20.0, 22.0, 24.0
 , 26.0, 28.0, 30.0 ]
λ> a + row [100,200,300]
(5><3)
 [ 101.0, 202.0, 303.0
 , 104.0, 205.0, 306.0
 , 107.0, 208.0, 309.0
 , 110.0, 211.0, 312.0
 , 113.0, 214.0, 315.0 ]
λ> diagl [1..4]
(4><4)
 [ 1.0, 0.0, 0.0, 0.0
 , 0.0, 2.0, 0.0, 0.0
 , 0.0, 0.0, 3.0, 0.0
 , 0.0, 0.0, 0.0, 4.0 ]
λ> u <.> diagl [1..5] #> v
187.0
λ>  vector [1,2,3] `outer` vector [10,20,30,40]
3x4
10  20  30   40
20  40  60   80
30  60  90  120
λ>  diagl [1,20] `kronecker` b
4x10
1  2   3  0  -2   0    0    0   0    0
0  7  -2  4   1   0    0    0   0    0
0  0   0  0   0  20   40   60   0  -40
0  0   0  0   0   0  140  -40  80   20

data constructors

vector

There are several ways to define a vector. The simplest method is fromList, which admits any desired element type.

λ> fromList [1,2,3::R]
fromList [1.0,2.0,3.0]
λ> fromList [2,3+2*iC,-8]
fromList [2.0 :+ 0.0,3.0 :+ 2.0,(-8.0) :+ (-0.0)]

The function vector used above is specialized for double precision real elements (Vector R). It can be useful to avoid a possible type annotation.

λ> vector [1,2,3]
fromList [1.0,2.0,3.0]

The operator |> explicitly takes the length and admits extra elements which are discarded.

λ> 3 |> [0..] :: Vector Z
fromList [0,1,2]

The functions idxs and range create Vector I which can be used to define matrix slices (explained below).

λ> idxs [5,3,2,1]
fromList [5,3,2,1]
λ> range 4
fromList [0,1,2,3]

More examples:

λ> linspace 5 (0,1) :: Vector Float
fromList [0.0,0.25,0.5,0.75,1.0]
λ> build 5 (^2) :: Vector R
fromList [0.0,1.0,4.0,9.0,16.0]
λ> subVector 2 3 (vector [0..9])
fromList [2.0,3.0,4.0]
λ> vjoin[vector[5,3,8], 12, vector[1..3]]
fromList [5.0,3.0,8.0,12.0,1.0,2.0,3.0]

We can also import qualified Data.Storable.Vector as V to use any desired function from the vector package. Many functions provided by hmatrix admit both vectors and matrices.

matrix

A matrix can be created from a list of elements in row order, using the operator (><) to specify the dimensions. This method admits any Element type and extra elements are discarded.

λ> (3><4)[0..] :: Matrix Z
(3><4)
 [ 0, 1,  2,  3
 , 4, 5,  6,  7
 , 8, 9, 10, 11 ]

There is also a specialized constructor of Matrix R (double precision real elements), which takes only the number of columns of the matrix. (The number of rows is deduced from the length of the list, which in this case cannot be infinite.)

λ> matrix 2 [1..6]
(3><2)
 [ 1.0, 2.0
 , 3.0, 4.0
 , 5.0, 6.0 ]

Other examples:

λ> build (5,2) (\i j -> 2*i*iC + 3*j) :: Matrix C
(5><2)
 [ 0.0 :+ 0.0, 3.0 :+ 0.0
 , 0.0 :+ 2.0, 3.0 :+ 2.0
 , 0.0 :+ 4.0, 3.0 :+ 4.0
 , 0.0 :+ 6.0, 3.0 :+ 6.0
 , 0.0 :+ 8.0, 3.0 :+ 8.0 ]
λ> accum (ident 5) (+) [((1,1),5),((0,3),3)] :: Matrix R
(5><5)
 [ 1.0, 0.0, 0.0, 3.0, 0.0
 , 0.0, 6.0, 0.0, 0.0, 0.0
 , 0.0, 0.0, 1.0, 0.0, 0.0
 , 0.0, 0.0, 0.0, 1.0, 0.0
 , 0.0, 0.0, 0.0, 0.0, 1.0 ]
λ> repmat (ident 2) 2 3 :: Matrix I
(4><6)
 [ 1, 0, 1, 0, 1, 0
 , 0, 1, 0, 1, 0, 1
 , 1, 0, 1, 0, 1, 0
 , 0, 1, 0, 1, 0, 1 ]

See Numeric.LinearAlgebra.Data for more information.

matrix blocks

λ> fromBlocks [[konst 7 (1,5), 0, ident 3],[0,konst 1 (3,2),8]]
6x10
7  7  7  7  7  0  0  1  0  0
7  7  7  7  7  0  0  0  1  0
7  7  7  7  7  0  0  0  0  1
0  0  0  0  0  1  1  8  8  8
0  0  0  0  0  1  1  8  8  8
0  0  0  0  0  1  1  8  8  8
λ> fromBlocks [[konst 7 (2,5), 0],[0,1]]
3x6
7  7  7  7  7  0
7  7  7  7  7  0
0  0  0  0  0  1
λ> ident 3 ||| 7 :: Matrix I
(3><4)
 [ 1, 0, 0, 7
 , 0, 1, 0, 7
 , 0, 0, 1, 7 ]
λ> konst 5 (3,4) ||| row [1,2,3]
3x7
5  5  5  5  1  2  3
5  5  5  5  1  2  3
5  5  5  5  1  2  3
λ> col [10,20,30] ||| konst 5 (3,4)
3x5
10  5  5  5  5
20  5  5  5  5
30  5  5  5  5
λ> row [1,1,1] ||| row [2,2] === row [3,3] ||| row [4,4,4]
2x5
1  1  1  2  2
3  3  4  4  4
λ> diagBlock [konst 7 (2,3), 1]
3x4
7  7  7  0
7  7  7  0
0  0  0  1

matrix slices

λ> let m = (5><10) [0..] :: Matrix I
λ> m
(5><10)
 [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9
 , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
 , 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
 , 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
 , 40, 41, 42, 43, 44, 45, 46, 47, 48, 49 ]
λ> m ?? (All, Take 3)
(5><3)
 [  0,  1,  2
 , 10, 11, 12
 , 20, 21, 22
 , 30, 31, 32
 , 40, 41, 42 ]
λ> m ?? (DropLast 2, Range 2 1 4)
(3><3)
 [  2,  3,  4
 , 12, 13, 14
 , 22, 23, 24 ]

We can select arbitrary sets of indexes using Pos (idxs creates a Vector I from a list Ints):

λ> m ?? (Pos (idxs [2,3,0]), Pos (4-2*range 3))
(3><3)
 [ 24, 22, 20
 , 34, 32, 30
 ,  4,  2,  0 ]

Cyclic access is provided by PosCyc:

λ> m ?? (PosCyc (idxs [8,-2]), All)
(2><10)
 [ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
 , 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 ]

Many data manipulation functions are defined in terms of (??).

λ> m ? [2,1]
(2><10)
 [ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
 , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]
λ> m ¿ [5,7]
(5><2)
 [  5,  7
 , 15, 17
 , 25, 27
 , 35, 37
 , 45, 47 ]

Rectangular slices are taken from the original matrix without data copy:

λ> subMatrix (1,3) (3,2) m
(3><2)
 [ 13, 14
 , 23, 24
 , 33, 34 ]

(If we only need a small slice of a big matrix it is better to take a fresh array using ?? with the Pos selector, so that the original matrix can be freed.)

Finally, there is also a more general "2D" element extraction:

λ> let r = (2><3) [2,1,2,0,3,3] :: Matrix I
λ> let c = (2><3) [1,1,3,2,0,1] :: Matrix I
λ> r
(2><3)
 [ 2, 1, 2
 , 0, 3, 3 ]
λ> c
(2><3)
 [ 1, 1, 3
 , 2, 0, 1 ]
λ> remap r c m
(2><3)
 [ 21, 11, 23
 ,  2, 30, 31 ]

The matrices containing the indexes for remap are autoconformable:

λ> remap (asColumn (range 3)) (asRow (range 4)) m
(3><4)
 [  0,  1,  2,  3
 , 10, 11, 12, 13
 , 20, 21, 22, 23 ]

sort

λ> v <- flatten <$> randn 1 10
λ> v
-0.368  2.427  -2.534  0.703  1.384  1.330  -0.177  -0.452  0.262  0.823
λ> sortVector v
-2.534  -0.452  -0.368  -0.177  0.262  0.703  0.823  1.330  1.384  2.427
λ> sortIndex v
fromList [2,7,0,6,8,3,9,5,4,1]
λ> m <- randn 4 10
λ> disp 2 m
4x10
0.46   0.32   0.40  -0.89  -0.85   1.04  -1.00   1.05  -2.27   0.73
1.19   1.38  -0.13   0.32   0.01   0.33  -0.49  -1.98  -0.18  -0.56
1.33   0.91   0.88   2.37  -0.38  -1.30   1.01   0.91  -0.79  -1.82
1.02  -1.98   0.15  -1.45  -1.04  -0.46   0.49  -0.56   1.00  -1.30

Sort columns by the second row:

λ> disp 2 $ m ?? (All, Pos $ sortIndex (m!1))
4x10
 1.05   0.73  -1.00  -2.27   0.40  -0.85  -0.89   1.04  0.46   0.32
-1.98  -0.56  -0.49  -0.18  -0.13   0.01   0.32   0.33  1.19   1.38
 0.91  -1.82   1.01  -0.79   0.88  -0.38   2.37  -1.30  1.33   0.91
-0.56  -1.30   0.49   1.00   0.15  -1.04  -1.45  -0.46  1.02  -1.98

display

λ> b
(2><5)
 [ 1.0, 2.0,  3.0, 0.0, -2.0
 , 0.0, 7.0, -2.0, 4.0,  1.0 ]
λ> disp 4 (b/3)
2x5
0.3333  0.6667   1.0000  0.0000  -0.6667
0.0000  2.3333  -0.6667  1.3333   0.3333
λ> disp 4 b
2x5
1  2   3  0  -2
0  7  -2  4   1
λ> ident 3 :: Matrix C
(3><3)
 [ 1.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0
 , 0.0 :+ 0.0, 1.0 :+ 0.0, 0.0 :+ 0.0
 , 0.0 :+ 0.0, 0.0 :+ 0.0, 1.0 :+ 0.0 ]
λ> putStr . dispcf 2 . diag . fromList $ [1,iC,3-2*iC]
3x3
1  0     0
0  i     0
0  0  3-2i
λ> let z = conv2 (konst 1 (3,3)) (diagl [1..10])
λ> z
(12><12)
 [ 1.0, 1.0, 1.0, 0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0
 , 1.0, 3.0, 3.0, 2.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0
 , 1.0, 3.0, 6.0, 5.0,  3.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0
 , 0.0, 2.0, 5.0, 9.0,  7.0,  4.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0
 , 0.0, 0.0, 3.0, 7.0, 12.0,  9.0,  5.0,  0.0,  0.0,  0.0,  0.0,  0.0
 , 0.0, 0.0, 0.0, 4.0,  9.0, 15.0, 11.0,  6.0,  0.0,  0.0,  0.0,  0.0
 , 0.0, 0.0, 0.0, 0.0,  5.0, 11.0, 18.0, 13.0,  7.0,  0.0,  0.0,  0.0
 , 0.0, 0.0, 0.0, 0.0,  0.0,  6.0, 13.0, 21.0, 15.0,  8.0,  0.0,  0.0
 , 0.0, 0.0, 0.0, 0.0,  0.0,  0.0,  7.0, 15.0, 24.0, 17.0,  9.0,  0.0
 , 0.0, 0.0, 0.0, 0.0,  0.0,  0.0,  0.0,  8.0, 17.0, 27.0, 19.0, 10.0
 , 0.0, 0.0, 0.0, 0.0,  0.0,  0.0,  0.0,  0.0,  9.0, 19.0, 19.0, 10.0
 , 0.0, 0.0, 0.0, 0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 10.0, 10.0, 10.0 ]
λ> disp 2 (z/2)
12x12
0.50  0.50  0.50  0.00  0.00  0.00  0.00   0.00   0.00   0.00  0.00  0.00
0.50  1.50  1.50  1.00  0.00  0.00  0.00   0.00   0.00   0.00  0.00  0.00
0.50  1.50  3.00  2.50  1.50  0.00  0.00   0.00   0.00   0.00  0.00  0.00
0.00  1.00  2.50  4.50  3.50  2.00  0.00   0.00   0.00   0.00  0.00  0.00
0.00  0.00  1.50  3.50  6.00  4.50  2.50   0.00   0.00   0.00  0.00  0.00
0.00  0.00  0.00  2.00  4.50  7.50  5.50   3.00   0.00   0.00  0.00  0.00
0.00  0.00  0.00  0.00  2.50  5.50  9.00   6.50   3.50   0.00  0.00  0.00
0.00  0.00  0.00  0.00  0.00  3.00  6.50  10.50   7.50   4.00  0.00  0.00
0.00  0.00  0.00  0.00  0.00  0.00  3.50   7.50  12.00   8.50  4.50  0.00
0.00  0.00  0.00  0.00  0.00  0.00  0.00   4.00   8.50  13.50  9.50  5.00
0.00  0.00  0.00  0.00  0.00  0.00  0.00   0.00   4.50   9.50  9.50  5.00
0.00  0.00  0.00  0.00  0.00  0.00  0.00   0.00   0.00   5.00  5.00  5.00
λ> disp 2 z
12x12
1  1  1  0   0   0   0   0   0   0   0   0
1  3  3  2   0   0   0   0   0   0   0   0
1  3  6  5   3   0   0   0   0   0   0   0
0  2  5  9   7   4   0   0   0   0   0   0
0  0  3  7  12   9   5   0   0   0   0   0
0  0  0  4   9  15  11   6   0   0   0   0
0  0  0  0   5  11  18  13   7   0   0   0
0  0  0  0   0   6  13  21  15   8   0   0
0  0  0  0   0   0   7  15  24  17   9   0
0  0  0  0   0   0   0   8  17  27  19  10
0  0  0  0   0   0   0   0   9  19  19  10
0  0  0  0   0   0   0   0   0  10  10  10
λ> dispDots 1 z
1  1  1  .   .   .   .   .   .   .   .   .
1  3  3  2   .   .   .   .   .   .   .   .
1  3  6  5   3   .   .   .   .   .   .   .
.  2  5  9   7   4   .   .   .   .   .   .
.  .  3  7  12   9   5   .   .   .   .   .
.  .  .  4   9  15  11   6   .   .   .   .
.  .  .  .   5  11  18  13   7   .   .   .
.  .  .  .   .   6  13  21  15   8   .   .
.  .  .  .   .   .   7  15  24  17   9   .
.  .  .  .   .   .   .   8  17  27  19  10
.  .  .  .   .   .   .   .   9  19  19  10
.  .  .  .   .   .   .   .   .  10  10  10
λ> dispDots 2 $ z/9
0.11  0.11  0.11   .     .     .     .     .     .     .     .     .  
0.11  0.33  0.33  0.22   .     .     .     .     .     .     .     .  
0.11  0.33  0.67  0.56  0.33   .     .     .     .     .     .     .  
 .    0.22  0.56  1.    0.78  0.44   .     .     .     .     .     .  
 .     .    0.33  0.78  1.33  1.    0.56   .     .     .     .     .  
 .     .     .    0.44  1.    1.67  1.22  0.67   .     .     .     .  
 .     .     .     .    0.56  1.22  2.    1.44  0.78   .     .     .  
 .     .     .     .     .    0.67  1.44  2.33  1.67  0.89   .     .  
 .     .     .     .     .     .    0.78  1.67  2.67  1.89  1.     .  
 .     .     .     .     .     .     .    0.89  1.89  3.    2.11  1.11
 .     .     .     .     .     .     .     .    1.    2.11  2.11  1.11
 .     .     .     .     .     .     .     .     .    1.11  1.11  1.11
λ> dispBlanks 2 $ z/1000
0.00  0.00  0.00                                                      
0.00  0.00  0.00  0.00                                                
0.00  0.00  0.01  0.00  0.00                                          
      0.00  0.00  0.01  0.01  0.00                                    
            0.00  0.01  0.01  0.01  0.00                              
                  0.00  0.01  0.02  0.01  0.01                        
                        0.00  0.01  0.02  0.01  0.01                  
                              0.01  0.01  0.02  0.02  0.01            
                                    0.01  0.02  0.02  0.02  0.01      
                                          0.01  0.02  0.03  0.02  0.01
                                                0.01  0.02  0.02  0.01
                                                      0.01  0.01  0.01
λ> dispDots 2 (diagl [1..15])
1  .  .  .  .  .  .  .  .   .   .   .   .   .   .
.  2  .  .  .  .  .  .  .   .   .   .   .   .   .
.  .  3  .  .  .  .  .  .   .   .   .   .   .   .
.  .  .  4  .  .  .  .  .   .   .   .   .   .   .
.  .  .  .  5  .  .  .  .   .   .   .   .   .   .
.  .  .  .  .  6  .  .  .   .   .   .   .   .   .
.  .  .  .  .  .  7  .  .   .   .   .   .   .   .
.  .  .  .  .  .  .  8  .   .   .   .   .   .   .
.  .  .  .  .  .  .  .  9   .   .   .   .   .   .
.  .  .  .  .  .  .  .  .  10   .   .   .   .   .
.  .  .  .  .  .  .  .  .   .  11   .   .   .   .
.  .  .  .  .  .  .  .  .   .   .  12   .   .   .
.  .  .  .  .  .  .  .  .   .   .   .  13   .   .
.  .  .  .  .  .  .  .  .   .   .   .   .  14   .
.  .  .  .  .  .  .  .  .   .   .   .   .   .  15
λ> dispShort 10 10 1 (matrix 30 [1..30*30])
30x30
  1.0    2.0    3.0    4.0    5.0    6.0    7.0  ..  29.0   30.0
 31.0   32.0   33.0   34.0   35.0   36.0   37.0  ..  59.0   60.0
 61.0   62.0   63.0   64.0   65.0   66.0   67.0  ..  89.0   90.0
 91.0   92.0   93.0   94.0   95.0   96.0   97.0  .. 119.0  120.0
121.0  122.0  123.0  124.0  125.0  126.0  127.0  .. 149.0  150.0
151.0  152.0  153.0  154.0  155.0  156.0  157.0  .. 179.0  180.0
181.0  182.0  183.0  184.0  185.0  186.0  187.0  .. 209.0  210.0
   :      :      :      :      :      :      :   ::    :      : 
841.0  842.0  843.0  844.0  845.0  846.0  847.0  .. 869.0  870.0
871.0  872.0  873.0  874.0  875.0  876.0  877.0  .. 899.0  900.0
λ> dispShort 10 10 2 =<< randn 1000 5
1000x5
 1.41  -0.72   0.46   1.62  -1.19
-0.45   1.00   0.71   0.12  -0.77
 1.31  -1.22   1.41  -0.16   1.04
-0.54  -2.06   1.21  -1.48  -1.63
-0.34  -0.41   1.36  -0.91  -1.91
-0.53   0.33   0.54   0.40   1.08
-0.35   0.38   0.56  -0.71   0.57
  :      :      :      :      :  
-0.86  -0.09   0.46  -0.45   0.62
-0.08   1.06  -2.45  -0.43   1.15
λ> let h = build (5,5) (\r c -> r - 2*iC*(c-2))
λ> h
(5><5)
 [ 0.0 :+ 4.0, 0.0 :+ 2.0, 0.0 :+ 0.0, 0.0 :+ (-2.0), 0.0 :+ (-4.0)
 , 1.0 :+ 4.0, 1.0 :+ 2.0, 1.0 :+ 0.0, 1.0 :+ (-2.0), 1.0 :+ (-4.0)
 , 2.0 :+ 4.0, 2.0 :+ 2.0, 2.0 :+ 0.0, 2.0 :+ (-2.0), 2.0 :+ (-4.0)
 , 3.0 :+ 4.0, 3.0 :+ 2.0, 3.0 :+ 0.0, 3.0 :+ (-2.0), 3.0 :+ (-4.0)
 , 4.0 :+ 4.0, 4.0 :+ 2.0, 4.0 :+ 0.0, 4.0 :+ (-2.0), 4.0 :+ (-4.0) ]
λ> putStrLn $ dispcf 2 h
5x5
  4i    2i  0   -2i   -4i
1+4i  1+2i  1  1-2i  1-4i
2+4i  2+2i  2  2-2i  2-4i
3+4i  3+2i  3  3-2i  3-4i
4+4i  4+2i  4  4-2i  4-4i

λ> let latex = putStrLn . latexFormat "bmatrix" . dispcf 2