SpM Handbook 1.3.0
Loading...
Searching...
No Matches
spm.c
Go to the documentation of this file.
1/**
2 *
3 * @file spm.c
4 *
5 * SParse Matrix package main routines.
6 *
7 * @copyright 2016-2026 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
8 * Univ. Bordeaux. All rights reserved.
9 *
10 * @version 1.3.0
11 * @author Pierre Ramet
12 * @author Mathieu Faverge
13 * @author Tony Delarue
14 * @author Alban Bellot
15 * @author Matias Hastaran
16 * @author Matthieu Kuhn
17 * @author Gregoire Pichon
18 * @author Alycia Lisito
19 * @author Gregoire Pichon
20 * @author Florent Pruvost
21 * @date 2026-07-06
22 *
23 * @addtogroup spm
24 * @{
25 **/
26#include "common.h"
27#include <cblas.h>
28#include <lapacke.h>
29#if defined(HAVE_BLAS_SET_NUM_THREADS)
30#if defined(HAVE_BLI_THREAD_SET_NUM_THREADS)
31#include <blis.h>
32#elif defined(HAVE_MKL_SET_NUM_THREADS)
33#include <mkl_service.h>
34#endif
35#endif
36
37#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
38
39static int (*conversionTable[3][3][6])(spmatrix_t*) = {
40 /* From CSC */
41 {{ NULL, NULL, NULL, NULL, NULL, NULL },
43 NULL,
49 NULL,
54 /* From CSR */
56 NULL,
61 { NULL, NULL, NULL, NULL, NULL, NULL },
63 NULL,
68 /* From IJV */
70 NULL,
76 NULL,
81 { NULL, NULL, NULL, NULL, NULL, NULL }}
82};
83
84#endif /* !defined(DOXYGEN_SHOULD_SKIP_THIS) */
85
86/**
87 *******************************************************************************
88 *
89 * @brief Init the spm structure with a specific communicator.
90 *
91 *******************************************************************************
92 *
93 * @param[inout] spm
94 * The sparse matrix to init.
95 *
96 * @param[in] comm
97 * The MPI communicator used for the sparse matrix. MPI_COMM_WORLD by default.
98 *
99 *******************************************************************************/
100void
102 SPM_Comm comm )
103{
104 spm->baseval = 0;
105 spm->mtxtype = SpmGeneral;
106 spm->flttype = SpmDouble;
107 spm->fmttype = SpmCSC;
108
109 spm->gN = -1;
110 spm->n = 0;
111 spm->gnnz = -1;
112 spm->nnz = 0;
113
114 spm->gNexp = -1;
115 spm->nexp = -1;
116 spm->gnnzexp = -1;
117 spm->nnzexp = -1;
118
119 spm->dof = 1;
120 spm->dofs = NULL;
121 spm->layout = SpmColMajor;
122
123 spm->colptr = NULL;
124 spm->rowptr = NULL;
125 spm->loc2glob = NULL;
126 spm->values = NULL;
127
128 spm->glob2loc = NULL;
129 spm->comm = comm;
130 spm->replicated = -1;
131#if defined(SPM_WITH_MPI)
132 MPI_Comm_rank( spm->comm, &(spm->clustnum) );
133 MPI_Comm_size( spm->comm, &(spm->clustnbr) );
134#else
135 spm->clustnum = 0;
136 spm->clustnbr = 1;
137#endif /* defined(SPM_WITH_MPI) */
138
139 if ( spm->clustnbr == 1 ) {
140 spm->replicated = 1;
141 }
142}
143
144/**
145 *******************************************************************************
146 *
147 * @brief Init the spm structure.
148 *
149 *******************************************************************************
150 *
151 * @param[inout] spm
152 * The sparse matrix to init.
153 *
154 *******************************************************************************/
155void
157{
158 spmInitDist( spm, MPI_COMM_WORLD );
159 spm->replicated = 1;
160}
161
162/**
163 *******************************************************************************
164 *
165 * @brief Allocate the arrays of an spm structure.
166 *
167 * This function must be called after initialization of the non-computed fields,
168 * and the call to spmUpdateComputedFields(). It allocates the colptr, rowptr,
169 * dof, and values arrays with C malloc function. This is highly
170 * recommended to use this function when using PaStiX from Fortran.
171 *
172 *******************************************************************************
173 *
174 * @param[inout] spm
175 * The sparse matrix fr which the internal arrays needs to be allocated.
176 *
177 *******************************************************************************/
178void
180{
181 size_t colsize = (spm->fmttype == SpmCSC) ? spm->n + 1 : spm->nnz;
182 size_t rowsize = (spm->fmttype == SpmCSR) ? spm->n + 1 : spm->nnz;
183
184 if ( spm->colptr == NULL ) {
185 spm->colptr = (spm_int_t*)malloc( colsize * sizeof(spm_int_t) );
186 }
187 if ( spm->rowptr == NULL ) {
188 spm->rowptr = (spm_int_t*)malloc( rowsize * sizeof(spm_int_t) );
189 }
190
191 if ( ( spm->dof < 1 ) &&
192 ( spm->dofs == NULL ) )
193 {
194 size_t dofsize = spm->gN + 1;
195 spm->dofs = (spm_int_t*)malloc( dofsize * sizeof(spm_int_t) );
196 }
197
198 if ( (spm->flttype != SpmPattern) &&
199 (spm->values == NULL ) )
200 {
201 size_t valsize = (size_t)(spm->nnzexp) * spm_size_of( spm->flttype );
202 spm->values = malloc( valsize );
203 }
204
205 if ( spm->clustnbr == 1 ) {
206 assert( spm->loc2glob == NULL );
207 /* Enforce replicated to 1 */
208 spm->replicated = 1;
209 }
210
211 if ( spm->loc2glob == NULL ) {
212 if ( spm->replicated == 1 ) {
213 spm->loc2glob = NULL;
214 } else if ( spm->replicated == 0 ) {
215 spm->loc2glob = (spm_int_t*)malloc( spm->n * sizeof(spm_int_t) );
216 } else {
217 fprintf( stderr, "[%s] WARNING: replicated field is not initialized, loc2glob can't be correctly allocated\n", __func__ );
218 }
219 }
220}
221
222/**
223 *******************************************************************************
224 *
225 * @brief Cleanup the spm structure but do not free the spm pointer.
226 *
227 *******************************************************************************
228 *
229 * @param[inout] spm
230 * The sparse matrix to free.
231 *
232 *******************************************************************************/
233void
235{
236 assert( spm->replicated != -1 );
237 if(spm->colptr != NULL) {
238 free(spm->colptr);
239 spm->colptr = NULL;
240 }
241 if(spm->rowptr != NULL) {
242 free(spm->rowptr);
243 spm->rowptr = NULL;
244 }
245 if(spm->loc2glob != NULL) {
246 assert( !spm->replicated );
247 free(spm->loc2glob);
248 spm->loc2glob = NULL;
249 }
250 if(spm->values != NULL) {
251 free(spm->values);
252 spm->values = NULL;
253 }
254 if(spm->dofs != NULL) {
255 free(spm->dofs);
256 spm->dofs = NULL;
257 }
258 if(spm->glob2loc != NULL) {
259 free(spm->glob2loc);
260 spm->glob2loc = NULL;
261 }
262}
263
264/**
265 *******************************************************************************
266 *
267 * @brief Rebase the arrays of the spm to the given value.
268 *
269 * If the value is equal to the original base, then nothing is performed.
270 *
271 *******************************************************************************
272 *
273 * @param[inout] spm
274 * The sparse matrix to rebase.
275 *
276 * @param[in] baseval
277 * The new base value to use in the graph (0 or 1).
278 *
279 *******************************************************************************/
280void
282 int baseval )
283{
284 spm_int_t baseadj;
285 size_t i, n, nnz, colsize, rowsize;
286
287 /* Parameter checks */
288 if ( spm == NULL ) {
289 fprintf( stderr,"spmBase: spm pointer is NULL");
290 return;
291 }
292
293 assert( spm->replicated != -1 );
294 assert( (spm->replicated == 1) || (spm->clustnbr > 1) );
295
296 n = spm->n;
297 nnz = spm->nnz;
298 colsize = (spm->fmttype == SpmCSC) ? n + 1 : nnz;
299 rowsize = (spm->fmttype == SpmCSR) ? n + 1 : nnz;
300
301 if ( ((colsize > 0) && (spm->colptr == NULL)) ||
302 ((rowsize > 0) && (spm->rowptr == NULL)) )
303 {
304 fprintf( stderr,"spmBase: spm pointers are not correctly initialized");
305 return;
306 }
307 if ( (baseval != 0) &&
308 (baseval != 1) )
309 {
310 fprintf( stderr,"spmBase: baseval is incorrect, must be 0 or 1");
311 return;
312 }
313
314 baseadj = baseval - spm->baseval;
315 if ( baseadj == 0 ) {
316 return;
317 }
318
319 for (i = 0; i < colsize; i++) {
320 spm->colptr[i] += baseadj;
321 }
322 for (i = 0; i < rowsize; i++) {
323 spm->rowptr[i] += baseadj;
324 }
325
326 if (spm->loc2glob != NULL) {
327 assert( !spm->replicated );
328 for (i = 0; i < n; i++) {
329 spm->loc2glob[i] += baseadj;
330 }
331 }
332 if (spm->dofs != NULL) {
333 for (i = 0; i <= (size_t)(spm->gN); i++) {
334 spm->dofs[i] += baseadj;
335 }
336 }
337
338 spm->baseval = baseval;
339 return;
340}
341
342/**
343 *******************************************************************************
344 *
345 * @brief Search the base used in the spm structure.
346 *
347 *******************************************************************************
348 *
349 * @param[in] spm
350 * The sparse matrix structure.
351 *
352 ********************************************************************************
353 *
354 * @retval The baseval used in the given sparse matrix structure.
355 *
356 *******************************************************************************/
359{
360 spm_int_t baseval = 2;
361
362 assert( spm->replicated != -1 );
363
364 /*
365 * Check the baseval, we consider that arrays are sorted by columns or rows
366 */
367 if ( (spm->n > 0 ) &&
368 (spm->nnz > 0 ) )
369 {
370 baseval = spm_imin( *(spm->colptr), *(spm->rowptr) );
371 }
372
373 if ( spm->fmttype == SpmIJV )
374 {
375 assert( baseval >= 0 );
376
377 if ( ( baseval != 0 ) &&
378 ( baseval != 1 ) )
379 {
380 spm_int_t i;
381 const spm_int_t *colptr = spm->colptr;
382 const spm_int_t *rowptr = spm->rowptr;
383
384 for(i=0; i<spm->nnz; i++, colptr++, rowptr++){
385 baseval = spm_imin( *colptr, baseval );
386 baseval = spm_imin( *rowptr, baseval );
387 }
388 }
389 }
390
391#if defined(SPM_WITH_MPI)
392 /* Reduce for all cases, just to cover the case with one node without unknowns */
393 if ( (!spm->replicated) && (spm->clustnbr > 1) ) {
394 MPI_Allreduce( MPI_IN_PLACE, &baseval, 1, SPM_MPI_INT,
395 MPI_MIN, spm->comm );
396 }
397#endif
398
399 assert( ( baseval == 0 ) ||
400 ( baseval == 1 ) );
401
402 return baseval;
403}
404
405/**
406 *******************************************************************************
407 *
408 * @brief Convert the storage format of the spm.
409 *
410 *******************************************************************************
411 *
412 * @param[in] ofmttype
413 * The output format of the sparse matrix. It must be:
414 * - SpmCSC
415 * - SpmCSR
416 * - SpmIJV
417 *
418 * @param[inout] spm
419 * The sparse matrix structure to convert.
420 *
421 ********************************************************************************
422 *
423 * @retval SPM_SUCCESS if the conversion happened successfully.
424 * @retval SPM_ERR_BADPARAMETER if one the parameter is incorrect.
425 * @retval SPM_ERR_NOTIMPLEMENTED if the case is not yet implemented.
426 *
427 *******************************************************************************/
428int
429spmConvert( int ofmttype,
430 spmatrix_t *spm )
431{
432 assert( spm->replicated != -1 );
433
434 if ( conversionTable[spm->fmttype][ofmttype][spm->flttype] ) {
435 return conversionTable[spm->fmttype][ofmttype][spm->flttype]( spm );
436 }
437 else {
438 return SPM_SUCCESS;
439 }
440}
441
442/**
443 *******************************************************************************
444 *
445 * @brief Convert the spm matrix into a dense matrix for test purpose.
446 *
447 * @remark DO NOT USE with large matrices. This is for test purpose only.
448 *
449 *******************************************************************************
450 *
451 * @param[in] spm
452 * The sparse matrix structure to convert.
453 *
454 * @param[inout] A
455 * On entry, an allocated matrix of size spm->gNexp-by-spm->gNexp in the
456 * datatype of spm->flttype.
457 * On exit, the matrix A is set to the sparse matrix spm.
458 *
459 *******************************************************************************/
460void
461spm2Dense( const spmatrix_t *spm, void *A )
462{
463 assert( spm->replicated != -1 );
464
465 switch (spm->flttype) {
466 case SpmComplex64:
467 z_spm2dense( spm, A );
468 return;
469 case SpmComplex32:
470 c_spm2dense( spm, A );
471 return;
472 case SpmDouble:
473 d_spm2dense( spm, A );
474 return;
475 case SpmFloat:
476 s_spm2dense( spm, A );
477 return;
478 default:
479 return;
480 }
481}
482
483/**
484 *******************************************************************************
485 *
486 * @brief Compute the norm of the spm.
487 *
488 * Return the ntype norm of the sparse matrix spm.
489 *
490 * spmNorm = ( max(abs(spm(i,j))), NORM = SpmMaxNorm
491 * (
492 * ( norm1(spm), NORM = SpmOneNorm
493 * (
494 * ( normI(spm), NORM = SpmInfNorm
495 * (
496 * ( normF(spm), NORM = SpmFrobeniusNorm
497 *
498 * where norm1 denotes the one norm of a matrix (maximum column sum),
499 * normI denotes the infinity norm of a matrix (maximum row sum) and
500 * normF denotes the Frobenius norm of a matrix (square root of sum
501 * of squares). Note that max(abs(spm(i,j))) is not a consistent matrix
502 * norm.
503 *
504 *******************************************************************************
505 *
506 * @param[in] ntype
507 * - SpmMaxNorm
508 * - SpmOneNorm
509 * - SpmInfNorm
510 * - SpmFrobeniusNorm
511 *
512 * @param[in] spm
513 * The sparse matrix structure.
514 *
515 ********************************************************************************
516 *
517 * @retval norm The norm described above. Note that for simplicity, even if the
518 * norm of single real or single complex matrix is computed with
519 * single precision, the returned norm is stored in double
520 * precision.
521 * @retval -1 If the floating point of the sparse matrix is undefined.
522 *
523 *******************************************************************************/
524double
526 const spmatrix_t *spm )
527{
528 double norm = -1.;
529
530 assert( spm->replicated != -1 );
531
532 switch (spm->flttype) {
533 case SpmFloat:
534 norm = (double)s_spmNorm( ntype, spm );
535 break;
536
537 case SpmDouble:
538 norm = d_spmNorm( ntype, spm );
539 break;
540
541 case SpmComplex32:
542 norm = (double)c_spmNorm( ntype, spm );
543 break;
544
545 case SpmComplex64:
546 norm = z_spmNorm( ntype, spm );
547 break;
548
549 case SpmPattern:
550 default:
551 return norm;
552 }
553
554 return norm;
555}
556
557/**
558 *******************************************************************************
559 *
560 * @brief Compute the norm of the spm.
561 *
562 * Return the ntype norm of the sparse matrix spm.
563 *
564 * spmNormVec = ( max(abs(x(i))), NORM = SpmMaxNorm
565 * (
566 * ( norm1(x), NORM = SpmOneNorm
567 * (
568 * ( normI(x), NORM = SpmInfNorm
569 * (
570 * ( normF(x), NORM = SpmFrobeniusNorm
571 *
572 * where norm1 denotes the one norm of a matrix (maximum column sum),
573 * normI denotes the infinity norm of a matrix (maximum row sum) and
574 * normF denotes the Frobenius norm of a matrix (square root of sum
575 * of squares). Note that max(abs(x(i))) is not a consistent matrix
576 * norm.
577 *
578 *******************************************************************************
579 *
580 * @param[in] ntype
581 * - SpmMaxNorm
582 * - SpmOneNorm
583 * - SpmInfNorm
584 * - SpmFrobeniusNorm
585 *
586 * @param[in] spm
587 * The sparse matrix structure.
588 *
589 * @param[in] x
590 * The vector for which to compute the norm that is distributed by row
591 * as described in the spm.
592 * The arithmetic type used is the one described by spm->flttype.
593 *
594 * @param[in] inc
595 * The incremental step between each element of the vector.
596 *
597 ********************************************************************************
598 *
599 * @retval norm The norm described above. Note that for simplicity, even if the
600 * norm of single real or single complex matrix is computed with
601 * single precision, the returned norm is stored in double
602 * precision.
603 * @retval -1 If the floating point of the sparse matrix is undefined.
604 *
605 *******************************************************************************/
606double
608 const spmatrix_t *spm,
609 const void *x,
610 spm_int_t inc )
611{
612 double norm = -1.;
613 assert( inc == 1 );
614
615 if ( inc > 1 ) {
616 fprintf( stderr, "spmNormVec: incx values different from 1 are not supported yet\n" );
617 return norm;
618 }
619
620 if ( inc <= 0 ) {
621 fprintf( stderr, "spmNormVec: invalide value of parameter incx. Must be > 0\n" );
622 return norm;
623 }
624
625 assert( spm->replicated != -1 );
626
627 switch (spm->flttype) {
628 case SpmFloat:
629 norm = (double)s_spmNormMat( ntype, spm, 1, x, spm->nexp );
630 break;
631
632 case SpmDouble:
633 norm = d_spmNormMat( ntype, spm, 1, x, spm->nexp );
634 break;
635
636 case SpmComplex32:
637 norm = (double)c_spmNormMat( ntype, spm, 1, x, spm->nexp );
638 break;
639
640 case SpmComplex64:
641 norm = z_spmNormMat( ntype, spm, 1, x, spm->nexp );
642 break;
643
644 case SpmPattern:
645 default:
646 return norm;
647 }
648
649 return norm;
650}
651
652/**
653 *******************************************************************************
654 *
655 * @brief Compute the norm of the spm.
656 *
657 * Return the ntype norm of the sparse matrix spm.
658 *
659 * spmNormMat = ( max(abs(A(i,j))), NORM = SpmMaxNorm
660 * (
661 * ( norm1(A), NORM = SpmOneNorm
662 * (
663 * ( normI(A), NORM = SpmInfNorm
664 * (
665 * ( normF(A), NORM = SpmFrobeniusNorm
666 *
667 * where norm1 denotes the one norm of a matrix (maximum column sum),
668 * normI denotes the infinity norm of a matrix (maximum row sum) and
669 * normF denotes the Frobenius norm of a matrix (square root of sum
670 * of squares). Note that max(abs(A(i,j))) is not a consistent matrix
671 * norm.
672 *
673 *******************************************************************************
674 *
675 * @param[in] ntype
676 * - SpmMaxNorm
677 * - SpmOneNorm
678 * - SpmInfNorm
679 * - SpmFrobeniusNorm
680 *
681 * @param[in] spm
682 * The sparse matrix structure.
683 *
684 * @param[in] n
685 * The number of columns of the matrix A.
686 *
687 * @param[in] A
688 * The matrix A of size lda-by-n.
689 *
690 * @param[in] lda
691 * The leading dimension of the matrix A. Must be >= max(1, spm->nexp).
692 *
693 ********************************************************************************
694 *
695 * @retval norm The norm described above. Note that for simplicity, even if the
696 * norm of single real or single complex matrix is computed with
697 * single precision, the returned norm is stored in double
698 * precision.
699 * @retval -1 If the floating point of the sparse matrix is undefined.
700 *
701 *******************************************************************************/
702double
704 const spmatrix_t *spm,
705 spm_int_t n,
706 const void *A,
707 spm_int_t lda )
708{
709 double norm = -1.;
710
711 assert( spm->replicated != -1 );
712
713 switch (spm->flttype) {
714 case SpmFloat:
715 norm = (double)s_spmNormMat( ntype, spm, n, A, lda );
716 break;
717
718 case SpmDouble:
719 norm = d_spmNormMat( ntype, spm, n, A, lda );
720 break;
721
722 case SpmComplex32:
723 norm = (double)c_spmNormMat( ntype, spm, n, A, lda );
724 break;
725
726 case SpmComplex64:
727 norm = z_spmNormMat( ntype, spm, n, A, lda );
728 break;
729
730 case SpmPattern:
731 default:
732 return norm;
733 }
734
735 return norm;
736}
737
738/**
739 *******************************************************************************
740 *
741 * @brief Sort the subarray of edges of each vertex.
742 *
743 *******************************************************************************
744 *
745 * @param[inout] spm
746 * On entry, the pointer to the sparse matrix structure.
747 * On exit, the same sparse matrix with subarrays of edges sorted by
748 * ascending order.
749 *
750 ********************************************************************************
751 *
752 * @retval SPM_SUCCESS if the sort was called
753 * @retval SPM_ERR_BADPARAMETER if the given spm was incorrect.
754 *
755 *******************************************************************************/
756int
758{
759 assert( spm->replicated != -1 );
760
761 switch (spm->flttype) {
762 case SpmPattern:
763 p_spmSort( spm );
764 break;
765 case SpmFloat:
766 s_spmSort( spm );
767 break;
768 case SpmDouble:
769 d_spmSort( spm );
770 break;
771 case SpmComplex32:
772 c_spmSort( spm );
773 break;
774 case SpmComplex64:
775 z_spmSort( spm );
776 break;
777 default:
779 }
780 return SPM_SUCCESS;
781}
782
783/**
784 *******************************************************************************
785 *
786 * @brief Merge multiple entries in a spm by summing their values together.
787 *
788 * The sparse matrix needs to be sorted first (see z_spmSort()). In distributed,
789 * only local entries are merged together.
790 *
791 * @warning Not implemented for IJV format.
792 *
793 *******************************************************************************
794 *
795 * @param[inout] spm
796 * On entry, the pointer to the sparse matrix structure.
797 * On exit, the reduced sparse matrix of multiple entries were present
798 * in it. The multiple values for a same vertex are sum up together.
799 *
800 ********************************************************************************
801 *
802 * @retval >=0 the number of vertices that were merged,
803 * @retval SPM_ERR_BADPARAMETER if the given spm was incorrect.
804 *
805 *******************************************************************************/
808{
809 spm_int_t local, global;
810
811 assert( spm->replicated != -1 );
812
813 switch (spm->flttype) {
814 case SpmPattern:
815 local = p_spmMergeDuplicate( spm );
816 break;
817
818 case SpmFloat:
819 local = s_spmMergeDuplicate( spm );
820 break;
821
822 case SpmDouble:
823 local = d_spmMergeDuplicate( spm );
824 break;
825
826 case SpmComplex32:
827 local = c_spmMergeDuplicate( spm );
828 break;
829
830 case SpmComplex64:
831 local = z_spmMergeDuplicate( spm );
832 break;
833
834 default:
836 }
837
838#if defined(SPM_WITH_MPI)
839 if ( (!spm->replicated) && (spm->clustnbr > 1) ) {
840 MPI_Allreduce( &local, &global, 1, SPM_MPI_INT, MPI_SUM, spm->comm );
841
842 /* Update computed fields */
843 if( global > 0 ) {
844 MPI_Allreduce( &(spm->nnz), &(spm->gnnz), 1, SPM_MPI_INT, MPI_SUM, spm->comm );
845 MPI_Allreduce( &(spm->nnzexp), &(spm->gnnzexp), 1, SPM_MPI_INT, MPI_SUM, spm->comm );
846 }
847 }
848 else
849#endif
850 {
851 global = local;
852 if ( global > 0 ) {
853 spm->gnnz = spm->nnz;
854 spm->gnnzexp = spm->nnzexp;
855 }
856 }
857
858 return global;
859}
860
861/**
862 *******************************************************************************
863 *
864 * @brief Check the correctness of a spm.
865 *
866 * This routine initializes the sparse matrix to fit the PaStiX requirements. If
867 * needed, the format is changed to CSC, the duplicated vertices are merged
868 * together by summing their values; the graph is made symmetric for matrices
869 * with unsymmetric pattern, new values are set to 0. Only the lower part is
870 * kept for symmetric matrices.
871 *
872 *******************************************************************************
873 *
874 * @param[in] spm_in
875 * The pointer to the sparse matrix structure to check, and correct.
876 *
877 * @param[inout] spm_out
878 * On entry, an allocated structure to hold the corrected spm.
879 * On exit, holds the pointer to spm corrected.
880 *
881 *******************************************************************************
882 *
883 * @retval 0 if no changes have been made to the spm matrix.
884 * @retval 1 if corrections have been applied and a new spm is returned.
885 *
886 *******************************************************************************/
887int
889 spmatrix_t *spm_out )
890{
891 spmatrix_t newspm;
892 spm_int_t count;
893 int modified = 0;
894
895 assert( spm_in->replicated != -1 );
896
897 /*
898 * Let's work on a copy
899 */
900 spmCopy( spm_in, &newspm );
901
902 /* PaStiX works on CSC matrices */
903 if ( spmConvert( SpmCSC, &newspm ) != SPM_SUCCESS ) {
904 spm_print_error( "spmCheckAndCorrect: error during the conversion to CSC format\n" );
905 spmExit( &newspm );
906 return 0;
907 }
908
909 if ( spm_in->fmttype != newspm.fmttype ) {
910 modified = 1;
911 }
912
913 /* Sort the rowptr for each column */
914 spmSort( &newspm );
915
916 /* Merge the duplicated entries by summing the values */
917 count = spmMergeDuplicate( &newspm );
918 if ( count > 0 )
919 {
920 modified = 1;
921 if ( spm_in->clustnum == 0 ) {
922 fprintf( stderr, "spmCheckAndCorrect: %ld entries have been merged\n", (long)count );
923 }
924 }
925
926 /*
927 * If the matrix is symmetric or hermitian, we keep only the upper or lower
928 * part, otherwise, we symmetrize the graph to get A+A^t, new values are set
929 * to 0.
930 */
931 if ( newspm.mtxtype == SpmGeneral ) {
932 count = spmSymmetrize( &newspm );
933 if ( count > 0 )
934 {
935 modified = 1;
936 if ( spm_in->clustnum == 0 ) {
937 fprintf( stderr, "spmCheckAndCorrect: %ld entries have been added for symmetry\n", (long)count );
938 }
939 }
940 }
941 else {
942 //spmToLower( &newspm );
943 }
944
945 /*
946 * Check if we return the new one, or the original one because no changes
947 * have been made
948 */
949 if ( modified ) {
950 memcpy( spm_out, &newspm, sizeof(spmatrix_t) );
951 return 1;
952 }
953 else {
954 memcpy( spm_out, spm_in, sizeof(spmatrix_t) );
955 spmExit( &newspm );
956 return 0;
957 }
958}
959
960/**
961 *******************************************************************************
962 *
963 * @brief Create a copy of the spm.
964 *
965 * Duplicate the spm data structure given as parameter. All new arrays are
966 * allocated and copied from the original matrix. Both matrices need to be
967 * freed.
968 * Procedure version.
969 *
970 *******************************************************************************
971 *
972 * @param[in] spm
973 * The sparse matrix to copy.
974 *
975 * @param[out] newspm
976 * The pre-allocated spm to copy into.
977 *
978 *******************************************************************************/
979void
980spmCopy( const spmatrix_t *spm,
981 spmatrix_t *newspm )
982{
983 size_t colsize, rowsize, valsize, dofsize;
984
985 assert( spm->replicated != -1 );
986
987 memcpy( newspm, spm, sizeof(spmatrix_t));
988
989 colsize = (spm->fmttype == SpmCSC) ? spm->n + 1 : spm->nnz;
990 rowsize = (spm->fmttype == SpmCSR) ? spm->n + 1 : spm->nnz;
991 valsize = spm->nnzexp;
992 dofsize = spm->gN + 1;
993
994 if(spm->colptr != NULL) {
995 newspm->colptr = (spm_int_t*)malloc( colsize * sizeof(spm_int_t) );
996 memcpy( newspm->colptr, spm->colptr, colsize * sizeof(spm_int_t) );
997 }
998 if(spm->rowptr != NULL) {
999 newspm->rowptr = (spm_int_t*)malloc( rowsize * sizeof(spm_int_t) );
1000 memcpy( newspm->rowptr, spm->rowptr, rowsize * sizeof(spm_int_t) );
1001 }
1002 if(spm->loc2glob != NULL) {
1003 assert( !spm->replicated );
1004 newspm->loc2glob = (spm_int_t*)malloc( spm->n * sizeof(spm_int_t) );
1005 memcpy( newspm->loc2glob, spm->loc2glob, spm->n * sizeof(spm_int_t) );
1006 }
1007 if(spm->glob2loc != NULL) {
1008 newspm->glob2loc = (spm_int_t*)malloc( spm->gN * sizeof(spm_int_t) );
1009 memcpy( newspm->glob2loc, spm->glob2loc, spm->gN * sizeof(spm_int_t) );
1010 }
1011 if(spm->dofs != NULL) {
1012 newspm->dofs = (spm_int_t*)malloc( dofsize * sizeof(spm_int_t) );
1013 memcpy( newspm->dofs, spm->dofs, dofsize * sizeof(spm_int_t) );
1014 }
1015 if(spm->values != NULL) {
1016 valsize = valsize * spm_size_of( spm->flttype );
1017 newspm->values = malloc(valsize);
1018 memcpy( newspm->values, spm->values, valsize );
1019 }
1020}
1021
1022/**
1023 *******************************************************************************
1024 *
1025 * @brief Print basic informations about the spm matrix into a given stream.
1026 *
1027 *******************************************************************************
1028 *
1029 * @param[in] spm
1030 * The sparse matrix to print.
1031 *
1032 * @param[inout] stream
1033 * Stream to print the spm matrix. stdout is used if stream == NULL.
1034 *
1035 *******************************************************************************/
1036void
1038 FILE *stream )
1039{
1040 char *mtxtypestr[4] = { "General", "Symmetric", "Hermitian", "Incorrect" };
1041 char *flttypestr[7] = { "Pattern", "", "Float", "Double", "Complex32", "Complex64", "Incorrect" };
1042 char *fmttypestr[4] = { "CSC", "CSR", "IJV", "Incorrect" };
1043 int mtxtype = spm->mtxtype - SpmGeneral;
1044 int flttype = spm->flttype - SpmPattern;
1045 int fmttype = spm->fmttype - SpmCSC;
1046
1047 assert( spm->replicated != -1 );
1048
1049 if (stream == NULL) {
1050 stream = stdout;
1051 }
1052
1053 mtxtype = (mtxtype > 2 || mtxtype < 0) ? 3 : mtxtype;
1054 flttype = (flttype > 5 || flttype < 0) ? 6 : flttype;
1055 fmttype = (fmttype > 2 || fmttype < 0) ? 3 : fmttype;
1056
1057 if ( spm->clustnum == 0 ) {
1058 fprintf( stream,
1059 " Matrix type: %s\n"
1060 " Arithmetic: %s\n"
1061 " Format: %s\n"
1062 " N: %ld\n"
1063 " nnz: %ld\n",
1064 mtxtypestr[mtxtype],
1065 flttypestr[flttype],
1066 fmttypestr[fmttype],
1067 (long)spm->gN,
1068 (long)spm->gnnz );
1069
1070 if ( spm->dof != 1 ) {
1071 if ( spm->dof > 1 ) {
1072 fprintf( stream,
1073 " Dof: %ld\n",
1074 (long)spm->dof );
1075 }
1076 else {
1077 fprintf( stream,
1078 " Dof: Variadic\n" );
1079 }
1080
1081 fprintf( stream,
1082 " N expanded: %ld\n"
1083 " NNZ expanded: %ld\n",
1084 (long)spm->gNexp, (long)spm->gnnzexp );
1085 }
1086 }
1087 if ( (!spm->replicated) && (spm->clustnbr > 1) ) {
1088 int c;
1089 if ( spm->clustnum == 0 ) {
1090 fprintf( stream,
1091 " Details:\n"
1092 " N nnz %s\n",
1093 ( spm->dof != 1 ) ? " Nexp NNZexp" : "" );
1094 }
1095 for( c=0; c<spm->clustnbr; c++ ) {
1096 if ( spm->clustnum == c ) {
1097 if ( spm->dof != 1 ) {
1098 fprintf( stream,
1099 " %4d: %7ld %9ld %8ld %11ld\n",
1100 spm->clustnum, (long)spm->n, (long)spm->nnz,
1101 (long)spm->nexp, (long)spm->nnzexp );
1102 }
1103 fprintf( stream,
1104 " %4d: %7ld %9ld\n",
1105 spm->clustnum, (long)spm->n, (long)spm->nnz );
1106 }
1107#if defined(SPM_WITH_MPI)
1108 MPI_Barrier( spm->comm );
1109#endif
1110 }
1111 }
1112 fflush( stream );
1113}
1114
1115/**
1116 *******************************************************************************
1117 *
1118 * @brief Print an spm matrix into into a given file.
1119 *
1120 *******************************************************************************
1121 *
1122 * @param[in] spm
1123 * The sparse matrix to print.
1124 *
1125 * @param[in] stream
1126 * File to print the spm matrix. stdout, if stream == NULL.
1127 *
1128 *******************************************************************************/
1129void
1131 FILE *stream )
1132{
1133 assert( spm->replicated != -1 );
1134
1135 if (stream == NULL) {
1136 stream = stdout;
1137 }
1138
1139 switch(spm->flttype)
1140 {
1141 case SpmPattern:
1142 //return p_f, spmPrint(f, spm);
1143 break;
1144 case SpmFloat:
1145 s_spmPrint(stream, spm);
1146 break;
1147 case SpmComplex32:
1148 c_spmPrint(stream, spm);
1149 break;
1150 case SpmComplex64:
1151 z_spmPrint(stream, spm);
1152 break;
1153 case SpmDouble:
1154 default:
1155 d_spmPrint(stream, spm);
1156 }
1157}
1158
1159/**
1160 *******************************************************************************
1161 *
1162 * @brief Expand a multi-dof spm matrix into an spm with constant dof set to 1.
1163 *
1164 * Duplicate the spm data structure given as parameter. All new arrays are
1165 * allocated and copied from the original matrix. Both matrices need to be
1166 * freed.
1167 *
1168 *******************************************************************************
1169 *
1170 * @param[in] spm_in
1171 * The original non expanded matrix in CSC format used as the template
1172 * for the muti-dof matrix.
1173 *
1174 * @param[inout] spm_out
1175 * The output expanded matrix generated from the template.
1176 *
1177 *******************************************************************************/
1178void
1179spmExpand( const spmatrix_t *spm_in,
1180 spmatrix_t *spm_out )
1181{
1182 assert( spm_in->replicated != -1 );
1183
1184 switch(spm_in->flttype)
1185 {
1186 case SpmPattern:
1187 p_spmExpand(spm_in, spm_out);
1188 break;
1189 case SpmFloat:
1190 s_spmExpand(spm_in, spm_out);
1191 break;
1192 case SpmComplex32:
1193 c_spmExpand(spm_in, spm_out);
1194 break;
1195 case SpmComplex64:
1196 z_spmExpand(spm_in, spm_out);
1197 break;
1198 case SpmDouble:
1199 default:
1200 d_spmExpand(spm_in, spm_out);
1201 }
1202}
1203
1204/**
1205 *******************************************************************************
1206 *
1207 * @brief Compute a matrix-vector product.
1208 *
1209 * Performs \f$ y = alpha * op(A) * x + beta * y \f$, where \f$ op(A) \f$ is one of
1210 *
1211 * \f$ op( A ) = A \f$ or \f$ op( A ) = A' \f$ or \f$ op( A ) = conjg( A' ) \f$
1212 *
1213 * alpha and beta are scalars, and x and y are vectors.
1214 *
1215 *******************************************************************************
1216 *
1217 * @param[in] trans
1218 * Specifies whether the matrix spm is transposed, not transposed or conjugate transposed:
1219 * - SpmTrans
1220 * - SpmNoTrans
1221 * - SpmConjTrans
1222 *
1223 * @param[in] alpha
1224 * alpha specifies the scalar alpha.
1225 *
1226 * @param[in] spm
1227 * The SpmGeneral spm.
1228 *
1229 * @param[in] x
1230 * The vector x.
1231 *
1232 * @param[in] beta
1233 * beta specifies the scalar beta.
1234 *
1235 * @param[inout] y
1236 * The vector y.
1237 *
1238 *******************************************************************************
1239 *
1240 * @retval SPM_SUCCESS if the y vector has been computed successfully,
1241 * @retval SPM_ERR_BADPARAMETER otherwise.
1242 *
1243 *******************************************************************************/
1244int
1246 double alpha,
1247 const spmatrix_t *spm,
1248 const void *x,
1249 double beta,
1250 void *y )
1251{
1252 spmatrix_t *espm = (spmatrix_t*)spm;
1253 int rc = SPM_SUCCESS;
1254
1255 if ( (spm->fmttype != SpmCSC) && (spm->fmttype != SpmCSR) && (spm->fmttype != SpmIJV) ) {
1256 return SPM_ERR_BADPARAMETER;
1257 }
1258 if ( spm->flttype == SpmPattern ) {
1259 return SPM_ERR_BADPARAMETER;
1260 }
1261
1262 assert( spm->replicated != -1 );
1263
1264 switch (spm->flttype) {
1265 case SpmFloat:
1266 rc = spm_sspmv( trans, alpha, espm, x, 1, beta, y, 1 );
1267 break;
1268 case SpmComplex32:
1269 rc = spm_cspmv( trans, alpha, espm, x, 1, beta, y, 1 );
1270 break;
1271 case SpmComplex64:
1272 rc = spm_zspmv( trans, alpha, espm, x, 1, beta, y, 1 );
1273 break;
1274 case SpmDouble:
1275 default:
1276 rc = spm_dspmv( trans, alpha, espm, x, 1, beta, y, 1 );
1277 }
1278
1279 if ( spm != espm ) {
1280 spmExit( espm );
1281 free(espm);
1282 }
1283 return rc;
1284}
1285
1286/**
1287 *******************************************************************************
1288 *
1289 * @brief Compute a matrix-matrix product.
1290 *
1291 * y = alpha * op(A) * B + beta * C
1292 *
1293 * where op(A) is one of:
1294 *
1295 * op( A ) = A or op( A ) = A' or op( A ) = conjg( A' )
1296 *
1297 * alpha and beta are scalars, and x and y are vectors.
1298 *
1299 *******************************************************************************
1300 *
1301 * @param[in] trans
1302 * Specifies whether the matrix spm is transposed, not transposed or conjugate transposed:
1303 * - SpmTrans
1304 * - SpmNoTrans
1305 * - SpmConjTrans
1306 *
1307 * @param[in] n
1308 * The number of columns of the matrices B and C.
1309 *
1310 * @param[in] alpha
1311 * alpha specifies the scalar alpha.
1312 *
1313 * @param[in] A
1314 * The square sparse matrix A
1315 *
1316 * @param[in] B
1317 * The matrix B of size ldb-by-n
1318 *
1319 * @param[in] ldb
1320 * The leading dimension of the matrix B. ldb >= max( A->nexp, 1 )
1321 *
1322 * @param[in] beta
1323 * beta specifies the scalar beta.
1324 *
1325 * @param[inout] C
1326 * The matrix C of size ldc-by-n
1327 *
1328 * @param[in] ldc
1329 * The leading dimension of the matrix C. ldc >= max( A->nexp, 1 )
1330 *
1331 *******************************************************************************
1332 *
1333 * @retval SPM_SUCCESS if the y vector has been computed successfully,
1334 * @retval SPM_ERR_BADPARAMETER otherwise.
1335 *
1336 *******************************************************************************/
1337int
1339 spm_int_t n,
1340 double alpha,
1341 const spmatrix_t *A,
1342 const void *B,
1343 spm_int_t ldb,
1344 double beta,
1345 void *C,
1346 spm_int_t ldc )
1347{
1348 spmatrix_t *espm = (spmatrix_t*)A;
1349 int rc = SPM_SUCCESS;
1350
1351 if ( ldb < spm_imax( 1, A->nexp ) ) {
1352 fprintf( stderr, "spmMatMat: ldb must be >= max( 1, A->nexp )\n" );
1353 return SPM_ERR_BADPARAMETER;
1354 }
1355 if ( ldc < spm_imax( 1, A->nexp ) ) {
1356 fprintf( stderr, "spmMatMat: ldc must be >= max( 1, A->nexp )\n" );
1357 return SPM_ERR_BADPARAMETER;
1358 }
1359
1360 assert( A->replicated != -1 );
1361
1362 switch (A->flttype) {
1363 case SpmFloat:
1364 rc = spm_sspmm( SpmLeft, trans, SpmNoTrans, n, alpha, espm, B, ldb, beta, C, ldc );
1365 break;
1366 case SpmComplex32:
1367 rc = spm_cspmm( SpmLeft, trans, SpmNoTrans, n, alpha, espm, B, ldb, beta, C, ldc );
1368 break;
1369 case SpmComplex64:
1370 rc = spm_zspmm( SpmLeft, trans, SpmNoTrans, n, alpha, espm, B, ldb, beta, C, ldc );
1371 break;
1372 case SpmDouble:
1373 default:
1374 rc = spm_dspmm( SpmLeft, trans, SpmNoTrans, n, alpha, espm, B, ldb, beta, C, ldc );
1375 break;
1376 }
1377
1378 if ( A != espm ) {
1379 spmExit( espm );
1380 free(espm);
1381 }
1382 return rc;
1383}
1384
1385/**
1386 *******************************************************************************
1387 *
1388 * @brief Check the backward error, and the forward error if x0 is provided.
1389 *
1390 *******************************************************************************
1391 *
1392 * @param[in] eps
1393 * The epsilon threshold used for the refinement step. -1. to use the
1394 * machine precision.
1395 *
1396 * @param[in] nrhs
1397 * Defines the number of right hand side that must be generated.
1398 *
1399 * @param[in] spm
1400 * The sparse matrix used to generate the right hand side, and the
1401 * solution of the full problem.
1402 *
1403 * @param[inout] x0
1404 * If x0 != NULL, the forward error is computed.
1405 * On exit, x0 stores x0-x
1406 *
1407 * @param[in] ldx0
1408 * Defines the leading dimension of x0 when multiple right hand sides
1409 * are available. ldx0 >= max( 1, spm->nexp ).
1410 *
1411 * @param[inout] b
1412 * b is a matrix of size at least ldb * nrhs.
1413 * On exit, b stores Ax-b.
1414 *
1415 * @param[in] ldb
1416 * Defines the leading dimension of b when multiple right hand sides
1417 * are available. ldb >= max( 1, spm->nexp ).
1418 *
1419 * @param[in] x
1420 * Contains the solution computed by the solver.
1421 *
1422 * @param[in] ldx
1423 * Defines the leading dimension of x when multiple right hand sides
1424 * are available. ldx >= max( 1, spm->nexp ).
1425 *
1426 *******************************************************************************
1427 *
1428 * @retval SPM_SUCCESS if the tests are succesfull
1429 * @retval SPM_ERR_BADPARAMETER if the input matrix is incorrect
1430 * @retval 1, if one of the test failed
1431 *
1432 *******************************************************************************/
1433int
1434spmCheckAxb( double eps,
1435 spm_int_t nrhs,
1436 const spmatrix_t *spm,
1437 void *x0,
1438 spm_int_t ldx0,
1439 void *b,
1440 spm_int_t ldb,
1441 const void *x,
1442 spm_int_t ldx )
1443{
1444 static int (*ptrfunc[4])( double, int, const spmatrix_t *,
1445 void *, int, void *, int, const void *, int ) =
1446 {
1448 };
1449
1450 int id = spm->flttype - SpmFloat;
1451
1452 if ( (x0 != NULL) && (ldx0 < spm_imax( 1, spm->nexp )) ) {
1453 fprintf( stderr, "spmCheckAxb: ldx0 must be >= max( 1, spm->nexp )\n" );
1454 return SPM_ERR_BADPARAMETER;
1455 }
1456 if ( ldb < spm_imax( 1, spm->nexp ) ) {
1457 fprintf( stderr, "spmCheckAxb: ldb must be >= max( 1, spm->nexp )\n" );
1458 return SPM_ERR_BADPARAMETER;
1459 }
1460 if ( ldx < spm_imax( 1, spm->nexp ) ) {
1461 fprintf( stderr, "spmCheckAxb: ldx must be >= max( 1, spm->nexp )\n" );
1462 return SPM_ERR_BADPARAMETER;
1463 }
1464
1465 if ( (id < 0) || (id > 3) ) {
1466 return SPM_ERR_BADPARAMETER;
1467 }
1468 else {
1469 assert( spm->replicated != -1 );
1470
1471 return ptrfunc[id]( eps, nrhs, spm, x0, ldx0, b, ldb, x, ldx );
1472 }
1473}
1474
1475/**
1476 *******************************************************************************
1477 *
1478 * @brief Scale the spm.
1479 *
1480 * A = alpha * A
1481 *
1482 *******************************************************************************
1483 *
1484 * @param[in] alpha
1485 * The scaling parameter.
1486 *
1487 * @param[inout] spm
1488 * The sparse matrix to scal.
1489 *
1490 *******************************************************************************/
1491void
1492spmScal( double alpha,
1493 spmatrix_t *spm )
1494{
1495 assert( spm->replicated != -1 );
1496 switch(spm->flttype)
1497 {
1498 case SpmPattern:
1499 break;
1500 case SpmFloat:
1501 s_spmScal((float)alpha, spm);
1502 break;
1503 case SpmComplex32:
1504 c_spmScal((float)alpha, spm);
1505 break;
1506 case SpmComplex64:
1507 z_spmScal(alpha, spm);
1508 break;
1509 case SpmDouble:
1510 default:
1511 d_spmScal(alpha, spm);
1512 }
1513}
1514
1515/**
1516 *******************************************************************************
1517 *
1518 * @copydoc spmScal
1519 * @details Deprecated function replaced by spmScal().
1520 *
1521 *******************************************************************************/
1522void
1523spmScalMatrix( double alpha,
1524 spmatrix_t *spm )
1525{
1526 spmScal( alpha, spm );
1527}
1528
1529/**
1530 *******************************************************************************
1531 *
1532 * @brief Scale a vector associated to a sparse matrix. Deprecated function
1533 * replaced by spmScalVec() or spmScalMat().
1534 *
1535 * x = alpha * x
1536 *
1537 *******************************************************************************
1538 *
1539 * @param[in] alpha
1540 * The scaling parameter.
1541 *
1542 * @param[in] spm
1543 * The sparse matrix structure associated to the vector to describe the
1544 * size, the arithmetic used and the distribution of x.
1545 *
1546 * @param[inout] x
1547 * The local vector to scal of size ( 1 + (spm->nexp-1) * abs(incx) ),
1548 * and of type defined by spm->flttype.
1549 *
1550 * @param[in] incx
1551 * Storage spacing between elements of x. Usually 1, unless corner
1552 * cases (see blas/lapack).
1553 *
1554 *******************************************************************************/
1555void
1556spmScalVec( double alpha,
1557 const spmatrix_t *spm,
1558 void *x,
1559 spm_int_t incx )
1560{
1561 spm_int_t n = spm->nexp;
1562
1563 assert( spm->replicated != -1 );
1564 switch( spm->flttype )
1565 {
1566 case SpmPattern:
1567 break;
1568 case SpmFloat:
1569 cblas_sscal( n, (float)alpha, x, incx );
1570 break;
1571 case SpmComplex32:
1572 cblas_csscal( n, (float)alpha, x, incx );
1573 break;
1574 case SpmComplex64:
1575 cblas_zdscal( n, alpha, x, incx );
1576 break;
1577 case SpmDouble:
1578 default:
1579 cblas_dscal( n, alpha, x, incx );
1580 }
1581}
1582
1583/**
1584 *******************************************************************************
1585 *
1586 * @brief Scale a matrix associated to a sparse matrix.
1587 *
1588 * A = alpha * A
1589 * Rk: We do consider that the matrix A is stored in column major, and
1590 * distributed by rows similarly to the distribution of the spm if in
1591 * distributed.
1592 *
1593 *******************************************************************************
1594 *
1595 * @param[in] alpha
1596 * The scaling parameter.
1597 *
1598 * @param[in] spm
1599 * The sparse matrix structure associated to the matrix to describe the
1600 * size, the arithmetic used and the distribution of A.
1601 *
1602 * @param[in] n
1603 * The number of columns of the matrix A.
1604 *
1605 * @param[inout] A
1606 * The local matrix A of size LDA -by- n.
1607 *
1608 * @param[in] lda
1609 * The leading dimension of the matrix A. lda >= max( 1, spm->nexp ).
1610 *
1611 *******************************************************************************/
1612void
1613spmScalMat( double alpha,
1614 const spmatrix_t *spm,
1615 spm_int_t n,
1616 void *A,
1617 spm_int_t lda )
1618{
1619 spm_int_t m = spm->nexp;
1620
1621 assert( spm->replicated != -1 );
1622 switch( spm->flttype )
1623 {
1624 case SpmPattern:
1625 break;
1626 case SpmFloat:
1627 LAPACKE_slascl_work( LAPACK_COL_MAJOR, 'G', 1, 1, 1., alpha,
1628 m, n, (float *)A, lda );
1629 break;
1630 case SpmComplex32:
1631 LAPACKE_clascl_work( LAPACK_COL_MAJOR, 'G', 1, 1, 1., alpha,
1632 m, n, (spm_complex32_t *)A, lda );
1633 break;
1634 case SpmComplex64:
1635 LAPACKE_zlascl_work( LAPACK_COL_MAJOR, 'G', 1, 1, 1., alpha,
1636 m, n, (spm_complex64_t *)A, lda );
1637 break;
1638 case SpmDouble:
1639 default:
1640 LAPACKE_dlascl_work( LAPACK_COL_MAJOR, 'G', 1, 1, 1., alpha,
1641 m, n, (double *)A, lda );
1642 }
1643}
1644
1645/**
1646 *******************************************************************************
1647 *
1648 * @brief Scale a vector according to the spm type.
1649 *
1650 * x = alpha * x
1651 *
1652 *******************************************************************************
1653 *
1654 * @param[in] flt
1655 * Datatype of the elements in the vector that must be:
1656 * @arg SpmFloat
1657 * @arg SpmDouble
1658 * @arg SpmComplex32
1659 * @arg SpmComplex64
1660 *
1661 * @param[in] n
1662 * Number of elements in the input vectors
1663 *
1664 * @param[in] alpha
1665 * The scaling parameter.
1666 *
1667 * @param[inout] x
1668 * The vector to scal of size ( 1 + (n-1) * abs(incx) ), and of type
1669 * defined by flt.
1670 *
1671 * @param[in] incx
1672 * Storage spacing between elements of x.
1673 *
1674 *******************************************************************************/
1675void
1677 double alpha,
1678 spm_int_t n,
1679 void *x,
1680 spm_int_t incx )
1681{
1682 switch( flt )
1683 {
1684 case SpmPattern:
1685 break;
1686 case SpmFloat:
1687 cblas_sscal( n, (float)alpha, x, incx );
1688 break;
1689 case SpmComplex32:
1690 cblas_csscal( n, (float)alpha, x, incx );
1691 break;
1692 case SpmComplex64:
1693 cblas_zdscal( n, alpha, x, incx );
1694 break;
1695 case SpmDouble:
1696 default:
1697 cblas_dscal( n, alpha, x, incx );
1698 }
1699}
1700
1701/**
1702 *******************************************************************************
1703 *
1704 * @brief Generate a set of vectors associated to a given matrix.
1705 *
1706 *******************************************************************************
1707 *
1708 * @param[in] type
1709 * Defines how to compute the vector b.
1710 * @arg SpmRhsOne: x = 1 [ + I ]
1711 * @arg SpmRhsI: x = i [ + i * I ]
1712 * @arg SpmRhsRndX: x is random
1713 * @arg SpmRhsRndB: x is random
1714 *
1715 * @param[in] nrhs
1716 * Number of columns of the generated vectors
1717 *
1718 * @param[in] spm
1719 * The sparse matrix used to generate the right hand side, and the
1720 * solution of the full problem.
1721 *
1722 * @param[in] alpha
1723 * Scaling factor of x.
1724 *
1725 * @param[in] seed
1726 * The seed for the random generator
1727 *
1728 * @param[out] A
1729 * The generated matrix. It has to be preallocated with a size
1730 * lda -by- nrhs.
1731 *
1732 * @param[in] lda
1733 * Defines the leading dimension of A when multiple right hand sides
1734 * are available. lda >= spm->nexp.
1735 *
1736 *******************************************************************************
1737 *
1738 * @retval SPM_SUCCESS if the b vector has been computed successfully,
1739 * @retval SPM_ERR_BADPARAMETER otherwise.
1740 *
1741 *******************************************************************************/
1742int
1744 spm_int_t nrhs,
1745 const spmatrix_t *spm,
1746 void *alpha,
1747 unsigned long long int seed,
1748 void *A,
1749 spm_int_t lda )
1750{
1751 static int (*ptrfunc[4])( spm_rhstype_t, int,
1752 const spmatrix_t *,
1753 void *, unsigned long long int,
1754 void *, int ) =
1755 {
1757 };
1758 int id = spm->flttype - SpmFloat;
1759
1760 if ( lda < spm_imax( 1, spm->nexp ) ) {
1761 fprintf( stderr, "spmGenMat: lda(%ld) must be >= max( 1, spm->nexp(%ld) )\n",
1762 (long)lda, (long)spm->nexp );
1763 return SPM_ERR_BADPARAMETER;
1764 }
1765
1766 if ( (id < 0) || (id > 3) ) {
1767 return SPM_ERR_BADPARAMETER;
1768 }
1769 else {
1770 assert( spm->replicated != -1 );
1771 return ptrfunc[id]( type, nrhs, spm, alpha, seed, A, lda );
1772 }
1773}
1774
1775/**
1776 *******************************************************************************
1777 *
1778 * @brief Generate a vector associated to a given matrix.
1779 *
1780 *******************************************************************************
1781 *
1782 * @param[in] type
1783 * Defines how to compute the vector b.
1784 * @arg SpmRhsOne: x = 1 [ + I ]
1785 * @arg SpmRhsI: x = i [ + i * I ]
1786 * @arg SpmRhsRndX: x is random
1787 * @arg SpmRhsRndB: x is random
1788 *
1789 * @param[in] spm
1790 * The sparse matrix used to generate the right hand side, and the
1791 * solution of the full problem.
1792 *
1793 * @param[in] alpha
1794 * Scaling factor of x.
1795 *
1796 * @param[in] seed
1797 * The seed for the random generator
1798 *
1799 * @param[out] x
1800 * The generated vector. Its size has to be preallocated.
1801 *
1802 * @param[in] incx
1803 * Defines the increment of x. Must be superior to 0.
1804 * @warning For the moement, only incx = 1 is supported..
1805 *
1806 *******************************************************************************
1807 *
1808 * @retval SPM_SUCCESS if the b vector has been computed successfully,
1809 * @retval SPM_ERR_BADPARAMETER otherwise.
1810 *
1811 *******************************************************************************/
1812int
1814 const spmatrix_t *spm,
1815 void *alpha,
1816 unsigned long long int seed,
1817 void *x,
1818 spm_int_t incx )
1819{
1820 if( incx != 1 ) {
1821 return SPM_ERR_BADPARAMETER;
1822 }
1823
1824 return spmGenMat( type, 1, spm, alpha, seed, x, spm_imax( 1, spm->nexp ) );
1825}
1826
1827/**
1828 * @}
1829 */
1830
1831/**
1832 *******************************************************************************
1833 *
1834 * @ingroup spm_dev_mpi
1835 *
1836 * @brief Generate a continuous loc2glob array on each node.
1837 *
1838 *******************************************************************************
1839 *
1840 * @param[in] spm
1841 * The allocated spm with the correct gN field.
1842 *
1843 * @param[out] l2g_ptr
1844 * Pointer to the loc2glob array that will be allocated and initialized.
1845 *
1846 *******************************************************************************
1847 *
1848 * @retval The number of unknowns of the local spm.
1849 *
1850 *******************************************************************************/
1853 spm_int_t **l2g_ptr )
1854{
1855 spm_int_t i, size, begin, end, *loc2glob;
1856 spm_int_t baseval = spm->baseval;
1857 int clustnum, clustnbr;
1858
1859 clustnum = spm->clustnum;
1860 clustnbr = spm->clustnbr;
1861
1862 size = spm->gN / clustnbr;
1863 begin = size * clustnum + spm_imin( clustnum, spm->gN % clustnbr );
1864 end = size * (clustnum+1) + spm_imin( clustnum+1, spm->gN % clustnbr );
1865 size = end - begin;
1866
1867 *l2g_ptr = malloc( size * sizeof(spm_int_t) );
1868 loc2glob = *l2g_ptr;
1869
1870 for ( i=begin; i<end; i++, loc2glob++ )
1871 {
1872 *loc2glob = i+baseval;
1873 }
1874
1875 return size;
1876}
1877
1878/**
1879 *******************************************************************************
1880 *
1881 * @ingroup spm_dev_mpi
1882 *
1883 * @brief Computes the glob2loc array if needed, and returns it
1884 *
1885 *******************************************************************************
1886 *
1887 * @param[inout] spm
1888 * The sparse matrix for which the glob2loc array must be computed.
1889 *
1890 *******************************************************************************
1891 *
1892 * @retval The pointer to the glob2loc array of the spm.
1893 *
1894 *******************************************************************************/
1895spm_int_t *
1897{
1898 spm_int_t *glob2loc = NULL;
1899
1900 if ( (spm->clustnbr == 1) ||
1901 (spm->replicated) ||
1902 (spm->glob2loc != NULL) )
1903 {
1904 return spm->glob2loc;
1905 }
1906
1907#if defined(SPM_WITH_MPI)
1908 {
1909 spm_int_t c, il, ig, n, nr = 0;
1910 spm_int_t *loc2glob, *loc2globptr = NULL;
1911 spm_int_t *glob2locptr;
1912
1913 /* Make sure fields are computed */
1914 assert( spm->gN != -1 );
1915
1916 glob2locptr = malloc( spm->gN * sizeof(spm_int_t) );
1917 glob2loc = glob2locptr;
1918
1919#if !defined(NDEBUG)
1920 {
1921 /* Initialize to incorrect values */
1922 for( ig=0; ig<spm->gN; ig++ ) {
1923 glob2loc[ig] = - spm->clustnbr - 1;
1924 }
1925 }
1926#endif
1927
1928 /* Initialize glob2loc with baseval shift to avoid extra calculation in loop */
1929 glob2loc = glob2locptr - spm->baseval;
1930
1931 for( c=0; c<spm->clustnbr; c++ ) {
1932 if ( c == spm->clustnum ) {
1933 n = spm->n;
1934 loc2glob = spm->loc2glob;
1935
1936 /* Let's send the local size */
1937 MPI_Bcast( &n, 1, SPM_MPI_INT, c, spm->comm );
1938
1939 /* Let's send the loc2glob and store the info in the array */
1940 if ( n > 0 )
1941 {
1942 MPI_Bcast( loc2glob, n, SPM_MPI_INT, c, spm->comm );
1943
1944 for(il=0; il<n; il++, loc2glob++) {
1945 ig = *loc2glob;
1946 glob2loc[ig] = il;
1947 }
1948 }
1949 }
1950 else {
1951 /* Let's recv the remote size */
1952 MPI_Bcast( &n, 1, SPM_MPI_INT, c, spm->comm );
1953
1954 if ( n > nr ) {
1955 spm_int_t *newptr;
1956 nr = n;
1957 newptr = realloc( loc2globptr, nr * sizeof(spm_int_t) );
1958 if ( newptr == NULL ) {
1959 free( loc2globptr );
1960 free( glob2locptr );
1961
1962 return NULL;
1963 }
1964 loc2globptr = newptr;
1965 }
1966 loc2glob = loc2globptr;
1967
1968 /* Let's recv the loc2glob and store the info in the array */
1969 if ( n > 0 )
1970 {
1971 MPI_Bcast( loc2glob, n, SPM_MPI_INT, c, spm->comm );
1972
1973 for(il=0; il<n; il++, loc2glob++) {
1974 ig = *loc2glob;
1975 glob2loc[ ig ] = - c - 1;
1976 }
1977 }
1978 }
1979 }
1980
1981 /* Restore glob2loc baseval shift */
1982 glob2loc = glob2locptr;
1983
1984 free( loc2globptr );
1985
1986#if !defined(NDEBUG)
1987 {
1988 const spm_int_t *g2l = glob2loc;
1989 /* Check that we have no more incorrect values */
1990 for( ig=0; ig<spm->gN; ig++, g2l++ ) {
1991 assert( *g2l != (- spm->clustnbr - 1) );
1992 }
1993 }
1994#endif
1995 }
1996#endif /* defined(SPM_WITH_MPI) */
1997
1998 return glob2loc;
1999}
2000
2001/**
2002 *******************************************************************************
2003 *
2004 * @ingroup spm_dev_mpi
2005 *
2006 * @brief Computes the glob2loc array if needed, and returns it
2007 *
2008 *******************************************************************************
2009 *
2010 * @param[inout] spm
2011 * The sparse matrix for which the glob2loc array must be computed.
2012 *
2013 *******************************************************************************
2014 *
2015 * @retval The pointer to the glob2loc array of the spm.
2016 *
2017 *******************************************************************************/
2018spm_int_t *
2020{
2021 if ( (spm->replicated) ||
2022 (spm->clustnbr == 1) ||
2023 (spm->glob2loc != NULL) )
2024 {
2025 return spm->glob2loc;
2026 }
2027
2028#if defined(SPM_WITH_MPI)
2029 {
2030 /* Make sure fields are computed */
2031 if ( spm->gN == -1 ) {
2033 }
2034
2035 spm->glob2loc = spm_get_glob2loc( spm );
2036 }
2037#endif /* defined(SPM_WITH_MPI) */
2038
2039 return spm->glob2loc;
2040}
2041
2042/**
2043 *******************************************************************************
2044 *
2045 * @ingroup spm_dev_mpi
2046 *
2047 * @brief Search the distribution pattern used in the spm structure.
2048 *
2049 *******************************************************************************
2050 *
2051 * @param[in] spm
2052 * The sparse matrix structure.
2053 *
2054 ********************************************************************************
2055 *
2056 * @return SpmDistByColumn if the distribution is column based.
2057 * SpmDistByRow if the distribution is row based.
2058 * (SpmDistByColumn|SpmDistByRow) if the matrix is not distributed.
2059 *
2060 *******************************************************************************/
2061int
2063{
2064 int distribution = 0;
2065
2066 /* The matrix is not distributed */
2067 if ( spm->replicated || (spm->clustnbr == 1) ) {
2068 distribution = ( SpmDistByColumn | SpmDistByRow );
2069 return distribution;
2070 }
2071 if ( spm->fmttype == SpmCSC ) {
2072 distribution = SpmDistByColumn;
2073 }
2074 else if ( spm->fmttype == SpmCSR ) {
2075 distribution = SpmDistByRow;
2076 }
2077 else {
2078 spm_int_t i, baseval;
2079 spm_int_t *colptr = spm->colptr;
2080 spm_int_t *rowptr = spm->rowptr;
2081 spm_int_t *glob2loc = spm->glob2loc;
2082
2083 distribution = SpmDistByColumn | SpmDistByRow;
2084 if ( !((spm->n == spm->gN) || (spm->n == 0)) )
2085 {
2086 baseval = spm->baseval;
2087 if ( glob2loc == NULL ) {
2088 glob2loc = spm_get_glob2loc( spm );
2089 }
2090 assert( glob2loc != NULL );
2091 for ( i = 0; i < spm->nnz; i++, colptr++, rowptr++ )
2092 {
2093 /*
2094 * If the global column index is not local
2095 * => row distribution
2096 */
2097 if ( glob2loc[*colptr - baseval] < 0 ) {
2098 distribution &= ~SpmDistByColumn;
2099 break;
2100 }
2101 /*
2102 * If the global row index is not local
2103 * => column distribution
2104 */
2105 if ( glob2loc[*rowptr - baseval] < 0 ) {
2106 distribution &= ~SpmDistByRow;
2107 break;
2108 }
2109 }
2110
2111 if ( (spm->glob2loc == NULL) && glob2loc ) {
2112 free( glob2loc );
2113 }
2114 }
2115
2116#if defined(SPM_WITH_MPI)
2117 {
2118 MPI_Allreduce( MPI_IN_PLACE, &distribution, 1, MPI_INT,
2119 MPI_BAND, spm->comm );
2120 /*
2121 * If a matrix is distributed it cannot be distributed by row AND
2122 * column, unless a single node has all the matrix
2123 */
2124 assert( ( (spm->n == 0) || (spm->n == spm->gN) ) ||
2125 (( (spm->n != 0) && (spm->n != spm->gN) ) && (distribution != 0)) );
2126 }
2127#endif
2128 }
2129
2130 return distribution;
2131}
2132
2133/**
2134 *******************************************************************************
2135 *
2136 * @ingroup spm_dev_check
2137 *
2138 * @brief Create an array that represents the shift for each sub-element
2139 * of the original multidof value array.
2140 *
2141 *******************************************************************************
2142 *
2143 * @param[in] spm
2144 * The sparse matrix structure.
2145 *
2146 ********************************************************************************
2147 *
2148 * @return An array of size nnz+1 that stores the indices of each A(i,j)
2149 * subblock in the spm->values array
2150 *
2151 *******************************************************************************/
2152spm_int_t *
2154{
2155 spm_int_t i, j, ig, jg;
2156 spm_int_t baseval, n;
2157 spm_int_t dof, dofi, dofj;
2158 const spm_int_t *colptr = spm->colptr;
2159 const spm_int_t *rowptr = spm->rowptr;
2160 const spm_int_t *dofs = spm->dofs;
2161 const spm_int_t *loc2glob = spm->loc2glob;
2162 spm_int_t *values = malloc( (spm->n + 1) * sizeof(spm_int_t));
2163 spm_int_t *valtmp = values;
2164
2165 values[0] = 0;
2166 baseval = spm->baseval;
2167 dof = spm->dof;
2168 switch (spm->fmttype)
2169 {
2170 case SpmCSR:
2171 colptr = spm->rowptr;
2172 rowptr = spm->colptr;
2173
2174 spm_attr_fallthrough;
2175
2176 case SpmCSC:
2177 n = spm->n;
2178 loc2glob = spm->loc2glob;
2179 for ( j = 0; j < n; j++, colptr++, loc2glob++, valtmp++ )
2180 {
2181 jg = spm->replicated ? j : *loc2glob - baseval;
2182 dofj = (dof > 0) ? dof : dofs[jg+1] - dofs[jg];
2183
2184 dofi = 0;
2185 for ( i = colptr[0]; i < colptr[1]; i++, rowptr++ )
2186 {
2187 ig = *rowptr - baseval;
2188 dofi += (dof > 0) ? dof : dofs[ig+1] - dofs[ig];
2189 }
2190 valtmp[1] = valtmp[0] + (dofj*dofi);
2191 }
2192 break;
2193
2194 case SpmIJV:
2195 /* Available only for CSC/CSR matrices */
2196 assert( 0 );
2197 break;
2198 }
2199 assert((valtmp - values) == spm->n);
2200 assert( values[spm->n] == spm->nnzexp );
2201 return values;
2202}
2203
2204/**
2205 *******************************************************************************
2206 *
2207 * @ingroup spm_dev_check
2208 *
2209 * @brief Create an array that represents the shift for each sub-element
2210 * of the original multidof value array.
2211 *
2212 *******************************************************************************
2213 *
2214 * @param[in] spm
2215 * The sparse matrix structure.
2216 *
2217 ********************************************************************************
2218 *
2219 * @return An array of size nnz+1 that stores the indices of each A(i,j)
2220 * subblock in the spm->values array
2221 *
2222 *******************************************************************************/
2223spm_int_t *
2225{
2226 spm_int_t i, j, ig, jg;
2227 spm_int_t baseval, n;
2228 spm_int_t dof, dofi, dofj;
2229 const spm_int_t *colptr = spm->colptr;
2230 const spm_int_t *rowptr = spm->rowptr;
2231 const spm_int_t *dofs = spm->dofs;
2232 const spm_int_t *loc2glob = spm->loc2glob;
2233 spm_int_t *values = malloc( (spm->nnz + 1) * sizeof(spm_int_t));
2234 spm_int_t *valtmp = values;
2235
2236 values[0] = 0;
2237 baseval = spm->baseval;
2238 dof = spm->dof;
2239 switch (spm->fmttype)
2240 {
2241 case SpmCSR:
2242 colptr = spm->rowptr;
2243 rowptr = spm->colptr;
2244
2245 spm_attr_fallthrough;
2246
2247 case SpmCSC:
2248 n = spm->n;
2249 loc2glob = spm->loc2glob;
2250 for ( j = 0; j < n; j++, colptr++, loc2glob++ )
2251 {
2252 jg = spm->replicated ? j : *loc2glob - baseval;
2253 dofj = (dof > 0) ? dof : dofs[jg+1] - dofs[jg];
2254 for ( i = colptr[0]; i < colptr[1]; i++, rowptr++, valtmp++ )
2255 {
2256 ig = *rowptr - baseval;
2257 dofi = (dof > 0) ? dof : dofs[ig+1] - dofs[ig];
2258
2259 valtmp[1] = valtmp[0] + (dofj*dofi);
2260 }
2261 }
2262 break;
2263
2264 case SpmIJV:
2265 n = spm->nnz;
2266 for ( j = 0; j < n; j++, colptr++, rowptr++, valtmp++ )
2267 {
2268 jg = *colptr - baseval;
2269 dofj = (dof > 0) ? dof : dofs[jg+1] - dofs[jg];
2270 ig = *rowptr - baseval;
2271 dofi = (dof > 0) ? dof : dofs[ig+1] - dofs[ig];
2272
2273 valtmp[1] = valtmp[0] + (dofj*dofi);
2274 }
2275 break;
2276 }
2277 assert((valtmp - values) == spm->nnz);
2278 assert( values[spm->nnz] == spm->nnzexp );
2279 return values;
2280}
2281
2282/**
2283 *******************************************************************************
2284 *
2285 * @brief Return the current number of threads used for blas calls.
2286 *
2287 *******************************************************************************
2288 *
2289 * @return The number of threads.
2290 *
2291 *******************************************************************************/
2292int
2294{
2295#if defined(HAVE_BLI_THREAD_SET_NUM_THREADS)
2296 return bli_thread_get_num_threads();
2297#elif defined(HAVE_MKL_SET_NUM_THREADS)
2298 return mkl_get_max_threads();
2299#elif defined(HAVE_OPENBLAS_SET_NUM_THREADS)
2300 return openblas_get_num_threads();
2301#else
2302 return 1;
2303#endif
2304}
2305
2306/**
2307 *******************************************************************************
2308 *
2309 * @brief Set the number of threads for blas calls (BLIS, MKL, OpenBLAS) and
2310 * return the previous number of blas threads.
2311 *
2312 * @param[in] nt
2313 * Number of threads.
2314 *
2315 *******************************************************************************
2316 *
2317 * @return The previous number of blas threads.
2318 *
2319 *******************************************************************************/
2320int
2322{
2323 int prevnt = spmBlasGetNumThreads();
2324#if defined(HAVE_BLI_THREAD_SET_NUM_THREADS)
2325 bli_thread_set_num_threads( nt );
2326#elif defined(HAVE_MKL_SET_NUM_THREADS)
2327 mkl_set_num_threads( nt );
2328#elif defined(HAVE_OPENBLAS_SET_NUM_THREADS)
2329 openblas_set_num_threads( nt );
2330#endif
2331 (void)nt;
2332 return prevnt;
2333}
2334
2335/**
2336 *******************************************************************************
2337 *
2338 * @brief Set the number of threads for blas calls (BLIS, MKL, OpenBLAS) to 1
2339 * and return the previous number of blas threads.
2340 *
2341 *******************************************************************************
2342 *
2343 * @return The previous number of blas threads.
2344 *
2345 *******************************************************************************/
2346int
2348{
2349 return spmBlasSetNumThreads( 1 );
2350}
#define LAPACKE_clascl_work(_dir_, _uplo_, _kl_, _ku_, _cfrom_, _cto_, _m_, _n_, _A_, _lda_)
Alias if Lapacke zlscl is not available.
#define LAPACKE_dlascl_work(_dir_, _uplo_, _kl_, _ku_, _cfrom_, _cto_, _m_, _n_, _A_, _lda_)
Alias if Lapacke zlscl is not available.
static size_t spm_size_of(spm_coeftype_t type)
Double datatype that is not converted through precision generator functions.
Definition datatypes.h:209
static spm_int_t spm_imin(spm_int_t a, spm_int_t b)
Internal function to compute min(a,b).
Definition datatypes.h:97
static spm_int_t spm_imax(spm_int_t a, spm_int_t b)
Internal function to compute max(a,b).
Definition datatypes.h:119
#define SpmDistByRow
Definition const.h:43
enum spm_rhstype_e spm_rhstype_t
How to generate RHS.
enum spm_coeftype_e spm_coeftype_t
Arithmetic types.
#define SpmDistByColumn
Distribution of the matrix storage.
Definition const.h:42
enum spm_normtype_e spm_normtype_t
Norms.
enum spm_trans_e spm_trans_t
Transpostion.
@ SPM_ERR_BADPARAMETER
Definition const.h:89
@ SPM_SUCCESS
Definition const.h:82
@ SpmNoTrans
Definition const.h:155
@ SpmColMajor
Definition const.h:148
@ SpmComplex64
Definition const.h:66
@ SpmDouble
Definition const.h:64
@ SpmFloat
Definition const.h:63
@ SpmComplex32
Definition const.h:65
@ SpmPattern
Definition const.h:62
@ SpmGeneral
Definition const.h:165
@ SpmCSC
Definition const.h:73
@ SpmCSR
Definition const.h:74
@ SpmIJV
Definition const.h:75
@ SpmLeft
Definition const.h:191
void d_spmSort(spmatrix_t *spm)
This routine sorts the spm matrix.
Definition d_spm_sort.c:303
void z_spmSort(spmatrix_t *spm)
This routine sorts the spm matrix.
Definition z_spm_sort.c:303
spm_int_t * spm_get_value_idx_by_elt(const spmatrix_t *spm)
Create an array that represents the shift for each sub-element of the original multidof value array.
Definition spm.c:2224
spm_int_t d_spmMergeDuplicate(spmatrix_t *spm)
This routine merge the multiple entries in a sparse matrix by summing their values together.
spm_int_t s_spmMergeDuplicate(spmatrix_t *spm)
This routine merge the multiple entries in a sparse matrix by summing their values together.
void c_spmSort(spmatrix_t *spm)
This routine sorts the spm matrix.
Definition c_spm_sort.c:303
spm_int_t c_spmMergeDuplicate(spmatrix_t *spm)
This routine merge the multiple entries in a sparse matrix by summing their values together.
spm_int_t p_spmMergeDuplicate(spmatrix_t *spm)
This routine merge the multiple entries in a sparse matrix by summing their values together.
void p_spmSort(spmatrix_t *spm)
This routine sorts the spm matrix.
Definition p_spm_sort.c:303
void s_spmSort(spmatrix_t *spm)
This routine sorts the spm matrix.
Definition s_spm_sort.c:303
spm_int_t z_spmMergeDuplicate(spmatrix_t *spm)
This routine merge the multiple entries in a sparse matrix by summing their values together.
spm_int_t * spm_get_value_idx_by_col(const spmatrix_t *spm)
Create an array that represents the shift for each sub-element of the original multidof value array.
Definition spm.c:2153
int c_spmConvertCSR2CSC(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in CSC format.
int z_spmConvertCSR2CSC(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in CSC format.
int d_spmConvertIJV2CSC(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSC format.
int p_spmConvertIJV2CSR(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSR format.
int d_spmConvertCSR2IJV(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in IJV format.
void s_spm2dense(const spmatrix_t *spm, float *A)
Convert a sparse matrix into a dense matrix.
int d_spmConvertCSR2CSC(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in CSC format.
int p_spmConvertCSR2CSC(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in CSC format.
int c_spmConvertIJV2CSR(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSR format.
int z_spmConvertCSR2IJV(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in IJV format.
int p_spmConvertCSR2IJV(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in IJV format.
int s_spmConvertIJV2CSC(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSC format.
void c_spm2dense(const spmatrix_t *spm, spm_complex32_t *A)
Convert a sparse matrix into a dense matrix.
int p_spmConvertCSC2CSR(spmatrix_t *spm)
Conversion routines.
int z_spmConvertCSC2IJV(spmatrix_t *spm)
Convert a matrix in CSC format to a matrix in IJV format.
int c_spmConvertCSC2IJV(spmatrix_t *spm)
Convert a matrix in CSC format to a matrix in IJV format.
int d_spmConvertCSC2IJV(spmatrix_t *spm)
Convert a matrix in CSC format to a matrix in IJV format.
int z_spmConvertIJV2CSR(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSR format.
int s_spmConvertCSC2IJV(spmatrix_t *spm)
Convert a matrix in CSC format to a matrix in IJV format.
int s_spmConvertIJV2CSR(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSR format.
int p_spmConvertIJV2CSC(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSC format.
int p_spmConvertCSC2IJV(spmatrix_t *spm)
Convert a matrix in CSC format to a matrix in IJV format.
int s_spmConvertCSC2CSR(spmatrix_t *spm)
convert a matrix in CSC format to a matrix in CSR format.
int c_spmConvertCSR2IJV(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in IJV format.
int d_spmConvertCSC2CSR(spmatrix_t *spm)
convert a matrix in CSC format to a matrix in CSR format.
int c_spmConvertIJV2CSC(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSC format.
int d_spmConvertIJV2CSR(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSR format.
int c_spmConvertCSC2CSR(spmatrix_t *spm)
convert a matrix in CSC format to a matrix in CSR format.
int z_spmConvertCSC2CSR(spmatrix_t *spm)
convert a matrix in CSC format to a matrix in CSR format.
int z_spmConvertIJV2CSC(spmatrix_t *spm)
convert a matrix in IJV format to a matrix in CSC format.
void z_spm2dense(const spmatrix_t *spm, spm_complex64_t *A)
Convert a sparse matrix into a dense matrix.
int s_spmConvertCSR2CSC(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in CSC format.
int s_spmConvertCSR2IJV(spmatrix_t *spm)
convert a matrix in CSR format to a matrix in IJV format.
void d_spm2dense(const spmatrix_t *spm, double *A)
Convert a sparse matrix into a dense matrix.
void s_spmExpand(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Expand a single dof sparse matrix to a multi-dofs sparse matrix.
void c_spmExpand(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Expand a single dof sparse matrix to a multi-dofs sparse matrix.
void p_spmExpand(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Expand a single dof sparse matrix to a multi-dofs sparse matrix.
void d_spmExpand(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Expand a single dof sparse matrix to a multi-dofs sparse matrix.
void z_spmExpand(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Expand a single dof sparse matrix to a multi-dofs sparse matrix.
int spm_zspmv(spm_trans_t trans, spm_complex64_t alpha, const spmatrix_t *A, const spm_complex64_t *x, spm_int_t incx, spm_complex64_t beta, spm_complex64_t *y, spm_int_t incy)
compute the matrix-vector product:
int spm_zspmm(spm_side_t side, spm_trans_t transA, spm_trans_t transB, spm_int_t K, spm_complex64_t alpha, const spmatrix_t *A, const spm_complex64_t *B, spm_int_t ldb, spm_complex64_t beta, spm_complex64_t *C, spm_int_t ldc)
Compute a matrix-matrix product.
int spm_sspmv(spm_trans_t trans, float alpha, const spmatrix_t *A, const float *x, spm_int_t incx, float beta, float *y, spm_int_t incy)
compute the matrix-vector product:
int spm_sspmm(spm_side_t side, spm_trans_t transA, spm_trans_t transB, spm_int_t K, float alpha, const spmatrix_t *A, const float *B, spm_int_t ldb, float beta, float *C, spm_int_t ldc)
Compute a matrix-matrix product.
int spm_dspmm(spm_side_t side, spm_trans_t transA, spm_trans_t transB, spm_int_t K, double alpha, const spmatrix_t *A, const double *B, spm_int_t ldb, double beta, double *C, spm_int_t ldc)
Compute a matrix-matrix product.
int spm_dspmv(spm_trans_t trans, double alpha, const spmatrix_t *A, const double *x, spm_int_t incx, double beta, double *y, spm_int_t incy)
compute the matrix-vector product:
int spm_cspmv(spm_trans_t trans, spm_complex32_t alpha, const spmatrix_t *A, const spm_complex32_t *x, spm_int_t incx, spm_complex32_t beta, spm_complex32_t *y, spm_int_t incy)
compute the matrix-vector product:
int spm_cspmm(spm_side_t side, spm_trans_t transA, spm_trans_t transB, spm_int_t K, spm_complex32_t alpha, const spmatrix_t *A, const spm_complex32_t *B, spm_int_t ldb, spm_complex32_t beta, spm_complex32_t *C, spm_int_t ldc)
Compute a matrix-matrix product.
double d_spmNorm(spm_normtype_t ntype, const spmatrix_t *spm)
Compute the norm of an spm matrix.
double z_spmNormMat(spm_normtype_t ntype, const spmatrix_t *spm, spm_int_t n, const spm_complex64_t *A, spm_int_t lda)
Compute the norm of a dense matrix that follows the distribution of an spm matrix.
double z_spmNorm(spm_normtype_t ntype, const spmatrix_t *spm)
Compute the norm of an spm matrix.
float s_spmNorm(spm_normtype_t ntype, const spmatrix_t *spm)
Compute the norm of an spm matrix.
float c_spmNormMat(spm_normtype_t ntype, const spmatrix_t *spm, spm_int_t n, const spm_complex32_t *A, spm_int_t lda)
Compute the norm of a dense matrix that follows the distribution of an spm matrix.
float s_spmNormMat(spm_normtype_t ntype, const spmatrix_t *spm, spm_int_t n, const float *A, spm_int_t lda)
Compute the norm of a dense matrix that follows the distribution of an spm matrix.
float c_spmNorm(spm_normtype_t ntype, const spmatrix_t *spm)
Compute the norm of an spm matrix.
double d_spmNormMat(spm_normtype_t ntype, const spmatrix_t *spm, spm_int_t n, const double *A, spm_int_t lda)
Compute the norm of a dense matrix that follows the distribution of an spm matrix.
void z_spmPrint(FILE *f, const spmatrix_t *spm)
Write a spm matrix in a file.
void s_spmPrint(FILE *f, const spmatrix_t *spm)
Write a spm matrix in a file.
void d_spmPrint(FILE *f, const spmatrix_t *spm)
Write a spm matrix in a file.
void c_spmPrint(FILE *f, const spmatrix_t *spm)
Write a spm matrix in a file.
int z_spmGenMat(spm_rhstype_t type, int nrhs, const spmatrix_t *spm, void *alpha, unsigned long long int seed, void *A, int lda)
Generate nrhs right hand side vectors associated to a given matrix to test a problem with a solver.
int d_spmCheckAxb(spm_fixdbl_t eps, int nrhs, const spmatrix_t *spm, void *x0, int ldx0, void *b, int ldb, const void *x, int ldx)
Check the backward error, and the forward error if x0 is provided.
int d_spmGenMat(spm_rhstype_t type, int nrhs, const spmatrix_t *spm, void *alpha, unsigned long long int seed, void *A, int lda)
Generate nrhs right hand side vectors associated to a given matrix to test a problem with a solver.
int s_spmCheckAxb(spm_fixdbl_t eps, int nrhs, const spmatrix_t *spm, void *x0, int ldx0, void *b, int ldb, const void *x, int ldx)
Check the backward error, and the forward error if x0 is provided.
int c_spmGenMat(spm_rhstype_t type, int nrhs, const spmatrix_t *spm, void *alpha, unsigned long long int seed, void *A, int lda)
Generate nrhs right hand side vectors associated to a given matrix to test a problem with a solver.
int z_spmCheckAxb(spm_fixdbl_t eps, int nrhs, const spmatrix_t *spm, void *x0, int ldx0, void *b, int ldb, const void *x, int ldx)
Check the backward error, and the forward error if x0 is provided.
int s_spmGenMat(spm_rhstype_t type, int nrhs, const spmatrix_t *spm, void *alpha, unsigned long long int seed, void *A, int lda)
Generate nrhs right hand side vectors associated to a given matrix to test a problem with a solver.
int c_spmCheckAxb(spm_fixdbl_t eps, int nrhs, const spmatrix_t *spm, void *x0, int ldx0, void *b, int ldb, const void *x, int ldx)
Check the backward error, and the forward error if x0 is provided.
void d_spmScal(const double alpha, spmatrix_t *spm)
Scal the spm: A = alpha * A.
Definition d_spm_scal.c:39
void c_spmScal(const float alpha, spmatrix_t *spm)
Scal the spm: A = alpha * A.
Definition c_spm_scal.c:39
void z_spmScal(const double alpha, spmatrix_t *spm)
Scal the spm: A = alpha * A.
Definition z_spm_scal.c:39
void s_spmScal(const float alpha, spmatrix_t *spm)
Scal the spm: A = alpha * A.
Definition s_spm_scal.c:39
spm_coeftype_t flttype
Definition spm.h:68
spm_int_t * dofs
Definition spm.h:86
spm_int_t nexp
Definition spm.h:79
void * values
Definition spm.h:93
int clustnbr
Definition spm.h:97
spm_int_t nnz
Definition spm.h:76
spm_int_t nnzexp
Definition spm.h:81
spm_int_t * rowptr
Definition spm.h:91
spm_int_t gnnz
Definition spm.h:75
spm_fmttype_t fmttype
Definition spm.h:70
spm_int_t dof
Definition spm.h:83
spm_int_t n
Definition spm.h:74
spm_mtxtype_t mtxtype
Definition spm.h:66
spm_int_t * loc2glob
Definition spm.h:92
spm_layout_t layout
Definition spm.h:88
SPM_Comm comm
Definition spm.h:98
spm_int_t baseval
Definition spm.h:72
spm_int_t * glob2loc
Definition spm.h:95
spm_int_t gnnzexp
Definition spm.h:80
spm_int_t * colptr
Definition spm.h:90
spm_int_t gNexp
Definition spm.h:78
int clustnum
Definition spm.h:96
spm_int_t gN
Definition spm.h:73
int replicated
Definition spm.h:99
double spmNormMat(spm_normtype_t ntype, const spmatrix_t *spm, spm_int_t n, const void *A, spm_int_t lda)
Compute the norm of the spm.
Definition spm.c:703
void spmAlloc(spmatrix_t *spm)
Allocate the arrays of an spm structure.
Definition spm.c:179
void spmExit(spmatrix_t *spm)
Cleanup the spm structure but do not free the spm pointer.
Definition spm.c:234
spm_int_t spmSymmetrize(spmatrix_t *spm)
Symmetrize the pattern of the spm.
#define SPM_MPI_INT
The MPI type associated to spm_int_t.
Definition datatypes.h:72
void spmUpdateComputedFields(spmatrix_t *spm)
Update all the computed fields based on the static values stored.
void spmBase(spmatrix_t *spm, int baseval)
Rebase the arrays of the spm to the given value.
Definition spm.c:281
struct spmatrix_s spmatrix_t
The sparse matrix data structure.
spm_int_t spmFindBase(const spmatrix_t *spm)
Search the base used in the spm structure.
Definition spm.c:358
int spmMatVec(spm_trans_t trans, double alpha, const spmatrix_t *spm, const void *x, double beta, void *y)
Compute a matrix-vector product.
Definition spm.c:1245
int spmCheckAxb(double eps, spm_int_t nrhs, const spmatrix_t *spm, void *opt_X0, spm_int_t opt_ldx0, void *B, spm_int_t ldb, const void *X, spm_int_t ldx)
Check the backward error, and the forward error if x0 is provided.
Definition spm.c:1434
void spmInitDist(spmatrix_t *spm, SPM_Comm comm)
Init the spm structure with a specific communicator.
Definition spm.c:101
int spmConvert(int ofmttype, spmatrix_t *ospm)
Convert the storage format of the spm.
Definition spm.c:429
double spmNormVec(spm_normtype_t ntype, const spmatrix_t *spm, const void *x, spm_int_t incx)
Compute the norm of the spm.
Definition spm.c:607
spm_int_t spmMergeDuplicate(spmatrix_t *spm)
Merge multiple entries in a spm by summing their values together.
Definition spm.c:807
int spmMatMat(spm_trans_t trans, spm_int_t n, double alpha, const spmatrix_t *A, const void *B, spm_int_t ldb, double beta, void *C, spm_int_t ldc)
Compute a matrix-matrix product.
Definition spm.c:1338
int spmCheckAndCorrect(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Check the correctness of a spm.
Definition spm.c:888
int spmSort(spmatrix_t *spm)
Sort the subarray of edges of each vertex.
Definition spm.c:757
void spmScal(double alpha, spmatrix_t *spm)
Scale the spm.
Definition spm.c:1492
void spmExpand(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Expand a multi-dof spm matrix into an spm with constant dof set to 1.
Definition spm.c:1179
void spmPrint(const spmatrix_t *spm, FILE *f)
Print an spm matrix into into a given file.
Definition spm.c:1130
void spmScalVec(double alpha, const spmatrix_t *spm, void *x, spm_int_t incx)
Scale a vector associated to a sparse matrix. Deprecated function replaced by spmScalVec() or spmScal...
Definition spm.c:1556
void spmScalMat(double alpha, const spmatrix_t *spm, spm_int_t n, void *A, spm_int_t lda)
Scale a matrix associated to a sparse matrix.
Definition spm.c:1613
void spmScalMatrix(double alpha, spmatrix_t *spm) __attribute__((__deprecated__("Please replace by spmScal() function (will be removed in 1.3.0)")))
Scale the spm.
Definition spm.c:1523
double _Complex spm_complex64_t
The double complex arithmetic datatype.
Definition datatypes.h:162
int spmGenVec(spm_rhstype_t type, const spmatrix_t *spm, void *alpha, unsigned long long int seed, void *x, spm_int_t incx)
Generate a vector associated to a given matrix.
Definition spm.c:1813
double spmNorm(spm_normtype_t ntype, const spmatrix_t *spm)
Compute the norm of the spm.
Definition spm.c:525
void spm2Dense(const spmatrix_t *spm, void *A)
Convert the spm matrix into a dense matrix for test purpose.
Definition spm.c:461
void spmCopy(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Create a copy of the spm.
Definition spm.c:980
void spmInit(spmatrix_t *spm)
Init the spm structure.
Definition spm.c:156
int spm_int_t
The main integer datatype used in spm arrays.
Definition datatypes.h:70
int spmGenMat(spm_rhstype_t type, spm_int_t nrhs, const spmatrix_t *spm, void *alpha, unsigned long long int seed, void *A, spm_int_t lda)
Generate a set of vectors associated to a given matrix.
Definition spm.c:1743
void spmScalVector(spm_coeftype_t flt, double alpha, spm_int_t n, void *A, spm_int_t lda) __attribute__((__deprecated__("Please replace by spmScalVec() or spmScalMat() depending on usage (will be removed in 1.3.0)")))
Scale a vector according to the spm type.
Definition spm.c:1676
float _Complex spm_complex32_t
The real complex arithmetic datatype.
Definition datatypes.h:161
void spmPrintInfo(const spmatrix_t *spm, FILE *f)
Print basic informations about the spm matrix into a given stream.
Definition spm.c:1037
#define LAPACKE_slascl_work(_dir_, _uplo_, _kl_, _ku_, _cfrom_, _cto_, _m_, _n_, _A_, _lda_)
Alias if Lapacke zlscl is not available.
int spmBlasSetNumThreadsOne(void)
Set the number of threads for blas calls (BLIS, MKL, OpenBLAS) to 1 and return the previous number of...
Definition spm.c:2347
spm_int_t * spm_getandset_glob2loc(spmatrix_t *spm)
Computes the glob2loc array if needed, and returns it.
Definition spm.c:2019
int spmBlasGetNumThreads(void)
Return the current number of threads used for blas calls.
Definition spm.c:2293
int spmBlasSetNumThreads(int nt)
Set the number of threads for blas calls (BLIS, MKL, OpenBLAS) and return the previous number of blas...
Definition spm.c:2321
spm_int_t spm_create_loc2glob_continuous(const spmatrix_t *spm, spm_int_t **l2g_ptr)
Generate a continuous loc2glob array on each node.
Definition spm.c:1852
spm_int_t * spm_get_glob2loc(const spmatrix_t *spm)
Computes the glob2loc array if needed, and returns it.
Definition spm.c:1896
int spm_get_distribution(const spmatrix_t *spm)
Search the distribution pattern used in the spm structure.
Definition spm.c:2062
#define LAPACKE_zlascl_work(_dir_, _uplo_, _kl_, _ku_, _cfrom_, _cto_, _m_, _n_, _A_, _lda_)
Alias if Lapacke zlscl is not available.