Arcane  v4.1.11.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
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/* Matrix d'algèbre linéraire. */
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/*---------------------------------------------------------------------------*/
38class MatrixImpl
39{
40 public:
41
42 MatrixImpl()
43 : m_nb_reference(0)
44 , m_nb_row(0)
45 , m_nb_column(0)
46 , m_nb_element(0)
47 {}
48 MatrixImpl(Integer nb_row, Integer nb_column);
49
50 private:
51
52 void operator=(const Matrix& rhs);
53
54 public:
55
56 MatrixImpl* clone()
57 {
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();
65 return m2;
66 }
67
68 private:
69 public:
70
71 Integer nbRow() const { return m_nb_row; }
72 Integer nbColumn() const { return m_nb_column; }
73 void setRowsSize(IntegerConstArrayView rows_size);
74 void setValues(IntegerConstArrayView columns, RealConstArrayView values);
75 void dump(std::ostream& o);
76 RealConstArrayView values() const { return m_values; }
77 RealArrayView values() { return m_values; }
78 Real value(Integer row, Integer column) const;
79 IntegerConstArrayView rowsIndex() const { return m_rows_index; }
80 IntegerConstArrayView columns() const { return m_columns; }
81 IntegerArrayView rowsIndex() { return m_rows_index; }
82 IntegerArrayView columns() { return m_columns; }
83 void setValue(Integer row, Integer column, Real value);
84 void sortDiagonale();
85 void assemble();
86
87 public:
88
89 void checkValid();
90
91 public:
92
93 void addReference()
94 {
95 ++m_nb_reference;
96 }
97 void removeReference()
98 {
99 --m_nb_reference;
100 if (m_nb_reference == 0)
101 delete this;
102 }
103
104 private:
105
106 Integer m_nb_reference;
107 Integer m_nb_row;
108 Integer m_nb_column;
109 Integer m_nb_element;
110 SharedArray<Real> m_values;
111 SharedArray<Integer> m_rows_index;
112 SharedArray<Integer> m_columns;
113};
114
115/*---------------------------------------------------------------------------*/
116/*---------------------------------------------------------------------------*/
117
118MatrixImpl::
119MatrixImpl(Integer nb_row, Integer nb_column)
120: m_nb_reference(0)
121, m_nb_row(nb_row)
122, m_nb_column(nb_column)
123, m_nb_element(0)
124, m_rows_index(m_nb_row + 1)
125{
126}
127
128/*---------------------------------------------------------------------------*/
129/*---------------------------------------------------------------------------*/
130
131Matrix::
132Matrix(Integer nb_row, Integer nb_column)
133: m_impl(new MatrixImpl(nb_row, nb_column))
134{
135 m_impl->addReference();
136}
137
138/*---------------------------------------------------------------------------*/
139/*---------------------------------------------------------------------------*/
140
141Matrix::
142Matrix(MatrixImpl* impl)
143: m_impl(impl)
144{
145 if (m_impl)
146 m_impl->addReference();
147}
148
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
151
152Matrix::
153Matrix(const Matrix& rhs)
154: m_impl(rhs.m_impl)
155{
156 if (m_impl)
157 m_impl->addReference();
158}
159
160/*---------------------------------------------------------------------------*/
161/*---------------------------------------------------------------------------*/
162
163void Matrix::
164operator=(const Matrix& rhs)
165{
166 if (rhs.m_impl)
167 rhs.m_impl->addReference();
168 if (m_impl)
169 m_impl->removeReference();
170 m_impl = rhs.m_impl;
171}
172
173/*---------------------------------------------------------------------------*/
174/*---------------------------------------------------------------------------*/
175
176Matrix::
177~Matrix()
178{
179 if (m_impl)
180 m_impl->removeReference();
181}
182
183/*---------------------------------------------------------------------------*/
184/*---------------------------------------------------------------------------*/
185
186Integer Matrix::
187nbRow() const
188{
189 return m_impl->nbRow();
190}
191
192/*---------------------------------------------------------------------------*/
193/*---------------------------------------------------------------------------*/
194
197{
198 return m_impl->sortDiagonale();
199}
200
201/*---------------------------------------------------------------------------*/
202/*---------------------------------------------------------------------------*/
203
204Integer Matrix::
205nbColumn() const
206{
207 return m_impl->nbColumn();
208}
209
210/*---------------------------------------------------------------------------*/
211/*---------------------------------------------------------------------------*/
212
214clone() const
215{
216 MatrixImpl* m = m_impl->clone();
217 return Matrix(m);
218}
219
220/*---------------------------------------------------------------------------*/
221/*---------------------------------------------------------------------------*/
222
224rowsIndex() const
225{
226 return m_impl->rowsIndex();
227}
228
229/*---------------------------------------------------------------------------*/
230/*---------------------------------------------------------------------------*/
231
233dump(std::ostream& o) const
234{
235 m_impl->dump(o);
236}
237
238/*---------------------------------------------------------------------------*/
239/*---------------------------------------------------------------------------*/
240
242setValue(Integer row, Integer column, Real value)
243{
244 m_impl->setValue(row, column, value);
245}
246
247/*---------------------------------------------------------------------------*/
248/*---------------------------------------------------------------------------*/
249
251value(Integer row, Integer column) const
252{
253 return m_impl->value(row, column);
254}
255
256/*---------------------------------------------------------------------------*/
257/*---------------------------------------------------------------------------*/
258
264
265/*---------------------------------------------------------------------------*/
266/*---------------------------------------------------------------------------*/
267
270{
271 m_impl->setRowsSize(rows_size);
272}
273
274/*---------------------------------------------------------------------------*/
275/*---------------------------------------------------------------------------*/
276
278values() const
279{
280 return m_impl->values();
281}
282
283/*---------------------------------------------------------------------------*/
284/*---------------------------------------------------------------------------*/
285
287values()
288{
289 return m_impl->values();
290}
291
292/*---------------------------------------------------------------------------*/
293/*---------------------------------------------------------------------------*/
294
296columns()
297{
298 return m_impl->columns();
299}
300
301/*---------------------------------------------------------------------------*/
302/*---------------------------------------------------------------------------*/
303
305rowsIndex()
306{
307 return m_impl->rowsIndex();
308}
309
310/*---------------------------------------------------------------------------*/
311/*---------------------------------------------------------------------------*/
312
314columns() const
315{
316 return m_impl->columns();
317}
318
319/*---------------------------------------------------------------------------*/
320/*---------------------------------------------------------------------------*/
321
322DiagonalPreconditioner::
323DiagonalPreconditioner(const Matrix& matrix)
324: m_inverse_diagonal(matrix.nbRow())
325{
326 Integer size = m_inverse_diagonal.size();
327 IntegerConstArrayView rows_index = matrix.rowsIndex();
329 RealConstArrayView mat_values = matrix.values();
330 RealArrayView vec_values = m_inverse_diagonal.values();
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) {
333 Integer mj = columns[z];
334 if (mj == i)
335 vec_values[i] = mat_values[z];
336 }
337 }
338#if 0
339 cout << "DIAG1=";
340 m_inverse_diagonal.dump(cout);
341 cout << "\n";
342#endif
343 const double epsilon = std::numeric_limits<Real>::min();
344
345 // Inverse la diagonale si la valeur n'est pas inférieure à l'epsilon de Real
346 // (sinon cela génère un FPE)
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);
351 }
352
353#if 0
354 cout << "DIAG2=";
355 m_inverse_diagonal.dump(cout);
356 cout << "\n";
357#endif
358}
359
360/*---------------------------------------------------------------------------*/
361/*---------------------------------------------------------------------------*/
362
363void DiagonalPreconditioner::
364apply(Vector& out_vec, const Vector& vec)
365{
366 Integer size = m_inverse_diagonal.size();
367 RealConstArrayView inverse_diagonal_values = m_inverse_diagonal.values();
368 RealConstArrayView vec_values = vec.values();
369 RealArrayView out_vec_values = out_vec.values();
370 for (Integer i = 0; i < size; ++i)
371 out_vec_values[i] = vec_values[i] * inverse_diagonal_values[i];
372}
373
374/*---------------------------------------------------------------------------*/
375/*---------------------------------------------------------------------------*/
376
377void MatrixOperation::
378matrixVectorProduct(const Matrix& mat, const Vector& vec, Vector& out_vec)
379{
380 Integer nb_row = mat.nbRow();
381 Integer nb_column = mat.nbColumn();
382 //cout << "** MATRIX ROW=" << nb_row << " COL=" << nb_column
383 // << " intput_size=" << vec.size()
384 // << " output_size=" << out_vec.size()
385 // << "\n";
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");
390 IntegerConstArrayView rows_index = mat.rowsIndex();
391 IntegerConstArrayView columns = mat.columns();
392 RealConstArrayView mat_values = mat.values();
393 RealConstArrayView vec_values = vec.values();
394 RealArrayView out_vec_values = out_vec.values();
395
396 for (Integer i = 0, is = nb_row; i < is; ++i) {
397 Real sum = 0.0;
398 for (Integer z = rows_index[i], zs = rows_index[i + 1]; z < zs; ++z) {
399 Integer mj = columns[z];
400 Real mv = mat_values[z];
401 //cout << "ADD vec=" << vec_values[mj] << " mv=" << mv << " sum=" << sum << '\n';
402 sum += vec_values[mj] * mv;
403 }
404 out_vec_values[i] = sum;
405 }
406}
407
408Real MatrixOperation::
409dot(const Vector& vec)
410{
411 Integer size = vec.size();
412 RealConstArrayView vec_values = vec.values();
413 Real v = 0.0;
414 for (Integer i = 0; i < size; ++i)
415 v += vec_values[i] * vec_values[i];
416 return v;
417}
418
419Real MatrixOperation::
420dot(const Vector& vec1, const Vector& vec2)
421{
422 Real v = 0.0;
423 Integer size = vec1.size();
424 RealConstArrayView vec1_values = vec1.values();
425 RealConstArrayView vec2_values = vec2.values();
426 for (Integer i = 0; i < size; ++i) {
427 v += vec1_values[i] * vec2_values[i];
428 //cout << " i=" << i << " v=" << v << '\n';
429 }
430 return v;
431}
432
433void MatrixOperation::
434negateVector(Vector& vec)
435{
436 Integer size = vec.size();
437 RealArrayView vec_values = vec.values();
438 for (Integer i = 0; i < size; ++i)
439 vec_values[i] = -vec_values[i];
440}
441
442void MatrixOperation::
443scaleVector(Vector& vec, Real mul)
444{
445 Integer size = vec.size();
446 RealArrayView vec_values = vec.values();
447 for (Integer i = 0; i < size; ++i)
448 vec_values[i] *= mul;
449}
450
451void MatrixOperation::
452addVector(Vector& out_vec, const Vector& vec)
453{
454 Integer size = vec.size();
455 RealConstArrayView vec_values = vec.values();
456 RealArrayView out_vec_values = out_vec.values();
457 for (Integer i = 0; i < size; ++i)
458 out_vec_values[i] += vec_values[i];
459}
460
461/*---------------------------------------------------------------------------*/
462/*---------------------------------------------------------------------------*/
463
464void ConjugateGradientSolver::
465_applySolver(const Matrix& a, const Vector& b, Vector& x, Real epsilon, IPreconditioner* p)
466{
467 MatrixOperation mat_op;
468 Integer vec_size = a.nbRow();
469 Vector r(vec_size);
470
471 // r = b - Ax
472 mat_op.matrixVectorProduct(a, x, r);
473 mat_op.negateVector(r);
474 mat_op.addVector(r, b);
475
476 m_nb_iteration = 0;
477 m_residual_norm = 0.0;
478
479 /*cout << " R=";
480 r.dump(cout);
481 cout << '\n';*/
482
483 Vector d(r.size(), 0.0);
484 if (p)
485 p->apply(d, r);
486 else
487 d.copy(r);
488
489 Vector q(r.size());
490 Vector t(r.size());
491 Vector s(r.size(), 0.0);
492 Real delta_new = 0.0;
493 //Real r0=mat_op.dot(r);
494 if (p) {
495 delta_new = mat_op.dot(r, d);
496 }
497 else
498 delta_new = mat_op.dot(r);
499#if 0
500 cout << "R=";
501 r.dump(cout);
502 cout << "\n";
503 cout << "D=";
504 d.dump(cout);
505 cout << "\n";
506#endif
507 //Real norm0 = r.normInf();
508 const Real delta0 = delta_new;
509
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 // Si on utilise la norme inf
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 // Trie la diagonale pour qu'elle soit le premièr élément de la ligne
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 // Nouvelle ligne.
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 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.
Interface d'un préconditionneur.
Matrice avec stockage CSR.
Definition Matrix.cc:39
Matrice avec stockage CSR.
MatrixImpl * m_impl
Implémentation.
static Matrix readHypre(const String &filename)
Lit la matrice au format Hypre.
Definition Matrix.cc:1153
void sortDiagonale()
Arrange le stockage pour que la diagonale soit le premier élément.
Definition Matrix.cc:196
IntegerConstArrayView rowsIndex() const
Indices des premiers éléments de chaque ligne.
Definition Matrix.cc:224
Real value(Integer row, Integer column) const
Retourne la valeur d'un élément de la matrice.
Definition Matrix.cc:251
void setRowsSize(IntegerConstArrayView rows_size)
Positionne le nombre d'éléments non nuls de chaque ligne.
Definition Matrix.cc:269
void setValues(IntegerConstArrayView columns, RealConstArrayView values)
Positionne les valeurs des éléments de la matrice.
Definition Matrix.cc:260
IntegerConstArrayView columns() const
Indices des colonnes des valeurs.
Definition Matrix.cc:314
void setValue(Integer row, Integer column, Real value)
Positionne la valeur d'un élément de la matrice.
Definition Matrix.cc:242
static Matrix read(const String &filename)
Lit la matrice au format X Y.
Definition Matrix.cc:1118
void dump(std::ostream &o) const
Imprime la matrice.
Definition Matrix.cc:233
RealConstArrayView values() const
Valeurs de la matrice.
Definition Matrix.cc:278
Matrix clone() const
Clone la matrice.
Definition Matrix.cc:214
Vecteur d'algèbre linéraire.
static Vector readHypre(const String &file_name)
Initialise un vecteur en utilisant un fichier au format Hypre.
Definition Vector.cc:241
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.
Definition String.cc:228
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.
Definition Misc.cc:68
Int32 Integer
Type représentant un entier.
ArrayView< Integer > IntegerArrayView
Equivalent C d'un tableau à une dimension d'entiers.
Definition UtilsTypes.h:457
UniqueArray< Real > RealUniqueArray
Tableau dynamique à une dimension de réels.
Definition UtilsTypes.h:349
double Real
Type représentant un réel.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:347
ConstArrayView< Integer > IntegerConstArrayView
Equivalent C d'un tableau à une dimension d'entiers.
Definition UtilsTypes.h:486
ArrayView< Real > RealArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:459
std::int32_t Int32
Type entier signé sur 32 bits.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:488