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