Mentions légales du service

Skip to content
Snippets Groups Projects
spm.c 40.4 KiB
Newer Older
 * @file spm.c
Mathieu Faverge's avatar
Mathieu Faverge committed
 * SParse Matrix package main 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 Xavier Lacoste
 * @author Pierre Ramet
 * @author Mathieu Faverge
 * @date 2013-06-24
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @addtogroup spm
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @{
 **/
#include "common.h"

#include "z_spm.h"
#include "c_spm.h"
#include "d_spm.h"
#include "s_spm.h"
#include "p_spm.h"

RAMET Pierre's avatar
RAMET Pierre committed
#include <lapacke.h>
Mathieu Faverge's avatar
Mathieu Faverge committed
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
Mathieu Faverge's avatar
Mathieu Faverge committed
static int (*conversionTable[3][3][6])(spmatrix_t*) = {
    /* From CSC */
    {{ NULL, NULL, NULL, NULL, NULL, NULL },
     { p_spmConvertCSC2CSR,
       NULL,
       s_spmConvertCSC2CSR,
       d_spmConvertCSC2CSR,
       c_spmConvertCSC2CSR,
       z_spmConvertCSC2CSR },
     { p_spmConvertCSC2IJV,
       NULL,
       s_spmConvertCSC2IJV,
       d_spmConvertCSC2IJV,
       c_spmConvertCSC2IJV,
       z_spmConvertCSC2IJV }},
    /* From CSR */
    {{ p_spmConvertCSR2CSC,
       NULL,
       s_spmConvertCSR2CSC,
       d_spmConvertCSR2CSC,
       c_spmConvertCSR2CSC,
       z_spmConvertCSR2CSC },
     { NULL, NULL, NULL, NULL, NULL, NULL },
     { p_spmConvertCSR2IJV,
       NULL,
       s_spmConvertCSR2IJV,
       d_spmConvertCSR2IJV,
       c_spmConvertCSR2IJV,
       z_spmConvertCSR2IJV }},
    /* From IJV */
    {{ p_spmConvertIJV2CSC,
       NULL,
       s_spmConvertIJV2CSC,
       d_spmConvertIJV2CSC,
       c_spmConvertIJV2CSC,
       z_spmConvertIJV2CSC },
     { p_spmConvertIJV2CSR,
       NULL,
       s_spmConvertIJV2CSR,
       d_spmConvertIJV2CSR,
       c_spmConvertIJV2CSR,
       z_spmConvertIJV2CSR },
     { NULL, NULL, NULL, NULL, NULL, NULL }}
};

Mathieu Faverge's avatar
Mathieu Faverge committed
#endif /* !defined(DOXYGEN_SHOULD_SKIP_THIS) */
Alban Bellot's avatar
Alban Bellot committed
/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Init the spm structure.
Alban Bellot's avatar
Alban Bellot committed
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
Alban Bellot's avatar
Alban Bellot committed
 *          The sparse matrix to init.
 *
 *******************************************************************************/
void
Mathieu Faverge's avatar
Mathieu Faverge committed
spmInit( spmatrix_t *spm )
Alban Bellot's avatar
Alban Bellot committed
{
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm->mtxtype = SpmGeneral;
    spm->flttype = SpmDouble;
    spm->fmttype = SpmCSC;
Alban Bellot's avatar
Alban Bellot committed

    spm->gN   = 0;
    spm->n    = 0;
    spm->gnnz = 0;
    spm->nnz  = 0;

    spm->gNexp   = 0;
    spm->nexp    = 0;
    spm->gnnzexp = 0;
    spm->nnzexp  = 0;

    spm->dof      = 1;
    spm->dofs     = NULL;
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm->layout   = SpmColMajor;
Alban Bellot's avatar
Alban Bellot committed

    spm->colptr   = NULL;
    spm->rowptr   = NULL;
    spm->loc2glob = NULL;
    spm->values   = NULL;
}

/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Update all the computed fields based on the static values stored.
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          The sparse matrix to update.
 *
 *******************************************************************************/
void
Mathieu Faverge's avatar
Mathieu Faverge committed
spmUpdateComputedFields( spmatrix_t *spm )
Pierre Ramet's avatar
Pierre Ramet committed
    /*
     * Compute the local expended field for multi-dofs
     */
    if ( spm->dof > 0 ) {
        spm->nexp   = spm->n   * spm->dof;
        spm->nnzexp = spm->nnz * spm->dof * spm->dof;
    }
    else {
Mathieu Faverge's avatar
Mathieu Faverge committed
        spm_int_t i, j, k, dofi, dofj, baseval;
        spm_int_t *dofptr, *colptr, *rowptr;

        baseval = spmFindBase( spm );

        colptr = spm->colptr;
        rowptr = spm->rowptr;
        dofptr = spm->dofs;

        spm->nexp = dofptr[ spm->n ] - baseval;

        spm->nnzexp = 0;
        switch(spm->fmttype)
        {
Mathieu Faverge's avatar
Mathieu Faverge committed
        case SpmCSR:
            /* Swap pointers to call CSC */
            colptr = spm->rowptr;
            rowptr = spm->colptr;

Mathieu Faverge's avatar
Mathieu Faverge committed
            spm_attr_fallthrough;
Mathieu Faverge's avatar
Mathieu Faverge committed
        case SpmCSC:
            for(j=0; j<spm->n; j++, colptr++) {
                dofj = dofptr[j+1] - dofptr[j];

                for(k=colptr[0]; k<colptr[1]; k++, rowptr++) {
                    i = *rowptr - baseval;
                    dofi = dofptr[i+1] - dofptr[i];

                    spm->nnzexp += dofi * dofj;
                }
            }
            break;
Mathieu Faverge's avatar
Mathieu Faverge committed
        case SpmIJV:
            for(k=0; k<spm->nnz; k++, rowptr++, colptr++)
            {
                i = *rowptr - baseval;
                j = *colptr - baseval;
                dofi = dofptr[i+1] - dofptr[i];
                dofj = dofptr[j+1] - dofptr[j];

                spm->nnzexp += dofi * dofj;
            }
        }
    }

    /* TODO: add communicator */
    spm->gN      = spm->n;
    spm->gnnz    = spm->nnz;
    spm->gNexp   = spm->nexp;
    spm->gnnzexp = spm->nnzexp;
}

