Actual source code: svdsetup.c
1: /*
2: SVD routines for setting up the solver.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2012, Universitat Politecnica de Valencia, Spain
8: This file is part of SLEPc.
9:
10: SLEPc is free software: you can redistribute it and/or modify it under the
11: terms of version 3 of the GNU Lesser General Public License as published by
12: the Free Software Foundation.
14: SLEPc is distributed in the hope that it will be useful, but WITHOUT ANY
15: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17: more details.
19: You should have received a copy of the GNU Lesser General Public License
20: along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
21: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22: */
24: #include <slepc-private/svdimpl.h> /*I "slepcsvd.h" I*/
25: #include <slepc-private/ipimpl.h>
29: /*@
30: SVDSetOperator - Set the matrix associated with the singular value problem.
32: Collective on SVD and Mat
34: Input Parameters:
35: + svd - the singular value solver context
36: - A - the matrix associated with the singular value problem
38: Level: beginner
40: .seealso: SVDSolve(), SVDGetOperator()
41: @*/
42: PetscErrorCode SVDSetOperator(SVD svd,Mat mat)
43: {
50: if (svd->setupcalled) { SVDReset(svd); }
51: PetscObjectReference((PetscObject)mat);
52: MatDestroy(&svd->OP);
53: svd->OP = mat;
54: return(0);
55: }
59: /*@
60: SVDGetOperator - Get the matrix associated with the singular value problem.
62: Not collective, though parallel Mats are returned if the SVD is parallel
64: Input Parameter:
65: . svd - the singular value solver context
67: Output Parameters:
68: . A - the matrix associated with the singular value problem
70: Level: advanced
72: .seealso: SVDSolve(), SVDSetOperator()
73: @*/
74: PetscErrorCode SVDGetOperator(SVD svd,Mat *A)
75: {
79: *A = svd->OP;
80: return(0);
81: }
85: /*@
86: SVDSetUp - Sets up all the internal data structures necessary for the
87: execution of the singular value solver.
89: Collective on SVD
91: Input Parameter:
92: . svd - singular value solver context
94: Level: advanced
96: Notes:
97: This function need not be called explicitly in most cases, since SVDSolve()
98: calls it. It can be useful when one wants to measure the set-up time
99: separately from the solve time.
101: .seealso: SVDCreate(), SVDSolve(), SVDDestroy()
102: @*/
103: PetscErrorCode SVDSetUp(SVD svd)
104: {
106: PetscBool flg,lindep;
107: PetscInt i,k,M,N;
108: PetscReal norm;
109:
112: if (svd->setupcalled) return(0);
113: PetscLogEventBegin(SVD_SetUp,svd,0,0,0);
115: /* Set default solver type (SVDSetFromOptions was not called) */
116: if (!((PetscObject)svd)->type_name) {
117: SVDSetType(svd,SVDCROSS);
118: }
119: if (!svd->ip) { SVDGetIP(svd,&svd->ip); }
120: if (!((PetscObject)svd->ip)->type_name) {
121: IPSetDefaultType_Private(svd->ip);
122: }
123: if (!svd->ds) { SVDGetDS(svd,&svd->ds); }
124: DSReset(svd->ds);
125: if (!((PetscObject)svd->rand)->type_name) {
126: PetscRandomSetFromOptions(svd->rand);
127: }
129: /* check matrix */
130: if (!svd->OP) SETERRQ(((PetscObject)svd)->comm,PETSC_ERR_ARG_WRONGSTATE,"SVDSetOperator must be called first");
131:
132: /* determine how to build the transpose */
133: if (svd->transmode == PETSC_DECIDE) {
134: MatHasOperation(svd->OP,MATOP_TRANSPOSE,&flg);
135: if (flg) svd->transmode = SVD_TRANSPOSE_EXPLICIT;
136: else svd->transmode = SVD_TRANSPOSE_IMPLICIT;
137: }
138:
139: /* build transpose matrix */
140: MatDestroy(&svd->A);
141: MatDestroy(&svd->AT);
142: MatGetSize(svd->OP,&M,&N);
143: PetscObjectReference((PetscObject)svd->OP);
144: switch (svd->transmode) {
145: case SVD_TRANSPOSE_EXPLICIT:
146: if (M>=N) {
147: svd->A = svd->OP;
148: MatTranspose(svd->OP,MAT_INITIAL_MATRIX,&svd->AT);
149: MatConjugate(svd->AT);
150: } else {
151: MatTranspose(svd->OP,MAT_INITIAL_MATRIX,&svd->A);
152: MatConjugate(svd->A);
153: svd->AT = svd->OP;
154: }
155: break;
156: case SVD_TRANSPOSE_IMPLICIT:
157: if (M>=N) {
158: svd->A = svd->OP;
159: svd->AT = PETSC_NULL;
160: } else {
161: svd->A = PETSC_NULL;
162: svd->AT = svd->OP;
163: }
164: break;
165: default:
166: SETERRQ(((PetscObject)svd)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Invalid transpose mode");
167: }
169: VecDestroy(&svd->tr);
170: VecDestroy(&svd->tl);
171: if (svd->A) {
172: SlepcMatGetVecsTemplate(svd->A,&svd->tr,&svd->tl);
173: } else {
174: SlepcMatGetVecsTemplate(svd->AT,&svd->tl,&svd->tr);
175: }
177: /* call specific solver setup */
178: (*svd->ops->setup)(svd);
180: /* set tolerance if not yet set */
181: if (svd->tol==PETSC_DEFAULT) svd->tol = SLEPC_DEFAULT_TOL;
183: if (svd->ncv > M || svd->ncv > N) SETERRQ(((PetscObject)svd)->comm,PETSC_ERR_ARG_OUTOFRANGE,"ncv bigger than matrix dimensions");
184: if (svd->nsv > svd->ncv) SETERRQ(((PetscObject)svd)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nsv bigger than ncv");
186: if (svd->ncv != svd->n) {
187: /* free memory for previous solution */
188: if (svd->n) {
189: PetscFree(svd->sigma);
190: PetscFree(svd->perm);
191: PetscFree(svd->errest);
192: VecDestroyVecs(svd->n,&svd->V);
193: }
194: /* allocate memory for next solution */
195: PetscMalloc(svd->ncv*sizeof(PetscReal),&svd->sigma);
196: PetscMalloc(svd->ncv*sizeof(PetscInt),&svd->perm);
197: PetscMalloc(svd->ncv*sizeof(PetscReal),&svd->errest);
198: PetscLogObjectMemory(svd,PetscMax(0,svd->ncv-svd->n)*(2*sizeof(PetscReal)+sizeof(PetscInt)));
199: VecDuplicateVecs(svd->tr,svd->ncv,&svd->V);
200: PetscLogObjectParents(svd,svd->ncv,svd->V);
201: svd->n = svd->ncv;
202: }
204: /* process initial vectors */
205: if (svd->nini<0) {
206: svd->nini = -svd->nini;
207: if (svd->nini>svd->ncv) SETERRQ(((PetscObject)svd)->comm,1,"The number of initial vectors is larger than ncv");
208: k = 0;
209: for (i=0;i<svd->nini;i++) {
210: VecCopy(svd->IS[i],svd->V[k]);
211: VecDestroy(&svd->IS[i]);
212: IPOrthogonalize(svd->ip,0,PETSC_NULL,k,PETSC_NULL,svd->V,svd->V[k],PETSC_NULL,&norm,&lindep);
213: if (norm==0.0 || lindep) { PetscInfo(svd,"Linearly dependent initial vector found, removing...\n"); }
214: else {
215: VecScale(svd->V[k],1.0/norm);
216: k++;
217: }
218: }
219: svd->nini = k;
220: PetscFree(svd->IS);
221: }
223: PetscLogEventEnd(SVD_SetUp,svd,0,0,0);
224: svd->setupcalled = 1;
225: return(0);
226: }
230: /*@
231: SVDSetInitialSpace - Specify a basis of vectors that constitute the initial
232: space, that is, the subspace from which the solver starts to iterate.
234: Collective on SVD and Vec
236: Input Parameter:
237: + svd - the singular value solver context
238: . n - number of vectors
239: - is - set of basis vectors of the initial space
241: Notes:
242: Some solvers start to iterate on a single vector (initial vector). In that case,
243: the other vectors are ignored.
245: These vectors do not persist from one SVDSolve() call to the other, so the
246: initial space should be set every time.
248: The vectors do not need to be mutually orthonormal, since they are explicitly
249: orthonormalized internally.
251: Common usage of this function is when the user can provide a rough approximation
252: of the wanted singular space. Then, convergence may be faster.
254: Level: intermediate
255: @*/
256: PetscErrorCode SVDSetInitialSpace(SVD svd,PetscInt n,Vec *is)
257: {
259: PetscInt i;
260:
264: if (n<0) SETERRQ(((PetscObject)svd)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument n cannot be negative");
266: /* free previous non-processed vectors */
267: if (svd->nini<0) {
268: for (i=0;i<-svd->nini;i++) {
269: VecDestroy(&svd->IS[i]);
270: }
271: PetscFree(svd->IS);
272: }
274: /* get references of passed vectors */
275: PetscMalloc(n*sizeof(Vec),&svd->IS);
276: for (i=0;i<n;i++) {
277: PetscObjectReference((PetscObject)is[i]);
278: svd->IS[i] = is[i];
279: }
281: svd->nini = -n;
282: svd->setupcalled = 0;
283: return(0);
284: }