protected:
void Allocate(Int_t nrows, Int_t ncols, Int_t row_lwb = 0, Int_t col_lwb = 0)
void AMultB(const TMatrix& a, const TMatrix& b)
void AtMultB(const TMatrix& a, const TMatrix& b)
void EigenSort(TMatrix& eigenVectors, TVector& eigenValues)
void Invalidate()
void Invert(const TMatrix& m)
void InvertPosDef(const TMatrix& m)
void MakeEigenVectors(TVector& d, TVector& e, TMatrix& z)
void MakeTridiagonal(TMatrix& a, TVector& d, TVector& e)
Int_t Pdcholesky(const Real_t* a, Real_t* u, const Int_t n)
void Transpose(const TMatrix& m)
public:
TMatrix TMatrix()
TMatrix TMatrix(Int_t nrows, Int_t ncols)
TMatrix TMatrix(Int_t row_lwb, Int_t row_upb, Int_t col_lwb, Int_t col_upb)
TMatrix TMatrix(Int_t nrows, Int_t ncols, const Float_t* elements, Option_t* option)
TMatrix TMatrix(Int_t row_lwb, Int_t row_upb, Int_t col_lwb, Int_t col_upb, const Float_t* elements, Option_t* option)
TMatrix TMatrix(const TMatrix& another)
TMatrix TMatrix(TMatrix::EMatrixCreatorsOp1 op, const TMatrix& prototype)
TMatrix TMatrix(const TMatrix& a, TMatrix::EMatrixCreatorsOp2 op, const TMatrix& b)
TMatrix TMatrix(const TLazyMatrix& lazy_constructor)
TMatrix EigenVectors(TVector& eigenValues)
virtual void ~TMatrix()
TMatrix& Abs()
TMatrix& Apply(TElementAction& action)
TMatrix& Apply(TElementPosAction& action)
static TClass* Class()
Double_t ColNorm() const
Double_t Determinant() const
virtual void Draw(Option_t* option)
Double_t E2Norm() const
Int_t GetColLwb() const
Int_t GetColUpb() const
Float_t* GetElements()
void GetElements(Float_t* elements, Option_t* option) const
Int_t GetNcols() const
Int_t GetNoElements() const
Int_t GetNrows() const
Int_t GetRowLwb() const
Int_t GetRowUpb() const
TMatrix& HilbertMatrix()
TMatrix& Invert(Double_t* determ_ptr = 0)
TMatrix& InvertPosDef()
virtual TClass* IsA() const
Bool_t IsSymmetric() const
Bool_t IsValid() const
TMatrix& MakeSymmetric()
void Mult(const TMatrix& a, const TMatrix& b)
Double_t Norm1() const
TMatrix& NormByColumn(const TVector& v, Option_t* option = "D")
TMatrix& NormByDiag(const TVector& v, Option_t* option = "D")
TMatrix& NormByRow(const TVector& v, Option_t* option = "D")
Double_t NormInf() const
Bool_t operator!=(Real_t val) const
const Real_t& operator()(Int_t rown, Int_t coln) const
Real_t& operator()(Int_t rown, Int_t coln)
TMatrix& operator*=(Double_t val)
TMatrix& operator*=(const TMatrix& source)
TMatrix& operator*=(const TMatrixDiag& diag)
TMatrix& operator*=(const TMatrixRow& diag)
TMatrix& operator*=(const TMatrixColumn& diag)
TMatrix& operator+=(Double_t val)
TMatrix& operator-=(Double_t val)
TMatrix& operator/=(const TMatrixDiag& diag)
TMatrix& operator/=(const TMatrixRow& diag)
TMatrix& operator/=(const TMatrixColumn& diag)
Bool_t operator<(Real_t val) const
Bool_t operator<=(Real_t val) const
TMatrix& operator=(const TMatrix& source)
TMatrix& operator=(const TLazyMatrix& source)
TMatrix& operator=(Real_t val)
Bool_t operator==(Real_t val) const
Bool_t operator>(Real_t val) const
Bool_t operator>=(Real_t val) const
const TMatrixRow operator[](Int_t rown) const
TMatrixRow operator[](Int_t rown)
virtual void Print(Option_t* option) const
void ResizeTo(Int_t nrows, Int_t ncols)
void ResizeTo(Int_t row_lwb, Int_t row_upb, Int_t col_lwb, Int_t col_upb)
void ResizeTo(const TMatrix& m)
Double_t RowNorm() const
void SetElements(const Float_t* elements, Option_t* option)
virtual void ShowMembers(TMemberInspector& insp, char* parent)
TMatrix& Sqr()
TMatrix& Sqrt()
virtual void Streamer(TBuffer& b)
void StreamerNVirtual(TBuffer& b)
TMatrix& UnitMatrix()
TMatrix& Zero()
protected:
Int_t fNrows number of rows
Int_t fNcols number of columns
Int_t fNelems number of elements in matrix
Int_t fRowLwb lower bound of the row index
Int_t fColLwb lower bound of the col index
Real_t* fElements [fNelems] elements themselves
Real_t** fIndex ! index[i] = &matrix(0,i) (col index)
public:
static const TMatrix::EMatrixCreatorsOp1 kZero
static const TMatrix::EMatrixCreatorsOp1 kUnit
static const TMatrix::EMatrixCreatorsOp1 kTransposed
static const TMatrix::EMatrixCreatorsOp1 kInverted
static const TMatrix::EMatrixCreatorsOp1 kInvertedPosDef
static const TMatrix::EMatrixCreatorsOp2 kMult
static const TMatrix::EMatrixCreatorsOp2 kTransposeMult
static const TMatrix::EMatrixCreatorsOp2 kInvMult
static const TMatrix::EMatrixCreatorsOp2 kInvPosDefMult
static const TMatrix::EMatrixCreatorsOp2 kAtBA
Linear Algebra Package
The present package implements all the basic algorithms dealing
with vectors, matrices, matrix columns, rows, diagonals, etc.
Matrix elements are arranged in memory in a COLUMN-wise
fashion (in FORTRAN's spirit). In fact, it makes it very easy to
feed the matrices to FORTRAN procedures, which implement more
elaborate algorithms.
Unless otherwise specified, matrix and vector indices always start
with 0, spanning up to the specified limit-1. However, there are
constructors to which one can specify aribtrary lower and upper
bounds, e.g. TMatrix m(1,10,1,5) defines a matrix that ranges, and
that can be addresses, from 1..10, 1..5 (a(1,1)..a(10,5)).
The present package provides all facilities to completely AVOID
returning matrices. Use "TMatrix A(TMatrix::kTransposed,B);" and
other fancy constructors as much as possible. If one really needs
to return a matrix, return a TLazyMatrix object instead. The
conversion is completely transparent to the end user, e.g.
"TMatrix m = THaarMatrix(5);" and _is_ efficient.
Since TMatrix et al. are fully integrated in ROOT they of course
can be stored in a ROOT database.
How to efficiently use this package
-----------------------------------
1. Never return complex objects (matrices or vectors)
Danger: For example, when the following snippet:
TMatrix foo(int n)
{
TMatrix foom(n,n); fill_in(foom); return foom;
}
TMatrix m = foo(5);
runs, it constructs matrix foo:foom, copies it onto stack as a
return value and destroys foo:foom. Return value (a matrix)
from foo() is then copied over to m (via a copy constructor),
and the return value is destroyed. So, the matrix constructor is
called 3 times and the destructor 2 times. For big matrices,
the cost of multiple constructing/copying/destroying of objects
may be very large. *Some* optimized compilers can cut down on 1
copying/destroying, but still it leaves at least two calls to
the constructor. Note, TLazyMatrices (see below) can construct
TMatrix m "inplace", with only a _single_ call to the
constructor.
2. Use "two-address instructions"
"void TMatrix::operator += (const TMatrix &B);"
as much as possible.
That is, to add two matrices, it's much more efficient to write
A += B;
than
TMatrix C = A + B;
(if both operand should be preserved,
TMatrix C = A; C += B;
is still better).
3. Use glorified constructors when returning of an object seems
inevitable:
"TMatrix A(TMatrix::kTransposed,B);"
"TMatrix C(A,TMatrix::kTransposeMult,B);"
like in the following snippet (from $ROOTSYS/test/vmatrix.cxx)
that verifies that for an orthogonal matrix T, T'T = TT' = E.
TMatrix haar = THaarMatrix(5);
TMatrix unit(TMatrix::kUnit,haar);
TMatrix haar_t(TMatrix::kTransposed,haar);
TMatrix hth(haar,TMatrix::kTransposeMult,haar);
TMatrix hht(haar,TMatrix::kMult,haar_t);
TMatrix hht1 = haar; hht1 *= haar_t;
VerifyMatrixIdentity(unit,hth);
VerifyMatrixIdentity(unit,hht);
VerifyMatrixIdentity(unit,hht1);
4. Accessing row/col/diagonal of a matrix without much fuss
(and without moving a lot of stuff around):
TMatrix m(n,n); TVector v(n); TMatrixDiag(m) += 4;
v = TMatrixRow(m,0);
TMatrixColumn m1(m,1); m1(2) = 3; // the same as m(2,1)=3;
Note, constructing of, say, TMatrixDiag does *not* involve any
copying of any elements of the source matrix.
5. It's possible (and encouraged) to use "nested" functions
For example, creating of a Hilbert matrix can be done as follows:
void foo(const TMatrix &m)
{
TMatrix m1(TMatrix::kZero,m);
struct MakeHilbert : public TElementPosAction {
void Operation(Real_t &element) { element = 1./(fI+fJ-1); }
};
m1.Apply(MakeHilbert());
}
of course, using a special method TMatrix::HilbertMatrix() is
still more optimal, but not by a whole lot. And that's right,
class MakeHilbert is declared *within* a function and local to
that function. It means one can define another MakeHilbert class
(within another function or outside of any function, that is, in
the global scope), and it still will be OK. Note, this currently
is not yet supported by the interpreter CINT.
Another example is applying of a simple function to each matrix
element:
void foo(TMatrix &m, TMatrix &m1)
{
typedef double (*dfunc_t)(double);
class ApplyFunction : public TElementAction {
dfunc_t fFunc;
void Operation(Real_t &element) { element=fFunc(element); }
public:
ApplyFunction(dfunc_t func):fFunc(func) {}
};
ApplyFunction x(TMath::Sin);
m.Apply(x);
}
Validation code $ROOTSYS/test/vmatrix.cxx and vvector.cxx contain
a few more examples of that kind.
6. Lazy matrices: instead of returning an object return a "recipe"
how to make it. The full matrix would be rolled out only when
and where it's needed:
TMatrix haar = THaarMatrix(5);
THaarMatrix() is a *class*, not a simple function. However
similar this looks to a returning of an object (see note #1
above), it's dramatically different. THaarMatrix() constructs a
TLazyMatrix, an object of just a few bytes long. A
"TMatrix(const TLazyMatrix &recipe)" constructor follows the
recipe and makes the matrix haar() right in place. No matrix
element is moved whatsoever!
The implementation is based on original code by
Oleg E. Kiselyov (oleg@pobox.com).
Allocate new matrix. Arguments are number of rows, columns, row lowerbound (0 default) and column lowerbound (0 default).
TMatrix destructor.
Draw this matrix using an intermediate histogram The histogram is named "TMatrix" by default and no title
Erase the old matrix and create a new one according to new boundaries with indexation starting at 0.
Erase the old matrix and create a new one according to new boudaries.
Create a matrix applying a specific operation to the prototype. Example: TMatrix a(10,12); ...; TMatrix b(TMatrix::kTransposed, a); Supported operations are: kZero, kUnit, kTransposed, kInverted and kInvertedPosDef.
Create a matrix applying a specific operation to two prototypes. Example: TMatrix a(10,12), b(12,5); ...; TMatrix c(a, TMatrix::kMult, b); Supported operations are: kMult (a*b), kTransposeMult (a'*b), kInvMult,kInvPosDefMult (a^(-1)*b) and kAtBA (a'*b*a).
symmetrize matrix (matrix needs to be a square one).
make a unit matrix (matrix need not be a square one). The matrix is traversed in the natural (that is, column by column) order.
Make a Hilbert matrix. Hilb[i,j] = 1/(i+j-1), i,j=1...max, OR Hilb[i,j] = 1/(i+j+1), i,j=0...max-1 (matrix need not be a square one). The matrix is traversed in the natural (that is, column by column) order.
Take an absolute value of a matrix, i.e. apply Abs() to each element.
Square each element of the matrix.
Take square root of all elements.
Apply action to each element of the matrix. In action the location of the current element is known. The matrix is traversed in the natural (that is, column by column) order.
Row matrix norm, MAX{ SUM{ |M(i,j)|, over j}, over i}.
The norm is induced by the infinity vector norm.
Column matrix norm, MAX{ SUM{ |M(i,j)|, over i}, over j}.
The norm is induced by the 1 vector norm.
Square of the Euclidian norm, SUM{ m(i,j)^2 }.
b(i,j) = a(i,j)/sqrt(abs*(v(i)*v(j)))
Multiply/divide a matrix columns with a vector: matrix(i,j) *= v(i)
Multiply/divide a matrix row with a vector: matrix(i,j) *= v(j)
Print the matrix as a table of elements (zeros are printed as dots).
Transpose a matrix.
The most general (Gauss-Jordan) matrix inverse This method works for any matrix (which of course must be square and non-singular). Use this method only if none of specialized algorithms (for symmetric, tridiagonal, etc) matrices isn't applicable/available. Also, the matrix to invert has to be _well_ conditioned: Gauss-Jordan eliminations (even with pivoting) perform poorly for near-singular matrices (e.g., Hilbert matrices). The method inverts matrix inplace and returns the determinant if determ_ptr was specified as not 0. Determinant will be exactly zero if the matrix turns out to be (numerically) singular. If determ_ptr is 0 and matrix happens to be singular, throw up. The algorithm perform inplace Gauss-Jordan eliminations with full pivoting. It was adapted from my Algol-68 "translation" (ca 1986) of the FORTRAN code described in Johnson, K. Jeffrey, "Numerical methods in chemistry", New York, N.Y.: Dekker, c1980, 503 pp, p.221 Note, since it's much more efficient to perform operations on matrix columns rather than matrix rows (due to the layout of elements in the matrix), the present method implements a "transposed" algorithm.
Allocate new matrix and set it to inv(m).
Program Pdcholesky inverts a positiv definite (n x n) - matrix A, using the Cholesky decomposition Input: a - (n x n)- Matrix A n - dimensions n of matrices Output: u - (n x n)- Matrix U so that U^T . U = A return - 0 decomposition succesful - 1 decomposition failed
Allocate new matrix and set it to inv(m).
Return a matrix containing the eigen-vectors; also fill the supplied vector with the eigen values.
The comments in this algorithm are modified version of those in
"Numerical ...". Please refer to that book (web-page) for more on
the algorithm.
/*
PRIVATE METHOD:
The basic idea is to perform
orthogonal transformation, where
each transformation eat away the off-diagonal elements, except the
inner most.
*/
/*
PRIVATE METHOD:
The basic idea is to find matrices
and
so that
, where
is orthogonal and
is lower triangular. The QL algorithm
consist of a
sequence of orthogonal transformations
*/
/*
PRIVATE METHOD:
*/
General matrix multiplication. Create a matrix C such that C = A * B. Note, matrix C needs to be allocated.
Compute C = A*B. The same as AMultB(), only matrix C is already allocated, and it is *this.
Create a matrix C such that C = A' * B. In other words,
c[i,j] = SUM{ a[k,i] * b[k,j] }. Note, matrix C needs to be allocated.
Compute the determinant of a general square matrix. Example: Matrix A; Double_t A.Determinant(); Gauss-Jordan transformations of the matrix with a slight modification to take advantage of the *column*-wise arrangement of Matrix elements. Thus we eliminate matrix's columns rather than rows in the Gauss-Jordan transformations. Note that determinant is invariant to matrix transpositions. The matrix is copied to a special object of type TMatrixPivoting, where all Gauss-Jordan eliminations with full pivoting are to take place.
Stream an object of class TMatrix.
option="F": array elements contains the matrix stored column-wise
like in Fortran, so a[i,j] = elements[i+no_rows*j],
else it is supposed that array elements are stored row-wise
a[i,j] = elements[i*no_cols+j]
void Invalidate()
TMatrix TMatrix(const TLazyMatrix& lazy_constructor)
Int_t GetRowLwb() const
Int_t GetRowUpb() const
Int_t GetNrows() const
Int_t GetColLwb() const
Int_t GetColUpb() const
Int_t GetNcols() const
Int_t GetNoElements() const
void GetElements(Float_t* elements, Option_t* option) const
const Real_t& operator()(Int_t rown, Int_t coln) const
Real_t& operator()(Int_t rown, Int_t coln)
const TMatrixRow operator[](Int_t rown) const
TMatrixRow operator[](Int_t rown)
TMatrix& operator=(const TMatrix& source)
TMatrix& operator=(const TLazyMatrix& source)
TMatrix& operator=(Real_t val)
TMatrix& operator-=(Double_t val)
TMatrix& operator+=(Double_t val)
TMatrix& operator*=(Double_t val)
Bool_t operator==(Real_t val) const
Bool_t operator!=(Real_t val) const
Bool_t operator<(Real_t val) const
Bool_t operator<=(Real_t val) const
Bool_t operator>(Real_t val) const
Bool_t operator>=(Real_t val) const
TMatrix& operator*=(const TMatrix& source)
TMatrix& operator*=(const TMatrixDiag& diag)
TMatrix& operator/=(const TMatrixDiag& diag)
TMatrix& operator*=(const TMatrixRow& diag)
TMatrix& operator/=(const TMatrixRow& diag)
TMatrix& operator*=(const TMatrixColumn& diag)
TMatrix& operator/=(const TMatrixColumn& diag)
Double_t NormInf() const
Double_t Norm1() const
TClass* Class()
TClass* IsA() const
void ShowMembers(TMemberInspector& insp, char* parent)
void StreamerNVirtual(TBuffer& b)