/*$Id: matmatmult.c,v 1.15 2001/09/07 20:04:44 buschelm Exp $*/ /* Defines a matrix-matrix product routines for pairs of SeqAIJ matrices C = A * B C = P^T * A * P C = P * A * P^T */ #include "src/mat/impls/aij/seq/aij.h" static int logkey_matmatmult = 0; static int logkey_matmatmult_symbolic = 0; static int logkey_matmatmult_numeric = 0; static int logkey_matgetsymtranspose = 0; static int logkey_mattranspose = 0; static int logkey_matapplyptap = 0; static int logkey_matapplyptap_symbolic = 0; static int logkey_matapplyptap_numeric = 0; static int logkey_matapplypapt = 0; static int logkey_matapplypapt_symbolic = 0; static int logkey_matapplypapt_numeric = 0; typedef struct _Space *FreeSpaceList; typedef struct _Space { FreeSpaceList more_space; int *array; int *array_head; int total_array_size; int local_used; int local_remaining; } FreeSpace; #undef __FUNCT__ #define __FUNCT__ "GetMoreSpace" int GetMoreSpace(int size,FreeSpaceList *list) { FreeSpaceList a; int ierr; PetscFunctionBegin; ierr = PetscMalloc(sizeof(FreeSpace),&a);CHKERRQ(ierr); ierr = PetscMalloc(size*sizeof(int),&(a->array_head));CHKERRQ(ierr); a->array = a->array_head; a->local_remaining = size; a->local_used = 0; a->total_array_size = 0; a->more_space = NULL; if (*list) { (*list)->more_space = a; a->total_array_size = (*list)->total_array_size; } a->total_array_size += size; *list = a; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "MakeSpaceContiguous" int MakeSpaceContiguous(int *space,FreeSpaceList *head) { FreeSpaceList a; int ierr; PetscFunctionBegin; while ((*head)!=NULL) { a = (*head)->more_space; ierr = PetscMemcpy(space,(*head)->array_head,((*head)->local_used)*sizeof(int));CHKERRQ(ierr); space += (*head)->local_used; ierr = PetscFree((*head)->array_head);CHKERRQ(ierr); ierr = PetscFree(*head);CHKERRQ(ierr); *head = a; } PetscFunctionReturn(0); } /* MatMatMult_Symbolic_SeqAIJ_SeqAIJ - Forms the symbolic product of two SeqAIJ matrices C = A * B; Note: C is assumed to be uncreated. If this is not the case, Destroy C before calling this routine. */ #undef __FUNCT__ #define __FUNCT__ "MatMatMult_Symbolic_SeqAIJ_SeqAIJ" int MatMatMult_Symbolic_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat *C) { int ierr; FreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ*)B->data,*c; int aishift=a->indexshift,bishift=b->indexshift; int *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj; int *ci,*cj,*denserow,*sparserow; int an=A->N,am=A->M,bn=B->N,bm=B->M; int i,j,k,anzi,brow,bnzj,cnzi; MatScalar *ca; PetscFunctionBegin; /* some error checking which could be moved into interface layer */ if (aishift || bishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); if (an!=bm) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",an,bm); /* Set up timers */ if (!logkey_matmatmult_symbolic) { ierr = PetscLogEventRegister(&logkey_matmatmult_symbolic,"MatMatMult_Symbolic",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_matmatmult_symbolic,A,B,0,0);CHKERRQ(ierr); /* Set up */ /* Allocate ci array, arrays for fill computation and */ /* free space for accumulating nonzero column info */ ierr = PetscMalloc(((am+1)+1)*sizeof(int),&ci);CHKERRQ(ierr); ci[0] = 0; ierr = PetscMalloc((2*bn+1)*sizeof(int),&denserow);CHKERRQ(ierr); ierr = PetscMemzero(denserow,(2*bn+1)*sizeof(int));CHKERRQ(ierr); sparserow = denserow + bn; /* Initial FreeSpace size is nnz(B)=bi[bm] */ /* No idea what is most reasonable here. */ ierr = GetMoreSpace(bi[bm],&free_space);CHKERRQ(ierr); current_space = free_space; /* Determine symbolic info for each row of the product: */ for (i=0;ilocal_remainingtotal_array_size,¤t_space);CHKERRQ(ierr); } /* Copy data into free space, and zero out denserow */ ierr = PetscMemcpy(current_space->array,sparserow,cnzi*sizeof(int));CHKERRQ(ierr); current_space->array += cnzi; current_space->local_used += cnzi; current_space->local_remaining -= cnzi; for (j=0;jcomm,am,bn,ci,cj,ca,C);CHKERRQ(ierr); /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */ /* These are PETSc arrays, so change flags so arrays can be deleted by PETSc */ c = (Mat_SeqAIJ *)((*C)->data); c->freedata = PETSC_TRUE; c->nonew = 0; ierr = PetscLogEventEnd(logkey_matmatmult_symbolic,A,B,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); } /* MatMatMult_Numeric_SeqAIJ_SeqAIJ - Forms the numeric product of two SeqAIJ matrices C=A*B; Note: C must have been created by calling MatMatMult_Symbolic_SeqAIJ_SeqAIJ. */ #undef __FUNCT__ #define __FUNCT__ "MatMatMult_Numeric_SeqAIJ_SeqAIJ" int MatMatMult_Numeric_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat C) { int ierr,flops=0; Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data; int aishift=a->indexshift,bishift=b->indexshift,cishift=c->indexshift; int *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj,*ci=c->i,*cj=c->j; int an=A->N,am=A->M,bn=B->N,bm=B->M,cn=C->N,cm=C->M; int i,j,k,anzi,bnzi,cnzi,brow; MatScalar *aa=a->a,*ba=b->a,*baj,*ca=c->a,*temp; PetscFunctionBegin; /* This error checking should be unnecessary if the symbolic was performed */ if (aishift || bishift || cishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); if (am!=cm) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",am,cm); if (an!=bm) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",an,bm); if (bn!=cn) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",bn,cn); /* Set up timers */ if (!logkey_matmatmult_numeric) { ierr = PetscLogEventRegister(&logkey_matmatmult_numeric,"MatMatMult_Numeric",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_matmatmult_numeric,A,B,C,0);CHKERRQ(ierr); /* Allocate temp accumulation space to avoid searching for nonzero columns in C */ ierr = PetscMalloc((cn+1)*sizeof(MatScalar),&temp);CHKERRQ(ierr); ierr = PetscMemzero(temp,cn*sizeof(MatScalar));CHKERRQ(ierr); /* Traverse A row-wise. */ /* Build the ith row in C by summing over nonzero columns in A, */ /* the rows of B corresponding to nonzeros of A. */ for (i=0;idata; int aishift = a->indexshift,an=A->N,am=A->M; int *ati,*atj,*atfill,*ai=a->i,*aj=a->j; PetscFunctionBegin; ierr = PetscLogInfo(A,"Getting Symbolic Transpose.\n");CHKERRQ(ierr); if (aishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); /* Set up timers */ if (!logkey_matgetsymtranspose) { ierr = PetscLogEventRegister(&logkey_matgetsymtranspose,"MatGetSymbolicTranspose",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_matgetsymtranspose,A,0,0,0);CHKERRQ(ierr); /* Allocate space for symbolic transpose info and work array */ ierr = PetscMalloc((an+1)*sizeof(int),&ati);CHKERRQ(ierr); ierr = PetscMalloc(ai[am]*sizeof(int),&atj);CHKERRQ(ierr); ierr = PetscMalloc(an*sizeof(int),&atfill);CHKERRQ(ierr); ierr = PetscMemzero(ati,(an+1)*sizeof(int));CHKERRQ(ierr); /* Walk through aj and count ## of non-zeros in each row of A^T. */ /* Note: offset by 1 for fast conversion into csr format. */ for (i=0;idata,*at; int aishift = a->indexshift,an=A->N,am=A->M; int *ati,*atj,*atfill,*ai=a->i,*aj=a->j; MatScalar *ata,*aa=a->a; PetscFunctionBegin; if (aishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); /* Set up timers */ if (!logkey_mattranspose) { ierr = PetscLogEventRegister(&logkey_mattranspose,"MatTranspose_SeqAIJ_FAST",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_mattranspose,A,0,0,0);CHKERRQ(ierr); /* Allocate space for symbolic transpose info and work array */ ierr = PetscMalloc((an+1)*sizeof(int),&ati);CHKERRQ(ierr); ierr = PetscMalloc(ai[am]*sizeof(int),&atj);CHKERRQ(ierr); ierr = PetscMalloc(ai[am]*sizeof(MatScalar),&ata);CHKERRQ(ierr); ierr = PetscMalloc(an*sizeof(int),&atfill);CHKERRQ(ierr); ierr = PetscMemzero(ati,(an+1)*sizeof(int));CHKERRQ(ierr); /* Walk through aj and count ## of non-zeros in each row of A^T. */ /* Note: offset by 1 for fast conversion into csr format. */ for (i=0;icomm,an,am,ati,atj,ata,&At);CHKERRQ(ierr); at = (Mat_SeqAIJ *)(At->data); at->freedata = PETSC_TRUE; at->nonew = 0; if (B) { *B = At; } else { ierr = MatHeaderCopy(A,At); } ierr = PetscLogEventEnd(logkey_mattranspose,A,0,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "MatRestoreSymbolicTranspose" int MatRestoreSymbolicTranspose(Mat A,int *ati[],int *atj[]) { int ierr; PetscFunctionBegin; ierr = PetscLogInfo(A,"Restoring Symbolic Transpose.\n");CHKERRQ(ierr); ierr = PetscFree(*ati);CHKERRQ(ierr); ati = PETSC_NULL; ierr = PetscFree(*atj);CHKERRQ(ierr); atj = PETSC_NULL; PetscFunctionReturn(0); } /* MatApplyPtAP_Symbolic_SeqAIJ - Forms the symbolic product of two SeqAIJ matrices C = P^T * A * P; Note: C is assumed to be uncreated. If this is not the case, Destroy C before calling this routine. */ #undef __FUNCT__ #define __FUNCT__ "MatApplyPtAP_Symbolic_SeqAIJ" int MatApplyPtAP_Symbolic_SeqAIJ(Mat A,Mat P,Mat *C) { int ierr; FreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data,*p=(Mat_SeqAIJ*)P->data,*c; int aishift=a->indexshift,pishift=p->indexshift; int *pti,*ptj,*ptJ,*ai=a->i,*aj=a->j,*ajj,*pi=p->i,*pj=p->j,*pjj; int *ci,*cj,*denserow,*sparserow,*ptadenserow,*ptasparserow,*ptaj; int an=A->N,am=A->M,pn=P->N,pm=P->M; int i,j,k,ptnzi,arow,anzj,ptanzi,prow,pnzj,cnzi; MatScalar *ca; PetscFunctionBegin; /* some error checking which could be moved into interface layer */ if (aishift || pishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); if (pm!=an) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pm,an); if (am!=an) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",am, an); /* Set up timers */ if (!logkey_matapplyptap_symbolic) { ierr = PetscLogEventRegister(&logkey_matapplyptap_symbolic,"MatApplyPtAP_Symbolic",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_matapplyptap_symbolic,A,P,0,0);CHKERRQ(ierr); /* Get ij structure of P^T */ ierr = MatGetSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr); ptJ=ptj; /* Allocate ci array, arrays for fill computation and */ /* free space for accumulating nonzero column info */ ierr = PetscMalloc(((pn+1)*1)*sizeof(int),&ci);CHKERRQ(ierr); ci[0] = 0; ierr = PetscMalloc((2*pn+2*an+1)*sizeof(int),&ptadenserow);CHKERRQ(ierr); ierr = PetscMemzero(ptadenserow,(2*pn+2*an+1)*sizeof(int));CHKERRQ(ierr); ptasparserow = ptadenserow + an; denserow = ptasparserow + an; sparserow = denserow + pn; /* Set initial free space to be nnz(A) scaled by aspect ratio of P. */ /* This should be reasonable if sparsity of PtAP is similar to that of A. */ ierr = GetMoreSpace((ai[am]/pm)*pn,&free_space); current_space = free_space; /* Determine symbolic info for each row of C: */ for (i=0;ilocal_remainingtotal_array_size,¤t_space);CHKERRQ(ierr); } /* Copy data into free space, and zero out denserows */ ierr = PetscMemcpy(current_space->array,sparserow,cnzi*sizeof(int));CHKERRQ(ierr); current_space->array += cnzi; current_space->local_used += cnzi; current_space->local_remaining -= cnzi; for (j=0;jcomm,pn,pn,ci,cj,ca,C);CHKERRQ(ierr); /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */ /* Since these are PETSc arrays, change flags to free them as necessary. */ c = (Mat_SeqAIJ *)((*C)->data); c->freedata = PETSC_TRUE; c->nonew = 0; /* Clean up. */ ierr = MatRestoreSymbolicTranspose(P,&pti,&ptj);CHKERRQ(ierr); ierr = PetscLogEventEnd(logkey_matapplyptap_symbolic,A,P,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); } /* MatApplyPtAP_Numeric_SeqAIJ - Forms the numeric product of two SeqAIJ matrices C = P^T * A * P; Note: C must have been created by calling MatApplyPtAP_Symbolic_SeqAIJ. */ #undef __FUNCT__ #define __FUNCT__ "MatApplyPtAP_Numeric_SeqAIJ" int MatApplyPtAP_Numeric_SeqAIJ(Mat A,Mat P,Mat C) { int ierr,flops=0; Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; Mat_SeqAIJ *p = (Mat_SeqAIJ *) P->data; Mat_SeqAIJ *c = (Mat_SeqAIJ *) C->data; int aishift=a->indexshift,pishift=p->indexshift,cishift=c->indexshift; int *ai=a->i,*aj=a->j,*apj,*apjdense,*pi=p->i,*pj=p->j,*pJ=p->j,*pjj; int *ci=c->i,*cj=c->j,*cjj; int an=A->N,am=A->M,pn=P->N,pm=P->M,cn=C->N,cm=C->M; int i,j,k,anzi,pnzi,apnzj,nextap,pnzj,cnzj,prow,crow; MatScalar *aa=a->a,*apa,*pa=p->a,*pA=p->a,*paj,*ca=c->a,*caj; PetscFunctionBegin; /* This error checking should be unnecessary if the symbolic was performed */ if (aishift || pishift || cishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); if (pn!=cm) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pn,cm); if (pm!=an) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pm,an); if (am!=an) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",am, an); if (pn!=cn) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pn, cn); /* Set up timers */ if (!logkey_matapplyptap_numeric) { ierr = PetscLogEventRegister(&logkey_matapplyptap_numeric,"MatApplyPtAP_Numeric",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_matapplyptap_numeric,A,P,C,0);CHKERRQ(ierr); ierr = PetscMalloc(cn*(sizeof(MatScalar)+2*sizeof(int)),&apa);CHKERRQ(ierr); ierr = PetscMemzero(apa,cn*(sizeof(MatScalar)+2*sizeof(int)));CHKERRQ(ierr); ierr = PetscMemzero(ca,ci[cm]*sizeof(MatScalar));CHKERRQ(ierr); apj = (int *)(apa + cn); apjdense = apj + cn; for (i=0;idata,*p=(Mat_SeqAIJ*)P->data,*c; int aishift=a->indexshift,pishift=p->indexshift; int *ai=a->i,*aj=a->j,*ajj,*pi=p->i,*pj=p->j,*pti,*ptj,*ptjj; int *ci,*cj,*paj,*padenserow,*pasparserow,*denserow,*sparserow; int an=A->N,am=A->M,pn=P->N,pm=P->M; int i,j,k,pnzi,arow,anzj,panzi,ptrow,ptnzj,cnzi; MatScalar *ca; PetscFunctionBegin; /* some error checking which could be moved into interface layer */ if (aishift || pishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); if (pn!=am) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pn,am); if (am!=an) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",am, an); /* Set up timers */ if (!logkey_matapplypapt_symbolic) { ierr = PetscLogEventRegister(&logkey_matapplypapt_symbolic,"MatApplyPAPt_Symbolic",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_matapplypapt_symbolic,A,P,0,0);CHKERRQ(ierr); /* Create ij structure of P^T */ ierr = MatGetSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr); /* Allocate ci array, arrays for fill computation and */ /* free space for accumulating nonzero column info */ ierr = PetscMalloc(((pm+1)*1)*sizeof(int),&ci);CHKERRQ(ierr); ci[0] = 0; ierr = PetscMalloc((2*an+2*pm+1)*sizeof(int),&padenserow);CHKERRQ(ierr); ierr = PetscMemzero(padenserow,(2*an+2*pm+1)*sizeof(int));CHKERRQ(ierr); pasparserow = padenserow + an; denserow = pasparserow + an; sparserow = denserow + pm; /* Set initial free space to be nnz(A) scaled by aspect ratio of Pt. */ /* This should be reasonable if sparsity of PAPt is similar to that of A. */ ierr = GetMoreSpace((ai[am]/pn)*pm,&free_space); current_space = free_space; /* Determine fill for each row of C: */ for (i=0;ilocal_remainingtotal_array_size,¤t_space);CHKERRQ(ierr); } /* Copy data into free space, and zero out dense row */ ierr = PetscMemcpy(current_space->array,sparserow,cnzi*sizeof(int));CHKERRQ(ierr); current_space->array += cnzi; current_space->local_used += cnzi; current_space->local_remaining -= cnzi; for (j=0;jcomm,pm,pm,ci,cj,ca,C);CHKERRQ(ierr); /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */ /* Since these are PETSc arrays, change flags to free them as necessary. */ c = (Mat_SeqAIJ *)((*C)->data); c->freedata = PETSC_TRUE; c->nonew = 0; /* Clean up. */ ierr = MatRestoreSymbolicTranspose(P,&pti,&ptj);CHKERRQ(ierr); ierr = PetscLogEventEnd(logkey_matapplypapt_symbolic,A,P,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); } /* MatApplyPAPt_Numeric_SeqAIJ - Forms the numeric product of two SeqAIJ matrices C = P * A * P^T; Note: C must have been created by calling MatApplyPAPt_Symbolic_SeqAIJ. */ #undef __FUNCT__ #define __FUNCT__ "MatApplyPAPt_Numeric_SeqAIJ" int MatApplyPAPt_Numeric_SeqAIJ(Mat A,Mat P,Mat C) { int ierr,flops=0; Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; Mat_SeqAIJ *p = (Mat_SeqAIJ *) P->data; Mat_SeqAIJ *c = (Mat_SeqAIJ *) C->data; int aishift=a->indexshift,pishift=p->indexshift,cishift=c->indexshift; int *ai=a->i,*aj=a->j,*ajj,*pi=p->i,*pj=p->j,*pjj=p->j,*paj,*pajdense,*ptj; int *ci=c->i,*cj=c->j; int an=A->N,am=A->M,pn=P->N,pm=P->M,cn=C->N,cm=C->M; int i,j,k,k1,k2,pnzi,anzj,panzj,arow,ptcol,ptnzj,cnzi; MatScalar *aa=a->a,*pa=p->a,*pta=p->a,*ptaj,*paa,*aaj,*ca=c->a,sum; PetscFunctionBegin; /* This error checking should be unnecessary if the symbolic was performed */ if (aishift || pishift || cishift) SETERRQ(PETSC_ERR_SUP,"Shifted matrix indices are not supported."); if (pm!=cm) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pm,cm); if (pn!=am) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pn,am); if (am!=an) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",am, an); if (pm!=cn) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",pm, cn); /* Set up timers */ if (!logkey_matapplypapt_numeric) { ierr = PetscLogEventRegister(&logkey_matapplypapt_numeric,"MatApplyPAPt_Numeric",MAT_COOKIE);CHKERRQ(ierr); } ierr = PetscLogEventBegin(logkey_matapplypapt_numeric,A,P,C,0);CHKERRQ(ierr); ierr = PetscMalloc(an*(sizeof(MatScalar)+2*sizeof(int)),&paa);CHKERRQ(ierr); ierr = PetscMemzero(paa,an*(sizeof(MatScalar)+2*sizeof(int)));CHKERRQ(ierr); ierr = PetscMemzero(ca,ci[cm]*sizeof(MatScalar));CHKERRQ(ierr); paj = (int *)(paa + an); pajdense = paj + an; for (i=0;i ptj[k2]) */ { k2++; } } *ca++ = sum; } /* Zero the current row info for P*A */ for (j=0;j