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