1 #ifndef lint 2 static char vcid[] = "$Id: aij.c,v 1.145 1996/02/09 15:00:43 curfman Exp curfman $"; 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(Mat_SeqAIJ*,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, &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],real(a->a[j]), 240 imag(a->a[j])); 241 #else 242 fprintf(fd,"%d %d %18.16e\n", i+1, a->j[j], 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 994 if (ISStrideGetInfo(iscol,&first,&step) && step == 1) { 995 /* special case of contiguous rows */ 996 lens = (int *) PetscMalloc((2*ncols+1)*sizeof(int)); CHKPTRQ(lens); 997 starts = lens + ncols; 998 /* loop over new rows determining lens and starting points */ 999 for (i=0; i<nrows; i++) { 1000 kstart = ai[irow[i]]+shift; 1001 kend = kstart + ailen[irow[i]]; 1002 for ( k=kstart; k<kend; k++ ) { 1003 if (aj[k]+shift >= first) { 1004 starts[i] = k; 1005 break; 1006 } 1007 } 1008 sum = 0; 1009 while (k < kend) { 1010 if (aj[k++]+shift >= first+ncols) break; 1011 sum++; 1012 } 1013 lens[i] = sum; 1014 } 1015 /* create submatrix */ 1016 if (scall == MAT_REUSE_MATRIX) { 1017 int n_cols,n_rows; 1018 ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr); 1019 if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:"); 1020 ierr = MatZeroEntries(*B); CHKERRQ(ierr); 1021 C = *B; 1022 } 1023 else { 1024 ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr); 1025 } 1026 c = (Mat_SeqAIJ*) C->data; 1027 1028 /* loop over rows inserting into submatrix */ 1029 a_new = c->a; 1030 j_new = c->j; 1031 i_new = c->i; 1032 i_new[0] = -shift; 1033 for (i=0; i<nrows; i++) { 1034 ii = starts[i]; 1035 lensi = lens[i]; 1036 for ( k=0; k<lensi; k++ ) { 1037 *j_new++ = aj[ii+k] - first; 1038 } 1039 PetscMemcpy(a_new,a->a + starts[i],lensi*sizeof(Scalar)); 1040 a_new += lensi; 1041 i_new[i+1] = i_new[i] + lensi; 1042 c->ilen[i] = lensi; 1043 } 1044 PetscFree(lens); 1045 } 1046 else { 1047 ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr); 1048 smap = (int *) PetscMalloc((1+oldcols)*sizeof(int)); CHKPTRQ(smap); 1049 ssmap = smap + shift; 1050 cwork = (int *) PetscMalloc((1+nrows+ncols)*sizeof(int)); CHKPTRQ(cwork); 1051 lens = cwork + ncols; 1052 vwork = (Scalar *) PetscMalloc((1+ncols)*sizeof(Scalar)); CHKPTRQ(vwork); 1053 PetscMemzero(smap,oldcols*sizeof(int)); 1054 for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1; 1055 /* determine lens of each row */ 1056 for (i=0; i<nrows; i++) { 1057 kstart = ai[irow[i]]+shift; 1058 kend = kstart + a->ilen[irow[i]]; 1059 lens[i] = 0; 1060 for ( k=kstart; k<kend; k++ ) { 1061 if (ssmap[aj[k]]) { 1062 lens[i]++; 1063 } 1064 } 1065 } 1066 /* Create and fill new matrix */ 1067 if (scall == MAT_REUSE_MATRIX) { 1068 int n_cols,n_rows; 1069 ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr); 1070 if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:"); 1071 ierr = MatZeroEntries(*B); CHKERRQ(ierr); 1072 C = *B; 1073 } 1074 else { 1075 ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr); 1076 } 1077 for (i=0; i<nrows; i++) { 1078 nznew = 0; 1079 kstart = ai[irow[i]]+shift; 1080 kend = kstart + a->ilen[irow[i]]; 1081 for ( k=kstart; k<kend; k++ ) { 1082 if (ssmap[a->j[k]]) { 1083 cwork[nznew] = ssmap[a->j[k]] - 1; 1084 vwork[nznew++] = a->a[k]; 1085 } 1086 } 1087 ierr = MatSetValues(C,1,&i,nznew,cwork,vwork,INSERT_VALUES); CHKERRQ(ierr); 1088 } 1089 /* Free work space */ 1090 ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr); 1091 PetscFree(smap); PetscFree(cwork); PetscFree(vwork); 1092 } 1093 ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 1094 ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 1095 1096 ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr); 1097 *B = C; 1098 return 0; 1099 } 1100 1101 /* 1102 note: This can only work for identity for row and col. It would 1103 be good to check this and otherwise generate an error. 1104 */ 1105 static int MatILUFactor_SeqAIJ(Mat inA,IS row,IS col,double efill,int fill) 1106 { 1107 Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data; 1108 int ierr; 1109 Mat outA; 1110 1111 if (fill != 0) SETERRQ(1,"MatILUFactor_SeqAIJ:Only fill=0 supported"); 1112 1113 outA = inA; 1114 inA->factor = FACTOR_LU; 1115 a->row = row; 1116 a->col = col; 1117 1118 a->solve_work = (Scalar *) PetscMalloc( (a->m+1)*sizeof(Scalar)); CHKPTRQ(a->solve_work); 1119 1120 if (!a->diag) { 1121 ierr = MatMarkDiag_SeqAIJ(inA); CHKERRQ(ierr); 1122 } 1123 ierr = MatLUFactorNumeric_SeqAIJ(inA,&outA); CHKERRQ(ierr); 1124 return 0; 1125 } 1126 1127 #include "pinclude/plapack.h" 1128 static int MatScale_SeqAIJ(Scalar *alpha,Mat inA) 1129 { 1130 Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data; 1131 int one = 1; 1132 BLscal_( &a->nz, alpha, a->a, &one ); 1133 PLogFlops(a->nz); 1134 return 0; 1135 } 1136 1137 static int MatGetSubMatrices_SeqAIJ(Mat A,int n, IS *irow,IS *icol,MatGetSubMatrixCall scall, 1138 Mat **B) 1139 { 1140 int ierr,i; 1141 1142 if (scall == MAT_INITIAL_MATRIX) { 1143 *B = (Mat *) PetscMalloc( (n+1)*sizeof(Mat) ); CHKPTRQ(*B); 1144 } 1145 1146 for ( i=0; i<n; i++ ) { 1147 ierr = MatGetSubMatrix(A,irow[i],icol[i],scall,&(*B)[i]); CHKERRQ(ierr); 1148 } 1149 return 0; 1150 } 1151 1152 static int MatIncreaseOverlap_SeqAIJ(Mat A, int is_max, IS *is, int ov) 1153 { 1154 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 1155 int shift, row, i,j,k,l,m,n, *idx,ierr, *nidx, isz, val; 1156 int start, end, *ai, *aj; 1157 char *table; 1158 shift = a->indexshift; 1159 m = a->m; 1160 ai = a->i; 1161 aj = a->j+shift; 1162 1163 if (ov < 0) SETERRQ(1,"MatIncreaseOverlap_SeqAIJ: illegal overlap value used"); 1164 1165 table = (char *) PetscMalloc((m/BITSPERBYTE +1)*sizeof(char)); CHKPTRQ(table); 1166 nidx = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(nidx); 1167 1168 for ( i=0; i<is_max; i++ ) { 1169 /* Initialise the two local arrays */ 1170 isz = 0; 1171 PetscMemzero(table,(m/BITSPERBYTE +1)*sizeof(char)); 1172 1173 /* Extract the indices, assume there can be duplicate entries */ 1174 ierr = ISGetIndices(is[i],&idx); CHKERRQ(ierr); 1175 ierr = ISGetLocalSize(is[i],&n); CHKERRQ(ierr); 1176 1177 /* Enter these into the temp arrays i.e mark table[row], enter row into new index */ 1178 for ( j=0; j<n ; ++j){ 1179 if(!BT_LOOKUP(table, idx[j])) { nidx[isz++] = idx[j];} 1180 } 1181 ierr = ISRestoreIndices(is[i],&idx); CHKERRQ(ierr); 1182 ierr = ISDestroy(is[i]); CHKERRQ(ierr); 1183 1184 k = 0; 1185 for ( j=0; j<ov; j++){ /* for each overlap*/ 1186 n = isz; 1187 for ( ; k<n ; k++){ /* do only those rows in nidx[k], which are not done yet */ 1188 row = nidx[k]; 1189 start = ai[row]; 1190 end = ai[row+1]; 1191 for ( l = start; l<end ; l++){ 1192 val = aj[l] + shift; 1193 if (!BT_LOOKUP(table,val)) {nidx[isz++] = val;} 1194 } 1195 } 1196 } 1197 ierr = ISCreateSeq(MPI_COMM_SELF, isz, nidx, (is+i)); CHKERRQ(ierr); 1198 } 1199 PetscFree(table); 1200 PetscFree(nidx); 1201 return 0; 1202 } 1203 1204 int MatPrintHelp_SeqAIJ(Mat A) 1205 { 1206 static int called = 0; 1207 MPI_Comm comm = A->comm; 1208 1209 if (called) return 0; else called = 1; 1210 MPIU_printf(comm," Options for MATSEQAIJ and MATMPIAIJ matrix formats (the defaults):\n"); 1211 MPIU_printf(comm," -mat_lu_pivotthreshold <threshold>\n"); 1212 MPIU_printf(comm," -mat_aij_oneindex - internal indices begin at 1 instead of the default 0.\n"); 1213 MPIU_printf(comm," -mat_aij_no_inode - Do not use inodes\n"); 1214 MPIU_printf(comm," -mat_aij_inode_limit <limit> - Set inode limit (max limit=5)\n"); 1215 #if defined(HAVE_ESSL) 1216 MPIU_printf(comm," -mat_aij_essl - Use IBM sparse LU factorization and solve.\n"); 1217 #endif 1218 return 0; 1219 } 1220 /* -------------------------------------------------------------------*/ 1221 static struct _MatOps MatOps = {MatSetValues_SeqAIJ, 1222 MatGetRow_SeqAIJ,MatRestoreRow_SeqAIJ, 1223 MatMult_SeqAIJ,MatMultAdd_SeqAIJ, 1224 MatMultTrans_SeqAIJ,MatMultTransAdd_SeqAIJ, 1225 MatSolve_SeqAIJ,MatSolveAdd_SeqAIJ, 1226 MatSolveTrans_SeqAIJ,MatSolveTransAdd_SeqAIJ, 1227 MatLUFactor_SeqAIJ,0, 1228 MatRelax_SeqAIJ, 1229 MatTranspose_SeqAIJ, 1230 MatGetInfo_SeqAIJ,0, 1231 MatGetDiagonal_SeqAIJ,MatDiagonalScale_SeqAIJ,MatNorm_SeqAIJ, 1232 0,MatAssemblyEnd_SeqAIJ, 1233 MatCompress_SeqAIJ, 1234 MatSetOption_SeqAIJ,MatZeroEntries_SeqAIJ,MatZeroRows_SeqAIJ, 1235 MatGetReordering_SeqAIJ, 1236 MatLUFactorSymbolic_SeqAIJ,MatLUFactorNumeric_SeqAIJ,0,0, 1237 MatGetSize_SeqAIJ,MatGetSize_SeqAIJ,MatGetOwnershipRange_SeqAIJ, 1238 MatILUFactorSymbolic_SeqAIJ,0, 1239 0,0,MatConvert_SeqAIJ, 1240 MatGetSubMatrix_SeqAIJ,0, 1241 MatConvertSameType_SeqAIJ,0,0, 1242 MatILUFactor_SeqAIJ,0,0, 1243 MatGetSubMatrices_SeqAIJ,MatIncreaseOverlap_SeqAIJ, 1244 MatGetValues_SeqAIJ,0, 1245 MatPrintHelp_SeqAIJ, 1246 MatScale_SeqAIJ}; 1247 1248 extern int MatUseSuperLU_SeqAIJ(Mat); 1249 extern int MatUseEssl_SeqAIJ(Mat); 1250 extern int MatUseDXML_SeqAIJ(Mat); 1251 1252 /*@C 1253 MatCreateSeqAIJ - Creates a sparse matrix in AIJ (compressed row) format 1254 (the default parallel PETSc format). For good matrix assembly performance 1255 the user should preallocate the matrix storage by setting the parameter nz 1256 (or nzz). By setting these parameters accurately, performance can be 1257 increased by more than a factor of 50. 1258 1259 Input Parameters: 1260 . comm - MPI communicator, set to MPI_COMM_SELF 1261 . m - number of rows 1262 . n - number of columns 1263 . nz - number of nonzeros per row (same for all rows) 1264 . nzz - number of nonzeros per row or null (possibly different for each row) 1265 1266 Output Parameter: 1267 . A - the matrix 1268 1269 Notes: 1270 The AIJ format (also called the Yale sparse matrix format or 1271 compressed row storage), is fully compatible with standard Fortran 77 1272 storage. That is, the stored row and column indices can begin at 1273 either one (as in Fortran) or zero. See the users manual for details. 1274 1275 Specify the preallocated storage with either nz or nnz (not both). 1276 Set nz=PETSC_DEFAULT and nnz=PETSC_NULL for PETSc to control dynamic memory 1277 allocation. For additional details, see the users manual chapter on 1278 matrices and the file $(PETSC_DIR)/Performance. 1279 1280 By default, this format uses inodes (identical nodes) when possible, to 1281 improve numerical efficiency of Matrix vector products and solves. We 1282 search for consecutive rows with the same nonzero structure, thereby 1283 reusing matrix information to achieve increased efficiency. 1284 1285 Options Database Keys: 1286 $ -mat_aij_no_inode - Do not use inodes 1287 $ -mat_aij_inode_limit <limit> - Set inode limit. 1288 $ (max limit=5) 1289 $ -mat_aij_oneindex - Internally use indexing starting at 1 1290 $ rather than 0. Note: When calling MatSetValues(), 1291 $ the user still MUST index entries starting at 0! 1292 1293 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues() 1294 @*/ 1295 int MatCreateSeqAIJ(MPI_Comm comm,int m,int n,int nz,int *nnz, Mat *A) 1296 { 1297 Mat B; 1298 Mat_SeqAIJ *b; 1299 int i,len,ierr, flg; 1300 1301 *A = 0; 1302 PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSEQAIJ,comm); 1303 PLogObjectCreate(B); 1304 B->data = (void *) (b = PetscNew(Mat_SeqAIJ)); CHKPTRQ(b); 1305 PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps)); 1306 B->destroy = MatDestroy_SeqAIJ; 1307 B->view = MatView_SeqAIJ; 1308 B->factor = 0; 1309 B->lupivotthreshold = 1.0; 1310 ierr = OptionsGetDouble(PETSC_NULL,"-mat_lu_pivotthreshold",&B->lupivotthreshold, \ 1311 &flg); CHKERRQ(ierr); 1312 b->row = 0; 1313 b->col = 0; 1314 b->indexshift = 0; 1315 b->reallocs = 0; 1316 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_oneindex", &flg); CHKERRQ(ierr); 1317 if (flg) b->indexshift = -1; 1318 1319 b->m = m; 1320 b->n = n; 1321 b->imax = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(b->imax); 1322 if (nnz == PETSC_NULL) { 1323 if (nz == PETSC_DEFAULT) nz = 10; 1324 else if (nz <= 0) nz = 1; 1325 for ( i=0; i<m; i++ ) b->imax[i] = nz; 1326 nz = nz*m; 1327 } 1328 else { 1329 nz = 0; 1330 for ( i=0; i<m; i++ ) {b->imax[i] = nnz[i]; nz += nnz[i];} 1331 } 1332 1333 /* allocate the matrix space */ 1334 len = nz*(sizeof(int) + sizeof(Scalar)) + (b->m+1)*sizeof(int); 1335 b->a = (Scalar *) PetscMalloc( len ); CHKPTRQ(b->a); 1336 b->j = (int *) (b->a + nz); 1337 PetscMemzero(b->j,nz*sizeof(int)); 1338 b->i = b->j + nz; 1339 b->singlemalloc = 1; 1340 1341 b->i[0] = -b->indexshift; 1342 for (i=1; i<m+1; i++) { 1343 b->i[i] = b->i[i-1] + b->imax[i-1]; 1344 } 1345 1346 /* b->ilen will count nonzeros in each row so far. */ 1347 b->ilen = (int *) PetscMalloc((m+1)*sizeof(int)); 1348 PLogObjectMemory(B,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ)); 1349 for ( i=0; i<b->m; i++ ) { b->ilen[i] = 0;} 1350 1351 b->nz = 0; 1352 b->maxnz = nz; 1353 b->sorted = 0; 1354 b->roworiented = 1; 1355 b->nonew = 0; 1356 b->diag = 0; 1357 b->solve_work = 0; 1358 b->spptr = 0; 1359 b->inode.node_count = 0; 1360 b->inode.size = 0; 1361 b->inode.limit = 5; 1362 b->inode.max_limit = 5; 1363 1364 *A = B; 1365 /* SuperLU is not currently supported through PETSc */ 1366 #if defined(HAVE_SUPERLU) 1367 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_superlu", &flg); CHKERRQ(ierr); 1368 if (flg) { ierr = MatUseSuperLU_SeqAIJ(B); CHKERRQ(ierr); } 1369 #endif 1370 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_essl", &flg); CHKERRQ(ierr); 1371 if (flg) { ierr = MatUseEssl_SeqAIJ(B); CHKERRQ(ierr); } 1372 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_dxml", &flg); CHKERRQ(ierr); 1373 if (flg) { 1374 if (!b->indexshift) SETERRQ(1,"MatCreateSeqAIJ:need -mat_aij_oneindex with -mat_aij_dxml"); 1375 ierr = MatUseDXML_SeqAIJ(B); CHKERRQ(ierr); 1376 } 1377 ierr = OptionsHasName(PETSC_NULL,"-help", &flg); CHKERRQ(ierr); 1378 if (flg) {ierr = MatPrintHelp(B); CHKERRQ(ierr); } 1379 return 0; 1380 } 1381 1382 int MatConvertSameType_SeqAIJ(Mat A,Mat *B,int cpvalues) 1383 { 1384 Mat C; 1385 Mat_SeqAIJ *c,*a = (Mat_SeqAIJ *) A->data; 1386 int i,len, m = a->m,shift = a->indexshift; 1387 1388 *B = 0; 1389 PetscHeaderCreate(C,_Mat,MAT_COOKIE,MATSEQAIJ,A->comm); 1390 PLogObjectCreate(C); 1391 C->data = (void *) (c = PetscNew(Mat_SeqAIJ)); CHKPTRQ(c); 1392 PetscMemcpy(&C->ops,&A->ops,sizeof(struct _MatOps)); 1393 C->destroy = MatDestroy_SeqAIJ; 1394 C->view = MatView_SeqAIJ; 1395 C->factor = A->factor; 1396 c->row = 0; 1397 c->col = 0; 1398 c->indexshift = shift; 1399 C->assembled = PETSC_TRUE; 1400 1401 c->m = a->m; 1402 c->n = a->n; 1403 1404 c->imax = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->imax); 1405 c->ilen = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->ilen); 1406 for ( i=0; i<m; i++ ) { 1407 c->imax[i] = a->imax[i]; 1408 c->ilen[i] = a->ilen[i]; 1409 } 1410 1411 /* allocate the matrix space */ 1412 c->singlemalloc = 1; 1413 len = (m+1)*sizeof(int)+(a->i[m])*(sizeof(Scalar)+sizeof(int)); 1414 c->a = (Scalar *) PetscMalloc( len ); CHKPTRQ(c->a); 1415 c->j = (int *) (c->a + a->i[m] + shift); 1416 c->i = c->j + a->i[m] + shift; 1417 PetscMemcpy(c->i,a->i,(m+1)*sizeof(int)); 1418 if (m > 0) { 1419 PetscMemcpy(c->j,a->j,(a->i[m]+shift)*sizeof(int)); 1420 if (cpvalues == COPY_VALUES) { 1421 PetscMemcpy(c->a,a->a,(a->i[m]+shift)*sizeof(Scalar)); 1422 } 1423 } 1424 1425 PLogObjectMemory(C,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ)); 1426 c->sorted = a->sorted; 1427 c->roworiented = a->roworiented; 1428 c->nonew = a->nonew; 1429 1430 if (a->diag) { 1431 c->diag = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(c->diag); 1432 PLogObjectMemory(C,(m+1)*sizeof(int)); 1433 for ( i=0; i<m; i++ ) { 1434 c->diag[i] = a->diag[i]; 1435 } 1436 } 1437 else c->diag = 0; 1438 c->inode.limit = a->inode.limit; 1439 c->inode.max_limit = a->inode.max_limit; 1440 if (a->inode.size){ 1441 c->inode.size = (int *) PetscMalloc( m *sizeof(int) ); CHKPTRQ(c->inode.size); 1442 c->inode.node_count = a->inode.node_count; 1443 PetscMemcpy( c->inode.size, a->inode.size, m*sizeof(int)); 1444 } else { 1445 c->inode.size = 0; 1446 c->inode.node_count = 0; 1447 } 1448 c->nz = a->nz; 1449 c->maxnz = a->maxnz; 1450 c->solve_work = 0; 1451 c->spptr = 0; /* Dangerous -I'm throwing away a->spptr */ 1452 1453 *B = C; 1454 return 0; 1455 } 1456 1457 int MatLoad_SeqAIJ(Viewer bview,MatType type,Mat *A) 1458 { 1459 Mat_SeqAIJ *a; 1460 Mat B; 1461 int i, nz, ierr, fd, header[4],size,*rowlengths = 0,M,N,shift; 1462 PetscObject vobj = (PetscObject) bview; 1463 MPI_Comm comm = vobj->comm; 1464 1465 MPI_Comm_size(comm,&size); 1466 if (size > 1) SETERRQ(1,"MatLoad_SeqAIJ:view must have one processor"); 1467 ierr = ViewerFileGetDescriptor_Private(bview,&fd); CHKERRQ(ierr); 1468 ierr = SYRead(fd,header,4,SYINT); CHKERRQ(ierr); 1469 if (header[0] != MAT_COOKIE) SETERRQ(1,"MatLoad_SeqAIJ:not matrix object in file"); 1470 M = header[1]; N = header[2]; nz = header[3]; 1471 1472 /* read in row lengths */ 1473 rowlengths = (int*) PetscMalloc( M*sizeof(int) ); CHKPTRQ(rowlengths); 1474 ierr = SYRead(fd,rowlengths,M,SYINT); CHKERRQ(ierr); 1475 1476 /* create our matrix */ 1477 ierr = MatCreateSeqAIJ(comm,M,N,0,rowlengths,A); CHKERRQ(ierr); 1478 B = *A; 1479 a = (Mat_SeqAIJ *) B->data; 1480 shift = a->indexshift; 1481 1482 /* read in column indices and adjust for Fortran indexing*/ 1483 ierr = SYRead(fd,a->j,nz,SYINT); CHKERRQ(ierr); 1484 if (shift) { 1485 for ( i=0; i<nz; i++ ) { 1486 a->j[i] += 1; 1487 } 1488 } 1489 1490 /* read in nonzero values */ 1491 ierr = SYRead(fd,a->a,nz,SYSCALAR); CHKERRQ(ierr); 1492 1493 /* set matrix "i" values */ 1494 a->i[0] = -shift; 1495 for ( i=1; i<= M; i++ ) { 1496 a->i[i] = a->i[i-1] + rowlengths[i-1]; 1497 a->ilen[i-1] = rowlengths[i-1]; 1498 } 1499 PetscFree(rowlengths); 1500 1501 ierr = MatAssemblyBegin(B,FINAL_ASSEMBLY); CHKERRQ(ierr); 1502 ierr = MatAssemblyEnd(B,FINAL_ASSEMBLY); CHKERRQ(ierr); 1503 return 0; 1504 } 1505 1506 1507 1508