/*$Id: matmatmult.c,v 1.15 2001/09/07 20:04:44 buschelm Exp $*/ /* Defines a matrix-matrix product for 2 SeqAIJ matrices C = A * B */ #include "src/mat/impls/aij/seq/aij.h" 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); } static int logkey_matmatmult_symbolic = 0; static int logkey_matmatmult_numeric = 0; /* MatMatMult_SeqAIJ_SeqAIJ_Symbolic - Forms the symbolic product of two SeqAIJ matrices C=A*B; Note: C is assumed to be uninitialized. If this is not the case, Destroy C before calling this routine. */ #undef __FUNCT__ #define __FUNCT__ "MatMatMult_SeqAIJ_SeqAIJ_Symbolic" int MatMatMult_SeqAIJ_SeqAIJ_Symbolic(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,*densefill,*sparsefill; 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); 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),&densefill);CHKERRQ(ierr); ierr = PetscMemzero(densefill,(2*bn+1)*sizeof(int));CHKERRQ(ierr); sparsefill = densefill + bn; /* Initial FreeSpace size is nnz(B)=bi[bm] */ ierr = GetMoreSpace(bi[bm],&free_space);CHKERRQ(ierr); current_space = free_space; /* Determine fill for each row: */ for (i=0;ilocal_remainingtotal_array_size,¤t_space);CHKERRQ(ierr); } /* Copy data into free space, and zero out densefill */ ierr = PetscMemcpy(current_space->array,sparsefill,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_SeqAIJ_SeqAIJ_Numeric - Forms the numeric product of two SeqAIJ matrices C=A*B; Note: C must have been created by calling MatMatMult_SeqAIJ_SeqAIJ_Symbolic. */ #undef __FUNCT__ #define __FUNCT__ "MatMatMult_SeqAIJ_SeqAIJ_Numeric" int MatMatMult_SeqAIJ_SeqAIJ_Numeric(Mat A,Mat B,Mat C) { 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 ierr,i,j,k,anzi,bnzi,cnzi,brow,flops; 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); 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); flops = 0; /* 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,*p=(Mat_SeqAIJ*)P->data,*c; int aishift=a->indexshift,pishift=p->indexshift; int *pti,*ptj,*ptfill,*ai=a->i,*aj=a->j,*ajj,*pi=p->i,*pj=p->j,*pjj; int *ci,*cj,*densefill,*sparsefill,*ptadensefill,*ptasparsefill,*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); 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); /* Create ij structure of P^T */ /* Recall in P^T there are pn rows and pi[pm] nonzeros. */ ierr = PetscMalloc((pn+1+pi[pm])*sizeof(int),&pti);CHKERRQ(ierr); ierr = PetscMemzero(pti,(pn+1+pi[pm])*sizeof(int));CHKERRQ(ierr); ptj = pti + pn+1; /* Walk through pj and count ## of non-zeros in each row of P^T. */ for (i=0;ij; /* Clean-up temporary space. */ ierr = PetscFree(ptfill);CHKERRQ(ierr); /* 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),&ptadensefill);CHKERRQ(ierr); ierr = PetscMemzero(ptadensefill,(2*pn+2*an+1)*sizeof(int));CHKERRQ(ierr); ptasparsefill = ptadensefill + an; densefill = ptasparsefill + an; sparsefill = densefill + pn; /* Set initial free space to be nnz(A) scaled by aspect ratio of P. */ /* Reason: Take pn/pm = 1/2. */ /* P^T*A*P will take A(NxN) and create C(N/2xN/2). */ /* If C has same sparsity pattern as A, nnz(C)~1/2*nnz(A). */ /* Is this reasonable???? */ 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 densefills */ ierr = PetscMemcpy(current_space->array,sparsefill,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. */ /* Perhaps we should attach the (i,j) info for P^T to P for future use. */ /* For now, we won't. */ ierr = PetscFree(pti); ierr = PetscLogEventEnd(logkey_matapplyptap_symbolic,A,P,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "MatApplyPtAP_SeqAIJ_Numeric" int MatApplyPtAP_SeqAIJ_Numeric(Mat A,Mat P,Mat C) { int ierr,flops; 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,*pi=p->i,*pj=p->j,*pJ=p->j,*pjj,*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,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); 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); flops = 0; ierr = PetscMalloc(cn*(sizeof(MatScalar)+sizeof(int)),&apa);CHKERRQ(ierr); ierr = PetscMemzero(apa,cn*(sizeof(MatScalar)+sizeof(int)));CHKERRQ(ierr); apj = (int *)(apa + cn); ierr = PetscMemzero(ca,ci[cm]*sizeof(MatScalar));CHKERRQ(ierr); for (i=0;i