1 /* Copyright (c) 2015 Gerald Knizia
2 *
3 * This file is part of the IboView program (see: http://www.iboview.org)
4 *
5 * IboView is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * IboView is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
16 *
17 * Please see IboView documentation in README.txt for:
18 * -- A list of included external software and their licenses. The included
19 * external software's copyright is not touched by this agreement.
20 * -- Notes on re-distribution and contributions to/further development of
21 * the IboView software
22 */
23
24 #ifndef CT8k_MATRIX_H
25 #define CT8k_MATRIX_H
26
27 #include "CxTypes.h" // for size_t.
28 #include "CxAlgebra.h"
29 #include "CxMemoryStack.h"
30 #include "CxPodArray.h"
31
32 #include <string>
33 #include <sstream>
34
35 namespace ct {
36
37 typedef double
38 FScalar;
39
40 using std::size_t;
41
42 /// Describes the layout of a matrix somewhere in memory, which this object
43 /// DOES NOT own.
44 /// fixme: replace uints by size_t...
45 struct FMatrixView
46 {
47 FScalar
48 *pData; ///< start of data of this matrix.
49 size_t
50 nRows, ///< number of rows (first index, fast)
51 nCols, ///< number of columns (second index, slow)
52 nRowSt, ///< number of words between adjacent rows. In default-alignment, nRowSt == 1
53 nColSt; ///< number of words between adjacent cols. In default-alignment, nColSt == nRows
54 // Note: One of both strides should be 1.
55
56 /// element retrieval operator: m(nRow,nCol) -> element stored at that
57 /// part of the matrix. Note: indices are 0-based!.
operatorFMatrixView58 inline FScalar& operator () ( size_t iRow, size_t iCol ){
59 assert( iRow <= nRows );
60 assert( iCol <= nCols );
61 return pData[nRowSt * iRow + nColSt * iCol];
62 };
operatorFMatrixView63 inline FScalar const& operator () ( size_t iRow, size_t iCol ) const {
64 return const_cast<FMatrixView *const>(this)->operator()( iRow, iCol );
65 };
66
67 FScalar &operator [] (size_t iEntry) { return pData[iEntry]; }
68 FScalar const &operator [] (size_t iEntry) const { return pData[iEntry]; }
69
FMatrixViewFMatrixView70 FMatrixView()
71 : pData(0)
72 {}
73
74 FMatrixView( double *pData_, size_t nRows_, size_t nCols_, size_t nRowSt_ = 1, size_t nColSt_ = 0 )
pDataFMatrixView75 : pData(pData_), nRows(nRows_), nCols(nCols_),
76 nRowSt(nRowSt_), nColSt( (nColSt_ != 0)? nColSt_ : nRows )
77 {};
78
79 inline size_t GetStridedSize() const;
80
81 void Print( std::ostream &out, std::string const &Name = "" ) const;
82 /// sets matrix to zero
83 void Clear();
84 /// sets matrix to identity
85 void SetIdentity();
86 // /// returns copy of diagonal elements of the matrix. Only valid for square matrices.
87 // std::vector<FScalar> GetDiagonal() const;
88
IsSquareFMatrixView89 bool IsSquare() const { return nRows == nCols; };
90 bool IsSymmetric(FScalar Thresh) const;
91
92 double fRmsdFromIdentity() const;
93 double fRmsdFromZero() const;
94 double fRmsdFromSymmetry() const;
95
96 /// if nRowSt==1, sets space between nRow and nColSt to zero (in order to
97 /// not have possible NaNs/Denorms in spaces in the matrices which are only
98 /// there for alignment purposes; e.g., ntb vs nt strides.
99 void ClearEmptySpace();
100
101 /// returns size of this matrix would require in triangular storage (e.g.,
102 /// storing only the lower triangular part). If Sign == -1, size is
103 /// calculated for anti-symmetric matrix.
104 size_t TriangularStorageSize(int Sign = 1) const;
TriangularStorageSize1FMatrixView105 size_t TriangularStorageSize1() const { return TriangularStorageSize(1); };
106 void TriangularExpand(int Sign = 1, FScalar *pTriangData = 0);
107 // fOffDiagFactor: if given, off diagonal elements will be multiplied by this factor before reduction.
108 void TriangularReduce(int Sign = 1, FScalar *pTriangData = 0, FScalar fOffDiagFactor = 1.);
109 enum FTriangularTransformFlags {
110 TRIANG_Expand,
111 TRIANG_Reduce
112 };
113 void TriangularExpandOrReduce(int Sign, FScalar *pTriangData, FTriangularTransformFlags Direction);
114 };
115
GetStridedSize()116 size_t FMatrixView::GetStridedSize() const {
117 if ( nRowSt == 1 )
118 return nCols * nColSt;
119 else {
120 if ( nColSt == 1 )
121 return nRows * nRowSt;
122 else
123 assert(0); // not supported.
124 return 0;
125 }
126 };
127
128
129
130 // export version (can also be used in other files than CtMatrix.cpp)
131 void AssertCompatible1( FMatrixView const &A, FMatrixView const &B );
132
133 // allocate a nRows x nCols matrix on Mem and return the given object.
MakeStackMatrix(size_t nRows,size_t nCols,FMemoryStack & Mem)134 inline FMatrixView MakeStackMatrix(size_t nRows, size_t nCols, FMemoryStack &Mem)
135 {
136 FMatrixView r(0, nRows, nCols);
137 Mem.Alloc(r.pData, nRows * nCols);
138 return r;
139 }
140
141 uint const MXM_AddToDest = 0x1u;
142 uint const MXM_Add = MXM_AddToDest;
143
144 /// Creates a view representing the transpose of the input matrix.
145 /// The returned view still references the original data (i.e., In and Out are aliased)
146 FMatrixView Transpose( FMatrixView const &In );
147 /// Out += f * In
148 void Add( FMatrixView &Out, FMatrixView const &In, FScalar fFactor = 1.0 );
149 /// Out = f * In
150 void Move( FMatrixView &Out, FMatrixView const &In, FScalar fFactor = 1.0 );
151 /// Out = A * B
152 void Mxm( FMatrixView &Out, FMatrixView const &A, FMatrixView const &B, uint Flags = 0 );
153 /// Out = f * A * B
154 void Mxm( FMatrixView &Out, FMatrixView const &A, FMatrixView const &B, FScalar fFactor, uint Flags = 0 );
155 /// Out = f * A * A^T for symmetric matrix Out [Note: Out will be symmetrized!].
156 void SyrkNT( FMatrixView &Out, FMatrixView const &A, FScalar fFactor = 1.0, uint Flags = 0 );
157 /// Out = f * A^T * A for symmetric matrix Out [Note: Out will be symmetrized!].
158 void SyrkTN( FMatrixView &Out, FMatrixView const &A, FScalar fFactor = 1.0, uint Flags = 0 );
159
160 /// Chained matrix product: Out = A0 * A1 * A2....
161 void ChainMxm(FMatrixView Out, FMatrixView A0, FMemoryStack &Mem, uint Flags = 0);
162 void ChainMxm(FMatrixView Out, FMatrixView A0, FMatrixView A1, FMemoryStack &Mem, uint Flags = 0);
163 void ChainMxm(FMatrixView Out, FMatrixView A0, FMatrixView A1, FMatrixView A2, FMemoryStack &Mem, uint Flags = 0);
164 void ChainMxm(FMatrixView Out, FMatrixView A0, FMatrixView A1, FMatrixView A2, FMatrixView A3, FMemoryStack &Mem, uint Flags = 0);
165 void ChainMxm(FMatrixView Out, FMatrixView A0, FMatrixView A1, FMatrixView A2, FMatrixView A3, FMatrixView A4, FMemoryStack &Mem, uint Flags = 0);
166 void ChainMxm(FMatrixView Out, FMatrixView A0, FMatrixView A1, FMatrixView A2, FMatrixView A3, FMatrixView A4, FMatrixView A5, FMemoryStack &Mem, uint Flags = 0);
167
168
169 // Out = A * B, Out,B being vectors
170 void Mxva(FScalar *RESTRICT pOut, FMatrixView const &A, FScalar const *RESTRICT pIn);
171 // Out += A * B, Out,B being vectors
172 void Mxvb(FScalar *RESTRICT pOut, FMatrixView const &A, FScalar const *RESTRICT pIn);
173 /// trace of a matrix
174 FScalar Trace( FMatrixView const &In );
175 /// dot-product of two matrices. dot(A^T B) = Tr(A * B).
176 FScalar Dot( FMatrixView const &A, FMatrixView const &B );
177 /// scale matrix by a factor in place
178 void Scale( FMatrixView &Out, FScalar fFactor );
179 /// diagonalize a matrix in place and store the eigenvalues at pEigenValues.
180 /// Input matrix must be symmetric and pEigenValues must hold room for nRows==nCols
181 /// entries.
182 void Diagonalize( FMatrixView &InOut, FScalar *pEigenValues, FMemoryStack &Mem );
183 /// As Diagonalize(), but eigenvalues are returned in descending order.
184 void Diagonalize_LargeEwFirst( FMatrixView &InOut, FScalar *pEigenValues, FMemoryStack &Mem );
185
186 // Factorize InAndTmp into U * diag(sigma) * Vt,
187 // where U and Vt are unitary. If InAndTmp is a nRows x nCols matrix,
188 // then on output U will have dimension nRows x nSig and Vt dimension nCols x nSig,
189 // where nSig = min(nRows,nCols).
190 // Note: Content of In is left alone (input is copied).
191 void ComputeSvd(FMatrixView &U, FScalar *pSigma, FMatrixView &Vt, FMatrixView In, FMemoryStack &Mem);
192
193 // As ComputeSvd, but allocate output quantities (U, pSigma, and Vt) on Mem.
194 void AllocAndComputeSvd(FMatrixView &U, FScalar *&pSigma, FMatrixView &Vt, FMatrixView In, FMemoryStack &Mem);
195 void AllocAndComputeSvd(FMatrixView &U, FMatrixView &Sigma, FMatrixView &Vt, FMatrixView In, FMemoryStack &Mem);
196
197 // calculate Cholesky factorization M = L * L^T
198 void CalcCholeskyFactors(FMatrixView M);
199 // invert lower triangular matrix L. Upper part ignored.
200 void InvertTriangularMatrix(FMatrixView L);
201 // Solve L X = B where L is a lower triangular matrix.
202 void TriangularSolve(FMatrixView RhsSol, FMatrixView const &L);
203 // set A := L * A where L is a lower triangular matrix (Side == 'L').
204 // or A := A * L where L is a lower triangular matrix (Side == 'R')
205 void TriangularMxm(FMatrixView A, FMatrixView const &L, char Side, double fFactor = 1.0);
206 // solve linear least squares ||M * x - b||_2 -> min subject to ||x||_2 ->min
207 // using singular value decomposition of A. Singular values below fThrRel are
208 // treated as zero. A negative value indicates the usage of machine precision.
209 // Both M and RhsSol are overwritten.
210 //
211 // Notes:
212 // - On input, RhsSol is the RHS and must have format M.nRows x nRhs
213 // On output, RhsSol is the solution and is set to format M.nCols x nRhs
214 // - This happens IN PLACE. That means that RhsSol must have a column stride
215 // of at least std::max(M.nCols, M.nRows).
216 // - Number of rows on RhsSol is adjusted as required on output.
217 void LeastSquaresSolve(FMatrixView M, FMatrixView &RhsSol, double fThrRel, FMemoryStack &Mem);
218 // Solve M * Sol == Rhs.
219 // Similar to LeastSquaresSolve, but Rhs and Sol are provided independently (and are copied
220 // if required for reasons of strides). Neither M nor Rhs is overwritten.
221 void LeastSquaresSolveSafe(FMatrixView const M, FMatrixView Sol, FMatrixView const Rhs, double fThrRel, FMemoryStack &Mem);
222
223
224 // // Solve X L = B where L is a lower triangular matrix.
225 // void TriangularSolveRight(FMatrixView RhsSol, FMatrixView const &L);
226 // Solve A X = B, where A = L*L^T and L is a lower triangular matrix.
227 void CholeskySolve(FMatrixView RhsAndSolution, FMatrixView const &L);
228 void CholeskySolve(double *pRhsAndSolution, FMatrixView const &L);
229 // Multiply B = A * X, where A = L*L^T and L is a lower triangular matrix.
230 void CholeskyMxm(FMatrixView RhsSol, FMatrixView const &L);
231 void CholeskyMxm(double *pRhsAndSolution, FMatrixView const &L);
232
233 void Symmetrize(FMatrixView M, double Phase = 1);
234
235 /// creates a view representing the sub-matrix of size nRow x nCol
236 /// starting at (iRow,iCol).
237 /// The returned view still references the original data (i.e., In and Out are aliased)
238 FMatrixView Select( FMatrixView const &In, size_t iRow, size_t iCol, size_t nRows, size_t nCols );
239
240 // exactly same as above, but allowing for temporaries as first argument (C++ ftw...).
241 inline void Add0( FMatrixView Out, FMatrixView const &In, FScalar fFactor = 1.0 ) {
242 return Add(Out,In,fFactor);
243 }
244 inline void Move0( FMatrixView Out, FMatrixView const &In, FScalar fFactor = 1.0 ) {
245 return Move(Out, In, fFactor);
246 }
247 inline void Mxm0( FMatrixView Out, FMatrixView const &A, FMatrixView const &B, uint Flags = 0 ) {
248 return Mxm(Out, A, B, Flags);
249 }
250 inline void Mxm0( FMatrixView Out, FMatrixView const &A, FMatrixView const &B, FScalar fFactor, uint Flags = 0 ) {
251 return Mxm(Out, A, B, fFactor, Flags);
252 }
Scale0(FMatrixView Out,FScalar fFactor)253 inline void Scale0( FMatrixView Out, FScalar fFactor ) {
254 return Scale(Out, fFactor);
255 }
256
257
258
259 // An interface to FMatrixView which owns its data.
260 // Will adjust to input dimensions of operations as long as the actual
261 // matrix size does not exceed nMaxSize.
262 struct FStackMatrix : public FMatrixView
263 {
FStackMatrixFStackMatrix264 FStackMatrix( size_t nMaxSize_, FMemoryStack *pMemoryStack_ )
265 : nMaxSize(nMaxSize_), pMemory(pMemoryStack_)
266 {
267 pMemory->Align(8);
268 pMemory->Alloc(pData, nMaxSize_);
269 Reshape(0,0);
270 };
271
FStackMatrixFStackMatrix272 FStackMatrix( size_t nRows_, size_t nCols_, FMemoryStack *pMemoryStack_ )
273 : nMaxSize(nRows_*nCols_), pMemory(pMemoryStack_)
274 {
275 pMemory->Align(8);
276 pMemory->Alloc(pData, nMaxSize);
277 Reshape(nRows_, nCols_);
278 };
279
~FStackMatrixFStackMatrix280 ~FStackMatrix(){ Free(); }
FreeFStackMatrix281 void Free() { if (pData) pMemory->Free(pData); pData = 0; }
ReshapeFStackMatrix282 void Reshape( size_t nRows_, size_t nCols_ ){
283 assert( nRows_ * nCols_ <= nMaxSize );
284 nRows = nRows_; nCols = nCols_; nRowSt = 1; nColSt = nRows_;
285 };
286 private:
287 size_t
288 nMaxSize;
289 FMemoryStack
290 *pMemory; // a
291 };
292
293 // a matrix with data stored in a local heap-allocated array.
294 // Warning: This has *no* virtual destructor! and FMatrixView is not going to get one.
295 struct FHeapMatrix : public FMatrixView, public FIntrusivePtrDest
296 {
297 FHeapMatrix();
298 FHeapMatrix(FMatrixView v);
299 FHeapMatrix(size_t nRows, size_t nCols);
300 virtual ~FHeapMatrix();
301 void Reshape(size_t nRows_, size_t nCols_);
302
303 FHeapMatrix(FHeapMatrix const &other);
304 void operator = (FHeapMatrix const &other);
305 protected:
306 TArray<FScalar>
307 m_Buffer;
308 };
309 typedef boost::intrusive_ptr<FHeapMatrix>
310 FHeapMatrixPtr;
311
312
313 /// Out = f * In
314 void Move( FStackMatrix &Out, FMatrixView const &In, FScalar fFactor = 1.0 );
315 /// Out = A * B
316 void Mxm( FStackMatrix &Out, FMatrixView const &A, FMatrixView const &B, uint Flags = 0 );
317 /// Out = f * A * B
318 void Mxm( FStackMatrix &Out, FMatrixView const &A, FMatrixView const &B, FScalar fFactor, uint Flags = 0 );
319
320 void Move( FHeapMatrix &Out, FMatrixView const &In, FScalar fFactor = 1.0 );
321
322
323 // Note: the other operations from FMatrixView should work unchanged
324 // on FStackMatrix, because they do not require a change in the shape.
325
326 void PrintMatrixGen( std::ostream &out, double const *pData,
327 size_t nRows, size_t nRowStride, size_t nCols, size_t nColStride, std::string const &Name );
328 void PrintMatrixGen( std::ostream &out, float const *pData,
329 size_t nRows, size_t nRowStride, size_t nCols, size_t nColStride, std::string const &Name );
330
331
332 struct FSmhOptions{
333 double
334 // ignore eigenvectors with eigenvalue < std::max(ThrAbs, MaxEw * ThrRel)
335 ThrAbs, ThrRel;
336 char const
337 *pDelMsg; // may be 0.
338 std::ostream
339 *pXout; // may be 0 if pDelMsg is 0.
340 FSmhOptions(double ThrAbs_ = 0, double ThrRel_ = 0, char const *pDelMsg_ = 0,
341 std::ostream *pXout_ = 0)
ThrAbsFSmhOptions342 : ThrAbs(ThrAbs_), ThrRel(ThrRel_), pDelMsg(pDelMsg_), pXout(pXout_)
343 {}
344 };
345
346 // calculates M^{-1/2} in place.
347 void CalcSmhMatrix( FMatrixView M, FMemoryStack &Mem, FSmhOptions const &Opt );
348 // orthogonalizes C in place, where S is C's overlap matrix.
349 // both C and S are overwritten.
350 void OrthSchmidt1(FMatrixView S, FMatrixView C, FMemoryStack &Mem);
351 // symmetrically orthogonalize a set of vectors with respect to overlap matrix S.
352 void SymOrth(FMatrixView Orbs, FMatrixView const S, FMemoryStack &Mem, double fThrAbs=1e-15, double fThrRel=1e-15);
353
354
355 // permute rows of matrix such that
356 // NewM[iRow,iCol] = OldM[P[iRow], iCol]
357 void PermuteRows(FMatrixView M, size_t const *P, FMemoryStack &Mem);
358 void Permute(FMatrixView &M, size_t const *pRowPerm, size_t const *pColPerm, FMemoryStack &Mem);
359 void WriteMatrixToFile(std::string const &FileName, FMatrixView const &M, std::string const &MatrixName, size_t *pRowPerm = 0, size_t *pColPerm = 0);
360
361 void ArgSort1(size_t *pOrd, double const *pVals, size_t nValSt, size_t nVals, bool Reverse = false);
362
363
364
365
366 } // namespace ct
367
368 #endif // CT8k_MATRIX_H
369
370 // kate: space-indent on; tab-indent on; backspace-indent on; tab-width 4; indent-width 4; mixedindent off; indent-mode normal;
371