Next: , Previous: Getting started, Up: Top


3 Tutorial

3.1 Starting

On SBCL, make sure that asdf:*centeral-registry* contains lisplab.asd and type

     CL-USER> (let ((*read-default-float-format* 'double-float))
                (require :lisplab))
     CL-USER> (in-package :ll))

The *read-default-float-format* is only needed when requiring for first time. The main package of Lisplab is lisplab, with nickname ll, and the package lisplab-user, with nickname ll-user.

3.2 Matrix classes

The matrix classes hierarchy has three lines of inheritance: on structure, on element type and on implementation. This hierarchy is similar to the stream example in Object-Oriented Programming in Common Lisp, by Sonya E. Keene.

Objects of the most important classes can be created by read macros. For double-float matrices, matrix-dge,

     LL-USER> #md((1 2) (3 4))
     #md(( 1.000      2.000    )
         ( 3.000      4.000    ))

For complex double-float matrices, matrix-zge,

     LL-USER> #mz((1 2) (#c(1 2) #c(3 4)))
     #mz((#c( 1.0      0.0    ) #c( 2.0      0.0    ))
         (#c( 1.0      2.0    ) #c( 3.0      4.0    )))

Untyped matrices, matrix-ge,

     LL-USER> #mm(('a 'b) ('c 'd))
     #mm((A B)
         (C D))

There are more matrix classes, but these are not exported. Even more matrix classes can be created dynamically, but these capabilities are not yet fully in use. See Structure.

3.3 Matrix construction

There are many ways to create a matrix, such as

     LL-USER> (dnew 0 2 2)
     #md(( 0.000      0.000    )
         ( 0.000      0.000    ))
     
     LL-USER> (drow 1 2)
     #md(( 1.000      2.000    ))
     
     LL-USER> (dcol 1 2)
     #md(( 1.000    )
         ( 2.000    ))
     
     LL-USER> (dmat '((1 2) (3 4)))
     #md(( 1.000      2.000    )
         ( 3.000      4.000    ))

Similarly, there are znew, zcol, zrow, and zmat for complex double float matrices and mnew, mcol, mrow, and mmat for any matrices. The latter take matrix class as first argument.

Often you want to create a matrix of the same type as a input matrix. Then you can use mcreate and mcreate* for extended syntax. They are useful when creating methods that should operate on many matrix types.

To create matrices from something else, use convert

     LL-USER> (convert '((1 2) (3 4)) '(:d :ge :any))
     #md(( 1.000      2.000    )
         ( 3.000      4.000    ))

Convert also converts between matrix types. If the matrix contents cannot be converted directly (e.g., conversion from complex to real), use copy-contents instead.

Other matrix constructors are mcreate, mcreate*, drange, dgrid, fmat, funmat. The most fundamental constructor is make-matrix-instance.

3.4 Matrix element reference

