OOFEM 3.0
Loading...
Searching...
No Matches
floatmatrix.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "floatmatrix.h"
36#include "floatarray.h"
37#include "intarray.h"
38#include "mathfem.h"
39#include "error.h"
40#include "datastream.h"
41
42#include <cstdio>
43#include <cstdlib>
44#include <cstring>
45#include <cmath>
46#include <ostream>
47#include <iostream>
48#include <fstream>
49#include <iomanip>
50
51
52#ifdef _USE_EIGEN
53 #include<Eigen/Eigenvalues>
54#endif
55
56
57
58namespace oofem {
59
60
61#define _LOOP_MATRIX(r,c) for(Index c=0; c<cols(); c++) for(Index r=0; r<rows(); r++)
62
63#ifdef _USE_EIGEN
64 void FloatMatrix::_resize_internal(int nr, int nc){
65 MatrixXXd::resize(nr,nc);
66 }
67#else
68 void FloatMatrix::_resize_internal(int nr, int nc){
69 this->nRows = nr; this->nColumns = nc;
70 std::size_t nsize = this->nRows * this->nColumns;
71 if ( nsize < this->values.size() ) {
72 this->values.resize(nsize);
73 } else if ( nsize > this->values.size() ) {
74 this->values.assign(nsize, 0.);
75 }
76 };
77
78
79 void FloatMatrix :: resize(Index rows, Index columns)
80 //
81 // resizes receiver, all data will be lost
82 //
83 {
84 this->nRows = rows;
85 this->nColumns = columns;
86 this->values.assign(rows * columns, 0.);
87 }
88
89#endif
90
91void FloatMatrix :: resizeWithData(Index rows, Index columns)
92//
93// resizes receiver, all data kept
94//
95{
96 // Check of resize if necessary at all.
97 if ( rows == this->rows() && columns == this->cols() ) {
98 return;
99 }
100
101
102
103 #ifdef _USE_EIGEN
104 FloatMatrix old(*this); // inefficient, but for testing okay
105 resize(rows,columns); // FIXME: useless zeroing
106 #else
107 FloatMatrix old( std :: move(* this) );
108 this->nRows = rows;
109 this->nColumns = columns;
110 this->values.resize(rows * columns);
111 #endif
112
113 Index ii = min( rows, (Index)old.rows() );
114 Index jj = min( columns, (Index)old.cols() );
115 // copy old values if possible
116 for (Index i = 1; i <= ii; i++ ) {
117 for (Index j = 1; j <= jj; j++ ) {
118 this->at(i, j) = old.at(i, j);
119 }
120 }
121}
122
123
124
125
126FloatMatrix FloatMatrix::fromIniList(std::initializer_list<std::initializer_list<double>> ini){
127 FloatMatrix ret;
128 ret._resize_internal( ( int ) ini.begin()->size(), ( int ) ini.size() );
129 Index c=0;
130 for (auto col : ini) {
131 #if DEBUG
132 if ( ret.rows() != (Index) col.size() ) {
133 OOFEM_ERROR("Initializer list has inconsistent column sizes.");
134 }
135 #endif
136 Index r=0;
137 for(const double& x: col) ret(r++,c)=x;
138 c++;
139 }
140 return ret;
141}
142
143
144FloatMatrix FloatMatrix :: fromCols ( std :: initializer_list< FloatArray >mat )
145{
146 FloatMatrix ret( mat.begin()->giveSize(), ( int ) mat.size() );
147 Index c=0;
148 for ( auto col : mat ) {
149 #if DEBUG
150 if ( ret.rows() != (Index) col.size() ) {
151 OOFEM_ERROR("Columns have inconsistent column sizes.");
152 }
153 #endif
154 for(Index r=0; r<col.size(); r++) ret(r,c)=col(r);
155 c++;
156 }
157
158 return ret;
159}
160
161void FloatMatrix :: checkBounds(Index i, Index j) const
162// Checks that the receiver includes a position (i,j).
163{
164 if ( i <= 0 ) {
165 OOFEM_ERROR("matrix error on rows : %d < 0", (int)i);
166 }
167 if ( j <= 0 ) {
168 OOFEM_ERROR("matrix error on columns : %d < 0", (int)j);
169 }
170
171 if ( i > rows() ) {
172 OOFEM_ERROR("matrix error on rows : %d > %d", (int)i, (int)rows());
173 }
174
175 if ( j > cols() ) {
176 OOFEM_ERROR("matrix error on columns : %d > %d", (int)j, (int)cols());
177 }
178}
179
180
181void FloatMatrix :: assemble(const FloatMatrix &src, const IntArray &loc)
182{
183 std::size_t ii, jj, size = src.rows();
184
185#ifndef NDEBUG
186 if ( size != loc.size() ) {
187 OOFEM_ERROR("dimensions of 'src' and 'loc' mismatch");
188 }
189
190 if ( !src.isSquare() ) {
191 OOFEM_ERROR("'src' is not sqaure matrix");
192 }
193#endif
194
195 for ( std::size_t i = 1; i <= size; i++ ) {
196 if ( ( ii = loc.at(i) ) ) {
197 for ( std::size_t j = 1; j <= size; j++ ) {
198 if ( ( jj = loc.at(j) ) ) {
199 this->at(ii, jj) += src.at(i, j);
200 }
201 }
202 }
203 }
204}
205
206#ifdef _USE_EIGEN___BROKEN
207 void FloatMatrix :: assemble(const FloatMatrix &src, const IntArray &rowind, const IntArray &colind){
208 /* rowind may contain 0s, which mean that the element is skipped */
209 Eigen::Map<const Eigen::ArrayXi> rr(rowind.givePointer(),rowind.size());
210 Eigen::Map<const Eigen::ArrayXi> cc(rowind.givePointer(),rowind.size());
211 // auto rOk=(rr>0), cOk=(cc>0);
212 Eigen::VectorXi R=Eigen::VectorXi::LinSpaced(rr.size(), 0, rr.size()-1).array();
213 Eigen::VectorXi C=Eigen::VectorXi::LinSpaced(cc.size(), 0, cc.size()-1).array();
214 // Eigen::VectorXi rThis=rr[rr>0];
215 (*this)(rr[rr>0]-1,cc[cc>0]-1)=src(R,C);
216 // auto rOk=(rr>0), cOk=(cc>0);
217 //(*this)((rr-1)(rr!=0),(cc-1)(cOk))+=src(Eigen::seq(0,src.rows()(rOk),cOk);
218 // FloatMatrix src2=src(rowind>0
219 //(*this)(rowind.minusOne(),colind.minusOne())+=src;
220 }
221#else
222void FloatMatrix :: assemble(const FloatMatrix &src, const IntArray &rowind, const IntArray &colind)
223{
224 int ii, jj;
225 int nr = src.giveNumberOfRows();
226 int nc = src.giveNumberOfColumns();
227
228#ifndef NDEBUG
229 if ( nr != rowind.giveSize() ) {
230 OOFEM_ERROR("row dimensions of 'src' and 'rowind' mismatch");
231 }
232
233 if ( nc != colind.giveSize() ) {
234 OOFEM_ERROR("column dimensions of 'src' and 'colind' mismatch");
235 }
236#endif
237
238 for ( int i = 1; i <= nr; i++ ) {
239 if ( ( ii = rowind.at(i) ) ) {
240 for ( int j = 1; j <= nc; j++ ) {
241 if ( ( jj = colind.at(j) ) ) {
242 this->at(ii, jj) += src.at(i, j);
243 }
244 }
245 }
246 }
247}
248#endif
249
250#ifdef _USE_EIGEN___BROKEN
251void FloatMatrix :: assembleT(const FloatMatrix &src, const IntArray &rowind, const IntArray &colind){
252 (*this)(rowind.minusOne(),colind.minusOne())+=src.transpose();
253}
254#else
255void FloatMatrix :: assembleT(const FloatMatrix &src, const IntArray &rowind, const IntArray &colind)
256{
257 int ii, jj;
258 int nr = src.giveNumberOfRows();
259 int nc = src.giveNumberOfColumns();
260
261#ifndef NDEBUG
262 if ( nr != rowind.giveSize() ) {
263 OOFEM_ERROR("row dimensions of 'src' and 'rowind' mismatch");
264 }
265
266 if ( nc != colind.giveSize() ) {
267 OOFEM_ERROR("column dimensions of 'src' and 'colind' mismatch");
268 }
269#endif
270
271 for ( int i = 1; i <= nr; i++ ) {
272 if ( ( ii = rowind.at(i) ) ) {
273 for ( int j = 1; j <= nc; j++ ) {
274 if ( ( jj = colind.at(j) ) ) {
275 this->at(jj, ii) += src.at(i, j);
276 }
277 }
278 }
279 }
280}
281#endif
282
283
284#ifdef _USE_EIGEN
285// helper routines
286void _zeroedIfEmpty(FloatMatrix& A, Eigen::Index rows, Eigen::Index cols){ if(A.isNotEmpty()) return; A.setZero(rows,cols); }
287void _ensureRowsCols(FloatMatrix& A, Eigen::Index minRows, Eigen::Index minCols){ if(A.rows()>=minRows && A.cols()>=minCols) return; A.resizeWithData(max(A.rows(),minRows),max(A.cols(),minCols)); }
288
289
290bool FloatMatrix::isAllFinite() const { return this->array().isFinite().all(); }
291void FloatMatrix :: beTranspositionOf(const FloatMatrix &src) { *this=src.transpose(); }
292void FloatMatrix :: beProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix){ *this=aMatrix*bMatrix; }
293void FloatMatrix :: beTProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix){ *this=aMatrix.transpose()*bMatrix; }
294void FloatMatrix :: beProductTOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix){ *this=aMatrix*bMatrix.transpose(); }
295void FloatMatrix :: addProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix){ *this+=aMatrix*bMatrix; }
296void FloatMatrix :: addTProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix){ *this+=aMatrix.transpose()*bMatrix; }
297void FloatMatrix :: beDyadicProductOf(const FloatArray &vec1, const FloatArray &vec2){ *this=vec1*vec2.transpose(); }
298void FloatMatrix :: symmetrized() { *this = this->selfadjointView<Eigen::Upper>().toDenseMatrix(); }
299void FloatMatrix :: times(double factor) { (*this)*=factor; }
300void FloatMatrix :: negated() { (*this)*=-1; }
301double FloatMatrix :: computeFrobeniusNorm() const { return this->norm(); }
302double FloatMatrix :: computeNorm(char p) const {
303 if(p=='1') return this->lpNorm<1>();
304 OOFEM_ERROR("p == %d not implemented.\n", p);
305}
306void FloatMatrix::setSubMatrix(const FloatMatrix &src, int sr, int sc){ this->block(sr-1,sc-1,src.rows(),src.cols())=src; }
307void FloatMatrix::setTSubMatrix(const FloatMatrix &src, int sr, int sc){ this->block(sr-1,sc-1,src.cols(),src.rows())=src.transpose(); }
308void FloatMatrix :: addSubVectorRow(const FloatArray &src, int sr, int sc){ Index sr0=sr-1, sc0=sc-1; _ensureRowsCols(*this,sr0+1,sc0+src.size()+1); row(sr0).segment(sc0,src.size())=src; }
309void FloatMatrix :: addSubVectorCol(const FloatArray &src, int sr, int sc){ Index sr0=sr-1, sc0=sc-1; _ensureRowsCols(*this,sr0+src.size()+1,sc0+1); col(sc0).segment(sr0,src.size())=src; }
310void FloatMatrix :: setColumn(const FloatArray &src, int c){ this->col(c-1)=src; }
311void FloatMatrix :: copyColumn(FloatArray &dest, int c) const { dest=this->col(c-1); }
312// void FloatMatrix :: plusProductSymmUpper(const FloatMatrix &a, const FloatMatrix &b, double dV){ _zeroedIfEmpty(*this,a.cols(),b.cols()); /*...*/ } // not sure who to write this nicely with Eigen
313void FloatMatrix :: plusDyadSymmUpper(const FloatArray &a, double dV) { _zeroedIfEmpty(*this,a.size(),a.size()); this->selfadjointView<Eigen::Upper>().rankUpdate(a,dV); }
314void FloatMatrix :: plusProductUnsym(const FloatMatrix &a, const FloatMatrix &b, double dV) { _zeroedIfEmpty(*this,a.cols(),b.cols()); *this+=a.transpose()*b*dV; }
315void FloatMatrix :: plusDyadUnsym(const FloatArray &a, const FloatArray &b, double dV) { _zeroedIfEmpty(*this,a.size(),b.size()); *this+=a*b.transpose()*dV; }
316void FloatMatrix :: plus_Nt_a_otimes_b_B(const FloatMatrix &N, const FloatArray &a, const FloatArray &b, const FloatMatrix &B, double dV){ _zeroedIfEmpty(*this,N.cols(),B.cols()); *this=dV*((N*a)*(b.transpose()*B).transpose()); }
317bool FloatMatrix :: beInverseOf(const FloatMatrix &src){
318 Eigen::FullPivLU<Eigen::MatrixXd> lu(src);
319 // lu.setThreshold(1e-30); // this is what the original code uses
320 if(!lu.isInvertible()) return false;
321 *this=lu.inverse();
322 return true;
323}
324void FloatMatrix :: beSubMatrixOf(const FloatMatrix &src, Index topRow, Index bottomRow, Index topCol, Index bottomCol){ *this=src.block(topRow-1,topCol-1,bottomRow-topRow+1,bottomCol-topCol+1); }
325void FloatMatrix :: beSubMatrixOf(const FloatMatrix &src, const IntArray &indxRow, const IntArray &indxCol) { *this=src(indxRow.minusOne(),indxCol.minusOne()); }
326void FloatMatrix::add(const FloatMatrix& a) { if(!a.isNotEmpty()) return; if(!isNotEmpty()){ *this=a; return; } *this+=a; }
327void FloatMatrix::add(double s, const FloatMatrix& a){ if(!a.isNotEmpty()) return; if(!isNotEmpty()){ *this=s*a; return; } *this+=s*a; }
328void FloatMatrix :: subtract(const FloatMatrix &a) { if(!a.isNotEmpty()) return; if(!isNotEmpty()){ *this=-a; return; } *this-=a; }
329FloatMatrix FloatMatrix :: fromArray(const FloatArray &vector, bool transposed){ if(transposed) return vector.transpose(); return vector; }
330void FloatMatrix :: zero() { this->setZero(); }
331void FloatMatrix :: beUnitMatrix(){ if(!this->isSquare()) OOFEM_ERROR("cannot make unit matrix of %ld by %ld matrix", rows(), cols()); *this=Eigen::MatrixXd::setIdentity(); }
332double FloatMatrix :: giveDeterminant() const { return this->determinant(); }
333void FloatMatrix :: beDiagonal(const FloatArray &diag) { *this=diag.asDiagonal().toDenseMatrix(); }
334double FloatMatrix :: giveTrace() const { return this->trace(); }
335#endif
336
337#ifndef _USE_EIGEN
338
339bool FloatMatrix :: isAllFinite() const
340{
341 for(Index r=0; r<rows(); r++) for(Index c=0; c<cols(); c++){
342 if ( !std::isfinite((*this)(r,c)) ) {
343 return false;
344 }
345 }
346
347 return true;
348}
349
350
351void FloatMatrix :: beTranspositionOf(const FloatMatrix &src)
352{
353 // receiver becomes a transposition of src
354 int nrows = src.giveNumberOfColumns(), ncols = src.giveNumberOfRows();
355 _resize_internal(nrows, ncols);
356
357 for ( int i = 1; i <= nrows; i++ ) {
358 for ( int j = 1; j <= ncols; j++ ) {
359 this->at(i, j) = src.at(j, i);
360 }
361 }
362}
363
364
365void FloatMatrix :: beProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix)
366// Receiver = aMatrix * bMatrix
367{
368# ifndef NDEBUG
369 if ( aMatrix.cols() != bMatrix.rows() ) {
370 OOFEM_ERROR("error in product A*B : dimensions do not match, A(*,%d), B(%d,*)", aMatrix.cols(), bMatrix.rows());
371 }
372# endif
373 _resize_internal(aMatrix.rows(), bMatrix.cols());
374# ifdef __LAPACK_MODULE
375 const int this_nColumns=cols(), this_nRows=rows();
376 const int aMatrix_nColumns=aMatrix.cols(), aMatrix_nRows=aMatrix.rows();
377 const int bMatrix_nColumns=bMatrix.cols(), bMatrix_nRows=bMatrix.rows();
378 double alpha = 1., beta = 0.;
379 dgemm_("n", "n", & this_nRows, & this_nColumns, & aMatrix_nColumns,
380 & alpha, aMatrix.givePointer(), & aMatrix_nRows, bMatrix.givePointer(), & bMatrix_nRows,
381 & beta, this->givePointer(), & this_nRows,
382 aMatrix_nColumns, bMatrix_nColumns, this_nColumns);
383# else
384 for ( Index i = 1; i <= aMatrix.rows(); i++ ) {
385 for ( Index j = 1; j <= bMatrix.cols(); j++ ) {
386 double coeff = 0.;
387 for ( Index k = 1; k <= aMatrix.cols(); k++ ) {
388 coeff += aMatrix.at(i, k) * bMatrix.at(k, j);
389 }
390
391 this->at(i, j) = coeff;
392 }
393 }
394# endif
395}
396
397
398void FloatMatrix :: beTProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix)
399// Receiver = aMatrix^T * bMatrix
400{
401# ifndef NDEBUG
402 if ( aMatrix.rows() != bMatrix.rows() ) {
403 OOFEM_ERROR("error in product A*B : dimensions do not match");
404 }
405# endif
406 _resize_internal(aMatrix.cols(), bMatrix.cols());
407# ifdef __LAPACK_MODULE
408 double alpha = 1., beta = 0.;
409 const int this_nColumns=cols(), this_nRows=rows();
410 const int aMatrix_nColumns=aMatrix.cols(), aMatrix_nRows=aMatrix.rows();
411 const int bMatrix_nColumns=bMatrix.cols(), bMatrix_nRows=bMatrix.rows();
412 dgemm_("t", "n", & this_nRows, & this_nColumns, & aMatrix_nRows,
413 & alpha, aMatrix.givePointer(), & aMatrix_nRows, bMatrix.givePointer(), & bMatrix_nRows,
414 & beta, this->givePointer(), & this_nRows,
415 aMatrix_nColumns, bMatrix_nColumns, this_nColumns);
416# else
417 for ( Index i = 1; i <= aMatrix.cols(); i++ ) {
418 for (Index j = 1; j <= bMatrix.cols(); j++ ) {
419 double coeff = 0.;
420 for (Index k = 1; k <= aMatrix.rows(); k++ ) {
421 coeff += aMatrix.at(k, i) * bMatrix.at(k, j);
422 }
423
424 this->at(i, j) = coeff;
425 }
426 }
427#endif
428}
429
430
431void FloatMatrix :: beProductTOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix)
432// Receiver = aMatrix * bMatrix^T
433{
434# ifndef NDEBUG
435 if ( aMatrix.cols() != bMatrix.cols() ) {
436 OOFEM_ERROR("error in product A*B : dimensions do not match");
437 }
438# endif
439 _resize_internal(aMatrix.rows(), bMatrix.rows());
440# ifdef __LAPACK_MODULE
441 const int this_nColumns=cols(), this_nRows=rows();
442 const int aMatrix_nColumns=aMatrix.cols(), aMatrix_nRows=aMatrix.rows();
443 const int bMatrix_nColumns=bMatrix.cols(), bMatrix_nRows=bMatrix.rows();
444 double alpha = 1., beta = 0.;
445 dgemm_("n", "t", & this_nRows, & this_nColumns, & aMatrix_nColumns,
446 & alpha, aMatrix.givePointer(), & aMatrix_nRows, bMatrix.givePointer(), & bMatrix_nRows,
447 & beta, this->givePointer(), & this_nRows,
448 aMatrix_nColumns, bMatrix_nColumns, this_nColumns);
449# else
450 for (Index i = 1; i <= aMatrix.rows(); i++ ) {
451 for (Index j = 1; j <= bMatrix.rows(); j++ ) {
452 double coeff = 0.;
453 for (Index k = 1; k <= aMatrix.cols(); k++ ) {
454 coeff += aMatrix.at(i, k) * bMatrix.at(j, k);
455 }
456
457 this->at(i, j) = coeff;
458 }
459 }
460# endif
461}
462
463
464void FloatMatrix :: addProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix)
465// Receiver = aMatrix * bMatrix
466{
467# ifndef NDEBUG
468 if ( aMatrix.cols() != bMatrix.rows() ) {
469 OOFEM_ERROR("error in product A*B : dimensions do not match");
470 }
471 if ( aMatrix.rows() != this->rows() || bMatrix.cols() != this->cols() ) {
472 OOFEM_ERROR("error in product receiver : dimensions do not match");
473 }
474# endif
475
476# ifdef __LAPACK_MODULE
477 const int this_nColumns=cols(), this_nRows=rows();
478 const int aMatrix_nColumns=aMatrix.cols(), aMatrix_nRows=aMatrix.rows();
479 const int bMatrix_nColumns=bMatrix.cols(), bMatrix_nRows=bMatrix.rows();
480 double alpha = 1., beta = 1.;
481 dgemm_("n", "n", & this_nRows, & this_nColumns, & aMatrix_nColumns,
482 & alpha, aMatrix.givePointer(), & aMatrix_nRows, bMatrix.givePointer(), & bMatrix_nRows,
483 & beta, this->givePointer(), & this_nRows,
484 aMatrix_nColumns, bMatrix_nColumns, this_nColumns);
485# else
486 for (Index i = 1; i <= aMatrix.rows(); i++ ) {
487 for (Index j = 1; j <= bMatrix.cols(); j++ ) {
488 double coeff = 0.;
489 for (Index k = 1; k <= aMatrix.cols(); k++ ) {
490 coeff += aMatrix.at(i, k) * bMatrix.at(k, j);
491 }
492
493 this->at(i, j) += coeff;
494 }
495 }
496# endif
497}
498
499void FloatMatrix :: addTProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix)
500// Receiver += aMatrix^T * bMatrix
501{
502# ifndef NDEBUG
503 if ( aMatrix.rows() != bMatrix.rows() ) {
504 OOFEM_ERROR("error in product A*B : dimensions do not match");
505 }
506 if ( aMatrix.cols() != this->cols() || bMatrix.cols() != this->rows() ) {
507 OOFEM_ERROR("error in product receiver : dimensions do not match");
508 }
509# endif
510
511# ifdef __LAPACK_MODULE
512 double alpha = 1., beta = 1.;
513 const int this_nColumns=cols(), this_nRows=rows();
514 const int aMatrix_nColumns=aMatrix.cols(), aMatrix_nRows=aMatrix.rows();
515 const int bMatrix_nColumns=bMatrix.cols(), bMatrix_nRows=bMatrix.rows();
516 dgemm_("t", "n", & this_nRows, & this_nColumns, & aMatrix_nRows,
517 & alpha, aMatrix.givePointer(), & aMatrix_nRows, bMatrix.givePointer(), & bMatrix_nRows,
518 & beta, this->givePointer(), & this_nRows,
519 aMatrix_nColumns, bMatrix_nColumns, this_nColumns);
520# else
521 for (Index i = 1; i <= aMatrix.cols(); i++ ) {
522 for (Index j = 1; j <= bMatrix.cols(); j++ ) {
523 double coeff = 0.;
524 for (Index k = 1; k <= aMatrix.rows(); k++ ) {
525 coeff += aMatrix.at(k, i) * bMatrix.at(k, j);
526 }
527
528 this->at(i, j) += coeff;
529 }
530 }
531# endif
532}
533
534
535void FloatMatrix :: beDyadicProductOf(const FloatArray &vec1, const FloatArray &vec2)
536// Receiver = vec1 * vec2^T
537{
538 int n1 = vec1.giveSize();
539 int n2 = vec2.giveSize();
540 _resize_internal(n1, n2);
541 for ( int j = 1; j <= n2; j++ ) {
542 for ( int i = 1; i <= n1; i++ ) {
543 this->at(i, j) = vec1.at(i) * vec2.at(j);
544 }
545 }
546}
547
548
549void FloatMatrix :: setSubMatrix(const FloatMatrix &src, int sr, int sc)
550{
551 sr--;
552 sc--;
553
554 int srcRows = src.giveNumberOfRows(), srcCols = src.giveNumberOfColumns();
555#ifndef NDEBUG
556 int nr = sr + srcRows;
557 int nc = sc + srcCols;
558
559 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) {
560 OOFEM_ERROR("Sub matrix doesn't fit inside allocated space.");
561 }
562#endif
563
564 // add sub-matrix
565 for ( int j = 0; j < srcCols; j++ ) {
566 for ( int i = 0; i < srcRows; i++ ) {
567 ( * this )( sr + i, sc + j ) = src(i, j);
568 }
569 }
570 //memcpy( &(*this)(sr + 0, sc + j), &src(0,j), srcRows * sizeof(int));
571}
572
573
574void FloatMatrix :: setTSubMatrix(const FloatMatrix &src, int sr, int sc)
575{
576 sr--;
577 sc--;
578
579 int srcRows = src.giveNumberOfRows(), srcCols = src.giveNumberOfColumns();
580#ifndef NDEBUG
581 int nr = sr + srcCols;
582 int nc = sc + srcRows;
583
584 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) {
585 OOFEM_ERROR("Sub matrix doesn't fit inside allocated space");
586 }
587#endif
588
589 // add sub-matrix
590 for ( int i = 0; i < srcCols; i++ ) {
591 for ( int j = 0; j < srcRows; j++ ) {
592 ( * this )( sr + i, sc + j ) = src(j, i);
593 }
594 }
595}
596
597
598
599
600void FloatMatrix :: addSubVectorRow(const FloatArray &src, int sr, int sc)
601{
602 sc--;
603
604 int srcCols = src.giveSize();
605
606 int nr = sr;
607 int nc = sc + srcCols;
608
609 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) {
610 this->resizeWithData( max(this->giveNumberOfRows(), nr), max(this->giveNumberOfColumns(), nc) );
611 }
612
613 // add sub-matrix
614 for ( int j = 1; j <= srcCols; j++ ) {
615 this->at(sr, sc + j) += src.at(j);
616 }
617}
618
619
620
621
622void FloatMatrix :: addSubVectorCol(const FloatArray &src, int sr, int sc)
623{
624 sr--;
625
626 int srcRows = src.giveSize();
627
628 int nr = sr + srcRows;
629 int nc = sc;
630
631 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) {
632 this->resizeWithData( max(this->giveNumberOfRows(), nr), max(this->giveNumberOfColumns(), nc) );
633 }
634
635 // add sub-matrix
636 for ( int j = 1; j <= srcRows; j++ ) {
637 this->at(sr + j, sc) += src.at(j);
638 }
639}
640
641void FloatMatrix :: setColumn(const FloatArray &src, int c)
642{
643 int nr = src.giveSize();
644#ifndef NDEBUG
645 if ( this->giveNumberOfRows() != nr || c < 1 || c > this->giveNumberOfColumns() ) {
646 OOFEM_ERROR("Size mismatch");
647 }
648#endif
649
650 for(int r=0; r<nr; r++) (*this)(r,c-1)=src(r);
651}
652
653
654void FloatMatrix :: copyColumn(FloatArray &dest, int c) const
655{
656 int nr = this->giveNumberOfRows();
657#ifndef NDEBUG
658 if ( c < 1 || c > this->giveNumberOfColumns() ) {
659 OOFEM_ERROR("Column outside range (%d)", c);
660 }
661#endif
662
663 dest.resize(nr);
664 for(int r=0; r<nr; r++) dest(r)=(*this)(r,c-1);
665}
666
667void FloatMatrix :: plusDyadSymmUpper(const FloatArray &a, double dV)
668{
669 if ( !this->isNotEmpty() ) {
670 this->resize(a.giveSize(),a.giveSize());
671 }
672#ifdef __LAPACK_MODULE
673 int inc = 1;
674 int sizeA = a.giveSize();
675 const int this_nColumns=cols(), this_nRows=rows();
676 dsyr_("u", & sizeA, & dV, a.givePointer(), & inc,
677 this->givePointer(), & this_nRows,
678 sizeA, this_nColumns);
679#else
680 for (Index i = 1; i <= rows(); i++ ) {
681 for (Index j = i; j <= cols(); j++ ) {
682 this->at(i, j) += a.at(i) * a.at(j) * dV;
683 }
684 }
685#endif
686}
687
688
689
690
691void FloatMatrix :: plusProductUnsym(const FloatMatrix &a, const FloatMatrix &b, double dV)
692// Adds to the receiver the product a(transposed).b dV .
693// If the receiver has a null size, it is expanded.
694// Advantage : does not compute the transposition of matrix a.
695{
696 if ( !this->isNotEmpty() ) {
697 this->resize(a.cols(),b.cols());
698 }
699#ifdef __LAPACK_MODULE
700 const int this_nColumns=cols(), this_nRows=rows();
701 const int a_nColumns=a.cols(), a_nRows=a.rows();
702 const int b_nColumns=b.cols(), b_nRows=b.rows();
703 double beta = 1.;
704 dgemm_("t", "n", & this_nRows, & this_nColumns, & a_nRows,
705 & dV, a.givePointer(), & a_nRows, b.givePointer(), & b_nRows,
706 & beta, this->givePointer(), & this_nRows,
707 a_nColumns, b_nColumns, this_nColumns);
708#else
709 for (Index i = 1; i <= rows(); i++ ) {
710 for (Index j = 1; j <= cols(); j++ ) {
711 double summ = 0.;
712 for (Index k = 1; k <= a.rows(); k++ ) {
713 summ += a.at(k, i) * b.at(k, j);
714 }
715
716 this->at(i, j) += summ * dV;
717 }
718 }
719#endif
720}
721
722
723void FloatMatrix :: plusDyadUnsym(const FloatArray &a, const FloatArray &b, double dV)
724{
725 if ( !this->isNotEmpty() ) {
726 this->resize(a.giveSize(),b.giveSize());
727 }
728#ifdef __LAPACK_MODULE
729 int inc = 1;
730 int sizeA = a.giveSize();
731 int sizeB = b.giveSize();
732 const int this_nColumns=cols(), this_nRows=rows();
733 dger_(& sizeA, & sizeB, & dV, a.givePointer(), & inc,
734 b.givePointer(), & inc, this->givePointer(), & this_nRows,
735 sizeA, sizeB, this_nColumns);
736#else
737 for (Index i = 1; i <= rows(); i++ ) {
738 for (Index j = 1; j <= cols(); j++ ) {
739 this->at(i, j) += a.at(i) * b.at(j) * dV;
740 }
741 }
742#endif
743}
744
745void FloatMatrix :: plus_Nt_a_otimes_b_B(const FloatMatrix &N, const FloatArray &a, const FloatArray &b, const FloatMatrix &B, double dV)
746{
747 if ( !this->isNotEmpty() ) {
748 this->nRows = N.nColumns;
749 this->nColumns = B.nColumns;
750 this->values.assign(this->nRows * this->nColumns, 0.);
751 }
752 auto a_size = a.giveSize();
753 auto b_size = b.giveSize();
754 for (std::size_t i = 1; i <= nRows; i++ ) {
755 for (std::size_t j = 1; j <= nColumns; j++ ) {
756 for (int k = 1; k <= a_size; k++ ) {
757 for (int l = 1; l <= b_size; l++ ) {
758 this->at(i, j) += N.at(k,i) * a.at(k) * b.at(l) * B.at(l,j) * dV;
759 }
760 }
761 }
762 }
763}
764
765
766
767
768bool FloatMatrix :: beInverseOf(const FloatMatrix &src)
769// Receiver becomes inverse of given parameter src. If necessary, size is adjusted.
770{
771 double det;
772
773# ifndef NDEBUG
774 if ( !src.isSquare() ) {
775 OOFEM_ERROR("cannot inverse a %d by %d matrix", src.rows(), src.cols());
776 }
777# endif
778
779 _resize_internal(src.rows(), src.cols());
780 int nRows=this->rows();
781
782 if ( nRows == 1 ) {
783 if (fabs(src.at(1,1)) > 1.e-30) {
784 this->at(1, 1) = 1. / src.at(1, 1);
785 return true;
786 } else {
787 return false;
788 }
789 } else if ( nRows == 2 ) {
790 det = src.at(1, 1) * src.at(2, 2) - src.at(1, 2) * src.at(2, 1);
791 if (fabs(det)>1.e-30) {
792 this->at(1, 1) = src.at(2, 2) / det;
793 this->at(2, 1) = -src.at(2, 1) / det;
794 this->at(1, 2) = -src.at(1, 2) / det;
795 this->at(2, 2) = src.at(1, 1) / det;
796 return true;
797 } else {
798 return false;
799 }
800 } else if ( nRows == 3 ) {
801 det = src.at(1, 1) * src.at(2, 2) * src.at(3, 3) + src.at(1, 2) * src.at(2, 3) * src.at(3, 1) +
802 src.at(1, 3) * src.at(2, 1) * src.at(3, 2) - src.at(1, 3) * src.at(2, 2) * src.at(3, 1) -
803 src.at(2, 3) * src.at(3, 2) * src.at(1, 1) - src.at(3, 3) * src.at(1, 2) * src.at(2, 1);
804 if (fabs(det)>1.e-30) {
805 this->at(1, 1) = ( src.at(2, 2) * src.at(3, 3) - src.at(2, 3) * src.at(3, 2) ) / det;
806 this->at(2, 1) = ( src.at(2, 3) * src.at(3, 1) - src.at(2, 1) * src.at(3, 3) ) / det;
807 this->at(3, 1) = ( src.at(2, 1) * src.at(3, 2) - src.at(2, 2) * src.at(3, 1) ) / det;
808 this->at(1, 2) = ( src.at(1, 3) * src.at(3, 2) - src.at(1, 2) * src.at(3, 3) ) / det;
809 this->at(2, 2) = ( src.at(1, 1) * src.at(3, 3) - src.at(1, 3) * src.at(3, 1) ) / det;
810 this->at(3, 2) = ( src.at(1, 2) * src.at(3, 1) - src.at(1, 1) * src.at(3, 2) ) / det;
811 this->at(1, 3) = ( src.at(1, 2) * src.at(2, 3) - src.at(1, 3) * src.at(2, 2) ) / det;
812 this->at(2, 3) = ( src.at(1, 3) * src.at(2, 1) - src.at(1, 1) * src.at(2, 3) ) / det;
813 this->at(3, 3) = ( src.at(1, 1) * src.at(2, 2) - src.at(1, 2) * src.at(2, 1) ) / det;
814 return true;
815 } else {
816 return false;
817 }
818 } else {
819 #ifdef __LAPACK_MODULE
820 const int this_nRows=rows();
821 IntArray ipiv(this_nRows);
822 int lwork, info;
823 * this = src;
824
825 // LU-factorization
826 dgetrf_(& this_nRows, & this_nRows, this->givePointer(), & this_nRows, ipiv.givePointer(), & info);
827 if ( info != 0 ) {
828 OOFEM_WARNING("dgetrf error %d", info);
829 return false;
830 }
831
832 // Inverse
833 lwork = this_nRows * this_nRows;
834 FloatArray work(lwork);
835 dgetri_(& this_nRows, this->givePointer(), & this_nRows, ipiv.givePointer(), work.givePointer(), & lwork, & info);
836 if ( info > 0 ) {
837 OOFEM_WARNING("Singular at %d", info);
838 return false;
839 } else if ( info < 0 ) {
840 OOFEM_ERROR("Error on input %d", info);
841 }
842 #else
843 // size >3 ... gaussian elimination - slow but safe
844 //
845 double piv, linkomb;
846 FloatMatrix tmp = src;
847 // initialize answer to be unity matrix;
848 this->zero();
849 for (Index i = 1; i <= nRows; i++ ) {
850 this->at(i, i) = 1.0;
851 }
852
853 // lower triangle elimination by columns
854 for (Index i = 1; i < nRows; i++ ) {
855 piv = tmp.at(i, i);
856 if ( fabs(piv) < 1.e-30 ) {
857 OOFEM_WARNING("pivot (%d,%d) to close to small (< 1.e-20)", i, i);
858 return false;
859 }
860
861 for (Index j = i + 1; j <= nRows; j++ ) {
862 linkomb = tmp.at(j, i) / tmp.at(i, i);
863 for (Index k = i; k <= nRows; k++ ) {
864 tmp.at(j, k) -= tmp.at(i, k) * linkomb;
865 }
866
867 for (Index k = 1; k <= nRows; k++ ) {
868 this->at(j, k) -= this->at(i, k) * linkomb;
869 }
870 }
871 }
872
873 // upper triangle elimination by columns
874 for ( Index i = nRows; i > 1; i-- ) {
875 piv = tmp.at(i, i);
876 for ( Index j = i - 1; j > 0; j-- ) {
877 linkomb = tmp.at(j, i) / piv;
878 for ( Index k = i; k > 0; k-- ) {
879 tmp.at(j, k) -= tmp.at(i, k) * linkomb;
880 }
881
882 for ( Index k = nRows; k > 0; k-- ) {
883 // tmp -> at(j,k)-= tmp ->at(i,k)*linkomb;
884 this->at(j, k) -= this->at(i, k) * linkomb;
885 }
886 }
887 }
888
889 // diagonal scaling
890 for ( Index i = 1; i <= nRows; i++ ) {
891 for ( Index j = 1; j <= nRows; j++ ) {
892 this->at(i, j) /= tmp.at(i, i);
893 }
894 }
895 #endif
896 return true;
897 }
898}
899
900
901void FloatMatrix :: beSubMatrixOf(const FloatMatrix &src,
902 Index topRow, Index bottomRow, Index topCol, Index bottomCol)
903/*
904 * modifies receiver to be submatrix of the src matrix
905 * size of receiver submatrix is determined from
906 * input parameters
907 */
908{
909#ifndef NDEBUG
910 if ( ( topRow < 1 ) || ( bottomRow < 1 ) || ( topCol < 1 ) || ( bottomCol < 1 ) ) {
911 OOFEM_ERROR("subindexes size mismatch");
912 }
913
914 if ( ( src.rows() < bottomRow ) || ( src.cols() < bottomCol ) || ( ( bottomRow - topRow ) > src.rows() ) ||
915 ( ( bottomCol - topCol ) > src.cols() ) ) {
916 OOFEM_ERROR("subindexes size mismatch");
917 }
918#endif
919
920
921 Index topRm1, topCm1;
922 topRm1 = topRow - 1;
923 topCm1 = topCol - 1;
924
925 // allocate return value
926 this->resize(bottomRow - topRm1, bottomCol - topCm1);
927 for (Index i = topRow; i <= bottomRow; i++ ) {
928 for (Index j = topCol; j <= bottomCol; j++ ) {
929 this->at(i - topRm1, j - topCm1) = src.at(i, j);
930 }
931 }
932}
933
934
935
936void
937FloatMatrix :: beSubMatrixOf(const FloatMatrix &src, const IntArray &indxRow, const IntArray &indxCol)
938/*
939 * Modifies receiver to be a sub-matrix of the src matrix.
940 * sub-matrix has size(indxRow) x size(indxCol) with values given as
941 * this(i,j) = src( indxRow(i), indxCol(j) )
942 */
943{
944# ifndef NDEBUG
945 if ( indxRow.maximum() > src.giveNumberOfRows() || indxCol.maximum() > src.giveNumberOfColumns() ||
946 indxRow.minimum() < 1 || indxCol.minimum() < 1 ) {
947 OOFEM_ERROR("index exceeds source dimensions");
948 }
949# endif
950
951 int szRow = indxRow.giveSize();
952 int szCol = indxCol.giveSize();
953 this->resize(szRow, szCol);
954
955 for ( int i = 1; i <= szRow; i++ ) {
956 for ( int j = 1; j <= szCol; j++ ) {
957 this->at(i, j) = src.at( indxRow.at(i), indxCol.at(j) );
958 }
959 }
960}
961
962void FloatMatrix :: add(const FloatMatrix &aMatrix)
963// Adds aMatrix to the receiver. If the receiver has a null size,
964// adjusts its size to that of aMatrix. Returns the modified receiver.
965{
966 if ( aMatrix.rows() == 0 || aMatrix.cols() == 0 ) {
967 return;
968 }
969
970 if ( !this->isNotEmpty() ) {
971 this->operator = ( aMatrix );
972 return;
973 }
974# ifndef NDEBUG
975 if ( ( aMatrix.rows() != rows() || aMatrix.cols() != cols() ) && aMatrix.isNotEmpty() ) {
976 OOFEM_ERROR("dimensions mismatch : (r1,c1)+(r2,c2) : (%d,%d)+(%d,%d)", rows(), cols(), aMatrix.rows(), aMatrix.cols());
977 }
978# endif
979
980#ifdef __LAPACK_MODULE
981 int aSize = aMatrix.rows() * aMatrix.cols();
982 int inc = 1;
983 double s = 1.;
984 daxpy_(& aSize, & s, aMatrix.givePointer(), & inc, this->givePointer(), & inc, aSize, aSize);
985#else
986 _LOOP_MATRIX(r,c){ (*this)(r,c)+=aMatrix(r,c); }
987#endif
988}
989
990
991void FloatMatrix :: add(double s, const FloatMatrix &aMatrix)
992// Adds aMatrix to the receiver. If the receiver has a null size,
993// adjusts its size to that of aMatrix. Returns the modified receiver.
994{
995 if ( aMatrix.rows() == 0 || aMatrix.cols() == 0 ) {
996 return;
997 }
998
999 if ( !this->isNotEmpty() ) {
1000 this->operator = ( aMatrix );
1001 this->times(s);
1002 return;
1003 }
1004# ifndef NDEBUG
1005 if ( ( aMatrix.rows() != rows() || aMatrix.cols() != cols() ) && aMatrix.isNotEmpty() ) {
1006 OOFEM_ERROR("dimensions mismatch : (r1,c1)+(r2,c2) : (%d,%d)+(%d,%d)", rows(), cols(), aMatrix.rows(), aMatrix.cols());
1007 }
1008# endif
1009
1010#ifdef __LAPACK_MODULE
1011 int aSize = aMatrix.rows() * aMatrix.cols();
1012 int inc = 1;
1013 daxpy_(& aSize, & s, aMatrix.givePointer(), & inc, this->givePointer(), & inc, aSize, aSize);
1014#else
1015 _LOOP_MATRIX(r,c){ (*this)(r,c)+=s*aMatrix(r,c); }
1016#endif
1017}
1018
1019
1020void FloatMatrix :: subtract(const FloatMatrix &aMatrix)
1021// Adds aMatrix to the receiver. If the receiver has a null size,
1022// adjusts its size to that of aMatrix. Returns the modified receiver.
1023{
1024 if ( !this->isNotEmpty() ) {
1025 this->operator = ( aMatrix );
1026 this->negated();
1027 return;
1028 }
1029# ifndef NDEBUG
1030 if ( ( aMatrix.rows() != rows() || aMatrix.cols() != cols() ) && aMatrix.isNotEmpty() ) {
1031 OOFEM_ERROR("dimensions mismatch : (r1,c1)-(r2,c2) : (%d,%d)-(%d,%d)", rows(), cols(), aMatrix.rows(), aMatrix.cols());
1032 }
1033# endif
1034
1035#ifdef __LAPACK_MODULE
1036 int aSize = aMatrix.rows() * aMatrix.cols();
1037 int inc = 1;
1038 double s = -1.;
1039 daxpy_(& aSize, & s, aMatrix.givePointer(), & inc, this->givePointer(), & inc, aSize, aSize);
1040#else
1041 _LOOP_MATRIX(r,c){ (*this)(r,c)-=aMatrix(r,c); }
1042#endif
1043}
1044
1045
1046FloatMatrix FloatMatrix :: fromArray(const FloatArray &vector, bool transposed)
1047//
1048// constructor : creates (vector->giveSize(),1) FloatMatrix
1049// if transpose = 1 creates (1,vector->giveSize()) FloatMatrix
1050//
1051{
1052 FloatMatrix ret;
1053 if ( transposed ) {
1054 ret.resize(1,vector.size());
1055 for(int c=0; c<ret.cols(); c++) ret(0,c)=vector(c);
1056 } else {
1057 ret.resize(vector.size(),1);
1058 for(int r=0; r<ret.rows(); r++) ret(r,0)=vector(r);
1059 }
1060 return ret;
1061}
1062
1063
1064void FloatMatrix :: zero()
1065{
1066 _LOOP_MATRIX(r,c) (*this)(r,c)=0.;
1067}
1068
1069
1070void FloatMatrix :: beUnitMatrix()
1071{
1072 #ifndef NDEBUG
1073 if ( !this->isSquare() ) {
1074 OOFEM_ERROR("cannot make unit matrix of %d by %d matrix", rows(), cols());
1075 }
1076 #endif
1077
1078 this->zero();
1079 for (Index i = 1; i <= rows(); i++ ) {
1080 this->at(i, i) = 1.0;
1081 }
1082}
1083
1084
1085double FloatMatrix :: giveDeterminant() const
1086// Returns the determinant of the receiver.
1087{
1088 # ifndef NDEBUG
1089 if ( !this->isSquare() ) {
1090 OOFEM_ERROR("cannot compute the determinant of a non-square %d by %d matrix", rows(), cols());
1091 }
1092 # endif
1093 const FloatMatrix& m(*this);
1094 if ( rows() == 1 ) {
1095 return m(0,0);
1096 } else if ( rows() == 2 ) {
1097 // return ( values [ 0 ] * values [ 3 ] - values [ 1 ] * values [ 2 ] );
1098 return m(0,0)*m(1,1)-m(1,0)*m(0,1);
1099 // return ( values [ 0 ] * values [ 3 ] - values [ 1 ] * values [ 2 ] );
1100 } else if ( rows() == 3 ) {
1101 return
1102 m(0,0)*m(1,1)*m(2,2)+m(1,0)*m(2,1)*m(0,2)+m(2,0)*m(0,1)*m(1,2)
1103 -m(0,2)*m(1,1)*m(2,0)-m(1,2)*m(2,1)*m(0,0)-m(2,2)*m(0,1)*m(1,0);
1104 }
1105
1106 OOFEM_ERROR("sorry, cannot compute the determinant of a matrix larger than 3x3");
1107 // return 0.;
1108}
1109
1110
1111void FloatMatrix :: beDiagonal(const FloatArray &diag)
1112{
1113 int n = diag.giveSize();
1114 this->resize(n, n);
1115 for ( int i = 0; i < n; ++i ) {
1116 (*this)(i, i) = diag[i];
1117 }
1118}
1119
1120
1121double FloatMatrix :: giveTrace() const
1122{
1123 # ifndef NDEBUG
1124 if ( !this->isSquare() ) {
1125 OOFEM_ERROR("cannot compute the trace of a non-square %d by %d matrix", rows(), cols());
1126 }
1127 # endif
1128 double answer = 0.;
1129 for (Index k = 0; k < rows(); k++ ) {
1130 answer += (*this)(k,k);;
1131 }
1132 return answer;
1133}
1134
1135
1136
1137void FloatMatrix :: symmetrized()
1138// Initializes the lower half of the receiver to the upper half.
1139{
1140 # ifndef NDEBUG
1141 if ( rows() != cols() ) {
1142 OOFEM_ERROR("cannot symmetrize a non-square matrix");
1143 }
1144
1145 # endif
1146
1147 for (Index i = 2; i <= rows(); i++ ) {
1148 for (Index j = 1; j < i; j++ ) {
1149 this->at(i, j) = this->at(j, i);
1150 }
1151 }
1152}
1153
1154
1155void FloatMatrix :: times(double factor)
1156// Multiplies every coefficient of the receiver by factor. Answers the
1157// modified receiver.
1158{
1159 _LOOP_MATRIX(r,c) (*this)(r,c)*=factor;
1160 // dscal_ seemed to be slower for typical usage of this function.
1161}
1162
1163
1164void FloatMatrix :: negated()
1165{
1166 _LOOP_MATRIX(r,c) (*this)(r,c)=-(*this)(r,c);
1167}
1168
1169
1170double FloatMatrix :: computeFrobeniusNorm() const
1171{
1172 // return sqrt( std :: inner_product(this->values.begin(), this->values.end(), this->values.begin(), 0.) );
1173 double ret=0;
1174 _LOOP_MATRIX(r,c) ret+=(*this)(r,c)*(*this)(r,c);
1175 return std::sqrt(ret);
1176}
1177
1178
1179double FloatMatrix :: computeNorm(char p) const
1180{
1181 # ifdef __LAPACK_MODULE
1182 const int this_nRows=rows(), this_nColumns=cols();
1183 FloatArray work( this_nRows );
1184 int lda = max(this_nRows, 1);
1185 double norm = dlange_(& p, & this_nRows, & this_nColumns, this->givePointer(), & lda, work.givePointer(), 1);
1186 return norm;
1187
1188 # else
1189 if ( p == '1' ) { // Maximum absolute column sum.
1190 double col_sum, max_col = 0.0;
1191 for (Index j = 1; j <= this->cols(); j++ ) {
1192 col_sum = 0.0;
1193 for (Index i = 1; i <= this->rows(); i++ ) {
1194 col_sum += fabs( this->at(i, j) );
1195 }
1196 if ( col_sum > max_col ) {
1197 max_col = col_sum;
1198 }
1199 }
1200 return max_col;
1201 }
1203 /*else if (p == '2') {
1204 * double lambda_max;
1205 * FloatMatrix AtA;
1206 * FloatArray eigs;
1207 * AtA.beTProductOf(*this,this);
1208 * Ata.eigenValues(eigs, 1);
1209 * return sqrt(eigs(0));
1210 * } */
1211 else {
1212 OOFEM_ERROR("p == %d not implemented.\n", p);
1213 // return 0.0;
1214 }
1215 # endif
1216}
1217
1218#endif
1219
1220
1221
1222void FloatMatrix :: copySubVectorRow(const FloatArray &src, int sr, int sc)
1223{
1224 sc--;
1225
1226 int srcCols = src.giveSize();
1227
1228 int nr = sr;
1229 int nc = sc + srcCols;
1230
1231 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) {
1232 this->resizeWithData( max(this->giveNumberOfRows(), nr), max(this->giveNumberOfColumns(), nc) );
1233 }
1234
1235 // add sub-matrix
1236 for ( int j = 1; j <= srcCols; j++ ) {
1237 this->at(sr, sc + j) = src.at(j);
1238 }
1239}
1240
1241
1242
1243void FloatMatrix :: plusProductSymmUpper(const FloatMatrix &a, const FloatMatrix &b, double dV)
1244// Adds to the receiver the product a(transposed).b dV .
1245// The receiver size is adjusted, if necessary.
1246// This method assumes that both the receiver and the product above are
1247// symmetric matrices, and therefore computes only the upper half of the
1248// receiver ; the lower half is not modified. Other advantage : it does
1249// not compute the transposition of matrix a.
1250{
1251 if ( !this->isNotEmpty() ) {
1252 this->resize(a.cols(),b.cols());
1253 }
1254
1255 #ifdef __LAPACK_MODULE
1256 const int this_nColumns=cols(), this_nRows=rows();
1257 const int a_nColumns=a.cols(), a_nRows=a.rows();
1258 const int b_nColumns=b.cols(), b_nRows=b.rows();
1259 double beta = 1.;
1262 if ( this_nRows < 20 ) {
1263 // Split the matrix into 2 columns, s1 + s2 = n ( = nRows = nColumns ).
1264 int s1 = this_nRows / 2;
1265 int s2 = this_nRows - s1;
1266 // First column block, we only take the first s rows by only taking the first s columns in the matrix a.
1267 dgemm_("t", "n", & s1, & s1, & a_nRows, & dV, a.givePointer(), & a_nRows, b.givePointer(), & b_nRows, & beta, this->givePointer(), & this_nRows, a_nColumns, b_nColumns, this_nColumns);
1268 // Second column block starting a memory position c * nRows
1269 dgemm_("t", "n", & this_nRows, & s2, & a_nRows, & dV, a.givePointer(), & a_nRows, & b.givePointer() [ s1 * b_nRows ], & b_nRows, & beta, & this->givePointer() [ s1 * this_nRows ], & this_nRows, a_nColumns, b_nColumns, this_nColumns);
1270 } else {
1271 // Get suitable blocksize. Around 10 rows should be suitable (slightly adjusted to minimize number of blocks):
1272 // Smaller blocks than ~10 didn't show any performance gains in my benchmarks. / Mikael
1273 int block = ( this_nRows - 1 ) / ( this_nRows / 10 ) + 1;
1274 int start = 0;
1275 int end = block;
1276 while ( start < this_nRows ) {
1277 int s = end - start;
1278 dgemm_("t", "n", & end, & s, & a_nRows, & dV, a.givePointer(), & a_nRows, & b.givePointer() [ start * b_nRows ], & b_nRows, & beta, & this->givePointer() [ start * this_nRows ],
1279 & this_nRows, a_nColumns, b_nColumns, this_nColumns);
1280 start = end;
1281 end += block;
1282 if ( end > this_nRows ) {
1283 end = this_nRows;
1284 }
1285 }
1286 }
1287 #else
1288 for (Index i = 1; i <= rows(); i++ ) {
1289 for (Index j = i; j <= cols(); j++ ) {
1290 double summ = 0.;
1291 for (Index k = 1; k <= a.rows(); k++ ) {
1292 summ += a.at(k, i) * b.at(k, j);
1293 }
1294
1295 this->at(i, j) += summ * dV;
1296 }
1297 }
1298 #endif
1299}
1300
1301
1302
1303bool FloatMatrix :: solveForRhs(const FloatArray &b, FloatArray &answer, bool transpose)
1304// solves equation b = this * x
1305{
1306# ifndef NDEBUG
1307 if ( !this->isSquare() ) {
1308 OOFEM_ERROR("cannot solve a %d by %d matrix", rows(), cols());
1309 }
1310
1311 if ( rows() != b.size() ) {
1312 OOFEM_ERROR("dimension mismatch");
1313 }
1314# endif
1315
1316#ifdef __LAPACK_MODULE
1317 int info, nrhs = 1;
1318 const int this_nRows=rows();
1319 IntArray ipiv(this_nRows);
1320 answer = b;
1321 //dgesv_( &this_nRows, &nrhs, this->givePointer(), &this_nRows, ipiv.givePointer(), answer.givePointer(), &this_nRows, &info );
1322 dgetrf_(& this_nRows, & this_nRows, this->givePointer(), & this_nRows, ipiv.givePointer(), & info);
1323 if ( info == 0 ) {
1324 dgetrs_(transpose ? "Transpose" : "No transpose", & this_nRows, & nrhs, this->givePointer(), & this_nRows, ipiv.givePointer(), answer.givePointer(), & this_nRows, & info);
1325 }
1326 if ( info != 0 ) {
1327 return false;
1328 }
1329#else
1330 Index pivRow;
1331 double piv, linkomb, help;
1332 FloatMatrix *mtrx, trans;
1333 if ( transpose ) {
1334 trans.beTranspositionOf(* this);
1335 mtrx = & trans;
1336 } else {
1337 mtrx = this;
1338 }
1339
1340 answer = b;
1341
1342 // initialize answer to be unity matrix;
1343 // lower triangle elimination by columns
1344 int nRows=this->rows();
1345 for ( Index i = 1; i < nRows; i++ ) {
1346 // find the suitable row and pivot
1347 piv = fabs( mtrx->at(i, i) );
1348 pivRow = i;
1349 for (Index j = i + 1; j <= nRows; j++ ) {
1350 if ( fabs( mtrx->at(j, i) ) > piv ) {
1351 pivRow = j;
1352 piv = fabs( mtrx->at(j, i) );
1353 }
1354 }
1355
1356 if ( piv < 1.e-20 ) {
1357 return false;
1358 }
1359
1360 // exchange rows
1361 if ( pivRow != i ) {
1362 for (Index j = i; j <= nRows; j++ ) {
1363 help = mtrx->at(i, j);
1364 mtrx->at(i, j) = mtrx->at(pivRow, j);
1365 mtrx->at(pivRow, j) = help;
1366 }
1367 help = answer.at(i);
1368 answer.at(i) = answer.at(pivRow);
1369 answer.at(pivRow) = help;
1370 }
1371
1372 for (Index j = i + 1; j <= nRows; j++ ) {
1373 linkomb = mtrx->at(j, i) / mtrx->at(i, i);
1374 for (Index k = i; k <= nRows; k++ ) {
1375 mtrx->at(j, k) -= mtrx->at(i, k) * linkomb;
1376 }
1377
1378 answer.at(j) -= answer.at(i) * linkomb;
1379 }
1380 }
1381
1382 // back substitution
1383 for ( Index i = nRows; i >= 1; i-- ) {
1384 help = 0.;
1385 for ( Index j = i + 1; j <= nRows; j++ ) {
1386 help += mtrx->at(i, j) * answer.at(j);
1387 }
1388
1389 answer.at(i) = ( answer.at(i) - help ) / mtrx->at(i, i);
1390 }
1391#endif
1392
1393 return true;
1394}
1395
1396
1397bool FloatMatrix :: solveForRhs(const FloatMatrix &b, FloatMatrix &answer, bool transpose)
1398// solves equation b = this * x
1399// returns x. this and b are kept untouched
1400//
1401// gaussian elimination - slow but safe
1402//
1403{
1404# ifndef NDEBUG
1405 if ( !this->isSquare() ) {
1406 OOFEM_ERROR("cannot solve a %d by %d matrix", rows(), cols());
1407 }
1408
1409 if ( rows() != b.rows() ) {
1410 OOFEM_ERROR("dimension mismatch");
1411 }
1412# endif
1413
1414#ifdef __LAPACK_MODULE
1415 int info;
1416 const int this_nRows=rows();
1417 IntArray ipiv(this_nRows);
1418 answer = b;
1419 const int answer_nColumns=answer.cols();
1420 dgetrf_(& this_nRows, & this_nRows, this->givePointer(), & this_nRows, ipiv.givePointer(), & info);
1421 if ( info == 0 ) {
1422 dgetrs_(transpose ? "t" : "n", & this_nRows, & answer_nColumns, this->givePointer(), & this_nRows, ipiv.givePointer(), answer.givePointer(), & this_nRows, & info);
1423 }
1424 if ( info != 0 ) {
1425 return false; //OOFEM_ERROR("error %d", info);
1426 }
1427#else
1428 Index pivRow, nPs;
1429 double piv, linkomb, help;
1430 FloatMatrix *mtrx, trans;
1431 if ( transpose ) {
1432 trans.beTranspositionOf(* this);
1433 mtrx = & trans;
1434 } else {
1435 mtrx = this;
1436 }
1437
1438 nPs = b.giveNumberOfColumns();
1439 answer = b;
1440 int nRows=this->rows();
1441 // initialize answer to be unity matrix;
1442 // lower triangle elimination by columns
1443 for (Index i = 1; i < nRows; i++ ) {
1444 // find the suitable row and pivot
1445 piv = fabs( mtrx->at(i, i) );
1446 pivRow = i;
1447 for (Index j = i + 1; j <= nRows; j++ ) {
1448 if ( fabs( mtrx->at(j, i) ) > piv ) {
1449 pivRow = j;
1450 piv = fabs( mtrx->at(j, i) );
1451 }
1452 }
1453
1454 if ( fabs(piv) < 1.e-20 ) {
1455 return false; //OOFEM_ERROR("pivot too small, cannot solve %d by %d matrix", nRows, nColumns);
1456 }
1457
1458 // exchange rows
1459 if ( pivRow != i ) {
1460 for (Index j = i; j <= nRows; j++ ) {
1461 help = mtrx->at(i, j);
1462 mtrx->at(i, j) = mtrx->at(pivRow, j);
1463 mtrx->at(pivRow, j) = help;
1464 }
1465
1466 for (Index j = 1; j <= nPs; j++ ) {
1467 help = answer.at(i, j);
1468 answer.at(i, j) = answer.at(pivRow, j);
1469 answer.at(pivRow, j) = help;
1470 }
1471 }
1472
1473 for (Index j = i + 1; j <= nRows; j++ ) {
1474 linkomb = mtrx->at(j, i) / mtrx->at(i, i);
1475 for (Index k = i; k <= nRows; k++ ) {
1476 mtrx->at(j, k) -= mtrx->at(i, k) * linkomb;
1477 }
1478
1479 for (Index k = 1; k <= nPs; k++ ) {
1480 answer.at(j, k) -= answer.at(i, k) * linkomb;
1481 }
1482 }
1483 }
1484
1485 // back substitution
1486 for ( Index i = nRows; i >= 1; i-- ) {
1487 for (Index k = 1; k <= nPs; k++ ) {
1488 help = 0.;
1489 for ( Index j = i + 1; j <= nRows; j++ ) {
1490 help += mtrx->at(i, j) * answer.at(j, k);
1491 }
1492
1493 answer.at(i, k) = ( answer.at(i, k) - help ) / mtrx->at(i, i);
1494 }
1495 }
1496#endif
1497 return true;
1498}
1499
1500
1501void FloatMatrix :: printYourself() const
1502// Prints the receiver on screen.
1503{
1504 printf("FloatMatrix with dimensions : %ld %ld\n",
1505 (long)rows(), (long)cols());
1506 if ( rows() <= 250 && cols() <= 250 ) {
1507 for (Index i = 1; i <= rows(); ++i ) {
1508 for (Index j = 1; j <= cols() && j <= 100; ++j ) {
1509 printf( "%10.3e ", this->at(i, j) );
1510 }
1511
1512 printf("\n");
1513 }
1514 } else {
1515 printf(" large matrix : coefficients not printed \n");
1516 }
1517}
1518
1519
1520void FloatMatrix :: printYourselfToFile(const std::string filename, const bool showDimensions) const
1521// Prints the receiver to file.
1522{
1523 std :: ofstream matrixfile (filename);
1524 if (matrixfile.is_open()) {
1525 if (showDimensions)
1526 matrixfile << "FloatMatrix with dimensions : " << rows() << ", " << cols() << "\n";
1527 matrixfile << std::scientific << std::right << std::setprecision(3);
1528 for (Index i = 1; i <= rows(); ++i ) {
1529 for (Index j = 1; j <= cols(); ++j ) {
1530 matrixfile << std::setw(10) << this->at(i, j) << "\t";
1531 }
1532
1533 matrixfile << "\n";
1534 }
1535 matrixfile.close();
1536 } else {
1537 OOFEM_ERROR("Failed to write to file");
1538 }
1539}
1540
1541
1542void FloatMatrix :: printYourself(const std::string &name) const
1543// Prints the receiver on screen.
1544{
1545 printf("%s (%ld x %ld): \n", name.c_str(), (long)rows(), (long)cols());
1546 if ( rows() <= 250 && cols() <= 250 ) {
1547 for (Index i = 1; i <= rows(); ++i ) {
1548 for (Index j = 1; j <= cols() && j <= 100; ++j ) {
1549 printf( "%10.3e ", this->at(i, j) );
1550 }
1551
1552 printf("\n");
1553 }
1554 } else {
1555 for (Index i = 1; i <= rows() && i <= 20; ++i ) {
1556 for (Index j = 1; j <= cols() && j <= 10; ++j ) {
1557 printf( "%10.3e ", this->at(i, j) );
1558 }
1559 if ( cols() > 10 ) printf(" ...");
1560 printf("\n");
1561 }
1562 if ( rows() > 20 ) printf(" ...\n");
1563 }
1564}
1565
1566
1567void FloatMatrix :: pY() const
1568// Prints the receiver on screen with higher accuracy than printYourself.
1569{
1570 printf("[");
1571 for (Index i = 1; i <= rows(); ++i ) {
1572 for (Index j = 1; j <= cols(); ++j ) {
1573 printf( "%20.15e", this->at(i, j) );
1574 if ( j < cols() ) {
1575 printf(",");
1576 } else {
1577 printf(";");
1578 }
1579 }
1580 }
1581
1582 printf("];\n");
1583}
1584
1585
1586void FloatMatrix :: writeCSV(const std :: string &name) const
1587{
1588 FILE *file = fopen(name.c_str(), "w");
1589 for (Index i = 1; i <= rows(); ++i ) {
1590 for (Index j = 1; j <= cols(); ++j ) {
1591 fprintf(file, "%10.3e, ", this->at(i, j) );
1592 }
1593
1594 fprintf(file, "\n");
1595 }
1596 fclose(file);
1597}
1598
1599
1600void FloatMatrix :: bePinvID()
1601// this matrix is the product of the 6x6 deviatoric projection matrix ID
1602// and the inverse scaling matrix Pinv
1603{
1604 FloatMatrix& m(*this);
1605 m.resize(6, 6);
1606 m(0,0)=m(1,1)=m(2,2)=2/3.;
1607 m(0,1)=m(0,2)=m(1,0)=m(2,0)=m(1,2)=m(2,1)=-1/3.;
1608 m(3,3)=m(4,4)=m(5,5)=1/2.;
1609}
1610
1611
1612void FloatMatrix :: rotatedWith(const FloatMatrix &r, char mode)
1613// Returns the receiver 'a' rotated according the change-of-base matrix r.
1614// The method performs the operation a = r^T . a . r . or the inverse
1615{
1616 FloatMatrix rta;
1617
1618 if ( mode == 'n' ) {
1619 rta.beTProductOf(r, * this); // r^T . a
1620 this->beProductOf(rta, r); // r^T . a . r
1621 } else if ( mode == 't' ) {
1622 rta.beProductOf(r, * this); // r . a
1623 this->beProductTOf(rta, r); // r . a . r^T
1624 } else {
1625 OOFEM_ERROR("unsupported mode");
1626 }
1627}
1628
1629
1630
1631
1632
1633void FloatMatrix :: beNMatrixOf(const FloatArray &n, int nsd)
1634{
1635 this->resize(nsd, n.giveSize() * nsd);
1636 for ( int i = 0; i < n.giveSize(); ++i ) {
1637 for ( int j = 0; j < nsd; ++j ) {
1638 ( * this )( j, i * nsd + j ) = n(i);
1639 }
1640 }
1641}
1642
1643
1644
1645
1646void FloatMatrix :: beLocalCoordSys(const FloatArray &normal)
1647{ //normal should be at the first position, easier for interface material models
1648 if ( normal.giveSize() == 1 ) {
1649 this->resize(1, 1);
1650 this->at(1, 1) = normal(0);
1651 } else if ( normal.giveSize() == 2 ) {
1652 this->resize(2, 2);
1653 this->at(1, 1) = normal(0);
1654 this->at(1, 2) = normal(1);
1655
1656 this->at(2, 1) = normal(1);
1657 this->at(2, 2) = -normal(0);
1658
1659 } else if ( normal.giveSize() == 3 ) {
1660 // Create a permutated vector of n, *always* length 1 and significantly different from n.
1661 FloatArray b, t = {
1662 normal(1), -normal(2), normal(0)
1663 }; // binormal and tangent
1664
1665 // Construct orthogonal vector
1666 double npn = t.dotProduct(normal);
1667 t.add(-npn, normal);
1668 t.normalize();
1669 b.beVectorProductOf(t, normal);
1670
1671 this->resize(3, 3);
1672 this->at(1, 1) = normal.at(1);
1673 this->at(1, 2) = normal.at(2);
1674 this->at(1, 3) = normal.at(3);
1675
1676 this->at(2, 1) = b.at(1);
1677 this->at(2, 2) = b.at(2);
1678 this->at(2, 3) = b.at(3);
1679
1680 this->at(3, 1) = t.at(1);
1681 this->at(3, 2) = t.at(2);
1682 this->at(3, 3) = t.at(3);
1683 } else {
1684 OOFEM_ERROR("Normal needs 1 to 3 components.");
1685 }
1686}
1687
1688
1689void FloatMatrix :: beMatrixForm(const FloatArray &aArray)
1690{
1691 // Revrites the vector on matrix form (symmetrized matrix used if size is 6),
1692 // order: 11, 22, 33, 23, 13, 12
1693 // order: 11, 22, 33, 23, 13, 12, 32, 31, 21
1694# ifndef NDEBUG
1695 if ( aArray.giveSize() != 6 && aArray.giveSize() != 9 ) {
1696 OOFEM_ERROR("matrix dimension is not 3x3");
1697 }
1698# endif
1699 this->resize(3, 3);
1700 if ( aArray.giveSize() == 9 ) {
1701 this->at(1, 1) = aArray.at(1);
1702 this->at(2, 2) = aArray.at(2);
1703 this->at(3, 3) = aArray.at(3);
1704 this->at(2, 3) = aArray.at(4);
1705 this->at(1, 3) = aArray.at(5);
1706 this->at(1, 2) = aArray.at(6);
1707 this->at(3, 2) = aArray.at(7);
1708 this->at(3, 1) = aArray.at(8);
1709 this->at(2, 1) = aArray.at(9);
1710 } else if ( aArray.giveSize() == 6 ) {
1711 this->at(1, 1) = aArray.at(1);
1712 this->at(2, 2) = aArray.at(2);
1713 this->at(3, 3) = aArray.at(3);
1714 this->at(2, 3) = aArray.at(4);
1715 this->at(1, 3) = aArray.at(5);
1716 this->at(1, 2) = aArray.at(6);
1717 this->at(3, 2) = aArray.at(4);
1718 this->at(3, 1) = aArray.at(5);
1719 this->at(2, 1) = aArray.at(6);
1720 }
1721}
1722
1723void FloatMatrix :: changeComponentOrder()
1724{
1725 // Changes index order between abaqus <-> OOFEM
1726//# ifndef NDEBUG
1727// if ( nRows != 6 || cols() != 6 ) {
1728// OOFEM_ERROR("matrix dimension is not 6x6");
1729// }
1730//# endif
1731
1732 if ( rows() == 6 && cols() == 6 ) {
1733 // This could probably be done more beautifully + efficiently.
1734
1735 std :: swap( this->at(4, 1), this->at(6, 1) );
1736
1737 std :: swap( this->at(4, 2), this->at(6, 2) );
1738
1739 std :: swap( this->at(4, 3), this->at(6, 3) );
1740
1741 std :: swap( this->at(1, 4), this->at(1, 6) );
1742 std :: swap( this->at(2, 4), this->at(2, 6) );
1743 std :: swap( this->at(3, 4), this->at(3, 6) );
1744 std :: swap( this->at(4, 4), this->at(6, 6) );
1745 std :: swap( this->at(5, 4), this->at(5, 6) );
1746 std :: swap( this->at(6, 4), this->at(4, 6) );
1747
1748 std :: swap( this->at(4, 5), this->at(6, 5) );
1749 } else if ( rows() == 9 && cols() == 9 ) {
1750 // OOFEM: 11, 22, 33, 23, 13, 12, 32, 31, 21
1751 // UMAT: 11, 22, 33, 12, 13, 23, 32, 21, 31
1752 const int abq2oo [ 9 ] = {
1753 1, 2, 3, 6, 5, 4, 7, 9, 8
1754 };
1755
1756 FloatMatrix tmp(9, 9);
1757 for ( int i = 1; i <= 9; i++ ) {
1758 for ( int j = 1; j <= 9; j++ ) {
1759 tmp.at(i, j) = this->at(abq2oo [ i - 1 ], abq2oo [ j - 1 ]);
1760 }
1761 }
1762
1763 * this = tmp;
1764 }
1765}
1766
1767
1768
1769double FloatMatrix :: computeReciprocalCondition(char p) const
1770{
1771# ifndef NDEBUG
1772 if ( !this->isSquare() ) {
1773 OOFEM_ERROR("receiver must be square (is %d by %d)", this->rows(), this->cols());
1774 }
1775# endif
1776 double anorm = this->computeNorm(p);
1777
1778# ifdef __LAPACK_MODULE
1779 const int n = this->rows();
1780 FloatArray work(4 *n);
1781 IntArray iwork(n);
1782 int info;
1783 double rcond;
1784
1785 if ( n > 3 ) { // Only use this routine for larger matrices. (not sure if it's suitable for n = 3) // Mikael
1786 FloatMatrix a_cpy = * this;
1787 dgetrf_(& n, & n, a_cpy.givePointer(), & n, iwork.givePointer(), & info);
1788 if ( info < 0 ) {
1789 OOFEM_ERROR("dgetfr error %d\n", info);
1790 }
1791 dgecon_(& p, & n, a_cpy.givePointer(), & n, & anorm, & rcond, work.givePointer(), iwork.givePointer(), & info, 1);
1792 if ( info < 0 ) {
1793 OOFEM_ERROR("dgecon error %d\n", info);
1794 }
1795 return rcond;
1796 }
1797# endif
1798 if ( this->giveDeterminant() <= 1e-6 * anorm ) {
1799 return 0.0;
1800 }
1802 inv.beInverseOf(* this);
1803 return 1.0 / ( inv.computeNorm(p) * anorm );
1804}
1805
1806void FloatMatrix :: beMatrixFormOfStress(const FloatArray &aArray)
1807{
1808 // Revrites the matrix on vector form (symmetrized matrix used), order: 11, 22, 33, 23, 13, 12
1809# ifndef NDEBUG
1810 if ( aArray.giveSize() != 6 && aArray.giveSize() != 9 ) {
1811 OOFEM_ERROR("matrix dimension is not 3x3");
1812 }
1813# endif
1814 this->resize(3, 3);
1815 if ( aArray.giveSize() == 9 ) {
1816 this->at(1, 1) = aArray.at(1);
1817 this->at(2, 2) = aArray.at(2);
1818 this->at(3, 3) = aArray.at(3);
1819 this->at(2, 3) = aArray.at(4);
1820 this->at(1, 3) = aArray.at(5);
1821 this->at(1, 2) = aArray.at(6);
1822 this->at(3, 2) = aArray.at(7);
1823 this->at(3, 1) = aArray.at(8);
1824 this->at(2, 1) = aArray.at(9);
1825 } else if ( aArray.giveSize() == 6 ) {
1826 this->at(1, 1) = aArray.at(1);
1827 this->at(2, 2) = aArray.at(2);
1828 this->at(3, 3) = aArray.at(3);
1829 this->at(2, 3) = aArray.at(4);
1830 this->at(1, 3) = aArray.at(5);
1831 this->at(1, 2) = aArray.at(6);
1832 this->at(3, 2) = aArray.at(4);
1833 this->at(3, 1) = aArray.at(5);
1834 this->at(2, 1) = aArray.at(6);
1835 }
1836}
1837
1838#if 0
1839bool FloatMatrix :: computeEigenValuesSymmetric(FloatArray &lambda, FloatMatrix &v, int neigs) const
1840{
1841 #ifdef __LAPACK_MODULE
1842 double abstol = 1.0;
1843 int lda, n, ldz, info, found, lwork;
1844 n = this->rows();
1845 lda = n;
1846 ldz = n;
1847 FloatMatrix a;
1848 a = * this;
1849 if ( neigs == 0 ) {
1850 neigs = n;
1851 }
1852
1853 lambda.resize(neigs);
1854 v.resize(n, neigs);
1855
1856 IntArray ifail(n), iwork(5 * n);
1857 FloatArray work( ( n + 3 ) *n ); // maximum block size should be less than n (?)
1858 lwork = ( n + 3 ) * n;
1859 if ( neigs > 0 ) {
1860 int one = 1;
1861 dsyevx_("N", "I", "U",
1862 & n, a.givePointer(), & n,
1863 NULL, NULL, & one, & neigs,
1864 & abstol, & found, lambda.givePointer(), v.givePointer(), & ldz,
1865 work.givePointer(), & lwork, iwork.givePointer(), ifail.givePointer(), & info, 1, 1, 1);
1866 } else {
1867 dsyevx_("N", "A", "U",
1868 & n, a.givePointer(), & n,
1869 NULL, NULL, NULL, NULL,
1870 & abstol, & found, lambda.givePointer(), v.givePointer(), & ldz,
1871 work.givePointer(), & lwork, iwork.givePointer(), ifail.givePointer(), & info, 1, 1, 1);
1872 }
1873
1874 return info == 0;
1875
1876 #else
1877 OOFEM_ERROR("Requires LAPACK");
1878 return false;
1879
1880 #endif
1881}
1882#endif
1883
1884contextIOResultType FloatMatrix :: storeYourself(DataStream &stream) const
1885// writes receiver's binary image into stream
1886// use id to distinguish some instances
1887// return value >0 success
1888// =0 file i/o error
1889{
1890 // write size
1891 if ( !stream.write(rows()) ) {
1892 return ( CIO_IOERR );
1893 }
1894
1895 if ( !stream.write(cols()) ) {
1896 return ( CIO_IOERR );
1897 }
1898
1899 // write raw data
1900 if ( !stream.write(this->givePointer(), rows() * cols()) ) {
1901 return ( CIO_IOERR );
1902 }
1903
1904 // return result back
1905 return CIO_OK;
1906}
1907
1908
1909contextIOResultType FloatMatrix :: restoreYourself(DataStream &stream)
1910// reads receiver from stream
1911// warning - overwrites existing data!
1912// returns 0 if file i/o error
1913// -1 if id of class id is not correct
1914{
1915 int r,c;
1916 // read size
1917 if ( !stream.read(r) ) {
1918 return ( CIO_IOERR );
1919 }
1920
1921 if ( !stream.read(c) ) {
1922 return ( CIO_IOERR );
1923 }
1924
1925 this->resize(r,c); // FIXME: uselessly fills with zeros
1926
1927 // read raw data
1928 if ( !stream.read(this->givePointer(), r*c) ) {
1929 return ( CIO_IOERR );
1930 }
1931
1932 // return result back
1933 return CIO_OK;
1934}
1935
1936
1937int
1938FloatMatrix :: givePackSize(DataStream &buff) const
1939{
1940 return buff.givePackSizeOfSizet(1) + buff.givePackSizeOfSizet(1) +
1941 buff.givePackSizeOfDouble(rows() * cols());
1942}
1943
1944#ifdef _USE_EIGEN__BROKEN
1945bool FloatMatrix :: jaco_(FloatArray &eval, FloatMatrix &v, int nf){
1946 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(*this,nf);
1947 if(eig.info()!=Eigen::Success) return false;
1948 v=eig.eigenvectors();
1949 eval=eig.eigenvalues();
1950 return true;
1951}
1952#else
1953bool FloatMatrix :: jaco_(FloatArray &eval, FloatMatrix &v, int nf)
1954{
1955 using std::pow, std::sin, std::cos, std::atan2;
1956 /*
1957 * Solves the eigenvalues and eigenvectors of real
1958 * symmetric matrix by jacobi method.
1959 * Written by bp. Inspired by ED WILSON jaco_ procedure.
1960 *
1961 * Parameters (input):
1962 * nf - number of significant figures
1963 *
1964 * Output params:
1965 * eval - eigen values (not sorted)
1966 * v - eigenvectors (stored columvise)
1967 */
1968
1969
1970 /* Local variables */
1971 int neq = this->giveNumberOfRows();
1972
1973 double c_b2 = .10;
1974 //double c_b27 = .01;
1975
1976 /* Function Body */
1977#ifndef NDEBUG
1978 if ( !isSquare() ) {
1979 OOFEM_ERROR("Not square matrix");
1980 }
1981 // check for symmetry
1982 for ( int i = 1; i <= neq; i++ ) {
1983 for ( int j = i + 1; j <= neq; j++ ) {
1984 //if ( this->at(i, j) != this->at(j, i) ) {
1985 if ( fabs( this->at(i, j) - this->at(j, i) ) > 1.0e-6 ) {
1986 OOFEM_ERROR("Not Symmetric matrix");
1987 }
1988 }
1989 }
1990
1991#endif
1992
1993 eval.resize(neq);
1994 v.resize(neq, neq);
1995
1996 for ( int i = 1; i <= neq; i++ ) {
1997 eval.at(i) = this->at(i, i);
1998 }
1999
2000 double tol = pow(c_b2, nf);
2001 double sum = 0.0;
2002 for ( int i = 1; i <= neq; ++i ) {
2003 for ( int j = 1; j <= neq; ++j ) {
2004 sum += fabs( this->at(i, j) );
2005 v.at(i, j) = 0.0;
2006 }
2007
2008 v.at(i, i) = 1.0;
2009 }
2010
2011 if ( sum <= 0.0 ) {
2012 return 0;
2013 }
2014
2015
2016 /* ---- REDUCE MATRIX TO DIAGONAL ---------------- */
2017 int ite = 0;
2018 double ssum;
2019 do {
2020 ssum = 0.0;
2021 for ( int j = 2; j <= neq; ++j ) {
2022 int ih = j - 1;
2023 for ( int i = 1; i <= ih; ++i ) {
2024 if ( ( fabs( this->at(i, j) ) / sum ) > tol ) {
2025 ssum += fabs( this->at(i, j) );
2026 /* ---- CALCULATE ROTATION ANGLE ----------------- */
2027 double aa = atan2( this->at(i, j) * 2.0, eval.at(i) - eval.at(j) ) / 2.0;
2028 double si = sin(aa);
2029 double co = cos(aa);
2030 /*
2031 * // ---- MODIFY "I" AND "J" COLUMNS OF "A" AND "V"
2032 * for (k = 1; k <= neq; ++k) {
2033 * tt = this->at(k, i);
2034 * this->at(k, i) = co * tt + si * this->at(k, j);
2035 * this->at(k, j) = -si * tt + co * this->at(k, j);
2036 * tt = v.at(k, i);
2037 * v.at(k, i) = co * tt + si * v.at(k, j);
2038 * // L500:
2039 * v.at(k, j) = -si * tt + co * v.at(k, j);
2040 * }
2041 * // ---- MODIFY DIAGONAL TERMS --------------------
2042 * this->at(i, i) = co * this->at(i, i) + si * this->at(j, i);
2043 * this->at(j, j) = -si * this->at(i, j) + co * this->at(j, j);
2044 * this->at(i, j) = 0.0;
2045 * // ---- MAKE "A" MATRIX SYMMETRICAL --------------
2046 * for (k = 1; k <= neq; ++k) {
2047 * this->at(i, k) = this->at(k, i);
2048 * this->at(j, k) = this->at(k, j);
2049 * // L600:
2050 * }
2051 */
2052 // ---- MODIFY "I" AND "J" COLUMNS OF "A" AND "V"
2053 for ( int k = 1; k < i; ++k ) {
2054 double tt = this->at(k, i);
2055 this->at(k, i) = co * tt + si * this->at(k, j);
2056 this->at(k, j) = -si * tt + co * this->at(k, j);
2057 tt = v.at(k, i);
2058 v.at(k, i) = co * tt + si *v.at(k, j);
2059 v.at(k, j) = -si * tt + co *v.at(k, j);
2060 }
2061
2062 // diagonal term (i,i)
2063 double tt = eval.at(i);
2064 eval.at(i) = co * tt + si * this->at(i, j);
2065 double aij = -si * tt + co *this->at(i, j);
2066 tt = v.at(i, i);
2067 v.at(i, i) = co * tt + si *v.at(i, j);
2068 v.at(i, j) = -si * tt + co *v.at(i, j);
2069
2070 for ( int k = i + 1; k < j; ++k ) {
2071 double tt = this->at(i, k);
2072 this->at(i, k) = co * tt + si * this->at(k, j);
2073 this->at(k, j) = -si * tt + co * this->at(k, j);
2074 tt = v.at(k, i);
2075 v.at(k, i) = co * tt + si *v.at(k, j);
2076 v.at(k, j) = -si * tt + co *v.at(k, j);
2077 }
2078
2079 // diagonal term (j,j)
2080 tt = this->at(i, j);
2081 double aji = co * tt + si *eval.at(j);
2082 eval.at(j) = -si * tt + co *eval.at(j);
2083
2084 tt = v.at(j, i);
2085 v.at(j, i) = co * tt + si *v.at(j, j);
2086 v.at(j, j) = -si * tt + co *v.at(j, j);
2087 //
2088 for ( int k = j + 1; k <= neq; ++k ) {
2089 double tt = this->at(i, k);
2090 this->at(i, k) = co * tt + si *this->at(j, k);
2091 this->at(j, k) = -si * tt + co *this->at(j, k);
2092 tt = v.at(k, i);
2093 v.at(k, i) = co * tt + si *v.at(k, j);
2094 v.at(k, j) = -si * tt + co *v.at(k, j);
2095 }
2096
2097 // ---- MODIFY DIAGONAL TERMS --------------------
2098 eval.at(i) = co * eval.at(i) + si * aji;
2099 eval.at(j) = -si * aij + co *eval.at(j);
2100 this->at(i, j) = 0.0;
2101 } else {
2102 /* ---- A(I,J) MADE ZERO BY ROTATION ------------- */
2103 ;
2104 }
2105 }
2106 }
2107
2108 /* ---- CHECK FOR CONVERGENCE -------------------- */
2109 if ( ++ite > 50 ) {
2110 OOFEM_ERROR("too many iterations");
2111 }
2112 } while ( fabs(ssum) / sum > tol );
2113
2114 // restore original matrix
2115 for ( int i = 1; i <= neq; i++ ) {
2116 for ( int j = i; j <= neq; j++ ) {
2117 this->at(i, j) = this->at(j, i);
2118 }
2119 }
2120
2121 return 0;
2122} /* jaco_ */
2123#endif
2124
2125
2126std :: ostream &operator << ( std :: ostream & out, const FloatMatrix & x )
2127{
2128 out << x.rows() << " " << x.cols() << " {";
2129 for (Index i = 0; i < x.rows(); ++i ) {
2130 for (Index j = 0; j < x.cols(); ++j ) {
2131 out << " " << x(i, j);
2132 }
2133 out << ";";
2134 }
2135 out << "}";
2136 return out;
2137}
2138
2139FloatMatrix &operator *= ( FloatMatrix & x, const double & a ) {x.times(a); return x;}
2140FloatMatrix operator * ( const FloatMatrix &x, const double & a ) {FloatMatrix ans(x); ans.times(a); return ans;}
2141FloatMatrix operator * ( const double & a, const FloatMatrix &x ) {FloatMatrix ans(x); ans.times(a); return ans;}
2142FloatMatrix operator *( const FloatMatrix & a, const FloatMatrix & b ) {FloatMatrix ans; ans.beProductOf (a,b); return ans;}
2143FloatArray operator *( const FloatMatrix & a, const FloatArray & b ) {FloatArray ans; ans.beProductOf (a,b); return ans;}
2144FloatMatrix operator +( const FloatMatrix & a, const FloatMatrix & b ) {FloatMatrix ans(a); ans.add(b); return ans;}
2145FloatMatrix operator -( const FloatMatrix & a, const FloatMatrix & b ) {FloatMatrix ans(a); ans.subtract(b); return ans;}
2146FloatMatrix &operator += ( FloatMatrix & a, const FloatMatrix & b ) {a.add(b); return a;}
2147FloatMatrix &operator -= ( FloatMatrix & a, const FloatMatrix & b ) {a.subtract(b); return a;}
2148
2149} // end namespace oofem
#define N(a, b)
virtual int read(int *data, std::size_t count)=0
Reads count integer values into array pointed by data.
virtual int givePackSizeOfDouble(std::size_t count)=0
virtual int givePackSizeOfSizet(std::size_t count)=0
Index size() const
Definition floatarray.h:162
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
double dotProduct(const FloatArray &x) const
Definition floatarray.C:524
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void beVectorProductOf(const FloatArray &v1, const FloatArray &v2)
Definition floatarray.C:476
void add(const FloatArray &src)
Definition floatarray.C:218
const double * givePointer() const
Definition floatarray.h:506
const double * givePointer() const
bool isAllFinite() const
Returns true if no element is NAN or infinite.
void times(double f)
std::size_t nRows
Number of rows.
Definition floatmatrix.h:95
std ::vector< double > values
Values of matrix stored column wise.
Definition floatmatrix.h:99
void resizeWithData(Index, Index)
Definition floatmatrix.C:91
static FloatMatrix fromIniList(std ::initializer_list< std ::initializer_list< double > >)
std::size_t nColumns
Number of columns.
Definition floatmatrix.h:97
void add(const FloatMatrix &a)
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
void beProductTOf(const FloatMatrix &a, const FloatMatrix &b)
int giveNumberOfColumns() const
Returns number of columns of receiver.
void beProductOf(const FloatMatrix &a, const FloatMatrix &b)
void setSubMatrix(const FloatMatrix &src, int sr, int sc)
double computeNorm(char p) const
void beTranspositionOf(const FloatMatrix &src)
bool isNotEmpty() const
Tests for empty matrix.
void _resize_internal(int nr, int nc)
Definition floatmatrix.C:68
double giveDeterminant() const
int giveNumberOfRows() const
Returns number of rows of receiver.
double at(std::size_t i, std::size_t j) const
void subtract(const FloatMatrix &a)
void beTProductOf(const FloatMatrix &a, const FloatMatrix &b)
bool isSquare() const
Returns nonzero if receiver is square matrix.
FloatMatrix(std::size_t n, std::size_t m)
int maximum() const
Definition intarray.C:144
std::vector< int > minusOne() const
Definition intarray.h:365
int minimum() const
Definition intarray.C:133
const int * givePointer() const
Definition intarray.h:345
std::size_t size() const
Definition intarray.h:212
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
#define OOFEM_WARNING(...)
Definition error.h:80
#define OOFEM_ERROR(...)
Definition error.h:79
#define _LOOP_MATRIX(r, c)
Definition floatmatrix.C:61
FloatArray operator+(const FloatArray &x, const FloatArray &y)
Definition floatarray.C:978
double norm(const FloatArray &x)
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
FloatMatrixF< M, N > transpose(const FloatMatrixF< N, M > &mat)
Constructs transposed matrix.
FloatArray operator-(const FloatArray &x, const FloatArray &y)
Definition floatarray.C:985
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
std::pair< FloatArrayF< N >, FloatMatrixF< N, N > > eig(const FloatMatrixF< N, N > &mat, int nf=9)
FloatArray & operator+=(FloatArray &x, const FloatArray &y)
Definition floatarray.C:992
std::ostream & operator<<(std ::ostream &out, const Dictionary &r)
Definition dictionary.C:247
double det(const FloatMatrixF< 2, 2 > &mat)
Computes the determinant.
int Index
Definition numerics.h:73
double sum(const FloatArray &x)
double rcond(const FloatMatrixF< N, N > &mat, int p=1)
FloatMatrixF< N, N > diag(const FloatArrayF< N > &v)
FloatMatrixF< N, M > zero()
Constructs a zero matrix (this is the default behavior when constructing a matrix,...
FloatArray & operator-=(FloatArray &x, const FloatArray &y)
Definition floatarray.C:998
FloatMatrixF< N, N > inv(const FloatMatrixF< N, N > &mat, double zeropiv=1e-24)
Computes the inverse.
FloatArray operator*(const double &a, const FloatArray &x)
Definition floatarray.C:964
FloatArray & operator*=(FloatArray &x, const double &a)
Vector multiplication by scalar.
Definition floatarray.C:958
@ CIO_IOERR
General IO error.
double trace(const FloatMatrixF< N, N > &mat)

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011