xref: /petsc/src/mat/impls/shell/shell.c (revision f8e07d23ddf66943c8ff1b4ce09eace82a62b995)
1e51e0e81SBarry Smith /*
220563c6bSBarry Smith    This provides a simple shell for Fortran (and C programmers) to
320563c6bSBarry Smith   create a very simple matrix class for use with KSP without coding
4ed3cc1f0SBarry Smith   much of anything.
5e51e0e81SBarry Smith */
6e51e0e81SBarry Smith 
7af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
845960306SStefano Zampini #include <petsc/private/vecimpl.h>
9e51e0e81SBarry Smith 
1028f357e3SAlex Fikl struct _MatShellOps {
11976e8c5aSLisandro Dalcin   /*   3 */ PetscErrorCode (*mult)(Mat, Vec, Vec);
12976e8c5aSLisandro Dalcin   /*   5 */ PetscErrorCode (*multtranspose)(Mat, Vec, Vec);
13976e8c5aSLisandro Dalcin   /*  17 */ PetscErrorCode (*getdiagonal)(Mat, Vec);
14976e8c5aSLisandro Dalcin   /*  43 */ PetscErrorCode (*copy)(Mat, Mat, MatStructure);
15976e8c5aSLisandro Dalcin   /*  60 */ PetscErrorCode (*destroy)(Mat);
16*f8e07d23SBlanca Mellado Pinto   /* 121 */ PetscErrorCode (*multhermitiantranspose)(Mat, Vec, Vec);
1728f357e3SAlex Fikl };
1828f357e3SAlex Fikl 
19b77ba244SStefano Zampini struct _n_MatShellMatFunctionList {
20b77ba244SStefano Zampini   PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **);
21b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
22b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void *);
23b77ba244SStefano Zampini   MatProductType ptype;
24b77ba244SStefano Zampini   char          *composedname; /* string to identify routine with double dispatch */
25b77ba244SStefano Zampini   char          *resultname;   /* result matrix type */
26b77ba244SStefano Zampini 
27b77ba244SStefano Zampini   struct _n_MatShellMatFunctionList *next;
28b77ba244SStefano Zampini };
29b77ba244SStefano Zampini typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList;
30b77ba244SStefano Zampini 
3128f357e3SAlex Fikl typedef struct {
3228f357e3SAlex Fikl   struct _MatShellOps ops[1];
332205254eSKarl Rupp 
34b77ba244SStefano Zampini   /* The user will manage the scaling and shifts for the MATSHELL, not the default */
35b77ba244SStefano Zampini   PetscBool managescalingshifts;
36b77ba244SStefano Zampini 
37b77ba244SStefano Zampini   /* support for MatScale, MatShift and MatMultAdd */
38ef66eb69SBarry Smith   PetscScalar vscale, vshift;
398fe8eb27SJed Brown   Vec         dshift;
408fe8eb27SJed Brown   Vec         left, right;
418fe8eb27SJed Brown   Vec         left_work, right_work;
425edf6516SJed Brown   Vec         left_add_work, right_add_work;
43b77ba244SStefano Zampini 
44ef5c7bd2SStefano Zampini   /* support for MatAXPY */
459f137db4SBarry Smith   Mat              axpy;
469f137db4SBarry Smith   PetscScalar      axpy_vscale;
47b77ba244SStefano Zampini   Vec              axpy_left, axpy_right;
48ef5c7bd2SStefano Zampini   PetscObjectState axpy_state;
49b77ba244SStefano Zampini 
5045960306SStefano Zampini   /* support for ZeroRows/Columns operations */
5145960306SStefano Zampini   IS         zrows;
5245960306SStefano Zampini   IS         zcols;
5345960306SStefano Zampini   Vec        zvals;
5445960306SStefano Zampini   Vec        zvals_w;
5545960306SStefano Zampini   VecScatter zvals_sct_r;
5645960306SStefano Zampini   VecScatter zvals_sct_c;
57b77ba244SStefano Zampini 
58b77ba244SStefano Zampini   /* MatMat operations */
59b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
60b77ba244SStefano Zampini 
61b77ba244SStefano Zampini   /* user defined context */
62800f99ffSJeremy L Thompson   PetscContainer ctxcontainer;
6388cf3e7dSBarry Smith } Mat_Shell;
640c0fd78eSBarry Smith 
6545960306SStefano Zampini /*
6645960306SStefano Zampini      Store and scale values on zeroed rows
6745960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed columns
6845960306SStefano Zampini */
69d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx)
70d71ae5a4SJacob Faibussowitsch {
7145960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
7245960306SStefano Zampini 
7345960306SStefano Zampini   PetscFunctionBegin;
7445960306SStefano Zampini   *xx = x;
7545960306SStefano Zampini   if (shell->zrows) {
769566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w, 0.0));
779566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
789566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
799566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals));
8045960306SStefano Zampini   }
8145960306SStefano Zampini   if (shell->zcols) {
8248a46eb9SPierre Jolivet     if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
839566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->right_work));
849566063dSJacob Faibussowitsch     PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0));
8545960306SStefano Zampini     *xx = shell->right_work;
8645960306SStefano Zampini   }
873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8845960306SStefano Zampini }
8945960306SStefano Zampini 
9045960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
91d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x)
92d71ae5a4SJacob Faibussowitsch {
9345960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
9445960306SStefano Zampini 
9545960306SStefano Zampini   PetscFunctionBegin;
9645960306SStefano Zampini   if (shell->zrows) {
979566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
989566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
9945960306SStefano Zampini   }
1003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10145960306SStefano Zampini }
10245960306SStefano Zampini 
10345960306SStefano Zampini /*
10445960306SStefano Zampini      Store and scale values on zeroed rows
10545960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed rows
10645960306SStefano Zampini */
107d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx)
108d71ae5a4SJacob Faibussowitsch {
10945960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
11045960306SStefano Zampini 
11145960306SStefano Zampini   PetscFunctionBegin;
11245960306SStefano Zampini   *xx = NULL;
11345960306SStefano Zampini   if (!shell->zrows) {
11445960306SStefano Zampini     *xx = x;
11545960306SStefano Zampini   } else {
11648a46eb9SPierre Jolivet     if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
1179566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->left_work));
1189566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w, 0.0));
1199566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
1209566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
1219566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
1229566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
1239566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals));
12445960306SStefano Zampini     *xx = shell->left_work;
12545960306SStefano Zampini   }
1263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12745960306SStefano Zampini }
12845960306SStefano Zampini 
12945960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
130d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x)
131d71ae5a4SJacob Faibussowitsch {
13245960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
13345960306SStefano Zampini 
13445960306SStefano Zampini   PetscFunctionBegin;
1351baa6e33SBarry Smith   if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0));
13645960306SStefano Zampini   if (shell->zrows) {
1379566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
1389566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
13945960306SStefano Zampini   }
1403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14145960306SStefano Zampini }
14245960306SStefano Zampini 
1438fe8eb27SJed Brown /*
1440c0fd78eSBarry Smith       xx = diag(left)*x
1458fe8eb27SJed Brown */
146*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx, PetscBool conjugate)
147d71ae5a4SJacob Faibussowitsch {
1488fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1498fe8eb27SJed Brown 
1508fe8eb27SJed Brown   PetscFunctionBegin;
1510298fd71SBarry Smith   *xx = NULL;
1528fe8eb27SJed Brown   if (!shell->left) {
1538fe8eb27SJed Brown     *xx = x;
1548fe8eb27SJed Brown   } else {
1559566063dSJacob Faibussowitsch     if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work));
156*f8e07d23SBlanca Mellado Pinto     if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */
157*f8e07d23SBlanca Mellado Pinto       PetscInt           i, m;
158*f8e07d23SBlanca Mellado Pinto       const PetscScalar *d, *xarray;
159*f8e07d23SBlanca Mellado Pinto       PetscScalar       *w;
160*f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetLocalSize(x, &m));
161*f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayRead(shell->left, &d));
162*f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayRead(x, &xarray));
163*f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayWrite(shell->left_work, &w));
164*f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) w[i] = PetscConj(d[i]) * xarray[i];
165*f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayRead(shell->dshift, &d));
166*f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayRead(x, &xarray));
167*f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayWrite(shell->left_work, &w));
168*f8e07d23SBlanca Mellado Pinto     } else PetscCall(VecPointwiseMult(shell->left_work, x, shell->left));
1698fe8eb27SJed Brown     *xx = shell->left_work;
1708fe8eb27SJed Brown   }
1713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1728fe8eb27SJed Brown }
1738fe8eb27SJed Brown 
1740c0fd78eSBarry Smith /*
1750c0fd78eSBarry Smith      xx = diag(right)*x
1760c0fd78eSBarry Smith */
177d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx)
178d71ae5a4SJacob Faibussowitsch {
1798fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1808fe8eb27SJed Brown 
1818fe8eb27SJed Brown   PetscFunctionBegin;
1820298fd71SBarry Smith   *xx = NULL;
1838fe8eb27SJed Brown   if (!shell->right) {
1848fe8eb27SJed Brown     *xx = x;
1858fe8eb27SJed Brown   } else {
1869566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work));
1879566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->right_work, x, shell->right));
1888fe8eb27SJed Brown     *xx = shell->right_work;
1898fe8eb27SJed Brown   }
1903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1918fe8eb27SJed Brown }
1928fe8eb27SJed Brown 
1930c0fd78eSBarry Smith /*
1940c0fd78eSBarry Smith     x = diag(left)*x
1950c0fd78eSBarry Smith */
196d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x)
197d71ae5a4SJacob Faibussowitsch {
1988fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1998fe8eb27SJed Brown 
2008fe8eb27SJed Brown   PetscFunctionBegin;
2019566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left));
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2038fe8eb27SJed Brown }
2048fe8eb27SJed Brown 
2050c0fd78eSBarry Smith /*
2060c0fd78eSBarry Smith     x = diag(right)*x
2070c0fd78eSBarry Smith */
208*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x, PetscBool conjugate)
209d71ae5a4SJacob Faibussowitsch {
2108fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
2118fe8eb27SJed Brown 
2128fe8eb27SJed Brown   PetscFunctionBegin;
213*f8e07d23SBlanca Mellado Pinto   if (shell->right) {
214*f8e07d23SBlanca Mellado Pinto     if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */
215*f8e07d23SBlanca Mellado Pinto       PetscInt           i, m;
216*f8e07d23SBlanca Mellado Pinto       const PetscScalar *d;
217*f8e07d23SBlanca Mellado Pinto       PetscScalar       *xarray;
218*f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetLocalSize(x, &m));
219*f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayRead(shell->right, &d));
220*f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArray(x, &xarray));
221*f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) xarray[i] = PetscConj(d[i]) * xarray[i];
222*f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayRead(shell->dshift, &d));
223*f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArray(x, &xarray));
224*f8e07d23SBlanca Mellado Pinto     } else PetscCall(VecPointwiseMult(x, x, shell->right));
225*f8e07d23SBlanca Mellado Pinto   }
2263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2278fe8eb27SJed Brown }
2288fe8eb27SJed Brown 
2290c0fd78eSBarry Smith /*
2300c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
2310c0fd78eSBarry Smith 
2320c0fd78eSBarry Smith          On input Y already contains A*x
233*f8e07d23SBlanca Mellado Pinto 
234*f8e07d23SBlanca Mellado Pinto          If conjugate=PETSC_TRUE then vscale, dshift, and vshift are conjugated
2350c0fd78eSBarry Smith */
236*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y, PetscBool conjugate)
237d71ae5a4SJacob Faibussowitsch {
2388fe8eb27SJed Brown   Mat_Shell  *shell  = (Mat_Shell *)A->data;
239*f8e07d23SBlanca Mellado Pinto   PetscScalar vscale = conjugate ? PetscConj(shell->vscale) : shell->vscale;
240*f8e07d23SBlanca Mellado Pinto   PetscScalar vshift = conjugate ? PetscConj(shell->vshift) : shell->vshift;
2418fe8eb27SJed Brown 
2428fe8eb27SJed Brown   PetscFunctionBegin;
2438fe8eb27SJed Brown   if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */
2448fe8eb27SJed Brown     PetscInt           i, m;
2458fe8eb27SJed Brown     const PetscScalar *x, *d;
2468fe8eb27SJed Brown     PetscScalar       *y;
2479566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(X, &m));
2489566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->dshift, &d));
2499566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(X, &x));
2509566063dSJacob Faibussowitsch     PetscCall(VecGetArray(Y, &y));
251*f8e07d23SBlanca Mellado Pinto     if (conjugate)
252*f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) y[i] = vscale * y[i] + PetscConj(d[i]) * x[i];
253*f8e07d23SBlanca Mellado Pinto     else
254*f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) y[i] = vscale * y[i] + d[i] * x[i];
2559566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->dshift, &d));
2569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(X, &x));
2579566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(Y, &y));
2580c0fd78eSBarry Smith   } else {
259*f8e07d23SBlanca Mellado Pinto     PetscCall(VecScale(Y, vscale));
2608fe8eb27SJed Brown   }
261*f8e07d23SBlanca Mellado Pinto   if (vshift != 0.0) PetscCall(VecAXPY(Y, vshift, X)); /* if test is for non-square matrices */
2623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2638fe8eb27SJed Brown }
264e51e0e81SBarry Smith 
265d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx)
266d71ae5a4SJacob Faibussowitsch {
267800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
268800f99ffSJeremy L Thompson 
269789d8953SBarry Smith   PetscFunctionBegin;
270800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx));
271800f99ffSJeremy L Thompson   else *(void **)ctx = NULL;
2723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
273789d8953SBarry Smith }
274789d8953SBarry Smith 
2759d225801SJed Brown /*@
27611a5261eSBarry Smith   MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix.
277b4fd4287SBarry Smith 
278c7fcc2eaSBarry Smith   Not Collective
279c7fcc2eaSBarry Smith 
280b4fd4287SBarry Smith   Input Parameter:
28111a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()`
282b4fd4287SBarry Smith 
283b4fd4287SBarry Smith   Output Parameter:
284b4fd4287SBarry Smith . ctx - the user provided context
285b4fd4287SBarry Smith 
28615091d37SBarry Smith   Level: advanced
28715091d37SBarry Smith 
288fe59aa6dSJacob Faibussowitsch   Fortran Notes:
28927430b45SBarry Smith   You must write a Fortran interface definition for this
290daf670e6SBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
291a62d957aSLois Curfman McInnes 
2921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()`
2930bc0a719SBarry Smith @*/
294d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx)
295d71ae5a4SJacob Faibussowitsch {
2963a40ed3dSBarry Smith   PetscFunctionBegin;
2970700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2984f572ea9SToby Isaac   PetscAssertPointer(ctx, 2);
299cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx));
3003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
301b4fd4287SBarry Smith }
302b4fd4287SBarry Smith 
303d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc)
304d71ae5a4SJacob Faibussowitsch {
30545960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell *)mat->data;
30645960306SStefano Zampini   Vec             x = NULL, b = NULL;
30745960306SStefano Zampini   IS              is1, is2;
30845960306SStefano Zampini   const PetscInt *ridxs;
30945960306SStefano Zampini   PetscInt       *idxs, *gidxs;
31045960306SStefano Zampini   PetscInt        cum, rst, cst, i;
31145960306SStefano Zampini 
31245960306SStefano Zampini   PetscFunctionBegin;
31348a46eb9SPierre Jolivet   if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals));
31448a46eb9SPierre Jolivet   if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w));
3159566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(mat, &rst, NULL));
3169566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL));
31745960306SStefano Zampini 
31845960306SStefano Zampini   /* Expand/create index set of zeroed rows */
3199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &idxs));
32045960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
3219566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1));
3229566063dSJacob Faibussowitsch   PetscCall(ISSort(is1));
3239566063dSJacob Faibussowitsch   PetscCall(VecISSet(shell->zvals, is1, diag));
32445960306SStefano Zampini   if (shell->zrows) {
3259566063dSJacob Faibussowitsch     PetscCall(ISSum(shell->zrows, is1, &is2));
3269566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
3279566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is1));
32845960306SStefano Zampini     shell->zrows = is2;
32945960306SStefano Zampini   } else shell->zrows = is1;
33045960306SStefano Zampini 
33145960306SStefano Zampini   /* Create scatters for diagonal values communications */
3329566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
3339566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
33445960306SStefano Zampini 
33545960306SStefano Zampini   /* row scatter: from/to left vector */
3369566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &b));
3379566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r));
33845960306SStefano Zampini 
33945960306SStefano Zampini   /* col scatter: from right vector to left vector */
3409566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(shell->zrows, &ridxs));
3419566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(shell->zrows, &nr));
3429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &gidxs));
34345960306SStefano Zampini   for (i = 0, cum = 0; i < nr; i++) {
34445960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
34545960306SStefano Zampini     gidxs[cum] = ridxs[i];
34645960306SStefano Zampini     cum++;
34745960306SStefano Zampini   }
3489566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1));
3499566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c));
3509566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is1));
3519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
3529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b));
35345960306SStefano Zampini 
35445960306SStefano Zampini   /* Expand/create index set of zeroed columns */
35545960306SStefano Zampini   if (rc) {
3569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc, &idxs));
35745960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
3589566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1));
3599566063dSJacob Faibussowitsch     PetscCall(ISSort(is1));
36045960306SStefano Zampini     if (shell->zcols) {
3619566063dSJacob Faibussowitsch       PetscCall(ISSum(shell->zcols, is1, &is2));
3629566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&shell->zcols));
3639566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is1));
36445960306SStefano Zampini       shell->zcols = is2;
36545960306SStefano Zampini     } else shell->zcols = is1;
36645960306SStefano Zampini   }
3673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36845960306SStefano Zampini }
36945960306SStefano Zampini 
370d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
371d71ae5a4SJacob Faibussowitsch {
372ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
37345960306SStefano Zampini   PetscInt   nr, *lrows;
37445960306SStefano Zampini 
37545960306SStefano Zampini   PetscFunctionBegin;
37645960306SStefano Zampini   if (x && b) {
37745960306SStefano Zampini     Vec          xt;
37845960306SStefano Zampini     PetscScalar *vals;
37945960306SStefano Zampini     PetscInt    *gcols, i, st, nl, nc;
38045960306SStefano Zampini 
3819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &gcols));
3829371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
3839371c9d4SSatish Balay       if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
38445960306SStefano Zampini 
3859566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, NULL));
3869566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
3879566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nc, &vals));
3889566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
3899566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
3909566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3919566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3929566063dSJacob Faibussowitsch     PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */
39345960306SStefano Zampini 
3949566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
3959566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
3969566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
39745960306SStefano Zampini     for (i = 0; i < nl; i++) {
39845960306SStefano Zampini       PetscInt g = i + st;
39945960306SStefano Zampini       if (g > mat->rmap->N) continue;
40045960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4019566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES));
40245960306SStefano Zampini     }
4039566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
4049566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4059566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1, x2 * diag] */
4069566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4079566063dSJacob Faibussowitsch     PetscCall(PetscFree(gcols));
40845960306SStefano Zampini   }
4099566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL));
4109566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE));
4111baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL));
4129566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
4133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41445960306SStefano Zampini }
41545960306SStefano Zampini 
416d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b)
417d71ae5a4SJacob Faibussowitsch {
418ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
41945960306SStefano Zampini   PetscInt  *lrows, *lcols;
42045960306SStefano Zampini   PetscInt   nr, nc;
42145960306SStefano Zampini   PetscBool  congruent;
42245960306SStefano Zampini 
42345960306SStefano Zampini   PetscFunctionBegin;
42445960306SStefano Zampini   if (x && b) {
42545960306SStefano Zampini     Vec          xt, bt;
42645960306SStefano Zampini     PetscScalar *vals;
42745960306SStefano Zampini     PetscInt    *grows, *gcols, i, st, nl;
42845960306SStefano Zampini 
4299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(n, &grows, n, &gcols));
4309371c9d4SSatish Balay     for (i = 0, nr = 0; i < n; i++)
4319371c9d4SSatish Balay       if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
4329371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
4339371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
4349566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &vals));
43545960306SStefano Zampini 
4369566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, &bt));
4379566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
4389566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
4399566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
4409566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
4419566063dSJacob Faibussowitsch     PetscCall(VecAXPY(xt, -1.0, x));                             /* xt = [0, -x2] */
4429566063dSJacob Faibussowitsch     PetscCall(MatMult(mat, xt, bt));                             /* bt = [-A12*x2,-A22*x2] */
4439566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */
4449566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4459566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4469566063dSJacob Faibussowitsch     PetscCall(VecAXPY(b, 1.0, bt));                              /* b  = [b1 - A12*x2, b2] */
4479566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b  = [b1 - A12*x2, 0] */
4489566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4499566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4509566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
45145960306SStefano Zampini 
4529566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
4539566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
4549566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
45545960306SStefano Zampini     for (i = 0; i < nl; i++) {
45645960306SStefano Zampini       PetscInt g = i + st;
45745960306SStefano Zampini       if (g > mat->rmap->N) continue;
45845960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4599566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES));
46045960306SStefano Zampini     }
4619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
4629566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4639566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1 - A12*x2, x2 * diag] */
4649566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4659566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bt));
4669566063dSJacob Faibussowitsch     PetscCall(PetscFree2(grows, gcols));
46745960306SStefano Zampini   }
4689566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL));
4699566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(mat, &congruent));
47045960306SStefano Zampini   if (congruent) {
47145960306SStefano Zampini     nc    = nr;
47245960306SStefano Zampini     lcols = lrows;
47345960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
47445960306SStefano Zampini     PetscInt i, nt, *t;
47545960306SStefano Zampini 
4769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &t));
4779371c9d4SSatish Balay     for (i = 0, nt = 0; i < n; i++)
4789371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
4799566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL));
4809566063dSJacob Faibussowitsch     PetscCall(PetscFree(t));
48145960306SStefano Zampini   }
4829566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE));
48348a46eb9SPierre Jolivet   if (!congruent) PetscCall(PetscFree(lcols));
4849566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
4851baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL));
4863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48745960306SStefano Zampini }
48845960306SStefano Zampini 
489d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat)
490d71ae5a4SJacob Faibussowitsch {
491bf0cc555SLisandro Dalcin   Mat_Shell              *shell = (Mat_Shell *)mat->data;
492b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
493ed3cc1f0SBarry Smith 
4943a40ed3dSBarry Smith   PetscFunctionBegin;
4951baa6e33SBarry Smith   if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat));
4969566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps)));
4979566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
4989566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
4999566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->dshift));
5009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_work));
5019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_work));
5029566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_add_work));
5039566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_add_work));
5049566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_left));
5059566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_right));
5069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shell->axpy));
5079566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals_w));
5089566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals));
5099566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
5109566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
5119566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zrows));
5129566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zcols));
513b77ba244SStefano Zampini 
514b77ba244SStefano Zampini   matmat = shell->matmat;
515b77ba244SStefano Zampini   while (matmat) {
516b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
517b77ba244SStefano Zampini 
5189566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL));
5199566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->composedname));
5209566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->resultname));
5219566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat));
522b77ba244SStefano Zampini     matmat = next;
523b77ba244SStefano Zampini   }
524800f99ffSJeremy L Thompson   PetscCall(MatShellSetContext(mat, NULL));
5259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL));
5269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL));
527800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL));
5289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL));
5299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL));
5309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL));
5319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL));
5329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL));
5339566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
5343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
535b77ba244SStefano Zampini }
536b77ba244SStefano Zampini 
537b77ba244SStefano Zampini typedef struct {
538b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
539b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void *);
540b77ba244SStefano Zampini   void *userdata;
541b77ba244SStefano Zampini   Mat   B;
542b77ba244SStefano Zampini   Mat   Bt;
543b77ba244SStefano Zampini   Mat   axpy;
544b77ba244SStefano Zampini } MatMatDataShell;
545b77ba244SStefano Zampini 
546d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data)
547d71ae5a4SJacob Faibussowitsch {
548b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
549b77ba244SStefano Zampini 
550b77ba244SStefano Zampini   PetscFunctionBegin;
5511baa6e33SBarry Smith   if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata));
5529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
5539566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
5549566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
5559566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
5563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
557b77ba244SStefano Zampini }
558b77ba244SStefano Zampini 
559d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
560d71ae5a4SJacob Faibussowitsch {
561b77ba244SStefano Zampini   Mat_Product     *product;
562b77ba244SStefano Zampini   Mat              A, B;
563b77ba244SStefano Zampini   MatMatDataShell *mdata;
564b77ba244SStefano Zampini   PetscScalar      zero = 0.0;
565b77ba244SStefano Zampini 
566b77ba244SStefano Zampini   PetscFunctionBegin;
567b77ba244SStefano Zampini   MatCheckProduct(D, 1);
568b77ba244SStefano Zampini   product = D->product;
56928b400f6SJacob Faibussowitsch   PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty");
570b77ba244SStefano Zampini   A     = product->A;
571b77ba244SStefano Zampini   B     = product->B;
572b77ba244SStefano Zampini   mdata = (MatMatDataShell *)product->data;
573b77ba244SStefano Zampini   if (mdata->numeric) {
574b77ba244SStefano Zampini     Mat_Shell *shell                = (Mat_Shell *)A->data;
575b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
576b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
577b77ba244SStefano Zampini     PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
578b77ba244SStefano Zampini 
579b77ba244SStefano Zampini     if (shell->managescalingshifts) {
58008401ef6SPierre Jolivet       PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns");
581b77ba244SStefano Zampini       if (shell->right || shell->left) {
582b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
583b77ba244SStefano Zampini         if (!mdata->B) {
5849566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B));
585b77ba244SStefano Zampini         } else {
586b77ba244SStefano Zampini           newB = PETSC_FALSE;
587b77ba244SStefano Zampini         }
5889566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN));
589b77ba244SStefano Zampini       }
590b77ba244SStefano Zampini       switch (product->type) {
591b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
5921baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
593b77ba244SStefano Zampini         break;
594b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
5951baa6e33SBarry Smith         if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL));
596b77ba244SStefano Zampini         break;
597b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
5981baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
599b77ba244SStefano Zampini         break;
600b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
601b77ba244SStefano Zampini         if (shell->right && shell->left) {
602b77ba244SStefano Zampini           PetscBool flg;
603b77ba244SStefano Zampini 
6049566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
6059371c9d4SSatish Balay           PetscCheck(flg, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling", MatProductTypes[product->type], ((PetscObject)A)->type_name,
6069371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
607b77ba244SStefano Zampini         }
6081baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
609b77ba244SStefano Zampini         break;
610b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
611b77ba244SStefano Zampini         if (shell->right && shell->left) {
612b77ba244SStefano Zampini           PetscBool flg;
613b77ba244SStefano Zampini 
6149566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
6159371c9d4SSatish Balay           PetscCheck(flg, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling", MatProductTypes[product->type], ((PetscObject)A)->type_name,
6169371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
617b77ba244SStefano Zampini         }
6181baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
619b77ba244SStefano Zampini         break;
620d71ae5a4SJacob Faibussowitsch       default:
621d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name);
622b77ba244SStefano Zampini       }
623b77ba244SStefano Zampini     }
624b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
625b77ba244SStefano Zampini     D->product              = NULL;
626b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
627b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
628b77ba244SStefano Zampini 
6299566063dSJacob Faibussowitsch     PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata));
630b77ba244SStefano Zampini 
631b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
6329566063dSJacob Faibussowitsch     PetscCall(MatProductClear(D));
633b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
634b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
635b77ba244SStefano Zampini     D->product              = product;
636b77ba244SStefano Zampini 
637b77ba244SStefano Zampini     if (shell->managescalingshifts) {
6389566063dSJacob Faibussowitsch       PetscCall(MatScale(D, shell->vscale));
639b77ba244SStefano Zampini       switch (product->type) {
640b77ba244SStefano Zampini       case MATPRODUCT_AB:  /* s L A R B + v L R B + L D R B */
641b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
642b77ba244SStefano Zampini         if (shell->left) {
6439566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->left, NULL));
644b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
6459566063dSJacob Faibussowitsch             if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
646b77ba244SStefano Zampini             if (shell->dshift) {
6479566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->left_work));
6489566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->left_work, shell->vshift));
6499566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left));
650b77ba244SStefano Zampini             } else {
6519566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->left_work, shell->vshift));
652b77ba244SStefano Zampini             }
653b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
654b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
655b77ba244SStefano Zampini               MatStructure str   = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
656b77ba244SStefano Zampini 
6579566063dSJacob Faibussowitsch               PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt));
6589566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL));
6599566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->Bt, str));
660b77ba244SStefano Zampini             } else {
661b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
662b77ba244SStefano Zampini 
6639566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL));
6649566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->B, str));
665b77ba244SStefano Zampini             }
666b77ba244SStefano Zampini           }
667b77ba244SStefano Zampini         }
668b77ba244SStefano Zampini         break;
669b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
670b77ba244SStefano Zampini         if (shell->right) {
6719566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->right, NULL));
672b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
673b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
674b77ba244SStefano Zampini 
6759566063dSJacob Faibussowitsch             if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
676b77ba244SStefano Zampini             if (shell->dshift) {
6779566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->right_work));
6789566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->right_work, shell->vshift));
6799566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right));
680b77ba244SStefano Zampini             } else {
6819566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->right_work, shell->vshift));
682b77ba244SStefano Zampini             }
6839566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL));
6849566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D, 1.0, mdata->B, str));
685b77ba244SStefano Zampini           }
686b77ba244SStefano Zampini         }
687b77ba244SStefano Zampini         break;
688b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
689b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
6909371c9d4SSatish Balay         PetscCheck(!shell->dshift && shell->vshift == zero, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices with diagonal shift", MatProductTypes[product->type], ((PetscObject)A)->type_name,
6919371c9d4SSatish Balay                    ((PetscObject)B)->type_name);
692b77ba244SStefano Zampini         break;
693d71ae5a4SJacob Faibussowitsch       default:
694d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name);
695b77ba244SStefano Zampini       }
696b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
697b77ba244SStefano Zampini         Mat              X;
698b77ba244SStefano Zampini         PetscObjectState axpy_state;
699b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
700b77ba244SStefano Zampini 
7019566063dSJacob Faibussowitsch         PetscCall(MatShellGetContext(shell->axpy, &X));
7029566063dSJacob Faibussowitsch         PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
70308401ef6SPierre Jolivet         PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
704b77ba244SStefano Zampini         if (!mdata->axpy) {
705b77ba244SStefano Zampini           str = DIFFERENT_NONZERO_PATTERN;
7069566063dSJacob Faibussowitsch           PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy));
7079566063dSJacob Faibussowitsch           PetscCall(MatProductSetType(mdata->axpy, product->type));
7089566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
7099566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
710b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
711b77ba244SStefano Zampini           PetscBool flg;
712b77ba244SStefano Zampini 
7139566063dSJacob Faibussowitsch           PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy));
7149566063dSJacob Faibussowitsch           PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg));
715b77ba244SStefano Zampini           if (!flg) {
716b77ba244SStefano Zampini             str = DIFFERENT_NONZERO_PATTERN;
7179566063dSJacob Faibussowitsch             PetscCall(MatProductSetFromOptions(mdata->axpy));
7189566063dSJacob Faibussowitsch             PetscCall(MatProductSymbolic(mdata->axpy));
719b77ba244SStefano Zampini           }
720b77ba244SStefano Zampini         }
7219566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(mdata->axpy));
7229566063dSJacob Faibussowitsch         PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str));
723b77ba244SStefano Zampini       }
724b77ba244SStefano Zampini     }
725b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation");
7263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
727b77ba244SStefano Zampini }
728b77ba244SStefano Zampini 
729d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
730d71ae5a4SJacob Faibussowitsch {
731b77ba244SStefano Zampini   Mat_Product            *product;
732b77ba244SStefano Zampini   Mat                     A, B;
733b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
734b77ba244SStefano Zampini   Mat_Shell              *shell;
735eae3dc7dSJacob Faibussowitsch   PetscBool               flg = PETSC_FALSE;
736b77ba244SStefano Zampini   char                    composedname[256];
737b77ba244SStefano Zampini   MatMatDataShell        *mdata;
738b77ba244SStefano Zampini 
739b77ba244SStefano Zampini   PetscFunctionBegin;
740b77ba244SStefano Zampini   MatCheckProduct(D, 1);
741b77ba244SStefano Zampini   product = D->product;
74228b400f6SJacob Faibussowitsch   PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty");
743b77ba244SStefano Zampini   A      = product->A;
744b77ba244SStefano Zampini   B      = product->B;
745b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
746b77ba244SStefano Zampini   matmat = shell->matmat;
7479566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
748b77ba244SStefano Zampini   while (matmat) {
7499566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
750b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
751b77ba244SStefano Zampini     if (flg) break;
752b77ba244SStefano Zampini     matmat = matmat->next;
753b77ba244SStefano Zampini   }
75428b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]);
755b77ba244SStefano Zampini   switch (product->type) {
756d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
757d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
758d71ae5a4SJacob Faibussowitsch     break;
759d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
760d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
761d71ae5a4SJacob Faibussowitsch     break;
762d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
763d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N));
764d71ae5a4SJacob Faibussowitsch     break;
765d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
766d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N));
767d71ae5a4SJacob Faibussowitsch     break;
768d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
769d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N));
770d71ae5a4SJacob Faibussowitsch     break;
771d71ae5a4SJacob Faibussowitsch   default:
772d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name);
773b77ba244SStefano Zampini   }
774b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
775b77ba244SStefano Zampini   if (matmat->resultname) {
7769566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg));
77748a46eb9SPierre Jolivet     if (!flg) PetscCall(MatSetType(D, matmat->resultname));
778b77ba244SStefano Zampini   }
779b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
780b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
781b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
782b77ba244SStefano Zampini   /* attach product data */
7839566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
784b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
785b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
786b77ba244SStefano Zampini   if (matmat->symbolic) {
7879566063dSJacob Faibussowitsch     PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata));
788b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7899566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
790b77ba244SStefano Zampini   }
79128b400f6SJacob Faibussowitsch   PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase");
79228b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase");
793b77ba244SStefano Zampini   D->product->data    = mdata;
794b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
795b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
796b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
797b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
7983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
799b77ba244SStefano Zampini }
800b77ba244SStefano Zampini 
801d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
802d71ae5a4SJacob Faibussowitsch {
803b77ba244SStefano Zampini   Mat_Product            *product;
804b77ba244SStefano Zampini   Mat                     A, B;
805b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
806b77ba244SStefano Zampini   Mat_Shell              *shell;
807b77ba244SStefano Zampini   PetscBool               flg;
808b77ba244SStefano Zampini   char                    composedname[256];
809b77ba244SStefano Zampini 
810b77ba244SStefano Zampini   PetscFunctionBegin;
811b77ba244SStefano Zampini   MatCheckProduct(D, 1);
812b77ba244SStefano Zampini   product = D->product;
813b77ba244SStefano Zampini   A       = product->A;
814b77ba244SStefano Zampini   B       = product->B;
8159566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A, &flg));
8163ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
817b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
818b77ba244SStefano Zampini   matmat = shell->matmat;
8199566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
820b77ba244SStefano Zampini   while (matmat) {
8219566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
822b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
823b77ba244SStefano Zampini     if (flg) break;
824b77ba244SStefano Zampini     matmat = matmat->next;
825b77ba244SStefano Zampini   }
8269371c9d4SSatish Balay   if (flg) {
8279371c9d4SSatish Balay     D->ops->productsymbolic = MatProductSymbolic_Shell_X;
8289371c9d4SSatish Balay   } else PetscCall(PetscInfo(D, "  symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type]));
8293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
830b77ba244SStefano Zampini }
831b77ba244SStefano Zampini 
832d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetMatProductOperation_Private(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), char *composedname, const char *resultname)
833d71ae5a4SJacob Faibussowitsch {
834b77ba244SStefano Zampini   PetscBool               flg;
835b77ba244SStefano Zampini   Mat_Shell              *shell;
836b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
837b77ba244SStefano Zampini 
838b77ba244SStefano Zampini   PetscFunctionBegin;
83928b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine");
84028b400f6SJacob Faibussowitsch   PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name");
841b77ba244SStefano Zampini 
842b77ba244SStefano Zampini   /* add product callback */
843b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
844b77ba244SStefano Zampini   matmat = shell->matmat;
845b77ba244SStefano Zampini   if (!matmat) {
8469566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
847b77ba244SStefano Zampini     matmat = shell->matmat;
848b77ba244SStefano Zampini   } else {
849b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
850b77ba244SStefano Zampini     while (entry) {
8519566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname, entry->composedname, &flg));
852b77ba244SStefano Zampini       flg    = (PetscBool)(flg && (entry->ptype == ptype));
853b77ba244SStefano Zampini       matmat = entry;
8542e956fe4SStefano Zampini       if (flg) goto set;
855b77ba244SStefano Zampini       entry = entry->next;
856b77ba244SStefano Zampini     }
8579566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
858b77ba244SStefano Zampini     matmat = matmat->next;
859b77ba244SStefano Zampini   }
860b77ba244SStefano Zampini 
861843d480fSStefano Zampini set:
862b77ba244SStefano Zampini   matmat->symbolic = symbolic;
863b77ba244SStefano Zampini   matmat->numeric  = numeric;
864b77ba244SStefano Zampini   matmat->destroy  = destroy;
865b77ba244SStefano Zampini   matmat->ptype    = ptype;
8669566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8679566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8689566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname, &matmat->composedname));
8699566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname, &matmat->resultname));
8709566063dSJacob Faibussowitsch   PetscCall(PetscInfo(A, "Composing %s for product type %s with result %s\n", matmat->composedname, MatProductTypes[matmat->ptype], matmat->resultname ? matmat->resultname : "not specified"));
8719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X));
8723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
873b77ba244SStefano Zampini }
874b77ba244SStefano Zampini 
875b77ba244SStefano Zampini /*@C
87611a5261eSBarry Smith   MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix.
877b77ba244SStefano Zampini 
87827430b45SBarry Smith   Logically Collective; No Fortran Support
879b77ba244SStefano Zampini 
880b77ba244SStefano Zampini   Input Parameters:
88111a5261eSBarry Smith + A        - the `MATSHELL` shell matrix
882b77ba244SStefano Zampini . ptype    - the product type
8832ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`)
884b77ba244SStefano Zampini . numeric  - the function for the numerical phase
8852ef1f0ffSBarry Smith . destroy  - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`)
886b77ba244SStefano Zampini . Btype    - the matrix type for the matrix to be multiplied against
8872ef1f0ffSBarry Smith - Ctype    - the matrix type for the result (can be `NULL`)
888b77ba244SStefano Zampini 
889b77ba244SStefano Zampini   Level: advanced
890b77ba244SStefano Zampini 
8912920cce0SJacob Faibussowitsch   Example Usage:
892cf53795eSBarry Smith .vb
893cf53795eSBarry Smith   extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**);
894cf53795eSBarry Smith   extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*);
895cf53795eSBarry Smith   extern PetscErrorCode userdestroy(void*);
8962920cce0SJacob Faibussowitsch 
897cf53795eSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
8982920cce0SJacob Faibussowitsch   MatShellSetMatProductOperation(
8992920cce0SJacob Faibussowitsch     A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE
9002920cce0SJacob Faibussowitsch   );
9012920cce0SJacob Faibussowitsch   // create B of type SEQAIJ etc..
9022920cce0SJacob Faibussowitsch   MatProductCreate(A, B, PETSC_NULLPTR, &C);
903cf53795eSBarry Smith   MatProductSetType(C, MATPRODUCT_AB);
904cf53795eSBarry Smith   MatProductSetFromOptions(C);
9052920cce0SJacob Faibussowitsch   MatProductSymbolic(C); // actually runs the user defined symbolic operation
9062920cce0SJacob Faibussowitsch   MatProductNumeric(C); // actually runs the user defined numeric operation
9072920cce0SJacob Faibussowitsch   // use C = A * B
908cf53795eSBarry Smith .ve
909b77ba244SStefano Zampini 
910b77ba244SStefano Zampini   Notes:
911cf53795eSBarry Smith   `MATPRODUCT_ABC` is not supported yet.
91211a5261eSBarry Smith 
9132ef1f0ffSBarry Smith   If the symbolic phase is not specified, `MatSetUp()` is called on the result matrix that must have its type set if Ctype is `NULL`.
91411a5261eSBarry Smith 
915b77ba244SStefano Zampini   Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
916b77ba244SStefano Zampini   PETSc will take care of calling the user-defined callbacks.
917b77ba244SStefano Zampini   It is allowed to specify the same callbacks for different Btype matrix types.
91827430b45SBarry Smith   The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence.
919b77ba244SStefano Zampini 
9201cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
921b77ba244SStefano Zampini @*/
922d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetMatProductOperation(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), MatType Btype, MatType Ctype)
923d71ae5a4SJacob Faibussowitsch {
924b77ba244SStefano Zampini   PetscFunctionBegin;
925b77ba244SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
926b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A, ptype, 2);
92708401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]);
92828b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4");
9294f572ea9SToby Isaac   PetscAssertPointer(Btype, 6);
9304f572ea9SToby Isaac   if (Ctype) PetscAssertPointer(Ctype, 7);
931cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetMatProductOperation_C", (Mat, MatProductType, PetscErrorCode(*)(Mat, Mat, Mat, void **), PetscErrorCode(*)(Mat, Mat, Mat, void *), PetscErrorCode(*)(void *), MatType, MatType), (A, ptype, symbolic, numeric, destroy, Btype, Ctype));
9323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933b77ba244SStefano Zampini }
934b77ba244SStefano Zampini 
935d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetMatProductOperation_Shell(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), MatType Btype, MatType Ctype)
936d71ae5a4SJacob Faibussowitsch {
937b77ba244SStefano Zampini   PetscBool   flg;
938b77ba244SStefano Zampini   char        composedname[256];
939b77ba244SStefano Zampini   MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList;
940b77ba244SStefano Zampini   PetscMPIInt size;
941b77ba244SStefano Zampini 
942b77ba244SStefano Zampini   PetscFunctionBegin;
943b77ba244SStefano Zampini   PetscValidType(A, 1);
944b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
9459566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg));
946b77ba244SStefano Zampini     if (flg) break;
947b77ba244SStefano Zampini     Bnames = Bnames->next;
948b77ba244SStefano Zampini   }
949b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
9509566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg));
951b77ba244SStefano Zampini     if (flg) break;
952b77ba244SStefano Zampini     Cnames = Cnames->next;
953b77ba244SStefano Zampini   }
9549566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
955b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
956b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9579566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype));
9589566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype));
9593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
960e51e0e81SBarry Smith }
961e51e0e81SBarry Smith 
962d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str)
963d71ae5a4SJacob Faibussowitsch {
96428f357e3SAlex Fikl   Mat_Shell              *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data;
965cb8c8a77SBarry Smith   PetscBool               matflg;
966b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9677fabda3fSAlex Fikl 
9687fabda3fSAlex Fikl   PetscFunctionBegin;
9699566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B, &matflg));
97028b400f6SJacob Faibussowitsch   PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name);
9717fabda3fSAlex Fikl 
972aea10558SJacob Faibussowitsch   B->ops[0]      = A->ops[0];
973aea10558SJacob Faibussowitsch   shellB->ops[0] = shellA->ops[0];
9747fabda3fSAlex Fikl 
9751baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str));
9767fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9777fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9780c0fd78eSBarry Smith   if (shellA->dshift) {
97948a46eb9SPierre Jolivet     if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift));
9809566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift, shellB->dshift));
9817fabda3fSAlex Fikl   } else {
9829566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9837fabda3fSAlex Fikl   }
9840c0fd78eSBarry Smith   if (shellA->left) {
98548a46eb9SPierre Jolivet     if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left));
9869566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left, shellB->left));
9877fabda3fSAlex Fikl   } else {
9889566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9897fabda3fSAlex Fikl   }
9900c0fd78eSBarry Smith   if (shellA->right) {
99148a46eb9SPierre Jolivet     if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right));
9929566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right, shellB->right));
9937fabda3fSAlex Fikl   } else {
9949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9957fabda3fSAlex Fikl   }
9969566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
997ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
998ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
99940e381c3SBarry Smith   if (shellA->axpy) {
10009566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
100140e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
100240e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
1003ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
100440e381c3SBarry Smith   }
100545960306SStefano Zampini   if (shellA->zrows) {
10069566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows));
100748a46eb9SPierre Jolivet     if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols));
10089566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals));
10099566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals, shellB->zvals));
10109566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w));
10119566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
10129566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
101345960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
101445960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
101545960306SStefano Zampini   }
1016b77ba244SStefano Zampini 
1017b77ba244SStefano Zampini   matmatA = shellA->matmat;
1018b77ba244SStefano Zampini   if (matmatA) {
1019b77ba244SStefano Zampini     while (matmatA->next) {
10209566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname));
1021b77ba244SStefano Zampini       matmatA = matmatA->next;
1022b77ba244SStefano Zampini     }
1023b77ba244SStefano Zampini   }
10243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10257fabda3fSAlex Fikl }
10267fabda3fSAlex Fikl 
1027d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M)
1028d71ae5a4SJacob Faibussowitsch {
1029cb8c8a77SBarry Smith   PetscFunctionBegin;
1030800f99ffSJeremy L Thompson   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M));
1031800f99ffSJeremy L Thompson   ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer;
1032800f99ffSJeremy L Thompson   PetscCall(PetscObjectCompose((PetscObject)(*M), "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer));
10339566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)(*M), ((PetscObject)mat)->type_name));
103448a46eb9SPierre Jolivet   if (op != MAT_DO_NOT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
103501f93aa2SJose E. Roman   PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M));
10363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1037cb8c8a77SBarry Smith }
1038cb8c8a77SBarry Smith 
103966976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y)
1040d71ae5a4SJacob Faibussowitsch {
1041ef66eb69SBarry Smith   Mat_Shell       *shell = (Mat_Shell *)A->data;
104225578ef6SJed Brown   Vec              xx;
1043e3f487b0SBarry Smith   PetscObjectState instate, outstate;
1044ef66eb69SBarry Smith 
1045ef66eb69SBarry Smith   PetscFunctionBegin;
10469566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A, x, &xx));
10479566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A, xx, &xx));
10489566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10499566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A, xx, y));
10509566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1051e3f487b0SBarry Smith   if (instate == outstate) {
1052e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10539566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1054e3f487b0SBarry Smith   }
1055*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
10569566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A, y));
10579566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A, y));
10589f137db4SBarry Smith 
10599f137db4SBarry Smith   if (shell->axpy) {
1060ef5c7bd2SStefano Zampini     Mat              X;
1061ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1062ef5c7bd2SStefano Zampini 
10639566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10649566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
106508401ef6SPierre Jolivet     PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
1066b77ba244SStefano Zampini 
10679566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10689566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_right));
10699566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left));
10709566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left));
10719f137db4SBarry Smith   }
10723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1073ef66eb69SBarry Smith }
1074ef66eb69SBarry Smith 
1075d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1076d71ae5a4SJacob Faibussowitsch {
10775edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10785edf6516SJed Brown 
10795edf6516SJed Brown   PetscFunctionBegin;
10805edf6516SJed Brown   if (y == z) {
10819566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work));
10829566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->right_add_work));
10839566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->right_add_work));
10845edf6516SJed Brown   } else {
10859566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
10869566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
10875edf6516SJed Brown   }
10883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10895edf6516SJed Brown }
10905edf6516SJed Brown 
1091d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y)
1092d71ae5a4SJacob Faibussowitsch {
109318be62a5SSatish Balay   Mat_Shell       *shell = (Mat_Shell *)A->data;
109425578ef6SJed Brown   Vec              xx;
1095e3f487b0SBarry Smith   PetscObjectState instate, outstate;
109618be62a5SSatish Balay 
109718be62a5SSatish Balay   PetscFunctionBegin;
10989566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1099*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_FALSE));
11009566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
11019566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A, xx, y));
11029566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1103e3f487b0SBarry Smith   if (instate == outstate) {
1104e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
11059566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1106e3f487b0SBarry Smith   }
1107*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
1108*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_FALSE));
11099566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A, y));
1110350ec83bSStefano Zampini 
1111350ec83bSStefano Zampini   if (shell->axpy) {
1112ef5c7bd2SStefano Zampini     Mat              X;
1113ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1114ef5c7bd2SStefano Zampini 
11159566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
11169566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
111708401ef6SPierre Jolivet     PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
11189566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
11199566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_left));
11209566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
11219566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right));
1122350ec83bSStefano Zampini   }
11233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
112418be62a5SSatish Balay }
112518be62a5SSatish Balay 
1126*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Shell(Mat A, Vec x, Vec y)
1127*f8e07d23SBlanca Mellado Pinto {
1128*f8e07d23SBlanca Mellado Pinto   Mat_Shell       *shell = (Mat_Shell *)A->data;
1129*f8e07d23SBlanca Mellado Pinto   Vec              xx;
1130*f8e07d23SBlanca Mellado Pinto   PetscObjectState instate, outstate;
1131*f8e07d23SBlanca Mellado Pinto 
1132*f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1133*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1134*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_TRUE));
1135*f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
1136*f8e07d23SBlanca Mellado Pinto   PetscCall((*shell->ops->multhermitiantranspose)(A, xx, y));
1137*f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1138*f8e07d23SBlanca Mellado Pinto   if (instate == outstate) {
1139*f8e07d23SBlanca Mellado Pinto     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1140*f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1141*f8e07d23SBlanca Mellado Pinto   }
1142*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_TRUE));
1143*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_TRUE));
1144*f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostZeroRight(A, y));
1145*f8e07d23SBlanca Mellado Pinto 
1146*f8e07d23SBlanca Mellado Pinto   if (shell->axpy) {
1147*f8e07d23SBlanca Mellado Pinto     Mat              X;
1148*f8e07d23SBlanca Mellado Pinto     PetscObjectState axpy_state;
1149*f8e07d23SBlanca Mellado Pinto 
1150*f8e07d23SBlanca Mellado Pinto     PetscCall(MatShellGetContext(shell->axpy, &X));
1151*f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
1152*f8e07d23SBlanca Mellado Pinto     PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
1153*f8e07d23SBlanca Mellado Pinto     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
1154*f8e07d23SBlanca Mellado Pinto     PetscCall(VecCopy(x, shell->axpy_left));
1155*f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
1156*f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(y, PetscConj(shell->axpy_vscale), shell->axpy_right));
1157*f8e07d23SBlanca Mellado Pinto   }
1158*f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1159*f8e07d23SBlanca Mellado Pinto }
1160*f8e07d23SBlanca Mellado Pinto 
1161d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1162d71ae5a4SJacob Faibussowitsch {
11635edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
11645edf6516SJed Brown 
11655edf6516SJed Brown   PetscFunctionBegin;
11665edf6516SJed Brown   if (y == z) {
11679566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
11689566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->left_add_work));
11699566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
11705edf6516SJed Brown   } else {
11719566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
11729566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
11735edf6516SJed Brown   }
11743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11755edf6516SJed Brown }
11765edf6516SJed Brown 
1177*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1178*f8e07d23SBlanca Mellado Pinto {
1179*f8e07d23SBlanca Mellado Pinto   Mat_Shell *shell = (Mat_Shell *)A->data;
1180*f8e07d23SBlanca Mellado Pinto 
1181*f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1182*f8e07d23SBlanca Mellado Pinto   if (y == z) {
1183*f8e07d23SBlanca Mellado Pinto     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
1184*f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, shell->left_add_work));
1185*f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
1186*f8e07d23SBlanca Mellado Pinto   } else {
1187*f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, z));
1188*f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, y));
1189*f8e07d23SBlanca Mellado Pinto   }
1190*f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1191*f8e07d23SBlanca Mellado Pinto }
1192*f8e07d23SBlanca Mellado Pinto 
11930c0fd78eSBarry Smith /*
11940c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11950c0fd78eSBarry Smith */
1196d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v)
1197d71ae5a4SJacob Faibussowitsch {
119818be62a5SSatish Balay   Mat_Shell *shell = (Mat_Shell *)A->data;
119918be62a5SSatish Balay 
120018be62a5SSatish Balay   PetscFunctionBegin;
12010c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
12029566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A, v));
1203305211d5SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Must provide shell matrix with routine to return diagonal using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL,...)");
12049566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->vscale));
12051baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift));
12069566063dSJacob Faibussowitsch   PetscCall(VecShift(v, shell->vshift));
12079566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left));
12089566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right));
120945960306SStefano Zampini   if (shell->zrows) {
12109566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
12119566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
121245960306SStefano Zampini   }
121381c02519SBarry Smith   if (shell->axpy) {
1214ef5c7bd2SStefano Zampini     Mat              X;
1215ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1216ef5c7bd2SStefano Zampini 
12179566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
12189566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
121908401ef6SPierre Jolivet     PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
12209566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left));
12219566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left));
12229566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left));
122381c02519SBarry Smith   }
12243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122518be62a5SSatish Balay }
122618be62a5SSatish Balay 
1227d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a)
1228d71ae5a4SJacob Faibussowitsch {
1229ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1230789d8953SBarry Smith   PetscBool  flg;
1231b24ad042SBarry Smith 
1232ef66eb69SBarry Smith   PetscFunctionBegin;
12339566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y, &flg));
123428b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent");
12350c0fd78eSBarry Smith   if (shell->left || shell->right) {
12368fe8eb27SJed Brown     if (!shell->dshift) {
12379566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
12389566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift, a));
12390c0fd78eSBarry Smith     } else {
12409566063dSJacob Faibussowitsch       if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left));
12419566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right));
12429566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift, a));
12430c0fd78eSBarry Smith     }
12449566063dSJacob Faibussowitsch     if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left));
12459566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right));
12468fe8eb27SJed Brown   } else shell->vshift += a;
12471baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals, a));
12483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1249ef66eb69SBarry Smith }
1250ef66eb69SBarry Smith 
1251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s)
1252d71ae5a4SJacob Faibussowitsch {
12536464bf51SAlex Fikl   Mat_Shell *shell = (Mat_Shell *)A->data;
12546464bf51SAlex Fikl 
12556464bf51SAlex Fikl   PetscFunctionBegin;
12569566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift));
12570c0fd78eSBarry Smith   if (shell->left || shell->right) {
12589566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
12599f137db4SBarry Smith     if (shell->left && shell->right) {
12609566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12619566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right));
12629f137db4SBarry Smith     } else if (shell->left) {
12639566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12649f137db4SBarry Smith     } else {
12659566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right));
12669f137db4SBarry Smith     }
12679566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, shell->right_work));
12680c0fd78eSBarry Smith   } else {
12699566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, D));
1270b253ae0bS“Marek   }
12713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1272b253ae0bS“Marek }
1273b253ae0bS“Marek 
127466976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins)
1275d71ae5a4SJacob Faibussowitsch {
127645960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1277b253ae0bS“Marek   Vec        d;
1278789d8953SBarry Smith   PetscBool  flg;
1279b253ae0bS“Marek 
1280b253ae0bS“Marek   PetscFunctionBegin;
12819566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &flg));
128228b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent");
1283b253ae0bS“Marek   if (ins == INSERT_VALUES) {
12849566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D, &d));
12859566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A, d));
12869566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.));
12879566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12889566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12891baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D, shell->zvals));
1290b253ae0bS“Marek   } else {
12919566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12921baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D));
12936464bf51SAlex Fikl   }
12943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12956464bf51SAlex Fikl }
12966464bf51SAlex Fikl 
1297d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a)
1298d71ae5a4SJacob Faibussowitsch {
1299ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1300b24ad042SBarry Smith 
1301ef66eb69SBarry Smith   PetscFunctionBegin;
1302f4df32b1SMatthew Knepley   shell->vscale *= a;
13030c0fd78eSBarry Smith   shell->vshift *= a;
13041baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift, a));
130581c02519SBarry Smith   shell->axpy_vscale *= a;
13061baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals, a));
13073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
130818be62a5SSatish Balay }
13098fe8eb27SJed Brown 
1310d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right)
1311d71ae5a4SJacob Faibussowitsch {
13128fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)Y->data;
13138fe8eb27SJed Brown 
13148fe8eb27SJed Brown   PetscFunctionBegin;
13158fe8eb27SJed Brown   if (left) {
13160c0fd78eSBarry Smith     if (!shell->left) {
13179566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &shell->left));
13189566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, shell->left));
13190c0fd78eSBarry Smith     } else {
13209566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left, shell->left, left));
132118be62a5SSatish Balay     }
13221baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left));
1323ef66eb69SBarry Smith   }
13248fe8eb27SJed Brown   if (right) {
13250c0fd78eSBarry Smith     if (!shell->right) {
13269566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &shell->right));
13279566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, shell->right));
13280c0fd78eSBarry Smith     } else {
13299566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right, shell->right, right));
13308fe8eb27SJed Brown     }
133145960306SStefano Zampini     if (shell->zrows) {
133248a46eb9SPierre Jolivet       if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work));
13339566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w, 1.0));
13349566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
13359566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
13369566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w));
133745960306SStefano Zampini     }
13388fe8eb27SJed Brown   }
13391baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right));
13403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1341ef66eb69SBarry Smith }
1342ef66eb69SBarry Smith 
134366976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t)
1344d71ae5a4SJacob Faibussowitsch {
1345ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1346ef66eb69SBarry Smith 
1347ef66eb69SBarry Smith   PetscFunctionBegin;
13488fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1349ef66eb69SBarry Smith     shell->vshift      = 0.0;
1350ef66eb69SBarry Smith     shell->vscale      = 1.0;
1351ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1352ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
13539566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
13549566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
13559566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
13569566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
13579566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
13589566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
13599566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
13609566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
13619566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
13629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1363ef66eb69SBarry Smith   }
13643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1365ef66eb69SBarry Smith }
1366ef66eb69SBarry Smith 
1367d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d)
1368d71ae5a4SJacob Faibussowitsch {
13693b49f96aSBarry Smith   PetscFunctionBegin;
13703b49f96aSBarry Smith   *missing = PETSC_FALSE;
13713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13723b49f96aSBarry Smith }
13733b49f96aSBarry Smith 
137466976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str)
1375d71ae5a4SJacob Faibussowitsch {
13769f137db4SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
13779f137db4SBarry Smith 
13789f137db4SBarry Smith   PetscFunctionBegin;
1379ef5c7bd2SStefano Zampini   if (X == Y) {
13809566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
13813ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1382ef5c7bd2SStefano Zampini   }
1383ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13849566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy));
13859f137db4SBarry Smith     shell->axpy_vscale = a;
13869566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state));
1387ef5c7bd2SStefano Zampini   } else {
13889566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str));
1389ef5c7bd2SStefano Zampini   }
13903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13919f137db4SBarry Smith }
13929f137db4SBarry Smith 
1393f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1394f4259b30SLisandro Dalcin                                        NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396f4259b30SLisandro Dalcin                                        NULL,
13970c0fd78eSBarry Smith                                        /* 4*/ MatMultAdd_Shell,
1398f4259b30SLisandro Dalcin                                        NULL,
13990c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1404f4259b30SLisandro Dalcin                                        NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        NULL,
1407f4259b30SLisandro Dalcin                                        NULL,
1408f4259b30SLisandro Dalcin                                        /*15*/ NULL,
1409f4259b30SLisandro Dalcin                                        NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
14118fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        /*20*/ NULL,
1414ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        NULL,
141745960306SStefano Zampini                                        /*24*/ MatZeroRows_Shell,
1418f4259b30SLisandro Dalcin                                        NULL,
1419f4259b30SLisandro Dalcin                                        NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        NULL,
1422f4259b30SLisandro Dalcin                                        /*29*/ NULL,
1423f4259b30SLisandro Dalcin                                        NULL,
1424f4259b30SLisandro Dalcin                                        NULL,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        NULL,
1427cb8c8a77SBarry Smith                                        /*34*/ MatDuplicate_Shell,
1428f4259b30SLisandro Dalcin                                        NULL,
1429f4259b30SLisandro Dalcin                                        NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        NULL,
14329f137db4SBarry Smith                                        /*39*/ MatAXPY_Shell,
1433f4259b30SLisandro Dalcin                                        NULL,
1434f4259b30SLisandro Dalcin                                        NULL,
1435f4259b30SLisandro Dalcin                                        NULL,
1436cb8c8a77SBarry Smith                                        MatCopy_Shell,
1437f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1438ef66eb69SBarry Smith                                        MatScale_Shell,
1439ef66eb69SBarry Smith                                        MatShift_Shell,
14406464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
144145960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1442f4259b30SLisandro Dalcin                                        /*49*/ NULL,
1443f4259b30SLisandro Dalcin                                        NULL,
1444f4259b30SLisandro Dalcin                                        NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        NULL,
1447f4259b30SLisandro Dalcin                                        /*54*/ NULL,
1448f4259b30SLisandro Dalcin                                        NULL,
1449f4259b30SLisandro Dalcin                                        NULL,
1450f4259b30SLisandro Dalcin                                        NULL,
1451f4259b30SLisandro Dalcin                                        NULL,
1452f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1453b9b97703SBarry Smith                                        MatDestroy_Shell,
1454f4259b30SLisandro Dalcin                                        NULL,
1455251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1456f4259b30SLisandro Dalcin                                        NULL,
1457f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1458f4259b30SLisandro Dalcin                                        NULL,
1459f4259b30SLisandro Dalcin                                        NULL,
1460f4259b30SLisandro Dalcin                                        NULL,
1461f4259b30SLisandro Dalcin                                        NULL,
1462f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1463f4259b30SLisandro Dalcin                                        NULL,
1464c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1465f4259b30SLisandro Dalcin                                        NULL,
1466f4259b30SLisandro Dalcin                                        NULL,
1467f4259b30SLisandro Dalcin                                        /*74*/ NULL,
1468f4259b30SLisandro Dalcin                                        NULL,
1469f4259b30SLisandro Dalcin                                        NULL,
1470f4259b30SLisandro Dalcin                                        NULL,
1471f4259b30SLisandro Dalcin                                        NULL,
1472f4259b30SLisandro Dalcin                                        /*79*/ NULL,
1473f4259b30SLisandro Dalcin                                        NULL,
1474f4259b30SLisandro Dalcin                                        NULL,
1475f4259b30SLisandro Dalcin                                        NULL,
1476f4259b30SLisandro Dalcin                                        NULL,
1477f4259b30SLisandro Dalcin                                        /*84*/ NULL,
1478f4259b30SLisandro Dalcin                                        NULL,
1479f4259b30SLisandro Dalcin                                        NULL,
1480f4259b30SLisandro Dalcin                                        NULL,
1481f4259b30SLisandro Dalcin                                        NULL,
1482f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1483f4259b30SLisandro Dalcin                                        NULL,
1484f4259b30SLisandro Dalcin                                        NULL,
1485f4259b30SLisandro Dalcin                                        NULL,
1486f4259b30SLisandro Dalcin                                        NULL,
1487f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1488f4259b30SLisandro Dalcin                                        NULL,
1489f4259b30SLisandro Dalcin                                        NULL,
1490f4259b30SLisandro Dalcin                                        NULL,
1491f4259b30SLisandro Dalcin                                        NULL,
1492f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1493f4259b30SLisandro Dalcin                                        NULL,
1494f4259b30SLisandro Dalcin                                        NULL,
1495f4259b30SLisandro Dalcin                                        NULL,
1496f4259b30SLisandro Dalcin                                        NULL,
1497f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1498f4259b30SLisandro Dalcin                                        NULL,
1499f4259b30SLisandro Dalcin                                        NULL,
1500f4259b30SLisandro Dalcin                                        NULL,
1501f4259b30SLisandro Dalcin                                        NULL,
1502f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1503f4259b30SLisandro Dalcin                                        NULL,
1504f4259b30SLisandro Dalcin                                        NULL,
1505f4259b30SLisandro Dalcin                                        NULL,
15063b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1507f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1508f4259b30SLisandro Dalcin                                        NULL,
1509f4259b30SLisandro Dalcin                                        NULL,
1510f4259b30SLisandro Dalcin                                        NULL,
1511f4259b30SLisandro Dalcin                                        NULL,
1512f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1513f4259b30SLisandro Dalcin                                        NULL,
1514f4259b30SLisandro Dalcin                                        NULL,
1515*f8e07d23SBlanca Mellado Pinto                                        MatMultHermitianTransposeAdd_Shell,
1516f4259b30SLisandro Dalcin                                        NULL,
1517f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1518f4259b30SLisandro Dalcin                                        NULL,
1519f4259b30SLisandro Dalcin                                        NULL,
1520f4259b30SLisandro Dalcin                                        NULL,
1521f4259b30SLisandro Dalcin                                        NULL,
1522f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1523f4259b30SLisandro Dalcin                                        NULL,
1524f4259b30SLisandro Dalcin                                        NULL,
1525f4259b30SLisandro Dalcin                                        NULL,
1526f4259b30SLisandro Dalcin                                        NULL,
1527f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1528f4259b30SLisandro Dalcin                                        NULL,
1529f4259b30SLisandro Dalcin                                        NULL,
1530f4259b30SLisandro Dalcin                                        NULL,
1531f4259b30SLisandro Dalcin                                        NULL,
1532f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1533f4259b30SLisandro Dalcin                                        NULL,
1534d70f29a3SPierre Jolivet                                        NULL,
1535d70f29a3SPierre Jolivet                                        NULL,
1536d70f29a3SPierre Jolivet                                        NULL,
1537d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1538d70f29a3SPierre Jolivet                                        NULL,
1539d70f29a3SPierre Jolivet                                        NULL,
154099a7f59eSMark Adams                                        NULL,
154199a7f59eSMark Adams                                        NULL,
15427fb60732SBarry Smith                                        NULL,
1543dec0b466SHong Zhang                                        /*150*/ NULL,
1544dec0b466SHong Zhang                                        NULL};
1545273d9f13SBarry Smith 
1546d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx)
1547d71ae5a4SJacob Faibussowitsch {
1548789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1549789d8953SBarry Smith 
1550789d8953SBarry Smith   PetscFunctionBegin;
1551800f99ffSJeremy L Thompson   if (ctx) {
1552800f99ffSJeremy L Thompson     PetscContainer ctxcontainer;
1553800f99ffSJeremy L Thompson     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer));
1554800f99ffSJeremy L Thompson     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1555800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer));
1556800f99ffSJeremy L Thompson     shell->ctxcontainer = ctxcontainer;
1557800f99ffSJeremy L Thompson     PetscCall(PetscContainerDestroy(&ctxcontainer));
1558800f99ffSJeremy L Thompson   } else {
1559800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL));
1560800f99ffSJeremy L Thompson     shell->ctxcontainer = NULL;
1561800f99ffSJeremy L Thompson   }
1562800f99ffSJeremy L Thompson 
15633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1564800f99ffSJeremy L Thompson }
1565800f99ffSJeremy L Thompson 
156666976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *))
1567d71ae5a4SJacob Faibussowitsch {
1568800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
1569800f99ffSJeremy L Thompson 
1570800f99ffSJeremy L Thompson   PetscFunctionBegin;
1571800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f));
15723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1573789d8953SBarry Smith }
1574789d8953SBarry Smith 
1575d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype)
1576d71ae5a4SJacob Faibussowitsch {
1577db77db73SJeremy L Thompson   PetscFunctionBegin;
15789566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
15799566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype));
15803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1581db77db73SJeremy L Thompson }
1582db77db73SJeremy L Thompson 
158366976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1584d71ae5a4SJacob Faibussowitsch {
1585789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)A->data;
1586789d8953SBarry Smith 
1587789d8953SBarry Smith   PetscFunctionBegin;
1588789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1589789d8953SBarry Smith   A->ops->diagonalset        = NULL;
1590789d8953SBarry Smith   A->ops->diagonalscale      = NULL;
1591789d8953SBarry Smith   A->ops->scale              = NULL;
1592789d8953SBarry Smith   A->ops->shift              = NULL;
1593789d8953SBarry Smith   A->ops->axpy               = NULL;
15943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1595789d8953SBarry Smith }
1596789d8953SBarry Smith 
1597d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void))
1598d71ae5a4SJacob Faibussowitsch {
1599feb237baSPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)mat->data;
1600789d8953SBarry Smith 
1601789d8953SBarry Smith   PetscFunctionBegin;
1602789d8953SBarry Smith   switch (op) {
1603d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1604d71ae5a4SJacob Faibussowitsch     shell->ops->destroy = (PetscErrorCode(*)(Mat))f;
1605d71ae5a4SJacob Faibussowitsch     break;
1606789d8953SBarry Smith   case MATOP_VIEW:
1607ad540459SPierre Jolivet     if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view;
1608789d8953SBarry Smith     mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f;
1609789d8953SBarry Smith     break;
1610d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1611d71ae5a4SJacob Faibussowitsch     shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f;
1612d71ae5a4SJacob Faibussowitsch     break;
1613789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1614789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1615789d8953SBarry Smith   case MATOP_SHIFT:
1616789d8953SBarry Smith   case MATOP_SCALE:
1617789d8953SBarry Smith   case MATOP_AXPY:
1618789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1619789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
162028b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1621789d8953SBarry Smith     (((void (**)(void))mat->ops)[op]) = f;
1622789d8953SBarry Smith     break;
1623789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1624789d8953SBarry Smith     if (shell->managescalingshifts) {
1625789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f;
1626789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1627789d8953SBarry Smith     } else {
1628789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1629789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode(*)(Mat, Vec))f;
1630789d8953SBarry Smith     }
1631789d8953SBarry Smith     break;
1632789d8953SBarry Smith   case MATOP_MULT:
1633789d8953SBarry Smith     if (shell->managescalingshifts) {
1634789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1635789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1636789d8953SBarry Smith     } else {
1637789d8953SBarry Smith       shell->ops->mult = NULL;
1638789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1639789d8953SBarry Smith     }
1640789d8953SBarry Smith     break;
1641789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1642789d8953SBarry Smith     if (shell->managescalingshifts) {
1643789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1644789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1645789d8953SBarry Smith     } else {
1646789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1647789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1648789d8953SBarry Smith     }
1649789d8953SBarry Smith     break;
1650*f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
1651*f8e07d23SBlanca Mellado Pinto     if (shell->managescalingshifts) {
1652*f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1653*f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = MatMultHermitianTranspose_Shell;
1654*f8e07d23SBlanca Mellado Pinto     } else {
1655*f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = NULL;
1656*f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1657*f8e07d23SBlanca Mellado Pinto     }
1658*f8e07d23SBlanca Mellado Pinto     break;
1659d71ae5a4SJacob Faibussowitsch   default:
1660d71ae5a4SJacob Faibussowitsch     (((void (**)(void))mat->ops)[op]) = f;
1661d71ae5a4SJacob Faibussowitsch     break;
1662789d8953SBarry Smith   }
16633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1664789d8953SBarry Smith }
1665789d8953SBarry Smith 
1666d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void))
1667d71ae5a4SJacob Faibussowitsch {
1668789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1669789d8953SBarry Smith 
1670789d8953SBarry Smith   PetscFunctionBegin;
1671789d8953SBarry Smith   switch (op) {
1672d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1673d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->destroy;
1674d71ae5a4SJacob Faibussowitsch     break;
1675d71ae5a4SJacob Faibussowitsch   case MATOP_VIEW:
1676d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))mat->ops->view;
1677d71ae5a4SJacob Faibussowitsch     break;
1678d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1679d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->copy;
1680d71ae5a4SJacob Faibussowitsch     break;
1681789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1682789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1683789d8953SBarry Smith   case MATOP_SHIFT:
1684789d8953SBarry Smith   case MATOP_SCALE:
1685789d8953SBarry Smith   case MATOP_AXPY:
1686789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1687d71ae5a4SJacob Faibussowitsch   case MATOP_ZERO_ROWS_COLUMNS:
1688d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1689d71ae5a4SJacob Faibussowitsch     break;
1690789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
16919371c9d4SSatish Balay     if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal;
16929371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1693789d8953SBarry Smith     break;
1694789d8953SBarry Smith   case MATOP_MULT:
16959371c9d4SSatish Balay     if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult;
16969371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1697789d8953SBarry Smith     break;
1698789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
16999371c9d4SSatish Balay     if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose;
17009371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1701789d8953SBarry Smith     break;
1702*f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
1703*f8e07d23SBlanca Mellado Pinto     if (shell->ops->multhermitiantranspose) *f = (void (*)(void))shell->ops->multhermitiantranspose;
1704*f8e07d23SBlanca Mellado Pinto     else *f = (((void (**)(void))mat->ops)[op]);
1705*f8e07d23SBlanca Mellado Pinto     break;
1706d71ae5a4SJacob Faibussowitsch   default:
1707d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1708789d8953SBarry Smith   }
17093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1710789d8953SBarry Smith }
1711789d8953SBarry Smith 
17120bad9183SKris Buschelman /*MC
171301c1178eSBarry Smith    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free.
17140bad9183SKris Buschelman 
17150bad9183SKris Buschelman   Level: advanced
17160bad9183SKris Buschelman 
17171cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`
17180bad9183SKris Buschelman M*/
17190bad9183SKris Buschelman 
1720d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1721d71ae5a4SJacob Faibussowitsch {
1722273d9f13SBarry Smith   Mat_Shell *b;
1723273d9f13SBarry Smith 
1724273d9f13SBarry Smith   PetscFunctionBegin;
17254dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1726273d9f13SBarry Smith   A->data   = (void *)b;
1727aea10558SJacob Faibussowitsch   A->ops[0] = MatOps_Values;
1728273d9f13SBarry Smith 
1729800f99ffSJeremy L Thompson   b->ctxcontainer        = NULL;
1730ef66eb69SBarry Smith   b->vshift              = 0.0;
1731ef66eb69SBarry Smith   b->vscale              = 1.0;
17320c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1733273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1734210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
17352205254eSKarl Rupp 
17369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell));
17379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell));
1738800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell));
17399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell));
17409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell));
17419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell));
17429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell));
17439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell));
17449566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL));
17453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1746273d9f13SBarry Smith }
1747e51e0e81SBarry Smith 
17484b828684SBarry Smith /*@C
174911a5261eSBarry Smith   MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined
1750ff756334SLois Curfman McInnes   private data storage format.
1751e51e0e81SBarry Smith 
1752d083f849SBarry Smith   Collective
1753c7fcc2eaSBarry Smith 
1754e51e0e81SBarry Smith   Input Parameters:
1755c7fcc2eaSBarry Smith + comm - MPI communicator
175645f401ebSJose E. Roman . m    - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given)
175745f401ebSJose E. Roman . n    - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given)
175845f401ebSJose E. Roman . M    - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given)
175945f401ebSJose E. Roman . N    - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given)
1760c7fcc2eaSBarry Smith - ctx  - pointer to data needed by the shell matrix routines
1761e51e0e81SBarry Smith 
1762ff756334SLois Curfman McInnes   Output Parameter:
176344cd7ae7SLois Curfman McInnes . A - the matrix
1764e51e0e81SBarry Smith 
1765ff2fd236SBarry Smith   Level: advanced
1766ff2fd236SBarry Smith 
17672920cce0SJacob Faibussowitsch   Example Usage:
176827430b45SBarry Smith .vb
176927430b45SBarry Smith   extern PetscErrorCode mult(Mat, Vec, Vec);
17702920cce0SJacob Faibussowitsch 
177127430b45SBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &mat);
177227430b45SBarry Smith   MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult);
17732920cce0SJacob Faibussowitsch   // Use matrix for operations that have been set
177427430b45SBarry Smith   MatDestroy(mat);
177527430b45SBarry Smith .ve
1776f39d1f56SLois Curfman McInnes 
1777ff756334SLois Curfman McInnes   Notes:
1778ff756334SLois Curfman McInnes   The shell matrix type is intended to provide a simple class to use
177911a5261eSBarry Smith   with `KSP` (such as, for use with matrix-free methods). You should not
1780ff756334SLois Curfman McInnes   use the shell type if you plan to define a complete matrix class.
1781e51e0e81SBarry Smith 
1782f39d1f56SLois Curfman McInnes   PETSc requires that matrices and vectors being used for certain
1783f39d1f56SLois Curfman McInnes   operations are partitioned accordingly.  For example, when
17842ef1f0ffSBarry Smith   creating a shell matrix, `A`, that supports parallel matrix-vector
178511a5261eSBarry Smith   products using `MatMult`(A,x,y) the user should set the number
1786645985a0SLois Curfman McInnes   of local matrix rows to be the number of local elements of the
1787645985a0SLois Curfman McInnes   corresponding result vector, y. Note that this is information is
1788645985a0SLois Curfman McInnes   required for use of the matrix interface routines, even though
1789645985a0SLois Curfman McInnes   the shell matrix may not actually be physically partitioned.
1790645985a0SLois Curfman McInnes   For example,
1791f39d1f56SLois Curfman McInnes 
179227430b45SBarry Smith .vb
179327430b45SBarry Smith      Vec x, y
179427430b45SBarry Smith      extern PetscErrorCode mult(Mat,Vec,Vec);
179527430b45SBarry Smith      Mat A
179627430b45SBarry Smith 
179727430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,M,&y);
179827430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,N,&x);
179927430b45SBarry Smith      VecGetLocalSize(y,&m);
180027430b45SBarry Smith      VecGetLocalSize(x,&n);
180127430b45SBarry Smith      MatCreateShell(comm,m,n,M,N,ctx,&A);
180227430b45SBarry Smith      MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
180327430b45SBarry Smith      MatMult(A,x,y);
180427430b45SBarry Smith      MatDestroy(&A);
180527430b45SBarry Smith      VecDestroy(&y);
180627430b45SBarry Smith      VecDestroy(&x);
180727430b45SBarry Smith .ve
1808e51e0e81SBarry Smith 
18092ef1f0ffSBarry Smith   `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()`
18102ef1f0ffSBarry Smith   internally, so these  operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called.
18110c0fd78eSBarry Smith 
181227430b45SBarry Smith   Developer Notes:
18132ef1f0ffSBarry Smith   For rectangular matrices do all the scalings and shifts make sense?
18142ef1f0ffSBarry Smith 
181595452b02SPatrick Sanan   Regarding shifting and scaling. The general form is
18160c0fd78eSBarry Smith 
18170c0fd78eSBarry Smith   diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
18180c0fd78eSBarry Smith 
18190c0fd78eSBarry Smith   The order you apply the operations is important. For example if you have a dshift then
18200c0fd78eSBarry Smith   apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
18210c0fd78eSBarry Smith   you get s*vscale*A + diag(shift)
18220c0fd78eSBarry Smith 
18230c0fd78eSBarry Smith   A is the user provided function.
18240c0fd78eSBarry Smith 
182527430b45SBarry Smith   `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for
1826c5dec841SPierre Jolivet   for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger
182711a5261eSBarry Smith   an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat);
182811a5261eSBarry Smith   each time the `MATSHELL` matrix has changed.
1829ad2f5c3fSBarry Smith 
183011a5261eSBarry Smith   Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()`
1831b77ba244SStefano Zampini 
183211a5261eSBarry Smith   Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided
183311a5261eSBarry Smith   with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`.
1834ad2f5c3fSBarry Smith 
1835fe59aa6dSJacob Faibussowitsch   Fortran Notes:
18362ef1f0ffSBarry Smith   To use this from Fortran with a `ctx` you must write an interface definition for this
183711a5261eSBarry Smith   function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing
18382ef1f0ffSBarry Smith   in as the `ctx` argument.
183911a5261eSBarry Smith 
1840fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1841e51e0e81SBarry Smith @*/
1842d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A)
1843d71ae5a4SJacob Faibussowitsch {
18443a40ed3dSBarry Smith   PetscFunctionBegin;
18459566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
18469566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
18479566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATSHELL));
18489566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A, ctx));
18499566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
18503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1851c7fcc2eaSBarry Smith }
1852c7fcc2eaSBarry Smith 
1853c6866cfdSSatish Balay /*@
185411a5261eSBarry Smith   MatShellSetContext - sets the context for a `MATSHELL` shell matrix
1855c7fcc2eaSBarry Smith 
1856c3339decSBarry Smith   Logically Collective
1857c7fcc2eaSBarry Smith 
1858273d9f13SBarry Smith   Input Parameters:
185911a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1860273d9f13SBarry Smith - ctx - the context
1861273d9f13SBarry Smith 
1862273d9f13SBarry Smith   Level: advanced
1863273d9f13SBarry Smith 
1864fe59aa6dSJacob Faibussowitsch   Fortran Notes:
186527430b45SBarry Smith   You must write a Fortran interface definition for this
18662ef1f0ffSBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
1867273d9f13SBarry Smith 
18681cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
18690bc0a719SBarry Smith @*/
1870d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx)
1871d71ae5a4SJacob Faibussowitsch {
1872273d9f13SBarry Smith   PetscFunctionBegin;
18730700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1874cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx));
18753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1876e51e0e81SBarry Smith }
1877e51e0e81SBarry Smith 
1878fe59aa6dSJacob Faibussowitsch /*@C
187911a5261eSBarry Smith   MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context
1880800f99ffSJeremy L Thompson 
1881c3339decSBarry Smith   Logically Collective
1882800f99ffSJeremy L Thompson 
1883800f99ffSJeremy L Thompson   Input Parameters:
1884800f99ffSJeremy L Thompson + mat - the shell matrix
1885800f99ffSJeremy L Thompson - f   - the context destroy function
1886800f99ffSJeremy L Thompson 
188727430b45SBarry Smith   Level: advanced
188827430b45SBarry Smith 
1889800f99ffSJeremy L Thompson   Note:
1890800f99ffSJeremy L Thompson   If the `MatShell` is never duplicated, the behavior of this function is equivalent
189111a5261eSBarry Smith   to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()`
1892800f99ffSJeremy L Thompson   ensures proper reference counting for the user provided context data in the case that
189311a5261eSBarry Smith   the `MATSHELL` is duplicated.
1894800f99ffSJeremy L Thompson 
18951cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()`
1896800f99ffSJeremy L Thompson @*/
1897d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *))
1898d71ae5a4SJacob Faibussowitsch {
1899800f99ffSJeremy L Thompson   PetscFunctionBegin;
1900800f99ffSJeremy L Thompson   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1901800f99ffSJeremy L Thompson   PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f));
19023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1903800f99ffSJeremy L Thompson }
1904800f99ffSJeremy L Thompson 
1905db77db73SJeremy L Thompson /*@C
19062ef1f0ffSBarry Smith   MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()`
1907db77db73SJeremy L Thompson 
19082ef1f0ffSBarry Smith   Logically Collective
1909db77db73SJeremy L Thompson 
1910db77db73SJeremy L Thompson   Input Parameters:
191111a5261eSBarry Smith + mat   - the `MATSHELL` shell matrix
1912db77db73SJeremy L Thompson - vtype - type to use for creating vectors
1913db77db73SJeremy L Thompson 
1914db77db73SJeremy L Thompson   Level: advanced
1915db77db73SJeremy L Thompson 
19161cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()`
1917db77db73SJeremy L Thompson @*/
1918d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype)
1919d71ae5a4SJacob Faibussowitsch {
1920db77db73SJeremy L Thompson   PetscFunctionBegin;
1921cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype));
19223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1923db77db73SJeremy L Thompson }
1924db77db73SJeremy L Thompson 
19250c0fd78eSBarry Smith /*@
192611a5261eSBarry Smith   MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately
192711a5261eSBarry Smith   after `MatCreateShell()`
19280c0fd78eSBarry Smith 
192927430b45SBarry Smith   Logically Collective
19300c0fd78eSBarry Smith 
19310c0fd78eSBarry Smith   Input Parameter:
1932fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix
19330c0fd78eSBarry Smith 
19340c0fd78eSBarry Smith   Level: advanced
19350c0fd78eSBarry Smith 
19361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
19370c0fd78eSBarry Smith @*/
1938d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1939d71ae5a4SJacob Faibussowitsch {
19400c0fd78eSBarry Smith   PetscFunctionBegin;
19410c0fd78eSBarry Smith   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1942cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A));
19433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19440c0fd78eSBarry Smith }
19450c0fd78eSBarry Smith 
1946c16cb8f2SBarry Smith /*@C
194711a5261eSBarry Smith   MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function.
1948f3b1f45cSBarry Smith 
1949cf53795eSBarry Smith   Logically Collective; No Fortran Support
1950f3b1f45cSBarry Smith 
1951f3b1f45cSBarry Smith   Input Parameters:
195211a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
1953f3b1f45cSBarry Smith . f    - the function
195411a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1955f3b1f45cSBarry Smith - ctx  - an optional context for the function
1956f3b1f45cSBarry Smith 
1957f3b1f45cSBarry Smith   Output Parameter:
195811a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
1959f3b1f45cSBarry Smith 
19603c7db156SBarry Smith   Options Database Key:
1961f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1962f3b1f45cSBarry Smith 
1963f3b1f45cSBarry Smith   Level: advanced
1964f3b1f45cSBarry Smith 
19651cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
1966f3b1f45cSBarry Smith @*/
1967d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1968d71ae5a4SJacob Faibussowitsch {
1969f3b1f45cSBarry Smith   PetscInt  m, n;
1970f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1971f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
197274e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1973f3b1f45cSBarry Smith 
1974f3b1f45cSBarry Smith   PetscFunctionBegin;
1975f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
19769566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v));
19779566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
19789566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf));
19799566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
19809566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
1981f3b1f45cSBarry Smith 
19829566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
19839566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat));
1984f3b1f45cSBarry Smith 
19859566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
19869566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
19879566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
19889566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1989f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1990f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1991f3b1f45cSBarry Smith     if (v) {
199201c1178eSBarry Smith       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n", (double)(Diffnorm / Dmfnorm)));
19939566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view"));
19949566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view"));
19959566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view"));
1996f3b1f45cSBarry Smith     }
1997f3b1f45cSBarry Smith   } else if (v) {
199801c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n"));
1999f3b1f45cSBarry Smith   }
2000f3b1f45cSBarry Smith   if (flg) *flg = flag;
20019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
20029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
20039566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
20049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
20053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2006f3b1f45cSBarry Smith }
2007f3b1f45cSBarry Smith 
2008f3b1f45cSBarry Smith /*@C
200911a5261eSBarry Smith   MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function.
2010f3b1f45cSBarry Smith 
2011cf53795eSBarry Smith   Logically Collective; No Fortran Support
2012f3b1f45cSBarry Smith 
2013f3b1f45cSBarry Smith   Input Parameters:
201411a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
2015f3b1f45cSBarry Smith . f    - the function
201611a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
2017f3b1f45cSBarry Smith - ctx  - an optional context for the function
2018f3b1f45cSBarry Smith 
2019f3b1f45cSBarry Smith   Output Parameter:
202011a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
2021f3b1f45cSBarry Smith 
20223c7db156SBarry Smith   Options Database Key:
2023f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
2024f3b1f45cSBarry Smith 
2025f3b1f45cSBarry Smith   Level: advanced
2026f3b1f45cSBarry Smith 
20271cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
2028f3b1f45cSBarry Smith @*/
2029d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
2030d71ae5a4SJacob Faibussowitsch {
2031f3b1f45cSBarry Smith   Vec       x, y, z;
2032f3b1f45cSBarry Smith   PetscInt  m, n, M, N;
2033f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
2034f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
203574e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
2036f3b1f45cSBarry Smith 
2037f3b1f45cSBarry Smith   PetscFunctionBegin;
2038f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
20399566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v));
20409566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &y));
20419566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &z));
20429566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20439566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20449566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf));
20459566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
20469566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
20479566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
20489566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf));
20499566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat));
2050f3b1f45cSBarry Smith 
20519566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
20529566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
20539566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
20549566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
2055f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
2056f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2057f3b1f45cSBarry Smith     if (v) {
205801c1178eSBarry Smith       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n", (double)(Diffnorm / Dmfnorm)));
20599566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
20609566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
20619566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
2062f3b1f45cSBarry Smith     }
2063f3b1f45cSBarry Smith   } else if (v) {
206401c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n"));
2065f3b1f45cSBarry Smith   }
2066f3b1f45cSBarry Smith   if (flg) *flg = flag;
20679566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
20689566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
20699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
20709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
20719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
20729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
20739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
20743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2075f3b1f45cSBarry Smith }
2076f3b1f45cSBarry Smith 
2077f3b1f45cSBarry Smith /*@C
207811a5261eSBarry Smith   MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix.
2079e51e0e81SBarry Smith 
2080c3339decSBarry Smith   Logically Collective
2081fee21e36SBarry Smith 
2082c7fcc2eaSBarry Smith   Input Parameters:
208311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2084c7fcc2eaSBarry Smith . op  - the name of the operation
2085789d8953SBarry Smith - g   - the function that provides the operation.
2086c7fcc2eaSBarry Smith 
208715091d37SBarry Smith   Level: advanced
208815091d37SBarry Smith 
20892920cce0SJacob Faibussowitsch   Example Usage:
2090c3339decSBarry Smith .vb
2091c3339decSBarry Smith   extern PetscErrorCode usermult(Mat, Vec, Vec);
20922920cce0SJacob Faibussowitsch 
2093c3339decSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
2094c3339decSBarry Smith   MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult);
2095c3339decSBarry Smith .ve
20960b627109SLois Curfman McInnes 
2097a62d957aSLois Curfman McInnes   Notes:
2098e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
20991c1c02c0SLois Curfman McInnes   operations, which all have the form MATOP_<OPERATION>, where
2100a62d957aSLois Curfman McInnes   <OPERATION> is the name (in all capital letters) of the
210111a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2102a62d957aSLois Curfman McInnes 
210311a5261eSBarry Smith   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
2104deebb3c3SLois Curfman McInnes   sequence as the usual matrix interface routines, since they
2105deebb3c3SLois Curfman McInnes   are intended to be accessed via the usual matrix interface
2106deebb3c3SLois Curfman McInnes   routines, e.g.,
2107a62d957aSLois Curfman McInnes $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2108a62d957aSLois Curfman McInnes 
21094aa34b0aSBarry Smith   In particular each function MUST return an error code of 0 on success and
21104aa34b0aSBarry Smith   nonzero on failure.
21114aa34b0aSBarry Smith 
2112a62d957aSLois Curfman McInnes   Within each user-defined routine, the user should call
211311a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
211411a5261eSBarry Smith   set by `MatCreateShell()`.
2115a62d957aSLois Curfman McInnes 
21162ef1f0ffSBarry Smith   Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc)
21172ef1f0ffSBarry Smith   use `MatShellSetMatProductOperation()`
2118b77ba244SStefano Zampini 
2119fe59aa6dSJacob Faibussowitsch   Fortran Notes:
212011a5261eSBarry Smith   For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not
2121c4762a1bSJed Brown   generate a matrix. See src/mat/tests/ex120f.F
2122501d9185SBarry Smith 
21231cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2124e51e0e81SBarry Smith @*/
2125d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void))
2126d71ae5a4SJacob Faibussowitsch {
21273a40ed3dSBarry Smith   PetscFunctionBegin;
21280700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2129cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g));
21303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2131e51e0e81SBarry Smith }
2132f0479e8cSBarry Smith 
2133d4bb536fSBarry Smith /*@C
213411a5261eSBarry Smith   MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix.
2135d4bb536fSBarry Smith 
2136c7fcc2eaSBarry Smith   Not Collective
2137c7fcc2eaSBarry Smith 
2138d4bb536fSBarry Smith   Input Parameters:
213911a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2140c7fcc2eaSBarry Smith - op  - the name of the operation
2141d4bb536fSBarry Smith 
2142d4bb536fSBarry Smith   Output Parameter:
2143789d8953SBarry Smith . g - the function that provides the operation.
2144d4bb536fSBarry Smith 
214515091d37SBarry Smith   Level: advanced
214615091d37SBarry Smith 
214727430b45SBarry Smith   Notes:
2148e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
2149d4bb536fSBarry Smith   operations, which all have the form MATOP_<OPERATION>, where
2150d4bb536fSBarry Smith   <OPERATION> is the name (in all capital letters) of the
215111a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2152d4bb536fSBarry Smith 
2153d4bb536fSBarry Smith   All user-provided functions have the same calling
2154d4bb536fSBarry Smith   sequence as the usual matrix interface routines, since they
2155d4bb536fSBarry Smith   are intended to be accessed via the usual matrix interface
2156d4bb536fSBarry Smith   routines, e.g.,
2157d4bb536fSBarry Smith $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2158d4bb536fSBarry Smith 
2159d4bb536fSBarry Smith   Within each user-defined routine, the user should call
216011a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
216111a5261eSBarry Smith   set by `MatCreateShell()`.
2162d4bb536fSBarry Smith 
21631cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2164d4bb536fSBarry Smith @*/
2165d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void))
2166d71ae5a4SJacob Faibussowitsch {
21673a40ed3dSBarry Smith   PetscFunctionBegin;
21680700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2169cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g));
21703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2171d4bb536fSBarry Smith }
2172b77ba244SStefano Zampini 
2173b77ba244SStefano Zampini /*@
217411a5261eSBarry Smith   MatIsShell - Inquires if a matrix is derived from `MATSHELL`
2175b77ba244SStefano Zampini 
2176b77ba244SStefano Zampini   Input Parameter:
2177b77ba244SStefano Zampini . mat - the matrix
2178b77ba244SStefano Zampini 
2179b77ba244SStefano Zampini   Output Parameter:
2180b77ba244SStefano Zampini . flg - the boolean value
2181b77ba244SStefano Zampini 
2182b77ba244SStefano Zampini   Level: developer
2183b77ba244SStefano Zampini 
2184fe59aa6dSJacob Faibussowitsch   Developer Notes:
21852ef1f0ffSBarry Smith   In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices
21862ef1f0ffSBarry Smith   (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc)
2187b77ba244SStefano Zampini 
21881cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT`
2189b77ba244SStefano Zampini @*/
2190d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2191d71ae5a4SJacob Faibussowitsch {
2192b77ba244SStefano Zampini   PetscFunctionBegin;
2193b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
21944f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
2195b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
21963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2197b77ba244SStefano Zampini }
2198