Actual source code: lmesetup.c
slepc-main 2024-12-17
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: LME routines related to problem setup
12: */
14: #include <slepc/private/lmeimpl.h>
16: static inline PetscErrorCode LMESetUp_Lyapunov(LME lme)
17: {
18: Mat C1,C2,X1,X2;
19: Vec dc,dx;
21: PetscFunctionBegin;
22: PetscCall(MatLRCGetMats(lme->C,NULL,&C1,&dc,&C2));
23: PetscCheck(C1==C2,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_WRONGSTATE,"Lyapunov matrix equation requires symmetric right-hand side C");
24: PetscCheck(!dc,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_WRONGSTATE,"Lyapunov solvers currently require positive-definite right-hand side C");
25: if (lme->X) {
26: PetscCall(MatLRCGetMats(lme->X,NULL,&X1,&dx,&X2));
27: PetscCheck(X1==X2,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_WRONGSTATE,"Lyapunov matrix equation requires symmetric solution X");
28: PetscCheck(!dx,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_WRONGSTATE,"Lyapunov solvers currently assume a positive-definite solution X");
29: }
30: PetscFunctionReturn(PETSC_SUCCESS);
31: }
33: /*@
34: LMESetUp - Sets up all the internal data structures necessary for the
35: execution of the linear matrix equation solver.
37: Collective
39: Input Parameter:
40: . lme - linear matrix equation solver context
42: Notes:
43: This function need not be called explicitly in most cases, since LMESolve()
44: calls it. It can be useful when one wants to measure the set-up time
45: separately from the solve time.
47: Level: developer
49: .seealso: LMECreate(), LMESolve(), LMEDestroy()
50: @*/
51: PetscErrorCode LMESetUp(LME lme)
52: {
53: PetscInt N;
55: PetscFunctionBegin;
58: /* reset the convergence flag from the previous solves */
59: lme->reason = LME_CONVERGED_ITERATING;
61: if (lme->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
62: PetscCall(PetscLogEventBegin(LME_SetUp,lme,0,0,0));
64: /* Set default solver type (LMESetFromOptions was not called) */
65: if (!((PetscObject)lme)->type_name) PetscCall(LMESetType(lme,LMEKRYLOV));
67: /* Check problem dimensions */
68: PetscCheck(lme->A,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_WRONGSTATE,"LMESetCoefficients must be called first");
69: PetscCall(MatGetSize(lme->A,&N,NULL));
70: if (lme->ncv > N) lme->ncv = N;
72: /* setup options for the particular equation type */
73: switch (lme->problem_type) {
74: case LME_LYAPUNOV:
75: PetscCall(LMESetUp_Lyapunov(lme));
76: break;
77: case LME_SYLVESTER:
78: LMECheckCoeff(lme,lme->B,"B","Sylvester");
79: break;
80: case LME_GEN_LYAPUNOV:
81: LMECheckCoeff(lme,lme->D,"D","Generalized Lyapunov");
82: break;
83: case LME_GEN_SYLVESTER:
84: LMECheckCoeff(lme,lme->B,"B","Generalized Sylvester");
85: LMECheckCoeff(lme,lme->D,"D","Generalized Sylvester");
86: LMECheckCoeff(lme,lme->E,"E","Generalized Sylvester");
87: break;
88: case LME_DT_LYAPUNOV:
89: break;
90: case LME_STEIN:
91: LMECheckCoeff(lme,lme->D,"D","Stein");
92: break;
93: }
94: PetscCheck(lme->problem_type==LME_LYAPUNOV,PetscObjectComm((PetscObject)lme),PETSC_ERR_SUP,"There is no solver yet for this matrix equation type");
96: /* call specific solver setup */
97: PetscUseTypeMethod(lme,setup);
99: /* set tolerance if not yet set */
100: if (lme->tol==(PetscReal)PETSC_DETERMINE) lme->tol = SLEPC_DEFAULT_TOL;
102: PetscCall(PetscLogEventEnd(LME_SetUp,lme,0,0,0));
103: lme->setupcalled = 1;
104: PetscFunctionReturn(PETSC_SUCCESS);
105: }
107: static inline PetscErrorCode LMESetCoefficients_Private(LME lme,Mat A,Mat *lmeA)
108: {
109: PetscInt m,n;
111: PetscFunctionBegin;
112: PetscCall(MatGetSize(A,&m,&n));
113: PetscCheck(m==n,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_WRONG,"Matrix is non-square");
114: if (!lme->setupcalled) PetscCall(MatDestroy(lmeA));
115: PetscCall(PetscObjectReference((PetscObject)A));
116: *lmeA = A;
117: PetscFunctionReturn(PETSC_SUCCESS);
118: }
120: /*@
121: LMESetCoefficients - Sets the coefficient matrices that define the linear matrix
122: equation to be solved.
124: Collective
126: Input Parameters:
127: + lme - the matrix function context
128: . A - first coefficient matrix
129: . B - second coefficient matrix
130: . D - third coefficient matrix
131: - E - fourth coefficient matrix
133: Notes:
134: The matrix equation takes the general form A*X*E+D*X*B=C, where matrix C is not
135: provided here but with LMESetRHS(). Not all four matrices must be passed, some
136: can be NULL instead, see LMESetProblemType() for details.
138: It must be called before LMESetUp(). If it is called again after LMESetUp() then
139: the LME object is reset.
141: In order to delete a previously set matrix, pass a NULL in the corresponding
142: argument.
144: Level: beginner
146: .seealso: LMESolve(), LMESetUp(), LMESetRHS(), LMESetProblemType()
147: @*/
148: PetscErrorCode LMESetCoefficients(LME lme,Mat A,Mat B,Mat D,Mat E)
149: {
150: PetscFunctionBegin;
153: PetscCheckSameComm(lme,1,A,2);
154: if (B) {
156: PetscCheckSameComm(lme,1,B,3);
157: }
158: if (D) {
160: PetscCheckSameComm(lme,1,D,4);
161: }
162: if (E) {
164: PetscCheckSameComm(lme,1,E,5);
165: }
167: if (lme->setupcalled) PetscCall(LMEReset(lme));
169: PetscCall(LMESetCoefficients_Private(lme,A,&lme->A));
170: if (B) PetscCall(LMESetCoefficients_Private(lme,B,&lme->B));
171: else if (!lme->setupcalled) PetscCall(MatDestroy(&lme->B));
172: if (D) PetscCall(LMESetCoefficients_Private(lme,D,&lme->D));
173: else if (!lme->setupcalled) PetscCall(MatDestroy(&lme->D));
174: if (E) PetscCall(LMESetCoefficients_Private(lme,E,&lme->E));
175: else if (!lme->setupcalled) PetscCall(MatDestroy(&lme->E));
177: lme->setupcalled = 0;
178: PetscFunctionReturn(PETSC_SUCCESS);
179: }
181: /*@
182: LMEGetCoefficients - Gets the coefficient matrices of the matrix equation.
184: Not Collective
186: Input Parameter:
187: . lme - the LME context
189: Output Parameters:
190: + A - first coefficient matrix
191: . B - second coefficient matrix
192: . D - third coefficient matrix
193: - E - fourth coefficient matrix
195: Level: intermediate
197: .seealso: LMESolve(), LMESetCoefficients()
198: @*/
199: PetscErrorCode LMEGetCoefficients(LME lme,Mat *A,Mat *B,Mat *D,Mat *E)
200: {
201: PetscFunctionBegin;
203: if (A) *A = lme->A;
204: if (B) *B = lme->B;
205: if (D) *D = lme->D;
206: if (E) *E = lme->E;
207: PetscFunctionReturn(PETSC_SUCCESS);
208: }
210: /*@
211: LMESetRHS - Sets the right-hand side of the matrix equation, as a low-rank
212: matrix.
214: Collective
216: Input Parameters:
217: + lme - the matrix function context
218: - C - the right-hand side matrix
220: Notes:
221: The matrix equation takes the general form A*X*E+D*X*B=C, where matrix C is
222: given with this function. C must be a low-rank matrix of type MATLRC, that is,
223: C = U*D*V' where D is diagonal of order k, and U, V are dense tall-skinny
224: matrices with k columns. No sparse matrix must be provided when creating the
225: MATLRC matrix.
227: In equation types that require C to be symmetric, such as Lyapunov, C must be
228: created with V=U (or V=NULL).
230: Level: beginner
232: .seealso: LMESetSolution(), LMESetProblemType()
233: @*/
234: PetscErrorCode LMESetRHS(LME lme,Mat C)
235: {
236: Mat A;
238: PetscFunctionBegin;
241: PetscCheckSameComm(lme,1,C,2);
242: PetscCheckTypeName(C,MATLRC);
244: PetscCall(MatLRCGetMats(C,&A,NULL,NULL,NULL));
245: PetscCheck(!A,PetscObjectComm((PetscObject)C),PETSC_ERR_SUP,"The MatLRC must not have a sparse matrix term");
247: PetscCall(PetscObjectReference((PetscObject)C));
248: PetscCall(MatDestroy(&lme->C));
249: lme->C = C;
250: PetscFunctionReturn(PETSC_SUCCESS);
251: }
253: /*@
254: LMEGetRHS - Gets the right-hand side of the matrix equation.
256: Not Collective
258: Input Parameter:
259: . lme - the LME context
261: Output Parameters:
262: . C - the low-rank matrix
264: Level: intermediate
266: .seealso: LMESolve(), LMESetRHS()
267: @*/
268: PetscErrorCode LMEGetRHS(LME lme,Mat *C)
269: {
270: PetscFunctionBegin;
272: PetscAssertPointer(C,2);
273: *C = lme->C;
274: PetscFunctionReturn(PETSC_SUCCESS);
275: }
277: /*@
278: LMESetSolution - Sets the placeholder for the solution of the matrix
279: equation, as a low-rank matrix.
281: Collective
283: Input Parameters:
284: + lme - the matrix function context
285: - X - the solution matrix
287: Notes:
288: The matrix equation takes the general form A*X*E+D*X*B=C, where the solution
289: matrix is of low rank and is written in factored form X = U*D*V'. This function
290: provides a Mat object of type MATLRC that stores U, V and (optionally) D.
291: These factors will be computed during LMESolve().
293: In equation types whose solution X is symmetric, such as Lyapunov, X must be
294: created with V=U (or V=NULL).
296: If the user provides X with this function, then the solver will
297: return a solution with rank at most the number of columns of U. Alternatively,
298: it is possible to let the solver choose the rank of the solution, by
299: setting X to NULL and then calling LMEGetSolution() after LMESolve().
301: Level: intermediate
303: .seealso: LMEGetSolution(), LMESetRHS(), LMESetProblemType(), LMESolve()
304: @*/
305: PetscErrorCode LMESetSolution(LME lme,Mat X)
306: {
307: Mat A;
309: PetscFunctionBegin;
311: if (X) {
313: PetscCheckSameComm(lme,1,X,2);
314: PetscCheckTypeName(X,MATLRC);
315: PetscCall(MatLRCGetMats(X,&A,NULL,NULL,NULL));
316: PetscCheck(!A,PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"The MatLRC must not have a sparse matrix term");
317: PetscCall(PetscObjectReference((PetscObject)X));
318: }
319: PetscCall(MatDestroy(&lme->X));
320: lme->X = X;
321: PetscFunctionReturn(PETSC_SUCCESS);
322: }
324: /*@
325: LMEGetSolution - Gets the solution of the matrix equation.
327: Not Collective
329: Input Parameter:
330: . lme - the LME context
332: Output Parameters:
333: . X - the low-rank matrix
335: Level: intermediate
337: .seealso: LMESolve(), LMESetSolution()
338: @*/
339: PetscErrorCode LMEGetSolution(LME lme,Mat *X)
340: {
341: PetscFunctionBegin;
343: PetscAssertPointer(X,2);
344: *X = lme->X;
345: PetscFunctionReturn(PETSC_SUCCESS);
346: }
348: /*@
349: LMEAllocateSolution - Allocate memory storage for common variables such
350: as the basis vectors.
352: Collective
354: Input Parameters:
355: + lme - linear matrix equation solver context
356: - extra - number of additional positions, used for methods that require a
357: working basis slightly larger than ncv
359: Developer Notes:
360: This is SLEPC_EXTERN because it may be required by user plugin LME
361: implementations.
363: Level: developer
365: .seealso: LMESetUp()
366: @*/
367: PetscErrorCode LMEAllocateSolution(LME lme,PetscInt extra)
368: {
369: PetscInt oldsize,requested;
370: Vec t;
372: PetscFunctionBegin;
373: requested = lme->ncv + extra;
375: /* oldsize is zero if this is the first time setup is called */
376: PetscCall(BVGetSizes(lme->V,NULL,NULL,&oldsize));
378: /* allocate basis vectors */
379: if (!lme->V) PetscCall(LMEGetBV(lme,&lme->V));
380: if (!oldsize) {
381: if (!((PetscObject)lme->V)->type_name) PetscCall(BVSetType(lme->V,BVMAT));
382: PetscCall(MatCreateVecsEmpty(lme->A,&t,NULL));
383: PetscCall(BVSetSizesFromVec(lme->V,t,requested));
384: PetscCall(VecDestroy(&t));
385: } else PetscCall(BVResize(lme->V,requested,PETSC_FALSE));
386: PetscFunctionReturn(PETSC_SUCCESS);
387: }