Download |
||
CLAS provides basic operations for numerical linear algebra. Its name and organization is inspired by BLAS (Basic Linear Algebra Subroutines), which exist for many imperative languages such as C and FORTRAN.
CLAS is (much like BLAS) organized in three levels/modules
of increasing complexity and some additional modules.
The levels are
Importing one level, all lower levels will be imported as well, plus SampleVec and SampleMat.
At this time the CLAS functions are provided for full matrices only, defined as
:: Vector :== {# Real} :: Matrix :== {# .Vector}
Sparse storage schemes are being investigated and will be included at a later time.
With version 0.7 slicing is introduced in module slicing with instructive examples in slicingExamples.
function | name | types/remarks |
(+), (-) | vector addition, subtraction | {# a} {# a} -> {# a} Due to a recursive instantiation, this function can also be used for matrices and tensors. An instance for a of type Real gives: Vector Vector -> Vector, an instance for a of type Vector gives: Matrix Matrix -> Matrix etc. |
(*), (/) | Hadamard product, division | {# a} {# a} -> {# a} Due to a recursive instantiation, this function can also be used for matrices and tensors. An instance for a of type Real gives: Vector Vector -> Vector, an instance for a of type Vector gives: Matrix Matrix -> Matrix etc. The Hadamard product/division is not a very common operation. Do not confuse it with the dot product. |
dot | dot (inner) product |
.Vector .Vector -> Real
|
nrm1, nrm2, nrmInf | 1-norm, 2-norm, infinity-norm |
.Vector -> Real
|
(.*) | scalar product | Real a -> a If a is inferred to be of type Vector: Real Vector -> Vector, if a is inferred to be of type Matrix: Real Matrix -> Matrix etc. |
(/.) | scalar division | a Real -> a If a is inferred to be of type Vector: Vector Real -> Vector, if a is inferred to be of type Matrix: Matrix Real -> Matrix etc. |
givens | Givens rotation |
Real Real -> (Real, Real) Idea: zero out the lower component of a 2-by-1 vector by means of a rotation with angle t: Input is a and b, output is the pair of c = cos t and s = sin t. |
swap | swaps two elements of a unique vector | *{# a} .Int .Int -> .{# a} |
function | name | types/remarks |
(**) | matrix vector product | a .Vector -> .Vector An instance has been defined for type Matrix. |
transpose | matrix transposition | .Matrix -> .Matrix |
perVec | permutes a vector | {# Int} .Vector -> .Vector |
forwardSubst | forward substitution | Matrix Vector -> *Vector Idea: Solve a linear system with a lower left triangular system, where the diagonal elements are all one. BUG in 0.5: Please erase "\ l.[0,0]" at the end of the second line in the function forwardSubst in Clas2.icl |
backwardSubst | backward substitution | Matrix Vector -> *Vector Idea: Solve a linear system with an upper right triangular system. |
function | name | types/remarks |
(***) | matrix matrix product | a a -> a An instance has been defined for type Matrix |
lu | LU decomposition |
*Matrix -> *Matrix A will hereby be overwritten by both L and U. The diagonal of the result matrix will contain the diagonal elements of L, as the diagonal elements of U are know to be one.
|
luPartPiv | LU decomposition with partial pivoting | *Matrix -> (*Matrix, *{# Int}) Idea: During the LU decomposition rows are permuted such that the diagonal (or pivoting) element is the largest within the column. These permutations are stored in an array of integers for later reference. Thus a permutation of A is overwritten by both L and U: PA = LU. Remark: Due to the search for the pivoting element partial pivoting is more expensive, but applicable to a much larger class of problems. |
solveLS | solves a general linear system |
*Matrix .Vector -> .Vector Idea: Solve Ax=b for x, where A is a general nonsingular matrix, by means of LU decomposition, followed by forward and backward substitution. Solving a linear system is then Solving triangular systems can easily be done by forward and backward substitution. |
solvePartPiv | solves a general linear system |
*Matrix .Vector -> .Vector
|
invert | Gauss-Jordan algorithm to invert a general matrix | *Matrix -> .Matrix Idea: Efficiently invert a matrix (if this is really needed - it is not, if you want to solve a linear system!). |
function | name | types/remarks |
uniVec | creates a unique copy of a vector | .Vector -> *Vector |
zeros, ones, one2n | creates zero-vector, one-vector, a vector containing 1,...,n | Int -> .Vector returns the vector of a given length |
ek | k-th unit vector | Int Int -> .Vector returns the k-th unit vector (i. e. the k-th element of the vector is one, all others are zero) of given length n |
prettyRowVector, prettyColumnVector | vector output | Vector -> String |
function | name | types/remarks |
uniMat | creates a unique copy of a matrix | .Matrix -> *Matrix |
zeroMatrix | creates zero-matrix | Int Int -> .Matrix returns matrix of the given size (n columns, m rows) |
Ik | unit matrix | Int -> .Matrix returns the unit matrix of given size n-by-n (square matrix) |
prettyMatrix | matrix output | Matrix -> String |
What is a slice?
In general a slice is a rectangular sub-array of a multidimensional array, a matrix in our case. In FORTRAN 90 this is referred to as a section.
What can they be used for?
Working with slices of a matrix rather than with the whole matrix is useful for many algorithms that manipulate matrix elements. It can lead to very concise and elegant code.
How are they defined in Clean?
In general slices can be defined by stating a lower and an upper bound of the slice for each dimension.
We implement the type of a slice as a constructor followed by two lists of integers, one for each dimension of a matrix.
:: Sli = Sli ![Int] ![Int]The integers in the lists indicate the row/column numbers of a given matrix, that we want to treat as a slice.
For example within a matrix a, Sli [i .. (i+l)] [j .. (j+k)] refers to:
But besides continuous submatrices of a matrix we can define parts of a matrix less restrictively with lists. Lists allow us
- to define non-continuous parts of a matrix,
- to reorder/permute rows and columns, or
- to have rows and columns appear more than once.
Here is an example: Within a matrix a, Sli [1,7,5,5,13] [1,2,7,1] refers to
Besides Sli there are three more types defined for the following case: If one (or both) of the lists has got only one entry, the yielded slice is one-dimensional and thus some part of a row or of a column or just a single element:
:: Row = Row Int ![Int] :: Col = Col ![Int] Int :: Ele = Ele Int IntWe have to distinguish these one-dimensional slices from the "proper" slices, as operations change depending upon the dimension of the slices involved. We will see how later.
How can I work with slices?
Typically slice operations involve two or three slices. An obvious way to carry out this kind of operation is to cut slices out of their respective matrices (i. e. to copy them). Then the operation itself is performed, resulting in a new matrix or vector, which then has to be embedded into a matrix again.
For large matrices with almost equally large slices this becomes prohibitively expensive in both execution time and storage requirements, due to copying. Therefore we have to exploit uniqueness typing for the matrix we want to embed the resulting slice in. Luckily there are many algorithms in which all involved slices stem from the same matrix. Therefore we provide (among others) two families of functions named sliceXX(X) which take two and three slices along with one or two functions (that define the operation on the elements) and a unique matrix. The Xs indicate which kind of slice is involved and determines the operation. For example
sliceSS :: !Sli (Real Real -> Real) !Sli *Matrix -> *MatrixWe can use sliceSS for instance to add two slices and write its result to the first slice. In MATLAB this can be programmed as
A = ...; A(1:3,1:3) = A(1:3,1:3) + A(4:6,4:6);In Clean using CLAS it looks like this:
a :: .Matrix a = ... Start = sliceSS (Sli [1 .. 3] [1 .. 3]) (+) (Sli [1 .. 3] [4 .. 6]) aThis function overwrites the elements of the first slice with the (elementwise) sum of both slices:
Another very typical application is the outer product of a column and a row slice being add to a slice. In MATLAB again this can be coded as
A(k+1:n,k+1:n) = A(k+1:n,k+1:n) + A(k+1:n,k) * A(k,k+1:n);In Clean using CLAS this is:
a :: .Matrix a = ... Start = sliceSCR (Sli [inc k .. n] [inc k .. n]) (+) (Col [inc k .. n] k) (*) (Row k [inc k .. n]) aAnd again this is the effect on the matrix:
Two issues need special attention:
- The user has to make sure, that the dimensions of the involved slices match.
- The user further has to be aware that overlapping slices are not detected at compile time.
Which slicing functions are available?
- sliceXYZ
This family of functions performs operations of the kind
a <- a * (b o c),
where a,b and c are slices and (*) and (o) are operations on their elements.
Due to the absence of multiple type classes, we have to define a function for each feasible combination of slice types. Along with our four types of slices (Sli, Row, Col, Ele) we also accept the type Vector and the type Matrix to be able to work with external references as well. So there are actually 63 = 216 combinations of types to fill in X, Y and Z in the function sliceXYZ. However not all these combinations are sensible (If you think otherwise, feel free to fill in your definition). The following table shows all combinations we want to provide: The entry at the crossing of a row (the Y) and a column (the Z) is the type of the result (the X):
sliceXYZ Sli Row Col Ele Matrix Vector Sli Sli Sli Sli Row Row Ele Row Row Col Sli Col Col Col Ele Sli Row Col Ele Matrix Sli Sli Vector Row Col Sli, Row,
Col, EleLet us find the entry of the previous example of an outer product: sliceSCR, i. e. Sli, Col and Row. For Col and Row we find Sli, which is the result type. Changing the order to Row and Col we find Ele. So there is another function called sliceERC. It computes some kind of dot product between a Row and a Col and writes it to an Ele.
In the case of two vectors the first letter determines, how the vectors are interpreted.The type Vector does not carry the information of a vector is a column or a row vector. For instance if the two vectors are one row and one column vector, the result is a Sli (sliceSVV), two column vectors result in a Col (sliceCVV).
- sliceXY
The family of functions sliceXY follows pretty much the same idea. The operation is
a <- a * b,
where a and b are slices and (*) is an operation on their elements. Following our convention, that the first slice is used for the result, types Matrix and Vector are not allowed in the first position. The following table shows all defined functions. Notice that the result matches the first slice type.
sliceXY Sli Row Col Ele Matrix Vector Sli Sli Sli Sli Row Row Row Row Col Col Col Col Col Ele Ele
- sliceMipX
The two functions sliceMipC and sliceMipS provide inner products of slices with an external matrix. As the result will be written to the slice, the dimension of the external matrix has to be appropriate.
- imbedX
The functions imbedR, imbedC take a slice and an external vector and imbed the external vector at the place of the slice. The function imbedS takes a slice and a matrix and imbeds the external matrix at the position of the slice.
- cutX
The functions cutR and cutC return vectors with element of a given slice. The functions cutS, cutRM and cutCM return matrices, the latter two a matrix with only one row or column respectively.
- transposeSlice
The function transposeSlice takes a pair of a slice and a matrix and returns such a pair with the matrix and slicing information transposed.
All slicing operations are defined in Slicing, along with sample programs (for Gaussian LU, Householder QR and Givens QR decomposition) in SampleSlice.
function | name | types/remarks |
sliceXYZ | Please refer to the text for more information. | !X (Real Real -> Real) !Y (Real Real -> Real) !Z *Matrix -> *Matrix |
sliceXY | !X (Real Real -> Real) !Y *Matrix -> *Matrix | |
sliceMipX | .Matrix X *Matrix -> *Matrix | |
imbedX | X .Matrix *Matrix -> *Matrix X .Vector *Matrix -> *Matrix |
|
cutX | X .Matrix -> Vector X .Matrix -> .Matrix |
|
transposeSlice | (Sli, .Matrix) -> (Sli, .Matrix) |
function | name | types/remarks |
sliceGauss | LU decomposition | *Matrix -> *Matrix |
sliceCholesky | Cholesky decomposition |
*Matrix -> *Matrix Idea: Decompose a symmetric and positive definite matrix A into A = L LT, where L is a lower left triangular matrix L with positive diagonal
entries. |
solveLSP | solve a least square problem |
*Matrix .Vector -> .Vector Idea: Besides solving linear systems the solution of least square problems is very important. They have the form They can always be solved by applying the Gauss Normal Equation, which yields ATAx = ATb, where (ATA) is symmetric, which is a necessary property to
do e. g. a LU decomposition or a Cholesky decomposition (which is a special case
of the LU decomposition, where A=LTL). As the Cholesky decomposition of a matrix is unique, we can see that the triangular
matrix R is one factor of the Cholesky decomposition of ATA. The QR decomposition can be done in many ways, Householder reflections and Givens rotations are two of them. |
qrHouse | QR decomposition by means of Householder reflections |
*Matrix -> *Matrix From the elements of the matrix indicated with a star the Householder reflection is computed using the function house and applied to the matrix. The function qrHouse overwrites the given matrix with R. |
house | Householder reflection |
.Vector -> .(Vector, Real) Idea: For each non zero vector one can find an orthogonal operation that zeros out all elements except for the first element. This operation is called a Householder reflection. In can be expressed by a matrix P, which is readily given by the so called Householder vector and a scalar: The function house returns the Householder vector and the scalar as a pair. |
qrGivens | QR decomposition by means of Givens rotations | *Matrix -> *Matrix Givens rotations zero out single elements of a matrix (cf. function givens). This can be used for the QR decomposition to obtain an upper right triangular matrix. The function qrGivens overwrites the given matrix with R. |