Mentions légales du service

Skip to content
Snippets Groups Projects
z_spm.c 11.9 KiB
Newer Older
Mathieu Faverge's avatar
Mathieu Faverge committed
 * SParse Matrix package precision dependent routines.
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @copyright 2016-2017 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @version 1.0.0
 * @author Mathieu Faverge
 * @date 2013-06-24
 *
 * @precisions normal z -> c d s p
 *
 **/
#include "common.h"
Mathieu Faverge's avatar
Mathieu Faverge committed
#include <string.h>

/**
 *******************************************************************************
 *
 * @ingroup spm_dev_check
 * @brief This routine sorts the subarray of edges of each vertex in a
 * centralized spm stored in CSC or CSR format.
 *
 * Nothing is performed if IJV  format is used.
 * @warning This function should NOT be called if dof is greater than 1.
 *
 *******************************************************************************
 *
 *          On entry, the pointer to the sparse matrix structure.
 *          On exit, the same sparse matrix with subarrays of edges sorted by
 *          ascending order.
 *
 *******************************************************************************/
void
Mathieu Faverge's avatar
Mathieu Faverge committed
z_spmSort( spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm_int_t       *colptr = spm->colptr;
    spm_int_t       *rowptr = spm->rowptr;
    spm_complex64_t *values = spm->values;
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm_int_t n = spm->n;
    spm_int_t i, size;
    if (spm->dof > 1){
        fprintf(stderr, "z_spmSort: Number of dof (%d) greater than one not supported\n", (int)spm->dof);
Mathieu Faverge's avatar
Mathieu Faverge committed
    if ( spm->fmttype == SpmCSC ) {
        for (i=0; i<n; i++, colptr++)
        {
            size = colptr[1] - colptr[0];

#if defined(PRECISION_p)
#else
            sortptr[0] = rowptr;
            sortptr[1] = values;
            z_spmIntFltSortAsc( sortptr, size );
Mathieu Faverge's avatar
Mathieu Faverge committed
    else if ( spm->fmttype == SpmCSR ) {
        for (i=0; i<n; i++, rowptr++)
        {
            size = rowptr[1] - rowptr[0];

#if defined(PRECISION_p)
#else
            sortptr[0] = colptr;
            sortptr[1] = values;
            z_spmIntFltSortAsc( sortptr, size );
#endif
            colptr += size;
            values += size;
        }
    }
}

/**
 *******************************************************************************
 *
 * @ingroup spm_dev_check
 *
 * @brief This routine merge the multiple entries in a sparse
 * matrix by suming their values together.
 * The sparse matrix needs to be sorted  first (see z_spmSort()).
 * @warning This function should NOT be called if dof is greater than 1.
 *
 *******************************************************************************
 *
 *          On entry, the pointer to the sparse matrix structure.
 *          On exit, the reduced sparse matrix of multiple entries were present
 *          in it. The multiple values for a same vertex are sum up together.
 *
 ********************************************************************************
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @return The number of vertices that were merged
 *
 *******************************************************************************/
Mathieu Faverge's avatar
Mathieu Faverge committed
spm_int_t
z_spmMergeDuplicate( spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm_int_t       *colptr = spm->colptr;
    spm_int_t       *oldrow = spm->rowptr;
    spm_int_t       *newrow = spm->rowptr;
    spm_complex64_t *newval = spm->values;
    spm_complex64_t *oldval = spm->values;
    spm_int_t n       = spm->n;
    spm_int_t baseval = spm->colptr[0];
    spm_int_t dof2    = spm->dof * spm->dof;
    spm_int_t idx, i, j, d, size;
    spm_int_t merge = 0;

    if ( spm->fmttype == SpmCSC ) {
        idx = 0;
        for (i=0; i<n; i++, colptr++)
        {
            size = colptr[1] - colptr[0];
            for (j = 0; j < size;
                 j++, oldrow++, oldval+=dof2, newrow++, newval+=dof2, idx++)
            {
                if ( newrow != oldrow ) {
                    newrow[0] = oldrow[0];
#if !defined(PRECISION_p)
Mathieu Faverge's avatar
Mathieu Faverge committed
                    memcpy( newval, oldval, dof2 * sizeof(spm_complex64_t) );
#endif
                }

                while( ((j+1) < size) && (newrow[0] == oldrow[1]) ) {
                    j++; oldrow++; oldval+=dof2;
#if !defined(PRECISION_p)
                    /* Merge the two sets of values */
                    for (d = 0; d < dof2; d++) {
                        newval[d] += oldval[d];
                    }
#endif
                    merge++;
                }
            }
            assert( ((merge == 0) && ( colptr[1] == idx+baseval)) ||
                    ((merge != 0) && ( colptr[1] >  idx+baseval)) );

            colptr[1] = idx + baseval;
        }
Mathieu Faverge's avatar
Mathieu Faverge committed
        assert( ((merge == 0) && (spm->nnz         == idx)) ||
                ((merge != 0) && (spm->nnz - merge == idx)) );
            spm->nnz = spm->nnz - merge;
            spm->gnnz = spm->nnz;
Mathieu Faverge's avatar
Mathieu Faverge committed
            newrow = malloc( spm->nnz * sizeof(spm_int_t) );
            memcpy( newrow, spm->rowptr, spm->nnz * sizeof(spm_int_t) );
            free(spm->rowptr);
            spm->rowptr = newrow;
Mathieu Faverge's avatar
Mathieu Faverge committed
            newval = malloc( spm->nnz * dof2 * sizeof(spm_int_t) );
            memcpy( newval, spm->values, spm->nnz * dof2 * sizeof(spm_complex64_t) );
            free(spm->values);
            spm->values = newval;
Mathieu Faverge's avatar
Mathieu Faverge committed
    (void)d;
    return merge;
}

/**
 *******************************************************************************
 *
 * @ingroup spm_dev_check
 *
 * @brief This routine corrects the sparse matrix structure if it's
 * pattern is not symmetric.
Pierre Ramet's avatar
Pierre Ramet committed
 * It returns the new symmetric pattern with zeroes on
 * the new entries.
 *
 *******************************************************************************
 *
 *          On entry, the pointer to the sparse matrix structure.
Pierre Ramet's avatar
Pierre Ramet committed
 *          On exit, the same sparse matrix with extra entries that makes it
 *          pattern symmetric.
 *
 *******************************************************************************
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @retval Return the number of entries added to the matrix.
 *
 *******************************************************************************/
Mathieu Faverge's avatar
Mathieu Faverge committed
spm_int_t
z_spmSymmetrize( spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm_complex64_t *oldval, *valtmp, *newval = NULL;
    spm_int_t *oldcol, *coltmp, *newcol = NULL;
    spm_int_t *oldrow, *rowtmp, *newrow = NULL;
    spm_int_t *toaddtab = NULL;
    spm_int_t *toaddtmp, toaddcnt, toaddsze;
    spm_int_t  n       = spm->n;
    spm_int_t  dof2    = spm->dof * spm->dof;
    spm_int_t  i, j, k, r, size;
    spm_int_t  baseval;
Mathieu Faverge's avatar
Mathieu Faverge committed
    if ( (spm->fmttype == SpmCSC) || (spm->fmttype == SpmCSR) ) {
        if (spm->fmttype == SpmCSC) {
            oldcol = spm->colptr;
            coltmp = spm->colptr;
            oldrow = spm->rowptr;
            rowtmp = spm->rowptr;
            oldcol = spm->rowptr;
            coltmp = spm->rowptr;
            oldrow = spm->colptr;
            rowtmp = spm->colptr;
        }

        baseval  = oldcol[0];
        for (i=0; i<n; i++, coltmp++)
        {
            size = coltmp[1] - coltmp[0];
            for (r=0; r<size; r++, rowtmp++ )
            {
                j = rowtmp[0]-baseval;
                if ( i != j ) {
                    /* Look for the element (j, i) */
Mathieu Faverge's avatar
Mathieu Faverge committed
                    spm_int_t frow = oldcol[ j ] - baseval;
                    spm_int_t lrow = oldcol[ j+1 ] - baseval;
                    int found = 0;

                    for (k = frow; (k < lrow); k++)
                    {
                        if (i == (oldrow[k]-baseval))
                        {
                            found = 1;
                            break;
                        }
                        else if ( i < (oldrow[k]-baseval))
                        {
                            /* The spm is sorted so we will not find it later */
Mathieu Faverge's avatar
Mathieu Faverge committed
                            newcol = malloc( (spm->n+1) * sizeof(spm_int_t) );
                            for (k=0; k<spm->n; k++) {
                                newcol[k] = oldcol[k+1] - oldcol[k];
                            }

                            /* Let's start with a buffer that will contain 5% of extra elements */
Mathieu Faverge's avatar
Mathieu Faverge committed
                            toaddsze = spm_imax( 0.05 * (double)spm->nnz, 1 );
                            toaddtab = malloc( 2*toaddsze * sizeof(spm_int_t) );
Mathieu Faverge's avatar
Mathieu Faverge committed
                            toaddtab = (spm_int_t*)realloc( toaddtab, 2*toaddsze*sizeof(spm_int_t) );
                        }

                        /* Newcol stores the number of elements per column */
                        newcol[ j ]++;
                        /* toaddtab stores the couples (j, i) to be added in the final sparse matrix */
                        toaddtab[ toaddcnt * 2     ] = j;
                        toaddtab[ toaddcnt * 2 + 1 ] = i;
                        toaddcnt++;
                    }
                }
            }
        }

        if (toaddcnt > 0) {
Mathieu Faverge's avatar
Mathieu Faverge committed
            spm_int_t newsize, oldsize;
            spm->nnz = spm->nnz + toaddcnt;
            spm->gnnz = spm->nnz;
Mathieu Faverge's avatar
Mathieu Faverge committed
            newrow = malloc( spm->nnz        * sizeof(spm_int_t) );
Mathieu Faverge's avatar
Mathieu Faverge committed
            newval = malloc( spm->nnz * dof2 * sizeof(spm_complex64_t) );
#endif
            coltmp = newcol;
            rowtmp = newrow;
            valtmp = newval;
            oldval = spm->values;
            toaddtmp = toaddtab;

            newsize = coltmp[0];
            coltmp[0] = baseval;
            for (i=0; i<n; i++, coltmp++, oldcol++)
            {
                /* Copy the existing elements */
                oldsize = oldcol[1] - oldcol[0];
Mathieu Faverge's avatar
Mathieu Faverge committed
                memcpy( rowtmp, oldrow, oldsize * sizeof(spm_int_t) );
Mathieu Faverge's avatar
Mathieu Faverge committed
                memcpy( valtmp, oldval, oldsize * dof2 * sizeof(spm_complex64_t) );
#endif

                oldrow += oldsize;
                rowtmp += oldsize;
                oldval += oldsize * dof2;
                valtmp += oldsize * dof2;

                /* Some elements have been added */
                assert( newsize >= oldsize );
                if ( newsize > oldsize ) {
                    int added = 0;
                    int tobeadded = newsize - oldsize;

                    /* At least one element is equal to i */
                    assert( toaddtmp[0] == i );

                    /* Let's add the new vertices */
                    while( (added < tobeadded) && (toaddtmp[0] == i) ) {
                        rowtmp[0] = toaddtmp[1] + baseval;
                        rowtmp++; toaddtmp+=2; added++;
                    }
                    assert( added == tobeadded );

#if !defined(PRECISION_p)
                    /* Add 0.s for the associated values */
Mathieu Faverge's avatar
Mathieu Faverge committed
                    memset( valtmp, 0, added * dof2 * sizeof(spm_complex64_t) );
                    valtmp += added * dof2;
#endif
                }

                /* Use oldsize as temporary variable to update the new colptr */
                oldsize = newsize;
                newsize = coltmp[1];
                coltmp[1] = coltmp[0] + oldsize;
            }

            assert( coltmp[0]-baseval == spm->nnz );
            free( spm->colptr );
            free( spm->rowptr );
            free( spm->values );
Mathieu Faverge's avatar
Mathieu Faverge committed
            if (spm->fmttype == SpmCSC) {
                spm->colptr = newcol;
                spm->rowptr = newrow;
                spm->colptr = newrow;
                spm->rowptr = newcol;
            spm->values = newval;