xref: /petsc/src/mat/utils/axpy.c (revision c31cb41c0ee9b115779dca6896353b82fd361af9)
1 #define PETSCMAT_DLL
2 
3 #include "private/matimpl.h"  /*I   "petscmat.h"  I*/
4 
5 #undef __FUNCT__
6 #define __FUNCT__ "MatAXPY"
7 /*@
8    MatAXPY - Computes Y = a*X + Y.
9 
10    Logically  Collective on Mat
11 
12    Input Parameters:
13 +  a - the scalar multiplier
14 .  X - the first matrix
15 .  Y - the second matrix
16 -  str - either SAME_NONZERO_PATTERN, DIFFERENT_NONZERO_PATTERN
17          or SUBSET_NONZERO_PATTERN (nonzeros of X is a subset of Y's)
18 
19    Level: intermediate
20 
21 .keywords: matrix, add
22 
23 .seealso: MatAYPX()
24  @*/
25 PetscErrorCode  MatAXPY(Mat Y,PetscScalar a,Mat X,MatStructure str)
26 {
27   PetscErrorCode ierr;
28   PetscInt       m1,m2,n1,n2;
29 
30   PetscFunctionBegin;
31   PetscValidHeaderSpecific(X,MAT_CLASSID,3);
32   PetscValidHeaderSpecific(Y,MAT_CLASSID,1);
33   PetscValidLogicalCollectiveScalar(Y,a,2);
34   ierr = MatGetSize(X,&m1,&n1);CHKERRQ(ierr);
35   ierr = MatGetSize(Y,&m2,&n2);CHKERRQ(ierr);
36   if (m1 != m2 || n1 != n2) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Non conforming matrix add: %D %D %D %D",m1,m2,n1,n2);
37 
38   ierr = PetscLogEventBegin(MAT_AXPY,Y,0,0,0);CHKERRQ(ierr);
39   if (Y->ops->axpy) {
40     ierr = (*Y->ops->axpy)(Y,a,X,str);CHKERRQ(ierr);
41   } else {
42     ierr = MatAXPY_Basic(Y,a,X,str);CHKERRQ(ierr);
43   }
44   ierr = PetscLogEventEnd(MAT_AXPY,Y,0,0,0);CHKERRQ(ierr);
45   PetscFunctionReturn(0);
46 }
47 
48 #undef __FUNCT__
49 #define __FUNCT__ "MatAXPY_Basic"
50 PetscErrorCode MatAXPY_Basic(Mat Y,PetscScalar a,Mat X,MatStructure str)
51 {
52   PetscInt          i,start,end,j,ncols,m,n;
53   PetscErrorCode    ierr;
54   const PetscInt    *row;
55   PetscScalar       *val;
56   const PetscScalar *vals;
57 
58   PetscFunctionBegin;
59   ierr = MatGetSize(X,&m,&n);CHKERRQ(ierr);
60   ierr = MatGetOwnershipRange(X,&start,&end);CHKERRQ(ierr);
61   if (a == 1.0) {
62     for (i = start; i < end; i++) {
63       ierr = MatGetRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
64       ierr = MatSetValues(Y,1,&i,ncols,row,vals,ADD_VALUES);CHKERRQ(ierr);
65       ierr = MatRestoreRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
66     }
67   } else {
68     ierr = PetscMalloc((n+1)*sizeof(PetscScalar),&val);CHKERRQ(ierr);
69     for (i=start; i<end; i++) {
70       ierr = MatGetRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
71       for (j=0; j<ncols; j++) {
72 	val[j] = a*vals[j];
73       }
74       ierr = MatSetValues(Y,1,&i,ncols,row,val,ADD_VALUES);CHKERRQ(ierr);
75       ierr = MatRestoreRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
76     }
77     ierr = PetscFree(val);CHKERRQ(ierr);
78   }
79   ierr = MatAssemblyBegin(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
80   ierr = MatAssemblyEnd(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
81   PetscFunctionReturn(0);
82 }
83 
84 #undef __FUNCT__
85 #define __FUNCT__ "MatAXPY_BasicWithPreallocation"
86 PetscErrorCode MatAXPY_BasicWithPreallocation(Mat B,Mat Y,PetscScalar a,Mat X,MatStructure str)
87 {
88   PetscInt          i,start,end,j,ncols,m,n;
89   PetscErrorCode    ierr;
90   const PetscInt    *row;
91   PetscScalar       *val;
92   const PetscScalar *vals;
93 
94   PetscFunctionBegin;
95   ierr = MatGetSize(X,&m,&n);CHKERRQ(ierr);
96   ierr = MatGetOwnershipRange(X,&start,&end);CHKERRQ(ierr);
97   if (a == 1.0) {
98     for (i = start; i < end; i++) {
99       ierr = MatGetRow(Y,i,&ncols,&row,&vals);CHKERRQ(ierr);
100       ierr = MatSetValues(B,1,&i,ncols,row,vals,ADD_VALUES);CHKERRQ(ierr);
101       ierr = MatRestoreRow(Y,i,&ncols,&row,&vals);CHKERRQ(ierr);
102 
103       ierr = MatGetRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
104       ierr = MatSetValues(B,1,&i,ncols,row,vals,ADD_VALUES);CHKERRQ(ierr);
105       ierr = MatRestoreRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
106     }
107   } else {
108     ierr = PetscMalloc((n+1)*sizeof(PetscScalar),&val);CHKERRQ(ierr);
109     for (i=start; i<end; i++) {
110       ierr = MatGetRow(Y,i,&ncols,&row,&vals);CHKERRQ(ierr);
111       ierr = MatSetValues(B,1,&i,ncols,row,vals,ADD_VALUES);CHKERRQ(ierr);
112       ierr = MatRestoreRow(Y,i,&ncols,&row,&vals);CHKERRQ(ierr);
113 
114       ierr = MatGetRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
115       for (j=0; j<ncols; j++) {
116 	val[j] = a*vals[j];
117       }
118       ierr = MatSetValues(B,1,&i,ncols,row,val,ADD_VALUES);CHKERRQ(ierr);
119       ierr = MatRestoreRow(X,i,&ncols,&row,&vals);CHKERRQ(ierr);
120     }
121     ierr = PetscFree(val);CHKERRQ(ierr);
122   }
123   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
124   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
125   PetscFunctionReturn(0);
126 }
127 
128 #undef __FUNCT__
129 #define __FUNCT__ "MatShift"
130 /*@
131    MatShift - Computes Y =  Y + a I, where a is a PetscScalar and I is the identity matrix.
132 
133    Neighbor-wise Collective on Mat
134 
135    Input Parameters:
136 +  Y - the matrices
137 -  a - the PetscScalar
138 
139    Level: intermediate
140 
141 .keywords: matrix, add, shift
142 
143 .seealso: MatDiagonalSet()
144  @*/
145 PetscErrorCode  MatShift(Mat Y,PetscScalar a)
146 {
147   PetscErrorCode ierr;
148   PetscInt       i,start,end;
149 
150   PetscFunctionBegin;
151   PetscValidHeaderSpecific(Y,MAT_CLASSID,1);
152   if (!Y->assembled) SETERRQ(((PetscObject)Y)->comm,PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
153   if (Y->factortype) SETERRQ(((PetscObject)Y)->comm,PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
154   ierr = MatPreallocated(Y);CHKERRQ(ierr);
155 
156   if (Y->ops->shift) {
157     ierr = (*Y->ops->shift)(Y,a);CHKERRQ(ierr);
158   } else {
159     PetscScalar alpha = a;
160     ierr = MatGetOwnershipRange(Y,&start,&end);CHKERRQ(ierr);
161     for (i=start; i<end; i++) {
162       ierr = MatSetValues(Y,1,&i,1,&i,&alpha,ADD_VALUES);CHKERRQ(ierr);
163     }
164     ierr = MatAssemblyBegin(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
165     ierr = MatAssemblyEnd(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 #undef __FUNCT__
171 #define __FUNCT__ "MatDiagonalSet_Default"
172 PetscErrorCode  MatDiagonalSet_Default(Mat Y,Vec D,InsertMode is)
173 {
174   PetscErrorCode ierr;
175   PetscInt       i,start,end,vstart,vend;
176   PetscScalar    *v;
177 
178   PetscFunctionBegin;
179   ierr = VecGetOwnershipRange(D,&vstart,&vend);CHKERRQ(ierr);
180   ierr = MatGetOwnershipRange(Y,&start,&end);CHKERRQ(ierr);
181   if (vstart != start || vend != end) {
182     SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Vector ownership range not compatible with matrix: %D %D vec %D %D mat",vstart,vend,start,end);
183   }
184   ierr = VecGetArray(D,&v);CHKERRQ(ierr);
185   for (i=start; i<end; i++) {
186     ierr = MatSetValues(Y,1,&i,1,&i,v+i-start,is);CHKERRQ(ierr);
187   }
188   ierr = VecRestoreArray(D,&v);CHKERRQ(ierr);
189   ierr = MatAssemblyBegin(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
190   ierr = MatAssemblyEnd(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
191   PetscFunctionReturn(0);
192 }
193 
194 #undef __FUNCT__
195 #define __FUNCT__ "MatDiagonalSet"
196 /*@
197    MatDiagonalSet - Computes Y = Y + D, where D is a diagonal matrix
198    that is represented as a vector. Or Y[i,i] = D[i] if InsertMode is
199    INSERT_VALUES.
200 
201    Input Parameters:
202 +  Y - the input matrix
203 .  D - the diagonal matrix, represented as a vector
204 -  i - INSERT_VALUES or ADD_VALUES
205 
206    Neighbor-wise Collective on Mat and Vec
207 
208    Level: intermediate
209 
210 .keywords: matrix, add, shift, diagonal
211 
212 .seealso: MatShift()
213 @*/
214 PetscErrorCode  MatDiagonalSet(Mat Y,Vec D,InsertMode is)
215 {
216   PetscErrorCode ierr;
217 
218   PetscFunctionBegin;
219   PetscValidHeaderSpecific(Y,MAT_CLASSID,1);
220   PetscValidHeaderSpecific(D,VEC_CLASSID,2);
221   if (Y->ops->diagonalset) {
222     ierr = (*Y->ops->diagonalset)(Y,D,is);CHKERRQ(ierr);
223   } else {
224     ierr = MatDiagonalSet_Default(Y,D,is);CHKERRQ(ierr);
225   }
226   PetscFunctionReturn(0);
227 }
228 
229 #undef __FUNCT__
230 #define __FUNCT__ "MatAYPX"
231 /*@
232    MatAYPX - Computes Y = a*Y + X.
233 
234    Logically on Mat
235 
236    Input Parameters:
237 +  a - the PetscScalar multiplier
238 .  Y - the first matrix
239 .  X - the second matrix
240 -  str - either SAME_NONZERO_PATTERN, DIFFERENT_NONZERO_PATTERN or SUBSET_NONZERO_PATTERN
241 
242    Level: intermediate
243 
244 .keywords: matrix, add
245 
246 .seealso: MatAXPY()
247  @*/
248 PetscErrorCode  MatAYPX(Mat Y,PetscScalar a,Mat X,MatStructure str)
249 {
250   PetscScalar    one = 1.0;
251   PetscErrorCode ierr;
252   PetscInt       mX,mY,nX,nY;
253 
254   PetscFunctionBegin;
255   PetscValidHeaderSpecific(X,MAT_CLASSID,3);
256   PetscValidHeaderSpecific(Y,MAT_CLASSID,1);
257   PetscValidLogicalCollectiveScalar(Y,a,2);
258   ierr = MatGetSize(X,&mX,&nX);CHKERRQ(ierr);
259   ierr = MatGetSize(X,&mY,&nY);CHKERRQ(ierr);
260   if (mX != mY || nX != nY) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Non conforming matrices: %D %D first %D %D second",mX,mY,nX,nY);
261 
262   ierr = MatScale(Y,a);CHKERRQ(ierr);
263   ierr = MatAXPY(Y,one,X,str);CHKERRQ(ierr);
264   PetscFunctionReturn(0);
265 }
266 
267 #undef __FUNCT__
268 #define __FUNCT__ "MatComputeExplicitOperator"
269 /*@
270     MatComputeExplicitOperator - Computes the explicit matrix
271 
272     Collective on Mat
273 
274     Input Parameter:
275 .   inmat - the matrix
276 
277     Output Parameter:
278 .   mat - the explict preconditioned operator
279 
280     Notes:
281     This computation is done by applying the operators to columns of the
282     identity matrix.
283 
284     Currently, this routine uses a dense matrix format when 1 processor
285     is used and a sparse format otherwise.  This routine is costly in general,
286     and is recommended for use only with relatively small systems.
287 
288     Level: advanced
289 
290 .keywords: Mat, compute, explicit, operator
291 
292 @*/
293 PetscErrorCode  MatComputeExplicitOperator(Mat inmat,Mat *mat)
294 {
295   Vec            in,out;
296   PetscErrorCode ierr;
297   PetscInt       i,m,n,M,N,*rows,start,end;
298   MPI_Comm       comm;
299   PetscScalar    *array,zero = 0.0,one = 1.0;
300   PetscMPIInt    size;
301 
302   PetscFunctionBegin;
303   PetscValidHeaderSpecific(inmat,MAT_CLASSID,1);
304   PetscValidPointer(mat,2);
305 
306   comm = ((PetscObject)inmat)->comm;
307   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
308 
309   ierr = MatGetLocalSize(inmat,&m,&n);CHKERRQ(ierr);
310   ierr = MatGetSize(inmat,&M,&N);CHKERRQ(ierr);
311   ierr = MatGetVecs(inmat,&in,&out);CHKERRQ(ierr);
312   ierr = VecSetOption(in,VEC_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
313   ierr = VecGetOwnershipRange(out,&start,&end);CHKERRQ(ierr);
314   ierr = PetscMalloc(m*sizeof(PetscInt),&rows);CHKERRQ(ierr);
315   for (i=0; i<m; i++) {rows[i] = start + i;}
316 
317   ierr = MatCreate(comm,mat);CHKERRQ(ierr);
318   ierr = MatSetSizes(*mat,m,n,M,N);CHKERRQ(ierr);
319   if (size == 1) {
320     ierr = MatSetType(*mat,MATSEQDENSE);CHKERRQ(ierr);
321     ierr = MatSeqDenseSetPreallocation(*mat,PETSC_NULL);CHKERRQ(ierr);
322   } else {
323     ierr = MatSetType(*mat,MATMPIAIJ);CHKERRQ(ierr);
324     ierr = MatMPIAIJSetPreallocation(*mat,n,PETSC_NULL,N-n,PETSC_NULL);CHKERRQ(ierr);
325   }
326 
327   for (i=0; i<N; i++) {
328 
329     ierr = VecSet(in,zero);CHKERRQ(ierr);
330     ierr = VecSetValues(in,1,&i,&one,INSERT_VALUES);CHKERRQ(ierr);
331     ierr = VecAssemblyBegin(in);CHKERRQ(ierr);
332     ierr = VecAssemblyEnd(in);CHKERRQ(ierr);
333 
334     ierr = MatMult(inmat,in,out);CHKERRQ(ierr);
335 
336     ierr = VecGetArray(out,&array);CHKERRQ(ierr);
337     ierr = MatSetValues(*mat,m,rows,1,&i,array,INSERT_VALUES);CHKERRQ(ierr);
338     ierr = VecRestoreArray(out,&array);CHKERRQ(ierr);
339 
340   }
341   ierr = PetscFree(rows);CHKERRQ(ierr);
342   ierr = VecDestroy(out);CHKERRQ(ierr);
343   ierr = VecDestroy(in);CHKERRQ(ierr);
344   ierr = MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
345   ierr = MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
346   PetscFunctionReturn(0);
347 }
348 
349 /* Get the map xtoy which is used by MatAXPY() in the case of SUBSET_NONZERO_PATTERN */
350 #undef __FUNCT__
351 #define __FUNCT__ "MatAXPYGetxtoy_Private"
352 PetscErrorCode MatAXPYGetxtoy_Private(PetscInt m,PetscInt *xi,PetscInt *xj,PetscInt *xgarray, PetscInt *yi,PetscInt *yj,PetscInt *ygarray, PetscInt **xtoy)
353 {
354   PetscErrorCode ierr;
355   PetscInt       row,i,nz,xcol,ycol,jx,jy,*x2y;
356 
357   PetscFunctionBegin;
358   ierr = PetscMalloc(xi[m]*sizeof(PetscInt),&x2y);CHKERRQ(ierr);
359   i = 0;
360   for (row=0; row<m; row++){
361     nz = xi[1] - xi[0];
362     jy = 0;
363     for (jx=0; jx<nz; jx++,jy++){
364       if (xgarray && ygarray){
365         xcol = xgarray[xj[*xi + jx]];
366         ycol = ygarray[yj[*yi + jy]];
367       } else {
368         xcol = xj[*xi + jx];
369         ycol = yj[*yi + jy];  /* col index for y */
370       }
371       while ( ycol < xcol ) {
372         jy++;
373         if (ygarray){
374           ycol = ygarray[yj[*yi + jy]];
375         } else {
376           ycol = yj[*yi + jy];
377         }
378       }
379       if (xcol != ycol) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"X matrix entry (%D,%D) is not in Y matrix",row,ycol);
380       x2y[i++] = *yi + jy;
381     }
382     xi++; yi++;
383   }
384   *xtoy = x2y;
385   PetscFunctionReturn(0);
386 }
387