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"
22#include "arcane/utils/ValueConvert.h"
24#include "arcane/core/matvec/Matrix.h"
25#include "arcane/core/matvec/Vector.h"
30namespace Arcane::MatVec
52 void operator=(
const Matrix& rhs);
58 MatrixImpl* m2 =
new MatrixImpl();
59 m2->m_nb_row = m_nb_row;
60 m2->m_nb_column = m_nb_column;
61 m2->m_nb_element = m_nb_element;
62 m2->m_values = m_values.
clone();
63 m2->m_rows_index = m_rows_index.
clone();
64 m2->m_columns = m_columns.
clone();
71 Integer nbRow()
const {
return m_nb_row; }
72 Integer nbColumn()
const {
return m_nb_column; }
75 void dump(std::ostream& o);
97 void removeReference()
100 if (m_nb_reference == 0)
122, m_nb_column(nb_column)
124, m_rows_index(m_nb_row + 1)
133: m_impl(new MatrixImpl(nb_row, nb_column))
135 m_impl->addReference();
142Matrix(MatrixImpl* impl)
146 m_impl->addReference();
157 m_impl->addReference();
164operator=(
const Matrix& rhs)
167 rhs.m_impl->addReference();
169 m_impl->removeReference();
180 m_impl->removeReference();
198 return m_impl->sortDiagonale();
207 return m_impl->nbColumn();
226 return m_impl->rowsIndex();
233dump(std::ostream& o)
const
253 return m_impl->value(row, column);
271 m_impl->setRowsSize(rows_size);
307 return m_impl->rowsIndex();
322DiagonalPreconditioner::
323DiagonalPreconditioner(
const Matrix& matrix)
324: m_inverse_diagonal(matrix.nbRow())
326 Integer size = m_inverse_diagonal.size();
331 for (
Integer i = 0, is = size; i < is; ++i) {
332 for (
Integer z = rows_index[i], zs = rows_index[i + 1]; z < zs; ++z) {
335 vec_values[i] = mat_values[z];
340 m_inverse_diagonal.dump(cout);
343 const double epsilon = std::numeric_limits<Real>::min();
347 for (
Integer i = 0; i < size; ++i) {
348 Real v = vec_values[i];
349 bool is_zero = v > -epsilon && v < epsilon;
350 vec_values[i] = (is_zero) ? 1.0 : (1.0 / v);
355 m_inverse_diagonal.dump(cout);
363void DiagonalPreconditioner::
366 Integer size = m_inverse_diagonal.size();
370 for (
Integer i = 0; i < size; ++i)
371 out_vec_values[i] = vec_values[i] * inverse_diagonal_values[i];
377void MatrixOperation::
381 Integer nb_column = mat.nbColumn();
386 if (nb_column != vec.size())
387 throw ArgumentException(
"MatrixVectorProduct",
"Bad size for input vector");
388 if (nb_row != out_vec.size())
389 throw ArgumentException(
"MatrixVectorProduct",
"Bad size for output_vector");
396 for (
Integer i = 0, is = nb_row; i < is; ++i) {
398 for (
Integer z = rows_index[i], zs = rows_index[i + 1]; z < zs; ++z) {
400 Real mv = mat_values[z];
402 sum += vec_values[mj] * mv;
404 out_vec_values[i] = sum;
408Real MatrixOperation::
414 for (
Integer i = 0; i < size; ++i)
415 v += vec_values[i] * vec_values[i];
419Real MatrixOperation::
426 for (
Integer i = 0; i < size; ++i) {
427 v += vec1_values[i] * vec2_values[i];
433void MatrixOperation::
438 for (
Integer i = 0; i < size; ++i)
439 vec_values[i] = -vec_values[i];
442void MatrixOperation::
447 for (
Integer i = 0; i < size; ++i)
448 vec_values[i] *= mul;
451void MatrixOperation::
457 for (
Integer i = 0; i < size; ++i)
458 out_vec_values[i] += vec_values[i];
464void ConjugateGradientSolver::
467 MatrixOperation mat_op;
472 mat_op.matrixVectorProduct(a, x, r);
473 mat_op.negateVector(r);
474 mat_op.addVector(r, b);
477 m_residual_norm = 0.0;
483 Vector d(r.size(), 0.0);
491 Vector s(r.size(), 0.0);
492 Real delta_new = 0.0;
495 delta_new = mat_op.dot(r, d);
498 delta_new = mat_op.dot(r);
508 const Real delta0 = delta_new;
514 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
515 if (delta_new < epsilon * epsilon * delta0)
520 Real norm = r.normInf();
521 cout <<
" norm=" << norm <<
" norm0=" << norm0 <<
'\n';
522 if (norm < epsilon * norm0)
529 mat_op.matrixVectorProduct(a, d, q);
530 Real alpha = delta_new / mat_op.dot(d, q);
534 mat_op.scaleVector(t, alpha);
535 mat_op.addVector(x, t);
539 mat_op.matrixVectorProduct(a,x,r);
540 mat_op.negateVector(r);
541 mat_op.addVector(r,b);
544 mat_op.scaleVector(q, -alpha);
545 mat_op.addVector(r, q);
549 Real delta_old = delta_new;
551 delta_new = mat_op.dot(r, s);
553 delta_new = mat_op.dot(r);
554 Real beta = delta_new / delta_old;
557 mat_op.scaleVector(d, beta);
560 mat_op.addVector(d, s);
563 mat_op.addVector(d, r);
572 m_nb_iteration = nb_iter;
573 m_residual_norm = delta_new;
579void ConjugateGradientSolver::
586 MatrixOperation mat_op;
591 const bool is_two_norm =
true;
594 bi_prod = mat_op.dot(b, b);
597 precond->apply(p, b);
598 bi_prod = mat_op.dot(p, b);
600 Real eps = tol * tol;
604 mat_op.matrixVectorProduct(a, x, r);
605 mat_op.negateVector(r);
606 mat_op.addVector(r, b);
609 m_residual_norm = 0.0;
615 Vector tmp_x(x.size());
621 precond->apply(p, r);
624 Real gamma = mat_op.dot(r, p);
647 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
650 mat_op.matrixVectorProduct(a, p, s);
653 Real sdotp = mat_op.dot(s, p);
655 Real alpha = gamma / sdotp;
657 Real gamma_old = gamma;
660 mat_op.matrixVectorProduct(a, p, tmp_x);
661 mat_op.addVector(x, tmp_x);
665 mat_op.scaleVector(tmp_x, -alpha);
666 mat_op.addVector(r, tmp_x);
669 precond->apply(s, r);
672 gamma = mat_op.dot(r, s);
676 i_prod = mat_op.dot(r, r);
683 if (i_prod / bi_prod < eps) {
685 if (rel_change && i_prod > guard_zero_residual)
687 pi_prod = (*(pcg_functions->InnerProd))(p,p);
688 xi_prod = (*(pcg_functions->InnerProd))(x,x);
689 ratio = alpha*alpha*pi_prod/xi_prod;
692 (pcg_data -> converged) = 1;
707 Real beta = gamma / gamma_old;
713 mat_op.scaleVector(tmp_x, beta);
714 mat_op.addVector(tmp_x, s);
723 m_nb_iteration = nb_iter;
724 m_residual_norm = gamma;
730bool ConjugateGradientSolver::
736 m_residual_norm = 0.0;
739 const bool do_print =
false;
749 DiagonalPreconditioner p2(a);
752 _applySolver(a, b, x, epsilon, p);
755 cout <<
"\n\nSOLUTION\nx=";
772 cout <<
"** o=" << m.nbRow() <<
'\n';
777 for (
Integer i = 0; i < 10; ++i) {
778 v1.values()[i] = (
Real)(i + 1);
780 Real epsilon = 1.0e-10;
785 mat_op.matrixVectorProduct(m1, v1, v2);
793 for (
Integer i = 0; i < 10; ++i) {
794 b3.values()[i] = (
Real)(i + 1);
799 solver.solve(m1, b3, x3, epsilon, &p);
808 m.setRowsSize(rows_size);
824 values[10] = 5.0 / 8.0;
842 m.setValues(columns, values);
854 solver.solve(m, b, x, epsilon);
860void _testArcaneMatrix2(
Integer matrix_number)
863 cout.flags(std::ios::scientific);
864 String dir_name =
"test-matrix";
865 StringBuilder ext_name;
866 ext_name += matrix_number;
867 ext_name +=
".00000";
872 cout <<
"** XREF=" << xref.size() <<
'\n';
876 Real epsilon = 1.0e-15;
879 solver.solve(m, b, x, epsilon);
882 mat_op.negateVector(xref);
883 mat_op.addVector(xref, x);
885 Real x_norm = mat_op.dot(x);
886 Real diff_norm = mat_op.dot(xref);
887 cout <<
"** MATRIX_NUMBER = " << matrix_number;
888 if (!math::isNearlyZero(x_norm)) {
889 cout <<
"** norm=" << x_norm <<
" REL=" << diff_norm / x_norm <<
'\n';
892 cout <<
"** norm=" << x_norm <<
" DIFF=" << diff_norm <<
'\n';
896 Real epsilon = 1.0e-15;
897 x.values().fill(0.0);
901 solver.solve(m, b, x, epsilon, &p);
904 mat_op.negateVector(xref);
905 mat_op.addVector(xref, x);
907 Real x_norm = mat_op.dot(x);
908 Real diff_norm = mat_op.dot(xref);
909 cout <<
"** PRECOND MATRIX_NUMBER = " << matrix_number;
910 if (!math::isNearlyZero(x_norm)) {
911 cout <<
"** norm=" << x_norm <<
" REL=" << diff_norm / x_norm <<
'\n';
914 cout <<
"** norm=" << x_norm <<
" DIFF=" << diff_norm <<
'\n';
922extern "C" void _testArcaneMatrix()
924 _testArcaneMatrix1();
937 for (
Integer i = 0, is = m_nb_row; i < is; ++i) {
938 m_rows_index[i] = index;
939 index += rows_size[i];
941 m_rows_index[m_nb_row] = index;
942 m_nb_element = index;
943 m_columns.resize(index);
945 m_values.resize(index);
954 m_columns.copy(columns);
955 m_values.copy(values);
969 Integer nb_column = m_nb_column;
970 for (
Integer row = 0, nb_row = m_nb_row; row < nb_row; ++row) {
971 for (
Integer j = rows_index[row], js = rows_index[row + 1]; j < js; ++j) {
972 if (columns[j] >= nb_column || columns[j] < 0) {
973 cout <<
"BAD COLUMN VALUE for row=" << row <<
" column=" << columns[j]
974 <<
" column_index=" << j
975 <<
" nb_column=" << nb_column <<
" nb_row=" << nb_row <<
'\n';
976 throw FatalErrorException(
"MatrixImpl::checkValid");
992 for (
Integer z = rows_index[row], zs = rows_index[row + 1]; z < zs; ++z) {
993 if (columns[z] == column)
1008 if (row >= m_nb_row)
1009 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid row");
1010 if (column >= m_nb_column)
1011 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid column");
1013 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid row");
1015 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid column");
1017 for (
Integer j = rows_index[row], js = rows_index[row + 1]; j < js; ++j) {
1018 if (columns[j] == (-1) || columns[j] == column) {
1019 columns[j] = column;
1020 m_values[j] = value;
1024 throw ArgumentException(
"Matrix::setValue",
"column not found");
1041 for (
Integer row = 0, nb_row = m_nb_row; row < nb_row; ++row) {
1042 Integer first_col = rows_index[row];
1043 for (
Integer j = first_col, js = rows_index[row + 1]; j < js; ++j) {
1044 if (columns[j] == row) {
1045 Integer c = columns[first_col];
1046 Real v = values[first_col];
1047 columns[first_col] = columns[j];
1048 values[first_col] = values[j];
1068 SharedArray<Integer> new_rows_index(m_nb_row + 1);
1069 SharedArray<Integer> new_columns;
1070 SharedArray<Real> new_values;
1072 new_rows_index[0] = 0;
1073 for (
Integer row = 0, nb_row = m_nb_row; row < nb_row; ++row) {
1074 Integer first_col = rows_index[row];
1075 for (
Integer j = first_col, js = rows_index[row + 1]; j < js; ++j) {
1076 if (columns[j] >= 0) {
1077 new_columns.add(columns[j]);
1078 new_values.add(values[j]);
1081 new_rows_index[row + 1] = new_columns.size();
1084 m_rows_index = new_rows_index;
1085 m_columns = new_columns;
1086 m_values = new_values;
1087 m_nb_element = new_values.size();
1096dump(std::ostream& o)
1098 o <<
"(Matrix nb_row=" << m_nb_row <<
" nb_col=" << m_nb_column <<
")\n";
1100 for (
Integer i = 0, is = m_nb_row; i < is; ++i) {
1101 o <<
"[" << i <<
"] ";
1103 for (
Integer z = m_rows_index[i], zs = m_rows_index[i + 1]; z < zs; ++z) {
1105 Real v = m_values[z];
1107 o <<
" [" << j <<
"]=" << v;
1109 o <<
" S=" << sum <<
'\n';
1120 std::ifstream ifile(filename.
localstr());
1123 ifile >> ws >> nb_x >> ws >> nb_y;
1126 ARCANE_FATAL(
"not a square matrix nb_x={0} nb_y={1}", nb_x, nb_y);
1127 Matrix m(nb_x, nb_y);
1131 for (
Int32 x = 0; x < nb_x; ++x) {
1132 Int32 nb_column = 0;
1133 for (
Int32 y = 0; y < nb_y; ++y) {
1142 rows_size[x] = nb_column;
1155 const bool is_verbose =
false;
1156 std::ifstream ifile(filename.
localstr());
1158 ARCANE_FATAL(
"Can not read Hypre matrix file='{0}'", filename);
1163 ifile >> lower_i >> upper_i >> lower_j >> upper_j;
1165 std::cout <<
"** ** I=" << lower_i <<
' ' << upper_i <<
'\n';
1166 std::cout <<
"** ** IJ" << lower_j <<
' ' << upper_j <<
'\n';
1168 if (lower_i != 0 || lower_j != 0)
1169 ARCANE_FATAL(
"Only lower_i==0 or lower_j==0 is supported (lower_i={0} lower_j={1})", lower_i, lower_j);
1170 Int32 nb_x = 1 + upper_i - lower_i;
1171 Int32 nb_y = 1 + upper_j - lower_j;
1173 std::cout <<
"** ** N=" << nb_x <<
' ' << nb_y <<
'\n';
1175 ARCANE_FATAL(
"Not a square matrix nb_x={0} nb_y={1}", nb_x, nb_y);
1177 Matrix m(nb_x, nb_y);
1182 Int32 nb_column = 0;
1184 while (!ifile.eof()) {
1188 ifile >> ws >> x >> ws >> y >> ws >> v >> ws;
1190 std::cout <<
"X=" << x <<
" Y=" << y <<
" V=" << v <<
"\n";
1193 if (x != last_row) {
1196 std::cout <<
"New row last_row_size=" << nb_column <<
"\n";
1197 rows_size[last_row] = nb_column;
1205 rows_size[last_row] = nb_column;
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
constexpr Integer size() const noexcept
Retourne la taille du tableau.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Préconditionneur diagonal.
Interface d'un préconditionneur.
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.
Vecteur d'algèbre linéraire.
static Vector readHypre(const String &file_name)
Initialise un vecteur en utilisant un fichier au format Hypre.
Vecteur 1D de données avec sémantique par référence.
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.
Int32 Integer
Type représentant un entier.
ArrayView< Integer > IntegerArrayView
Equivalent C d'un tableau à une dimension d'entiers.
UniqueArray< Real > RealUniqueArray
Tableau dynamique à une dimension de réels.
double Real
Type représentant un réel.
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.
std::int32_t Int32
Type entier signé sur 32 bits.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.