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;
492 Real delta_new = 0.0;
495 delta_new = mat_op.dot(r, d);
498 delta_new = mat_op.dot(r);
508 Real delta0 = delta_new;
512 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
513 if (delta_new < epsilon * epsilon * delta0)
518 Real norm = r.normInf();
519 cout <<
" norm=" << norm <<
" norm0=" << norm0 <<
'\n';
520 if (norm < epsilon * norm0)
527 mat_op.matrixVectorProduct(a, d, q);
528 Real alpha = delta_new / mat_op.dot(d, q);
532 mat_op.scaleVector(t, alpha);
533 mat_op.addVector(x, t);
537 mat_op.matrixVectorProduct(a,x,r);
538 mat_op.negateVector(r);
539 mat_op.addVector(r,b);
542 mat_op.scaleVector(q, -alpha);
543 mat_op.addVector(r, q);
547 Real delta_old = delta_new;
549 delta_new = mat_op.dot(r, s);
551 delta_new = mat_op.dot(r);
552 Real beta = delta_new / delta_old;
555 mat_op.scaleVector(d, beta);
558 mat_op.addVector(d, s);
561 mat_op.addVector(d, r);
570 m_nb_iteration = nb_iter;
571 m_residual_norm = delta_new;
577void ConjugateGradientSolver::
584 MatrixOperation mat_op;
589 const bool is_two_norm =
true;
592 bi_prod = mat_op.dot(b, b);
595 precond->apply(p, b);
596 bi_prod = mat_op.dot(p, b);
598 Real eps = tol * tol;
602 mat_op.matrixVectorProduct(a, x, r);
603 mat_op.negateVector(r);
604 mat_op.addVector(r, b);
607 m_residual_norm = 0.0;
613 Vector tmp_x(x.size());
619 precond->apply(p, r);
622 Real gamma = mat_op.dot(r, p);
645 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
648 mat_op.matrixVectorProduct(a, p, s);
651 Real sdotp = mat_op.dot(s, p);
653 Real alpha = gamma / sdotp;
655 Real gamma_old = gamma;
658 mat_op.matrixVectorProduct(a, p, tmp_x);
659 mat_op.addVector(x, tmp_x);
663 mat_op.scaleVector(tmp_x, -alpha);
664 mat_op.addVector(r, tmp_x);
667 precond->apply(s, r);
670 gamma = mat_op.dot(r, s);
674 i_prod = mat_op.dot(r, r);
681 if (i_prod / bi_prod < eps) {
683 if (rel_change && i_prod > guard_zero_residual)
685 pi_prod = (*(pcg_functions->InnerProd))(p,p);
686 xi_prod = (*(pcg_functions->InnerProd))(x,x);
687 ratio = alpha*alpha*pi_prod/xi_prod;
690 (pcg_data -> converged) = 1;
705 Real beta = gamma / gamma_old;
711 mat_op.scaleVector(tmp_x, beta);
712 mat_op.addVector(tmp_x, s);
721 m_nb_iteration = nb_iter;
722 m_residual_norm = gamma;
728bool ConjugateGradientSolver::
734 m_residual_norm = 0.0;
737 const bool do_print =
false;
747 DiagonalPreconditioner p2(a);
750 _applySolver(a, b, x, epsilon, p);
753 cout <<
"\n\nSOLUTION\nx=";
770 cout <<
"** o=" << m.nbRow() <<
'\n';
775 for (
Integer i = 0; i < 10; ++i) {
776 v1.values()[i] = (
Real)(i + 1);
778 Real epsilon = 1.0e-10;
783 mat_op.matrixVectorProduct(m1, v1, v2);
791 for (
Integer i = 0; i < 10; ++i) {
792 b3.values()[i] = (
Real)(i + 1);
797 solver.solve(m1, b3, x3, epsilon, &p);
806 m.setRowsSize(rows_size);
822 values[10] = 5.0 / 8.0;
840 m.setValues(columns, values);
852 solver.solve(m, b, x, epsilon);
858void _testArcaneMatrix2(
Integer matrix_number)
861 cout.flags(std::ios::scientific);
862 String dir_name =
"test-matrix";
863 StringBuilder ext_name;
864 ext_name += matrix_number;
865 ext_name +=
".00000";
870 cout <<
"** XREF=" << xref.size() <<
'\n';
874 Real epsilon = 1.0e-15;
877 solver.solve(m, b, x, epsilon);
880 mat_op.negateVector(xref);
881 mat_op.addVector(xref, x);
883 Real x_norm = mat_op.dot(x);
884 Real diff_norm = mat_op.dot(xref);
885 cout <<
"** MATRIX_NUMBER = " << matrix_number;
886 if (!math::isNearlyZero(x_norm)) {
887 cout <<
"** norm=" << x_norm <<
" REL=" << diff_norm / x_norm <<
'\n';
890 cout <<
"** norm=" << x_norm <<
" DIFF=" << diff_norm <<
'\n';
894 Real epsilon = 1.0e-15;
895 x.values().fill(0.0);
899 solver.solve(m, b, x, epsilon, &p);
902 mat_op.negateVector(xref);
903 mat_op.addVector(xref, x);
905 Real x_norm = mat_op.dot(x);
906 Real diff_norm = mat_op.dot(xref);
907 cout <<
"** PRECOND MATRIX_NUMBER = " << matrix_number;
908 if (!math::isNearlyZero(x_norm)) {
909 cout <<
"** norm=" << x_norm <<
" REL=" << diff_norm / x_norm <<
'\n';
912 cout <<
"** norm=" << x_norm <<
" DIFF=" << diff_norm <<
'\n';
920extern "C" void _testArcaneMatrix()
922 _testArcaneMatrix1();
935 for (
Integer i = 0, is = m_nb_row; i < is; ++i) {
936 m_rows_index[i] = index;
937 index += rows_size[i];
939 m_rows_index[m_nb_row] = index;
940 m_nb_element = index;
941 m_columns.resize(index);
943 m_values.resize(index);
952 m_columns.copy(columns);
953 m_values.copy(values);
967 Integer nb_column = m_nb_column;
968 for (
Integer row = 0, nb_row = m_nb_row; row < nb_row; ++row) {
969 for (
Integer j = rows_index[row], js = rows_index[row + 1]; j < js; ++j) {
970 if (columns[j] >= nb_column || columns[j] < 0) {
971 cout <<
"BAD COLUMN VALUE for row=" << row <<
" column=" << columns[j]
972 <<
" column_index=" << j
973 <<
" nb_column=" << nb_column <<
" nb_row=" << nb_row <<
'\n';
974 throw FatalErrorException(
"MatrixImpl::checkValid");
990 for (
Integer z = rows_index[row], zs = rows_index[row + 1]; z < zs; ++z) {
991 if (columns[z] == column)
1006 if (row >= m_nb_row)
1007 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid row");
1008 if (column >= m_nb_column)
1009 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid column");
1011 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid row");
1013 throw ArgumentException(
"MatrixImpl::setValue",
"Invalid column");
1015 for (
Integer j = rows_index[row], js = rows_index[row + 1]; j < js; ++j) {
1016 if (columns[j] == (-1) || columns[j] == column) {
1017 columns[j] = column;
1018 m_values[j] = value;
1022 throw ArgumentException(
"Matrix::setValue",
"column not found");
1039 for (
Integer row = 0, nb_row = m_nb_row; row < nb_row; ++row) {
1040 Integer first_col = rows_index[row];
1041 for (
Integer j = first_col, js = rows_index[row + 1]; j < js; ++j) {
1042 if (columns[j] == row) {
1043 Integer c = columns[first_col];
1044 Real v = values[first_col];
1045 columns[first_col] = columns[j];
1046 values[first_col] = values[j];
1066 SharedArray<Integer> new_rows_index(m_nb_row + 1);
1067 SharedArray<Integer> new_columns;
1068 SharedArray<Real> new_values;
1070 new_rows_index[0] = 0;
1071 for (
Integer row = 0, nb_row = m_nb_row; row < nb_row; ++row) {
1072 Integer first_col = rows_index[row];
1073 for (
Integer j = first_col, js = rows_index[row + 1]; j < js; ++j) {
1074 if (columns[j] >= 0) {
1075 new_columns.add(columns[j]);
1076 new_values.add(values[j]);
1079 new_rows_index[row + 1] = new_columns.size();
1082 m_rows_index = new_rows_index;
1083 m_columns = new_columns;
1084 m_values = new_values;
1085 m_nb_element = new_values.size();
1094dump(std::ostream& o)
1096 o <<
"(Matrix nb_row=" << m_nb_row <<
" nb_col=" << m_nb_column <<
")\n";
1098 for (
Integer i = 0, is = m_nb_row; i < is; ++i) {
1099 o <<
"[" << i <<
"] ";
1101 for (
Integer z = m_rows_index[i], zs = m_rows_index[i + 1]; z < zs; ++z) {
1103 Real v = m_values[z];
1105 o <<
" [" << j <<
"]=" << v;
1107 o <<
" S=" << sum <<
'\n';
1118 std::ifstream ifile(filename.
localstr());
1121 ifile >> ws >> nb_x >> ws >> nb_y;
1124 ARCANE_FATAL(
"not a square matrix nb_x={0} nb_y={1}", nb_x, nb_y);
1125 Matrix m(nb_x, nb_y);
1129 for (
Int32 x = 0; x < nb_x; ++x) {
1130 Int32 nb_column = 0;
1131 for (
Int32 y = 0; y < nb_y; ++y) {
1140 rows_size[x] = nb_column;
1153 const bool is_verbose =
false;
1154 std::ifstream ifile(filename.
localstr());
1156 ARCANE_FATAL(
"Can not read Hypre matrix file='{0}'", filename);
1161 ifile >> lower_i >> upper_i >> lower_j >> upper_j;
1163 std::cout <<
"** ** I=" << lower_i <<
' ' << upper_i <<
'\n';
1164 std::cout <<
"** ** IJ" << lower_j <<
' ' << upper_j <<
'\n';
1166 if (lower_i != 0 || lower_j != 0)
1167 ARCANE_FATAL(
"Only lower_i==0 or lower_j==0 is supported (lower_i={0} lower_j={1})", lower_i, lower_j);
1168 Int32 nb_x = 1 + upper_i - lower_i;
1169 Int32 nb_y = 1 + upper_j - lower_j;
1171 std::cout <<
"** ** N=" << nb_x <<
' ' << nb_y <<
'\n';
1173 ARCANE_FATAL(
"Not a square matrix nb_x={0} nb_y={1}", nb_x, nb_y);
1175 Matrix m(nb_x, nb_y);
1180 Int32 nb_column = 0;
1182 while (!ifile.eof()) {
1186 ifile >> ws >> x >> ws >> y >> ws >> v >> ws;
1188 std::cout <<
"X=" << x <<
" Y=" << y <<
" V=" << v <<
"\n";
1191 if (x != last_row) {
1194 std::cout <<
"New row last_row_size=" << nb_column <<
"\n";
1195 rows_size[last_row] = nb_column;
1203 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.