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