xref: /petsc/src/ksp/ksp/utils/lmvm/brdn/badbrdn.c (revision 58bddbc0aeb8e2276be3739270a4176cb222ba3a)
1 #include <../src/ksp/ksp/utils/lmvm/brdn/brdn.h> /*I "petscksp.h" I*/
2 
3 // Bad Broyden is dual to Broyden: MatSolve routines are dual to Broyden MatMult routines
4 
MatSolve_LMVMBadBrdn_Recursive(Mat B,Vec F,Vec dX)5 static PetscErrorCode MatSolve_LMVMBadBrdn_Recursive(Mat B, Vec F, Vec dX)
6 {
7   PetscFunctionBegin;
8   PetscCall(BroydenKernel_Recursive(B, MATLMVM_MODE_DUAL, F, dX));
9   PetscFunctionReturn(PETSC_SUCCESS);
10 }
11 
MatSolve_LMVMBadBrdn_CompactDense(Mat B,Vec F,Vec dX)12 static PetscErrorCode MatSolve_LMVMBadBrdn_CompactDense(Mat B, Vec F, Vec dX)
13 {
14   PetscFunctionBegin;
15   PetscCall(BroydenKernel_CompactDense(B, MATLMVM_MODE_DUAL, F, dX));
16   PetscFunctionReturn(PETSC_SUCCESS);
17 }
18 
MatSolve_LMVMBadBrdn_Dense(Mat B,Vec F,Vec dX)19 PETSC_UNUSED static PetscErrorCode MatSolve_LMVMBadBrdn_Dense(Mat B, Vec F, Vec dX)
20 {
21   PetscFunctionBegin;
22   PetscCall(BroydenKernel_Dense(B, MATLMVM_MODE_DUAL, F, dX));
23   PetscFunctionReturn(PETSC_SUCCESS);
24 }
25 
MatSolveHermitianTranspose_LMVMBadBrdn_Recursive(Mat B,Vec F,Vec dX)26 static PetscErrorCode MatSolveHermitianTranspose_LMVMBadBrdn_Recursive(Mat B, Vec F, Vec dX)
27 {
28   PetscFunctionBegin;
29   PetscCall(BroydenKernelHermitianTranspose_Recursive(B, MATLMVM_MODE_DUAL, F, dX));
30   PetscFunctionReturn(PETSC_SUCCESS);
31 }
32 
MatSolveHermitianTranspose_LMVMBadBrdn_CompactDense(Mat B,Vec F,Vec dX)33 static PetscErrorCode MatSolveHermitianTranspose_LMVMBadBrdn_CompactDense(Mat B, Vec F, Vec dX)
34 {
35   PetscFunctionBegin;
36   PetscCall(BroydenKernelHermitianTranspose_CompactDense(B, MATLMVM_MODE_DUAL, F, dX));
37   PetscFunctionReturn(PETSC_SUCCESS);
38 }
39 
MatSolveHermitianTranspose_LMVMBadBrdn_Dense(Mat B,Vec F,Vec dX)40 PETSC_UNUSED static PetscErrorCode MatSolveHermitianTranspose_LMVMBadBrdn_Dense(Mat B, Vec F, Vec dX)
41 {
42   PetscFunctionBegin;
43   PetscCall(BroydenKernelHermitianTranspose_Dense(B, MATLMVM_MODE_DUAL, F, dX));
44   PetscFunctionReturn(PETSC_SUCCESS);
45 }
46 
47 /*
48    The bad Broyden kernel can be written as
49 
50      B_{k+1} x = B_k x + (y_k - B_k s_k)^T * (y_k^T B_k s_k)^{-1} y_k^T B_k x
51                = (I + (y_k - B_k s_k)^T (y_k^T B_k s_k)^{-1} y_k^T) (B_k x)
52                  \______________________ _________________________/
53                                         V
54                                recursive rank-1 update
55 
56    When the basis (y_k - B_k s_k) and the products (y_k^T B_k s_k) have been computed, the product can be computed by
57    application of rank-1 updates from oldest to newest
58  */
59 
BadBroydenKernel_Recursive_Inner(Mat B,MatLMVMMode mode,PetscInt oldest,PetscInt next,Vec B0X)60 static PetscErrorCode BadBroydenKernel_Recursive_Inner(Mat B, MatLMVMMode mode, PetscInt oldest, PetscInt next, Vec B0X)
61 {
62   Mat_LMVM        *lmvm        = (Mat_LMVM *)B->data;
63   Mat_Brdn        *lbrdn       = (Mat_Brdn *)lmvm->ctx;
64   MatLMVMBasisType Y_t         = LMVMModeMap(LMBASIS_Y, mode);
65   LMBasis          Y_minus_BkS = lbrdn->basis[LMVMModeMap(BROYDEN_BASIS_Y_MINUS_BKS, mode)];
66   LMBasis          Y;
67   LMProducts       YtBkS = lbrdn->products[LMVMModeMap(BROYDEN_PRODUCTS_YTBKS, mode)];
68 
69   PetscFunctionBegin;
70   PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
71   // These cannot be parallelized, notice the data dependence
72   for (PetscInt i = oldest; i < next; i++) {
73     Vec         y_i, yimbisi;
74     PetscScalar yitbix;
75     PetscScalar yitbisi;
76 
77     PetscCall(LMBasisGetVecRead(Y, i, &y_i));
78     PetscCall(VecDot(B0X, y_i, &yitbix));
79     PetscCall(LMBasisRestoreVecRead(Y, i, &y_i));
80     PetscCall(LMProductsGetDiagonalValue(YtBkS, i, &yitbisi));
81     PetscCall(LMBasisGetVecRead(Y_minus_BkS, i, &yimbisi));
82     PetscCall(VecAXPY(B0X, yitbix / yitbisi, yimbisi));
83     PetscCall(LMBasisRestoreVecRead(Y_minus_BkS, i, &yimbisi));
84   }
85   PetscFunctionReturn(PETSC_SUCCESS);
86 }
87 
88 /*
89    Compute the basis vectors (y_k - B_k s_k) and dot products (y_k^T B_k s_k) recursively
90  */
91 
BadBroydenRecursiveBasisUpdate(Mat B,MatLMVMMode mode)92 static PetscErrorCode BadBroydenRecursiveBasisUpdate(Mat B, MatLMVMMode mode)
93 {
94   Mat_LMVM           *lmvm  = (Mat_LMVM *)B->data;
95   Mat_Brdn           *lbrdn = (Mat_Brdn *)lmvm->ctx;
96   MatLMVMBasisType    Y_t   = LMVMModeMap(LMBASIS_Y, mode);
97   MatLMVMBasisType    B0S_t = LMVMModeMap(LMBASIS_B0S, mode);
98   LMBasis             Y_minus_BkS;
99   LMProducts          YtBkS;
100   BroydenBasisType    Y_minus_BkS_t = LMVMModeMap(BROYDEN_BASIS_Y_MINUS_BKS, mode);
101   BroydenProductsType YtBkS_t       = LMVMModeMap(BROYDEN_PRODUCTS_YTBKS, mode);
102   PetscInt            oldest, next;
103   PetscInt            products_oldest;
104   LMBasis             Y;
105   PetscInt            start;
106 
107   PetscFunctionBegin;
108   if (!lbrdn->basis[Y_minus_BkS_t]) PetscCall(LMBasisCreate(Y_t == LMBASIS_Y ? lmvm->Fprev : lmvm->Xprev, lmvm->m, &lbrdn->basis[Y_minus_BkS_t]));
109   Y_minus_BkS = lbrdn->basis[Y_minus_BkS_t];
110   if (!lbrdn->products[YtBkS_t]) PetscCall(MatLMVMCreateProducts(B, LMBLOCK_DIAGONAL, &lbrdn->products[YtBkS_t]));
111   YtBkS = lbrdn->products[YtBkS_t];
112   PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
113   PetscCall(MatLMVMGetRange(B, &oldest, &next));
114   // invalidate computed values if J0 has changed
115   PetscCall(LMProductsPrepare(YtBkS, lmvm->J0, oldest, next));
116   products_oldest = PetscMax(0, YtBkS->k - lmvm->m);
117   if (oldest > products_oldest) {
118     // recursion is starting from a different starting index, it must be recomputed
119     YtBkS->k = oldest;
120   }
121   Y_minus_BkS->k = start = YtBkS->k;
122   // recompute each column vector in Y_minus_BkS, and the product y_k^T B_k s_k, in order
123   for (PetscInt j = start; j < next; j++) {
124     Vec         p_j, y_j, B0s_j;
125     PetscScalar yjtbjsj, alpha;
126 
127     PetscCall(LMBasisGetWorkVec(Y_minus_BkS, &p_j));
128 
129     // p_j starts as B_0 * s_j
130     PetscCall(MatLMVMBasisGetVecRead(B, B0S_t, j, &B0s_j, &alpha));
131     PetscCall(VecAXPBY(p_j, alpha, 0.0, B0s_j));
132     PetscCall(MatLMVMBasisRestoreVecRead(B, B0S_t, j, &B0s_j, &alpha));
133 
134     /* Use the matmult kernel to compute p_j = B_j * p_j
135        (if j == oldest, p_j is already correct) */
136     if (j > oldest) PetscCall(BadBroydenKernel_Recursive_Inner(B, mode, oldest, j, p_j));
137     PetscCall(LMBasisGetVecRead(Y, j, &y_j));
138     PetscCall(VecDot(p_j, y_j, &yjtbjsj));
139     PetscCall(LMProductsInsertNextDiagonalValue(YtBkS, j, yjtbjsj));
140     PetscCall(VecAYPX(p_j, -1.0, y_j));
141     PetscCall(LMBasisRestoreVecRead(Y, j, &y_j));
142     PetscCall(LMBasisSetNextVec(Y_minus_BkS, p_j));
143     PetscCall(LMBasisRestoreWorkVec(Y_minus_BkS, &p_j));
144   }
145   PetscFunctionReturn(PETSC_SUCCESS);
146 }
147 
BadBroydenKernel_Recursive(Mat B,MatLMVMMode mode,Vec X,Vec Y)148 PETSC_INTERN PetscErrorCode BadBroydenKernel_Recursive(Mat B, MatLMVMMode mode, Vec X, Vec Y)
149 {
150   PetscInt oldest, next;
151 
152   PetscFunctionBegin;
153   PetscCall(MatLMVMApplyJ0Mode(mode)(B, X, Y));
154   PetscCall(MatLMVMGetRange(B, &oldest, &next));
155   if (next > oldest) {
156     PetscCall(BadBroydenRecursiveBasisUpdate(B, mode));
157     PetscCall(BadBroydenKernel_Recursive_Inner(B, mode, oldest, next, Y));
158   }
159   PetscFunctionReturn(PETSC_SUCCESS);
160 }
161 
162 /*
163    The adjoint of the recursive bad Broyden kernel is
164 
165      B_{k+1}^T x = B_k^T (I + y_k (s_k^T B_k^T y_k)^{-1} (y_k - B_k s_k)^T) x
166                          \____________________ ___________________________/
167                                             V
168                                 recursive rank-1 update
169 
170     which can be computed by application of rank-1 updates from newest to oldest
171  */
172 
BadBroydenKernelHermitianTranspose_Recursive_Inner(Mat B,MatLMVMMode mode,PetscInt oldest,PetscInt next,Vec X)173 static PetscErrorCode BadBroydenKernelHermitianTranspose_Recursive_Inner(Mat B, MatLMVMMode mode, PetscInt oldest, PetscInt next, Vec X)
174 {
175   MatLMVMBasisType    Y_t           = LMVMModeMap(LMBASIS_Y, mode);
176   BroydenBasisType    Y_minus_BkS_t = LMVMModeMap(BROYDEN_BASIS_Y_MINUS_BKS, mode);
177   BroydenProductsType YtBkS_t       = LMVMModeMap(BROYDEN_PRODUCTS_YTBKS, mode);
178   Mat_LMVM           *lmvm          = (Mat_LMVM *)B->data;
179   Mat_Brdn           *lbrdn         = (Mat_Brdn *)lmvm->ctx;
180   LMBasis             Y_minus_BkS   = lbrdn->basis[Y_minus_BkS_t];
181   LMBasis             Y;
182   LMProducts          YtBkS = lbrdn->products[YtBkS_t];
183 
184   PetscFunctionBegin;
185   PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
186   // These cannot be parallelized, notice the data dependence
187   for (PetscInt i = next - 1; i >= oldest; i--) {
188     Vec         yimbisi, y_i;
189     PetscScalar yimbisitx;
190     PetscScalar yitbisi;
191 
192     PetscCall(LMBasisGetVecRead(Y_minus_BkS, i, &yimbisi));
193     PetscCall(VecDot(X, yimbisi, &yimbisitx));
194     PetscCall(LMBasisRestoreVecRead(Y_minus_BkS, i, &yimbisi));
195     PetscCall(LMProductsGetDiagonalValue(YtBkS, i, &yitbisi));
196     PetscCall(LMBasisGetVecRead(Y, i, &y_i));
197     PetscCall(VecAXPY(X, yimbisitx / PetscConj(yitbisi), y_i));
198     PetscCall(LMBasisRestoreVecRead(Y, i, &y_i));
199   }
200   PetscFunctionReturn(PETSC_SUCCESS);
201 }
202 
BadBroydenKernelHermitianTranspose_Recursive(Mat B,MatLMVMMode mode,Vec X,Vec BX)203 PETSC_INTERN PetscErrorCode BadBroydenKernelHermitianTranspose_Recursive(Mat B, MatLMVMMode mode, Vec X, Vec BX)
204 {
205   MatLMVMBasisType Y_t = LMVMModeMap(LMBASIS_Y, mode);
206   PetscInt         oldest, next;
207   Vec              G = X;
208   LMBasis          Y;
209 
210   PetscFunctionBegin;
211   PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
212   PetscCall(MatLMVMGetRange(B, &oldest, &next));
213   if (next > oldest) {
214     PetscCall(LMBasisGetWorkVec(Y, &G));
215     PetscCall(VecCopy(X, G));
216     PetscCall(BadBroydenRecursiveBasisUpdate(B, mode));
217     PetscCall(BadBroydenKernelHermitianTranspose_Recursive_Inner(B, mode, oldest, next, G));
218   }
219   PetscCall(MatLMVMApplyJ0HermitianTransposeMode(mode)(B, G, BX));
220   if (next > oldest) PetscCall(LMBasisRestoreWorkVec(Y, &G));
221   PetscFunctionReturn(PETSC_SUCCESS);
222 }
223 
224 /*
225    The bad Broyden kernel can be written as
226 
227      B_k = B_0 + (Y - B_0 S) (Y^H B_0 S - stril(Y^H Y))^{-1} Y^H B_0
228          = (I + (Y - B_0 S) (Y^H B_0 S - stril(Y^H Y))^{-1} Y^H) B_0
229 
230    where stril is the strictly lower triangular component.  We compute and factorize
231    the small matrix in order to apply a single rank m update
232  */
233 
BadBroydenCompactProductsUpdate(Mat B,MatLMVMMode mode)234 static PetscErrorCode BadBroydenCompactProductsUpdate(Mat B, MatLMVMMode mode)
235 {
236   MatLMVMBasisType    Y_t               = LMVMModeMap(LMBASIS_Y, mode);
237   MatLMVMBasisType    B0S_t             = LMVMModeMap(LMBASIS_B0S, mode);
238   BroydenProductsType YtB0S_minus_YtY_t = LMVMModeMap(BROYDEN_PRODUCTS_YTB0S_MINUS_YTY, mode);
239   Mat_LMVM           *lmvm              = (Mat_LMVM *)B->data;
240   Mat_Brdn           *lbrdn             = (Mat_Brdn *)lmvm->ctx;
241   LMProducts          YtB0S, YtY, YtB0S_minus_YtY;
242   LMBasis             Y, B0S;
243   PetscScalar         alpha;
244   PetscInt            oldest, k, next;
245   PetscBool           local_is_nonempty;
246   Mat                 ytbsmyty_local;
247 
248   PetscFunctionBegin;
249   if (!lbrdn->products[YtB0S_minus_YtY_t]) PetscCall(MatLMVMCreateProducts(B, LMBLOCK_FULL, &lbrdn->products[YtB0S_minus_YtY_t]));
250   YtB0S_minus_YtY = lbrdn->products[YtB0S_minus_YtY_t];
251   PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
252   PetscCall(MatLMVMGetUpdatedBasis(B, B0S_t, &B0S, &B0S_t, &alpha));
253   PetscCall(MatLMVMGetRange(B, &oldest, &next));
254   // invalidate computed values if J0 has changed
255   PetscCall(LMProductsPrepare(YtB0S_minus_YtY, lmvm->J0, oldest, next));
256   PetscCall(LMProductsGetLocalMatrix(YtB0S_minus_YtY, &ytbsmyty_local, &k, &local_is_nonempty));
257   if (k < next) {
258     Mat yty_local, ytbs_local;
259 
260     PetscCall(MatLMVMGetUpdatedProducts(B, Y_t, B0S_t, LMBLOCK_FULL, &YtB0S));
261     PetscCall(MatLMVMGetUpdatedProducts(B, Y_t, Y_t, LMBLOCK_STRICT_UPPER_TRIANGLE, &YtY));
262     PetscCall(LMProductsGetLocalMatrix(YtB0S, &ytbs_local, NULL, NULL));
263     PetscCall(LMProductsGetLocalMatrix(YtY, &yty_local, NULL, NULL));
264     if (local_is_nonempty) {
265       PetscCall(MatSetUnfactored(ytbsmyty_local));
266       PetscCall(MatCopy(yty_local, ytbsmyty_local, SAME_NONZERO_PATTERN));
267       PetscCall(MatTranspose(ytbsmyty_local, MAT_INPLACE_MATRIX, &ytbsmyty_local));
268       if (PetscDefined(USE_COMPLEX)) PetscCall(MatConjugate(ytbsmyty_local));
269       PetscCall(MatScale(ytbsmyty_local, -1.0));
270       PetscCall(MatAXPY(ytbsmyty_local, alpha, ytbs_local, SAME_NONZERO_PATTERN));
271       PetscCall(LMProductsOnesOnUnusedDiagonal(ytbsmyty_local, oldest, next));
272       PetscCall(MatLUFactor(ytbsmyty_local, NULL, NULL, NULL));
273     }
274     PetscCall(LMProductsRestoreLocalMatrix(YtY, &yty_local, NULL));
275     PetscCall(LMProductsRestoreLocalMatrix(YtB0S, &ytbs_local, NULL));
276   }
277   PetscCall(LMProductsRestoreLocalMatrix(YtB0S_minus_YtY, &ytbsmyty_local, &next));
278   PetscFunctionReturn(PETSC_SUCCESS);
279 }
280 
BadBroydenKernel_CompactDense(Mat B,MatLMVMMode mode,Vec X,Vec BX)281 PETSC_INTERN PetscErrorCode BadBroydenKernel_CompactDense(Mat B, MatLMVMMode mode, Vec X, Vec BX)
282 {
283   PetscInt oldest, next;
284 
285   PetscFunctionBegin;
286   PetscCall(MatLMVMApplyJ0Mode(mode)(B, X, BX));
287   PetscCall(MatLMVMGetRange(B, &oldest, &next));
288   if (next > oldest) {
289     Mat_LMVM           *lmvm              = (Mat_LMVM *)B->data;
290     Mat_Brdn           *lbrdn             = (Mat_Brdn *)lmvm->ctx;
291     MatLMVMBasisType    Y_t               = LMVMModeMap(LMBASIS_Y, mode);
292     MatLMVMBasisType    Y_minus_B0S_t     = LMVMModeMap(LMBASIS_Y_MINUS_B0S, mode);
293     BroydenProductsType YtB0S_minus_YtY_t = LMVMModeMap(BROYDEN_PRODUCTS_YTB0S_MINUS_YTY, mode);
294     LMProducts          YtB0S_minus_YtY;
295     LMBasis             Y;
296     Vec                 YtB0X, v;
297 
298     PetscCall(BadBroydenCompactProductsUpdate(B, mode));
299     PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
300     YtB0S_minus_YtY = lbrdn->products[YtB0S_minus_YtY_t];
301     PetscCall(MatLMVMGetWorkRow(B, &YtB0X));
302     PetscCall(MatLMVMGetWorkRow(B, &v));
303     PetscCall(LMBasisGEMVH(Y, oldest, next, 1.0, BX, 0.0, YtB0X));
304     PetscCall(LMProductsSolve(YtB0S_minus_YtY, oldest, next, YtB0X, v, /* ^H */ PETSC_FALSE));
305     PetscCall(MatLMVMBasisGEMV(B, Y_minus_B0S_t, oldest, next, 1.0, v, 1.0, BX));
306     PetscCall(MatLMVMRestoreWorkRow(B, &v));
307     PetscCall(MatLMVMRestoreWorkRow(B, &YtB0X));
308   }
309   PetscFunctionReturn(PETSC_SUCCESS);
310 }
311 
312 /*
313    The adjoint of the above formula for the bad Broyden kernel is
314 
315      B_k^H = B_0^H + B_0^H Y (Y^H B_0 S - stril(Y^H Y))^{-H} (Y - B_0 S)^H
316            = B_0^H (I + Y (Y^H B_0 S - stril(Y^H Y))^{-H} (Y - B_0 S)^H)
317  */
318 
BadBroydenKernelHermitianTranspose_CompactDense(Mat B,MatLMVMMode mode,Vec X,Vec BHX)319 PETSC_INTERN PetscErrorCode BadBroydenKernelHermitianTranspose_CompactDense(Mat B, MatLMVMMode mode, Vec X, Vec BHX)
320 {
321   MatLMVMBasisType Y_t = LMVMModeMap(LMBASIS_Y, mode);
322   PetscInt         oldest, next;
323   Vec              G = X;
324   LMBasis          Y = NULL;
325 
326   PetscFunctionBegin;
327   PetscCall(MatLMVMGetRange(B, &oldest, &next));
328   if (next > oldest) {
329     Mat_LMVM           *lmvm              = (Mat_LMVM *)B->data;
330     Mat_Brdn           *lbrdn             = (Mat_Brdn *)lmvm->ctx;
331     MatLMVMBasisType    Y_minus_B0S_t     = LMVMModeMap(LMBASIS_Y_MINUS_B0S, mode);
332     BroydenProductsType YtB0S_minus_YtY_t = LMVMModeMap(BROYDEN_PRODUCTS_YTB0S_MINUS_YTY, mode);
333     LMProducts          YtB0S_minus_YtY;
334     Vec                 YmB0StG, v;
335 
336     PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
337     PetscCall(LMBasisGetWorkVec(Y, &G));
338     PetscCall(VecCopy(X, G));
339     PetscCall(BadBroydenCompactProductsUpdate(B, mode));
340     YtB0S_minus_YtY = lbrdn->products[YtB0S_minus_YtY_t];
341     PetscCall(MatLMVMGetWorkRow(B, &YmB0StG));
342     PetscCall(MatLMVMGetWorkRow(B, &v));
343     PetscCall(MatLMVMBasisGEMVH(B, Y_minus_B0S_t, oldest, next, 1.0, G, 0.0, YmB0StG));
344     PetscCall(LMProductsSolve(YtB0S_minus_YtY, oldest, next, YmB0StG, v, /* ^H */ PETSC_TRUE));
345     PetscCall(LMBasisGEMV(Y, oldest, next, 1.0, v, 1.0, G));
346     PetscCall(MatLMVMRestoreWorkRow(B, &v));
347     PetscCall(MatLMVMRestoreWorkRow(B, &YmB0StG));
348   }
349   PetscCall(MatLMVMApplyJ0HermitianTransposeMode(mode)(B, G, BHX));
350   if (next > oldest) PetscCall(LMBasisRestoreWorkVec(Y, &G));
351   PetscFunctionReturn(PETSC_SUCCESS);
352 }
353 
MatMult_LMVMBadBrdn_Recursive(Mat B,Vec F,Vec dX)354 static PetscErrorCode MatMult_LMVMBadBrdn_Recursive(Mat B, Vec F, Vec dX)
355 {
356   PetscFunctionBegin;
357   PetscCall(BadBroydenKernel_Recursive(B, MATLMVM_MODE_PRIMAL, F, dX));
358   PetscFunctionReturn(PETSC_SUCCESS);
359 }
360 
MatMult_LMVMBadBrdn_CompactDense(Mat B,Vec F,Vec dX)361 static PetscErrorCode MatMult_LMVMBadBrdn_CompactDense(Mat B, Vec F, Vec dX)
362 {
363   PetscFunctionBegin;
364   PetscCall(BadBroydenKernel_CompactDense(B, MATLMVM_MODE_PRIMAL, F, dX));
365   PetscFunctionReturn(PETSC_SUCCESS);
366 }
367 
MatMultHermitianTranspose_LMVMBadBrdn_Recursive(Mat B,Vec F,Vec dX)368 static PetscErrorCode MatMultHermitianTranspose_LMVMBadBrdn_Recursive(Mat B, Vec F, Vec dX)
369 {
370   PetscFunctionBegin;
371   PetscCall(BadBroydenKernelHermitianTranspose_Recursive(B, MATLMVM_MODE_PRIMAL, F, dX));
372   PetscFunctionReturn(PETSC_SUCCESS);
373 }
374 
MatMultHermitianTranspose_LMVMBadBrdn_CompactDense(Mat B,Vec F,Vec dX)375 static PetscErrorCode MatMultHermitianTranspose_LMVMBadBrdn_CompactDense(Mat B, Vec F, Vec dX)
376 {
377   PetscFunctionBegin;
378   PetscCall(BadBroydenKernelHermitianTranspose_CompactDense(B, MATLMVM_MODE_PRIMAL, F, dX));
379   PetscFunctionReturn(PETSC_SUCCESS);
380 }
381 
MatLMVMSetMultAlgorithm_BadBrdn(Mat B)382 static PetscErrorCode MatLMVMSetMultAlgorithm_BadBrdn(Mat B)
383 {
384   Mat_LMVM *lmvm = (Mat_LMVM *)B->data;
385 
386   PetscFunctionBegin;
387   switch (lmvm->mult_alg) {
388   case MAT_LMVM_MULT_RECURSIVE:
389     lmvm->ops->mult    = MatMult_LMVMBadBrdn_Recursive;
390     lmvm->ops->multht  = MatMultHermitianTranspose_LMVMBadBrdn_Recursive;
391     lmvm->ops->solve   = MatSolve_LMVMBadBrdn_Recursive;
392     lmvm->ops->solveht = MatSolveHermitianTranspose_LMVMBadBrdn_Recursive;
393     break;
394   case MAT_LMVM_MULT_DENSE:
395     lmvm->ops->mult    = MatMult_LMVMBadBrdn_CompactDense;
396     lmvm->ops->multht  = MatMultHermitianTranspose_LMVMBadBrdn_CompactDense;
397     lmvm->ops->solve   = MatSolve_LMVMBadBrdn_Dense;
398     lmvm->ops->solveht = MatSolveHermitianTranspose_LMVMBadBrdn_Dense;
399     break;
400   case MAT_LMVM_MULT_COMPACT_DENSE:
401     lmvm->ops->mult    = MatMult_LMVMBadBrdn_CompactDense;
402     lmvm->ops->multht  = MatMultHermitianTranspose_LMVMBadBrdn_CompactDense;
403     lmvm->ops->solve   = MatSolve_LMVMBadBrdn_CompactDense;
404     lmvm->ops->solveht = MatSolveHermitianTranspose_LMVMBadBrdn_CompactDense;
405     break;
406   }
407   PetscFunctionReturn(PETSC_SUCCESS);
408 }
409 
MatCreate_LMVMBadBrdn(Mat B)410 PetscErrorCode MatCreate_LMVMBadBrdn(Mat B)
411 {
412   Mat_LMVM *lmvm;
413 
414   PetscFunctionBegin;
415   PetscCall(MatCreate_LMVMBrdn(B));
416   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATLMVMBADBROYDEN));
417   lmvm                          = (Mat_LMVM *)B->data;
418   lmvm->ops->setmultalgorithm   = MatLMVMSetMultAlgorithm_BadBrdn;
419   lmvm->cache_gradient_products = PETSC_TRUE;
420   PetscCall(MatLMVMSetMultAlgorithm_BadBrdn(B));
421   PetscFunctionReturn(PETSC_SUCCESS);
422 }
423 
424 /*@
425   MatCreateLMVMBadBroyden - Creates a limited-memory modified (aka "bad") Broyden-type
426   approximation matrix used for a Jacobian. L-BadBrdn is not guaranteed to be
427   symmetric or positive-definite.
428 
429   To use the L-BadBrdn matrix with other vector types, the matrix must be
430   created using `MatCreate()` and `MatSetType()`, followed by `MatLMVMAllocate()`.
431   This ensures that the internal storage and work vectors are duplicated from the
432   correct type of vector.
433 
434   Collective
435 
436   Input Parameters:
437 + comm - MPI communicator
438 . n    - number of local rows for storage vectors
439 - N    - global size of the storage vectors
440 
441   Output Parameter:
442 . B - the matrix
443 
444   Options Database Keys:
445 + -mat_lmvm_hist_size         - the number of history vectors to keep
446 . -mat_lmvm_mult_algorithm    - the algorithm to use for multiplication (recursive, dense, compact_dense)
447 . -mat_lmvm_cache_J0_products - whether products between the base Jacobian J0 and history vectors should be cached or recomputed
448 - -mat_lmvm_debug             - (developer) perform internal debugging checks
449 
450   Level: intermediate
451 
452   Note:
453   It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`
454   paradigm instead of this routine directly.
455 
456 .seealso: [](ch_ksp), `MatCreate()`, `MATLMVM`, `MATLMVMBADBRDN`, `MatCreateLMVMDFP()`, `MatCreateLMVMSR1()`,
457           `MatCreateLMVMBFGS()`, `MatCreateLMVMBroyden()`, `MatCreateLMVMSymBroyden()`
458 @*/
MatCreateLMVMBadBroyden(MPI_Comm comm,PetscInt n,PetscInt N,Mat * B)459 PetscErrorCode MatCreateLMVMBadBroyden(MPI_Comm comm, PetscInt n, PetscInt N, Mat *B)
460 {
461   PetscFunctionBegin;
462   PetscCall(KSPInitializePackage());
463   PetscCall(MatCreate(comm, B));
464   PetscCall(MatSetSizes(*B, n, n, N, N));
465   PetscCall(MatSetType(*B, MATLMVMBADBROYDEN));
466   PetscCall(MatSetUp(*B));
467   PetscFunctionReturn(PETSC_SUCCESS);
468 }
469