Actual source code: dfp.c
1: #include <../src/ksp/ksp/utils/lmvm/symbrdn/symbrdn.h>
3: /* The DFP update can be written as
5: B_{k+1} = (I - y_k (y_k^T s_k)^{-1} s_k^T) B_k (I - s_k (y_k^T s_k)^{-1} y_k^T) + y_k (y_k^T s_k)^{-1} y_k^T
7: So B_{k+1}x can be computed in the following way
9: a_k = (y_k^T s_k)^{-1} y_k^T x
10: g = B_k (x - a s_k) <--- recursion
11: B_{k+1}x = g + y_k(a - (y_k^T s_k)^{-1} s_k^T g)
12: */
13: PETSC_INTERN PetscErrorCode DFPKernel_Recursive(Mat B, MatLMVMMode mode, Vec X, Vec BX)
14: {
15: MatLMVMBasisType S_t = LMVMModeMap(LMBASIS_S, mode);
16: MatLMVMBasisType Y_t = LMVMModeMap(LMBASIS_Y, mode);
17: LMBasis S, Y;
18: LMProducts YtS;
19: Vec G = X;
20: PetscScalar *alpha = NULL;
21: PetscInt oldest, next;
23: PetscFunctionBegin;
24: PetscCall(MatLMVMGetRange(B, &oldest, &next));
25: PetscCall(MatLMVMGetUpdatedBasis(B, S_t, &S, NULL, NULL));
26: PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
27: PetscCall(MatLMVMGetUpdatedProducts(B, Y_t, S_t, LMBLOCK_DIAGONAL, &YtS));
28: if (next > oldest) {
29: PetscCall(LMBasisGetWorkVec(S, &G));
30: PetscCall(VecCopy(X, G));
31: PetscCall(PetscMalloc1(next - oldest, &alpha));
32: }
33: for (PetscInt i = next - 1; i >= oldest; i--) {
34: Vec s_i, y_i;
35: PetscScalar yitsi, yitx, a;
37: PetscCall(LMBasisGetVecRead(Y, i, &y_i));
38: PetscCall(VecDot(G, y_i, &yitx));
39: PetscCall(LMBasisRestoreVecRead(Y, i, &y_i));
40: PetscCall(LMProductsGetDiagonalValue(YtS, i, &yitsi));
41: alpha[i - oldest] = a = yitx / yitsi;
42: PetscCall(LMBasisGetVecRead(S, i, &s_i));
43: PetscCall(VecAXPY(G, -a, s_i));
44: PetscCall(LMBasisRestoreVecRead(S, i, &s_i));
45: }
46: PetscCall(MatLMVMApplyJ0Mode(mode)(B, G, BX));
47: for (PetscInt i = oldest; i < next; i++) {
48: Vec s_i, y_i;
49: PetscScalar yitsi, sitbx, a, b;
51: PetscCall(LMBasisGetVecRead(S, i, &s_i));
52: PetscCall(VecDot(BX, s_i, &sitbx));
53: PetscCall(LMBasisRestoreVecRead(S, i, &s_i));
54: PetscCall(LMProductsGetDiagonalValue(YtS, i, &yitsi));
55: a = alpha[i - oldest];
56: b = sitbx / yitsi;
57: PetscCall(LMBasisGetVecRead(Y, i, &y_i));
58: PetscCall(VecAXPY(BX, a - b, y_i));
59: PetscCall(LMBasisRestoreVecRead(Y, i, &y_i));
60: }
61: if (next > oldest) {
62: PetscCall(PetscFree(alpha));
63: PetscCall(LMBasisRestoreWorkVec(S, &G));
64: }
65: PetscFunctionReturn(PETSC_SUCCESS);
66: }
68: PETSC_INTERN PetscErrorCode DFPKernel_CompactDense(Mat B, MatLMVMMode mode, Vec X, Vec BX)
69: {
70: PetscInt oldest, next;
72: PetscFunctionBegin;
73: PetscCall(MatLMVMApplyJ0Mode(mode)(B, X, BX));
74: PetscCall(MatLMVMGetRange(B, &oldest, &next));
75: if (next > oldest) {
76: MatLMVMBasisType S_t = LMVMModeMap(LMBASIS_S, mode);
77: MatLMVMBasisType Y_t = LMVMModeMap(LMBASIS_Y, mode);
78: MatLMVMBasisType B0S_t = LMVMModeMap(LMBASIS_B0S, mode);
79: Vec StB0X, YtX, u, v;
80: PetscBool use_B0S;
81: LMBasis S, Y;
82: LMProducts YtS, StB0S, D;
84: PetscCall(MatLMVMGetUpdatedBasis(B, S_t, &S, NULL, NULL));
85: PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
86: PetscCall(MatLMVMGetUpdatedProducts(B, Y_t, S_t, LMBLOCK_UPPER_TRIANGLE, &YtS));
87: PetscCall(MatLMVMGetUpdatedProducts(B, Y_t, S_t, LMBLOCK_DIAGONAL, &D));
88: PetscCall(MatLMVMGetUpdatedProducts(B, S_t, B0S_t, LMBLOCK_UPPER_TRIANGLE, &StB0S));
90: PetscCall(MatLMVMGetWorkRow(B, &StB0X));
91: PetscCall(MatLMVMGetWorkRow(B, &YtX));
92: PetscCall(MatLMVMGetWorkRow(B, &u));
93: PetscCall(MatLMVMGetWorkRow(B, &v));
95: PetscCall(SymBroydenCompactDenseKernelUseB0S(B, mode, X, &use_B0S));
96: if (use_B0S) PetscCall(MatLMVMBasisGEMVH(B, B0S_t, oldest, next, 1.0, X, 0.0, StB0X));
97: else PetscCall(LMBasisGEMVH(S, oldest, next, 1.0, BX, 0.0, StB0X));
99: PetscCall(LMBasisGEMVH(Y, oldest, next, 1.0, X, 0.0, YtX));
100: PetscCall(LMProductsSolve(YtS, oldest, next, YtX, YtX, /* ^H */ PETSC_FALSE));
102: PetscCall(VecAXPBY(u, -1.0, 0.0, YtX));
103: PetscCall(LMProductsMult(D, oldest, next, 1.0, YtX, 0.0, v, /* ^H */ PETSC_FALSE));
104: PetscCall(LMProductsMultHermitian(StB0S, oldest, next, 1.0, YtX, 1.0, v));
105: PetscCall(VecAXPY(v, -1.0, StB0X));
107: PetscCall(LMProductsSolve(YtS, oldest, next, v, v, /* ^H */ PETSC_TRUE));
108: PetscCall(LMBasisGEMV(Y, oldest, next, 1.0, v, 1.0, BX));
109: PetscCall(MatLMVMBasisGEMV(B, B0S_t, oldest, next, 1.0, u, 1.0, BX));
111: PetscCall(MatLMVMRestoreWorkRow(B, &v));
112: PetscCall(MatLMVMRestoreWorkRow(B, &u));
113: PetscCall(MatLMVMRestoreWorkRow(B, &YtX));
114: PetscCall(MatLMVMRestoreWorkRow(B, &StB0X));
115: }
116: PetscFunctionReturn(PETSC_SUCCESS);
117: }
119: PETSC_INTERN PetscErrorCode DFPKernel_Dense(Mat B, MatLMVMMode mode, Vec X, Vec BX)
120: {
121: Vec G = X;
122: Vec YtX = NULL, u = NULL;
123: PetscInt oldest, next;
124: LMProducts YtS = NULL, D = NULL;
125: LMBasis S = NULL, Y = NULL;
127: PetscFunctionBegin;
128: PetscCall(MatLMVMGetRange(B, &oldest, &next));
129: if (next > oldest) {
130: MatLMVMBasisType S_t = LMVMModeMap(LMBASIS_S, mode);
131: MatLMVMBasisType Y_t = LMVMModeMap(LMBASIS_Y, mode);
133: PetscCall(MatLMVMGetUpdatedBasis(B, S_t, &S, NULL, NULL));
134: PetscCall(MatLMVMGetUpdatedBasis(B, Y_t, &Y, NULL, NULL));
135: PetscCall(MatLMVMGetUpdatedProducts(B, Y_t, S_t, LMBLOCK_UPPER_TRIANGLE, &YtS));
136: PetscCall(MatLMVMGetUpdatedProducts(B, Y_t, S_t, LMBLOCK_DIAGONAL, &D));
137: PetscCall(LMBasisGetWorkVec(Y, &G));
138: PetscCall(VecCopy(X, G));
140: PetscCall(MatLMVMGetWorkRow(B, &YtX));
141: PetscCall(MatLMVMGetWorkRow(B, &u));
142: PetscCall(LMBasisGEMVH(Y, oldest, next, 1.0, X, 0.0, YtX));
143: PetscCall(LMProductsSolve(YtS, oldest, next, YtX, YtX, /* ^H */ PETSC_FALSE));
144: PetscCall(LMBasisGEMV(S, oldest, next, -1.0, YtX, 1.0, G));
145: }
146: PetscCall(MatLMVMApplyJ0Mode(mode)(B, G, BX));
147: if (next > oldest) {
148: PetscCall(LMProductsMult(D, oldest, next, 1.0, YtX, 0.0, u, /* ^H */ PETSC_FALSE));
149: PetscCall(LMBasisGEMVH(S, oldest, next, -1.0, BX, 1.0, u));
150: PetscCall(LMProductsSolve(YtS, oldest, next, u, u, /* ^H */ PETSC_TRUE));
151: PetscCall(LMBasisGEMV(Y, oldest, next, 1.0, u, 1.0, BX));
152: PetscCall(MatLMVMRestoreWorkRow(B, &u));
153: PetscCall(MatLMVMRestoreWorkRow(B, &YtX));
154: PetscCall(LMBasisRestoreWorkVec(Y, &G));
155: }
156: PetscFunctionReturn(PETSC_SUCCESS);
157: }
159: static PetscErrorCode MatMult_LMVMDFP_Recursive(Mat B, Vec X, Vec BX)
160: {
161: PetscFunctionBegin;
162: PetscCall(DFPKernel_Recursive(B, MATLMVM_MODE_PRIMAL, X, BX));
163: PetscFunctionReturn(PETSC_SUCCESS);
164: }
166: static PetscErrorCode MatMult_LMVMDFP_CompactDense(Mat B, Vec X, Vec BX)
167: {
168: PetscFunctionBegin;
169: PetscCall(DFPKernel_CompactDense(B, MATLMVM_MODE_PRIMAL, X, BX));
170: PetscFunctionReturn(PETSC_SUCCESS);
171: }
173: static PetscErrorCode MatMult_LMVMDFP_Dense(Mat B, Vec X, Vec BX)
174: {
175: PetscFunctionBegin;
176: PetscCall(DFPKernel_Dense(B, MATLMVM_MODE_PRIMAL, X, BX));
177: PetscFunctionReturn(PETSC_SUCCESS);
178: }
180: static PetscErrorCode MatSolve_LMVMDFP_Recursive(Mat B, Vec X, Vec HX)
181: {
182: PetscFunctionBegin;
183: PetscCall(BFGSKernel_Recursive(B, MATLMVM_MODE_DUAL, X, HX));
184: PetscFunctionReturn(PETSC_SUCCESS);
185: }
187: static PetscErrorCode MatSolve_LMVMDFP_CompactDense(Mat B, Vec X, Vec HX)
188: {
189: PetscFunctionBegin;
190: PetscCall(BFGSKernel_CompactDense(B, MATLMVM_MODE_DUAL, X, HX));
191: PetscFunctionReturn(PETSC_SUCCESS);
192: }
194: static PetscErrorCode MatSetFromOptions_LMVMDFP(Mat B, PetscOptionItems PetscOptionsObject)
195: {
196: Mat_LMVM *lmvm = (Mat_LMVM *)B->data;
197: Mat_SymBrdn *ldfp = (Mat_SymBrdn *)lmvm->ctx;
199: PetscFunctionBegin;
200: PetscCall(MatSetFromOptions_LMVM(B, PetscOptionsObject));
201: PetscOptionsHeadBegin(PetscOptionsObject, "DFP method for approximating SPD Jacobian actions (MATLMVMDFP)");
202: PetscCall(SymBroydenRescaleSetFromOptions(B, ldfp->rescale, PetscOptionsObject));
203: PetscOptionsHeadEnd();
204: PetscFunctionReturn(PETSC_SUCCESS);
205: }
207: static PetscErrorCode MatLMVMSetMultAlgorithm_DFP(Mat B)
208: {
209: Mat_LMVM *lmvm = (Mat_LMVM *)B->data;
211: PetscFunctionBegin;
212: switch (lmvm->mult_alg) {
213: case MAT_LMVM_MULT_RECURSIVE:
214: lmvm->ops->mult = MatMult_LMVMDFP_Recursive;
215: lmvm->ops->solve = MatSolve_LMVMDFP_Recursive;
216: break;
217: case MAT_LMVM_MULT_DENSE:
218: lmvm->ops->mult = MatMult_LMVMDFP_Dense;
219: lmvm->ops->solve = MatSolve_LMVMDFP_CompactDense;
220: break;
221: case MAT_LMVM_MULT_COMPACT_DENSE:
222: lmvm->ops->mult = MatMult_LMVMDFP_CompactDense;
223: lmvm->ops->solve = MatSolve_LMVMDFP_CompactDense;
224: break;
225: }
226: lmvm->ops->multht = lmvm->ops->mult;
227: lmvm->ops->solveht = lmvm->ops->solve;
228: PetscFunctionReturn(PETSC_SUCCESS);
229: }
231: PetscErrorCode MatCreate_LMVMDFP(Mat B)
232: {
233: Mat_LMVM *lmvm;
234: Mat_SymBrdn *ldfp;
236: PetscFunctionBegin;
237: PetscCall(MatCreate_LMVMSymBrdn(B));
238: PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATLMVMDFP));
239: B->ops->setfromoptions = MatSetFromOptions_LMVMDFP;
241: lmvm = (Mat_LMVM *)B->data;
242: lmvm->ops->setmultalgorithm = MatLMVMSetMultAlgorithm_DFP;
243: PetscCall(MatLMVMSetMultAlgorithm_DFP(B));
245: ldfp = (Mat_SymBrdn *)lmvm->ctx;
246: ldfp->phi_scalar = 1.0;
247: ldfp->psi_scalar = 0.0;
248: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatLMVMSymBadBroydenSetPsi_C", NULL));
249: PetscFunctionReturn(PETSC_SUCCESS);
250: }
252: /*@
253: MatCreateLMVMDFP - Creates a limited-memory Davidon-Fletcher-Powell (DFP) matrix
254: used for approximating Jacobians. L-DFP is symmetric positive-definite by
255: construction, and is the dual of L-BFGS where Y and S vectors swap roles.
257: To use the L-DFP matrix with other vector types, the matrix must be
258: created using `MatCreate()` and `MatSetType()`, followed by `MatLMVMAllocate()`.
259: This ensures that the internal storage and work vectors are duplicated from the
260: correct type of vector.
262: Collective
264: Input Parameters:
265: + comm - MPI communicator
266: . n - number of local rows for storage vectors
267: - N - global size of the storage vectors
269: Output Parameter:
270: . B - the matrix
272: Options Database Keys:
273: + -mat_lmvm_scale_type - (developer) type of scaling applied to J0 (none, scalar, diagonal)
274: . -mat_lmvm_theta - (developer) convex ratio between BFGS and DFP components of the diagonal J0 scaling
275: . -mat_lmvm_rho - (developer) update limiter for the J0 scaling
276: . -mat_lmvm_alpha - (developer) coefficient factor for the quadratic subproblem in J0 scaling
277: . -mat_lmvm_beta - (developer) exponential factor for the diagonal J0 scaling
278: - -mat_lmvm_sigma_hist - (developer) number of past updates to use in J0 scaling
280: Level: intermediate
282: Note:
283: It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`
284: paradigm instead of this routine directly.
286: .seealso: [](ch_ksp), `MatCreate()`, `MATLMVM`, `MATLMVMDFP`, `MatCreateLMVMBFGS()`, `MatCreateLMVMSR1()`,
287: `MatCreateLMVMBroyden()`, `MatCreateLMVMBadBroyden()`, `MatCreateLMVMSymBroyden()`
288: @*/
289: PetscErrorCode MatCreateLMVMDFP(MPI_Comm comm, PetscInt n, PetscInt N, Mat *B)
290: {
291: PetscFunctionBegin;
292: PetscCall(KSPInitializePackage());
293: PetscCall(MatCreate(comm, B));
294: PetscCall(MatSetSizes(*B, n, n, N, N));
295: PetscCall(MatSetType(*B, MATLMVMDFP));
296: PetscCall(MatSetUp(*B));
297: PetscFunctionReturn(PETSC_SUCCESS);
298: }