Arcane  v4.1.8.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());
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());
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 Real delta0 = delta_new;
509 //cout << " TOL=" << epsilon << " delta0=" << delta0 << '\n';
510 //cout << " deltanew=" << delta_new << '\n';
511 Integer nb_iter = 0;
512 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
513 if (delta_new < epsilon * epsilon * delta0)
514 break;
515#if 0
516 // Si on utilise la norme inf
517 {
518 Real norm = r.normInf();
519 cout << " norm=" << norm << " norm0=" << norm0 << '\n';
520 if (norm < epsilon * norm0)
521 break;
522 }
523#endif
524
525 //cout << "delta_new=" << delta_new << '\n';
526 // q = A * d
527 mat_op.matrixVectorProduct(a, d, q);
528 Real alpha = delta_new / mat_op.dot(d, q);
529
530 // x = x + alpha * d
531 t.copy(d);
532 mat_op.scaleVector(t, alpha);
533 mat_op.addVector(x, t);
534
535#if 0
536 // r = b - Ax
537 mat_op.matrixVectorProduct(a,x,r);
538 mat_op.negateVector(r);
539 mat_op.addVector(r,b);
540#endif
541 // r = r - alpha * q
542 mat_op.scaleVector(q, -alpha);
543 mat_op.addVector(r, q);
544
545 if (p)
546 p->apply(s, r);
547 Real delta_old = delta_new;
548 if (p)
549 delta_new = mat_op.dot(r, s);
550 else
551 delta_new = mat_op.dot(r);
552 Real beta = delta_new / delta_old;
553 //cout << " alpha=" << alpha << " beta=" << beta << " delta_new=" << delta_new << '\n';
554 // d = beta * d + s
555 mat_op.scaleVector(d, beta);
556 if (p) {
557 //mat_op.addVector(s,r);
558 mat_op.addVector(d, s);
559 }
560 else
561 mat_op.addVector(d, r);
562 //cout << '\n';
563 }
564 //cout << " X=";
565 //x.dump(cout);
566 //cout << '\n';
567 //cout << "NB ITER=" << nb_iter << " epsilon=" << epsilon
568 // << " delta0=" << delta0
569 // << " delta_new=" << delta_new << " r=" << mat_op.dot(r) << " r0=" << r0 << '\n';
570 m_nb_iteration = nb_iter;
571 m_residual_norm = delta_new;
572}
573
574/*---------------------------------------------------------------------------*/
575/*---------------------------------------------------------------------------*/
576
577void ConjugateGradientSolver::
578_applySolverAsHypre(const Matrix& a, const Vector& b, Vector& x, Real tol,
579 IPreconditioner* precond)
580{
581 //cout << "** APPLY ARCANE_SOLVER PCG using hypre method\n";
582 ARCANE_CHECK_POINTER(precond);
583
584 MatrixOperation mat_op;
585 Integer vec_size = a.nbRow();
586 Vector r(vec_size);
587 Vector p(vec_size);
588
589 const bool is_two_norm = true;
590 Real bi_prod = 0.0;
591 if (is_two_norm) {
592 bi_prod = mat_op.dot(b, b);
593 }
594 else {
595 precond->apply(p, b);
596 bi_prod = mat_op.dot(p, b);
597 }
598 Real eps = tol * tol;
599 //TODO: regarder stop_crit
600
601 // r = b - Ax
602 mat_op.matrixVectorProduct(a, x, r);
603 mat_op.negateVector(r);
604 mat_op.addVector(r, b);
605
606 m_nb_iteration = 0;
607 m_residual_norm = 0.0;
608
609 /*cout << " R=";
610 r.dump(cout);
611 cout << '\n';*/
612
613 Vector tmp_x(x.size());
614
615 Vector d(r.size());
616 Vector s(r.size());
617 d.copy(r);
618 // p = C*r
619 precond->apply(p, r);
620
621 /* gamma = <r,p> */
622 Real gamma = mat_op.dot(r, p);
623
624 Real i_prod = 0.0;
625
626 //Real delta_new = 0.0;
627 //Real r0=mat_op.dot(r);
628 //if (p){
629 // delta_new = mat_op.dot(r,d);
630 //}
631 //else
632 // delta_new = mat_op.dot(r);
633#if 0
634 cout << "R=";
635 r.dump(cout);
636 cout << "\n";
637 cout << "D=";
638 d.dump(cout);
639 cout << "\n";
640#endif
641 //Real delta0 = delta_new;
642 //cout << "** TOL=" << tol << " bi_prod=" << bi_prod << '\n';
643 //cout << " deltanew=" << delta_new << '\n';
644 Integer nb_iter = 0;
645 for (nb_iter = 0; nb_iter < m_max_iteration; ++nb_iter) {
646
647 // s = A * p
648 mat_op.matrixVectorProduct(a, p, s);
649
650 /* alpha = gamma / <s,p> */
651 Real sdotp = mat_op.dot(s, p);
652
653 Real alpha = gamma / sdotp;
654
655 Real gamma_old = gamma;
656
657 /* x = x + alpha*p */
658 mat_op.matrixVectorProduct(a, p, tmp_x);
659 mat_op.addVector(x, tmp_x);
660
661 /* r = r - alpha*s */
662 tmp_x.copy(s);
663 mat_op.scaleVector(tmp_x, -alpha);
664 mat_op.addVector(r, tmp_x);
665
666 /* s = C*r */
667 precond->apply(s, r);
668
669 /* gamma = <r,s> */
670 gamma = mat_op.dot(r, s);
671
672 /* set i_prod for convergence test */
673 if (is_two_norm)
674 i_prod = mat_op.dot(r, r);
675 else
676 i_prod = gamma;
677
678 //cout << "** sdotp=" << sdotp << " i_prod=" << i_prod << " bi_prod=" << bi_prod << '\n';
679
680 /* check for convergence */
681 if (i_prod / bi_prod < eps) {
682#if 0
683 if (rel_change && i_prod > guard_zero_residual)
684 {
685 pi_prod = (*(pcg_functions->InnerProd))(p,p);
686 xi_prod = (*(pcg_functions->InnerProd))(x,x);
687 ratio = alpha*alpha*pi_prod/xi_prod;
688 if (ratio < eps)
689 {
690 (pcg_data -> converged) = 1;
691 break;
692 }
693 }
694 else
695 {
696#endif
697 //(pcg_data -> converged) = 1;
698 break;
699#if 0
700 }
701#endif
702 }
703
704 /* beta = gamma / gamma_old */
705 Real beta = gamma / gamma_old;
706
707 //cout << " alpha=" << alpha << " beta=" << beta << " delta_new=" << gamma << '\n';
708
709 /* p = s + beta p */
710 tmp_x.copy(p);
711 mat_op.scaleVector(tmp_x, beta);
712 mat_op.addVector(tmp_x, s);
713 p.copy(tmp_x);
714 }
715 //cout << " X=";
716 //x.dump(cout);
717 //cout << '\n';
718 //cout << "NB ITER=" << nb_iter << " epsilon=" << epsilon
719 // << " delta0=" << delta0
720 // << " delta_new=" << delta_new << " r=" << mat_op.dot(r) << " r0=" << r0 << '\n';
721 m_nb_iteration = nb_iter;
722 m_residual_norm = gamma;
723}
724
725/*---------------------------------------------------------------------------*/
726/*---------------------------------------------------------------------------*/
727
728bool ConjugateGradientSolver::
729solve(const Matrix& a, const Vector& b, Vector& x, Real epsilon, IPreconditioner* p)
730{
731 //epsilon = 1e-12;
732 //x.values().fill(0.0);
733 m_nb_iteration = 0;
734 m_residual_norm = 0.0;
735 //_doConjugateGradient(a,b,x,epsilon,&p);
736 cout.precision(20);
737 const bool do_print = false;
738 if (do_print) {
739 cout << "A=";
740 a.dump(cout);
741 cout << '\n';
742 cout << "b=";
743 b.dump(cout);
744 cout << '\n';
745 }
746
747 DiagonalPreconditioner p2(a);
748 if (!p)
749 p = &p2;
750 _applySolver(a, b, x, epsilon, p);
751
752 if (do_print) {
753 cout << "\n\nSOLUTION\nx=";
754 x.dump(cout);
755 cout << '\n';
756 }
757
758 return false;
759}
760
761/*---------------------------------------------------------------------------*/
762/*---------------------------------------------------------------------------*/
763
764static void
765_testArcaneMatrix1()
766{
767 Integer s = 5;
768 Matrix m(s, s);
769 Matrix m1(Matrix::read("test.mat"));
770 cout << "** o=" << m.nbRow() << '\n';
771 cout << "** M1=";
772 m1.dump(cout);
773 cout << '\n';
774 Vector v1(10);
775 for (Integer i = 0; i < 10; ++i) {
776 v1.values()[i] = (Real)(i + 1);
777 }
778 Real epsilon = 1.0e-10;
779 {
780 Vector v2(10);
781 MatrixOperation mat_op;
782 Vector r(5);
783 mat_op.matrixVectorProduct(m1, v1, v2);
784 cout << "** V1=";
785 v1.dump(cout);
786 cout << "\n";
787 cout << "** V2=";
788 v2.dump(cout);
789 cout << "\n";
790 Vector b3(10);
791 for (Integer i = 0; i < 10; ++i) {
792 b3.values()[i] = (Real)(i + 1);
793 }
794 Vector x3(10);
797 solver.solve(m1, b3, x3, epsilon, &p);
798 }
799
800 IntegerUniqueArray rows_size(s);
801 rows_size[0] = 5;
802 rows_size[1] = 2;
803 rows_size[2] = 2;
804 rows_size[3] = 2;
805 rows_size[4] = 2;
806 m.setRowsSize(rows_size);
807 RealUniqueArray values(13);
808 IntegerUniqueArray columns(13);
809 values[0] = 9.0;
810 values[1] = 1.5;
811 values[2] = 6.0;
812 values[3] = 0.75;
813 values[4] = 3.0;
814
815 values[5] = 1.5;
816 values[6] = 0.5;
817
818 values[7] = 6.0;
819 values[8] = 0.5;
820
821 values[9] = 0.75;
822 values[10] = 5.0 / 8.0;
823
824 values[11] = 3.0;
825 values[12] = 16.0;
826
827 columns[0] = 0;
828 columns[1] = 1;
829 columns[2] = 2;
830 columns[3] = 3;
831 columns[4] = 4;
832 columns[5] = 0;
833 columns[6] = 1;
834 columns[7] = 0;
835 columns[8] = 2;
836 columns[9] = 0;
837 columns[10] = 3;
838 columns[11] = 0;
839 columns[12] = 4;
840 m.setValues(columns, values);
841 m.dump(cout);
842 cout << '\n';
843 Vector b(5);
844 RealArrayView rav(b.values());
845 rav[0] = 1.0;
846 rav[1] = 1.0;
847 rav[2] = 1.0;
848 rav[3] = 3.0;
849 rav[4] = 1.0;
850 Vector x(5);
852 solver.solve(m, b, x, epsilon);
853}
854
855/*---------------------------------------------------------------------------*/
856/*---------------------------------------------------------------------------*/
857
858void _testArcaneMatrix2(Integer matrix_number)
859{
860 cout.precision(16);
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";
866 Matrix m(Matrix::readHypre(dir_name + "/MATRIX_matrix" + ext_name.toString()));
867 Vector b(Vector::readHypre(dir_name + "/MATRIX_b" + ext_name.toString()));
868 Vector xref(Vector::readHypre(dir_name + "/MATRIX_x" + ext_name.toString()));
869 Vector x(m.nbRow());
870 cout << "** XREF=" << xref.size() << '\n';
871 //m.dump(cout);
872 cout << '\n';
873 {
874 Real epsilon = 1.0e-15;
875 {
877 solver.solve(m, b, x, epsilon);
878 }
879 MatrixOperation mat_op;
880 mat_op.negateVector(xref);
881 mat_op.addVector(xref, x);
882 //xref.dump(cout);
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';
888 }
889 else
890 cout << "** norm=" << x_norm << " DIFF=" << diff_norm << '\n';
891 cout << '\n';
892 }
893 {
894 Real epsilon = 1.0e-15;
895 x.values().fill(0.0);
896 {
899 solver.solve(m, b, x, epsilon, &p);
900 }
901 MatrixOperation mat_op;
902 mat_op.negateVector(xref);
903 mat_op.addVector(xref, x);
904 //xref.dump(cout);
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';
910 }
911 else
912 cout << "** norm=" << x_norm << " DIFF=" << diff_norm << '\n';
913 cout << '\n';
914 }
915}
916
917/*---------------------------------------------------------------------------*/
918/*---------------------------------------------------------------------------*/
919
920extern "C" void _testArcaneMatrix()
921{
922 _testArcaneMatrix1();
923 //for( Integer i=1; i<15; ++i )
924 //_testArcaneMatrix2(i);
925 exit(0);
926}
927
928/*---------------------------------------------------------------------------*/
929/*---------------------------------------------------------------------------*/
930
931void MatrixImpl::
932setRowsSize(IntegerConstArrayView rows_size)
933{
934 Integer index = 0;
935 for (Integer i = 0, is = m_nb_row; i < is; ++i) {
936 m_rows_index[i] = index;
937 index += rows_size[i];
938 }
939 m_rows_index[m_nb_row] = index;
940 m_nb_element = index;
941 m_columns.resize(index);
942 m_columns.fill(-1);
943 m_values.resize(index);
944}
945
946/*---------------------------------------------------------------------------*/
947/*---------------------------------------------------------------------------*/
948
949void MatrixImpl::
950setValues(IntegerConstArrayView columns, RealConstArrayView values)
951{
952 m_columns.copy(columns);
953 m_values.copy(values);
954 if (arcaneIsCheck())
955 checkValid();
956}
957
958/*---------------------------------------------------------------------------*/
959/*---------------------------------------------------------------------------*/
960
961void MatrixImpl::
962checkValid()
963{
964 IntegerConstArrayView columns = m_columns;
965 IntegerConstArrayView rows_index = m_rows_index;
966
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");
975 }
976 }
977 }
978}
979
980/*---------------------------------------------------------------------------*/
981/*---------------------------------------------------------------------------*/
982
983Real MatrixImpl::
984value(Integer row, Integer column) const
985{
986 IntegerConstArrayView rows_index = m_rows_index;
987 IntegerConstArrayView columns = m_columns;
988 RealConstArrayView values = m_values;
989
990 for (Integer z = rows_index[row], zs = rows_index[row + 1]; z < zs; ++z) {
991 if (columns[z] == column)
992 return values[z];
993 }
994 return 0.0;
995}
996
997/*---------------------------------------------------------------------------*/
998/*---------------------------------------------------------------------------*/
999
1000void MatrixImpl::
1001setValue(Integer row, Integer column, Real value)
1002{
1003 IntegerConstArrayView rows_index = m_rows_index;
1004 IntegerArrayView columns = m_columns;
1005#ifdef ARCANE_CHECK
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");
1010 if (row < 0)
1011 throw ArgumentException("MatrixImpl::setValue", "Invalid row");
1012 if (column < 0)
1013 throw ArgumentException("MatrixImpl::setValue", "Invalid column");
1014#endif
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;
1019 return;
1020 }
1021 }
1022 throw ArgumentException("Matrix::setValue", "column not found");
1023}
1024
1025/*---------------------------------------------------------------------------*/
1026/*---------------------------------------------------------------------------*/
1027
1028void MatrixImpl::
1029sortDiagonale()
1030{
1031 assemble();
1032 if (arcaneIsCheck()) {
1033 checkValid();
1034 }
1035 // Trie la diagonale pour qu'elle soit le premièr élément de la ligne
1036 IntegerConstArrayView rows_index = m_rows_index;
1037 IntegerArrayView columns = m_columns;
1038 RealArrayView values = m_values;
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];
1047 columns[j] = c;
1048 values[j] = v;
1049 }
1050 }
1051 }
1052 if (arcaneIsCheck())
1053 checkValid();
1054}
1055
1056/*---------------------------------------------------------------------------*/
1057/*---------------------------------------------------------------------------*/
1058
1059void MatrixImpl::
1060assemble()
1061{
1062 IntegerConstArrayView rows_index = m_rows_index;
1063 IntegerArrayView columns = m_columns;
1064 RealConstArrayView values = m_values;
1065
1066 SharedArray<Integer> new_rows_index(m_nb_row + 1);
1067 SharedArray<Integer> new_columns;
1068 SharedArray<Real> new_values;
1069
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]);
1077 }
1078 }
1079 new_rows_index[row + 1] = new_columns.size();
1080 }
1081
1082 m_rows_index = new_rows_index;
1083 m_columns = new_columns;
1084 m_values = new_values;
1085 m_nb_element = new_values.size();
1086 if (arcaneIsCheck())
1087 checkValid();
1088}
1089
1090/*---------------------------------------------------------------------------*/
1091/*---------------------------------------------------------------------------*/
1092
1093void MatrixImpl::
1094dump(std::ostream& o)
1095{
1096 o << "(Matrix nb_row=" << m_nb_row << " nb_col=" << m_nb_column << ")\n";
1097 //Integer index = 0;
1098 for (Integer i = 0, is = m_nb_row; i < is; ++i) {
1099 o << "[" << i << "] ";
1100 Real sum = 0.0;
1101 for (Integer z = m_rows_index[i], zs = m_rows_index[i + 1]; z < zs; ++z) {
1102 Integer j = m_columns[z];
1103 Real v = m_values[z];
1104 sum += v;
1105 o << " [" << j << "]=" << v;
1106 }
1107 o << " S=" << sum << '\n';
1108 }
1109 //o << ")";
1110}
1111
1112/*---------------------------------------------------------------------------*/
1113/*---------------------------------------------------------------------------*/
1114
1116read(const String& filename)
1117{
1118 std::ifstream ifile(filename.localstr());
1119 Integer nb_x = 0;
1120 Integer nb_y = 0;
1121 ifile >> ws >> nb_x >> ws >> nb_y;
1122 //cout << "** ** N=" << nb_x << ' ' << nb_y << '\n';
1123 if (nb_x != 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);
1126 UniqueArray<Int32> rows_size(nb_x);
1129 for (Int32 x = 0; x < nb_x; ++x) {
1130 Int32 nb_column = 0;
1131 for (Int32 y = 0; y < nb_y; ++y) {
1132 Real v = 0.0;
1133 ifile >> v;
1134 if (!math::isZero(v)) {
1135 columns.add(y);
1136 values.add(v);
1137 ++nb_column;
1138 }
1139 }
1140 rows_size[x] = nb_column;
1141 }
1142 m.setRowsSize(rows_size);
1144 return m;
1145}
1146
1147/*---------------------------------------------------------------------------*/
1148/*---------------------------------------------------------------------------*/
1149
1151readHypre(const String& filename)
1152{
1153 const bool is_verbose = false;
1154 std::ifstream ifile(filename.localstr());
1155 if (!ifile.good())
1156 ARCANE_FATAL("Can not read Hypre matrix file='{0}'", filename);
1157 Int32 lower_i = 0;
1158 Int32 upper_i = 0;
1159 Int32 lower_j = 0;
1160 Int32 upper_j = 0;
1161 ifile >> lower_i >> upper_i >> lower_j >> upper_j;
1162 if (is_verbose) {
1163 std::cout << "** ** I=" << lower_i << ' ' << upper_i << '\n';
1164 std::cout << "** ** IJ" << lower_j << ' ' << upper_j << '\n';
1165 }
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;
1170 if (is_verbose)
1171 std::cout << "** ** N=" << nb_x << ' ' << nb_y << '\n';
1172 if (nb_x != nb_y)
1173 ARCANE_FATAL("Not a square matrix nb_x={0} nb_y={1}", nb_x, nb_y);
1174
1175 Matrix m(nb_x, nb_y);
1176 UniqueArray<Int32> rows_size(nb_x);
1179
1180 Int32 nb_column = 0;
1181 Int32 last_row = 0;
1182 while (!ifile.eof()) {
1183 Int32 x = 0;
1184 Int32 y = 0;
1185 Real v = 0.0;
1186 ifile >> ws >> x >> ws >> y >> ws >> v >> ws;
1187 if (is_verbose)
1188 std::cout << "X=" << x << " Y=" << y << " V=" << v << "\n";
1189 if (!ifile.good())
1190 break;
1191 if (x != last_row) {
1192 // Nouvelle ligne.
1193 if (is_verbose)
1194 std::cout << "New row last_row_size=" << nb_column << "\n";
1195 rows_size[last_row] = nb_column;
1196 nb_column = 0;
1197 last_row = x;
1198 }
1199 columns.add(y);
1200 values.add(v);
1201 ++nb_column;
1202 }
1203 rows_size[last_row] = nb_column;
1204 m.setRowsSize(rows_size);
1206 return m;
1207}
1208
1209/*---------------------------------------------------------------------------*/
1210/*---------------------------------------------------------------------------*/
1211
1212} // namespace Arcane::MatVec
1213
1214/*---------------------------------------------------------------------------*/
1215/*---------------------------------------------------------------------------*/
#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:1151
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:1116
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:231
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