1 #ifndef lint 2 static char vcid[] = "$Id: aij.c,v 1.147 1996/02/13 23:27:29 bsmith Exp balay $"; 3 #endif 4 5 /* 6 Defines the basic matrix operations for the AIJ (compressed row) 7 matrix storage format. 8 */ 9 #include "aij.h" 10 #include "vec/vecimpl.h" 11 #include "inline/spops.h" 12 #include "petsc.h" 13 #include "inline/bitarray.h" 14 15 extern int MatToSymmetricIJ_SeqAIJ(int,int*,int*,int,int**,int**); 16 17 static int MatGetReordering_SeqAIJ(Mat A,MatOrdering type,IS *rperm, IS *cperm) 18 { 19 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 20 int ierr, *ia, *ja,n,*idx,i; 21 /*Viewer V1, V2;*/ 22 23 /* 24 this is tacky: In the future when we have written special factorization 25 and solve routines for the identity permutation we should use a 26 stride index set instead of the general one. 27 */ 28 if (type == ORDER_NATURAL) { 29 n = a->n; 30 idx = (int *) PetscMalloc( n*sizeof(int) ); CHKPTRQ(idx); 31 for ( i=0; i<n; i++ ) idx[i] = i; 32 ierr = ISCreateSeq(MPI_COMM_SELF,n,idx,rperm); CHKERRQ(ierr); 33 ierr = ISCreateSeq(MPI_COMM_SELF,n,idx,cperm); CHKERRQ(ierr); 34 PetscFree(idx); 35 ISSetPermutation(*rperm); 36 ISSetPermutation(*cperm); 37 ISSetIdentity(*rperm); 38 ISSetIdentity(*cperm); 39 return 0; 40 } 41 42 ierr = MatToSymmetricIJ_SeqAIJ(a->n,a->i,a->j,a->indexshift, &ia, &ja);CHKERRQ(ierr); 43 ierr = MatGetReordering_IJ(a->n,ia,ja,type,rperm,cperm); CHKERRQ(ierr); 44 45 PetscFree(ia); PetscFree(ja); 46 return 0; 47 } 48 49 #define CHUNKSIZE 15 50 51 /* This version has row oriented v */ 52 static int MatSetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,Scalar *v,InsertMode is) 53 { 54 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 55 int *rp,k,low,high,t,ii,row,nrow,i,col,l,rmax, N, sorted = a->sorted; 56 int *imax = a->imax, *ai = a->i, *ailen = a->ilen,roworiented = a->roworiented; 57 int *aj = a->j, nonew = a->nonew,shift = a->indexshift; 58 Scalar *ap,value, *aa = a->a; 59 60 for ( k=0; k<m; k++ ) { /* loop over added rows */ 61 row = im[k]; 62 if (row < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative row"); 63 if (row >= a->m) SETERRQ(1,"MatSetValues_SeqAIJ:Row too large"); 64 rp = aj + ai[row] + shift; ap = aa + ai[row] + shift; 65 rmax = imax[row]; nrow = ailen[row]; 66 low = 0; 67 for ( l=0; l<n; l++ ) { /* loop over added columns */ 68 if (in[l] < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative column"); 69 if (in[l] >= a->n) SETERRQ(1,"MatSetValues_SeqAIJ:Column too large"); 70 col = in[l] - shift; 71 if (roworiented) { 72 value = *v++; 73 } 74 else { 75 value = v[k + l*m]; 76 } 77 if (!sorted) low = 0; high = nrow; 78 while (high-low > 5) { 79 t = (low+high)/2; 80 if (rp[t] > col) high = t; 81 else low = t; 82 } 83 for ( i=low; i<high; i++ ) { 84 if (rp[i] > col) break; 85 if (rp[i] == col) { 86 if (is == ADD_VALUES) ap[i] += value; 87 else ap[i] = value; 88 goto noinsert; 89 } 90 } 91 if (nonew) goto noinsert; 92 if (nrow >= rmax) { 93 /* there is no extra room in row, therefore enlarge */ 94 int new_nz = ai[a->m] + CHUNKSIZE,len,*new_i,*new_j; 95 Scalar *new_a; 96 97 /* malloc new storage space */ 98 len = new_nz*(sizeof(int)+sizeof(Scalar))+(a->m+1)*sizeof(int); 99 new_a = (Scalar *) PetscMalloc( len ); CHKPTRQ(new_a); 100 new_j = (int *) (new_a + new_nz); 101 new_i = new_j + new_nz; 102 103 /* copy over old data into new slots */ 104 for ( ii=0; ii<row+1; ii++ ) {new_i[ii] = ai[ii];} 105 for ( ii=row+1; ii<a->m+1; ii++ ) {new_i[ii] = ai[ii]+CHUNKSIZE;} 106 PetscMemcpy(new_j,aj,(ai[row]+nrow+shift)*sizeof(int)); 107 len = (new_nz - CHUNKSIZE - ai[row] - nrow - shift); 108 PetscMemcpy(new_j+ai[row]+shift+nrow+CHUNKSIZE,aj+ai[row]+shift+nrow, 109 len*sizeof(int)); 110 PetscMemcpy(new_a,aa,(ai[row]+nrow+shift)*sizeof(Scalar)); 111 PetscMemcpy(new_a+ai[row]+shift+nrow+CHUNKSIZE,aa+ai[row]+shift+nrow, 112 len*sizeof(Scalar)); 113 /* free up old matrix storage */ 114 PetscFree(a->a); 115 if (!a->singlemalloc) {PetscFree(a->i);PetscFree(a->j);} 116 aa = a->a = new_a; ai = a->i = new_i; aj = a->j = new_j; 117 a->singlemalloc = 1; 118 119 rp = aj + ai[row] + shift; ap = aa + ai[row] + shift; 120 rmax = imax[row] = imax[row] + CHUNKSIZE; 121 PLogObjectMemory(A,CHUNKSIZE*(sizeof(int) + sizeof(Scalar))); 122 a->maxnz += CHUNKSIZE; 123 a->reallocs++; 124 } 125 N = nrow++ - 1; a->nz++; 126 /* shift up all the later entries in this row */ 127 for ( ii=N; ii>=i; ii-- ) { 128 rp[ii+1] = rp[ii]; 129 ap[ii+1] = ap[ii]; 130 } 131 rp[i] = col; 132 ap[i] = value; 133 noinsert:; 134 low = i + 1; 135 } 136 ailen[row] = nrow; 137 } 138 return 0; 139 } 140 141 static int MatGetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,Scalar *v) 142 { 143 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 144 int *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j; 145 int *ai = a->i, *ailen = a->ilen, shift = a->indexshift; 146 Scalar *ap, *aa = a->a, zero = 0.0; 147 148 for ( k=0; k<m; k++ ) { /* loop over rows */ 149 row = im[k]; 150 if (row < 0) SETERRQ(1,"MatGetValues_SeqAIJ:Negative row"); 151 if (row >= a->m) SETERRQ(1,"MatGetValues_SeqAIJ:Row too large"); 152 rp = aj + ai[row] + shift; ap = aa + ai[row] + shift; 153 nrow = ailen[row]; 154 for ( l=0; l<n; l++ ) { /* loop over columns */ 155 if (in[l] < 0) SETERRQ(1,"MatGetValues_SeqAIJ:Negative column"); 156 if (in[l] >= a->n) SETERRQ(1,"MatGetValues_SeqAIJ:Column too large"); 157 col = in[l] - shift; 158 high = nrow; low = 0; /* assume unsorted */ 159 while (high-low > 5) { 160 t = (low+high)/2; 161 if (rp[t] > col) high = t; 162 else low = t; 163 } 164 for ( i=low; i<high; i++ ) { 165 if (rp[i] > col) break; 166 if (rp[i] == col) { 167 *v++ = ap[i]; 168 goto finished; 169 } 170 } 171 *v++ = zero; 172 finished:; 173 } 174 } 175 return 0; 176 } 177 178 #include "draw.h" 179 #include "pinclude/pviewer.h" 180 #include "sysio.h" 181 182 static int MatView_SeqAIJ_Binary(Mat A,Viewer viewer) 183 { 184 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 185 int i, fd, *col_lens, ierr; 186 187 ierr = ViewerFileGetDescriptor_Private(viewer,&fd); CHKERRQ(ierr); 188 col_lens = (int *) PetscMalloc( (4+a->m)*sizeof(int) ); CHKPTRQ(col_lens); 189 col_lens[0] = MAT_COOKIE; 190 col_lens[1] = a->m; 191 col_lens[2] = a->n; 192 col_lens[3] = a->nz; 193 194 /* store lengths of each row and write (including header) to file */ 195 for ( i=0; i<a->m; i++ ) { 196 col_lens[4+i] = a->i[i+1] - a->i[i]; 197 } 198 ierr = SYWrite(fd,col_lens,4+a->m,SYINT,1); CHKERRQ(ierr); 199 PetscFree(col_lens); 200 201 /* store column indices (zero start index) */ 202 if (a->indexshift) { 203 for ( i=0; i<a->nz; i++ ) a->j[i]--; 204 } 205 ierr = SYWrite(fd,a->j,a->nz,SYINT,0); CHKERRQ(ierr); 206 if (a->indexshift) { 207 for ( i=0; i<a->nz; i++ ) a->j[i]++; 208 } 209 210 /* store nonzero values */ 211 ierr = SYWrite(fd,a->a,a->nz,SYSCALAR,0); CHKERRQ(ierr); 212 return 0; 213 } 214 215 static int MatView_SeqAIJ_ASCII(Mat A,Viewer viewer) 216 { 217 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 218 int ierr, i,j, m = a->m, shift = a->indexshift,format; 219 FILE *fd; 220 char *outputname; 221 222 ierr = ViewerFileGetPointer(viewer,&fd); CHKERRQ(ierr); 223 ierr = ViewerFileGetOutputname_Private(viewer,&outputname); CHKERRQ(ierr); 224 ierr = ViewerFileGetFormat_Private(viewer,&format); 225 if (format == FILE_FORMAT_INFO) { 226 /* no need to print additional information */ ; 227 } 228 else if (format == FILE_FORMAT_MATLAB) { 229 int nz, nzalloc, mem; 230 MatGetInfo(A,MAT_LOCAL,&nz,&nzalloc,&mem); 231 fprintf(fd,"%% Size = %d %d \n",m,a->n); 232 fprintf(fd,"%% Nonzeros = %d \n",nz); 233 fprintf(fd,"zzz = zeros(%d,3);\n",nz); 234 fprintf(fd,"zzz = [\n"); 235 236 for (i=0; i<m; i++) { 237 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 238 #if defined(PETSC_COMPLEX) 239 fprintf(fd,"%d %d %18.16e %18.16e \n",i+1,a->j[j]+!shift,real(a->a[j]), 240 imag(a->a[j])); 241 #else 242 fprintf(fd,"%d %d %18.16e\n", i+1, a->j[j]+!shift, a->a[j]); 243 #endif 244 } 245 } 246 fprintf(fd,"];\n %s = spconvert(zzz);\n",outputname); 247 } 248 else { 249 for ( i=0; i<m; i++ ) { 250 fprintf(fd,"row %d:",i); 251 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 252 #if defined(PETSC_COMPLEX) 253 if (imag(a->a[j]) != 0.0) { 254 fprintf(fd," %d %g + %g i",a->j[j]+shift,real(a->a[j]),imag(a->a[j])); 255 } 256 else { 257 fprintf(fd," %d %g ",a->j[j]+shift,real(a->a[j])); 258 } 259 #else 260 fprintf(fd," %d %g ",a->j[j]+shift,a->a[j]); 261 #endif 262 } 263 fprintf(fd,"\n"); 264 } 265 } 266 fflush(fd); 267 return 0; 268 } 269 270 static int MatView_SeqAIJ_Draw(Mat A,Viewer viewer) 271 { 272 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 273 int ierr, i,j, m = a->m, shift = a->indexshift,pause,color; 274 double xl,yl,xr,yr,w,h,xc,yc,scale = 1.0,x_l,x_r,y_l,y_r; 275 Draw draw = (Draw) viewer; 276 DrawButton button; 277 278 xr = a->n; yr = a->m; h = yr/10.0; w = xr/10.0; 279 xr += w; yr += h; xl = -w; yl = -h; 280 ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr); 281 /* loop over matrix elements drawing boxes */ 282 color = DRAW_BLUE; 283 for ( i=0; i<m; i++ ) { 284 y_l = m - i - 1.0; y_r = y_l + 1.0; 285 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 286 x_l = a->j[j] + shift; x_r = x_l + 1.0; 287 #if defined(PETSC_COMPLEX) 288 if (real(a->a[j]) >= 0.) continue; 289 #else 290 if (a->a[j] >= 0.) continue; 291 #endif 292 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 293 } 294 } 295 color = DRAW_CYAN; 296 for ( i=0; i<m; i++ ) { 297 y_l = m - i - 1.0; y_r = y_l + 1.0; 298 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 299 x_l = a->j[j] + shift; x_r = x_l + 1.0; 300 if (a->a[j] != 0.) continue; 301 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 302 } 303 } 304 color = DRAW_RED; 305 for ( i=0; i<m; i++ ) { 306 y_l = m - i - 1.0; y_r = y_l + 1.0; 307 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 308 x_l = a->j[j] + shift; x_r = x_l + 1.0; 309 #if defined(PETSC_COMPLEX) 310 if (real(a->a[j]) <= 0.) continue; 311 #else 312 if (a->a[j] <= 0.) continue; 313 #endif 314 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 315 } 316 } 317 DrawFlush(draw); 318 DrawGetPause(draw,&pause); 319 if (pause >= 0) { PetscSleep(pause); return 0;} 320 321 /* allow the matrix to zoom or shrink */ 322 ierr = DrawGetMouseButton(draw,&button,&xc,&yc,0,0); 323 while (button != BUTTON_RIGHT) { 324 DrawClear(draw); 325 if (button == BUTTON_LEFT) scale = .5; 326 else if (button == BUTTON_CENTER) scale = 2.; 327 xl = scale*(xl + w - xc) + xc - w*scale; 328 xr = scale*(xr - w - xc) + xc + w*scale; 329 yl = scale*(yl + h - yc) + yc - h*scale; 330 yr = scale*(yr - h - yc) + yc + h*scale; 331 w *= scale; h *= scale; 332 ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr); 333 color = DRAW_BLUE; 334 for ( i=0; i<m; i++ ) { 335 y_l = m - i - 1.0; y_r = y_l + 1.0; 336 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 337 x_l = a->j[j] + shift; x_r = x_l + 1.0; 338 #if defined(PETSC_COMPLEX) 339 if (real(a->a[j]) >= 0.) continue; 340 #else 341 if (a->a[j] >= 0.) continue; 342 #endif 343 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 344 } 345 } 346 color = DRAW_CYAN; 347 for ( i=0; i<m; i++ ) { 348 y_l = m - i - 1.0; y_r = y_l + 1.0; 349 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 350 x_l = a->j[j] + shift; x_r = x_l + 1.0; 351 if (a->a[j] != 0.) continue; 352 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 353 } 354 } 355 color = DRAW_RED; 356 for ( i=0; i<m; i++ ) { 357 y_l = m - i - 1.0; y_r = y_l + 1.0; 358 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 359 x_l = a->j[j] + shift; x_r = x_l + 1.0; 360 #if defined(PETSC_COMPLEX) 361 if (real(a->a[j]) <= 0.) continue; 362 #else 363 if (a->a[j] <= 0.) continue; 364 #endif 365 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 366 } 367 } 368 ierr = DrawGetMouseButton(draw,&button,&xc,&yc,0,0); 369 } 370 return 0; 371 } 372 373 static int MatView_SeqAIJ(PetscObject obj,Viewer viewer) 374 { 375 Mat A = (Mat) obj; 376 Mat_SeqAIJ *a = (Mat_SeqAIJ*) A->data; 377 PetscObject vobj = (PetscObject) viewer; 378 379 if (!viewer) { 380 viewer = STDOUT_VIEWER_SELF; vobj = (PetscObject) viewer; 381 } 382 if (vobj->cookie == VIEWER_COOKIE) { 383 if (vobj->type == MATLAB_VIEWER) { 384 return ViewerMatlabPutSparse_Private(viewer,a->m,a->n,a->nz,a->a,a->i,a->j); 385 } 386 else if (vobj->type == ASCII_FILE_VIEWER || vobj->type == ASCII_FILES_VIEWER){ 387 return MatView_SeqAIJ_ASCII(A,viewer); 388 } 389 else if (vobj->type == BINARY_FILE_VIEWER) { 390 return MatView_SeqAIJ_Binary(A,viewer); 391 } 392 } 393 else if (vobj->cookie == DRAW_COOKIE) { 394 if (vobj->type == NULLWINDOW) return 0; 395 else return MatView_SeqAIJ_Draw(A,viewer); 396 } 397 return 0; 398 } 399 extern int Mat_AIJ_CheckInode(Mat); 400 static int MatAssemblyEnd_SeqAIJ(Mat A,MatAssemblyType mode) 401 { 402 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 403 int fshift = 0,i,j,*ai = a->i, *aj = a->j, *imax = a->imax,ierr; 404 int m = a->m, *ip, N, *ailen = a->ilen,shift = a->indexshift; 405 Scalar *aa = a->a, *ap; 406 407 if (mode == FLUSH_ASSEMBLY) return 0; 408 409 for ( i=1; i<m; i++ ) { 410 /* move each row back by the amount of empty slots (fshift) before it*/ 411 fshift += imax[i-1] - ailen[i-1]; 412 if (fshift) { 413 ip = aj + ai[i] + shift; ap = aa + ai[i] + shift; 414 N = ailen[i]; 415 for ( j=0; j<N; j++ ) { 416 ip[j-fshift] = ip[j]; 417 ap[j-fshift] = ap[j]; 418 } 419 } 420 ai[i] = ai[i-1] + ailen[i-1]; 421 } 422 if (m) { 423 fshift += imax[m-1] - ailen[m-1]; 424 ai[m] = ai[m-1] + ailen[m-1]; 425 } 426 /* reset ilen and imax for each row */ 427 for ( i=0; i<m; i++ ) { 428 ailen[i] = imax[i] = ai[i+1] - ai[i]; 429 } 430 a->nz = ai[m] + shift; 431 432 /* diagonals may have moved, so kill the diagonal pointers */ 433 if (fshift && a->diag) { 434 PetscFree(a->diag); 435 PLogObjectMemory(A,-(m+1)*sizeof(int)); 436 a->diag = 0; 437 } 438 PLogInfo((PetscObject)A,"MatAssemblyEnd_SeqAIJ:Unneeded storage space %d used %d rows %d\n", 439 fshift,a->nz,m); 440 PLogInfo((PetscObject)A,"MatAssemblyEnd_SeqAIJ:Number of mallocs during MatSetValues %d\n", 441 a->reallocs); 442 /* check out for identical nodes. If found, use inode functions */ 443 ierr = Mat_AIJ_CheckInode(A); CHKERRQ(ierr); 444 return 0; 445 } 446 447 static int MatZeroEntries_SeqAIJ(Mat A) 448 { 449 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 450 PetscMemzero(a->a,(a->i[a->m]+a->indexshift)*sizeof(Scalar)); 451 return 0; 452 } 453 454 int MatDestroy_SeqAIJ(PetscObject obj) 455 { 456 Mat A = (Mat) obj; 457 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 458 459 #if defined(PETSC_LOG) 460 PLogObjectState(obj,"Rows=%d, Cols=%d, NZ=%d",a->m,a->n,a->nz); 461 #endif 462 PetscFree(a->a); 463 if (!a->singlemalloc) { PetscFree(a->i); PetscFree(a->j);} 464 if (a->diag) PetscFree(a->diag); 465 if (a->ilen) PetscFree(a->ilen); 466 if (a->imax) PetscFree(a->imax); 467 if (a->solve_work) PetscFree(a->solve_work); 468 if (a->inode.size) PetscFree(a->inode.size); 469 PetscFree(a); 470 PLogObjectDestroy(A); 471 PetscHeaderDestroy(A); 472 return 0; 473 } 474 475 static int MatCompress_SeqAIJ(Mat A) 476 { 477 return 0; 478 } 479 480 static int MatSetOption_SeqAIJ(Mat A,MatOption op) 481 { 482 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 483 if (op == ROW_ORIENTED) a->roworiented = 1; 484 else if (op == COLUMN_ORIENTED) a->roworiented = 0; 485 else if (op == COLUMNS_SORTED) a->sorted = 1; 486 else if (op == NO_NEW_NONZERO_LOCATIONS) a->nonew = 1; 487 else if (op == YES_NEW_NONZERO_LOCATIONS) a->nonew = 0; 488 else if (op == ROWS_SORTED || 489 op == SYMMETRIC_MATRIX || 490 op == STRUCTURALLY_SYMMETRIC_MATRIX || 491 op == YES_NEW_DIAGONALS) 492 PLogInfo((PetscObject)A,"Info:MatSetOption_SeqAIJ:Option ignored\n"); 493 else if (op == NO_NEW_DIAGONALS) 494 {SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqAIJ:NO_NEW_DIAGONALS");} 495 else if (op == INODE_LIMIT_1) a->inode.limit = 1; 496 else if (op == INODE_LIMIT_2) a->inode.limit = 2; 497 else if (op == INODE_LIMIT_3) a->inode.limit = 3; 498 else if (op == INODE_LIMIT_4) a->inode.limit = 4; 499 else if (op == INODE_LIMIT_5) a->inode.limit = 5; 500 else 501 {SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqAIJ:unknown option");} 502 return 0; 503 } 504 505 static int MatGetDiagonal_SeqAIJ(Mat A,Vec v) 506 { 507 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 508 int i,j, n,shift = a->indexshift; 509 Scalar *x, zero = 0.0; 510 511 VecSet(&zero,v); 512 VecGetArray(v,&x); VecGetLocalSize(v,&n); 513 if (n != a->m) SETERRQ(1,"MatGetDiagonal_SeqAIJ:Nonconforming matrix and vector"); 514 for ( i=0; i<a->m; i++ ) { 515 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 516 if (a->j[j]+shift == i) { 517 x[i] = a->a[j]; 518 break; 519 } 520 } 521 } 522 return 0; 523 } 524 525 /* -------------------------------------------------------*/ 526 /* Should check that shapes of vectors and matrices match */ 527 /* -------------------------------------------------------*/ 528 static int MatMultTrans_SeqAIJ(Mat A,Vec xx,Vec yy) 529 { 530 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 531 Scalar *x, *y, *v, alpha; 532 int m = a->m, n, i, *idx, shift = a->indexshift; 533 534 VecGetArray(xx,&x); VecGetArray(yy,&y); 535 PetscMemzero(y,a->n*sizeof(Scalar)); 536 y = y + shift; /* shift for Fortran start by 1 indexing */ 537 for ( i=0; i<m; i++ ) { 538 idx = a->j + a->i[i] + shift; 539 v = a->a + a->i[i] + shift; 540 n = a->i[i+1] - a->i[i]; 541 alpha = x[i]; 542 while (n-->0) {y[*idx++] += alpha * *v++;} 543 } 544 PLogFlops(2*a->nz - a->n); 545 return 0; 546 } 547 548 static int MatMultTransAdd_SeqAIJ(Mat A,Vec xx,Vec zz,Vec yy) 549 { 550 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 551 Scalar *x, *y, *v, alpha; 552 int m = a->m, n, i, *idx,shift = a->indexshift; 553 554 VecGetArray(xx,&x); VecGetArray(yy,&y); 555 if (zz != yy) VecCopy(zz,yy); 556 y = y + shift; /* shift for Fortran start by 1 indexing */ 557 for ( i=0; i<m; i++ ) { 558 idx = a->j + a->i[i] + shift; 559 v = a->a + a->i[i] + shift; 560 n = a->i[i+1] - a->i[i]; 561 alpha = x[i]; 562 while (n-->0) {y[*idx++] += alpha * *v++;} 563 } 564 return 0; 565 } 566 567 static int MatMult_SeqAIJ(Mat A,Vec xx,Vec yy) 568 { 569 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 570 Scalar *x, *y, *v, sum; 571 int m = a->m, n, i, *idx, shift = a->indexshift,*ii; 572 573 VecGetArray(xx,&x); VecGetArray(yy,&y); 574 x = x + shift; /* shift for Fortran start by 1 indexing */ 575 idx = a->j; 576 v = a->a; 577 ii = a->i; 578 for ( i=0; i<m; i++ ) { 579 n = ii[1] - ii[0]; ii++; 580 sum = 0.0; 581 /* SPARSEDENSEDOT(sum,x,v,idx,n); */ 582 /* for ( j=n-1; j>-1; j--) sum += v[j]*x[idx[j]]; */ 583 while (n--) sum += *v++ * x[*idx++]; 584 y[i] = sum; 585 } 586 PLogFlops(2*a->nz - m); 587 return 0; 588 } 589 590 static int MatMultAdd_SeqAIJ(Mat A,Vec xx,Vec yy,Vec zz) 591 { 592 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 593 Scalar *x, *y, *z, *v, sum; 594 int m = a->m, n, i, *idx, shift = a->indexshift,*ii; 595 596 VecGetArray(xx,&x); VecGetArray(yy,&y); VecGetArray(zz,&z); 597 x = x + shift; /* shift for Fortran start by 1 indexing */ 598 idx = a->j; 599 v = a->a; 600 ii = a->i; 601 for ( i=0; i<m; i++ ) { 602 n = ii[1] - ii[0]; ii++; 603 sum = y[i]; 604 /* SPARSEDENSEDOT(sum,x,v,idx,n); */ 605 while (n--) sum += *v++ * x[*idx++]; 606 z[i] = sum; 607 } 608 PLogFlops(2*a->nz); 609 return 0; 610 } 611 612 /* 613 Adds diagonal pointers to sparse matrix structure. 614 */ 615 616 int MatMarkDiag_SeqAIJ(Mat A) 617 { 618 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 619 int i,j, *diag, m = a->m,shift = a->indexshift; 620 621 diag = (int *) PetscMalloc( (m+1)*sizeof(int)); CHKPTRQ(diag); 622 PLogObjectMemory(A,(m+1)*sizeof(int)); 623 for ( i=0; i<a->m; i++ ) { 624 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 625 if (a->j[j]+shift == i) { 626 diag[i] = j - shift; 627 break; 628 } 629 } 630 } 631 a->diag = diag; 632 return 0; 633 } 634 635 static int MatRelax_SeqAIJ(Mat A,Vec bb,double omega,MatSORType flag, 636 double fshift,int its,Vec xx) 637 { 638 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 639 Scalar *x, *b, *bs, d, *xs, sum, *v = a->a,*t,scale,*ts, *xb; 640 int ierr, *idx, *diag,n = a->n, m = a->m, i, shift = a->indexshift; 641 642 VecGetArray(xx,&x); VecGetArray(bb,&b); 643 if (!a->diag) {if ((ierr = MatMarkDiag_SeqAIJ(A))) return ierr;} 644 diag = a->diag; 645 xs = x + shift; /* shifted by one for index start of a or a->j*/ 646 if (flag == SOR_APPLY_UPPER) { 647 /* apply ( U + D/omega) to the vector */ 648 bs = b + shift; 649 for ( i=0; i<m; i++ ) { 650 d = fshift + a->a[diag[i] + shift]; 651 n = a->i[i+1] - diag[i] - 1; 652 idx = a->j + diag[i] + (!shift); 653 v = a->a + diag[i] + (!shift); 654 sum = b[i]*d/omega; 655 SPARSEDENSEDOT(sum,bs,v,idx,n); 656 x[i] = sum; 657 } 658 return 0; 659 } 660 if (flag == SOR_APPLY_LOWER) { 661 SETERRQ(1,"MatRelax_SeqAIJ:SOR_APPLY_LOWER is not done"); 662 } 663 else if (flag & SOR_EISENSTAT) { 664 /* Let A = L + U + D; where L is lower trianglar, 665 U is upper triangular, E is diagonal; This routine applies 666 667 (L + E)^{-1} A (U + E)^{-1} 668 669 to a vector efficiently using Eisenstat's trick. This is for 670 the case of SSOR preconditioner, so E is D/omega where omega 671 is the relaxation factor. 672 */ 673 t = (Scalar *) PetscMalloc( m*sizeof(Scalar) ); CHKPTRQ(t); 674 scale = (2.0/omega) - 1.0; 675 676 /* x = (E + U)^{-1} b */ 677 for ( i=m-1; i>=0; i-- ) { 678 d = fshift + a->a[diag[i] + shift]; 679 n = a->i[i+1] - diag[i] - 1; 680 idx = a->j + diag[i] + (!shift); 681 v = a->a + diag[i] + (!shift); 682 sum = b[i]; 683 SPARSEDENSEMDOT(sum,xs,v,idx,n); 684 x[i] = omega*(sum/d); 685 } 686 687 /* t = b - (2*E - D)x */ 688 v = a->a; 689 for ( i=0; i<m; i++ ) { t[i] = b[i] - scale*(v[*diag++ + shift])*x[i]; } 690 691 /* t = (E + L)^{-1}t */ 692 ts = t + shift; /* shifted by one for index start of a or a->j*/ 693 diag = a->diag; 694 for ( i=0; i<m; i++ ) { 695 d = fshift + a->a[diag[i]+shift]; 696 n = diag[i] - a->i[i]; 697 idx = a->j + a->i[i] + shift; 698 v = a->a + a->i[i] + shift; 699 sum = t[i]; 700 SPARSEDENSEMDOT(sum,ts,v,idx,n); 701 t[i] = omega*(sum/d); 702 } 703 704 /* x = x + t */ 705 for ( i=0; i<m; i++ ) { x[i] += t[i]; } 706 PetscFree(t); 707 return 0; 708 } 709 if (flag & SOR_ZERO_INITIAL_GUESS) { 710 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){ 711 for ( i=0; i<m; i++ ) { 712 d = fshift + a->a[diag[i]+shift]; 713 n = diag[i] - a->i[i]; 714 idx = a->j + a->i[i] + shift; 715 v = a->a + a->i[i] + shift; 716 sum = b[i]; 717 SPARSEDENSEMDOT(sum,xs,v,idx,n); 718 x[i] = omega*(sum/d); 719 } 720 xb = x; 721 } 722 else xb = b; 723 if ((flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) && 724 (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP)) { 725 for ( i=0; i<m; i++ ) { 726 x[i] *= a->a[diag[i]+shift]; 727 } 728 } 729 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){ 730 for ( i=m-1; i>=0; i-- ) { 731 d = fshift + a->a[diag[i] + shift]; 732 n = a->i[i+1] - diag[i] - 1; 733 idx = a->j + diag[i] + (!shift); 734 v = a->a + diag[i] + (!shift); 735 sum = xb[i]; 736 SPARSEDENSEMDOT(sum,xs,v,idx,n); 737 x[i] = omega*(sum/d); 738 } 739 } 740 its--; 741 } 742 while (its--) { 743 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){ 744 for ( i=0; i<m; i++ ) { 745 d = fshift + a->a[diag[i]+shift]; 746 n = a->i[i+1] - a->i[i]; 747 idx = a->j + a->i[i] + shift; 748 v = a->a + a->i[i] + shift; 749 sum = b[i]; 750 SPARSEDENSEMDOT(sum,xs,v,idx,n); 751 x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]); 752 } 753 } 754 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){ 755 for ( i=m-1; i>=0; i-- ) { 756 d = fshift + a->a[diag[i] + shift]; 757 n = a->i[i+1] - a->i[i]; 758 idx = a->j + a->i[i] + shift; 759 v = a->a + a->i[i] + shift; 760 sum = b[i]; 761 SPARSEDENSEMDOT(sum,xs,v,idx,n); 762 x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]); 763 } 764 } 765 } 766 return 0; 767 } 768 769 static int MatGetInfo_SeqAIJ(Mat A,MatInfoType flag,int *nz,int *nzalloc,int *mem) 770 { 771 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 772 *nz = a->nz; 773 *nzalloc = a->maxnz; 774 *mem = (int)A->mem; 775 return 0; 776 } 777 778 extern int MatLUFactorSymbolic_SeqAIJ(Mat,IS,IS,double,Mat*); 779 extern int MatLUFactorNumeric_SeqAIJ(Mat,Mat*); 780 extern int MatLUFactor_SeqAIJ(Mat,IS,IS,double); 781 extern int MatSolve_SeqAIJ(Mat,Vec,Vec); 782 extern int MatSolveAdd_SeqAIJ(Mat,Vec,Vec,Vec); 783 extern int MatSolveTrans_SeqAIJ(Mat,Vec,Vec); 784 extern int MatSolveTransAdd_SeqAIJ(Mat,Vec,Vec,Vec); 785 786 static int MatZeroRows_SeqAIJ(Mat A,IS is,Scalar *diag) 787 { 788 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 789 int i,ierr,N, *rows,m = a->m - 1,shift = a->indexshift; 790 791 ierr = ISGetLocalSize(is,&N); CHKERRQ(ierr); 792 ierr = ISGetIndices(is,&rows); CHKERRQ(ierr); 793 if (diag) { 794 for ( i=0; i<N; i++ ) { 795 if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range"); 796 if (a->ilen[rows[i]] > 0) { /* in case row was completely empty */ 797 a->ilen[rows[i]] = 1; 798 a->a[a->i[rows[i]]+shift] = *diag; 799 a->j[a->i[rows[i]]+shift] = rows[i]+shift; 800 } 801 else { 802 ierr = MatSetValues_SeqAIJ(A,1,&rows[i],1,&rows[i],diag,INSERT_VALUES); 803 CHKERRQ(ierr); 804 } 805 } 806 } 807 else { 808 for ( i=0; i<N; i++ ) { 809 if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range"); 810 a->ilen[rows[i]] = 0; 811 } 812 } 813 ISRestoreIndices(is,&rows); 814 ierr = MatAssemblyBegin(A,FINAL_ASSEMBLY); CHKERRQ(ierr); 815 ierr = MatAssemblyEnd(A,FINAL_ASSEMBLY); CHKERRQ(ierr); 816 return 0; 817 } 818 819 static int MatGetSize_SeqAIJ(Mat A,int *m,int *n) 820 { 821 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 822 *m = a->m; *n = a->n; 823 return 0; 824 } 825 826 static int MatGetOwnershipRange_SeqAIJ(Mat A,int *m,int *n) 827 { 828 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 829 *m = 0; *n = a->m; 830 return 0; 831 } 832 static int MatGetRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v) 833 { 834 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 835 int *itmp,i,shift = a->indexshift; 836 837 if (row < 0 || row >= a->m) SETERRQ(1,"MatGetRow_SeqAIJ:Row out of range"); 838 839 *nz = a->i[row+1] - a->i[row]; 840 if (v) *v = a->a + a->i[row] + shift; 841 if (idx) { 842 if (*nz) { 843 itmp = a->j + a->i[row] + shift; 844 *idx = (int *) PetscMalloc( (*nz)*sizeof(int) ); CHKPTRQ(*idx); 845 for ( i=0; i<(*nz); i++ ) {(*idx)[i] = itmp[i] + shift;} 846 } 847 else *idx = 0; 848 } 849 return 0; 850 } 851 852 static int MatRestoreRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v) 853 { 854 if (idx) {if (*idx) PetscFree(*idx);} 855 return 0; 856 } 857 858 static int MatNorm_SeqAIJ(Mat A,NormType type,double *norm) 859 { 860 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 861 Scalar *v = a->a; 862 double sum = 0.0; 863 int i, j,shift = a->indexshift; 864 865 if (type == NORM_FROBENIUS) { 866 for (i=0; i<a->nz; i++ ) { 867 #if defined(PETSC_COMPLEX) 868 sum += real(conj(*v)*(*v)); v++; 869 #else 870 sum += (*v)*(*v); v++; 871 #endif 872 } 873 *norm = sqrt(sum); 874 } 875 else if (type == NORM_1) { 876 double *tmp; 877 int *jj = a->j; 878 tmp = (double *) PetscMalloc( a->n*sizeof(double) ); CHKPTRQ(tmp); 879 PetscMemzero(tmp,a->n*sizeof(double)); 880 *norm = 0.0; 881 for ( j=0; j<a->nz; j++ ) { 882 tmp[*jj++ + shift] += PetscAbsScalar(*v); v++; 883 } 884 for ( j=0; j<a->n; j++ ) { 885 if (tmp[j] > *norm) *norm = tmp[j]; 886 } 887 PetscFree(tmp); 888 } 889 else if (type == NORM_INFINITY) { 890 *norm = 0.0; 891 for ( j=0; j<a->m; j++ ) { 892 v = a->a + a->i[j] + shift; 893 sum = 0.0; 894 for ( i=0; i<a->i[j+1]-a->i[j]; i++ ) { 895 sum += PetscAbsScalar(*v); v++; 896 } 897 if (sum > *norm) *norm = sum; 898 } 899 } 900 else { 901 SETERRQ(1,"MatNorm_SeqAIJ:No support for two norm yet"); 902 } 903 return 0; 904 } 905 906 static int MatTranspose_SeqAIJ(Mat A,Mat *B) 907 { 908 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 909 Mat C; 910 int i, ierr, *aj = a->j, *ai = a->i, m = a->m, len, *col; 911 int shift = a->indexshift; 912 Scalar *array = a->a; 913 914 if (B == PETSC_NULL && m != a->n) 915 SETERRQ(1,"MatTranspose_MPIAIJ:Square matrix only for in-place"); 916 col = (int *) PetscMalloc((1+a->n)*sizeof(int)); CHKPTRQ(col); 917 PetscMemzero(col,(1+a->n)*sizeof(int)); 918 if (shift) { 919 for ( i=0; i<ai[m]-1; i++ ) aj[i] -= 1; 920 } 921 for ( i=0; i<ai[m]+shift; i++ ) col[aj[i]] += 1; 922 ierr = MatCreateSeqAIJ(A->comm,a->n,m,0,col,&C); CHKERRQ(ierr); 923 PetscFree(col); 924 for ( i=0; i<m; i++ ) { 925 len = ai[i+1]-ai[i]; 926 ierr = MatSetValues(C,len,aj,1,&i,array,INSERT_VALUES); CHKERRQ(ierr); 927 array += len; aj += len; 928 } 929 if (shift) { 930 for ( i=0; i<ai[m]-1; i++ ) aj[i] += 1; 931 } 932 933 ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 934 ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 935 936 if (B != PETSC_NULL) { 937 *B = C; 938 } else { 939 /* This isn't really an in-place transpose */ 940 PetscFree(a->a); 941 if (!a->singlemalloc) {PetscFree(a->i); PetscFree(a->j);} 942 if (a->diag) PetscFree(a->diag); 943 if (a->ilen) PetscFree(a->ilen); 944 if (a->imax) PetscFree(a->imax); 945 if (a->solve_work) PetscFree(a->solve_work); 946 PetscFree(a); 947 PetscMemcpy(A,C,sizeof(struct _Mat)); 948 PetscHeaderDestroy(C); 949 } 950 return 0; 951 } 952 953 static int MatDiagonalScale_SeqAIJ(Mat A,Vec ll,Vec rr) 954 { 955 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 956 Scalar *l,*r,x,*v; 957 int i,j,m = a->m, n = a->n, M, nz = a->nz, *jj,shift = a->indexshift; 958 959 if (ll) { 960 VecGetArray(ll,&l); VecGetSize(ll,&m); 961 if (m != a->m) SETERRQ(1,"MatDiagonalScale_SeqAIJ:Left scaling vector wrong length"); 962 v = a->a; 963 for ( i=0; i<m; i++ ) { 964 x = l[i]; 965 M = a->i[i+1] - a->i[i]; 966 for ( j=0; j<M; j++ ) { (*v++) *= x;} 967 } 968 } 969 if (rr) { 970 VecGetArray(rr,&r); VecGetSize(rr,&n); 971 if (n != a->n) SETERRQ(1,"MatDiagonalScale_SeqAIJ:Right scaling vector wrong length"); 972 v = a->a; jj = a->j; 973 for ( i=0; i<nz; i++ ) { 974 (*v++) *= r[*jj++ + shift]; 975 } 976 } 977 return 0; 978 } 979 980 static int MatGetSubMatrix_SeqAIJ(Mat A,IS isrow,IS iscol,MatGetSubMatrixCall scall,Mat *B) 981 { 982 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data,*c; 983 int nznew, *smap, i, k, kstart, kend, ierr, oldcols = a->n,*lens; 984 register int sum,lensi; 985 int *irow, *icol, nrows, ncols, *cwork, shift = a->indexshift,*ssmap; 986 int first,step,*starts,*j_new,*i_new,*aj = a->j, *ai = a->i,ii,*ailen = a->ilen; 987 Scalar *vwork,*a_new; 988 Mat C; 989 990 ierr = ISGetIndices(isrow,&irow); CHKERRQ(ierr); 991 ierr = ISGetSize(isrow,&nrows); CHKERRQ(ierr); 992 ierr = ISGetSize(iscol,&ncols); CHKERRQ(ierr); 993 ierr = SYIsort(nrows, irow); CHKERRQ(ierr); 994 995 if (ISStrideGetInfo(iscol,&first,&step) && step == 1) { /* no need to sort */ 996 /* special case of contiguous rows */ 997 lens = (int *) PetscMalloc((2*ncols+1)*sizeof(int)); CHKPTRQ(lens); 998 starts = lens + ncols; 999 /* loop over new rows determining lens and starting points */ 1000 for (i=0; i<nrows; i++) { 1001 kstart = ai[irow[i]]+shift; 1002 kend = kstart + ailen[irow[i]]; 1003 for ( k=kstart; k<kend; k++ ) { 1004 if (aj[k]+shift >= first) { 1005 starts[i] = k; 1006 break; 1007 } 1008 } 1009 sum = 0; 1010 while (k < kend) { 1011 if (aj[k++]+shift >= first+ncols) break; 1012 sum++; 1013 } 1014 lens[i] = sum; 1015 } 1016 /* create submatrix */ 1017 if (scall == MAT_REUSE_MATRIX) { 1018 int n_cols,n_rows; 1019 ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr); 1020 if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:"); 1021 ierr = MatZeroEntries(*B); CHKERRQ(ierr); 1022 C = *B; 1023 } 1024 else { 1025 ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr); 1026 } 1027 c = (Mat_SeqAIJ*) C->data; 1028 1029 /* loop over rows inserting into submatrix */ 1030 a_new = c->a; 1031 j_new = c->j; 1032 i_new = c->i; 1033 i_new[0] = -shift; 1034 for (i=0; i<nrows; i++) { 1035 ii = starts[i]; 1036 lensi = lens[i]; 1037 for ( k=0; k<lensi; k++ ) { 1038 *j_new++ = aj[ii+k] - first; 1039 } 1040 PetscMemcpy(a_new,a->a + starts[i],lensi*sizeof(Scalar)); 1041 a_new += lensi; 1042 i_new[i+1] = i_new[i] + lensi; 1043 c->ilen[i] = lensi; 1044 } 1045 PetscFree(lens); 1046 } 1047 else { 1048 ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr); 1049 ierr = SYIsort(ncols,icol); CHKERRQ(ierr); 1050 smap = (int *) PetscMalloc((1+oldcols)*sizeof(int)); CHKPTRQ(smap); 1051 ssmap = smap + shift; 1052 cwork = (int *) PetscMalloc((1+nrows+ncols)*sizeof(int)); CHKPTRQ(cwork); 1053 lens = cwork + ncols; 1054 vwork = (Scalar *) PetscMalloc((1+ncols)*sizeof(Scalar)); CHKPTRQ(vwork); 1055 PetscMemzero(smap,oldcols*sizeof(int)); 1056 for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1; 1057 /* determine lens of each row */ 1058 for (i=0; i<nrows; i++) { 1059 kstart = ai[irow[i]]+shift; 1060 kend = kstart + a->ilen[irow[i]]; 1061 lens[i] = 0; 1062 for ( k=kstart; k<kend; k++ ) { 1063 if (ssmap[aj[k]]) { 1064 lens[i]++; 1065 } 1066 } 1067 } 1068 /* Create and fill new matrix */ 1069 if (scall == MAT_REUSE_MATRIX) { 1070 int n_cols,n_rows; 1071 ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr); 1072 if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:"); 1073 ierr = MatZeroEntries(*B); CHKERRQ(ierr); 1074 C = *B; 1075 } 1076 else { 1077 ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr); 1078 } 1079 for (i=0; i<nrows; i++) { 1080 nznew = 0; 1081 kstart = ai[irow[i]]+shift; 1082 kend = kstart + a->ilen[irow[i]]; 1083 for ( k=kstart; k<kend; k++ ) { 1084 if (ssmap[a->j[k]]) { 1085 cwork[nznew] = ssmap[a->j[k]] - 1; 1086 vwork[nznew++] = a->a[k]; 1087 } 1088 } 1089 ierr = MatSetValues(C,1,&i,nznew,cwork,vwork,INSERT_VALUES); CHKERRQ(ierr); 1090 } 1091 /* Free work space */ 1092 ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr); 1093 PetscFree(smap); PetscFree(cwork); PetscFree(vwork); 1094 } 1095 ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 1096 ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 1097 1098 ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr); 1099 *B = C; 1100 return 0; 1101 } 1102 1103 /* 1104 note: This can only work for identity for row and col. It would 1105 be good to check this and otherwise generate an error. 1106 */ 1107 static int MatILUFactor_SeqAIJ(Mat inA,IS row,IS col,double efill,int fill) 1108 { 1109 Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data; 1110 int ierr; 1111 Mat outA; 1112 1113 if (fill != 0) SETERRQ(1,"MatILUFactor_SeqAIJ:Only fill=0 supported"); 1114 1115 outA = inA; 1116 inA->factor = FACTOR_LU; 1117 a->row = row; 1118 a->col = col; 1119 1120 a->solve_work = (Scalar *) PetscMalloc( (a->m+1)*sizeof(Scalar)); CHKPTRQ(a->solve_work); 1121 1122 if (!a->diag) { 1123 ierr = MatMarkDiag_SeqAIJ(inA); CHKERRQ(ierr); 1124 } 1125 ierr = MatLUFactorNumeric_SeqAIJ(inA,&outA); CHKERRQ(ierr); 1126 return 0; 1127 } 1128 1129 #include "pinclude/plapack.h" 1130 static int MatScale_SeqAIJ(Scalar *alpha,Mat inA) 1131 { 1132 Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data; 1133 int one = 1; 1134 BLscal_( &a->nz, alpha, a->a, &one ); 1135 PLogFlops(a->nz); 1136 return 0; 1137 } 1138 1139 static int MatGetSubMatrices_SeqAIJ(Mat A,int n, IS *irow,IS *icol,MatGetSubMatrixCall scall, 1140 Mat **B) 1141 { 1142 int ierr,i; 1143 1144 if (scall == MAT_INITIAL_MATRIX) { 1145 *B = (Mat *) PetscMalloc( (n+1)*sizeof(Mat) ); CHKPTRQ(*B); 1146 } 1147 1148 for ( i=0; i<n; i++ ) { 1149 ierr = MatGetSubMatrix(A,irow[i],icol[i],scall,&(*B)[i]); CHKERRQ(ierr); 1150 } 1151 return 0; 1152 } 1153 1154 static int MatIncreaseOverlap_SeqAIJ(Mat A, int is_max, IS *is, int ov) 1155 { 1156 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 1157 int shift, row, i,j,k,l,m,n, *idx,ierr, *nidx, isz, val; 1158 int start, end, *ai, *aj; 1159 char *table; 1160 shift = a->indexshift; 1161 m = a->m; 1162 ai = a->i; 1163 aj = a->j+shift; 1164 1165 if (ov < 0) SETERRQ(1,"MatIncreaseOverlap_SeqAIJ: illegal overlap value used"); 1166 1167 table = (char *) PetscMalloc((m/BITSPERBYTE +1)*sizeof(char)); CHKPTRQ(table); 1168 nidx = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(nidx); 1169 1170 for ( i=0; i<is_max; i++ ) { 1171 /* Initialise the two local arrays */ 1172 isz = 0; 1173 PetscMemzero(table,(m/BITSPERBYTE +1)*sizeof(char)); 1174 1175 /* Extract the indices, assume there can be duplicate entries */ 1176 ierr = ISGetIndices(is[i],&idx); CHKERRQ(ierr); 1177 ierr = ISGetLocalSize(is[i],&n); CHKERRQ(ierr); 1178 1179 /* Enter these into the temp arrays i.e mark table[row], enter row into new index */ 1180 for ( j=0; j<n ; ++j){ 1181 if(!BT_LOOKUP(table, idx[j])) { nidx[isz++] = idx[j];} 1182 } 1183 ierr = ISRestoreIndices(is[i],&idx); CHKERRQ(ierr); 1184 ierr = ISDestroy(is[i]); CHKERRQ(ierr); 1185 1186 k = 0; 1187 for ( j=0; j<ov; j++){ /* for each overlap*/ 1188 n = isz; 1189 for ( ; k<n ; k++){ /* do only those rows in nidx[k], which are not done yet */ 1190 row = nidx[k]; 1191 start = ai[row]; 1192 end = ai[row+1]; 1193 for ( l = start; l<end ; l++){ 1194 val = aj[l] + shift; 1195 if (!BT_LOOKUP(table,val)) {nidx[isz++] = val;} 1196 } 1197 } 1198 } 1199 ierr = ISCreateSeq(MPI_COMM_SELF, isz, nidx, (is+i)); CHKERRQ(ierr); 1200 } 1201 PetscFree(table); 1202 PetscFree(nidx); 1203 return 0; 1204 } 1205 1206 int MatPrintHelp_SeqAIJ(Mat A) 1207 { 1208 static int called = 0; 1209 MPI_Comm comm = A->comm; 1210 1211 if (called) return 0; else called = 1; 1212 MPIU_printf(comm," Options for MATSEQAIJ and MATMPIAIJ matrix formats (the defaults):\n"); 1213 MPIU_printf(comm," -mat_lu_pivotthreshold <threshold>\n"); 1214 MPIU_printf(comm," -mat_aij_oneindex - internal indices begin at 1 instead of the default 0.\n"); 1215 MPIU_printf(comm," -mat_aij_no_inode - Do not use inodes\n"); 1216 MPIU_printf(comm," -mat_aij_inode_limit <limit> - Set inode limit (max limit=5)\n"); 1217 #if defined(HAVE_ESSL) 1218 MPIU_printf(comm," -mat_aij_essl - Use IBM sparse LU factorization and solve.\n"); 1219 #endif 1220 return 0; 1221 } 1222 int MatEqual_SeqAIJ(Mat A,Mat B, int* flg); 1223 /* -------------------------------------------------------------------*/ 1224 static struct _MatOps MatOps = {MatSetValues_SeqAIJ, 1225 MatGetRow_SeqAIJ,MatRestoreRow_SeqAIJ, 1226 MatMult_SeqAIJ,MatMultAdd_SeqAIJ, 1227 MatMultTrans_SeqAIJ,MatMultTransAdd_SeqAIJ, 1228 MatSolve_SeqAIJ,MatSolveAdd_SeqAIJ, 1229 MatSolveTrans_SeqAIJ,MatSolveTransAdd_SeqAIJ, 1230 MatLUFactor_SeqAIJ,0, 1231 MatRelax_SeqAIJ, 1232 MatTranspose_SeqAIJ, 1233 MatGetInfo_SeqAIJ,MatEqual_SeqAIJ, 1234 MatGetDiagonal_SeqAIJ,MatDiagonalScale_SeqAIJ,MatNorm_SeqAIJ, 1235 0,MatAssemblyEnd_SeqAIJ, 1236 MatCompress_SeqAIJ, 1237 MatSetOption_SeqAIJ,MatZeroEntries_SeqAIJ,MatZeroRows_SeqAIJ, 1238 MatGetReordering_SeqAIJ, 1239 MatLUFactorSymbolic_SeqAIJ,MatLUFactorNumeric_SeqAIJ,0,0, 1240 MatGetSize_SeqAIJ,MatGetSize_SeqAIJ,MatGetOwnershipRange_SeqAIJ, 1241 MatILUFactorSymbolic_SeqAIJ,0, 1242 0,0,MatConvert_SeqAIJ, 1243 MatGetSubMatrix_SeqAIJ,0, 1244 MatConvertSameType_SeqAIJ,0,0, 1245 MatILUFactor_SeqAIJ,0,0, 1246 MatGetSubMatrices_SeqAIJ,MatIncreaseOverlap_SeqAIJ, 1247 MatGetValues_SeqAIJ,0, 1248 MatPrintHelp_SeqAIJ, 1249 MatScale_SeqAIJ}; 1250 1251 extern int MatUseSuperLU_SeqAIJ(Mat); 1252 extern int MatUseEssl_SeqAIJ(Mat); 1253 extern int MatUseDXML_SeqAIJ(Mat); 1254 1255 /*@C 1256 MatCreateSeqAIJ - Creates a sparse matrix in AIJ (compressed row) format 1257 (the default parallel PETSc format). For good matrix assembly performance 1258 the user should preallocate the matrix storage by setting the parameter nz 1259 (or nzz). By setting these parameters accurately, performance can be 1260 increased by more than a factor of 50. 1261 1262 Input Parameters: 1263 . comm - MPI communicator, set to MPI_COMM_SELF 1264 . m - number of rows 1265 . n - number of columns 1266 . nz - number of nonzeros per row (same for all rows) 1267 . nzz - number of nonzeros per row or null (possibly different for each row) 1268 1269 Output Parameter: 1270 . A - the matrix 1271 1272 Notes: 1273 The AIJ format (also called the Yale sparse matrix format or 1274 compressed row storage), is fully compatible with standard Fortran 77 1275 storage. That is, the stored row and column indices can begin at 1276 either one (as in Fortran) or zero. See the users manual for details. 1277 1278 Specify the preallocated storage with either nz or nnz (not both). 1279 Set nz=PETSC_DEFAULT and nnz=PETSC_NULL for PETSc to control dynamic memory 1280 allocation. For additional details, see the users manual chapter on 1281 matrices and the file $(PETSC_DIR)/Performance. 1282 1283 By default, this format uses inodes (identical nodes) when possible, to 1284 improve numerical efficiency of Matrix vector products and solves. We 1285 search for consecutive rows with the same nonzero structure, thereby 1286 reusing matrix information to achieve increased efficiency. 1287 1288 Options Database Keys: 1289 $ -mat_aij_no_inode - Do not use inodes 1290 $ -mat_aij_inode_limit <limit> - Set inode limit. 1291 $ (max limit=5) 1292 $ -mat_aij_oneindex - Internally use indexing starting at 1 1293 $ rather than 0. Note: When calling MatSetValues(), 1294 $ the user still MUST index entries starting at 0! 1295 1296 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues() 1297 @*/ 1298 int MatCreateSeqAIJ(MPI_Comm comm,int m,int n,int nz,int *nnz, Mat *A) 1299 { 1300 Mat B; 1301 Mat_SeqAIJ *b; 1302 int i,len,ierr, flg; 1303 1304 *A = 0; 1305 PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSEQAIJ,comm); 1306 PLogObjectCreate(B); 1307 B->data = (void *) (b = PetscNew(Mat_SeqAIJ)); CHKPTRQ(b); 1308 PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps)); 1309 B->destroy = MatDestroy_SeqAIJ; 1310 B->view = MatView_SeqAIJ; 1311 B->factor = 0; 1312 B->lupivotthreshold = 1.0; 1313 ierr = OptionsGetDouble(PETSC_NULL,"-mat_lu_pivotthreshold",&B->lupivotthreshold, 1314 &flg); CHKERRQ(ierr); 1315 b->ilu_preserve_row_sums = PETSC_FALSE; 1316 ierr = OptionsHasName(PETSC_NULL,"-pc_ilu_preserve_row_sums", 1317 (int*) &b->ilu_preserve_row_sums); CHKERRQ(ierr); 1318 b->row = 0; 1319 b->col = 0; 1320 b->indexshift = 0; 1321 b->reallocs = 0; 1322 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_oneindex", &flg); CHKERRQ(ierr); 1323 if (flg) b->indexshift = -1; 1324 1325 b->m = m; 1326 b->n = n; 1327 b->imax = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(b->imax); 1328 if (nnz == PETSC_NULL) { 1329 if (nz == PETSC_DEFAULT) nz = 10; 1330 else if (nz <= 0) nz = 1; 1331 for ( i=0; i<m; i++ ) b->imax[i] = nz; 1332 nz = nz*m; 1333 } 1334 else { 1335 nz = 0; 1336 for ( i=0; i<m; i++ ) {b->imax[i] = nnz[i]; nz += nnz[i];} 1337 } 1338 1339 /* allocate the matrix space */ 1340 len = nz*(sizeof(int) + sizeof(Scalar)) + (b->m+1)*sizeof(int); 1341 b->a = (Scalar *) PetscMalloc( len ); CHKPTRQ(b->a); 1342 b->j = (int *) (b->a + nz); 1343 PetscMemzero(b->j,nz*sizeof(int)); 1344 b->i = b->j + nz; 1345 b->singlemalloc = 1; 1346 1347 b->i[0] = -b->indexshift; 1348 for (i=1; i<m+1; i++) { 1349 b->i[i] = b->i[i-1] + b->imax[i-1]; 1350 } 1351 1352 /* b->ilen will count nonzeros in each row so far. */ 1353 b->ilen = (int *) PetscMalloc((m+1)*sizeof(int)); 1354 PLogObjectMemory(B,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ)); 1355 for ( i=0; i<b->m; i++ ) { b->ilen[i] = 0;} 1356 1357 b->nz = 0; 1358 b->maxnz = nz; 1359 b->sorted = 0; 1360 b->roworiented = 1; 1361 b->nonew = 0; 1362 b->diag = 0; 1363 b->solve_work = 0; 1364 b->spptr = 0; 1365 b->inode.node_count = 0; 1366 b->inode.size = 0; 1367 b->inode.limit = 5; 1368 b->inode.max_limit = 5; 1369 1370 *A = B; 1371 /* SuperLU is not currently supported through PETSc */ 1372 #if defined(HAVE_SUPERLU) 1373 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_superlu", &flg); CHKERRQ(ierr); 1374 if (flg) { ierr = MatUseSuperLU_SeqAIJ(B); CHKERRQ(ierr); } 1375 #endif 1376 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_essl", &flg); CHKERRQ(ierr); 1377 if (flg) { ierr = MatUseEssl_SeqAIJ(B); CHKERRQ(ierr); } 1378 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_dxml", &flg); CHKERRQ(ierr); 1379 if (flg) { 1380 if (!b->indexshift) SETERRQ(1,"MatCreateSeqAIJ:need -mat_aij_oneindex with -mat_aij_dxml"); 1381 ierr = MatUseDXML_SeqAIJ(B); CHKERRQ(ierr); 1382 } 1383 ierr = OptionsHasName(PETSC_NULL,"-help", &flg); CHKERRQ(ierr); 1384 if (flg) {ierr = MatPrintHelp(B); CHKERRQ(ierr); } 1385 return 0; 1386 } 1387 1388 int MatConvertSameType_SeqAIJ(Mat A,Mat *B,int cpvalues) 1389 { 1390 Mat C; 1391 Mat_SeqAIJ *c,*a = (Mat_SeqAIJ *) A->data; 1392 int i,len, m = a->m,shift = a->indexshift; 1393 1394 *B = 0; 1395 PetscHeaderCreate(C,_Mat,MAT_COOKIE,MATSEQAIJ,A->comm); 1396 PLogObjectCreate(C); 1397 C->data = (void *) (c = PetscNew(Mat_SeqAIJ)); CHKPTRQ(c); 1398 PetscMemcpy(&C->ops,&A->ops,sizeof(struct _MatOps)); 1399 C->destroy = MatDestroy_SeqAIJ; 1400 C->view = MatView_SeqAIJ; 1401 C->factor = A->factor; 1402 c->row = 0; 1403 c->col = 0; 1404 c->indexshift = shift; 1405 C->assembled = PETSC_TRUE; 1406 1407 c->m = a->m; 1408 c->n = a->n; 1409 1410 c->imax = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->imax); 1411 c->ilen = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->ilen); 1412 for ( i=0; i<m; i++ ) { 1413 c->imax[i] = a->imax[i]; 1414 c->ilen[i] = a->ilen[i]; 1415 } 1416 1417 /* allocate the matrix space */ 1418 c->singlemalloc = 1; 1419 len = (m+1)*sizeof(int)+(a->i[m])*(sizeof(Scalar)+sizeof(int)); 1420 c->a = (Scalar *) PetscMalloc( len ); CHKPTRQ(c->a); 1421 c->j = (int *) (c->a + a->i[m] + shift); 1422 c->i = c->j + a->i[m] + shift; 1423 PetscMemcpy(c->i,a->i,(m+1)*sizeof(int)); 1424 if (m > 0) { 1425 PetscMemcpy(c->j,a->j,(a->i[m]+shift)*sizeof(int)); 1426 if (cpvalues == COPY_VALUES) { 1427 PetscMemcpy(c->a,a->a,(a->i[m]+shift)*sizeof(Scalar)); 1428 } 1429 } 1430 1431 PLogObjectMemory(C,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ)); 1432 c->sorted = a->sorted; 1433 c->roworiented = a->roworiented; 1434 c->nonew = a->nonew; 1435 c->ilu_preserve_row_sums = a->ilu_preserve_row_sums; 1436 1437 if (a->diag) { 1438 c->diag = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(c->diag); 1439 PLogObjectMemory(C,(m+1)*sizeof(int)); 1440 for ( i=0; i<m; i++ ) { 1441 c->diag[i] = a->diag[i]; 1442 } 1443 } 1444 else c->diag = 0; 1445 c->inode.limit = a->inode.limit; 1446 c->inode.max_limit = a->inode.max_limit; 1447 if (a->inode.size){ 1448 c->inode.size = (int *) PetscMalloc( m *sizeof(int) ); CHKPTRQ(c->inode.size); 1449 c->inode.node_count = a->inode.node_count; 1450 PetscMemcpy( c->inode.size, a->inode.size, m*sizeof(int)); 1451 } else { 1452 c->inode.size = 0; 1453 c->inode.node_count = 0; 1454 } 1455 c->nz = a->nz; 1456 c->maxnz = a->maxnz; 1457 c->solve_work = 0; 1458 c->spptr = 0; /* Dangerous -I'm throwing away a->spptr */ 1459 1460 *B = C; 1461 return 0; 1462 } 1463 1464 int MatLoad_SeqAIJ(Viewer bview,MatType type,Mat *A) 1465 { 1466 Mat_SeqAIJ *a; 1467 Mat B; 1468 int i, nz, ierr, fd, header[4],size,*rowlengths = 0,M,N,shift; 1469 PetscObject vobj = (PetscObject) bview; 1470 MPI_Comm comm = vobj->comm; 1471 1472 MPI_Comm_size(comm,&size); 1473 if (size > 1) SETERRQ(1,"MatLoad_SeqAIJ:view must have one processor"); 1474 ierr = ViewerFileGetDescriptor_Private(bview,&fd); CHKERRQ(ierr); 1475 ierr = SYRead(fd,header,4,SYINT); CHKERRQ(ierr); 1476 if (header[0] != MAT_COOKIE) SETERRQ(1,"MatLoad_SeqAIJ:not matrix object in file"); 1477 M = header[1]; N = header[2]; nz = header[3]; 1478 1479 /* read in row lengths */ 1480 rowlengths = (int*) PetscMalloc( M*sizeof(int) ); CHKPTRQ(rowlengths); 1481 ierr = SYRead(fd,rowlengths,M,SYINT); CHKERRQ(ierr); 1482 1483 /* create our matrix */ 1484 ierr = MatCreateSeqAIJ(comm,M,N,0,rowlengths,A); CHKERRQ(ierr); 1485 B = *A; 1486 a = (Mat_SeqAIJ *) B->data; 1487 shift = a->indexshift; 1488 1489 /* read in column indices and adjust for Fortran indexing*/ 1490 ierr = SYRead(fd,a->j,nz,SYINT); CHKERRQ(ierr); 1491 if (shift) { 1492 for ( i=0; i<nz; i++ ) { 1493 a->j[i] += 1; 1494 } 1495 } 1496 1497 /* read in nonzero values */ 1498 ierr = SYRead(fd,a->a,nz,SYSCALAR); CHKERRQ(ierr); 1499 1500 /* set matrix "i" values */ 1501 a->i[0] = -shift; 1502 for ( i=1; i<= M; i++ ) { 1503 a->i[i] = a->i[i-1] + rowlengths[i-1]; 1504 a->ilen[i-1] = rowlengths[i-1]; 1505 } 1506 PetscFree(rowlengths); 1507 1508 ierr = MatAssemblyBegin(B,FINAL_ASSEMBLY); CHKERRQ(ierr); 1509 ierr = MatAssemblyEnd(B,FINAL_ASSEMBLY); CHKERRQ(ierr); 1510 return 0; 1511 } 1512 1513 1514 1515 /* 1516 1517 flg =0 if error; 1518 flg =1 if both are equal; 1519 */ 1520 int MatEqual_SeqAIJ(Mat A,Mat B, int* flg) 1521 { 1522 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 1523 1524 if (B->type !=MATSEQAIJ) SETERRQ(1,"MatEqual_SeqAIJ:Both matrices should be of type MATSEQAIJ"); 1525 1526 /* If the matrix dimensions are not equal, or no of nonzeros or shift */ 1527 if ((a->m != b->m ) || (a->n !=b->n) ||( a->nz != b->nz)|| 1528 (a->indexshift != b->indexshift)) { *flg =0 ; return 0; } 1529 1530 /* if the a->i are the same */ 1531 if(PetscMemcmp((char *)a->i, (char*)b->i, (a->n+1)*sizeof(int))) { *flg =0 ; return 0;} 1532 1533 /* if a->j are the same */ 1534 if(PetscMemcmp((char *)a->j, (char*)b->j, (a->nz)*sizeof(int))) { 1535 *flg =0 ; return 0; 1536 } 1537 1538 /* if a->j are the same */ 1539 if(PetscMemcmp((char *)a->a, (char*)b->a, (a->nz)*sizeof(Scalar))) { 1540 *flg =0 ; return 0; 1541 } 1542 *flg =1 ; 1543 return 0; 1544 1545 } 1546