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
53 void operator=(
const Matrix& rhs);
59 MatrixImpl* m2 =
new MatrixImpl();
60 m2->m_nb_row = m_nb_row;
61 m2->m_nb_column = m_nb_column;
62 m2->m_nb_element = m_nb_element;
63 m2->m_values = m_values.
clone();
64 m2->m_rows_index = m_rows_index.
clone();
65 m2->m_columns = m_columns.
clone();
72 Integer nbRow()
const {
return m_nb_row; }
73 Integer nbColumn()
const {
return m_nb_column; }
76 void dump(std::ostream& o);
98 void removeReference()
101 if (m_nb_reference == 0)
123, m_nb_column(nb_column)
125, m_rows_index(m_nb_row + 1)
134: m_impl(new MatrixImpl(nb_row, nb_column))
136 m_impl->addReference();
143Matrix(MatrixImpl* impl)
147 m_impl->addReference();
158 m_impl->addReference();
165operator=(
const Matrix& rhs)
168 rhs.m_impl->addReference();
170 m_impl->removeReference();
181 m_impl->removeReference();
199 return m_impl->sortDiagonale();
208 return m_impl->nbColumn();
227 return m_impl->rowsIndex();
234dump(std::ostream& o)
const
254 return m_impl->value(row, column);
272 m_impl->setRowsSize(rows_size);
308 return m_impl->rowsIndex();
323DiagonalPreconditioner::
324DiagonalPreconditioner(
const Matrix& matrix)
325: m_inverse_diagonal(matrix.nbRow())
327 Integer size = m_inverse_diagonal.size();
332 for (
Integer i = 0, is = size; i < is; ++i) {
333 for (
Integer z = rows_index[i], zs = rows_index[i + 1]; z < zs; ++z) {
336 vec_values[i] = mat_values[z];
341 m_inverse_diagonal.dump(cout);
344 const double epsilon = std::numeric_limits<Real>::min();
348 for (
Integer i = 0; i < size; ++i) {
349 Real v = vec_values[i];
350 bool is_zero = v > -epsilon && v < epsilon;
351 vec_values[i] = (is_zero) ? 1.0 : (1.0 / v);
356 m_inverse_diagonal.dump(cout);
364void DiagonalPreconditioner::
367 Integer size = m_inverse_diagonal.size();
371 for (
Integer i = 0; i < size; ++i)
372 out_vec_values[i] = vec_values[i] * inverse_diagonal_values[i];
378void MatrixOperation::
382 Integer nb_column = mat.nbColumn();
387 if (nb_column != vec.size())
388 throw ArgumentException(
"MatrixVectorProduct",
"Bad size for input vector");
389 if (nb_row != out_vec.size())
390 throw ArgumentException(
"MatrixVectorProduct",
"Bad size for output_vector");
397 for (
Integer i = 0, is = nb_row; i < is; ++i) {
399 for (
Integer z = rows_index[i], zs = rows_index[i + 1]; z < zs; ++z) {
401 Real mv = mat_values[z];
403 sum += vec_values[mj] * mv;
405 out_vec_values[i] = sum;
409Real MatrixOperation::
415 for (
Integer i = 0; i < size; ++i)
416 v += vec_values[i] * vec_values[i];
420Real MatrixOperation::
427 for (
Integer i = 0; i < size; ++i) {
428 v += vec1_values[i] * vec2_values[i];
434void MatrixOperation::
439 for (
Integer i = 0; i < size; ++i)
440 vec_values[i] = -vec_values[i];
443void MatrixOperation::
448 for (
Integer i = 0; i < size; ++i)
449 vec_values[i] *= mul;
452void MatrixOperation::
458 for (
Integer i = 0; i < size; ++i)
459 out_vec_values[i] += vec_values[i];
465void ConjugateGradientSolver::
468 MatrixOperation mat_op;
473 mat_op.matrixVectorProduct(a, x, r);
474 mat_op.negateVector(r);
475 mat_op.addVector(r, b);
478 m_residual_norm = 0.0;
484 Vector d(r.size(), 0.0);
492 Vector s(r.size(), 0.0);
493 Real delta_new = 0.0;
496 delta_new = mat_op.dot(r, d);
499 delta_new = mat_op.dot(r);
509 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 returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
constexpr Integer size() const noexcept
Returns the size of the array.
constexpr Integer size() const noexcept
Number of elements in the array.
Interface for a preconditioner.
MatrixImpl * m_impl
Implementation.
static Matrix readHypre(const String &filename)
Reads the matrix in Hypre format.
void sortDiagonale()
Arranges the storage so that the diagonal is the first element.
IntegerConstArrayView rowsIndex() const
Indices of the first elements of each row.
Real value(Integer row, Integer column) const
Returns the value of a matrix element.
void setRowsSize(IntegerConstArrayView rows_size)
Sets the number of non-zero elements for each row.
void setValues(IntegerConstArrayView columns, RealConstArrayView values)
Sets the values of the matrix elements.
IntegerConstArrayView columns() const
Column indices of the values.
void setValue(Integer row, Integer column, Real value)
Sets the value of a matrix element.
static Matrix read(const String &filename)
Reads the matrix in X Y format.
void dump(std::ostream &o) const
Prints the matrix.
RealConstArrayView values() const
Matrix values.
Matrix clone() const
Clone the matrix.
static Vector readHypre(const String &file_name)
Initializes a vector using a Hypre format file.
1D vector of data with reference semantics.
SharedArray< T > clone() const
Clones the array.
Unicode character string.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
1D data vector with value semantics (STL style).
bool isZero(const BuiltInProxy< _Type > &a)
Tests if a value is exactly equal to zero.
bool arcaneIsCheck()
True if running in check mode.
Int32 Integer
Type representing an integer.
ArrayView< Integer > IntegerArrayView
C equivalent of a 1D array of integers.
UniqueArray< Real > RealUniqueArray
Dynamic 1D array of reals.
double Real
Type representing a real number.
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
ConstArrayView< Integer > IntegerConstArrayView
C equivalent of a 1D array of integers.
ArrayView< Real > RealArrayView
C equivalent of a 1D array of reals.
std::int32_t Int32
Signed integer type of 32 bits.
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.