TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Matrice_Morse.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Matrice_Morse.h>
17#include <Sparskit.h>
18#include <unordered_map>
19#include <Matrice_Morse_Sym.h>
20#include <Check_espace_virtuel.h>
21#include <SFichier.h>
22#include <Noms.h>
23#include <ArrOfBit.h>
24#include <Array_tools.h>
25#include <TRUSTTrav.h>
26#include <TRUSTTrav.h>
27
28
29Implemente_instanciable_sans_constructeur(Matrice_Morse,"Matrice_Morse",Matrice_Base);
30
31/*! @brief Ecrit les trois tableaux de la structure de stockage Morse sur un flot de sortie.
32 *
33 * @param (Sortie& s) un flot de sortie
34 * @return (Sortie& s) le flot de sortie modifie
35 */
37{
38 s << tab1_;
39 s << tab2_;
40 s << coeff_;
41 s << m_ << finl;
42 return s;
43}
44
45/*! @brief NON CODE
46 *
47 * @param (Entree& s) un flot d'entree
48 * @return (Entree& s) le flot d'entree
49 * @throws NON CODE
50 */
52{
53 s >> tab1_;
54 s >> tab2_;
55 s >> coeff_;
56 s >> m_;
58 return s;
59}
60
62{
63 int n=nb_lignes();
64 for(int i=0; i<n; i++)
65 {
66 s <<i << ": " <<finl;
67 s << "--------------------------------" << finl;
68 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
69 {
70 s << "("<<(tab2_(k)-1) << "),(" <<coeff_(k)<< ") "
71 << " k= " << k << finl;
72 }
73 s <<finl;
74 }
75 return s;
76}
77
82
84{
85 int numerotation_fortran=(tab1_[0]==1);
86 for (int proc=0; proc<Process::nproc(); proc++)
87 {
88 if (proc==Process::me())
89 {
90 s << "Matrix morse on the processor " << proc << " : " << finl;
91 int n=nb_lignes();
92 Noms tab_imp;
93 tab_imp.dimensionner(nb_colonnes());
94 for(int i=0; i<n; i++)
95 {
96 for (int k=0; k<nb_colonnes(); k++)
97 tab_imp[k]=" . ";
98 if (i<10)
99 s <<i << " :" ;
100 else
101 s <<i << ":" ;
102
103 if (symetrie)
104 {
105 for (int j=0; j<i; j++)
106 {
107 for (auto k=tab1_(j)-numerotation_fortran; k<tab1_(j+1)-numerotation_fortran; k++)
108 if (tab2_(k)-numerotation_fortran==i)
109 tab_imp[j] = coeff_(k);
110 }
111 int ligne=tab2_(tab1_(i)-numerotation_fortran)-numerotation_fortran;
112 if (i!=ligne)
113 {
114 Cerr << "Problem detected on this Matrice_Morse_Sym." << finl;
115 Cerr << "The diagonal of the line " << ligne << " must be stored even if it is null." << finl;
116 exit();
117 }
118 }
119 for (auto k=tab1_(i)-numerotation_fortran; k<tab1_(i+1)-numerotation_fortran; k++)
120 if (tab2_(k)+!numerotation_fortran==0)
121 Cerr<<"Line " <<i<< " no coefficient "<<k<<finl;
122 else
123 {
124 if (coeff_(k)>=0)
125 tab_imp[tab2_(k)-numerotation_fortran]=" ";
126 else
127 tab_imp[tab2_(k)-numerotation_fortran]="";
128 tab_imp[tab2_(k)-numerotation_fortran] += (Nom)coeff_(k);
129 }
130 for(int k=0; k<nb_colonnes(); k++)
131 s<<tab_imp[k];
132 s<<finl;
133 }
134 }
136 }
137 return s;
138}
139
141{
142 return imprimer_image(s,0);
143}
144
146{
147 int numerotation_fortran=(tab1_[0]==1);
148 for (int proc=0; proc<Process::nproc(); proc++)
149 {
150 if (proc==Process::me())
151 {
152 s << "Matrix morse on the processor " << proc << " : " << finl;
153 int n=nb_lignes();
154 Noms tab_imp;
155 tab_imp.dimensionner(nb_colonnes());
156 for(int i=0; i<n; i++)
157 {
158 for (int k=0; k<nb_colonnes(); k++)
159 tab_imp[k]="\u2588\u2588";
160 if (i<10)
161 s <<i << " :" ;
162 else
163 s <<i << ":" ;
164
165 if (symetrie)
166 {
167 for (int j=0; j<i; j++)
168 {
169 for (auto k=tab1_(j)-numerotation_fortran; k<tab1_(j+1)-numerotation_fortran; k++)
170 if (tab2_(k)-numerotation_fortran==i)
171 tab_imp[j] = (std::abs(coeff_(k)) < 1e-20) ? " " : "\u2592\u2592";
172 }
173 int ligne=tab2_(tab1_(i)-numerotation_fortran)-numerotation_fortran;
174 if (i!=ligne)
175 {
176 Cerr << "Problem detected on this Matrice_Morse_Sym." << finl;
177 Cerr << "The diagonal of the line " << ligne << " must be stored even if it is null." << finl;
178 exit();
179 }
180 }
181 for (auto k=tab1_(i)-numerotation_fortran; k<tab1_(i+1)-numerotation_fortran; k++)
182 if (tab2_(k)+!numerotation_fortran==0)
183 Cerr<<"Line " <<i<< " no coefficient "<<k<<finl;
184 else
185 tab_imp[tab2_(k)-numerotation_fortran] = (std::abs(coeff_(k)) < 1e-20) ? " " : "\u2592\u2592";
186
187 for(int k=0; k<nb_colonnes(); k++)
188 s<<tab_imp[k];
189 s<<finl;
190 }
191 }
193 }
194 return s;
195}
196
197void Matrice_Morse::WriteFileMTX(const Nom& name) const
198{
200 {
201 Cerr << "Warning, matrix market format is not available yet in parallel." << finl;
202 return;
203 }
204 Nom filename(Objet_U::nom_du_cas());
205 filename += "_";
206 filename += name;
207 filename += ".mtx";
208 SFichier mtx(filename);
209 mtx.precision(14);
210 mtx.setf(ios::scientific);
211 int rows = nb_lignes();
212 Cerr << "Matrix (" << rows << " lines) written into file: " << filename << " ... " << finl;
213 mtx << "%%MatrixMarket matrix coordinate real " << (sub_type(Matrice_Morse_Sym, *this) ? "symmetric" : "general") << finl;
214 Cerr << "Matrix (" << rows << " lines) written into file: " << filename << finl;
215 mtx << "%%matrix" << finl;
216 mtx << rows << " " << rows << " " << get_tab1()[rows] << finl;
217 for (int row=0; row<rows; row++)
218 for (auto j=get_tab1()[row]; j<get_tab1()[row+1]; j++)
219 mtx << row+1 << " " << get_tab2()[j-1] << " " << get_coeff()[j-1] << finl;
220}
221
222/*! @brief Constructeur par copie d'une Matrice_Morse.
223 *
224 * Copie de chaque membre donne du paramtre.
225 *
226 * @param (Matrice_Morse& acopier) la matrice morse a copier
227 */
229 tab1_(acopier.tab1_),
230 tab2_(acopier.tab2_),
231 coeff_(acopier.coeff_),
232 m_(acopier.m_),
233 symetrique_(0),
234 zero_(0)
235{
238}
239/*! @brief Constructeur d'une matrice Morse carree d'ordre n et pouvant stocker au maximum nnz elements non nuls.
240 *
241 * Egalement constructeur par defaut car les 2 parametres
242 * ont une valeur par defaut.
243 *
244 * @param (int n) l'ordre de la matrice carree a construire
245 * @param (int nnz) le nombre d'elements non nuls que pourra stocker la matrice.
246 */
247template<typename _SIZE_>
250{
251 dimensionner(n,nnz), sorted_ = 0;
252 is_stencil_up_to_date_ = false ;
253}
254
256{
257 dimensionner(0,0);
259 symetrique_ = 0;
260 sorted_ = 0;
261 zero_ = 0;
262 is_stencil_up_to_date_ = false ;
263}
264
265
266/*! @brief Constructeur d'une matrice Morse avec n lignes et m colonnes pouvant stocker au maximum nnz elements non nuls.
267 *
268 * @param (int n) le nombre de ligne de la matrice
269 * @param (int m) le nombre de colonne de la matrice
270 * @param (int nnz) le nombre d'elements non nuls que pourra stocker la matrice.
271 */
272template<typename _SIZE_>
273Matrice_Morse::Matrice_Morse(int n, int m, _SIZE_ nnz):
275{
276 dimensionner(n,m,nnz);
277 is_stencil_up_to_date_ = false, sorted_ = 0 ;
278}
279
280
281Matrice_Morse::Matrice_Morse(int n, int nnz, const IntLists& voisins,
282 const DoubleLists& valeurs,
283 const DoubleVect& terme_diag)
285{
286 dimensionner(n,n,nnz);
287 remplir(voisins, valeurs, terme_diag);
288 is_stencil_up_to_date_ = false, sorted_ = 0;
289}
290
291void Matrice_Morse::set_nb_columns( const int nb_col )
292{
293 m_ = nb_col;
294}
295
296void Matrice_Morse::set_symmetric( const int symmetric )
297{
298 symetrique_ = symmetric ;
299}
300
301/*! @brief Size the matrix with n lines and n columns and nnz zero-values coefficients
302 *
303 */
304template<typename _SIZE_>
305void Matrice_Morse::dimensionner(int n, _SIZE_ nnz)
306{
307 dimensionner(n,n,nnz);
308 return ;
309}
310
311
312/*! @brief Redimensionne la matrice creuse en ajoutant eventuellement des coefficients non nuls
313 *
314 *
315 * Parametre : const IntTab &Ind
316 * Signification : tableau de taille nc * 2
317 * ou nc est le nombre de couples (i,j)
318 * pour les indices des nouveaux coefficients
319 *
320 *
321 */
322void Matrice_Morse::dimensionner(const IntTab& Ind)
323{
324 if (Ind.size()==0) return; // On ne fait rien si la structure est vide
325 int n_ancien = nb_lignes(), m_ancien = nb_colonnes();
326
327 assert(Ind.nb_dim() == 2);
328 assert(Ind.dimension(1) == 2);
329
330 // Calcul du nouveau nombre de lignes
331 // = max (ancien, indices de ligne des nouveaux coeffs)
332 //
333 // et du nouveau nombre de colonnes
334 // = max (ancien, indices de colonne des nouveaux coeffs)
335
336 int nInd = Ind.dimension(0);
337 int n = 0;
338 int m = 0;
339 for (int i=0; i<nInd; i++)
340 {
341 if (n < Ind(i,0)) n = Ind(i,0);
342 if (m < Ind(i,1)) m = Ind(i,1);
343 }
344 n++;
345 m++;
346 if (n < n_ancien) n = n_ancien;
347 if (m < m_ancien) m = m_ancien;
348
349 // Copies des anciens tableaux d'indices
350
351 auto tab1_temp(tab1_);
352
353 // Initialisation au nombre de coefficients deja presents a chaque ligne
354
355 tab1_.resize(n+1);
356 m_ = m;
357
358 for (int i=1; i<=n_ancien; i++)
359 tab1_[i] = tab1_temp[i] - tab1_temp[i-1];
360 for (int i=n_ancien+1; i<=n; i++)
361 tab1_[i] = 0;
362
363 // Parcourt des indices des nouveaux coeffs pour voir s'ils sont
364 // deja presents
365
366 int i_nouveaux = 0;
367 for (int i=0; i<nInd; i++)
368 {
369 int i0 = Ind(i,0);
370 int i1 = Ind(i,1) + 1;
371
372 int test_present = 0;
373
374 if (i0 < n_ancien)
375 {
376 auto kmin = tab1_temp[i0]-1;
377 auto kmax = tab1_temp[i0+1]-1;
378 for (auto k=kmin; k<kmax; k++)
379 if (tab2_[k] == i1)
380 {
381 test_present = 1;
382 break;
383 }
384 }
385 if (!test_present)
386 {
387 i_nouveaux++;
388 tab1_[i0+1] += 1;
389 }
390 }
391 if (i_nouveaux == 0)
392 {
393 tab1_=tab1_temp;
394 return;
395 }
396
397 // Nouveau tableau des positions des premiers coeffs de chaque ligne
398 tab1_[0] = 1;
399 for (int i=1; i<=n; i++)
400 tab1_[i] += tab1_[i-1];
401
402 auto nnz_ancien = tab2_.size_array();
403 auto nnz = nnz_ancien + i_nouveaux;
404
405 auto tab2_temp(tab2_);
406 auto coeff_temp(coeff_);
407 tab2_.resize(nnz);
408 coeff_.resize(nnz);
409
410 // Recopie des anciens coefficients et de leurs indices
411 // de colonne dans les nouveaux tableaux
412
413 tab2_ = -1;
414 for (int i=0; i<n_ancien; i++)
415 {
416 for (auto j1 = tab1_temp[i]-1, j2 = tab1_[i]-1;
417 j1 < tab1_temp[i+1]-1;
418 j1++, j2++)
419 {
420 tab2_[j2] = tab2_temp[j1];
421 coeff_[j2] = coeff_temp[j1];
422 }
423 }
424
425 for (int i=0; i<nInd; i++)
426 {
427 int j0 = Ind(i,0);
428 int j1 = Ind(i,1) + 1;
429 auto k(tab1_(0));
430 for (k=tab1_[j0]-1; tab2_[k] >= 0; k++)
431 if (tab2_[k] == j1)
432 {
433 break;
434 }
435 if (tab2_[k] < 0)
436 {
437 tab2_[k] = j1;
438 coeff_[k] = 0.0;
439 }
440 }
441 // on remet les coeffs dans l'ordre... pas optimal mais pour voir..
442 coeff_=0;
443 //
444 {
445 int nbis=nb_lignes();
446 for(int i=0; i<nbis; i++)
447 {
448 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
449 {
450 for (auto k2=k; k2<tab1_(i+1)-1; k2++)
451 {
452 int j1=tab2_(k);
453 int j2=tab2_(k2);
454 if (j1>j2)
455 {
456 tab2_(k)=j2;
457 tab2_(k2)=j1;
458 }
459 }
460 }
461 }
462 }
464}
465
466/*! @brief Size the matrix with n lines, m columns with nnz zero-values coefficients
467 *
468 */
469template<typename _SIZE_>
470void Matrice_Morse::dimensionner(int n, int m, _SIZE_ nnz)
471{
472 tab2_.resize(nnz);
473 coeff_.resize(nnz);
474 m_=m;
475
476 // on regarde si tab1 a la bonne taille et si tab1[n1]==nnz.
477 if ( tab1_.size_array()!=(n+1) || (tab1_[n]-1)!=nnz )
478 {
479 tab1_.resize(n+1);
480 tab1_=1;
481 }
482 tab1_.resize(n+1);
483 tab1_[n]=nnz+1;
484
486}
487
488/*! @brief Initialisation a la matrice unite (modif MT)
489 *
490 */
492{
493 coeff_ = 0.0;
494 int i,n = ordre();
495 for (i=0; i<n; i++)
496 operator()(i,i) = 1.0;
497}
498
499/*! @brief Renvoie l'ordre de la matrice: - le nombre de lignes si la matrice est carree
500 *
501 * - 0 sinon
502 *
503 * @return (int) l'ordre de la matrice
504 */
506{
507 if(nb_lignes()==nb_colonnes())
508 return nb_lignes();
509 else
510 return 0;
511}
512
513/*! @brief Method to check/clean the Matrice_Morse matrix: -Suppress coefficient defined several times
514 *
515 * -elim_coeff_nul=0, on ne supprime pas les coefficients nuls de la matrice
516 * -elim_coeff_nul=1, on supprime les coefficients nuls de la matrice
517 * -elim_coeff_nul=2, on supprime les coefficients nuls et quasi-nuls de la matrice
518 *
519 */
520void Matrice_Morse::compacte(int elim_coeff_nul)
521{
522 int n=nb_lignes();
523 int coeff_nuls=0;
524 int coeff_quasi_nuls=0;
525 auto tab_elim_coeff(tab2_); // Possibly BigArrOfInt
526 tab_elim_coeff = 0;
527 if (elim_coeff_nul)
528 {
529 ArrOfDouble tab_coeff_max(n);
530 tab_coeff_max = 0.;
531 // Recherche des coefficients nuls hors diagonale a supprimer de la matrice morse
532 {
533 ArrOfInt tab_cnt(1);
534 tab_cnt = 0;
535 auto tab1 = tab1_.view_ro();
536 CDoubleArrView coeff = coeff_.view_ro();
537 DoubleArrView coeff_max = tab_coeff_max.view_rw();
538 auto elim_coeff = tab_elim_coeff.view_rw();
539 IntArrView cnt = tab_cnt.view_rw();
540 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
541 {
542 auto k1 = tab1(i)-1;
543 auto k2 = tab1(i+1)-1;
544 for (auto k = k1; k < k2; k++)
545 {
546 double abs_c = Kokkos::fabs(coeff(k));
547 if (abs_c > coeff_max(i)) coeff_max(i) = abs_c;
548 if (coeff(k) == 0)
549 {
550 Kokkos::atomic_add(&cnt(0), 1);
551 elim_coeff(k) = 1;
552 }
553 }
554 });
555 end_gpu_timer(__KERNEL_NAME__);
556 coeff_nuls = tab_cnt(0);
557 }
558
559 if (elim_coeff_nul==2)
560 {
561 // Recherche des coefficients quasi nuls hors diagonale (1.e-12 plus petit que le coefficient le plus grand de la ligne) a supprimer de la matrice morse
562 const double eps = Objet_U::precision_geom;
563 ArrOfInt tab_cnt(1);
564 tab_cnt = 0;
565 auto tab1 = tab1_.view_ro();
566 CDoubleArrView coeff = coeff_.view_ro();
567 CDoubleArrView coeff_max = tab_coeff_max.view_ro();
568 IntArrView elim_coeff = tab_elim_coeff.view_rw();
569 IntArrView cnt = tab_cnt.view_rw();
570 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
571 {
572 double cm = coeff_max(i);
573 if (!est_egal(cm, 0., eps) && cm < 1e10)
574 {
575 auto k1 = tab1(i) - 1;
576 auto k2 = tab1(i + 1) - 1;
577 for (auto k = k1; k < k2; k++)
578 if (coeff(k) != 0 && est_egal(Kokkos::fabs(coeff(k)) / cm, 0., eps))
579 {
580 Kokkos::atomic_add(&cnt(0), 1);
581 elim_coeff(k) = 1;
582 }
583 }
584 });
585 end_gpu_timer(__KERNEL_NAME__);
586 coeff_quasi_nuls = tab_cnt(0);
587 }
588 }
589 // Recherche des coefficients doublons
590 int nb_doublons=0;
591 {
592 auto tab1 = tab1_.view_ro();
593 CIntArrView tab2 = tab2_.view_ro();
594 CDoubleArrView coeff = coeff_.view_ro();
595 IntArrView elim_coeff = tab_elim_coeff.view_rw();
596 ArrOfInt tab_doublons(1);
597 tab_doublons = 0;
598 ArrOfInt tab_error(1);
599 tab_error = 0;
600 IntArrView doublons = tab_doublons.view_rw();
601 IntArrView error = tab_error.view_rw();
602 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
603 {
604 auto k1 = tab1(i)-1;
605 auto k2 = tab1(i+1)-1;
606 int jmax = -1; // Highest column of a coefficient in the line i
607 for (auto k = k1; k < k2; k++)
608 {
609 int j = tab2(k)-1;
610 if (j > jmax)
611 jmax = j;
612 else
613 {
614 // Found a column j lower than jmax, check if not defined before:
615 for (auto kk = k-1; kk >= k1; kk--)
616 {
617 int jj = tab2(kk)-1;
618 if (jj == j)
619 {
620 // Already defined!
621 Kokkos::atomic_add(&doublons(0), 1);
622 elim_coeff(k) = 1;
623 // Check if same coefficients:
624 if (coeff(kk) != coeff(k))
625 Kokkos::atomic_add(&error(0), 1);
626 break;
627 }
628 }
629 }
630 }
631 });
632 end_gpu_timer(__KERNEL_NAME__);
633 nb_doublons = tab_doublons(0);
634 if (tab_error(0))
635 {
636 Cerr << "Error in a Matrix Morse: duplicate entries with different values!" << finl;
637 exit();
638 }
639 }
640
641 auto nnz(tab1_(0));
642 nnz=0;
643 if (nb_doublons || coeff_nuls || coeff_quasi_nuls)
644 {
645 // Step 1: Count kept entries per row (parallel_for over rows)
646 ArrOfInt tab_kept_per_row(n);
647 {
648 auto tab1 = tab1_.view_ro();
649 CIntArrView elim_coeff = tab_elim_coeff.view_ro();
650 IntArrView kept_per_row = tab_kept_per_row.view_wo();
651 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
652 {
653 int count = 0;
654 auto k1 = tab1(i)-1;
655 auto k2 = tab1(i+1)-1;
656 for (auto k = k1; k < k2; k++)
657 if (!elim_coeff(k)) count++;
658 kept_per_row(i) = count;
659 });
660 end_gpu_timer(__KERNEL_NAME__);
661 }
662
663 // Step 2: Save old tab1_ (needed for source offsets in scatter step)
664 auto old_tab1(tab1_);
665
666 // Step 3: Update tab1_ via prefix scan (updates tab1_(1..n), tab1_(0)=1 unchanged)
667 using tab1_scan_t = decltype(nnz);
668 {
669 auto tab1 = tab1_.view_rw();
670 CIntArrView kept_per_row = tab_kept_per_row.view_ro();
671 Kokkos::parallel_scan(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i, tab1_scan_t& update, const bool final)
672 {
673 update += kept_per_row(i);
674 if (final) tab1(i+1) = update + 1;
675 });
676 end_gpu_timer(__KERNEL_NAME__);
677 }
678
679 // Step 4: Out-of-place scatter of coeff_ and tab2_ to new positions (parallel_for over rows)
680 // Safe because new_pos(i) <= old_pos(i) always, and rows are processed independently
681 nnz = tab1_[n] - 1;
682 auto new_coeff(coeff_);
683 auto new_tab2(tab2_);
684 {
685 auto tab1 = tab1_.view_ro();
686 auto old_tab1_ro = old_tab1.view_ro();
687 CDoubleArrView coeff_src = coeff_.view_ro();
688 CIntArrView tab2_src = tab2_.view_ro();
689 DoubleArrView coeff_dst = new_coeff.view_wo();
690 IntArrView tab2_dst = new_tab2.view_wo();
691 CIntArrView elim_coeff = tab_elim_coeff.view_ro();
692 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
693 {
694 auto new_pos = tab1(i) - 1;
695 auto k1 = old_tab1_ro(i)-1;
696 auto k2 = old_tab1_ro(i+1)-1;
697 for (auto k = k1; k < k2; k++)
698 if (!elim_coeff(k))
699 {
700 coeff_dst(new_pos) = coeff_src(k);
701 tab2_dst(new_pos) = tab2_src(k);
702 new_pos++;
703 }
704 });
705 end_gpu_timer(__KERNEL_NAME__);
706 }
707
708 // Step 5: Copy compacted data back
709 {
710 auto tab2 = tab2_.view_rw();
711 auto coeff = coeff_.view_rw();
712 CIntArrView new_tab2_ro = new_tab2.view_ro();
713 CDoubleArrView new_coeff_ro = new_coeff.view_ro();
714 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, nnz), KOKKOS_LAMBDA(const int i)
715 {
716 tab2(i) = new_tab2_ro(i);
717 coeff(i) = new_coeff_ro(i);
718 });
719 end_gpu_timer(__KERNEL_NAME__);
720 }
721 }
722 else
723 {
724 nnz = tab1_[n] - 1;
725 }
726
727 // On redimensionne les tableaux
728 tab2_.resize(nnz);
729 coeff_.resize(nnz);
730
733}
734
735/*! @brief Operateur d'affectation d'une Matrice_Morse dans une autre Matrice_Morse.
736 *
737 * @param (Matrice_Morse& a) la partie droite de l'affectation
738 */
749
750/*! @brief *this = a transposee.
751 *
752 * @param (Matrice_Morse& a) la matrice a transposee
753 */
755{
756 int n=a.nb_lignes();
757 int jk=nb_lignes();
758 int job=1;
759 int ipos=1;
760 int m=a.nb_colonnes();
761 int l=nb_lignes();
762 if(m!=jk)
763 {
764 Cerr << "Matrice_Morse::transpose bad dimensions" << finl;
765 exit();
766 }
767 m=a.nb_lignes();
768 l=nb_colonnes();
769 if(m!=l)
770 {
771 Cerr << "Matrice_Morse::transpose bad dimensions" << finl;
772 exit();
773 }
774
775 for(int i=0; i<=jk; i++ ) tab1_[i] = 0 ;
776 for(int i=0; i<n; i++)
777 {
778 for(auto k=a.tab1_[i]-1; k<a.tab1_[i+1]-1; k++)
779 {
780 int j = a.tab2_[k] ;
781 tab1_[j] = tab1_[j] +1 ;
782 }
783 }
784 tab1_[0] = ipos ;
785 for(int i=0; i<jk; i++) tab1_[i+1] = tab1_[i] + tab1_[i+1] ;
786 for(int i=0; i<n; i++)
787 {
788 for(auto k=a.tab1_[i]-1; k<a.tab1_[i+1]-1; k++)
789 {
790 int j = a.tab2_[k]-1 ;
791 auto next = tab1_[j] ;
792 if (job == 1) coeff_[next-1] = a.coeff_[k] ;
793 tab2_[next-1] = i+1 ;
794 tab1_[j] = next+1 ;
795 }
796 }
797 for(int i=jk-1; i>=0; i--) tab1_[i+1] = tab1_[i] ;
798 tab1_[0] = ipos ;
799
801 return(*this);
802}
803
804
805//A=x*A avec x une matrice diagonale stockee dans un vecteur
806//la meme methode peut etre utilisee pour stocke le resultat dans
807//un autre matrice que la matrice initiale
809{
810 int m=nb_lignes();
811 int l=0;
812 int n=x.size_array();
813 if(n!=m)
814 {
815 Cerr << "Matrice_Morse::diagmulmat bad dimensions" << finl;
816 exit();
817 }
818 F77NAME(DIAMUA)(&m ,&l,
819 coeff_.addr(),tab2_.addr(),reinterpret_cast<const int*>(tab1_.addr()),x.addr(),
820 coeff_.addr(),tab2_.addr(),reinterpret_cast<int*>(tab1_.addr()));
821 return(*this);
822}
823
824//extraction de la partie superieure d'une matrice morse
825//la matrice resultat est celle appelante
827{
828 int m=nb_lignes();
829 int n=a.nb_lignes();
830 if(m!=n)
831 {
832 Cerr << "Matrice_Morse::partie_sup : bad dimensions m!=n." << finl;
833 exit();
834 }
835 double t;
836 auto ko(tab1_(0));
837 auto kfirst (ko);
838 auto kdiag(ko);
839 ko = -1;
840 for(int i=0; i< n; i++)
841 {
842 kfirst = ko + 1 ;
843 kdiag = -1 ;
844 for(auto k = a.tab1_[i]-1; k< a.tab1_[i+1]-1; k++)
845 {
846 if (a.tab2_[k]-1 >= i)
847 {
848 ko++ ;
849 coeff_[ko] = a.coeff_[k] ;
850 tab2_[ko] = a.tab2_[k] ;
851 if (a.tab2_[k] == i) kdiag = ko ;
852 }
853 }
854 if (kdiag != -1 && kdiag != kfirst)
855 {
856 t = coeff_[kdiag] ;
857 coeff_[kdiag] = coeff_[kfirst] ;
858 coeff_[kfirst] = t ;
859 { int ktmp = tab2_[kdiag] ; tab2_[kdiag] = tab2_[kfirst] ; tab2_[kfirst] = ktmp ; }
860 }
861 tab1_[i] = kfirst+1 ;
862 }
863 auto nnz = (ko + 1) ;
864
865 tab1_[n] = (nnz) + 1 ;
866 tab2_.resize( nnz );
867 coeff_.resize( nnz );
869 return(*this);
870}
871
872/*! @brief Operation de multiplication-accumulation (saxpy) matrice vecteur.
873 *
874 * Operation: resu = resu + A*x
875 *
876 */
877DoubleVect& Matrice_Morse::ajouter_multvect_(const DoubleVect& tab_x,DoubleVect& tab_resu) const
878{
880 const int n = tab1_.size_array() - 1;
881 assert(tab_x.size_array() == nb_colonnes());
882 // Test dans cet ordre car l'attribut size() peut etre invalide:
883 assert(tab_resu.size_array() == n || tab_resu.size() == n);
884 // If matrix, x, resu are on device, we compute on the device to avoid expensive copy during TRUST GCP:
885 if (tab_x.isDataOnDevice() && tab_resu.isDataOnDevice() && coeff_.isDataOnDevice())
886 {
887 //if (tab_x.line_size()>1) Process::exit("line_size>1 pour x dans Matrice_Morse::ajouter_multvect_");
888 // Faster implementation on GPU (ToDo Kokkos: future, use Kokkos kernel?)
889 auto tab1 = tab1_.view_ro();
890 CIntArrView tab2 = tab2_.view_ro();
891 CDoubleArrView coeff = coeff_.view_ro();
892 CDoubleArrView x = tab_x.view_ro();
893 DoubleArrView resu = tab_resu.view_rw();
894 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
895 Kokkos::RangePolicy<>(0, n), KOKKOS_LAMBDA(
896 const int i)
897 {
898 auto start = tab1(i)-1;
899 auto end = tab1(i + 1)-1;
900 double tmp {};
901
902 for (auto k = start; k < end; k++)
903 {
904 int j = tab2(k) - 1;
905 tmp+= coeff(k) * x(j);
906 }
907 resu(i) += tmp;
908 });
909 end_gpu_timer(__KERNEL_NAME__);
910 }
911 else
912 {
913 tab_x.ensureDataOnHost();
914 tab_resu.ensureDataOnHost();
915 coeff_.ensureDataOnHost();
916 // Fast CPU (old) implementation with pointer:
917 const DoubleVect& x = tab_x;
918 DoubleVect& resu = tab_resu;
919 const auto *tab1_ptr = tab1_.addr() + 1;
920 const int *tab2_ptr = tab2_.addr();
921 const double *coeff_ptr = coeff_.addr();
922 const double *x_fortran = x.addr() - 1; // Pour indexer x avec un indice fortran
923 auto k_fortran = 1; // indice fortran dans tab2 et coeff
924 for (int i = 0; i < n; i++, tab1_ptr++)
925 {
926 const auto kmax = *tab1_ptr; // tab1_[i+1] = indice fortran dans tab2_
927 assert(kmax >= k_fortran && kmax <= tab2_.size_array() + 1);
928 double t = resu[i];
929 assert(k_fortran == tab1_[i] && tab2_ptr == tab2_.addr() + (k_fortran - 1));
930 for (; k_fortran < kmax; k_fortran++, tab2_ptr++, coeff_ptr++)
931 {
932 int colonne = *tab2_ptr; // indice fortran
933 assert(colonne >= 1 && colonne <= nb_colonnes());
934 t += (*coeff_ptr) * x_fortran[colonne];
935 }
936 resu[i] = t;
937 }
938 }
939 return tab_resu;
940}
941
942// Multiplication de la matrice par un vecteur x en prenant uniquement les items reels non communs pour x
943ArrOfDouble& Matrice_Morse::ajouter_multvect_(const ArrOfDouble& x,ArrOfDouble& resu,ArrOfInt& est_reel_pas_com) const
944{
945 ToDo_Kokkos("critical ?");
947 int n = nb_lignes();
948
949 assert(nb_colonnes()==x.size_array());
950 assert(n==resu.size_array());
951 for(int i=0; i<n; i++)
952 {
953 double t = 0.0;
954 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
955 {
956 int j=tab2_(k)-1;
957 if (est_reel_pas_com[j]) t += coeff_(k)*x[j];
958 }
959 resu[i] += t ;
960 }
961 return resu;
962}
963
964/*! @brief Operation de multiplication-accumulation (saxpy) matrice matrice (matrice X representee par un tableau)
965 *
966 * Operation: RESU = RESU + A*X
967 *
968 * @param (DoubleTab& x) la matrice a multiplier
969 * @param (DoubleTab& resu) la matrice resultat de l'operation
970 * @return (DoubleTab&) la matrice resultat de l'operation
971 */
972DoubleTab& Matrice_Morse::ajouter_multTab_(const DoubleTab& x,DoubleTab& resu) const
973{
974
975 if ( (x.nb_dim() == 1) && (resu.nb_dim() == 1))
976 {
977 ajouter_multvect(x,resu);
978 return resu;
979 }
980
982 int nb_comp = x.dimension(1);
983
984 assert(resu.dimension(1) == nb_comp);
985 double* t= new double[nb_comp];
986 int ncomp;
987 int n=nb_lignes();
988 for(int i=0; i<n; i++)
989 {
990 for (ncomp=0; ncomp<nb_comp; ncomp++)
991 t[ncomp] = 0.0;
992 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
993 for (ncomp=0; ncomp<nb_comp; ncomp++)
994 t[ncomp] += coeff_(k)*x(tab2_(k)-1,ncomp);
995 for (ncomp=0; ncomp<nb_comp; ncomp++)
996 resu(i,ncomp) += t[ncomp] ;
997 }
998 delete [] t;
999 return resu;
1000}
1001
1002
1003/*! @brief Operation de multiplication-accumulation (saxpy) matrice vecteur, par la matrice transposee.
1004 *
1005 * Operation: resu = resu + A^{T}*x
1006 *
1007 * @param (DoubleVect& x) le vecteur a multiplier
1008 * @param (DoubleVect& resu) le vecteur resultat de l'operation
1009 * @return (DoubleVect&) le vecteur resultat de l'operation
1010 */
1011DoubleVect& Matrice_Morse::ajouter_multvectT_(const DoubleVect& x,DoubleVect& resu) const
1012{
1014
1015 int n=nb_lignes();
1016 for(int i=0; i<n; i++)
1017 {
1018 double xi = x(i);
1019 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
1020 resu(tab2_(k)-1) += coeff_(k) * xi;
1021 }
1022 return resu;
1023}
1024
1025// Multiplication de la tranposee de la matrice par un vecteur x en prenant uniquement les items reels non communs
1026ArrOfDouble& Matrice_Morse::ajouter_multvectT_(const ArrOfDouble& x,ArrOfDouble& resu,ArrOfInt& est_reel_pas_com) const
1027{
1029 int n=nb_lignes();
1030
1031 assert(n==x.size_array());
1032 assert(nb_colonnes()==resu.size_array());
1033 for(int i=0; i<n; i++)
1034 {
1035 if (est_reel_pas_com[i])
1036 {
1037 double xi = x[i];
1038 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
1039 resu[tab2_(k)-1] += coeff_(k) * xi;
1040 }
1041 }
1042 return resu;
1043}
1044
1045/*! @brief Fonction (hors classe) amie de la classe Matrice_Morse Addition de 2 matrices au format Morse.
1046 *
1047 * Operation: renvoie (A+B)
1048 *
1049 * @param (Matrice_Morse& A) une matrice au format Morse
1050 * @param (Matrice_Morse& B) une matrice au format Morse
1051 * @return (Matrice_Morse) le resultat de l'operation
1052 */
1054{
1055 int nrow=A.nb_lignes();
1056 int ncol=A.nb_colonnes();
1057 Matrice_Morse C;
1058 // PL: avant de dimensionner a nzmax on verifie si A et B n'ont pas la meme structure par hasard...
1059 // Cela evite un pic memoire provoque par l'addition de matrices dans Equation_base::dimensionner_matrice
1060 auto nzmax = A.has_same_morse_matrix_structure(B) ? A.nb_coeff() : A.nb_coeff() + B.nb_coeff();
1061 C.dimensionner(nrow, ncol, nzmax);
1062#ifndef TRUST_USE_GPU
1063 // Fortran call cause faster on serail version on some Baltik:
1064 int job = 1;
1065 int ierr = -1;
1066 IntVect iw(ncol);
1067 F77NAME(APLB)(&nrow, &ncol, &job, A.get_coeff().addr(), A.get_tab2().addr(), A.get_tab1().addr(),
1068 B.get_coeff().addr(), B.get_tab2().addr(), B.get_tab1().addr(), C.get_set_coeff().addr(),
1069 C.get_set_tab2().addr(), C.get_set_tab1().addr(),
1070 &nzmax, iw.addr(), &ierr);
1071#else
1072 // Algorithm (per row i):
1073 // 1. Collect entries from row i of A and B into a small temporary buffer
1074 // 2. Sort by column index
1075 // 3. Merge duplicate columns (accumulate coefficients)
1076 // 4. Write result into C and advance c_tab1
1077 //
1078 // Time: O((nnz_A + nnz_B) * log(max_nnz_per_row)) [sort dominates]
1079 // Space: O(max_nnz_per_row_A + max_nnz_per_row_B) [reused buffer]
1080 //
1081 // ToDo: Kokkos parallel version for GPU once CPU version is validated
1082 const auto& a_tab1 = A.get_tab1();
1083 const auto& a_tab2 = A.get_tab2();
1084 const auto& a_coeff = A.get_coeff();
1085 const auto& b_tab1 = B.get_tab1();
1086 const auto& b_tab2 = B.get_tab2();
1087 const auto& b_coeff = B.get_coeff();
1088 auto& c_tab1 = C.get_set_tab1();
1089 auto& c_tab2 = C.get_set_tab2();
1090 auto& c_coeff = C.get_set_coeff();
1091
1092 using idx_t = std::remove_reference_t<decltype(c_tab1[0])>;
1093 idx_t nnz_c = 0; // running count of non-zeros written into C (0-based offset)
1094 c_tab1[0] = 1; // 1-based (Morse/Fortran convention)
1095
1096 std::unordered_map<int, idx_t> col_to_pos;
1097 col_to_pos.reserve(256);
1098 for (int i = 0; i < nrow; ++i)
1099 {
1100 col_to_pos.clear();
1101
1102 // Step 1: copy A row i into C, recording each column's position
1103 for (auto k = a_tab1[i] - 1; k < a_tab1[i + 1] - 1; ++k)
1104 {
1105 c_tab2[nnz_c] = (int) a_tab2[k];
1106 c_coeff[nnz_c] = a_coeff[k];
1107 col_to_pos[(int) a_tab2[k]] = nnz_c;
1108 ++nnz_c;
1109 }
1110
1111 // Step 2: merge B row i — accumulate if column already in C, else append
1112 for (auto k = b_tab1[i] - 1; k < b_tab1[i + 1] - 1; ++k)
1113 {
1114 const int col = (int) b_tab2[k];
1115 auto it = col_to_pos.find(col);
1116 if (it != col_to_pos.end())
1117 c_coeff[it->second] += b_coeff[k]; // column shared with A: accumulate
1118 else
1119 {
1120 c_tab2[nnz_c] = col;
1121 c_coeff[nnz_c] = b_coeff[k];
1122 col_to_pos[col] = nnz_c;
1123 ++nnz_c;
1124 }
1125 }
1126
1127 c_tab1[i + 1] = nnz_c + 1; // 1-based pointer to start of next row
1128 }
1129#endif
1130 const auto nnz = C.tab1_[nrow] - 1;
1131 C.get_set_tab2().resize(nnz);
1132 C.get_set_coeff().resize(nnz);
1134 return(C);
1135}
1136
1138{
1139 int nrow = A.nb_lignes();
1140 for (int i = 0; i < nrow; i++)
1141 if (tab1_(i) != A.tab1_(i))
1142 return false;
1143 auto ncoeff = tab2_.size_array(), ncoeff_A = A.tab2_.size_array();
1144 if (ncoeff != ncoeff_A) return false;
1145
1146 for (auto i = 0; i < ncoeff; i++)
1147 if (tab2_(i) != A.tab2_(i))
1148 return false;
1149 return true;
1150}
1151
1152/*! @brief Calcule la solution du systeme lineaire: A * solution = secmem.
1153 *
1154 * La methode utilisee est GMRES preconditionnee avec ILUT.
1155 * ATTENTION: cette methode n'a vraisemblablement jamais ete testee en parallele
1156 *
1157 * @param (DoubleVect& secmem) le second membre du systeme lineaire
1158 * @param (DoubleVect& solution) la solution du systeme
1159 * @param (double coeff_seuil)
1160 * @return (int) renvoie toujours 1
1161 * @throws Erreur dans ilut 'matrix may be wrong' dixit SAAD
1162 * @throws Erreur dans ilut : debordement dans L
1163 * @throws Erreur dans ilut : debordement dans U
1164 * @throws Valeur illegale de lfil : sans doute ecrasement memoire
1165 * @throws Ligne vide rencontree
1166 * @throws Pivot nul rencontre ! au pas
1167 * @throws Il s'est passe quelque chose de bizarre : je prefere tout arreter.
1168 */
1169// Delegates to the 4-arg version with max_iter=-1 (retry-on-failure mode, maxits=ordre())
1170int Matrice_Morse::inverse(const DoubleVect& secmem, DoubleVect& solution,
1171 double coeff_seuil) const
1172{
1173 return inverse(secmem, solution, coeff_seuil, -1);
1174}
1175
1176// Solves A*solution=secmem using ILUT-preconditioned PGMRES.
1177// max_iter<0: use ordre() as iteration limit and retry with stronger preconditioner on failure (returns 1).
1178// max_iter>=0: use max_iter as iteration limit and return 0 on failure (used by hyperbolic implicit).
1179int Matrice_Morse::inverse(const DoubleVect& secmem, DoubleVect& solution,
1180 double coeff_seuil, int max_iter) const
1181{
1183 {
1184 Cerr << "Matrice_Morse::inverse has never been tested in parallel" << finl;
1185 Cerr << "Try 'Solveur Gmres { diag }' or 'Solveur Petsc Gmres { precond diag { } }'" << finl;
1186 Cerr << "instead of 'Solveur Gmres { }' which is not parallelized yet." << finl;
1187 exit();
1188 }
1189
1190 const bool retry_on_failure = (max_iter < 0);
1191
1192 DoubleVect toto(secmem);
1193 int prems=1; // recompute L and U only when prems=1
1194 int lf_min = 10;
1195 int lf = std::min(lf_min, ordre()/2); // fill level for ILUT
1196 int nn = ordre();
1197 int ima = std::min(lf_min, ordre()/2); // Krylov space dimension
1198 IntVect ju, jlu;
1199 DoubleVect alu, vv;
1200 DoubleVect Resini(toto);
1201
1202 int ie=1;
1203 auto n2 = nb_coeff()+(2*lf*nn); // number of non-zeros in LU
1204
1205 double r, coeff_seuilr;
1206
1207precond:
1208 if (prems)
1209 {
1210 int iw = (int)(n2 + 2);
1211 ju.resize(nn);
1212 jlu.resize(iw);
1213 alu.resize(iw);
1214 double to = 1.e-10; // drop tolerance for ILUT
1215 DoubleVect w(nn+1);
1216 IntVect jw(2*nn);
1218 F77NAME(ILUT)(&nn, coeff_.addr(), tab2_.addr(), get_tab1_int32().addr(), &lf,
1219 &to, alu.addr(), jlu.addr(), ju.addr(),
1220 &iw, w.addr(), jw.addr(), &ie);
1221 switch(ie)
1222 {
1223 case 0:
1224 break;
1225 case -1:
1226 Cerr << "Error in ilut 'matrix may be wrong' dixit SAAD" << finl;
1227 exit();
1228 break;
1229 case -2:
1230 Cerr << "Error in ilut : overflow in L" << finl;
1231 exit();
1232 break;
1233 case -3:
1234 Cerr << "Error in ilut : overflow in U" << finl;
1235 exit();
1236 break;
1237 case -4:
1238 Cerr << "Illegal value for lfil : it may be a memory trouble" << finl;
1239 exit();
1240 break;
1241 case -5:
1242 Cerr << "Empty line met" << finl;
1243 exit();
1244 break;
1245 default:
1246 Cerr << "Pivot null met ! at step " << ie << finl;
1247 exit();
1248 break;
1249 }
1250 prems=0;
1251 }
1252
1253 vv.resize(nn*(ima+1));
1254 assert_espace_virtuel_vect(solution);
1255 multvect(solution, Resini);
1256 Resini -= toto;
1257 r = mp_prodscal(Resini, Resini);
1258 r = sqrt(r);
1259 Cout << " Initial residu : " << r << finl;
1260 coeff_seuilr = (r == 0) ? DMAXFLOAT : coeff_seuil/r;
1261 Resini = toto;
1262 int minits = 10;
1263 int maxits = std::max(minits, retry_on_failure ? nn : max_iter);
1264 int io = 0;
1265 F77NAME(PGMRES)(&nn, &ima, toto.addr(), solution.addr(), vv.addr(), &coeff_seuilr,
1266 &maxits, &io, coeff_.addr(), tab2_.addr(), get_tab1_int32().addr(),
1267 alu.addr(), jlu.addr(), ju.addr(), &ie);
1268 switch(ie)
1269 {
1270 case 0:
1271 Cout << " ** PGMRES has converged **" << finl;
1272 break;
1273 case 1:
1274 Cout << " ** No convergence after " << maxits << " iterations **" << finl;
1275 if (retry_on_failure)
1276 {
1277 toto = Resini;
1278 if (lf < 50)
1279 {
1280 lf += 5;
1281 Cerr << " The degree of the preconditioning matrix LU is increased: " << lf << finl;
1282 n2 = (int)tab2_.size_array()+(2*lf*nn);
1283 prems = 1;
1284 goto precond;
1285 }
1286 }
1287 else
1288 return 0;
1289 break;
1290 case -1:
1291 Cerr << "Convergence after 0 iterations !! 'stationnary state may be obtained'" << finl;
1292 break;
1293 default:
1294 Cerr << "Something abnormal has happened : it is preferable to stop." << finl;
1295 exit();
1296 }
1297 return 1;
1298}
1299
1300
1301/*! @brief Operateur de multiplication d'une matrice par un vecteur: scaling des lignes de la matrice par les coefficients
1302 *
1303 * correspondants du vecteur passe en parametre.
1304 * A *= x, effectue les scaling suivants:
1305 * A(i,:) = A(i,:) * x(i), pour toutes les lignes i de A
1306 *
1307 * @param (DoubleVect& x) vecteur de scaling
1308 * @return (Matrice_Morse&) le resultat de l'operation (*this)
1309 */
1311{
1312 for(int i = 0; i<nb_lignes(); i++)
1313 for(auto k = tab1_(i)-1; k<tab1_(i+1)-1; k++)
1314 coeff_(k) *= x(i);
1315 return *this;
1316}
1317
1318
1319/*! @brief Affecte le produit de 2 matrices Morse A et B a l'objet (this).
1320 *
1321 * Operation: this = A * B
1322 *
1323 * @param (Matrice_Morse& A) une matrice au format Morse
1324 * @param (Matrice_Morse& B) une matrice au format Morse
1325 * @return (Matrice_Morse&) le resultat de l'operation (*this)
1326 */
1328{
1329 int nrow= a.nb_lignes(); // nb de lignes de A
1330 int ncol= b.nb_colonnes(); // nb de colonnes de B
1331 //assert(nrow==ncol);
1332 // Jloi non?
1333 assert(a.nb_colonnes()==b.nb_lignes());
1334 tab1_.resize(nrow+1);
1335 m_ = ncol;
1336 int job = 1 ; // on recupere tout (tab1, tab2, coeff de matrice_resu)
1337 auto nzmax = nb_coeff(); // nb de valeurs maximales de la matrice resultante
1338 if(nzmax==0)
1339 {
1340 nzmax=a.nb_coeff();
1341 tab2_.resize(nzmax);
1342 coeff_.resize(nzmax);
1343 assert(nzmax==nb_coeff());
1344 }
1345 IntVect iw(ncol+1); // tableau de travail
1346 double scal=0. ;
1347 int ii, jj ;
1348 int values = 0;
1349 if (job != 0) values = 1 ;
1350 auto len = -1 ;
1351 tab1_[0] = 1 ;
1352 iw = -1 ;
1353 for(ii=0; ii< nrow; ii++)
1354 {
1355 for(auto ka=a.tab1_[ii]-1; ka < a.tab1_[ii+1]-1; ka++)
1356 {
1357 if (values == 1) scal = a.coeff_[ka] ;
1358 jj = a.tab2_[ka] - 1 ;
1359 for (auto kb=b.tab1_[jj]-1; kb < b.tab1_[jj+1]-1; kb++)
1360 {
1361 int jcol = b.tab2_[kb] -1 ;
1362 int jpos = iw[jcol] ;
1363 if (jpos == -1)
1364 {
1365 len++ ;
1366 if (len > nzmax-1)
1367 {
1368 // Cerr << "Matrice_Morse::affect_prod len > nzmax -1 " << nzmax << finl;
1369 nzmax *= 2;
1370 coeff_.resize(nzmax);
1371 tab2_.resize(nzmax);
1372 }
1373 tab2_[len] = jcol + 1 ;
1374 iw[jcol]= (int)len ;
1375 if (values == 1) coeff_[len] = scal*b.coeff_[kb] ;
1376 }
1377 else
1378 {
1379 if (values == 1) coeff_[jpos] += scal*b.coeff_[kb] ;
1380 }
1381 }
1382 }
1383
1384 for (auto k=tab1_[ii]-1; k < len+1 ; k++) iw[tab2_[k]-1] = -1 ;
1385 tab1_[ii+1] = (len+1) + 1 ;
1386 }
1387
1388 coeff_.resize(tab1_[nrow]-1);
1389 tab2_.resize(tab1_[nrow]-1);
1391 return *this;
1392}
1393
1394
1395
1396/*! @brief Fonction (hors classe) amie de la classe Matrice_Morse Scaling de la matrice par un scalaire: multiplie tous
1397 *
1398 * les elements de la matrice par un scalaire.
1399 * Operation: renvoie x*A
1400 *
1401 * @param (double x) valeur du scaling
1402 * @param (Matrice_Morse& B) une matrice au format Morse
1403 * @return (Matrice_Morse) le resultat de l'operation
1404 */
1405Matrice_Morse operator *(double x , const Matrice_Morse& A)
1406{
1407 Matrice_Morse mat_res(A);
1408 mat_res.coeff_*=x;
1409 return(mat_res);
1410}
1411
1412/*! @brief Operateur de negation unaire, renvoie l'opposee de la matrice: - A Appelle operator*(double,const Matrice_Morse&)
1413 *
1414 * @return (Matrice_Morse) le resultat de l'appel a operator*(double,const Matrice_Morse&)
1415 */
1417{
1418 return((-1)*(*this));
1419}
1420
1421
1422/*! @brief NE FAIT RIEN
1423 *
1424 * @param (Matrice_Morse&) une matrice morse
1425 * @return (Matrice_Morse&) renvoie toujours *this
1426 */
1428{
1429 // PL: Avant de verifier de faire des operations couteuses en RAM, on verifie
1430 // si ce n'est pas la meme structure:
1432 {
1433 auto size = A.nb_coeff();
1434 const auto& coeff = A.get_coeff();
1435 for (auto i=0; i<size; i++)
1436 coeff_(i)+=coeff(i);
1437 }
1438 else
1439 {
1440 *this = *this + A;
1442 }
1443 return *this;
1444}
1445
1446
1447/*! @brief Operateur de multiplication (de tous les elements) d'une matrice par un scalaire.
1448 *
1449 * Operation: A = x * A
1450 *
1451 * @param (double x) le parametre de scaling
1452 * @return (Matrice_Morse&) le resultat de l'operation (*this)
1453 */
1455{
1456 scale( x );
1457 return(*this);
1458}
1459
1460void Matrice_Morse::scale( const double x )
1461{
1462 coeff_ *= x;
1463}
1464
1465void Matrice_Morse::get_stencil( Stencil& stencil ) const
1466{
1468
1470 {
1471 stencil = stencil_;
1472 return;
1473 }
1474
1475
1476 stencil.resize( 0, 2 );
1477 auto nnz = tab2_.size_array();
1478 stencil.resize(nnz, 2);
1479
1480
1481 ArrOfInt tmp;
1482
1483
1484 decltype(nnz) compteur = 0;
1485
1486 const int nb_lines = nb_lignes( );
1487 for ( int i=0; i<nb_lines; ++i )
1488 {
1489 auto k0 = tab1_( i ) - 1;
1490 auto k1 = tab1_( i + 1 ) - 1;
1491 const auto size = k1 - k0;
1492 const int size_int = (int)size;
1493
1494 tmp.resize_array( 0 );
1495 tmp.resize_array( size_int );
1496
1497 for ( int k=0; k<size_int; ++k )
1498 {
1499 tmp[ k ] = tab2_( k + k0 ) - 1;
1500 }
1501
1502 tmp.ordonne_array( );
1503
1504 for ( int k=0; k<size_int; ++k )
1505 {
1506 stencil( k+compteur , 0 ) = i;
1507 stencil( k+compteur , 1 ) = tmp[ k ];
1508 }
1509 compteur += size;
1510 }
1511
1512
1513}
1514
1515// Local template method : copy either value or ptr to value!
1516namespace
1517{
1518template<typename _T_> static inline void _fill_slot(_T_& dest, const double& src);
1519template<> inline void _fill_slot<double>(double& dest, const double& src)
1520{
1521 dest = src;
1522}
1523template<> inline void _fill_slot<const double *>(const double*& dest, const double& src)
1524{
1525 dest = &src;
1526}
1527}
1528
1529
1530template<typename _TAB_T_, typename _VALUE_T_>
1531inline void Matrice_Morse::get_stencil_coeff_templ( Stencil& stencil, _TAB_T_& coeffs_span) const
1532{
1533 auto nnz = tab2_.size_array();
1534 coeffs_span.resize(nnz);
1535 stencil.resize(nnz, 2);
1536 decltype(nnz) compteur = 0;
1537 const int nb_lines = nb_lignes( );
1538 for ( int i=0; i<nb_lines; ++i )
1539 {
1540 const auto k0 = tab1_( i ) - 1;
1541 const auto k1 = tab1_( i + 1 ) - 1;
1542 const int size_int = (int)(k1 - k0);
1543 for ( int k=0; k<size_int; ++k )
1544 {
1545 stencil( compteur + k , 0 ) = i;
1546 stencil( compteur + k , 1 ) = tab2_( k + k0 ) - 1;
1547 ::_fill_slot<_VALUE_T_>(coeffs_span[ compteur + k ], coeff_(k+k0));
1548 }
1549 compteur += size_int;
1550 }
1551
1552
1553}
1554
1555
1557 std::vector<const double *>& coeff_ptr) const
1558{
1560
1562 {
1563 Cerr << "Error in Matrice_Morse::get_symmetric_stencil_and_coeff_ptrs( )"<<finl;
1564 Cerr << " stencil up to date - function not impl. in this case."<<finl;
1565 Cerr << " Aborting..." << finl;
1566 Process::abort( );
1567 return;
1568 }
1569
1570 get_stencil_coeff_templ< std::vector<const double *>, const double *>(stencil, coeff_ptr);
1571 assert( (trustIdType)coeff_ptr.size( ) == stencil.dimension( 0 ));
1572}
1573
1574
1576 StencilCoeffs& coefficients ) const
1577{
1579 {
1580 if( coeff_.size( ) == 0 )
1581 {
1582 Cerr << "Error in Matrice_Morse::get_stencil_and_coefficients( )"<<finl;
1583 Cerr << " The coefficients are not filled."<<finl;
1584 Cerr << " Aborting..." << finl;
1585 Process::abort( );
1586 }
1587 stencil = stencil_ ;
1588 { const auto sz = coeff_.size_array(); coefficients.resize(sz); for (auto k=sz-sz; k<sz; k++) coefficients[k] = coeff_[k]; }
1589 return;
1590 }
1591
1592
1593
1595 assert( coefficients.size_array( ) == stencil.dimension( 0 ));
1596}
1597
1598
1599/*! @brief Operateur de division (de tous les elements) d'une matrice par un scalaire.
1600 *
1601 * Operation: A = A / x
1602 *
1603 * @param (double x) le parametre de scaling
1604 * @return (Matrice_Morse&) le resultat de l'operation (*this)
1605 * @throws division par zero impossible
1606 */
1608{
1609 coeff_/=x;
1610 return(*this);
1611}
1612
1613void Matrice_Morse::remplir(const IntLists& voisins,
1614 const DoubleLists& valeurs,
1615 const DoubleVect& terme_diag)
1616{
1617
1618 int num_elem;
1619 int compteur,rang =0;
1620
1621 // Remplissage des tableaux tab1, tab2 et coeff_ :
1622 auto* p_tab1 = tab1_.addr();
1623 int* p_tab2 = tab2_.addr();
1624 double* p_coeff = coeff_.addr();
1625
1626 int* tab2_ptr = p_tab2;
1627 int n=nb_lignes();
1628
1629 for (num_elem=0; num_elem<n; num_elem++)
1630 {
1631
1632 IntList_Curseur liste_vois(voisins[num_elem]);
1633 DoubleList_Curseur liste_val(valeurs[num_elem]);
1634 compteur =0;
1635 *p_tab1++ = rang;
1636
1637 *tab2_ptr++=num_elem;
1638 *p_coeff++ = terme_diag[num_elem];
1639
1640 while (liste_vois)
1641 {
1642 *tab2_ptr++ = liste_vois.valeur();
1643 *p_coeff++ = liste_val.valeur();
1644 ++liste_vois;
1645 ++liste_val;
1646 compteur++;
1647 }
1648 // tab2[rang] = compteur;
1649 rang += (compteur + 1);
1650 }
1651 tab1_(num_elem)=rang;
1652 formeF();
1655}
1656
1657void Matrice_Morse::remplir(const IntLists& voisins,
1658 const DoubleLists& valeurs)
1659{
1660
1661 int num_elem;
1662 int compteur,rang =0;
1663
1664 // Remplissage des tableaux tab1, tab2 et coeff_ :
1665 auto* p_tab1 = tab1_.addr();
1666 int* p_tab2 = tab2_.addr();
1667 double* p_coeff = coeff_.addr();
1668
1669 int* tab2_ptr = p_tab2;
1670 int n=nb_lignes();
1671
1672 for (num_elem=0; num_elem<n; num_elem++)
1673 {
1674
1675 IntList_Curseur liste_vois(voisins[num_elem]);
1676 DoubleList_Curseur liste_val(valeurs[num_elem]);
1677 compteur =0;
1678 *p_tab1++ = rang;
1679
1680 while (liste_vois)
1681 {
1682 *tab2_ptr++ = liste_vois.valeur();
1683 *p_coeff++ = liste_val.valeur();
1684 ++liste_vois;
1685 ++liste_val;
1686 compteur++;
1687 }
1688 // tab2[rang] = compteur;
1689 rang += (compteur);
1690 }
1691 tab1_(num_elem)=rang;
1692 formeF();
1695}
1696
1697/*! @brief Remplissage d'une matrice morse par une matrice morse plus petite
1698 *
1699 */
1700void Matrice_Morse::remplir(const int ideb, const int jdeb, const int n, const int m, const Matrice_Morse& mat)
1701{
1702 // Verification
1703 assert(ideb<=n);
1704 assert(jdeb<=m);
1705
1706 // On va construire une matrice locale
1707 Matrice_Morse matrice_locale(mat);
1708 // Cas ou la matrice locale est symetrique
1709 if (sub_type(Matrice_Morse_Sym,mat))
1710 {
1711 // Creation de la partie inferieure L
1712 Matrice_Morse L(matrice_locale);
1713 L.transpose(matrice_locale);
1714 int lordre = L.ordre();
1715 for (int i=0; i<lordre; i++)
1716 L(i, i) = 0.;
1717 // On ajoute M=U+L
1718 matrice_locale += L;
1719 }
1720
1721 // Dimensionnement de la matrice globale
1722 auto nnz=matrice_locale.nb_coeff();
1723 dimensionner(n,m,(int)nnz);
1724
1725 // Remplissage de la matrice globale par la matrice locale:
1726 // Remplissage de tab1_ avec le decalage par ideb:
1727 int mon_nb_lignes=matrice_locale.nb_lignes();
1728 assert(mon_nb_lignes+ideb<=n);
1729 for (int i=0; i<ideb; i++)
1730 tab1_(i)=1;
1731 for (int i=0; i<mon_nb_lignes; i++)
1732 tab1_(i+ideb)=matrice_locale.tab1_(i);
1733 for (int i=mon_nb_lignes+ideb; i<n+1; i++)
1734 tab1_(i)=matrice_locale.tab1_(mon_nb_lignes);
1735
1736 // Remplissage de tab2_ avec le decalage par jdeb:
1737 for (auto i=0; i<nnz; i++)
1738 tab2_(i)=matrice_locale.tab2_(i)+jdeb;
1739
1740 // Remplissage de coeff_:
1741 for (auto i=0; i<nnz; i++)
1742 coeff_(i)=matrice_locale.coeff_(i);
1743
1746}
1747
1749{
1750 int n=nb_lignes();
1751 for(int ii=0; ii<=n; ii++)
1752 tab1_(ii)--;
1753 for(int ii=0; ii<n; ii++)
1754 tab2_(tab1_(ii))=nb_vois(ii);
1755 for(auto k=0; k<nb_coeff(); k++)
1756 tab2_(k)--;
1759}
1760
1762{
1763 int n=nb_lignes();
1764 for(int ii=0; ii<=n; ii++)
1765 tab1_(ii)++;
1766 for(auto k=0; k<nb_coeff(); k++)
1767 tab2_(k)++;
1770}
1771
1772
1773
1774
1775/*! @brief NE FAIT RIEN
1776 *
1777 * @return (int) renvoie toujours 1
1778 */
1779int Matrice_Morse_test()
1780{
1781 return 1;
1782}
1783
1784/*! @brief Remplit la matrice avec des zeros.
1785 *
1786 */
1787
1789{
1790 coeff_ = 0;
1791}
1792
1793/*! @brief Calcule la largeur de bande d'une matrice morse
1794 *
1795 */
1797{
1798 int ldist,min = 0;
1799 const auto* p_tab1_ = get_tab1().addr();
1800 const int* p_tab2_ = get_tab2().addr();
1801 int N=ordre();
1802
1803 for(int i=0; i<N; i++)
1804 for(auto k = p_tab1_[i]; k < p_tab1_[i+1]; k++)
1805 {
1806 if (p_tab2_[k-1]-1<N)
1807 {
1808 ldist = p_tab2_[k-1] - i;
1809 if( min < ldist ) min = ldist;
1810 }
1811 };
1812 return min;
1813}
1814
1816{
1817 const int nb_lines = nb_lignes( );
1818 const int nb_columns = nb_colonnes( );
1819 const auto nb_coefficients = tab1_( nb_lines ) - 1;
1820
1821 if ( tab2_.size_array( ) != nb_coefficients )
1822 {
1823 Cerr << "invalid tab2 size" << finl;
1824 return false;
1825 }
1826
1827 if ( coeff_.size_array( ) != nb_coefficients )
1828 {
1829 Cerr << "invalid coeff size" << finl;
1830 return false;
1831 }
1832
1833 ArrOfBit flags( nb_columns );
1834
1835 for ( int i=0; i<nb_lines; ++i )
1836 {
1837 flags = 0;
1838
1839 auto k0 = tab1_( i ) - 1;
1840 auto k1 = tab1_( i + 1 ) - 1;
1841
1842 for ( auto k=k0; k<k1; ++k )
1843 {
1844 int j = tab2_( k ) - 1;
1845
1846 if ( j < 0 )
1847 {
1848 Cerr << "invalid column index (<0): " << j << finl;
1849 return false;
1850 }
1851
1852 if ( j >= nb_columns )
1853 {
1854 Cerr << "invalid column index (>nb_cols): " << j << " > " << nb_columns << finl;
1855 return false;
1856 }
1857
1858 if ( flags[ j ] )
1859 {
1860 Cerr << "invalid coefficient ( " << i << ", " << j << " ): already defined ( " << k << " )" << finl;
1861 return false;
1862 }
1863
1864 flags.setbit( j );
1865 }
1866 }
1867
1868 return true;
1869}
1870
1872{
1873 const int nb_lines = nb_lignes( );
1874 const int nb_columns = nb_colonnes( );
1875 const auto nb_coefficients = tab1_( nb_lines ) - 1;
1876
1877 if ( tab2_.size_array( ) != nb_coefficients )
1878 {
1879 Cerr << "invalid tab2 size" << finl;
1880 return false;
1881 }
1882
1883 if ( coeff_.size_array( ) != nb_coefficients )
1884 {
1885 Cerr << "invalid coeff size" << finl;
1886 return false;
1887 }
1888
1889 ArrOfBit flags( nb_columns );
1890
1891 for ( int i=0; i<nb_lines; ++i )
1892 {
1893 flags = 0;
1894
1895 auto k0 = tab1_( i ) - 1;
1896 auto k1 = tab1_( i + 1 ) - 1;
1897
1898 int j0 = tab2_( k0 ) - 1 - 1;
1899
1900 for ( auto k=k0; k<k1; ++k )
1901 {
1902 int j = tab2_( k ) - 1;
1903
1904 if ( j < 0 )
1905 {
1906 Cerr << "invalid column index (<0): " << j << finl;
1907 return false;
1908 }
1909
1910 if ( j >= nb_columns )
1911 {
1912 Cerr << "invalid column index (>nb_cols): " << j << " > " << nb_columns << finl;
1913 return false;
1914 }
1915
1916 if ( flags[ j ] )
1917 {
1918 Cerr << "invalid coefficient ( " << i << ", " << j << " ): already defined ( " << k << " )" << finl;
1919 return false;
1920 }
1921
1922 if ( j <= j0 )
1923 {
1924 Cerr << "unsorted coefficient: ( " << i << ", " << j << " ) after ( " << i << ", " << j0 << " ) " << finl;;
1925 return false;
1926 }
1927
1928 j0 = j;
1929 flags.setbit( j );
1930 }
1931 }
1932
1933 return true;
1934}
1935
1936
1938{
1940#ifndef NDEBUG
1941 if ( ! ( check_morse_matrix_structure( ) ) )
1942 {
1943 Cerr << "Error in 'Matrice_Morse::assert_check_morse_matrix_structure( )':" << finl;
1944 Cerr << " Exiting..." << finl;
1945 Process::exit( );
1946 }
1947 else
1949#endif
1950}
1951
1953{
1955#ifndef NDEBUG
1957 {
1958 Cerr << "Error in 'Matrice_Morse::assert_check_sorted_morse_matrix_structure( )':" << finl;
1959 Cerr << " Exiting..." << finl;
1960 Process::exit( );
1961 }
1962 else
1964#endif
1965}
1966
1967// Build a new Morse matrix spanning the rectangular area defined by the two points (nl0, nc0) and (nl1, nc1)
1968// in the original matrix.
1969// Indices are provided in C mode (0-based indexing).
1970void Matrice_Morse::construire_sous_bloc(int nl0, int nc0, int nl1, int nc1, Matrice_Morse& result) const
1971{
1972 // count non-zero entries:
1973 assert(nl0 >= 0);
1974 assert(nc0 >= 0);
1975 assert(nl0 <= nl1);
1976 assert(nc0 <= nc1);
1977
1978 auto max_nnz = tab1_(nl1+1) - tab1_(nl0); // maximum number of zeros that we will find
1979 int tot=0;
1980 IntTab loca((int)max_nnz, 2);
1981 DoubleTab sub_coeffs((int)max_nnz);
1982 for (int li=nl0; li <= nl1; li++)
1983 {
1984 auto idx_coeff = tab1_(li)-1;
1985 int nb_coeff_on_line = (int)(tab1_(li+1)-tab1_(li));
1986 for (int j=0; j < nb_coeff_on_line; j++)
1987 {
1988 int col_idx = tab2_(j+idx_coeff)-1;
1989 if (col_idx >= nc0 && col_idx <= nc1) // is the coeff in the window?
1990 {
1991 loca(tot, 0) = li - nl0;
1992 loca(tot, 1) = col_idx - nc0;
1993 sub_coeffs(tot) = coeff_(j+idx_coeff);
1994 tot++;
1995 }
1996 }
1997 }
1998 loca.resize(tot,2);
1999 sub_coeffs.resize(tot);
2000
2001 result.dimensionner(loca);
2002 // Set coefficient values:
2003 for (int i =0 ; i < tot; i++)
2004 {
2005 int il = loca(i, 0);
2006 int ic = loca(i, 1);
2007 result.coef(il, ic) = sub_coeffs(i);
2008 }
2009}
2010
2012{
2013 if (sorted_) return; //deja fait
2014 for (int i = 0; i + 1 < tab1_.size_array(); i++) //indice de ligne
2015 std::sort(tab2_.addr() + tab1_(i) - 1, tab2_.addr() + tab1_(i + 1) - 1);
2017}
2018
2019// Check if the matrix is sorted based on a stencil condition
2021{
2022 if (!sorted_)
2023 {
2024 const int n = nb_lignes();
2025 for (int i = 0; i < n; i++)
2026 {
2027 const auto k0 = tab1_( i ) - 1;
2028 const auto k1 = tab1_( i + 1 ) - 1;
2029 for (auto k=k0; k<k1-1; k++)
2030 if (tab2_(k)>tab2_(k+1))
2031 return sorted_; // not sorted
2032 }
2033 sorted_ = true;
2034 }
2035 return sorted_;
2036}
2037
2038// Check the matrix is diagonal:
2039// Faster than using:
2040// Stencil stencil;
2041// A.get_stencil(stencil);
2042// Matrix_tools::is_diagonal_stencil(A.nb_lignes(), A.nb_colonnes(), stencil);
2044{
2045 bool is_diagonal = true;
2046 const int n = nb_lignes();
2047 for (int i = 0; i < n; i++)
2048 {
2049 const auto k1 = get_tab1()(i) - 1;
2050 const auto k2 = get_tab1()(i + 1) - 1;
2051 for (auto k = k1; k < k2; k++)
2052 {
2053 if (k2-k1>1 || get_tab2()(k)-1!=i)
2054 {
2055 is_diagonal = false;
2056 break;
2057 }
2058 }
2059 }
2060 return is_diagonal;
2061}
2062
2063// Explicit instantiations for 'auto nnz' abbreviated function templates
2064template Matrice_Morse::Matrice_Morse(int, int);
2065template Matrice_Morse::Matrice_Morse(int, int, int);
2066template void Matrice_Morse::dimensionner(int, int);
2067template void Matrice_Morse::dimensionner(int, int, int);
2068#ifdef TRUST_USE_GPU
2069template Matrice_Morse::Matrice_Morse(int, trustIdType);
2070template Matrice_Morse::Matrice_Morse(int, int, trustIdType);
2071template void Matrice_Morse::dimensionner(int, trustIdType);
2072template void Matrice_Morse::dimensionner(int, int, trustIdType);
2073#endif
void setbit(int_t i) const
Met le bit e a 1.
Definition ArrOfBit.h:73
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
Classe Matrice_Base Classe de base de la hierarchie des matrices.
bool is_stencil_up_to_date_
virtual DoubleVect & multvect(const DoubleVect &, DoubleVect &) const
Multiplication d'un vecteur par la matrice.
Stencil stencil_
virtual DoubleVect & ajouter_multvect(const DoubleVect &x, DoubleVect &r) const
Operation de multiplication-accumulation (saxpy) matrice vecteur.
bool is_stencil_up_to_date() const
Classe Matrice_Morse_Sym Represente une matrice M (creuse) symetrique stockee au format Morse.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
void clean() override
Remplit la matrice avec des zeros.
friend Matrice_Morse operator+(const Matrice_Morse &, const Matrice_Morse &)
Fonction (hors classe) amie de la classe Matrice_Morse Addition de 2 matrices au format Morse.
int largeur_de_bande() const
Calcule la largeur de bande d'une matrice morse.
int morse_matrix_structure_has_changed_
Matrice_Morse & affecte_prod(const Matrice_Morse &A, const Matrice_Morse &B)
Affecte le produit de 2 matrices Morse A et B a l'objet (this).
void get_stencil_and_coeff_ptrs(Stencil &stencil, std::vector< const double * > &coeff_ptr) const override
void get_stencil(Stencil &stencil) const override
bool check_morse_matrix_structure() const
Sortie & imprimer_image(Sortie &s) const
auto nb_coeff() const
Matrice_Morse & operator*=(double)
Operateur de multiplication (de tous les elements) d'une matrice par un scalaire.
void WriteFileMTX(const Nom &) const
bool check_sorted_morse_matrix_structure() const
Matrice_Morse & operator=(const Matrice_Morse &)
Operateur d'affectation d'une Matrice_Morse dans une autre Matrice_Morse.
void assert_check_morse_matrix_structure() const
void scale(const double x) override
virtual Matrice_Morse & diagmulmat(const DoubleVect &x)
int nb_vois(int i) const
auto & get_set_tab2()
Matrice_Morse & operator/=(double)
Operateur de division (de tous les elements) d'une matrice par un scalaire.
void get_stencil_and_coefficients(Stencil &stencil, StencilCoeffs &coefficients) const override
DoubleVect coeff_
const auto & get_tab2() const
int ordre() const override
Renvoie l'ordre de la matrice: - le nombre de lignes si la matrice est carree.
bool is_sorted_stencil() const
Sortie & imprimer_formatte(Sortie &s) const override
virtual int inverse(const DoubleVect &, DoubleVect &, double) const
Calcule la solution du systeme lineaire: A * solution = secmem.
virtual Matrice_Morse & transpose(const Matrice_Morse &a)
*this = a transposee.
const IntVect & get_tab1_int32() const
Sortie & imprimer(Sortie &s) const override
void dimensionner(int n, _SIZE_ nnz)
Size the matrix with n lines and n columns and nnz zero-values coefficients.
const auto & get_tab1() const
void set_nb_columns(const int)
DoubleVect & ajouter_multvect_(const DoubleVect &, DoubleVect &) const override
Operation de multiplication-accumulation (saxpy) matrice vecteur.
DoubleVect & ajouter_multvectT_(const DoubleVect &, DoubleVect &) const override
Operation de multiplication-accumulation (saxpy) matrice vecteur, par la matrice transposee.
void get_stencil_coeff_templ(Stencil &stencil, _TAB_T_ &coeffs_span) const
void assert_check_sorted_morse_matrix_structure() const
auto & get_set_coeff()
Matrice_Morse & operator+=(const Matrice_Morse &)
NE FAIT RIEN.
double coef(int i, int j) const
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
bool has_same_morse_matrix_structure(const Matrice_Morse &) const
auto & get_set_tab1()
Matrice_Morse operator-() const
Operateur de negation unaire, renvoie l'opposee de la matrice: - A Appelle operator*(double,...
const auto & get_coeff() const
void set_symmetric(const int)
void remplir(const IntLists &, const DoubleLists &, const DoubleVect &)
virtual Matrice_Morse & partie_sup(const Matrice_Morse &a)
int nb_lignes() const override
Return local number of lines (=size on the current proc).
void compacte(int elim_coeff_nul=0)
Method to check/clean the Matrice_Morse matrix: -Suppress coefficient defined several times.
void construire_sous_bloc(int nl0, int nc0, int nl1, int nc1, Matrice_Morse &result) const
void unite()
Initialisation a la matrice unite (modif MT).
void set_tab1_int32() const
DoubleTab & ajouter_multTab_(const DoubleTab &, DoubleTab &) const override
Operation de multiplication-accumulation (saxpy) matrice matrice (matrice X representee par un tablea...
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
friend class Sortie
Definition Objet_U.h:75
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
static const Nom & nom_du_cas()
Renvoie une reference constante vers le nom du cas.
Definition Objet_U.cpp:146
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
static bool is_parallel()
Definition Process.cpp:110
static void abort()
Routine de sortie de Trio-U sur une erreur abort().
Definition Process.cpp:570
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
Definition Process.cpp:136
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Cette classe est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
void precision(int pre) override
void setf(IOS_FORMAT code) override
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ size_array() const
_TYPE_ * addr()
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void ordonne_array()
void resize(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTArray.h:156
bool isDataOnDevice() const
_TYPE_ valeur() const
Definition TRUSTList.h:115
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91