Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
Matrix.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* Matrix.cc (C) 2000-2026 */
9/* */
10/* Linear algebra matrix. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
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"
23
24#include "arcane/core/matvec/Matrix.h"
25#include "arcane/core/matvec/Vector.h"
26
27/*---------------------------------------------------------------------------*/
28/*---------------------------------------------------------------------------*/
29
30namespace Arcane::MatVec
31{
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
39class MatrixImpl
40{
41 public:
42
43 MatrixImpl()
44 : m_nb_reference(0)
45 , m_nb_row(0)
46 , m_nb_column(0)
47 , m_nb_element(0)
48 {}
49 MatrixImpl(Integer nb_row, Integer nb_column);
50
51 private:
52
53 void operator=(const Matrix& rhs);
54
55 public:
56
57 MatrixImpl* clone()
58 {
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();
66 return m2;
67 }
68
69 private:
70 public:
71
72 Integer nbRow() const { return m_nb_row; }
73 Integer nbColumn() const { return m_nb_column; }
74 void setRowsSize(IntegerConstArrayView rows_size);
75 void setValues(IntegerConstArrayView columns, RealConstArrayView values);
76 void dump(std::ostream& o);
77 RealConstArrayView values() const { return m_values; }
78 RealArrayView values() { return m_values; }
79 Real value(Integer row, Integer column) const;
80 IntegerConstArrayView rowsIndex() const { return m_rows_index; }
81 IntegerConstArrayView columns() const { return m_columns; }
82 IntegerArrayView rowsIndex() { return m_rows_index; }
83 IntegerArrayView columns() { return m_columns; }
84 void setValue(Integer row, Integer column, Real value);
85 void sortDiagonale();
86 void assemble();
87
88 public:
89
90 void checkValid();
91
92 public:
93
94 void addReference()
95 {
96 ++m_nb_reference;
97 }
98 void removeReference()
99 {
100 --m_nb_reference;
101 if (m_nb_reference == 0)
102 delete this;
103 }
104
105 private:
106
107 Integer m_nb_reference;
108 Integer m_nb_row;
109 Integer m_nb_column;
110 Integer m_nb_element;
111 SharedArray<Real> m_values;
112 SharedArray<Integer> m_rows_index;
113 SharedArray<Integer> m_columns;
114};
115
116/*---------------------------------------------------------------------------*/
117/*---------------------------------------------------------------------------*/
118
119MatrixImpl::
120MatrixImpl(Integer nb_row, Integer nb_column)
121: m_nb_reference(0)
122, m_nb_row(nb_row)
123, m_nb_column(nb_column)
124, m_nb_element(0)
125, m_rows_index(m_nb_row + 1)
126{
127}
128
129/*---------------------------------------------------------------------------*/
130/*---------------------------------------------------------------------------*/
131
132Matrix::
133Matrix(Integer nb_row, Integer nb_column)
134: m_impl(new MatrixImpl(nb_row, nb_column))
135{
136 m_impl->addReference();
137}
138
139/*---------------------------------------------------------------------------*/
140/*---------------------------------------------------------------------------*/
141
142Matrix::
143Matrix(MatrixImpl* impl)
144: m_impl(impl)
145{
146 if (m_impl)
147 m_impl->addReference();
148}
149
150/*---------------------------------------------------------------------------*/
151/*---------------------------------------------------------------------------*/
152
153Matrix::
154Matrix(const Matrix& rhs)
155: m_impl(rhs.m_impl)
156{
157 if (m_impl)
158 m_impl->addReference();
159}
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
163
164void Matrix::
165operator=(const Matrix& rhs)
166{
167 if (rhs.m_impl)
168 rhs.m_impl->addReference();
169 if (m_impl)
170 m_impl->removeReference();
171 m_impl = rhs.m_impl;
172}
173
174/*---------------------------------------------------------------------------*/
175/*---------------------------------------------------------------------------*/
176
177Matrix::
178~Matrix()
179{
180 if (m_impl)
181 m_impl->removeReference();
182}
183
184/*---------------------------------------------------------------------------*/
185/*---------------------------------------------------------------------------*/
186
187Integer Matrix::
188nbRow() const
189{
190 return m_impl->nbRow();
191}
192
193/*---------------------------------------------------------------------------*/
194/*---------------------------------------------------------------------------*/
195
198{
199 return m_impl->sortDiagonale();
200}
201
202/*---------------------------------------------------------------------------*/
203/*---------------------------------------------------------------------------*/
204
205Integer Matrix::
206nbColumn() const
207{
208 return m_impl->nbColumn();
209}
210
211/*---------------------------------------------------------------------------*/
212/*---------------------------------------------------------------------------*/
213
215clone() const
216{
217 MatrixImpl* m = m_impl->clone();
218 return Matrix(m);
219}
220
221/*---------------------------------------------------------------------------*/
222/*---------------------------------------------------------------------------*/
223
225rowsIndex() const
226{
227 return m_impl->rowsIndex();
228}
229
230/*---------------------------------------------------------------------------*/
231/*---------------------------------------------------------------------------*/
232
234dump(std::ostream& o) const
235{
236 m_impl->dump(o);
237}
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
241
243setValue(Integer row, Integer column, Real value)
244{
245 m_impl->setValue(row, column, value);
246}
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
250
252value(Integer row, Integer column) const
253{
254 return m_impl->value(row, column);
255}
256
257/*---------------------------------------------------------------------------*/
258/*---------------------------------------------------------------------------*/
259
265
266/*---------------------------------------------------------------------------*/
267/*---------------------------------------------------------------------------*/
268
271{
272 m_impl->setRowsSize(rows_size);
273}
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
277
279values() const
280{
281 return m_impl->values();
282}
283
284/*---------------------------------------------------------------------------*/
285/*---------------------------------------------------------------------------*/
286
288values()
289{
290 return m_impl->values();
291}
292
293/*---------------------------------------------------------------------------*/
294/*---------------------------------------------------------------------------*/
295
297columns()
298{
299 return m_impl->columns();
300}
301
302/*---------------------------------------------------------------------------*/
303/*---------------------------------------------------------------------------*/
304
306rowsIndex()
307{
308 return m_impl->rowsIndex();
309}
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
315columns() const
316{
317 return m_impl->columns();
318}
319
320/*---------------------------------------------------------------------------*/
321/*---------------------------------------------------------------------------*/
322
323DiagonalPreconditioner::
324DiagonalPreconditioner(const Matrix& matrix)
325: m_inverse_diagonal(matrix.nbRow())
326{
327 Integer size = m_inverse_diagonal.size();
328 IntegerConstArrayView rows_index = matrix.rowsIndex();
330 RealConstArrayView mat_values = matrix.values();
331 RealArrayView vec_values = m_inverse_diagonal.values();
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) {
334 Integer mj = columns[z];
335 if (mj == i)
336 vec_values[i] = mat_values[z];
337 }
338 }
339#if 0
340 cout << "DIAG1=";
341 m_inverse_diagonal.dump(cout);
342 cout << "\n";
343#endif
344 const double epsilon = std::numeric_limits<Real>::min();
345
346 // Invert the diagonal if the value is not less than the Real epsilon
347 // (otherwise it generates an FPE)
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);
352 }
353
354#if 0
355 cout << "DIAG2=";
356 m_inverse_diagonal.dump(cout);
357 cout << "\n";
358#endif
359}
360
361/*---------------------------------------------------------------------------*/
362/*---------------------------------------------------------------------------*/
363
364void DiagonalPreconditioner::
365apply(Vector& out_vec, const Vector& vec)
366{
367 Integer size = m_inverse_diagonal.size();
368 RealConstArrayView inverse_diagonal_values = m_inverse_diagonal.values();
369 RealConstArrayView vec_values = vec.values();
370 RealArrayView out_vec_values = out_vec.values();
371 for (Integer i = 0; i < size; ++i)
372 out_vec_values[i] = vec_values[i] * inverse_diagonal_values[i];
373}
374
375/*---------------------------------------------------------------------------*/
376/*---------------------------------------------------------------------------*/
377
378void MatrixOperation::
379matrixVectorProduct(const Matrix& mat, const Vector& vec, Vector& out_vec)
380{
381 Integer nb_row = mat.nbRow();
382 Integer nb_column = mat.nbColumn();
383 //cout << "** MATRIX ROW=" << nb_row << " COL=" << nb_column
384 // << " intput_size=" << vec.size()
385 // << " output_size=" << out_vec.size()
386 // << "\n";
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");
391 IntegerConstArrayView rows_index = mat.rowsIndex();
392 IntegerConstArrayView columns = mat.columns();
393 RealConstArrayView mat_values = mat.values();
394 RealConstArrayView vec_values = vec.values();
395 RealArrayView out_vec_values = out_vec.values();
396
397 for (Integer i = 0, is = nb_row; i < is; ++i) {
398 Real sum = 0.0;
399 for (Integer z = rows_index[i], zs = rows_index[i + 1]; z < zs; ++z) {
400 Integer mj = columns[z];
401 Real mv = mat_values[z];
402 //cout << "ADD vec=" << vec_values[mj] << " mv=" << mv << " sum=" << sum << '\n';
403 sum += vec_values[mj] * mv;
404 }
405 out_vec_values[i] = sum;
406 }
407}
408
409Real MatrixOperation::
410dot(const Vector& vec)
411{
412 Integer size = vec.size();
413 RealConstArrayView vec_values = vec.values();
414 Real v = 0.0;
415 for (Integer i = 0; i < size; ++i)
416 v += vec_values[i] * vec_values[i];
417 return v;
418}
419
420Real MatrixOperation::
421dot(const Vector& vec1, const Vector& vec2)
422{
423 Real v = 0.0;
424 Integer size = vec1.size();
425 RealConstArrayView vec1_values = vec1.values();
426 RealConstArrayView vec2_values = vec2.values();
427 for (Integer i = 0; i < size; ++i) {
428 v += vec1_values[i] * vec2_values[i];
429 //cout << " i=" << i << " v=" << v << '\n';
430 }
431 return v;
432}
433
434void MatrixOperation::
435negateVector(Vector& vec)
436{
437 Integer size = vec.size();
438 RealArrayView vec_values = vec.values();
439 for (Integer i = 0; i < size; ++i)
440 vec_values[i] = -vec_values[i];
441}
442
443void MatrixOperation::
444scaleVector(Vector& vec, Real mul)
445{
446 Integer size = vec.size();
447 RealArrayView vec_values = vec.values();
448 for (Integer i = 0; i < size; ++i)
449 vec_values[i] *= mul;
450}
451
452void MatrixOperation::
453addVector(Vector& out_vec, const Vector& vec)
454{
455 Integer size = vec.size();
456 RealConstArrayView vec_values = vec.values();
457 RealArrayView out_vec_values = out_vec.values();
458 for (Integer i = 0; i < size; ++i)
459 out_vec_values[i] += vec_values[i];
460}
461
462/*---------------------------------------------------------------------------*/
463/*---------------------------------------------------------------------------*/
464
465void ConjugateGradientSolver::
466_applySolver(const Matrix& a, const Vector& b, Vector& x, Real epsilon, IPreconditioner* p)
467{
468 MatrixOperation mat_op;
469 Integer vec_size = a.nbRow();
470 Vector r(vec_size);
471
472 // r = b - Ax
473 mat_op.matrixVectorProduct(a, x, r);
474 mat_op.negateVector(r);
475 mat_op.addVector(r, b);
476
477 m_nb_iteration = 0;
478 m_residual_norm = 0.0;
479
480 /*cout << " R=";
481 r.dump(cout);
482 cout << '\n';*/
483
484 Vector d(r.size(), 0.0);
485 if (p)
486 p->apply(d, r);
487 else
488 d.copy(r);
489
490 Vector q(r.size());
491 Vector t(r.size());
492 Vector s(r.size(), 0.0);
493 Real delta_new = 0.0;
494 //Real r0=mat_op.dot(r);
495 if (p) {
496 delta_new = mat_op.dot(r, d);
497 }
498 else
499 delta_new = mat_op.dot(r);
500#if 0
501 cout << "R=";
502 r.dump(cout);
503 cout << "\n";
504 cout << "D=";
505 d.dump(cout);
506 cout << "\n";
507#endif
508 //Real norm0 = r.normInf();
509 const Real delta0 = delta_new;
510
511 //cout << " TOL=" << epsilon << " delta0=" << delta0 << '\n';
512 //cout << " deltanew=" << delta_new << '\n';
513 Integer nb_iter = 0;
514 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
515 if (delta_new < epsilon * epsilon * delta0)
516 break;
517#if 0
518 // If we use the infinity norm
519 {
520 Real norm = r.normInf();
521 cout << " norm=" << norm << " norm0=" << norm0 << '\n';
522 if (norm < epsilon * norm0)
523 break;
524 }
525#endif
526
527 //cout << "delta_new=" << delta_new << '\n';
528 // q = A * d
529 mat_op.matrixVectorProduct(a, d, q);
530 Real alpha = delta_new / mat_op.dot(d, q);
531
532 // x = x + alpha * d
533 t.copy(d);
534 mat_op.scaleVector(t, alpha);
535 mat_op.addVector(x, t);
536
537#if 0
538 // r = b - Ax
539 mat_op.matrixVectorProduct(a,x,r);
540 mat_op.negateVector(r);
541 mat_op.addVector(r,b);
542#endif
543 // r = r - alpha * q
544 mat_op.scaleVector(q, -alpha);
545 mat_op.addVector(r, q);
546
547 if (p)
548 p->apply(s, r);
549 Real delta_old = delta_new;
550 if (p)
551 delta_new = mat_op.dot(r, s);
552 else
553 delta_new = mat_op.dot(r);
554 Real beta = delta_new / delta_old;
555 //cout << " alpha=" << alpha << " beta=" << beta << " delta_new=" << delta_new << '\n';
556 // d = beta * d + s
557 mat_op.scaleVector(d, beta);
558 if (p) {
559 //mat_op.addVector(s,r);
560 mat_op.addVector(d, s);
561 }
562 else
563 mat_op.addVector(d, r);
564 //cout << '\n';
565 }
566 //cout << " X=";
567 //x.dump(cout);
568 //cout << '\n';
569 //cout << "NB ITER=" << nb_iter << " epsilon=" << epsilon
570 // << " delta0=" << delta0
571 // << " delta_new=" << delta_new << " r=" << mat_op.dot(r) << " r0=" << r0 << '\n';
572 m_nb_iteration = nb_iter;
573 m_residual_norm = delta_new;
574}
575
576/*---------------------------------------------------------------------------*/
577/*---------------------------------------------------------------------------*/
578
579void ConjugateGradientSolver::
580_applySolverAsHypre(const Matrix& a, const Vector& b, Vector& x, Real tol,
581 IPreconditioner* precond)
582{
583 //cout << "** APPLY ARCANE_SOLVER PCG using hypre method\n";
584 ARCANE_CHECK_POINTER(precond);
585
586 MatrixOperation mat_op;
587 Integer vec_size = a.nbRow();
588 Vector r(vec_size);
589 Vector p(vec_size);
590
591 const bool is_two_norm = true;
592 Real bi_prod = 0.0;
593 if (is_two_norm) {
594 bi_prod = mat_op.dot(b, b);
595 }
596 else {
597 precond->apply(p, b);
598 bi_prod = mat_op.dot(p, b);
599 }
600 Real eps = tol * tol;
601 //TODO: regarder stop_crit
602
603 // r = b - Ax
604 mat_op.matrixVectorProduct(a, x, r);
605 mat_op.negateVector(r);
606 mat_op.addVector(r, b);
607
608 m_nb_iteration = 0;
609 m_residual_norm = 0.0;
610
611 /*cout << " R=";
612 r.dump(cout);
613 cout << '\n';*/
614
615 Vector tmp_x(x.size());
616
617 Vector d(r.size());
618 Vector s(r.size());
619 d.copy(r);
620 // p = C*r
621 precond->apply(p, r);
622
623 /* gamma = <r,p> */
624 Real gamma = mat_op.dot(r, p);
625
626 Real i_prod = 0.0;
627
628 //Real delta_new = 0.0;
629 //Real r0=mat_op.dot(r);
630 //if (p){
631 // delta_new = mat_op.dot(r,d);
632 //}
633 //else
634 // delta_new = mat_op.dot(r);
635#if 0
636 cout << "R=";
637 r.dump(cout);
638 cout << "\n";
639 cout << "D=";
640 d.dump(cout);
641 cout << "\n";
642#endif
643 //Real delta0 = delta_new;
644 //cout << "** TOL=" << tol << " bi_prod=" << bi_prod << '\n';
645 //cout << " deltanew=" << delta_new << '\n';
646 Integer nb_iter = 0;
647 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
648
649 // s = A * p
650 mat_op.matrixVectorProduct(a, p, s);
651
652 /* alpha = gamma / <s,p> */
653 Real sdotp = mat_op.dot(s, p);
654
655 Real alpha = gamma / sdotp;
656
657 Real gamma_old = gamma;
658
659 /* x = x + alpha*p */
660 mat_op.matrixVectorProduct(a, p, tmp_x);
661 mat_op.addVector(x, tmp_x);
662
663 /* r = r - alpha*s */
664 tmp_x.copy(s);
665 mat_op.scaleVector(tmp_x, -alpha);
666 mat_op.addVector(r, tmp_x);
667
668 /* s = C*r */
669 precond->apply(s, r);
670
671 /* gamma = <r,s> */
672 gamma = mat_op.dot(r, s);
673
674 /* set i_prod for convergence test */
675 if (is_two_norm)
676 i_prod = mat_op.dot(r, r);
677 else
678 i_prod = gamma;
679
680 //cout << "** sdotp=" << sdotp << " i_prod=" << i_prod << " bi_prod=" << bi_prod << '\n';
681
682 /* check for convergence */
683 if (i_prod / bi_prod < eps) {
684#if 0
685 if (rel_change && i_prod > guard_zero_residual)
686 {
687 pi_prod = (*(pcg_functions->InnerProd))(p,p);
688 xi_prod = (*(pcg_functions->InnerProd))(x,x);
689 ratio = alpha*alpha*pi_prod/xi_prod;
690 if (ratio < eps)
691 {
692 (pcg_data -> converged) = 1;
693 break;
694 }
695 }
696 else
697 {
698#endif
699 //(pcg_data -> converged) = 1;
700 break;
701#if 0
702 }
703#endif
704 }
705
706 /* beta = gamma / gamma_old */
707 Real beta = gamma / gamma_old;
708
709 //cout << " alpha=" << alpha << " beta=" << beta << " delta_new=" << gamma << '\n';
710
711 /* p = s + beta p */
712 tmp_x.copy(p);
713 mat_op.scaleVector(tmp_x, beta);
714 mat_op.addVector(tmp_x, s);
715 p.copy(tmp_x);
716 }
717 //cout << " X=";
718 //x.dump(cout);
719 //cout << '\n';
720 //cout << "NB ITER=" << nb_iter << " epsilon=" << epsilon
721 // << " delta0=" << delta0
722 // << " delta_new=" << delta_new << " r=" << mat_op.dot(r) << " r0=" << r0 << '\n';
723 m_nb_iteration = nb_iter;
724 m_residual_norm = gamma;
725}
726
727/*---------------------------------------------------------------------------*/
728/*---------------------------------------------------------------------------*/
729
730bool ConjugateGradientSolver::
731solve(const Matrix& a, const Vector& b, Vector& x, Real epsilon, IPreconditioner* p)
732{
733 //epsilon = 1e-12;
734 //x.values().fill(0.0);
735 m_nb_iteration = 0;
736 m_residual_norm = 0.0;
737 //_doConjugateGradient(a,b,x,epsilon,&p);
738 cout.precision(20);
739 const bool do_print = false;
740 if (do_print) {
741 cout << "A=";
742 a.dump(cout);
743 cout << '\n';
744 cout << "b=";
745 b.dump(cout);
746 cout << '\n';
747 }
748
749 DiagonalPreconditioner p2(a);
750 if (!p)
751 p = &p2;
752 _applySolver(a, b, x, epsilon, p);
753
754 if (do_print) {
755 cout << "\n\nSOLUTION\nx=";
756 x.dump(cout);
757 cout << '\n';
758 }
759
760 return false;
761}
762
763/*---------------------------------------------------------------------------*/
764/*---------------------------------------------------------------------------*/
765
766static void
767_testArcaneMatrix1()
768{
769 Integer s = 5;
770 Matrix m(s, s);
771 Matrix m1(Matrix::read("test.mat"));
772 cout << "** o=" << m.nbRow() << '\n';
773 cout << "** M1=";
774 m1.dump(cout);
775 cout << '\n';
776 Vector v1(10);
777 for (Integer i = 0; i < 10; ++i) {
778 v1.values()[i] = (Real)(i + 1);
779 }
780 Real epsilon = 1.0e-10;
781 {
782 Vector v2(10);
783 MatrixOperation mat_op;
784 Vector r(5);
785 mat_op.matrixVectorProduct(m1, v1, v2);
786 cout << "** V1=";
787 v1.dump(cout);
788 cout << "\n";
789 cout << "** V2=";
790 v2.dump(cout);
791 cout << "\n";
792 Vector b3(10);
793 for (Integer i = 0; i < 10; ++i) {
794 b3.values()[i] = (Real)(i + 1);
795 }
796 Vector x3(10);
799 solver.solve(m1, b3, x3, epsilon, &p);
800 }
801
802 IntegerUniqueArray rows_size(s);
803 rows_size[0] = 5;
804 rows_size[1] = 2;
805 rows_size[2] = 2;
806 rows_size[3] = 2;
807 rows_size[4] = 2;
808 m.setRowsSize(rows_size);
809 RealUniqueArray values(13);
810 IntegerUniqueArray columns(13);
811 values[0] = 9.0;
812 values[1] = 1.5;
813 values[2] = 6.0;
814 values[3] = 0.75;
815 values[4] = 3.0;
816
817 values[5] = 1.5;
818 values[6] = 0.5;
819
820 values[7] = 6.0;
821 values[8] = 0.5;
822
823 values[9] = 0.75;
824 values[10] = 5.0 / 8.0;
825
826 values[11] = 3.0;
827 values[12] = 16.0;
828
829 columns[0] = 0;
830 columns[1] = 1;
831 columns[2] = 2;
832 columns[3] = 3;
833 columns[4] = 4;
834 columns[5] = 0;
835 columns[6] = 1;
836 columns[7] = 0;
837 columns[8] = 2;
838 columns[9] = 0;
839 columns[10] = 3;
840 columns[11] = 0;
841 columns[12] = 4;
842 m.setValues(columns, values);
843 m.dump(cout);
844 cout << '\n';
845 Vector b(5);
846 RealArrayView rav(b.values());
847 rav[0] = 1.0;
848 rav[1] = 1.0;
849 rav[2] = 1.0;
850 rav[3] = 3.0;
851 rav[4] = 1.0;
852 Vector x(5);
854 solver.solve(m, b, x, epsilon);
855}
856
857/*---------------------------------------------------------------------------*/
858/*---------------------------------------------------------------------------*/
859
860void _testArcaneMatrix2(Integer matrix_number)
861{
862 cout.precision(16);
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";
868 Matrix m(Matrix::readHypre(dir_name + "/MATRIX_matrix" + ext_name.toString()));
869 Vector b(Vector::readHypre(dir_name + "/MATRIX_b" + ext_name.toString()));
870 Vector xref(Vector::readHypre(dir_name + "/MATRIX_x" + ext_name.toString()));
871 Vector x(m.nbRow());
872 cout << "** XREF=" << xref.size() << '\n';
873 //m.dump(cout);
874 cout << '\n';
875 {
876 Real epsilon = 1.0e-15;
877 {
879 solver.solve(m, b, x, epsilon);
880 }
881 MatrixOperation mat_op;
882 mat_op.negateVector(xref);
883 mat_op.addVector(xref, x);
884 //xref.dump(cout);
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';
890 }
891 else
892 cout << "** norm=" << x_norm << " DIFF=" << diff_norm << '\n';
893 cout << '\n';
894 }
895 {
896 Real epsilon = 1.0e-15;
897 x.values().fill(0.0);
898 {
901 solver.solve(m, b, x, epsilon, &p);
902 }
903 MatrixOperation mat_op;
904 mat_op.negateVector(xref);
905 mat_op.addVector(xref, x);
906 //xref.dump(cout);
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';
912 }
913 else
914 cout << "** norm=" << x_norm << " DIFF=" << diff_norm << '\n';
915 cout << '\n';
916 }
917}
918
919/*---------------------------------------------------------------------------*/
920/*---------------------------------------------------------------------------*/
921
922extern "C" void _testArcaneMatrix()
923{
924 _testArcaneMatrix1();
925 //for( Integer i=1; i<15; ++i )
926 //_testArcaneMatrix2(i);
927 exit(0);
928}
929
930/*---------------------------------------------------------------------------*/
931/*---------------------------------------------------------------------------*/
932
933void MatrixImpl::
934setRowsSize(IntegerConstArrayView rows_size)
935{
936 Integer index = 0;
937 for (Integer i = 0, is = m_nb_row; i < is; ++i) {
938 m_rows_index[i] = index;
939 index += rows_size[i];
940 }
941 m_rows_index[m_nb_row] = index;
942 m_nb_element = index;
943 m_columns.resize(index);
944 m_columns.fill(-1);
945 m_values.resize(index);
946}
947
948/*---------------------------------------------------------------------------*/
949/*---------------------------------------------------------------------------*/
950
951void MatrixImpl::
952setValues(IntegerConstArrayView columns, RealConstArrayView values)
953{
954 m_columns.copy(columns);
955 m_values.copy(values);
956 if (arcaneIsCheck())
957 checkValid();
958}
959
960/*---------------------------------------------------------------------------*/
961/*---------------------------------------------------------------------------*/
962
963void MatrixImpl::
964checkValid()
965{
966 IntegerConstArrayView columns = m_columns;
967 IntegerConstArrayView rows_index = m_rows_index;
968
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");
977 }
978 }
979 }
980}
981
982/*---------------------------------------------------------------------------*/
983/*---------------------------------------------------------------------------*/
984
985Real MatrixImpl::
986value(Integer row, Integer column) const
987{
988 IntegerConstArrayView rows_index = m_rows_index;
989 IntegerConstArrayView columns = m_columns;
990 RealConstArrayView values = m_values;
991
992 for (Integer z = rows_index[row], zs = rows_index[row + 1]; z < zs; ++z) {
993 if (columns[z] == column)
994 return values[z];
995 }
996 return 0.0;
997}
998
999/*---------------------------------------------------------------------------*/
1000/*---------------------------------------------------------------------------*/
1001
1002void MatrixImpl::
1003setValue(Integer row, Integer column, Real value)
1004{
1005 IntegerConstArrayView rows_index = m_rows_index;
1006 IntegerArrayView columns = m_columns;
1007#ifdef ARCANE_CHECK
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");
1012 if (row < 0)
1013 throw ArgumentException("MatrixImpl::setValue", "Invalid row");
1014 if (column < 0)
1015 throw ArgumentException("MatrixImpl::setValue", "Invalid column");
1016#endif
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;
1021 return;
1022 }
1023 }
1024 throw ArgumentException("Matrix::setValue", "column not found");
1025}
1026
1027/*---------------------------------------------------------------------------*/
1028/*---------------------------------------------------------------------------*/
1029
1030void MatrixImpl::
1031sortDiagonale()
1032{
1033 assemble();
1034 if (arcaneIsCheck()) {
1035 checkValid();
1036 }
1037 // Sort the diagonal so that it is the first element of the row
1038 IntegerConstArrayView rows_index = m_rows_index;
1039 IntegerArrayView columns = m_columns;
1040 RealArrayView values = m_values;
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];
1049 columns[j] = c;
1050 values[j] = v;
1051 }
1052 }
1053 }
1054 if (arcaneIsCheck())
1055 checkValid();
1056}
1057
1058/*---------------------------------------------------------------------------*/
1059/*---------------------------------------------------------------------------*/
1060
1061void MatrixImpl::
1062assemble()
1063{
1064 IntegerConstArrayView rows_index = m_rows_index;
1065 IntegerArrayView columns = m_columns;
1066 RealConstArrayView values = m_values;
1067
1068 SharedArray<Integer> new_rows_index(m_nb_row + 1);
1069 SharedArray<Integer> new_columns;
1070 SharedArray<Real> new_values;
1071
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]);
1079 }
1080 }
1081 new_rows_index[row + 1] = new_columns.size();
1082 }
1083
1084 m_rows_index = new_rows_index;
1085 m_columns = new_columns;
1086 m_values = new_values;
1087 m_nb_element = new_values.size();
1088 if (arcaneIsCheck())
1089 checkValid();
1090}
1091
1092/*---------------------------------------------------------------------------*/
1093/*---------------------------------------------------------------------------*/
1094
1095void MatrixImpl::
1096dump(std::ostream& o)
1097{
1098 o << "(Matrix nb_row=" << m_nb_row << " nb_col=" << m_nb_column << ")\n";
1099 //Integer index = 0;
1100 for (Integer i = 0, is = m_nb_row; i < is; ++i) {
1101 o << "[" << i << "] ";
1102 Real sum = 0.0;
1103 for (Integer z = m_rows_index[i], zs = m_rows_index[i + 1]; z < zs; ++z) {
1104 Integer j = m_columns[z];
1105 Real v = m_values[z];
1106 sum += v;
1107 o << " [" << j << "]=" << v;
1108 }
1109 o << " S=" << sum << '\n';
1110 }
1111 //o << ")";
1112}
1113
1114/*---------------------------------------------------------------------------*/
1115/*---------------------------------------------------------------------------*/
1116
1118read(const String& filename)
1119{
1120 std::ifstream ifile(filename.localstr());
1121 Integer nb_x = 0;
1122 Integer nb_y = 0;
1123 ifile >> ws >> nb_x >> ws >> nb_y;
1124 //cout << "** ** N=" << nb_x << ' ' << nb_y << '\n';
1125 if (nb_x != 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);
1128 UniqueArray<Int32> rows_size(nb_x);
1131 for (Int32 x = 0; x < nb_x; ++x) {
1132 Int32 nb_column = 0;
1133 for (Int32 y = 0; y < nb_y; ++y) {
1134 Real v = 0.0;
1135 ifile >> v;
1136 if (!math::isZero(v)) {
1137 columns.add(y);
1138 values.add(v);
1139 ++nb_column;
1140 }
1141 }
1142 rows_size[x] = nb_column;
1143 }
1144 m.setRowsSize(rows_size);
1146 return m;
1147}
1148
1149/*---------------------------------------------------------------------------*/
1150/*---------------------------------------------------------------------------*/
1151
1153readHypre(const String& filename)
1154{
1155 const bool is_verbose = false;
1156 std::ifstream ifile(filename.localstr());
1157 if (!ifile.good())
1158 ARCANE_FATAL("Can not read Hypre matrix file='{0}'", filename);
1159 Int32 lower_i = 0;
1160 Int32 upper_i = 0;
1161 Int32 lower_j = 0;
1162 Int32 upper_j = 0;
1163 ifile >> lower_i >> upper_i >> lower_j >> upper_j;
1164 if (is_verbose) {
1165 std::cout << "** ** I=" << lower_i << ' ' << upper_i << '\n';
1166 std::cout << "** ** IJ" << lower_j << ' ' << upper_j << '\n';
1167 }
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;
1172 if (is_verbose)
1173 std::cout << "** ** N=" << nb_x << ' ' << nb_y << '\n';
1174 if (nb_x != nb_y)
1175 ARCANE_FATAL("Not a square matrix nb_x={0} nb_y={1}", nb_x, nb_y);
1176
1177 Matrix m(nb_x, nb_y);
1178 UniqueArray<Int32> rows_size(nb_x);
1181
1182 Int32 nb_column = 0;
1183 Int32 last_row = 0;
1184 while (!ifile.eof()) {
1185 Int32 x = 0;
1186 Int32 y = 0;
1187 Real v = 0.0;
1188 ifile >> ws >> x >> ws >> y >> ws >> v >> ws;
1189 if (is_verbose)
1190 std::cout << "X=" << x << " Y=" << y << " V=" << v << "\n";
1191 if (!ifile.good())
1192 break;
1193 if (x != last_row) {
1194 // New row.
1195 if (is_verbose)
1196 std::cout << "New row last_row_size=" << nb_column << "\n";
1197 rows_size[last_row] = nb_column;
1198 nb_column = 0;
1199 last_row = x;
1200 }
1201 columns.add(y);
1202 values.add(v);
1203 ++nb_column;
1204 }
1205 rows_size[last_row] = nb_column;
1206 m.setRowsSize(rows_size);
1208 return m;
1209}
1210
1211/*---------------------------------------------------------------------------*/
1212/*---------------------------------------------------------------------------*/
1213
1214} // namespace Arcane::MatVec
1215
1216/*---------------------------------------------------------------------------*/
1217/*---------------------------------------------------------------------------*/
#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.
Matrix with CSR storage.
Definition Matrix.cc:40
Matrix with CSR storage.
MatrixImpl * m_impl
Implementation.
static Matrix readHypre(const String &filename)
Reads the matrix in Hypre format.
Definition Matrix.cc:1153
void sortDiagonale()
Arranges the storage so that the diagonal is the first element.
Definition Matrix.cc:197
IntegerConstArrayView rowsIndex() const
Indices of the first elements of each row.
Definition Matrix.cc:225
Real value(Integer row, Integer column) const
Returns the value of a matrix element.
Definition Matrix.cc:252
void setRowsSize(IntegerConstArrayView rows_size)
Sets the number of non-zero elements for each row.
Definition Matrix.cc:270
void setValues(IntegerConstArrayView columns, RealConstArrayView values)
Sets the values of the matrix elements.
Definition Matrix.cc:261
IntegerConstArrayView columns() const
Column indices of the values.
Definition Matrix.cc:315
void setValue(Integer row, Integer column, Real value)
Sets the value of a matrix element.
Definition Matrix.cc:243
static Matrix read(const String &filename)
Reads the matrix in X Y format.
Definition Matrix.cc:1118
void dump(std::ostream &o) const
Prints the matrix.
Definition Matrix.cc:234
RealConstArrayView values() const
Matrix values.
Definition Matrix.cc:279
Matrix clone() const
Clone the matrix.
Definition Matrix.cc:215
Linear algebra vector.
static Vector readHypre(const String &file_name)
Initializes a vector using a Hypre format file.
Definition Vector.cc:241
1D vector of data with reference semantics.
SharedArray< T > clone() const
Clones the array.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
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.
Definition Misc.cc:66
Int32 Integer
Type representing an integer.
ArrayView< Integer > IntegerArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:457
UniqueArray< Real > RealUniqueArray
Dynamic 1D array of reals.
Definition UtilsTypes.h:349
double Real
Type representing a real number.
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
Definition UtilsTypes.h:347
ConstArrayView< Integer > IntegerConstArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:486
ArrayView< Real > RealArrayView
C equivalent of a 1D array of reals.
Definition UtilsTypes.h:459
std::int32_t Int32
Signed integer type of 32 bits.
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.
Definition UtilsTypes.h:488