14#include "arcane/utils/Array.h"
15#include "arcane/utils/FatalErrorException.h"
16#include "arcane/utils/Iostream.h"
17#include "arcane/utils/Numeric.h"
18#include "arcane/utils/ArgumentException.h"
19#include "arcane/utils/NotImplementedException.h"
20#include "arcane/utils/TraceInfo.h"
21#include "arcane/utils/StringBuilder.h"
23#include "arcane/utils/ValueConvert.h"
25#include "arcane/matvec/Matrix.h"
26#include "arcane/matvec/Vector.h"
31namespace Arcane::MatVec
42 MatrixImpl() : m_nb_reference(0), m_nb_row(0), m_nb_column(0), m_nb_element(0) {}
50 m2->m_nb_row = m_nb_row;
51 m2->m_nb_column = m_nb_column;
52 m2->m_nb_element = m_nb_element;
53 m2->m_values = m_values.
clone();
54 m2->m_rows_index = m_rows_index.
clone();
55 m2->m_columns = m_columns.
clone();
60 Integer nbRow()
const {
return m_nb_row; }
61 Integer nbColumn()
const {
return m_nb_column; }
64 void dump(std::ostream& o);
67 Real value(Integer row,Integer column)
const;
72 void setValue(Integer row,Integer column,Real value);
82 void removeReference()
85 if (m_nb_reference==0)
89 Integer m_nb_reference;
108, m_rows_index(m_nb_row+1)
119 m_impl->addReference();
126Matrix(MatrixImpl* impl)
130 m_impl->addReference();
137Matrix(
const Matrix& rhs)
141 m_impl->addReference();
148operator=(
const Matrix& rhs)
151 rhs.m_impl->addReference();
153 m_impl->removeReference();
164 m_impl->removeReference();
182 return m_impl->sortDiagonale();
191 return m_impl->nbColumn();
210 return m_impl->rowsIndex();
217dump(std::ostream& o)
const
226setValue(Integer row,Integer column,Real value)
228 m_impl->setValue(row,column,value);
235value(Integer row,Integer column)
const
237 return m_impl->value(row,column);
291 return m_impl->rowsIndex();
306DiagonalPreconditioner::
307DiagonalPreconditioner(
const Matrix& matrix)
308: m_inverse_diagonal(matrix.nbRow())
310 Integer size = m_inverse_diagonal.size();
315 for( Integer i=0, is=size; i<is; ++i ){
324 m_inverse_diagonal.dump(cout);
327 const double epsilon = std::numeric_limits<Real>::min();
331 for( Integer i=0; i<size; ++i ){
332 Real v = vec_values[i];
333 bool is_zero = v>-epsilon && v<epsilon;
334 vec_values[i] = (is_zero) ? 1.0 : (1.0 / v);
339 m_inverse_diagonal.dump(cout);
347void DiagonalPreconditioner::
348apply(Vector& out_vec,
const Vector& vec)
354 for( Integer i=0; i<size; ++i )
355 out_vec_values[i] = vec_values[i] * inverse_diagonal_values[i];
361void MatrixOperation::
362matrixVectorProduct(
const Matrix& mat,
const Vector& vec,Vector& out_vec)
365 Integer nb_column = mat.nbColumn();
370 if (nb_column!=vec.size())
371 throw ArgumentException(
"MatrixVectorProduct",
"Bad size for input vector");
372 if (nb_row!=out_vec.size())
373 throw ArgumentException(
"MatrixVectorProduct",
"Bad size for output_vector");
380 for( Integer i=0, is=nb_row; i<is; ++i ){
382 for( Integer z=rows_index[i] ,zs=rows_index[i+1]; z<zs; ++z ){
384 Real mv = mat_values[z];
386 sum += vec_values[mj]*mv;
388 out_vec_values[i] = sum;
392Real MatrixOperation::
393dot(
const Vector& vec)
398 for( Integer i=0; i<size; ++i )
399 v += vec_values[i] * vec_values[i];
403Real MatrixOperation::
404dot(
const Vector& vec1,
const Vector& vec2)
410 for( Integer i=0; i<size; ++i ){
411 v += vec1_values[i] * vec2_values[i];
417void MatrixOperation::
418negateVector(Vector& vec)
422 for( Integer i=0; i<size; ++i )
423 vec_values[i] = -vec_values[i];
426void MatrixOperation::
427scaleVector(Vector& vec,
Real mul)
431 for( Integer i=0; i<size; ++i )
432 vec_values[i] *= mul;
435void MatrixOperation::
436addVector(Vector& out_vec,
const Vector& vec)
441 for( Integer i=0; i<size; ++i )
442 out_vec_values[i] += vec_values[i];
448void ConjugateGradientSolver::
449_applySolver(
const Matrix& a,
const Vector& b,Vector& x,
Real epsilon,IPreconditioner* p)
451 MatrixOperation mat_op;
456 mat_op.matrixVectorProduct(a,x,r);
457 mat_op.negateVector(r);
458 mat_op.addVector(r,b);
461 m_residual_norm = 0.0;
476 Real delta_new = 0.0;
479 delta_new = mat_op.dot(r,d);
482 delta_new = mat_op.dot(r);
492 Real delta0 = delta_new;
496 for( nb_iter=0; nb_iter<m_max_iteration; ++nb_iter ){
497 if (delta_new < epsilon*epsilon*delta0)
502 Real norm = r.normInf();
503 cout <<
" norm=" << norm <<
" norm0=" << norm0 <<
'\n';
504 if (norm < epsilon * norm0)
511 mat_op.matrixVectorProduct(a,d,q);
512 Real alpha = delta_new / mat_op.dot(d,q);
516 mat_op.scaleVector(t,alpha);
517 mat_op.addVector(x,t);
521 mat_op.matrixVectorProduct(a,x,r);
522 mat_op.negateVector(r);
523 mat_op.addVector(r,b);
526 mat_op.scaleVector(q,-alpha);
527 mat_op.addVector(r,q);
531 Real delta_old = delta_new;
533 delta_new = mat_op.dot(r,s);
535 delta_new = mat_op.dot(r);
536 Real beta = delta_new / delta_old;
539 mat_op.scaleVector(d,beta);
542 mat_op.addVector(d,s);
545 mat_op.addVector(d,r);
554 m_nb_iteration = nb_iter;
555 m_residual_norm = delta_new;
561void ConjugateGradientSolver::
562_applySolverAsHypre(
const Matrix& a,
const Vector& b,Vector& x,
Real tol,
563 IPreconditioner* precond)
568 MatrixOperation mat_op;
573 const bool is_two_norm =
true;
576 bi_prod = mat_op.dot(b,b);
580 bi_prod = mat_op.dot(p,b);
586 mat_op.matrixVectorProduct(a,x,r);
587 mat_op.negateVector(r);
588 mat_op.addVector(r,b);
591 m_residual_norm = 0.0;
597 Vector tmp_x(x.size());
606 Real gamma = mat_op.dot(r,p);
629 for( nb_iter=0; nb_iter<m_max_iteration; ++nb_iter ){
632 mat_op.matrixVectorProduct(a,p,s);
635 Real sdotp = mat_op.dot(s, p);
637 Real alpha = gamma / sdotp;
639 Real gamma_old = gamma;
642 mat_op.matrixVectorProduct(a,p,tmp_x);
643 mat_op.addVector(x,tmp_x);
647 mat_op.scaleVector(tmp_x,-alpha);
648 mat_op.addVector(r,tmp_x);
654 gamma = mat_op.dot(r,s);
658 i_prod = mat_op.dot(r,r);
665 if (i_prod / bi_prod < eps){
667 if (rel_change && i_prod > guard_zero_residual)
669 pi_prod = (*(pcg_functions->InnerProd))(p,p);
670 xi_prod = (*(pcg_functions->InnerProd))(x,x);
671 ratio = alpha*alpha*pi_prod/xi_prod;
674 (pcg_data -> converged) = 1;
689 Real beta = gamma / gamma_old;
695 mat_op.scaleVector(tmp_x,beta);
696 mat_op.addVector(tmp_x,s);
705 m_nb_iteration = nb_iter;
706 m_residual_norm = gamma;
712bool ConjugateGradientSolver::
713solve(
const Matrix& a,
const Vector& b,Vector& x,
Real epsilon,IPreconditioner* p)
718 m_residual_norm = 0.0;
721 const bool do_print =
false;
731 DiagonalPreconditioner p2(a);
734 _applySolver(a,b,x,epsilon,p);
737 cout <<
"\n\nSOLUTION\nx=";
754 cout <<
"** o=" << m.nbRow() <<
'\n';
759 for( Integer i=0; i<10; ++i ){
760 v1.values()[i] = (
Real)(i+1);
762 Real epsilon = 1.0e-10;
765 MatrixOperation mat_op;
767 mat_op.matrixVectorProduct(m1,v1,v2);
775 for( Integer i=0; i<10; ++i ){
776 b3.values()[i] = (
Real)(i+1);
779 DiagonalPreconditioner p(m1);
780 ConjugateGradientSolver solver;
781 solver.solve(m1,b3,x3,epsilon,&p);
790 m.setRowsSize(rows_size);
806 values[10] = 5.0 / 8.0;
824 m.setValues(columns,values);
835 ConjugateGradientSolver solver;
836 solver.solve(m,b,x,epsilon);
842void _testArcaneMatrix2(Integer matrix_number)
845 cout.flags(std::ios::scientific);
846 String dir_name =
"test-matrix";
847 StringBuilder ext_name;
848 ext_name += matrix_number;
849 ext_name +=
".00000";
854 cout <<
"** XREF=" << xref.size() <<
'\n';
858 Real epsilon = 1.0e-15;
860 ConjugateGradientSolver solver;
861 solver.solve(m,b,x,epsilon);
863 MatrixOperation mat_op;
864 mat_op.negateVector(xref);
865 mat_op.addVector(xref,x);
867 Real x_norm = mat_op.dot(x);
868 Real diff_norm = mat_op.dot(xref);
869 cout <<
"** MATRIX_NUMBER = " << matrix_number;
870 if (!math::isNearlyZero(x_norm)){
871 cout <<
"** norm=" << x_norm <<
" REL=" << diff_norm/x_norm <<
'\n';
874 cout <<
"** norm=" << x_norm <<
" DIFF=" << diff_norm <<
'\n';
878 Real epsilon = 1.0e-15;
879 x.values().fill(0.0);
881 DiagonalPreconditioner p(m);
882 ConjugateGradientSolver solver;
883 solver.solve(m,b,x,epsilon,&p);
885 MatrixOperation mat_op;
886 mat_op.negateVector(xref);
887 mat_op.addVector(xref,x);
889 Real x_norm = mat_op.dot(x);
890 Real diff_norm = mat_op.dot(xref);
891 cout <<
"** PRECOND MATRIX_NUMBER = " << matrix_number;
892 if (!math::isNearlyZero(x_norm)){
893 cout <<
"** norm=" << x_norm <<
" REL=" << diff_norm/x_norm <<
'\n';
896 cout <<
"** norm=" << x_norm <<
" DIFF=" << diff_norm <<
'\n';
904extern "C" void _testArcaneMatrix()
906 _testArcaneMatrix1();
919 for( Integer i=0, is=m_nb_row; i<is; ++i ){
920 m_rows_index[i] = index;
921 index += rows_size[i];
923 m_rows_index[m_nb_row] = index;
924 m_nb_element = index;
936 m_columns.
copy(columns);
937 m_values.
copy(values);
951 Integer nb_column = m_nb_column;
952 for( Integer row=0, nb_row = m_nb_row; row<nb_row; ++row ){
953 for( Integer j=rows_index[row],js=rows_index[row+1]; j<js; ++j ){
954 if (columns[j]>=nb_column || columns[j]<0){
955 cout <<
"BAD COLUMN VALUE for row=" << row <<
" column=" << columns[j]
956 <<
" column_index=" << j
957 <<
" nb_column=" << nb_column <<
" nb_row=" << nb_row <<
'\n';
958 throw FatalErrorException(
"MatrixImpl::checkValid");
968value(Integer row,Integer column)
const
974 for( Integer z=rows_index[row], zs=rows_index[row+1]; z<zs; ++z ){
975 if (columns[z]==column)
985setValue(Integer row,Integer column,
Real value)
991 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid row");
992 if (column>=m_nb_column)
993 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid column");
995 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid row");
997 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid column");
999 for( Integer j=rows_index[row],js=rows_index[row+1]; j<js; ++j ){
1000 if (columns[j]==(-1) || columns[j]==column){
1001 columns[j] = column;
1002 m_values[j] = value;
1006 throw ArgumentException(
"Matrix::setValue",
"column not found");
1023 for( Integer row=0, nb_row = m_nb_row; row<nb_row; ++row ){
1024 Integer first_col = rows_index[row];
1025 for( Integer j=first_col,js=rows_index[row+1]; j<js; ++j ){
1026 if (columns[j]==row){
1027 Integer c = columns[first_col];
1028 Real v = values[first_col];
1029 columns[first_col] = columns[j];
1030 values[first_col] = values[j];
1050 SharedArray<Integer> new_rows_index(m_nb_row+1);
1051 SharedArray<Integer> new_columns;
1052 SharedArray<Real> new_values;
1054 new_rows_index[0] = 0;
1055 for( Integer row=0, nb_row = m_nb_row; row<nb_row; ++row ){
1056 Integer first_col = rows_index[row];
1057 for( Integer j=first_col,js=rows_index[row+1]; j<js; ++j ){
1059 new_columns.add(columns[j]);
1060 new_values.add(values[j]);
1063 new_rows_index[row+1] = new_columns.size();
1066 m_rows_index = new_rows_index;
1067 m_columns = new_columns;
1068 m_values = new_values;
1069 m_nb_element = new_values.size();
1078dump(std::ostream& o)
1080 o <<
"(Matrix nb_row=" << m_nb_row <<
" nb_col=" << m_nb_column <<
")\n";
1082 for( Integer i=0, is=m_nb_row; i<is; ++i ){
1083 o <<
"[" << i <<
"] ";
1085 for( Integer z=m_rows_index[i] ,zs=m_rows_index[i+1]; z<zs; ++z ){
1087 Real v = m_values[z];
1089 o <<
" ["<<j<<
"]="<<v;
1091 o <<
" S=" << sum <<
'\n';
1113 for( Integer x=0; x<
nb_x; ++x ){
1115 for( Integer y=0; y<
nb_y; ++y ){
1157 for( Integer i=0; i<
nb_value; ++i ){
1161 ifile >> ws >> x >> ws >> y >> ws >> v;
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Matrice avec stockage CSR.
Matrice avec stockage CSR.
MatrixImpl * m_impl
Implémentation.
static Matrix readHypre(const String &filename)
Lit la matrice au format Hypre.
void sortDiagonale()
Arrange le stockage pour que la diagonale soit le premier élément.
IntegerConstArrayView rowsIndex() const
Indices des premiers éléments de chaque ligne.
Real value(Integer row, Integer column) const
Retourne la valeur d'un élément de la matrice.
void setRowsSize(IntegerConstArrayView rows_size)
Positionne le nombre d'éléments non nuls de chaque ligne.
void setValues(IntegerConstArrayView columns, RealConstArrayView values)
Positionne les valeurs des éléments de la matrice.
IntegerConstArrayView columns() const
Indices des colonnes des valeurs.
void setValue(Integer row, Integer column, Real value)
Positionne la valeur d'un élément de la matrice.
static Matrix read(const String &filename)
Lit la matrice au format X Y.
void dump(std::ostream &o) const
Imprime la matrice.
RealConstArrayView values() const
Valeurs de la matrice.
Matrix clone() const
Clone la matrice.
static Vector readHypre(const String &file_name)
Initialise un vecteur en utilisant un fichier au format Hypre.
Integer size() const
Nombre d'éléments du vecteur.
RealArrayView values()
Valeurs du vecteur.
Vue modifiable d'un tableau d'un type T.
void copy(Span< const T > rhs)
Copie les valeurs de rhs dans l'instance.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void fill(ConstReferenceType value)
Remplit le tableau avec la valeur value.
Vue constante d'un tableau de type T.
Exception lorsqu'une erreur fatale est survenue.
SharedArray< T > clone() const
Clone le tableau.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Vecteur 1D de données avec sémantique par valeur (style STL).
bool isZero(const BuiltInProxy< _Type > &a)
Teste si une valeur est exactement égale à zéro.
bool arcaneIsCheck()
Vrai si on est en mode vérification.
ArrayView< Integer > IntegerArrayView
Equivalent C d'un tableau à une dimension d'entiers.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.
UniqueArray< Real > RealUniqueArray
Tableau dynamique à une dimension de réels.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
ConstArrayView< Integer > IntegerConstArrayView
Equivalent C d'un tableau à une dimension d'entiers.
ArrayView< Real > RealArrayView
Equivalent C d'un tableau à une dimension de réels.
Int32 Integer
Type représentant un entier.