Actual source code: cgls.c
petsc-3.14.3 2021-01-09
1: /*
2: This file implements CGLS, the Conjugate Gradient method for Least-Squares problems.
3: */
4: #include <petsc/private/kspimpl.h>
6: typedef struct {
7: PetscInt nwork_n,nwork_m;
8: Vec *vwork_m; /* work vectors of length m, where the system is size m x n */
9: Vec *vwork_n; /* work vectors of length n */
10: } KSP_CGLS;
12: static PetscErrorCode KSPSetUp_CGLS(KSP ksp)
13: {
15: KSP_CGLS *cgls = (KSP_CGLS*)ksp->data;
18: cgls->nwork_m = 2;
19: if (cgls->vwork_m) {
20: VecDestroyVecs(cgls->nwork_m,&cgls->vwork_m);
21: }
23: cgls->nwork_n = 2;
24: if (cgls->vwork_n) {
25: VecDestroyVecs(cgls->nwork_n,&cgls->vwork_n);
26: }
27: KSPCreateVecs(ksp,cgls->nwork_n,&cgls->vwork_n,cgls->nwork_m,&cgls->vwork_m);
28: return(0);
29: }
31: static PetscErrorCode KSPSolve_CGLS(KSP ksp)
32: {
34: KSP_CGLS *cgls = (KSP_CGLS*)ksp->data;
35: Mat A;
36: Vec x,b,r,p,q,ss;
37: PetscScalar beta;
38: PetscReal alpha,gamma,oldgamma;
41: KSPGetOperators(ksp,&A,NULL); /* Matrix of the system */
43: /* vectors of length n, where system size is mxn */
44: x = ksp->vec_sol; /* Solution vector */
45: p = cgls->vwork_n[0];
46: ss = cgls->vwork_n[1];
48: /* vectors of length m, where system size is mxn */
49: b = ksp->vec_rhs; /* Right-hand side vector */
50: r = cgls->vwork_m[0];
51: q = cgls->vwork_m[1];
53: /* Minimization with the CGLS method */
54: ksp->its = 0;
55: ksp->rnorm = 0;
56: MatMult(A,x,r);
57: VecAYPX(r,-1,b); /* r_0 = b - A * x_0 */
58: MatMultTranspose(A,r,p); /* p_0 = A^T * r_0 */
59: VecCopy(p,ss); /* s_0 = p_0 */
60: VecNorm(ss,NORM_2,&gamma);
61: KSPCheckNorm(ksp,gamma);
62: if (ksp->normtype != KSP_NORM_NONE) ksp->rnorm = gamma;
63: (*ksp->converged)(ksp,ksp->its,ksp->rnorm,&ksp->reason,ksp->cnvP);
64: if (ksp->reason) return(0);
65: gamma = gamma*gamma; /* gamma = norm2(s)^2 */
67: do {
68: MatMult(A,p,q); /* q = A * p */
69: VecNorm(q,NORM_2,&alpha);
70: KSPCheckNorm(ksp,alpha);
71: alpha = alpha*alpha; /* alpha = norm2(q)^2 */
72: alpha = gamma / alpha; /* alpha = gamma / alpha */
73: VecAXPY(x,alpha,p); /* x += alpha * p */
74: VecAXPY(r,-alpha,q); /* r -= alpha * q */
75: MatMultTranspose(A,r,ss); /* ss = A^T * r */
76: oldgamma = gamma; /* oldgamma = gamma */
77: VecNorm(ss,NORM_2,&gamma);
78: KSPCheckNorm(ksp,gamma);
79: ksp->its++;
80: if (ksp->normtype != KSP_NORM_NONE) ksp->rnorm = gamma;
81: KSPMonitor(ksp,ksp->its,ksp->rnorm);
82: (*ksp->converged)(ksp,ksp->its,ksp->rnorm,&ksp->reason,ksp->cnvP);
83: if (ksp->reason) return(0);
84: gamma = gamma*gamma; /* gamma = norm2(s)^2 */
85: beta = gamma/oldgamma; /* beta = gamma / oldgamma */
86: VecAYPX(p,beta,ss); /* p = s + beta * p */
87: } while (ksp->its<ksp->max_it);
89: if (ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
90: return(0);
91: }
93: static PetscErrorCode KSPDestroy_CGLS(KSP ksp)
94: {
95: KSP_CGLS *cgls = (KSP_CGLS*)ksp->data;
99: /* Free work vectors */
100: if (cgls->vwork_n) {
101: VecDestroyVecs(cgls->nwork_n,&cgls->vwork_n);
102: }
103: if (cgls->vwork_m) {
104: VecDestroyVecs(cgls->nwork_m,&cgls->vwork_m);
105: }
106: PetscFree(ksp->data);
107: return(0);
108: }
110: /*MC
111: KSPCGLS - Conjugate Gradient method for Least-Squares problems
113: Level: beginner
115: Supports non-square (rectangular) matrices.
117: Notes:
118: This does not use the preconditioner, so one should probably use KSPLSQR instead.
120: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP,
121: KSPCGSetType(), KSPCGUseSingleReduction(), KSPPIPECG, KSPGROPPCG
123: M*/
124: PETSC_EXTERN PetscErrorCode KSPCreate_CGLS(KSP ksp)
125: {
127: KSP_CGLS *cgls;
130: PetscNewLog(ksp,&cgls);
131: ksp->data = (void*)cgls;
132: KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,3);
133: KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,1);
134: ksp->ops->setup = KSPSetUp_CGLS;
135: ksp->ops->solve = KSPSolve_CGLS;
136: ksp->ops->destroy = KSPDestroy_CGLS;
137: ksp->ops->buildsolution = KSPBuildSolutionDefault;
138: ksp->ops->buildresidual = KSPBuildResidualDefault;
139: ksp->ops->setfromoptions = NULL;
140: ksp->ops->view = NULL;
141: #if defined(PETSC_USE_COMPLEX)
142: SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"This is not supported for complex numbers");
143: #endif
144: return(0);
145: }