xref: /petsc/src/mat/impls/lrc/lrc.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
1ceb9aaf7SBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
3ceb9aaf7SBarry Smith 
4d751fb92SStefano Zampini PETSC_EXTERN PetscErrorCode VecGetRootType_Private(Vec, VecType *);
5d751fb92SStefano Zampini 
6ceb9aaf7SBarry Smith typedef struct {
7986c4d72SJose E. Roman   Mat A;            /* sparse matrix */
8986c4d72SJose E. Roman   Mat U, V;         /* dense tall-skinny matrices */
9986c4d72SJose E. Roman   Vec c;            /* sequential vector containing the diagonal of C */
10986c4d72SJose E. Roman   Vec work1, work2; /* sequential vectors that hold partial products */
110575051bSJose E. Roman   Vec xl, yl;       /* auxiliary sequential vectors for matmult operation */
12ab92ecdeSBarry Smith } Mat_LRC;
13ab92ecdeSBarry Smith 
14*9371c9d4SSatish Balay static PetscErrorCode MatMult_LRC_kernel(Mat N, Vec x, Vec y, PetscBool transpose) {
15ab92ecdeSBarry Smith   Mat_LRC    *Na = (Mat_LRC *)N->data;
16d751fb92SStefano Zampini   PetscMPIInt size;
17d751fb92SStefano Zampini   Mat         U, V;
18ceb9aaf7SBarry Smith 
19ceb9aaf7SBarry Smith   PetscFunctionBegin;
20d751fb92SStefano Zampini   U = transpose ? Na->V : Na->U;
21d751fb92SStefano Zampini   V = transpose ? Na->U : Na->V;
229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)N), &size));
23d751fb92SStefano Zampini   if (size == 1) {
249566063dSJacob Faibussowitsch     PetscCall(MatMultHermitianTranspose(V, x, Na->work1));
251baa6e33SBarry Smith     if (Na->c) PetscCall(VecPointwiseMult(Na->work1, Na->c, Na->work1));
26d751fb92SStefano Zampini     if (Na->A) {
27d751fb92SStefano Zampini       if (transpose) {
289566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(Na->A, x, y));
29d751fb92SStefano Zampini       } else {
309566063dSJacob Faibussowitsch         PetscCall(MatMult(Na->A, x, y));
31d751fb92SStefano Zampini       }
329566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(U, Na->work1, y, y));
33d751fb92SStefano Zampini     } else {
349566063dSJacob Faibussowitsch       PetscCall(MatMult(U, Na->work1, y));
35d751fb92SStefano Zampini     }
36d751fb92SStefano Zampini   } else {
37d751fb92SStefano Zampini     Mat                Uloc, Vloc;
38d751fb92SStefano Zampini     Vec                yl, xl;
39d751fb92SStefano Zampini     const PetscScalar *w1;
40d751fb92SStefano Zampini     PetscScalar       *w2;
41d751fb92SStefano Zampini     PetscInt           nwork;
42d751fb92SStefano Zampini     PetscMPIInt        mpinwork;
43d751fb92SStefano Zampini 
44d751fb92SStefano Zampini     xl = transpose ? Na->yl : Na->xl;
45d751fb92SStefano Zampini     yl = transpose ? Na->xl : Na->yl;
469566063dSJacob Faibussowitsch     PetscCall(VecGetLocalVector(y, yl));
479566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLocalMatrix(U, &Uloc));
489566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLocalMatrix(V, &Vloc));
490575051bSJose E. Roman 
50ab92ecdeSBarry Smith     /* multiply the local part of V with the local part of x */
519566063dSJacob Faibussowitsch     PetscCall(VecGetLocalVectorRead(x, xl));
529566063dSJacob Faibussowitsch     PetscCall(MatMultHermitianTranspose(Vloc, xl, Na->work1));
539566063dSJacob Faibussowitsch     PetscCall(VecRestoreLocalVectorRead(x, xl));
54ab92ecdeSBarry Smith 
5586eed97dSJose E. Roman     /* form the sum of all the local multiplies: this is work2 = V'*x =
56ab92ecdeSBarry Smith        sum_{all processors} work1 */
579566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(Na->work1, &w1));
589566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(Na->work2, &w2));
599566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(Na->work1, &nwork));
609566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(nwork, &mpinwork));
611c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(w1, w2, mpinwork, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)N)));
629566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(Na->work1, &w1));
639566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(Na->work2, &w2));
64ab92ecdeSBarry Smith 
65986c4d72SJose E. Roman     if (Na->c) { /* work2 = C*work2 */
669566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(Na->work2, Na->c, Na->work2));
67986c4d72SJose E. Roman     }
68986c4d72SJose E. Roman 
6986eed97dSJose E. Roman     if (Na->A) {
70d751fb92SStefano Zampini       /* form y = A*x or A^t*x */
71d751fb92SStefano Zampini       if (transpose) {
729566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(Na->A, x, y));
73d751fb92SStefano Zampini       } else {
749566063dSJacob Faibussowitsch         PetscCall(MatMult(Na->A, x, y));
75d751fb92SStefano Zampini       }
7686eed97dSJose E. Roman       /* multiply-add y = y + U*work2 */
779566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(Uloc, Na->work2, yl, yl));
7886eed97dSJose E. Roman     } else {
7986eed97dSJose E. Roman       /* multiply y = U*work2 */
809566063dSJacob Faibussowitsch       PetscCall(MatMult(Uloc, Na->work2, yl));
8186eed97dSJose E. Roman     }
820575051bSJose E. Roman 
839566063dSJacob Faibussowitsch     PetscCall(VecRestoreLocalVector(y, yl));
84d751fb92SStefano Zampini   }
85ceb9aaf7SBarry Smith   PetscFunctionReturn(0);
86ceb9aaf7SBarry Smith }
87ceb9aaf7SBarry Smith 
88*9371c9d4SSatish Balay static PetscErrorCode MatMult_LRC(Mat N, Vec x, Vec y) {
89d751fb92SStefano Zampini   PetscFunctionBegin;
909566063dSJacob Faibussowitsch   PetscCall(MatMult_LRC_kernel(N, x, y, PETSC_FALSE));
91d751fb92SStefano Zampini   PetscFunctionReturn(0);
92d751fb92SStefano Zampini }
93d751fb92SStefano Zampini 
94*9371c9d4SSatish Balay static PetscErrorCode MatMultTranspose_LRC(Mat N, Vec x, Vec y) {
95d751fb92SStefano Zampini   PetscFunctionBegin;
969566063dSJacob Faibussowitsch   PetscCall(MatMult_LRC_kernel(N, x, y, PETSC_TRUE));
97d751fb92SStefano Zampini   PetscFunctionReturn(0);
98d751fb92SStefano Zampini }
99d751fb92SStefano Zampini 
100*9371c9d4SSatish Balay static PetscErrorCode MatDestroy_LRC(Mat N) {
101ab92ecdeSBarry Smith   Mat_LRC *Na = (Mat_LRC *)N->data;
102ceb9aaf7SBarry Smith 
103ceb9aaf7SBarry Smith   PetscFunctionBegin;
1049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Na->A));
1059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Na->U));
1069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Na->V));
1079566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Na->c));
1089566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Na->work1));
1099566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Na->work2));
1109566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Na->xl));
1119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Na->yl));
1129566063dSJacob Faibussowitsch   PetscCall(PetscFree(N->data));
1139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatLRCGetMats_C", NULL));
114267ca84cSJose E. Roman   PetscFunctionReturn(0);
115267ca84cSJose E. Roman }
116267ca84cSJose E. Roman 
117*9371c9d4SSatish Balay static PetscErrorCode MatLRCGetMats_LRC(Mat N, Mat *A, Mat *U, Vec *c, Mat *V) {
118267ca84cSJose E. Roman   Mat_LRC *Na = (Mat_LRC *)N->data;
119267ca84cSJose E. Roman 
120267ca84cSJose E. Roman   PetscFunctionBegin;
121267ca84cSJose E. Roman   if (A) *A = Na->A;
122267ca84cSJose E. Roman   if (U) *U = Na->U;
123267ca84cSJose E. Roman   if (c) *c = Na->c;
124267ca84cSJose E. Roman   if (V) *V = Na->V;
125267ca84cSJose E. Roman   PetscFunctionReturn(0);
126267ca84cSJose E. Roman }
127267ca84cSJose E. Roman 
128267ca84cSJose E. Roman /*@
129267ca84cSJose E. Roman    MatLRCGetMats - Returns the constituents of an LRC matrix
130267ca84cSJose E. Roman 
131267ca84cSJose E. Roman    Collective on Mat
132267ca84cSJose E. Roman 
133267ca84cSJose E. Roman    Input Parameter:
134267ca84cSJose E. Roman .  N - matrix of type LRC
135267ca84cSJose E. Roman 
136267ca84cSJose E. Roman    Output Parameters:
137267ca84cSJose E. Roman +  A - the (sparse) matrix
1386b867d5aSJose E. Roman .  U - first dense rectangular (tall and skinny) matrix
1396b867d5aSJose E. Roman .  c - a sequential vector containing the diagonal of C
1406b867d5aSJose E. Roman -  V - second dense rectangular (tall and skinny) matrix
141267ca84cSJose E. Roman 
142267ca84cSJose E. Roman    Note:
143267ca84cSJose E. Roman    The returned matrices need not be destroyed by the caller.
144267ca84cSJose E. Roman 
145267ca84cSJose E. Roman    Level: intermediate
146267ca84cSJose E. Roman 
147db781477SPatrick Sanan .seealso: `MatCreateLRC()`
148267ca84cSJose E. Roman @*/
149*9371c9d4SSatish Balay PetscErrorCode MatLRCGetMats(Mat N, Mat *A, Mat *U, Vec *c, Mat *V) {
150267ca84cSJose E. Roman   PetscFunctionBegin;
151cac4c232SBarry Smith   PetscUseMethod(N, "MatLRCGetMats_C", (Mat, Mat *, Mat *, Vec *, Mat *), (N, A, U, c, V));
152ceb9aaf7SBarry Smith   PetscFunctionReturn(0);
153ceb9aaf7SBarry Smith }
154ceb9aaf7SBarry Smith 
155ceb9aaf7SBarry Smith /*@
156986c4d72SJose E. Roman    MatCreateLRC - Creates a new matrix object that behaves like A + U*C*V'
157ceb9aaf7SBarry Smith 
158ceb9aaf7SBarry Smith    Collective on Mat
159ceb9aaf7SBarry Smith 
1609d9032efSJose E. Roman    Input Parameters:
16186eed97dSJose E. Roman +  A    - the (sparse) matrix (can be NULL)
162986c4d72SJose E. Roman .  U, V - two dense rectangular (tall and skinny) matrices
163d751fb92SStefano Zampini -  c    - a vector containing the diagonal of C (can be NULL)
164ceb9aaf7SBarry Smith 
165ceb9aaf7SBarry Smith    Output Parameter:
166986c4d72SJose E. Roman .  N    - the matrix that represents A + U*C*V'
167ceb9aaf7SBarry Smith 
1689d9032efSJose E. Roman    Notes:
169986c4d72SJose E. Roman    The matrix A + U*C*V' is not formed! Rather the new matrix
170ceb9aaf7SBarry Smith    object performs the matrix-vector product by first multiplying by
1719d9032efSJose E. Roman    A and then adding the other term.
1729d9032efSJose E. Roman 
173986c4d72SJose E. Roman    C is a diagonal matrix (represented as a vector) of order k,
174986c4d72SJose E. Roman    where k is the number of columns of both U and V.
17586eed97dSJose E. Roman 
176986c4d72SJose E. Roman    If A is NULL then the new object behaves like a low-rank matrix U*C*V'.
177986c4d72SJose E. Roman 
178986c4d72SJose E. Roman    Use V=U (or V=NULL) for a symmetric low-rank correction, A + U*C*U'.
179986c4d72SJose E. Roman 
180986c4d72SJose E. Roman    If c is NULL then the low-rank correction is just U*V'.
181d751fb92SStefano Zampini    If a sequential c vector is used for a parallel matrix,
182d751fb92SStefano Zampini    PETSc assumes that the values of the vector are consistently set across processors.
18386eed97dSJose E. Roman 
1849d9032efSJose E. Roman    Level: intermediate
185267ca84cSJose E. Roman 
186db781477SPatrick Sanan .seealso: `MatLRCGetMats()`
187ceb9aaf7SBarry Smith @*/
188*9371c9d4SSatish Balay PetscErrorCode MatCreateLRC(Mat A, Mat U, Vec c, Mat V, Mat *N) {
189986c4d72SJose E. Roman   PetscBool   match;
1909d9032efSJose E. Roman   PetscInt    m, n, k, m1, n1, k1;
191ab92ecdeSBarry Smith   Mat_LRC    *Na;
192d751fb92SStefano Zampini   Mat         Uloc;
193d751fb92SStefano Zampini   PetscMPIInt size, csize = 0;
194ceb9aaf7SBarry Smith 
195ceb9aaf7SBarry Smith   PetscFunctionBegin;
19686eed97dSJose E. Roman   if (A) PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1979d9032efSJose E. Roman   PetscValidHeaderSpecific(U, MAT_CLASSID, 2);
198986c4d72SJose E. Roman   if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 3);
199986c4d72SJose E. Roman   if (V) {
200d751fb92SStefano Zampini     PetscValidHeaderSpecific(V, MAT_CLASSID, 4);
201d751fb92SStefano Zampini     PetscCheckSameComm(U, 2, V, 4);
202d751fb92SStefano Zampini   }
203d751fb92SStefano Zampini   if (A) PetscCheckSameComm(A, 1, U, 2);
204d751fb92SStefano Zampini 
205d751fb92SStefano Zampini   if (!V) V = U;
2069566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)U, &match, MATSEQDENSE, MATMPIDENSE, ""));
20728b400f6SJacob Faibussowitsch   PetscCheck(match, PetscObjectComm((PetscObject)U), PETSC_ERR_SUP, "Matrix U must be of type dense, found %s", ((PetscObject)U)->type_name);
2089566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)V, &match, MATSEQDENSE, MATMPIDENSE, ""));
20928b400f6SJacob Faibussowitsch   PetscCheck(match, PetscObjectComm((PetscObject)U), PETSC_ERR_SUP, "Matrix V must be of type dense, found %s", ((PetscObject)V)->type_name);
2109566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(U->defaultvectype, V->defaultvectype, &match));
21128b400f6SJacob Faibussowitsch   PetscCheck(match, PetscObjectComm((PetscObject)U), PETSC_ERR_ARG_WRONG, "Matrix U and V must have the same VecType %s != %s", U->defaultvectype, V->defaultvectype);
212d751fb92SStefano Zampini   if (A) {
2139566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(A->defaultvectype, U->defaultvectype, &match));
21428b400f6SJacob Faibussowitsch     PetscCheck(match, PetscObjectComm((PetscObject)U), PETSC_ERR_ARG_WRONG, "Matrix A and U must have the same VecType %s != %s", A->defaultvectype, U->defaultvectype);
215986c4d72SJose E. Roman   }
2169d9032efSJose E. Roman 
2179566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)U), &size));
2189566063dSJacob Faibussowitsch   PetscCall(MatGetSize(U, NULL, &k));
2199566063dSJacob Faibussowitsch   PetscCall(MatGetSize(V, NULL, &k1));
22008401ef6SPierre Jolivet   PetscCheck(k == k1, PetscObjectComm((PetscObject)U), PETSC_ERR_ARG_INCOMP, "U and V have different number of columns (%" PetscInt_FMT " vs %" PetscInt_FMT ")", k, k1);
2219566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(U, &m, NULL));
2229566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(V, &n, NULL));
22386eed97dSJose E. Roman   if (A) {
2249566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m1, &n1));
22508401ef6SPierre Jolivet     PetscCheck(m == m1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local dimensions of U %" PetscInt_FMT " and A %" PetscInt_FMT " do not match", m, m1);
22608401ef6SPierre Jolivet     PetscCheck(n == n1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local dimensions of V %" PetscInt_FMT " and A %" PetscInt_FMT " do not match", n, n1);
22786eed97dSJose E. Roman   }
228986c4d72SJose E. Roman   if (c) {
2299566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)c), &csize));
2309566063dSJacob Faibussowitsch     PetscCall(VecGetSize(c, &k1));
23108401ef6SPierre Jolivet     PetscCheck(k == k1, PetscObjectComm((PetscObject)c), PETSC_ERR_ARG_INCOMP, "The length of c %" PetscInt_FMT " does not match the number of columns of U and V (%" PetscInt_FMT ")", k1, k);
232aed4548fSBarry Smith     PetscCheck(csize == 1 || csize == size, PetscObjectComm((PetscObject)c), PETSC_ERR_ARG_INCOMP, "U and c must have the same communicator size %d != %d", size, csize);
233986c4d72SJose E. Roman   }
2349d9032efSJose E. Roman 
2359566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)U), N));
2369566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*N, m, n, PETSC_DECIDE, PETSC_DECIDE));
2379566063dSJacob Faibussowitsch   PetscCall(MatSetVecType(*N, U->defaultvectype));
2389566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*N, MATLRC));
239d751fb92SStefano Zampini   /* Flag matrix as symmetric if A is symmetric and U == V */
240b94d7dedSBarry Smith   PetscCall(MatSetOption(*N, MAT_SYMMETRIC, (PetscBool)((A ? A->symmetric == PETSC_BOOL3_TRUE : PETSC_TRUE) && U == V)));
241ceb9aaf7SBarry Smith 
2429566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(*N, &Na));
24338f2d2fdSLisandro Dalcin   (*N)->data = (void *)Na;
244ceb9aaf7SBarry Smith   Na->A      = A;
245a639b4dcSJose E. Roman   Na->U      = U;
246986c4d72SJose E. Roman   Na->c      = c;
247a639b4dcSJose E. Roman   Na->V      = V;
248ab92ecdeSBarry Smith 
2499566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)A));
2509566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)Na->U));
2519566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)Na->V));
2529566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)c));
253ceb9aaf7SBarry Smith 
2549566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(Na->U, &Uloc));
2559566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(Uloc, &Na->work1, NULL));
256d751fb92SStefano Zampini   if (size != 1) {
257d751fb92SStefano Zampini     Mat Vloc;
258d751fb92SStefano Zampini 
259d751fb92SStefano Zampini     if (Na->c && csize != 1) { /* scatter parallel vector to sequential */
260d751fb92SStefano Zampini       VecScatter sct;
261d751fb92SStefano Zampini 
2629566063dSJacob Faibussowitsch       PetscCall(VecScatterCreateToAll(Na->c, &sct, &c));
2639566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(sct, Na->c, c, INSERT_VALUES, SCATTER_FORWARD));
2649566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(sct, Na->c, c, INSERT_VALUES, SCATTER_FORWARD));
2659566063dSJacob Faibussowitsch       PetscCall(VecScatterDestroy(&sct));
2669566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&Na->c));
2679566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)*N, (PetscObject)c));
268d751fb92SStefano Zampini       Na->c = c;
269d751fb92SStefano Zampini     }
2709566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLocalMatrix(Na->V, &Vloc));
2719566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(Na->work1, &Na->work2));
2729566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(Vloc, NULL, &Na->xl));
2739566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(Uloc, NULL, &Na->yl));
274d751fb92SStefano Zampini   }
2759566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)*N, (PetscObject)Na->work1));
2769566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)*N, (PetscObject)Na->work1));
2779566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)*N, (PetscObject)Na->xl));
2789566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)*N, (PetscObject)Na->yl));
279ab92ecdeSBarry Smith 
280d751fb92SStefano Zampini   /* Internally create a scaling vector if roottypes do not match */
281d751fb92SStefano Zampini   if (Na->c) {
282d751fb92SStefano Zampini     VecType rt1, rt2;
283d751fb92SStefano Zampini 
2849566063dSJacob Faibussowitsch     PetscCall(VecGetRootType_Private(Na->work1, &rt1));
2859566063dSJacob Faibussowitsch     PetscCall(VecGetRootType_Private(Na->c, &rt2));
2869566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(rt1, rt2, &match));
287d751fb92SStefano Zampini     if (!match) {
2889566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(Na->c, &c));
2899566063dSJacob Faibussowitsch       PetscCall(VecCopy(Na->c, c));
2909566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&Na->c));
2919566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)*N, (PetscObject)c));
292d751fb92SStefano Zampini       Na->c = c;
293d751fb92SStefano Zampini     }
294d751fb92SStefano Zampini   }
2950575051bSJose E. Roman 
296ab92ecdeSBarry Smith   (*N)->ops->destroy       = MatDestroy_LRC;
297ab92ecdeSBarry Smith   (*N)->ops->mult          = MatMult_LRC;
298d751fb92SStefano Zampini   (*N)->ops->multtranspose = MatMultTranspose_LRC;
299d751fb92SStefano Zampini 
300ceb9aaf7SBarry Smith   (*N)->assembled    = PETSC_TRUE;
30126c5da1bSJose E. Roman   (*N)->preallocated = PETSC_TRUE;
302267ca84cSJose E. Roman 
3039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)(*N), "MatLRCGetMats_C", MatLRCGetMats_LRC));
3049566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*N));
305ceb9aaf7SBarry Smith   PetscFunctionReturn(0);
306ceb9aaf7SBarry Smith }
307