Lisplab matrices are zero-based and in column major order. Matrix reference is with the settable generic function mref

     LL-USER> (mref #md((1 2) (3 4)) 0 1)
     2.0

Matrices can also list their elements as vectors (similar to row-major-aref for arrays). Vector access is with the generic function vref

     LL-USER> (vref #md((1 2) (3 4)) 1)
     3.0

which is also settable.

3.5 Elementwise operators and functions

Lisplab introduces general mathematical operators .+, .-, .*, ./, and .^. These are generalization of +, -, *, /, and ^. For numbers they work the same,

     LL-USER>  (.+ 1 2)
     3

But the lisplab functions have a much wider functionality since they are based on the binary generic functions .add, .sub, .mul, .div, and .expt.

On matrices the all functions starting with a dot works elementwise. Hence

     LL-USER> (.sin (drow 0 1))
     #md(( 0.000     0.8415    ))

The dotted operators ignores the internal structure of the matrices

     LL-USER> (let ((a (drow 0 1))
     	       (b (dcol 0.1 0.2)))
     	   (.+ a (.* b 2)))
     #md((0.2000      1.400    ))

The output need not have same type as the input

     LL-USER> (.asin #md((1 2)))
     #mz((#c( 1.6      0.0    ) #c( 1.6      1.3    )))

The dotted functions and operators are optimized and very fast for the double-float matrices, but slow for the matrices with arbitrary element-types.

     LL-USER> (.+ #mm((1/2 3/2)) 1)
     #mm((3/2 5/2))

3.6 Linear algebra

The linear algebra functions feel and maybe also change the matrix structure. The linear algebra functions often start with m, although this conventions is not strictly followed. The number of linear algebra functions is small compared with LAPACK, but you will find matrix multiplication, matrix inversion, transpose, conjugate transpose, LU-decomposition and eigenvalues.

Matrix multiplication

     LL-USER> (let ((a #md((1 0) (0 -1)))
     	       (b #md((0.1) (0.2))))
     	   (m* a b))
     #md((0.1000    )
         (-.2000    ))

Matrix inversion

     LL-USER> (minv #md((1 2)
     		   (-2 1)))
     #md((0.2000     -.4000    )
         (0.4000     0.2000    ))

Transpose

     LL-USER> (mtp #md((1 2)
                       (-2 1)))
     #md(( 1.000     -2.000    )
         ( 2.000      1.000    ))

Conjugate transpose

     LL-USER> (mct #mz((1 (* 2 %i)) (-2 1)))
     #mz((#c( 1.0     -0.0    ) #c(-2.0     -0.0    ))
         (#c( 0.0     -2.0    ) #c( 1.0     -0.0    )))

Eigenvalues

     LL-USER> (eigenvalues #md((1 2) (0 0.5)))
     #md(( 1.000    )
         (0.5000    ))

Eigenvectors

     LL-USER> (eigenvectors #md((1 2) (0 0.5)))
     (
     #md(( 1.000    )
         (0.5000    ))
     
     #md(( 1.000     -.9701    )
         ( 0.000     0.2425    )))

Some of the linear algebra functions also work for general element matrices

     LL-USER> (let ((a #mm((1 0) (0 -1)))
                    (b #mm((1/2) (2/3))))
                 (m* a b))
     #mm((1/2)
         (-2/3))
     
     LL-USER> (minv #mm((1 2)(-2 1)))
     #mm((1/5 -2/5)
         (2/5 1/5))

3.7 Matrix IO

Delimited files are read with dlmread. Delimited files are written with dlmwrite. You can also write matrices as images with pgmwrite and pswrite, writing portable graymap and postscript respectively.

3.8 Matrices without store

The class function-matrix implements matrices with functions and has no store, but where the elements are given by a function

     LL-USER> (funmat '(2 2) (lambda (i j)
                                (if (= i j)
                                    1
                                    0)))
     #<FUNCTION-MATRIX  2x2
     1 0
     0 1
      {AC0F489}>

The similar macro fmat creates functions of any type by a function.

Function matrices are also used to view a part or restructured other matrix with view-matrix, view-col, or view-row.

3.9 Matrix map

There are two methods for mapping of matrices: mmap and mmap-into. For example

     LL-USER> (mmap 'matrix-dge #'.re #mz((1 %i) (-%i 2)))
     #md(( 1.000      0.000    )
         ( 0.000      2.000    ))

The output matrix takes the structure from the first arguments, but ignores in general matrix structure. If first argument t output type is same as type of first matrix argument.

3.10 Ordinary functions

.sin, .cos, .sin, .tan, .sinh, .cosh, .sinh, .tanh, .asin, .acos, .asin, .atan, .asinh, .acosh, .asinh, .atanh, .conj, .re, .im, .abs, .sqrt, .exp.

3.11 Special functions

.besj, .besy, .besi, .besk, .besh1, .besh2, .ai, .gamma.

3.12 Infix notation

Infix input is with the macro w/infix

     LL-USER> (w/infix
     	   (let ((x 3))
     	     (1 .+ 2 .* x)))
     7

The w/infix is compatible with the Lisp semantics. The infix math also works with the functions +, -, *, / and ^.