/**
 *******************************************************************************
 *
 * @brief Allocate the arrays of an spm structure with PaStiX internal
 * allocations.
 *
 * This function must be called after initialization of the non-computed fields,
 * and the call to spmUpdateComputedFields(). It allocates the colptr, rowptr,
 * dof, and values arrays with PaStiX C malloc function. This is highly
 * recommended to use this function when using PaStiX from Fortran.
 *
 *******************************************************************************
 *
 * @param[inout] spm
 *          The sparse matrix fr which the internal arrays needs to be allocated.
 *
 *******************************************************************************/
void
spmAlloc( spmatrix_t *spm )
{
    spm_int_t colsize, rowsize, valsize, dofsize;

    switch(spm->fmttype){
    case SpmCSC:
        colsize = spm->n + 1;
        rowsize = spm->nnz;
        valsize = spm->nnzexp;
        dofsize = spm->n + 1;
        break;
    case SpmCSR:
        colsize = spm->nnz;
        rowsize = spm->n + 1;
        valsize = spm->nnzexp;
        dofsize = spm->n + 1;
        break;
    case SpmIJV:
    default:
        colsize = spm->nnz;
        rowsize = spm->nnz;
        valsize = spm->nnzexp;
        dofsize = spm->n + 1;
    }

    spm->colptr = (spm_int_t*)malloc( colsize * sizeof(spm_int_t) );
    spm->rowptr = (spm_int_t*)malloc( rowsize * sizeof(spm_int_t) );
    if ( spm->dof < 1 ) {
        spm->dofs = (spm_int_t*)malloc( dofsize * sizeof(spm_int_t) );
    }
    valsize = valsize * spm_size_of( spm->flttype );
    spm->values = malloc(valsize);
}

