module ZBlop: sig endBigarray arrays
internally. Unfortunately these are not powerful enough to serve as
matrices because we cannot access arbitrary, but contiguous,
sub-matrices, without a lot of trickery. Psilab got around this by
changing the bigarray code. Unfortunately that change never made it
into the main OCaml distribution. Rather than attempt to change the
Bigarray implementation again I decided to wrap a new matrix
type around the existing Bigarray implementation. This has some
drawbacks. For one, element-by-element operations on matrix types
could be slower than equivalent Bigarray operations, especially
when functors prevent the OCaml compiler from inlining the access
calls. However, this can be overcome by using the function matrix
to efficiently convert native OCaml arrays to matrices, and
performing all element by element operations on native OCaml arrays
instead.type t
t is either float in modules DBlop and SBlop,
or Complex.t in modules ZBlop and CBlop.type precision_elt
float64_elt in DBlop, float32_elt in SBlop,
complex64_elt in ZBlop and complex32_elt in CBlop.type precision_elt_real
float64_elt in modules DBlop and ZBlop, and float32_elt in
modules SBlop and CBlop.val precision : (t, precision_elt) Bigarray.kindBigarray. The usual usage is Array2.create precision
fortran_layout m n.val precision_real : (float, precision_elt_real) Bigarray.kindval machine_epsilon : float10^{-16} in the
DBlop and ZBlop modules, and approximately 10^{-8} in the
SBlop and CBlop modules.val re : t -> floatre z returns the real part of the (possibly) complex number
z.val im : t -> floatim z returns the imaginary part of the (possibly) complex
number z.val conjugate : t -> tconjugate z returns the complex conjugate of the (possibly)
complex number z.val zero : tval one : tval minus_one : tval fromInt : int -> tfromInt n returns either the floating-point version of n or
the Complex.t version of n.val toInt : t -> inttoInt z returns the integer part of the real part of
(possibly) complex number z.val fromFloat : float -> tComplex.t as the case may be.val randn : unit -> trandn () returns a random possibly complex number.val printfn : t -> unitstdout.val addn : t -> t -> tval subn : t -> t -> tval muln : t -> t -> tval mulr : float -> t -> tmulr r z multiplies the possibly complex number z by the
real number r.
With that we are done with generic arithmetic
operators. Please note that t is not a union type. In any
instance t is either float or Complex.t. For example inside
module DBlop the type t always refers to float. Now, on to
the matrix stuff.
type matrix
Array2.t.type transformer = matrix -> unit
transformer encapsulates the most
common type of such functions. Furthermore most algorithms can be
implemented in a manner in which the destination matrix is the
last argument. This enables one to make the code look like the
mathematical specification of the algorithm (not the Matlab
specification). See the tutorial.type transform
transform (not transformer) is a
unitary matrix computed by a call to one of the unitary
factorization routines: Nla.BLOP.ql' or Nla.BLOP.lq'. It can
also be a product of such unitary transforms.type factor
factor is usually the triangular part from
a QL or LQ factorization. This type alone will save you from most
of the bugs encountered when programming on top of Lapack.val ($@) : Nla.BLOP.matrix -> int * int -> Nla.BLOP.ta $@ (i,j) returns the (i,j)-th entry of the matrix a.val (=>) : Nla.BLOP.t -> int * int -> Nla.BLOP.matrix -> unit(x => (i,j)) a has the effect of making a $@
(i,j) be equal to x. This weird syntax is part of the storage passing style I talked about earler, and its use will
become clear soon. Meanwhile, do not use these element-by-element
operations in critical for loops. You might take a speed-hit.val noOfRows : matrix -> intval noOfCols : matrix -> intval printMatrixHeight : int Pervasives.refprintMatrix.val printMatrixWidth : int Pervasives.refprintMatrix.val printMatrix : matrix -> unitstdout.val rawMatrix : int -> int -> matrixrawMatrix m n creates an m by n matrix whose entries are
uninitialized.val consts : t -> int -> int -> matrixconsts x m n creates an m by n matrix with every entry set
to x. See also const.val const : t -> matrix -> unitconst x a sets every entry of the matrix a to x. See also
consts.val zeros : int -> int -> matrixzeros m n creates a m by n zero matrix.val ones : int -> int -> matrixones m n creates a m by n matrix of ones.val randomMatrix : int -> int -> matrixrandomMatrix m n creates a m by n random matrix whose
entries (real and imaginary parts) are uniformly distributed
between -1.0 and 1.0.val fun2mat : (int -> int -> t) -> int -> int -> matrixfun2mat fn m n creates an m by n matrix whose (i,j)-th
entry is fn i j. See also fun2mat'.val fun2mat' : (int -> int -> t) -> matrix -> unitfun2mat' fn a modifies all the entries of the matrix a such
that the (i,j)-th entry becomes fn i j. See also fun2mat.val eye : int -> int -> matrixeye m n returns the top-left m by n submatrix of the max
m n by max m n identity matrix.val matrix : t array array -> matrixmatrix. Element-by-element operations are better done on
regular OCaml arrays.type range =
| |
Range of |
| |
All |
$.val ($) : Nla.BLOP.matrix -> Nla.BLOP.range * Nla.BLOP.range -> Nla.BLOP.matrixval (<->) : int -> int -> Nla.BLOP.rangea $ (sr <-> lr, sc <->
lc) returns the contiguous submatrix of a that includes rows sr
to lr, and columns sc to lc. In Matlab you would have
written this as a(sr:lr,sc:lc). If you write instead a $ (All,
sc <-> lc) then this would be the submatrix of a that includes
all the rows of a, and the columns from sc to
lc. In Matlab this would have been a(::,sc:lc). However, there
is one big difference from Matlab. a $ (sr <-> lr, sc <->
lc) and a share the same storage! Please be careful. The type
system will not keep track of this sharing for you. However, in
CleanFloat the uniqueness type attribute will keep track of
sharing.val partition2x1 : int -> int -> matrix -> matrix * matrixpartition2x1 m1 m2 a
will return the tuple (a1, a2), where, in Matlab notation, a1
is equal to a(1:m1,::) and a2 is equal to
a(m1+1:m1+m2,::). Note the index arithmetic that you must
perform correctly in Matlab. Furthermore, note that in CamlFloat
a1 and a2 share their storage with a, unlike Matlab.val partition1x2 : int -> int -> matrix -> matrix * matrixpartition1x2 n1 n2 a returns the tuple (a1,a2) obtained by
column partitioning a, with first block column a1 having the first
n1 columns, and the second block column a2 having the last
n2 columns. Note that a1 and a2 share storage with a.val partition2x2 : int ->
int ->
int ->
int ->
matrix ->
matrix * matrix * matrix * matrixpartition2x2 n1 n2 m1 m2 a returns the tuple (a11, a12, a21,
a22) obtained by block partitioning a into a 2 by 2 matrix,
with n1 columns in the first column partition and m1 rows in
the first row partition. I usually format the call as follows
partition2x2 n1 n2
m1
m2 a
so that it looks more like the mathematical notation.val partition1x3 : int ->
int ->
int -> matrix -> matrix * matrix * matrixpartition1x3 n1 n2 n3 a returns (a1,a2,a3) obtained by
doing a 1 by 3 block column partition of a.val partition3x1 : int ->
int ->
int -> matrix -> matrix * matrix * matrixpartition3x1 m1 m2 m3 a returns (a1,a2,a3) obtained by doing
a 3 by 1 block row partition of a.val partition3x3 : int ->
int ->
int ->
int ->
int ->
int ->
matrix ->
matrix * matrix * matrix * matrix *
matrix * matrix * matrix * matrix *
matrixpartition3x3 n1 n2 n3 m1 m2 m3 a returns
(a11,a12,a13,a21,a22,a23,a31,a32,a33) obtained by doing a 3 by 3
block partitioning of a. I usually format the call as
partition3x3 n1 n2 n3
m1
m2
m3 a
so that it looks more like the mathematical notation.val partitionInfx1 : int list -> matrix -> matrix listpartitionInfx1 ms a returns a list of block row
partitions of a, where the number of rows in the i-th
partition is determined by the number in the i-th position in
the list ms.val partition1xInf : int list -> matrix -> matrix listpartition1xInf ns a returns a list of block column partitions
of a, where the number of columns in the j-th partition is
determined by the number in the j-th position in the list ns.val partitionNx1 : int array -> matrix -> matrix arraypartitionNx1 ms a is identical to partitionInfx1 ms a,
except tha ms must be an array now.val partition1xN : int array -> matrix -> matrix arraypartition1xN ns a is identical to partition1xInf ns a,
except that ns must be an array now.val ooo : matrix -> unitooo is a nop. Very useful for subsequent
functions.val matrix2x1 : int ->
transformer ->
int -> transformer -> matrix -> unitmatrix2x1 m1 a1 m2 a2 a modifies the entries of the matrix
a, by applying the function (transformer) a1 to a $ (1<->
m1, All) and the transformer a2 to a $ (m1+1 <-> m1+m1,
All). I usually format the call as
matrix2x1 m1 a1
m2 a2 a
so that it looks more like the mathematical notation. If you
use a higher-order style of programming you can even drop the last
argument, the destination matrix a, from the call, and make it
look even more like the mathematical notation. See the tutorial
for a good example of this style. Again observe how this call
saves you from index gymnastics.val matrix3x1 : int ->
transformer ->
int ->
transformer ->
int -> transformer -> matrix -> unitmatrix3x1 m1 a1 m2 a2 m3 a3 a modifies the entries of a by
first applying the transformer a1 to the first block row of the 3 by
1 block row partitioning of a, then applying the transformer
a2 to the second block row partition of a, and so on. I
usually format the call a bit more suggestively as
matrix3x1 m1 a1
m2 a2
m3 a3 a
so that it looks more like the mathematical notation.val matrix1x2 : int ->
int ->
transformer -> transformer -> matrix -> unitmatrix1x2 n1 n2 a1 a2 a modifies the entries of a by
applying the two transformers a1 and a2 to the two block
column partitions of a. Please observe that matrix1x2 has a
very different type from matrix2x1. This is so that I can format
the call as
matrix1x2 n1 n2
a1 a2 a
so that it looks more like the mathematical notation.val matrix1x3 : int ->
int ->
int ->
transformer ->
transformer -> transformer -> matrix -> unitmatrix1x3 n1 n2 n3 a1 a2 a3 a modifies the entries of the
matrix a by applying the transformers a1, a2 and a3 to
the corresponding block column partitions of a. Note that
matrix1x3 has a different type from matrix3x1. This is so that
I can format the call as
matrix1x3 n1 n2 n3
a1 a2 a3 a
so that it looks more like the mathematical notation.val matrix2x2 : int ->
int ->
int ->
transformer ->
transformer ->
int ->
transformer -> transformer -> matrix -> unitmatrix2x2 n1 n2 m1 a11 a12 m2 a21 a22 a modifies the entries
of the matrix a by applying the transformers a11, a12,
a21 and a22 to the corresponding sub-matrices of a obtained
by a block 2 by 2 partitioning. I usually format the call as
matrix2x2 n1 n2
m1 a11 a12
m2 a21 a22 a
so that it looks more like the mathematical notation.val matrix2x3 : int ->
int ->
int ->
int ->
transformer ->
transformer ->
transformer ->
int ->
transformer ->
transformer -> transformer -> matrix -> unitmatrix2x3 n1 n2 n3 m1 a11 a12 a13 m2 a21 a22 a23 a modifies
the entries of the matrix a by applying the transformers
a11, a12, a13, a21, a22 and a23 to the corresponding
sub-matrices of
a obtained by a block 2 by 3 partitioning. I usually format the
call as
matrix2x3 n1 n2 n3
m1 a11 a12 a13
m2 a21 a22 a23 a
so that it looks more like the mathematical notation.val matrix4x2 : int ->
int ->
int ->
transformer ->
transformer ->
int ->
transformer ->
transformer ->
int ->
transformer ->
transformer ->
int ->
transformer -> transformer -> matrix -> unitmatrix4x2 n1 n2 m1 a11 a12 m2 a21 a22 m3 a31 a32 m4 a41 a42 a
modifies the entries
of the matrix a by applying the transformers aij to
the corresponding sub-matrices of a obtained
by a block 4 by 2 partitioning. I usually format the call as
matrix4x2 n1 n2
m1 a11 a12
m2 a21 a22
m3 a31 a32
m4 a41 a42 a
so that it looks more like the mathematical notation.val matrixInfx1 : int list -> transformer list -> matrix -> unitmatrixInfx1 ms ais a applies the transformers in the list
ais to the corresponding row partitions of a as determined by
the block sizes in the list ms.val copy : matrix -> matrix$ operator produces sub-matrices that share storage
with the parent matrix, we need a way to make copies of
matrices. copy a produces a copy of the matrix a such that
they do not share storage.val iD : matrix -> matrix -> unitiD a b replaces the contents of the matrix b with that of
a.val ($=>) : Nla.BLOP.matrix -> Nla.BLOP.range * Nla.BLOP.range -> Nla.BLOP.matrix -> unit(a $=> (sr<->lr,sc<->lc)) b will replace the contents of b $
(sr<->lc,sc<->lc) with that of a.val (<-|) : Nla.BLOP.matrix -> Nla.BLOP.transformer -> unit<-|. Therefore instead of
iD a b you can say b <-| (iD a). This is not needed, however,
if you use the matrixXxY functions.val (<-$) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a $=> (sr<->lr,All)) b can
now write (b $ (sr<->lr,All)) <-$ a instead. In other words, if
you don't like my notation, define your own! After all this is
OCaml.matrix2x2 for example. Some of the operator notation
might take some getting used to. I find them logical and
convenient. If you disagree just define your own notation.val (|+|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |+| b) c will replace the contents of c with that of a +
b.val (|-|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |-| b) c will replace the contents of c with that of a -
b.val (|++|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> unita |++| b will replace the contents of b with that of a + b.val (|--|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> unita |--| b will replace the contents of b with that of b - a.val (+$) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrixa +$ b returns a new matrix whose entries are those of a +
b.val (-$) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrixa -$ b returns a new matrix whose entries are those of a -
b.val transp : matrix -> matrixtransp a returns a new matrix formed by conjugate-transposing
a.val transp' : matrix -> matrix -> unittransp' a b replaces the contents of b with the
conjugate-transpose of a.val conjg' : matrix -> unitconjg' a replaces the entries of a by their conjugates.val (|*|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |*| b) c will replace the contents of c with that of a *
b.val (|*~|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |*~| b) c will replace the contents of c with that of a *$
transp b. Note that we use ~ to denote transposition and that
it is attached to the operator rather than the argument.val (|~*|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |~*| b) c will replace the contents of c with that of
transp a *$ b. Note that we use ~ to denote transposition and that
it is attached to the operator rather than the argument. Also note
that the position of ~ tells you to which argument the transpose
is attached.val (*$) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrixa *$ b will create a new matrix with the contents of a * b.val (*~$) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrixa *~$ b will create a new matrix with the contents of transp
a *$ b.val (*$~) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrixa *$~ b will create a new matrix with the contents of a *$
transp b.val (|*++|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |*++| b) c will replace the contents of c with that of c + a * b.val (|*--|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |*--| b) c will replace the contents of c with that of c - a * b.val (|*~++|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |*~++| b) c will replace the contents of c with that of
c + a * transp b.val (|*~--|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |*~--| b) c will replace the contents of c with that of a *
b.val (|~*++|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |~*++| b) c will replace the contents of c with that of
c + transp a * b.val (|~*--|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit(a |~*--| b) c will replace the contents of c with that of
c - transp a * b.val norm1 : matrix -> floatnorm1 a returns the 1-norm of a.val normInf : matrix -> floatnormInf a returns the infinity-norm of a.val normF : matrix -> floatnormF a returns the Frobenius-norm of a.val normMax : matrix -> floatnormMax a returns the largest entry of a in magnitude.val lq' : matrix -> factor * transformlq' a computes the LQ factorization of a. Note that a is
destroyed and its internal storage re-used for the returned l
and q. Any extant sub-matrices of a will be rendered
useless. You have been warned.val ql' : matrix -> transform * factorql' a computes the QL factorization of a. The contents of
a are destroyed and its storage is used to hold a and l.val copyL : factor -> matrixfactor l computed from ql' or lq', copyL l
returns a lower-triangular (or lower-trapezoidal) matrix that is
equivalent to l. Many bugs in the usage of Lapack can be traced
to this one operation.val iDL : factor -> matrix -> unitl factor computed using ql' or lq', iDL l a
copies the lower-trianglar (or lower-trapezoidal) part of l into
a.val (@*) : Nla.BLOP.transform -> Nla.BLOP.matrix -> unitq @* a applies a transform q to the matrix a changing
its contents.val (@~*) : Nla.BLOP.transform -> Nla.BLOP.matrix -> unitq @~* a applies the conjugate-transpose of the transform q
to the matrix a, changing its contents. Note again that the
transpose symbol ~ is attached to the operator rather than the
argument. In any operation involving transforms the transpose
symbol is always attached to the transform, not the matrix
argument. This is not a short-coming.val (*@) : Nla.BLOP.matrix -> Nla.BLOP.transform -> unita *@ q applies the transform q to the matrix a from
the right, changing its contents.val (*~@) : Nla.BLOP.matrix -> Nla.BLOP.transform -> unita *~@ q applies the conjugate-transpose of the transform q
to the matrix a from the right, changing its contents.val subs' : factor -> matrix -> unitsubs' l b replaces the contents of the matrix b by
l-1b. It assumes that l is a square lower-triangular
matrix. That is, if l is lower-trapezoidal you will get a
run-time error.val subsT' : factor -> matrix -> unitsubsT' l b replaces the contents of the matrix b with that
of (transpose l)-1b. It assumes that l is a square
lower-triangular factor. Otherwise you will get a run-tim
error.val (|/|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> unita |/| b replaces the contents of the matrix b by the
contents of the minimum-norm least-squares solution of the system of
linear equations ax = b. In the process the contents of the
matrix a are also destroyed. If a is a fat m by n (m <
n) matrix, then the matrix b must have n rows, and initially
the actual contents of the right-hand side must lie in the first
m rows. On the other hand, if a is a skinny m by n (m >
n) matrix, then the least-squares solution will be found in the
first n rows of b after the call returns.val (|~/|) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> unit|/|, except that the
system being solved now is (transp a)x=b.val (/$) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrixa /$ b returns a new matrix obtained by applying the
pseudo-inverse of a to b.val (/~$) : Nla.BLOP.matrix -> Nla.BLOP.matrix -> Nla.BLOP.matrixa /~$ b returns a new matrix obtained by applying the
pseudo-inverse of the conjugate-transpose of a to b.val scale' : t -> matrix -> unitscale' x a multiplies every entry of a in place by x.val rowScale' : (t, precision_elt, Bigarray.fortran_layout)
Bigarray.Array1.t -> matrix -> unitrowScale' x a scales every row of a in place by the
corresponding entry in x.val colScale' : matrix ->
(t, precision_elt, Bigarray.fortran_layout)
Bigarray.Array1.t -> unitcolScale' a x scales every column of a in place by the
corresponding entry in x.val scale_real' : float -> matrix -> unitscale' except that first argument must be a real
number.val rowScale_real' : (float, precision_elt_real, Bigarray.fortran_layout)
Bigarray.Array1.t -> matrix -> unitrowScale' except that the first argument must be a
real array. Useful for SVDs of complex matrices.val colScale_real' : matrix ->
(float, precision_elt_real, Bigarray.fortran_layout)
Bigarray.Array1.t -> unitcolScale' except that the second argument must be a
real array. Useful for SVDs of complex matrices.val svd' : matrix ->
matrix *
(float, precision_elt_real, Bigarray.fortran_layout)
Bigarray.Array1.t * matrixsvd' a returns the economy SVD of a, destroying its contents
in the process.val svdL' : matrix ->
matrix *
(float, precision_elt_real, Bigarray.fortran_layout)
Bigarray.Array1.tsvdL' a is identical svd' a except that the right singular
vectors are not calculated.val svdR' : matrix ->
(float, precision_elt_real, Bigarray.fortran_layout)
Bigarray.Array1.t * matrixsvdR' a is identical to svd' a except that the left singular
vectors are not calculated.val singValues' : matrix ->
(float, precision_elt_real, Bigarray.fortran_layout)
Bigarray.Array1.tsingValues' a is identical to svd' a except that the none of
the singular vectors are computed.val cond : matrix -> floatcond a returns the 2-norm condition number of the matrix a.