Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
SMatrix.h
Go to the documentation of this file.
1 // @(#)root/smatrix:$Id$
2 // Author: T. Glebe, L. Moneta, J. Palacios 2005
3 
4 #ifndef ROOT_Math_SMatrix
5 #define ROOT_Math_SMatrix
6 
7 /*********************************************************************************
8 //
9 // source:
10 //
11 // type: source code
12 //
13 // created: 20. Mar 2001
14 //
15 // author: Thorsten Glebe
16 // HERA-B Collaboration
17 // Max-Planck-Institut fuer Kernphysik
18 // Saupfercheckweg 1
19 // 69117 Heidelberg
20 // Germany
21 // E-mail: T.Glebe@mpi-hd.mpg.de
22 //
23 // Description: A fixed size two dimensional Matrix class
24 //
25 // changes:
26 // 20 Mar 2001 (TG) creation
27 // 21 Mar 2001 (TG) added operators +=, -=, *=, /=
28 // 26 Mar 2001 (TG) place_in_row(), place_in_col() added
29 // 02 Apr 2001 (TG) non-const Array() added
30 // 03 Apr 2001 (TG) invert() added
31 // 07 Apr 2001 (TG) CTOR from SVertex (dyadic product) added
32 // 09 Apr 2001 (TG) CTOR from array added
33 // 11 Apr 2001 (TG) rows(), cols(), size() replaced by rows, cols, size
34 // 25 Mai 2001 (TG) row(), col() added
35 // 04 Sep 2001 (TG) moved inlined functions to .icc file
36 // 11 Jan 2002 (TG) added operator==(), operator!=()
37 // 14 Jan 2002 (TG) added more operator==(), operator!=(), operator>(), operator<()
38 //
39 ***************************************************************************/
40 // for platform specific configurations
41 
42 #include "Math/MConfig.h"
43 
44 #include <iosfwd>
45 
46 
47 
48 
49 //doxygen tag
50 
51 /**
52  @defgroup SMatrixGroup SMatrix
53  @ingroup Math
54 
55  \ref SMatrixPage for high performance vector and matrix computations.
56  Classes representing Matrices and Vectors of arbitrary type and dimension and related functions.
57  For a detailed description and usage examples see:
58  <ul>
59  <li>\ref SMatrixPage home page
60  <li>\ref SVectorDoc
61  <li>\ref SMatrixDoc
62  <li>\ref MatVecFunctions
63  </ul>
64 
65 
66 */
67 
68 /**
69  @defgroup SMatrixSVector Matrix and Vector classes
70 
71  @ingroup SMatrixGroup
72 
73  Classes representing Matrices and Vectors of arbitrary type and dimension.
74  For a detailed description and usage examples see:
75  <ul>
76  <li>\ref SVectorDoc
77  <li>\ref SMatrixDoc
78  <li>\ref MatVecFunctions
79  </ul>
80 
81 */
82 
83 
84 #include "Math/Expression.h"
86 
87 
88 namespace ROOT {
89 
90 namespace Math {
91 
92 
93 template <class T, unsigned int D> class SVector;
94 
95 struct SMatrixIdentity { };
96 struct SMatrixNoInit { };
97 
98 //__________________________________________________________________________
99 /**
100  SMatrix: a generic fixed size D1 x D2 Matrix class.
101  The class is template on the scalar type, on the matrix sizes:
102  D1 = number of rows and D2 = number of columns
103  amd on the representation storage type.
104  By default the representation is MatRepStd<T,D1,D2> (standard D1xD2 of type T),
105  but it can be of type MatRepSym<T,D> for symmetric matrices DxD, where the storage is only
106  D*(D+1)/2.
107 
108  See \ref SMatrixDoc.
109 
110  Original author is Thorsten Glebe
111  HERA-B Collaboration, MPI Heidelberg (Germany)
112 
113  @ingroup SMatrixSVector
114 
115  @authors T. Glebe, L. Moneta and J. Palacios
116 */
117 //==============================================================================
118 // SMatrix: column-wise storage
119 //==============================================================================
120 template <class T,
121  unsigned int D1,
122  unsigned int D2 = D1,
123  class R=MatRepStd<T, D1, D2> >
124 class SMatrix {
125 public:
126  /** @name --- Typedefs --- */
127 
128  /** contained scalar type */
129  typedef T value_type;
130 
131  /** storage representation type */
132  typedef R rep_type;
133 
134  /** STL iterator interface. */
135  typedef T* iterator;
136 
137  /** STL const_iterator interface. */
138  typedef const T* const_iterator;
139 
140 
141 
142  /** @name --- Constructors and Assignment --- */
143 
144  /**
145  Default constructor:
146  */
147  SMatrix();
148  ///
149  /**
150  construct from without initialization
151  */
152  inline SMatrix( SMatrixNoInit ){}
153 
154  /**
155  construct from an identity matrix
156  */
157  SMatrix( SMatrixIdentity );
158  /**
159  copy constructor (from a matrix of the same representation
160  */
161  SMatrix(const SMatrix<T,D1,D2,R>& rhs);
162  /**
163  construct from a matrix with different representation.
164  Works only from symmetric to general and not viceversa.
165  */
166  template <class R2>
167  SMatrix(const SMatrix<T,D1,D2,R2>& rhs);
168 
169  /**
170  Construct from an expression.
171  In case of symmetric matrices does not work if expression is of type general
172  matrices. In case one needs to force the assignment from general to symmetric, one can use the
173  ROOT::Math::AssignSym::Evaluate function.
174  */
175  template <class A, class R2>
176  SMatrix(const Expr<A,T,D1,D2,R2>& rhs);
177 
178 
179  /**
180  Constructor with STL iterator interface. The data will be copied into the matrix
181  \param begin start iterator position
182  \param end end iterator position
183  \param triang if true only the triangular lower/upper part of the matrix is filled from the iterators
184  \param lower if true the lower triangular part is filled
185 
186  Size of the matrix must match size of the iterators, if triang is false, otherwise the size of the
187  triangular block. In the case of symmetric matrices triang is considered always to be true
188  (what-ever the user specifies) and the size of the iterators must be equal to the size of the
189  triangular block, which is the number of independent elements of a symmetric matrix: N*(N+1)/2
190 
191  */
192  template<class InputIterator>
193  SMatrix(InputIterator begin, InputIterator end, bool triang = false, bool lower = true);
194 
195  /**
196  Constructor with STL iterator interface. The data will be copied into the matrix
197  \param begin start iterator position
198  \param size iterator size
199  \param triang if true only the triangular lower/upper part of the matrix is filled from the iterators
200  \param lower if true the lower triangular part is filled
201 
202  Size of the iterators must not be larger than the size of the matrix representation.
203  In the case of symmetric matrices the size is N*(N+1)/2.
204 
205  */
206  template<class InputIterator>
207  SMatrix(InputIterator begin, unsigned int size, bool triang = false, bool lower = true);
208 
209  /**
210  constructor of a symmetrix a matrix from a SVector containing the lower (upper)
211  triangular part.
212  */
213 #ifndef UNSUPPORTED_TEMPLATE_EXPRESSION
214  SMatrix(const SVector<T, D1*(D2+1)/2> & v, bool lower = true );
215 #else
216  template<unsigned int N>
217  SMatrix(const SVector<T,N> & v, bool lower = true );
218 #endif
219 
220 
221  /**
222  Construct from a scalar value (only for size 1 matrices)
223  */
224  explicit SMatrix(const T& rhs);
225 
226  /**
227  Assign from another compatible matrix.
228  Possible Symmetirc to general but NOT vice-versa
229  */
230  template <class M>
231  SMatrix<T,D1,D2,R>& operator=(const M& rhs);
232 
233  SMatrix<T,D1,D2,R>& operator=(const SMatrix<T,D1,D2,R>& rhs);
234 
235  /**
236  Assign from a matrix expression
237  */
238  template <class A, class R2>
239  SMatrix<T,D1,D2,R>& operator=(const Expr<A,T,D1,D2,R2>& rhs);
240 
241  /**
242  Assign from an identity matrix
243  */
244  SMatrix<T,D1,D2,R> & operator=(SMatrixIdentity );
245 
246  /**
247  Assign from a scalar value (only for size 1 matrices)
248  */
249  SMatrix<T,D1,D2,R>& operator=(const T& rhs);
250 
251  /** @name --- Matrix dimension --- */
252 
253  /**
254  Enumeration defining the matrix dimension,
255  number of rows, columns and size = rows*columns)
256  */
257  enum {
258  /// return no. of matrix rows
259  kRows = D1,
260  /// return no. of matrix columns
261  kCols = D2,
262  /// return no of elements: rows*columns
263  kSize = D1*D2
264  };
265 
266  /** @name --- Access functions --- */
267 
268  /** access the parse tree with the index starting from zero and
269  following the C convention for the order in accessing
270  the matrix elements.
271  Same convention for general and symmetric matrices.
272  */
273  T apply(unsigned int i) const;
274 
275  /// return read-only pointer to internal array
276  const T* Array() const;
277  /// return pointer to internal array
278  T* Array();
279 
280  /** @name --- STL-like interface ---
281  The iterators access the matrix element in the order how they are
282  stored in memory. The C (row-major) convention is used, and in the
283  case of symmetric matrices the iterator spans only the lower diagonal
284  block. For example for a symmetric 3x3 matrices the order of the 6
285  elements \f${a_0,...a_5}\f$ is:
286  \f[
287  M = \left( \begin{array}{ccc}
288  a_0 & a_1 & a_3 \\
289  a_1 & a_2 & a_4 \\
290  a_3 & a_4 & a_5 \end{array} \right)
291  \f]
292  */
293 
294  /** STL iterator interface. */
295  iterator begin();
296 
297  /** STL iterator interface. */
298  iterator end();
299 
300  /** STL const_iterator interface. */
301  const_iterator begin() const;
302 
303  /** STL const_iterator interface. */
304  const_iterator end() const;
305 
306  /**
307  Set matrix elements with STL iterator interface. The data will be copied into the matrix
308  \param begin start iterator position
309  \param end end iterator position
310  \param triang if true only the triangular lower/upper part of the matrix is filled from the iterators
311  \param lower if true the lower triangular part is filled
312 
313  Size of the matrix must match size of the iterators, if triang is false, otherwise the size of the
314  triangular block. In the case of symmetric matrices triang is considered always to be true
315  (what-ever the user specifies) and the size of the iterators must be equal to the size of the
316  triangular block, which is the number of independent elements of a symmetric matrix: N*(N+1)/2
317 
318  */
319  template<class InputIterator>
320  void SetElements(InputIterator begin, InputIterator end, bool triang = false, bool lower = true);
321 
322  /**
323  Constructor with STL iterator interface. The data will be copied into the matrix
324  \param begin start iterator position
325  \param size iterator size
326  \param triang if true only the triangular lower/upper part of the matrix is filled from the iterators
327  \param lower if true the lower triangular part is filled
328 
329  Size of the iterators must not be larger than the size of the matrix representation.
330  In the case of symmetric matrices the size is N*(N+1)/2.
331 
332  */
333  template<class InputIterator>
334  void SetElements(InputIterator begin, unsigned int size, bool triang = false, bool lower = true);
335 
336 
337  /** @name --- Operators --- */
338  /// element wise comparison
339  bool operator==(const T& rhs) const;
340  /// element wise comparison
341  bool operator!=(const T& rhs) const;
342  /// element wise comparison
343  template <class R2>
344  bool operator==(const SMatrix<T,D1,D2,R2>& rhs) const;
345  /// element wise comparison
346  bool operator!=(const SMatrix<T,D1,D2,R>& rhs) const;
347  /// element wise comparison
348  template <class A, class R2>
349  bool operator==(const Expr<A,T,D1,D2,R2>& rhs) const;
350  /// element wise comparison
351  template <class A, class R2>
352  bool operator!=(const Expr<A,T,D1,D2,R2>& rhs) const;
353 
354  /// element wise comparison
355  bool operator>(const T& rhs) const;
356  /// element wise comparison
357  bool operator<(const T& rhs) const;
358  /// element wise comparison
359  template <class R2>
360  bool operator>(const SMatrix<T,D1,D2,R2>& rhs) const;
361  /// element wise comparison
362  template <class R2>
363  bool operator<(const SMatrix<T,D1,D2,R2>& rhs) const;
364  /// element wise comparison
365  template <class A, class R2>
366  bool operator>(const Expr<A,T,D1,D2,R2>& rhs) const;
367  /// element wise comparison
368  template <class A, class R2>
369  bool operator<(const Expr<A,T,D1,D2,R2>& rhs) const;
370 
371  /**
372  read only access to matrix element, with indices starting from 0
373  */
374  const T& operator()(unsigned int i, unsigned int j) const;
375  /**
376  read/write access to matrix element with indices starting from 0
377  */
378  T& operator()(unsigned int i, unsigned int j);
379 
380  /**
381  read only access to matrix element, with indices starting from 0.
382  Function will check index values and it will assert if they are wrong
383  */
384  const T& At(unsigned int i, unsigned int j) const;
385  /**
386  read/write access to matrix element with indices starting from 0.
387  Function will check index values and it will assert if they are wrong
388  */
389  T& At(unsigned int i, unsigned int j);
390 
391 
392  // helper class for implementing the m[i][j] operator
393 
394  class SMatrixRow {
395  public:
396  SMatrixRow ( SMatrix<T,D1,D2,R> & rhs, unsigned int i ) :
397  fMat(&rhs), fRow(i)
398  {}
399  T & operator[](int j) { return (*fMat)(fRow,j); }
400  private:
401  SMatrix<T,D1,D2,R> * fMat;
402  unsigned int fRow;
403  };
404 
405  class SMatrixRow_const {
406  public:
407  SMatrixRow_const ( const SMatrix<T,D1,D2,R> & rhs, unsigned int i ) :
408  fMat(&rhs), fRow(i)
409  {}
410 
411  const T & operator[](int j) const { return (*fMat)(fRow, j); }
412 
413  private:
414  const SMatrix<T,D1,D2,R> * fMat;
415  unsigned int fRow;
416  };
417 
418  /**
419  read only access to matrix element, with indices starting from 0 : m[i][j]
420  */
421  SMatrixRow_const operator[](unsigned int i) const { return SMatrixRow_const(*this, i); }
422  /**
423  read/write access to matrix element with indices starting from 0 : m[i][j]
424  */
425  SMatrixRow operator[](unsigned int i) { return SMatrixRow(*this, i); }
426 
427 
428  /**
429  addition with a scalar
430  */
431  SMatrix<T,D1,D2,R>&operator+=(const T& rhs);
432 
433  /**
434  addition with another matrix of any compatible representation
435  */
436  template <class R2>
437  SMatrix<T,D1,D2,R>&operator+=(const SMatrix<T,D1,D2,R2>& rhs);
438 
439  /**
440  addition with a compatible matrix expression
441  */
442  template <class A, class R2>
443  SMatrix<T,D1,D2,R>& operator+=(const Expr<A,T,D1,D2,R2>& rhs);
444 
445  /**
446  subtraction with a scalar
447  */
448  SMatrix<T,D1,D2,R>& operator-=(const T& rhs);
449 
450  /**
451  subtraction with another matrix of any compatible representation
452  */
453  template <class R2>
454  SMatrix<T,D1,D2,R>&operator-=(const SMatrix<T,D1,D2,R2>& rhs);
455 
456  /**
457  subtraction with a compatible matrix expression
458  */
459  template <class A, class R2>
460  SMatrix<T,D1,D2,R>& operator-=(const Expr<A,T,D1,D2,R2>& rhs);
461 
462  /**
463  multiplication with a scalar
464  */
465  SMatrix<T,D1,D2,R>& operator*=(const T& rhs);
466 
467 #ifndef __CINT__
468 
469 
470  /**
471  multiplication with another compatible matrix (it is a real matrix multiplication)
472  Note that this operation does not avid to create a temporary to store intermidiate result
473  */
474  template <class R2>
475  SMatrix<T,D1,D2,R>& operator*=(const SMatrix<T,D1,D2,R2>& rhs);
476 
477  /**
478  multiplication with a compatible matrix expression (it is a real matrix multiplication)
479  */
480  template <class A, class R2>
481  SMatrix<T,D1,D2,R>& operator*=(const Expr<A,T,D1,D2,R2>& rhs);
482 
483 #endif
484 
485  /**
486  division with a scalar
487  */
488  SMatrix<T,D1,D2,R>& operator/=(const T& rhs);
489 
490 
491 
492  /** @name --- Linear Algebra Functions --- */
493 
494  /**
495  Invert a square Matrix ( this method changes the current matrix).
496  Return true if inversion is successfull.
497  The method used for general square matrices is the LU factorization taken from Dinv routine
498  from the CERNLIB (written in C++ from CLHEP authors)
499  In case of symmetric matrices Bunch-Kaufman diagonal pivoting method is used
500  (The implementation is the one written by the CLHEP authors)
501  */
502  bool Invert();
503 
504  /**
505  Invert a square Matrix and returns a new matrix. In case the inversion fails
506  the current matrix is returned.
507  \param ifail . ifail will be set to 0 when inversion is successfull.
508  See ROOT::Math::SMatrix::Invert for the inversion algorithm
509  */
510  SMatrix<T,D1,D2,R> Inverse(int & ifail ) const;
511 
512  /**
513  Fast Invertion of a square Matrix ( this method changes the current matrix).
514  Return true if inversion is successfull.
515  The method used is based on direct inversion using the Cramer rule for
516  matrices upto 5x5. Afterwards the same default algorithm of Invert() is used.
517  Note that this method is faster but can suffer from much larger numerical accuracy
518  when the condition of the matrix is large
519  */
520  bool InvertFast();
521 
522  /**
523  Invert a square Matrix and returns a new matrix. In case the inversion fails
524  the current matrix is returned.
525  \param ifail . ifail will be set to 0 when inversion is successfull.
526  See ROOT::Math::SMatrix::InvertFast for the inversion algorithm
527  */
528  SMatrix<T,D1,D2,R> InverseFast(int & ifail ) const;
529 
530  /**
531  Invertion of a symmetric positive defined Matrix using Choleski decomposition.
532  ( this method changes the current matrix).
533  Return true if inversion is successfull.
534  The method used is based on Choleski decomposition
535  A compile error is given if the matrix is not of type symmetric and a run-time failure if the
536  matrix is not positive defined.
537  For solving a linear system, it is possible to use also the function
538  ROOT::Math::SolveChol(matrix, vector) which will be faster than performing the inversion
539  */
540  bool InvertChol();
541 
542  /**
543  Invert of a symmetric positive defined Matrix using Choleski decomposition.
544  A compile error is given if the matrix is not of type symmetric and a run-time failure if the
545  matrix is not positive defined.
546  In case the inversion fails the current matrix is returned.
547  \param ifail . ifail will be set to 0 when inversion is successfull.
548  See ROOT::Math::SMatrix::InvertChol for the inversion algorithm
549  */
550  SMatrix<T,D1,D2,R> InverseChol(int & ifail ) const;
551 
552  /**
553  determinant of square Matrix via Dfact.
554  Return true when the calculation is successfull.
555  \param det will contain the calculated determinant value
556  \b Note: this will destroy the contents of the Matrix!
557  */
558  bool Det(T& det);
559 
560  /**
561  determinant of square Matrix via Dfact.
562  Return true when the calculation is successfull.
563  \param det will contain the calculated determinant value
564  \b Note: this will preserve the content of the Matrix!
565  */
566  bool Det2(T& det) const;
567 
568 
569  /** @name --- Matrix Slice Functions --- */
570 
571  /// place a vector in a Matrix row
572  template <unsigned int D>
573  SMatrix<T,D1,D2,R>& Place_in_row(const SVector<T,D>& rhs,
574  unsigned int row,
575  unsigned int col);
576  /// place a vector expression in a Matrix row
577  template <class A, unsigned int D>
578  SMatrix<T,D1,D2,R>& Place_in_row(const VecExpr<A,T,D>& rhs,
579  unsigned int row,
580  unsigned int col);
581  /// place a vector in a Matrix column
582  template <unsigned int D>
583  SMatrix<T,D1,D2,R>& Place_in_col(const SVector<T,D>& rhs,
584  unsigned int row,
585  unsigned int col);
586  /// place a vector expression in a Matrix column
587  template <class A, unsigned int D>
588  SMatrix<T,D1,D2,R>& Place_in_col(const VecExpr<A,T,D>& rhs,
589  unsigned int row,
590  unsigned int col);
591  /// place a matrix in this matrix
592  template <unsigned int D3, unsigned int D4, class R2>
593  SMatrix<T,D1,D2,R>& Place_at(const SMatrix<T,D3,D4,R2>& rhs,
594  unsigned int row,
595  unsigned int col);
596  /// place a matrix expression in this matrix
597  template <class A, unsigned int D3, unsigned int D4, class R2>
598  SMatrix<T,D1,D2,R>& Place_at(const Expr<A,T,D3,D4,R2>& rhs,
599  unsigned int row,
600  unsigned int col);
601 
602  /**
603  return a full Matrix row as a vector (copy the content in a new vector)
604  */
605  SVector<T,D2> Row(unsigned int therow) const;
606 
607  /**
608  return a full Matrix column as a vector (copy the content in a new vector)
609  */
610  SVector<T,D1> Col(unsigned int thecol) const;
611 
612  /**
613  return a slice of therow as a vector starting at the colum value col0 until col0+N,
614  where N is the size of the vector (SubVector::kSize )
615  Condition col0+N <= D2
616  */
617  template <class SubVector>
618  SubVector SubRow(unsigned int therow, unsigned int col0 = 0 ) const;
619 
620  /**
621  return a slice of the column as a vector starting at the row value row0 until row0+Dsub.
622  where N is the size of the vector (SubVector::kSize )
623  Condition row0+N <= D1
624  */
625  template <class SubVector>
626  SubVector SubCol(unsigned int thecol, unsigned int row0 = 0) const;
627 
628  /**
629  return a submatrix with the upper left corner at the values (row0, col0) and with sizes N1, N2
630  where N1 and N2 are the dimension of the sub-matrix (SubMatrix::kRows and SubMatrix::kCols )
631  Condition row0+N1 <= D1 && col0+N2 <=D2
632  */
633  template <class SubMatrix >
634  SubMatrix Sub(unsigned int row0, unsigned int col0) const;
635 
636  /**
637  return diagonal elements of a matrix as a Vector.
638  It works only for squared matrices D1 == D2, otherwise it will produce a compile error
639  */
640  SVector<T,D1> Diagonal() const;
641 
642  /**
643  Set the diagonal elements from a Vector
644  Require that vector implements ::kSize since a check (statically) is done on
645  diagonal size == vector size
646  */
647  template <class Vector>
648  void SetDiagonal(const Vector & v);
649 
650  /**
651  return the trace of a matrix
652  Sum of the diagonal elements
653  */
654  T Trace() const;
655 
656 
657  /**
658  return the upper Triangular block of the matrices (including the diagonal) as
659  a vector of sizes N = D1 * (D1 + 1)/2.
660  It works only for square matrices with D1==D2, otherwise it will produce a compile error
661  */
662 #ifndef UNSUPPORTED_TEMPLATE_EXPRESSION
663  SVector<T, D1 * (D2 +1)/2> UpperBlock() const;
664 #else
665  template<class SubVector>
666  SubVector UpperBlock() const;
667 #endif
668 
669  /**
670  return the lower Triangular block of the matrices (including the diagonal) as
671  a vector of sizes N = D1 * (D1 + 1)/2.
672  It works only for square matrices with D1==D2, otherwise it will produce a compile error
673  */
674 #ifndef UNSUPPORTED_TEMPLATE_EXPRESSION
675  SVector<T, D1 * (D2 +1)/2> LowerBlock() const;
676 #else
677  template<class SubVector>
678  SubVector LowerBlock() const;
679 #endif
680 
681 
682  /** @name --- Other Functions --- */
683 
684  /**
685  Function to check if a matrix is sharing same memory location of the passed pointer
686  This function is used by the expression templates to avoid the alias problem during
687  expression evaluation. When the matrix is in use, for example in operations
688  like A = B * A, a temporary object storing the intermediate result is automatically
689  created when evaluating the expression.
690 
691  */
692  bool IsInUse(const T* p) const;
693 
694  // submatrices
695 
696  /// Print: used by operator<<()
697  std::ostream& Print(std::ostream& os) const;
698 
699 
700 
701 
702 public:
703 
704  /** @name --- Data Member --- */
705 
706  /**
707  Matrix Storage Object containing matrix data
708  */
709  R fRep;
710 
711 }; // end of class SMatrix
712 
713 
714 
715 
716 //==============================================================================
717 // operator<<
718 //==============================================================================
719 template <class T, unsigned int D1, unsigned int D2, class R>
720 inline std::ostream& operator<<(std::ostream& os, const ROOT::Math::SMatrix<T,D1,D2,R>& rhs) {
721  return rhs.Print(os);
722 }
723 
724 
725  } // namespace Math
726 
727 } // namespace ROOT
728 
729 
730 
731 
732 
733 
734 #ifndef __CINT__
735 
736 #include "Math/SMatrix.icc"
737 
738 #include "Math/MatrixFunctions.h"
739 
740 #endif //__CINT__
741 
742 #endif /* ROOT_Math_SMatrix */