/**
 *******************************************************************************
 *
 * @brief Cleanup the spm structure but do not free the spm pointer.
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          The sparse matrix to free.
 *******************************************************************************/
void
Mathieu Faverge's avatar
Mathieu Faverge committed
spmExit( spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    if(spm->colptr != NULL) {
        free(spm->colptr);
Mathieu Faverge's avatar
Mathieu Faverge committed
        spm->colptr = NULL;
Mathieu Faverge's avatar
Mathieu Faverge committed
    }
    if(spm->rowptr != NULL) {
        free(spm->rowptr);
Mathieu Faverge's avatar
Mathieu Faverge committed
        spm->rowptr = NULL;
Mathieu Faverge's avatar
Mathieu Faverge committed
    }
    if(spm->loc2glob != NULL) {
        free(spm->loc2glob);
Mathieu Faverge's avatar
Mathieu Faverge committed
        spm->loc2glob = NULL;
Mathieu Faverge's avatar
Mathieu Faverge committed
    }
    if(spm->values != NULL) {
        free(spm->values);
Mathieu Faverge's avatar
Mathieu Faverge committed
        spm->values = NULL;
Mathieu Faverge's avatar
Mathieu Faverge committed
    }
    if(spm->dofs != NULL) {
        free(spm->dofs);
Mathieu Faverge's avatar
Mathieu Faverge committed
        spm->dofs = NULL;
Mathieu Faverge's avatar
Mathieu Faverge committed
    }
}

/**
 *******************************************************************************
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Rebase the arrays of the spm to the given value.
Pierre Ramet's avatar
Pierre Ramet committed
 * If the value is equal to the original base, then nothing is performed.
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          The sparse matrix to rebase.
 *
 * @param[in] baseval
 *          The base value to use in the graph (0 or 1).
 *
 *******************************************************************************/
Mathieu Faverge's avatar
Mathieu Faverge committed
spmBase( spmatrix_t *spm,
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm_int_t baseadj;
    spm_int_t i, n, nnz;

    /* Parameter checks */
    if ( spm == NULL ) {
Mathieu Faverge's avatar
Mathieu Faverge committed
        fprintf( stderr,"spmBase: spm pointer is NULL");
    if ( (spm->colptr == NULL) ||
         (spm->rowptr == NULL) )
    {
Mathieu Faverge's avatar
Mathieu Faverge committed
        fprintf( stderr,"spmBase: spm pointer is not correctly initialized");
        return;
    }
    if ( (baseval != 0) &&
         (baseval != 1) )
    {
Mathieu Faverge's avatar
Mathieu Faverge committed
        fprintf( stderr,"spmBase: baseval is incorrect, must be 0 or 1");
        return;
    }

    baseadj = baseval - spmFindBase( spm );
    if (baseadj == 0)
Mathieu Faverge's avatar
Mathieu Faverge committed
        return;
    nnz = spm->nnz;

    switch(spm->fmttype)
    {
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmCSC:
        assert( nnz == (spm->colptr[n] - spm->colptr[0]) );
        for (i = 0; i <= n; i++) {
            spm->colptr[i] += baseadj;
        }
        for (i = 0; i < nnz; i++) {
            spm->rowptr[i] += baseadj;
        }
        break;

Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmCSR:
        assert( nnz == (spm->rowptr[n] - spm->rowptr[0]) );
        for (i = 0; i <= n; i++) {
            spm->rowptr[i] += baseadj;
        }
        for (i = 0; i < nnz; i++) {
            spm->colptr[i] += baseadj;
        }
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmIJV:
        for (i = 0; i < nnz; i++) {
            spm->rowptr[i] += baseadj;
            spm->colptr[i] += baseadj;
        }
    }

    if (spm->loc2glob != NULL) {
        for (i = 0; i < n; i++) {
            spm->loc2glob[i] += baseadj;
        }
        for (i = 0; i <= n; i++) {
}

/**
 *******************************************************************************
 *
 * @brief Search the base used in the spm structure.
 *
 *******************************************************************************
 *
 * @param[in] spm
 *          The sparse matrix structure.
 *
 ********************************************************************************
 *
 * @return  The baseval used in the given sparse matrix structure.
 *
 *******************************************************************************/
Mathieu Faverge's avatar
Mathieu Faverge committed
spm_int_t
spmFindBase( const spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    spm_int_t i, *tmp, baseval;

    /*
     * Check the baseval, we consider that arrays are sorted by columns or rows
     */
Mathieu Faverge's avatar
Mathieu Faverge committed
    baseval = spm_imin( *(spm->colptr), *(spm->rowptr) );
Mathieu Faverge's avatar
Mathieu Faverge committed
        assert( spm->fmttype == SpmIJV );

        baseval = spm->n;
        tmp = spm->colptr;
        for(i=0; i<spm->nnz; i++, tmp++){
Mathieu Faverge's avatar
Mathieu Faverge committed
            baseval = spm_imin( *tmp, baseval );
        }
    }

    return baseval;
}

/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief  Convert the storage format of the spm.
Pierre Ramet's avatar
Pierre Ramet committed
  *******************************************************************************
 *
 * @param[in] ofmttype
Pierre Ramet's avatar
Pierre Ramet committed
 *          The output format of the sparse matrix. It must be:
Mathieu Faverge's avatar
Mathieu Faverge committed
 *          - SpmCSC
 *          - SpmCSR
 *          - SpmIJV
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          The sparse matrix structure to convert.
 *
 ********************************************************************************
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @retval SPM_SUCCESS if the conversion happened successfully.
 * @retval SPM_ERR_BADPARAMETER if one the parameter is incorrect.
 * @retval SPM_ERR_NOTIMPLEMENTED if the case is not yet implemented.
 *
 *******************************************************************************/
int
Mathieu Faverge's avatar
Mathieu Faverge committed
spmConvert( int ofmttype, spmatrix_t *spm )
{
    if ( conversionTable[spm->fmttype][ofmttype][spm->flttype] ) {
Mathieu Faverge's avatar
Mathieu Faverge committed
        if ( (spm->dof != 1) && (spm->flttype != SpmPattern) ) {
Mathieu Faverge's avatar
Mathieu Faverge committed
            //fprintf( stderr, "spmConvert: Conversion of non unique dof not yet implemented\n");
            return SPM_ERR_NOTIMPLEMENTED;
        return conversionTable[spm->fmttype][ofmttype][spm->flttype]( spm );
    }
    else {
Mathieu Faverge's avatar
Mathieu Faverge committed
        return SPM_SUCCESS;
/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Convert the spm matrix into a dense matrix for test purpose.
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @remark DO NOT USE with large matrices.
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          The sparse matrix structure to convert.
 *
 ********************************************************************************
 *
 * @return
 *        The pointer to the allocated array storing the dense version of the
 *        matrix.
 *
 *******************************************************************************/
void *
Mathieu Faverge's avatar
Mathieu Faverge committed
spm2Dense( const spmatrix_t *spm )
{
    switch (spm->flttype) {
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmFloat:
        return s_spm2dense( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex32:
        return c_spm2dense( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex64:
        return z_spm2dense( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmDouble:
        return d_spm2dense( spm );
    default:
        return NULL;
    }
}

/**
 *******************************************************************************
 *
 * @brief Compute the norm of the spm.
 *
 * Return the ntype norm of the sparse matrix spm.
Mathieu Faverge's avatar
Mathieu Faverge committed
 *     spmNorm = ( max(abs(spm(i,j))), NORM = SpmMaxNorm
Mathieu Faverge's avatar
Mathieu Faverge committed
 *               ( norm1(spm),         NORM = SpmOneNorm
Mathieu Faverge's avatar
Mathieu Faverge committed
 *               ( normI(spm),         NORM = SpmInfNorm
Mathieu Faverge's avatar
Mathieu Faverge committed
 *               ( normF(spm),         NORM = SpmFrobeniusNorm
 *
 *  where norm1 denotes the one norm of a matrix (maximum column sum),
 *  normI denotes the infinity norm of a matrix (maximum row sum) and
 *  normF denotes the Frobenius norm of a matrix (square root of sum
 *  of squares). Note that max(abs(spm(i,j))) is not a consistent matrix
 *  norm.
 *
 *******************************************************************************
 *
 * @param[in] ntype
Mathieu Faverge's avatar
Mathieu Faverge committed
 *          - SpmMaxNorm
 *          - SpmOneNorm
 *          - SpmInfNorm
 *          - SpmFrobeniusNorm
 *
 * @param[in] spm
 *          The sparse matrix structure.
 *
 ********************************************************************************
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @retval norm The norm described above. Note that for simplicity, even if the
 *              norm of single real or single complex matrix is computed with
 *              single precision, the returned norm is stored in double
 *              precision.
Pierre Ramet's avatar
Pierre Ramet committed
 * @retval -1   If the floating point of the sparse matrix is undefined.
 *
 *******************************************************************************/
double
Mathieu Faverge's avatar
Mathieu Faverge committed
spmNorm( spm_normtype_t   ntype,
         const spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    spmatrix_t *spmtmp = (spmatrix_t*)spm;
    double norm = -1.;
Mathieu Faverge's avatar
Mathieu Faverge committed
    if ( spm->flttype == SpmPattern ) {
        return SPM_ERR_BADPARAMETER;
    }

    if ( spm->dof != 1 ) {
        fprintf(stderr, "WARNING: spm expanded due to non implemented norm for non-expanded spm\n");
        spmtmp = malloc( sizeof(spmatrix_t) );
        spmExpand( spm, spmtmp );
    switch (spm->flttype) {
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmFloat:
        norm = (double)s_spmNorm( ntype, spmtmp );
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmDouble:
        norm = d_spmNorm( ntype, spmtmp );
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex32:
        norm = (double)c_spmNorm( ntype, spmtmp );
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex64:
        norm = z_spmNorm( ntype, spmtmp );
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmPattern:
    if ( spmtmp != spm ) {
        spmExit( spmtmp );
    return norm;
}

/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Sort the subarray of edges of each vertex in a CSC or CSR format.
Pierre Ramet's avatar
Pierre Ramet committed
 * Nothing is performed if IJV format is used.
 * @warning This function should NOT be called if dof is greater than 1.
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          On entry, the pointer to the sparse matrix structure.
 *          On exit, the same sparse matrix with subarrays of edges sorted by
 *          ascending order.
 *
 ********************************************************************************
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @retval SPM_SUCCESS if the sort was called
 * @retval SPM_ERR_BADPARAMETER if the given spm was incorrect.
 *
 *******************************************************************************/
int
Mathieu Faverge's avatar
Mathieu Faverge committed
spmSort( spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    if ( (spm->dof != 1) && (spm->flttype != SpmPattern) ) {
Mathieu Faverge's avatar
Mathieu Faverge committed
        assert( 0 );
        fprintf(stderr, "ERROR: spmSort should not be called with non expanded matrices including values\n");
    switch (spm->flttype) {
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmPattern:
        p_spmSort( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmFloat:
        s_spmSort( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmDouble:
        d_spmSort( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex32:
        c_spmSort( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex64:
        z_spmSort( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
        return SPM_ERR_BADPARAMETER;
Mathieu Faverge's avatar
Mathieu Faverge committed
    return SPM_SUCCESS;
}

/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Merge multiple entries in a spm by summing their values together.
Pierre Ramet's avatar
Pierre Ramet committed
 * The sparse matrix needs to be sorted first (see spmSort()).
 * @warning Not implemented for CSR and IJV format.
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          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.
 *
 ********************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @retval >=0 the number of vertices that were merged,
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @retval SPM_ERR_BADPARAMETER if the given spm was incorrect.
 *
 *******************************************************************************/
Mathieu Faverge's avatar
Mathieu Faverge committed
spm_int_t
spmMergeDuplicate( spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    if ( (spm->dof < 1) && (spm->flttype != SpmPattern) ) {
        assert( 0 );
        fprintf(stderr, "Error: spmMergeDuplicate should not be called with non expanded matrices with variadic degrees of freedom and values\n" );
    switch (spm->flttype) {
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmPattern:
        return p_spmMergeDuplicate( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmFloat:
        return s_spmMergeDuplicate( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmDouble:
        return d_spmMergeDuplicate( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex32:
        return c_spmMergeDuplicate( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex64:
        return z_spmMergeDuplicate( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
        return SPM_ERR_BADPARAMETER;
    }
}

/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Symmetrize the pattern of the spm.
Pierre Ramet's avatar
Pierre Ramet committed
 * This routine corrects the sparse matrix structure if it's pattern is not
 * symmetric. It returns the new symmetric pattern with zeroes on the new
 * entries.
 *
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @param[inout] spm
 *          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.
 *
 ********************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @retval >=0 the number of entries added to the matrix,
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @retval SPM_ERR_BADPARAMETER if the given spm was incorrect.
 *
 *******************************************************************************/
Mathieu Faverge's avatar
Mathieu Faverge committed
spm_int_t
spmSymmetrize( spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    if ( (spm->dof != 1) && (spm->flttype != SpmPattern) ) {
Mathieu Faverge's avatar
Mathieu Faverge committed
        assert( 0 );
        fprintf(stderr, "ERROR: spmSymmetrize should not be called with non expanded matrices including values\n");
    switch (spm->flttype) {
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmPattern:
        return p_spmSymmetrize( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmFloat:
        return s_spmSymmetrize( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmDouble:
        return d_spmSymmetrize( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex32:
        return c_spmSymmetrize( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex64:
        return z_spmSymmetrize( spm );
Mathieu Faverge's avatar
Mathieu Faverge committed
        return SPM_ERR_BADPARAMETER;
    }
}

/**
 *******************************************************************************
 *
 * @brief Check the correctness of a spm.
 *
 * This routine initializes the sparse matrix to fit the PaStiX requirements. If
 * needed, the format is changed to CSC, the duplicated vertices are merged
 * together by summing their values; the graph is made symmetric for matrices
Pierre Ramet's avatar
Pierre Ramet committed
 * with unsymmetric pattern, new values are set to 0. Only the lower part is
 * kept for symmetric matrices.
Pierre Ramet's avatar
Pierre Ramet committed
  *******************************************************************************
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @param[in] spm_in
 *          The pointer to the sparse matrix structure to check, and correct.
 *
Mathieu Faverge's avatar
Mathieu Faverge committed
 * @param[inout] spm_out
 *          On entry, an allocated structure to hold the corrected spm.
 *          On exit, holds the pointer to spm corrected.
 *
 *******************************************************************************
 *
 * @return 0 if no changes have been made to the spm matrix.
 * @return 1 if corrections have been applied to the in sparse matrix.
 *
 *******************************************************************************/
int
spmCheckAndCorrect( const spmatrix_t *spm_in,
                    spmatrix_t       *spm_out )
Mathieu Faverge's avatar
Mathieu Faverge committed
    spmatrix_t *newspm = NULL;
    spm_int_t count;
    /*
     * Let's work on a copy
     * If multi-dof with variables, we need to expand the spm
     */
    if ( (spm_in->dof != 1) && (spm_in->flttype != SpmPattern) ) {
Mathieu Faverge's avatar
Mathieu Faverge committed
        fprintf(stderr, "spmCheckAndCorrect: spm is expanded due to multiple degrees of freedom\n");
        newspm = malloc( sizeof(spmatrix_t) );
        spmExpand( spm_in, newspm );
    }
    else {
        newspm = spmCopy( spm_in );
Mathieu Faverge's avatar
Mathieu Faverge committed
    /* PaStiX works on CSC matrices */
    spmConvert( SpmCSC, newspm );

    spmSort( newspm );

    /* Merge the duplicated entries by summing the values */
    count = spmMergeDuplicate( newspm );
        fprintf(stderr, "spmCheckAndCorrect: %ld entries have been merged\n", (long)count );
Pierre Ramet's avatar
Pierre Ramet committed
    /*
     * If the matrix is symmetric or hermitian, we keep only the upper or lower
     * part, otherwise, we symmetrize the graph to get A+A^t, new values are set
     * to 0.
     */
Mathieu Faverge's avatar
Mathieu Faverge committed
    if ( newspm->mtxtype == SpmGeneral ) {
        count = spmSymmetrize( newspm );
            fprintf(stderr, "spmCheckAndCorrect: %ld entries have been added for symmetry\n", (long)count );
        //spmToLower( newspm );
Pierre Ramet's avatar
Pierre Ramet committed
    /*
     * Check if we return the new one, or the original one because no changes
     * have been made
     */
    if (( spm_in->fmttype != newspm->fmttype ) ||
        ( spm_in->nnzexp  != newspm->nnzexp  ) )
        memcpy( spm_out, newspm, sizeof(spmatrix_t) );
        free( newspm );
        return 1;
        memcpy( spm_out, spm_in, sizeof(spmatrix_t) );
        spmExit( newspm );
        free( newspm );
        return 0;
    }
}

/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Create a copy of the spm.
 * Duplicate the spm data structure given as parameter. All new arrays are
 * allocated and copied from the original matrix. Both matrices need to be
 * freed.
 *
 *******************************************************************************
 *
 * @param[in] spm
 *          The sparse matrix to copy.
 *
 *******************************************************************************
 *
 * @return
 *          The copy of the sparse matrix.
 *
 *******************************************************************************/
Mathieu Faverge's avatar
Mathieu Faverge committed
spmatrix_t *
spmCopy( const spmatrix_t *spm )
Mathieu Faverge's avatar
Mathieu Faverge committed
    spmatrix_t *newspm = (spmatrix_t*)malloc(sizeof(spmatrix_t));
    spm_int_t colsize, rowsize, valsize, dofsize;
Mathieu Faverge's avatar
Mathieu Faverge committed
    memcpy( newspm, spm, sizeof(spmatrix_t));
    switch(spm->fmttype){
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmCSC:
        colsize = spm->n + 1;
        rowsize = spm->nnz;
        valsize = spm->nnzexp;
        dofsize = spm->n + 1;
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmCSR:
        colsize = spm->nnz;
        rowsize = spm->n + 1;
        valsize = spm->nnzexp;
        dofsize = spm->n + 1;
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmIJV:
        colsize = spm->nnz;
        rowsize = spm->nnz;
        valsize = spm->nnzexp;
        dofsize = spm->n + 1;
    }

Mathieu Faverge's avatar
Mathieu Faverge committed
        newspm->colptr = (spm_int_t*)malloc( colsize * sizeof(spm_int_t) );
        memcpy( newspm->colptr, spm->colptr, colsize * sizeof(spm_int_t) );
Mathieu Faverge's avatar
Mathieu Faverge committed
        newspm->rowptr = (spm_int_t*)malloc( rowsize * sizeof(spm_int_t) );
        memcpy( newspm->rowptr, spm->rowptr, rowsize * sizeof(spm_int_t) );
Mathieu Faverge's avatar
Mathieu Faverge committed
        newspm->loc2glob = (spm_int_t*)malloc( dofsize * sizeof(spm_int_t) );
        memcpy( newspm->loc2glob, spm->loc2glob, dofsize * sizeof(spm_int_t) );
    }
    if(spm->dofs != NULL) {
Mathieu Faverge's avatar
Mathieu Faverge committed
        newspm->dofs = (spm_int_t*)malloc( dofsize * sizeof(spm_int_t) );
Mathieu Faverge's avatar
Mathieu Faverge committed
        memcpy( newspm->dofs, spm->dofs, dofsize * sizeof(spm_int_t) );
Mathieu Faverge's avatar
Mathieu Faverge committed
        valsize = valsize * spm_size_of( spm->flttype );
Mathieu Faverge's avatar
Mathieu Faverge committed
        memcpy( newspm->values, spm->values, valsize );
Mathieu Faverge's avatar
Mathieu Faverge committed
/**
 *******************************************************************************
 *
 * @brief Print basic informations about the spm matrix into a given stream.
 *
 *******************************************************************************
 *
 * @param[in] spm
 *          The sparse matrix to print.
 *
 * @param[inout] stream
 *          Stream to print the spm matrix. stdout is used if stream == NULL.
 *
 *******************************************************************************/
void
Mathieu Faverge's avatar
Mathieu Faverge committed
spmPrintInfo( const spmatrix_t* spm, FILE *stream )
Mathieu Faverge's avatar
Mathieu Faverge committed
    char *mtxtypestr[4] = { "General", "Symmetric", "Hermitian", "Incorrect" };
Mathieu Faverge's avatar
Mathieu Faverge committed
    char *flttypestr[7] = { "Pattern", "", "Float", "Double", "Complex32", "Complex64", "Incorrect" };
    char *fmttypestr[4] = { "CSC", "CSR", "IJV", "Incorrect" };
Mathieu Faverge's avatar
Mathieu Faverge committed
    int mtxtype = spm->mtxtype - SpmGeneral;
    int flttype = spm->flttype - SpmPattern;
    int fmttype = spm->fmttype - SpmCSC;
Mathieu Faverge's avatar
Mathieu Faverge committed

    if (stream == NULL) {
        stream = stdout;
    }

    mtxtype = (mtxtype > 2 || mtxtype < 0) ? 3 : mtxtype;
    flttype = (flttype > 5 || flttype < 0) ? 6 : flttype;
    fmttype = (fmttype > 2 || fmttype < 0) ? 3 : fmttype;

    fprintf(stream,
            "  Matrix type:  %s\n"
            "  Arithmetic:   %s\n"
            "  Format:       %s\n"
            "  N:            %ld\n"
            "  nnz:          %ld\n",
            mtxtypestr[mtxtype],
            flttypestr[flttype],
            fmttypestr[fmttype],
Pierre Ramet's avatar
Pierre Ramet committed
            (long)spm->gN, (long)spm->gnnz );
Mathieu Faverge's avatar
Mathieu Faverge committed

    if ( spm->dof != 1 ) {
        if ( spm->dof > 1 ) {
            fprintf(stream,
                    "  Dof:          %ld\n",
Pierre Ramet's avatar
Pierre Ramet committed
                    (long)spm->dof );
Mathieu Faverge's avatar
Mathieu Faverge committed
        }
        else {
            fprintf(stream,
                    "  Dof:          Variadic\n" );
        }

        fprintf(stream,
                "  N expanded:   %ld\n"
                "  NNZ expanded: %ld\n",
Pierre Ramet's avatar
Pierre Ramet committed
                (long)spm->gNexp, (long)spm->gnnzexp );
Mathieu Faverge's avatar
Mathieu Faverge committed
/**
 *******************************************************************************
 *
 * @brief Print an spm matrix into into a given file.
 *
 *******************************************************************************
 *
 * @param[in] spm
Pierre Ramet's avatar
Pierre Ramet committed
 *          The sparse matrix to print.
 * @param[in] stream
 *          File to print the spm matrix. stdout, if stream == NULL.
Mathieu Faverge's avatar
Mathieu Faverge committed
 *******************************************************************************/
void
Mathieu Faverge's avatar
Mathieu Faverge committed
spmPrint( const spmatrix_t *spm,
Mathieu Faverge's avatar
Mathieu Faverge committed
    switch(spm->flttype)
    {
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmPattern:
Mathieu Faverge's avatar
Mathieu Faverge committed
        //return p_f, spmPrint(f, spm);
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmFloat:
Mathieu Faverge's avatar
Mathieu Faverge committed
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex32:
Mathieu Faverge's avatar
Mathieu Faverge committed
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmComplex64:
Mathieu Faverge's avatar
Mathieu Faverge committed
        break;
Mathieu Faverge's avatar
Mathieu Faverge committed
    case SpmDouble:
Mathieu Faverge's avatar
Mathieu Faverge committed
    default:
/**
 *******************************************************************************
 *
Pierre Ramet's avatar
Pierre Ramet committed
 * @brief Expand a multi-dof spm matrix into an spm with constant dof set to 1.