conjgrad.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /**************************************************************************
  2. **
  3. ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
  4. **
  5. ** Meschach Library
  6. **
  7. ** This Meschach Library is provided "as is" without any express
  8. ** or implied warranty of any kind with respect to this software.
  9. ** In particular the authors shall not be liable for any direct,
  10. ** indirect, special, incidental or consequential damages arising
  11. ** in any way from use of the software.
  12. **
  13. ** Everyone is granted permission to copy, modify and redistribute this
  14. ** Meschach Library, provided:
  15. ** 1. All copies contain this copyright notice.
  16. ** 2. All modified copies shall carry a notice stating who
  17. ** made the last modification and the date of such modification.
  18. ** 3. No charge is made for this software or works derived from it.
  19. ** This clause shall not be construed as constraining other software
  20. ** distributed on the same medium as this software, nor is a
  21. ** distribution fee considered a charge.
  22. **
  23. ***************************************************************************/
  24. /*
  25. Conjugate gradient routines file
  26. Uses sparse matrix input & sparse Cholesky factorisation in pccg().
  27. All the following routines use routines to define a matrix
  28. rather than use any explicit representation
  29. (with the exeception of the pccg() pre-conditioner)
  30. The matrix A is defined by
  31. VEC *(*A)(void *params, VEC *x, VEC *y)
  32. where y = A.x on exit, and y is returned. The params argument is
  33. intended to make it easier to re-use & modify such routines.
  34. If we have a sparse matrix data structure
  35. SPMAT *A_mat;
  36. then these can be used by passing sp_mv_mlt as the function, and
  37. A_mat as the param.
  38. */
  39. #include <stdio.h>
  40. #include <math.h>
  41. #include "matrix.h"
  42. #include "sparse.h"
  43. static char rcsid[] = "$Id: conjgrad.c,v 1.4 1994/01/13 05:36:45 des Exp $";
  44. /* #define MAX_ITER 10000 */
  45. static int max_iter = 10000;
  46. int cg_num_iters;
  47. /* matrix-as-routine type definition */
  48. /* #ifdef ANSI_C */
  49. /* typedef VEC *(*MTX_FN)(void *params, VEC *x, VEC *out); */
  50. /* #else */
  51. typedef VEC *(*MTX_FN)();
  52. /* #endif */
  53. #ifdef ANSI_C
  54. VEC *spCHsolve(SPMAT *,VEC *,VEC *);
  55. #else
  56. VEC *spCHsolve();
  57. #endif
  58. /* cg_set_maxiter -- sets maximum number of iterations if numiter > 1
  59. -- just returns current max_iter otherwise
  60. -- returns old maximum */
  61. int cg_set_maxiter(numiter)
  62. int numiter;
  63. {
  64. int temp;
  65. if ( numiter < 2 )
  66. return max_iter;
  67. temp = max_iter;
  68. max_iter = numiter;
  69. return temp;
  70. }
  71. /* pccg -- solves A.x = b using pre-conditioner M
  72. (assumed factored a la spCHfctr())
  73. -- results are stored in x (if x != NULL), which is returned */
  74. VEC *pccg(A,A_params,M_inv,M_params,b,eps,x)
  75. MTX_FN A, M_inv;
  76. VEC *b, *x;
  77. double eps;
  78. void *A_params, *M_params;
  79. {
  80. VEC *r = VNULL, *p = VNULL, *q = VNULL, *z = VNULL;
  81. int k;
  82. Real alpha, beta, ip, old_ip, norm_b;
  83. if ( ! A || ! b )
  84. error(E_NULL,"pccg");
  85. if ( x == b )
  86. error(E_INSITU,"pccg");
  87. x = v_resize(x,b->dim);
  88. if ( eps <= 0.0 )
  89. eps = MACHEPS;
  90. r = v_get(b->dim);
  91. p = v_get(b->dim);
  92. q = v_get(b->dim);
  93. z = v_get(b->dim);
  94. norm_b = v_norm2(b);
  95. v_zero(x);
  96. r = v_copy(b,r);
  97. old_ip = 0.0;
  98. for ( k = 0; ; k++ )
  99. {
  100. if ( v_norm2(r) < eps*norm_b )
  101. break;
  102. if ( k > max_iter )
  103. error(E_ITER,"pccg");
  104. if ( M_inv )
  105. (*M_inv)(M_params,r,z);
  106. else
  107. v_copy(r,z); /* M == identity */
  108. ip = in_prod(z,r);
  109. if ( k ) /* if ( k > 0 ) ... */
  110. {
  111. beta = ip/old_ip;
  112. p = v_mltadd(z,p,beta,p);
  113. }
  114. else /* if ( k == 0 ) ... */
  115. {
  116. beta = 0.0;
  117. p = v_copy(z,p);
  118. old_ip = 0.0;
  119. }
  120. q = (*A)(A_params,p,q);
  121. alpha = ip/in_prod(p,q);
  122. x = v_mltadd(x,p,alpha,x);
  123. r = v_mltadd(r,q,-alpha,r);
  124. old_ip = ip;
  125. }
  126. cg_num_iters = k;
  127. V_FREE(p);
  128. V_FREE(q);
  129. V_FREE(r);
  130. V_FREE(z);
  131. return x;
  132. }
  133. /* sp_pccg -- a simple interface to pccg() which uses sparse matrix
  134. data structures
  135. -- assumes that LLT contains the Cholesky factorisation of the
  136. actual pre-conditioner */
  137. VEC *sp_pccg(A,LLT,b,eps,x)
  138. SPMAT *A, *LLT;
  139. VEC *b, *x;
  140. double eps;
  141. { return pccg(sp_mv_mlt,A,spCHsolve,LLT,b,eps,x); }
  142. /*
  143. Routines for performing the CGS (Conjugate Gradient Squared)
  144. algorithm of P. Sonneveld:
  145. "CGS, a fast Lanczos-type solver for nonsymmetric linear
  146. systems", SIAM J. Sci. & Stat. Comp. v. 10, pp. 36--52
  147. */
  148. /* cgs -- uses CGS to compute a solution x to A.x=b
  149. -- the matrix A is not passed explicitly, rather a routine
  150. A is passed where A(x,Ax,params) computes
  151. Ax = A.x
  152. -- the computed solution is passed */
  153. VEC *cgs(A,A_params,b,r0,tol,x)
  154. MTX_FN A;
  155. VEC *x, *b;
  156. VEC *r0; /* tilde r0 parameter -- should be random??? */
  157. double tol; /* error tolerance used */
  158. void *A_params;
  159. {
  160. VEC *p, *q, *r, *u, *v, *tmp1, *tmp2;
  161. Real alpha, beta, norm_b, rho, old_rho, sigma;
  162. int iter;
  163. if ( ! A || ! x || ! b || ! r0 )
  164. error(E_NULL,"cgs");
  165. if ( x->dim != b->dim || r0->dim != x->dim )
  166. error(E_SIZES,"cgs");
  167. if ( tol <= 0.0 )
  168. tol = MACHEPS;
  169. p = v_get(x->dim);
  170. q = v_get(x->dim);
  171. r = v_get(x->dim);
  172. u = v_get(x->dim);
  173. v = v_get(x->dim);
  174. tmp1 = v_get(x->dim);
  175. tmp2 = v_get(x->dim);
  176. norm_b = v_norm2(b);
  177. (*A)(A_params,x,tmp1);
  178. v_sub(b,tmp1,r);
  179. v_zero(p); v_zero(q);
  180. old_rho = 1.0;
  181. iter = 0;
  182. while ( v_norm2(r) > tol*norm_b )
  183. {
  184. if ( ++iter > max_iter ) break;
  185. /* error(E_ITER,"cgs"); */
  186. rho = in_prod(r0,r);
  187. if ( old_rho == 0.0 )
  188. error(E_SING,"cgs");
  189. beta = rho/old_rho;
  190. v_mltadd(r,q,beta,u);
  191. v_mltadd(q,p,beta,tmp1);
  192. v_mltadd(u,tmp1,beta,p);
  193. (*A)(A_params,p,v);
  194. sigma = in_prod(r0,v);
  195. if ( sigma == 0.0 )
  196. error(E_SING,"cgs");
  197. alpha = rho/sigma;
  198. v_mltadd(u,v,-alpha,q);
  199. v_add(u,q,tmp1);
  200. (*A)(A_params,tmp1,tmp2);
  201. v_mltadd(r,tmp2,-alpha,r);
  202. v_mltadd(x,tmp1,alpha,x);
  203. old_rho = rho;
  204. }
  205. cg_num_iters = iter;
  206. V_FREE(p); V_FREE(q); V_FREE(r);
  207. V_FREE(u); V_FREE(v);
  208. V_FREE(tmp1); V_FREE(tmp2);
  209. return x;
  210. }
  211. /* sp_cgs -- simple interface for SPMAT data structures */
  212. VEC *sp_cgs(A,b,r0,tol,x)
  213. SPMAT *A;
  214. VEC *b, *r0, *x;
  215. double tol;
  216. { return cgs(sp_mv_mlt,A,b,r0,tol,x); }
  217. /*
  218. Routine for performing LSQR -- the least squares QR algorithm
  219. of Paige and Saunders:
  220. "LSQR: an algorithm for sparse linear equations and
  221. sparse least squares", ACM Trans. Math. Soft., v. 8
  222. pp. 43--71 (1982)
  223. */
  224. /* lsqr -- sparse CG-like least squares routine:
  225. -- finds min_x ||A.x-b||_2 using A defined through A & AT
  226. -- returns x (if x != NULL) */
  227. VEC *lsqr(A,AT,A_params,b,tol,x)
  228. MTX_FN A, AT; /* AT is A transposed */
  229. VEC *x, *b;
  230. double tol; /* error tolerance used */
  231. void *A_params;
  232. {
  233. VEC *u, *v, *w, *tmp;
  234. Real alpha, beta, norm_b, phi, phi_bar,
  235. rho, rho_bar, rho_max, theta;
  236. Real s, c; /* for Givens' rotations */
  237. int iter, m, n;
  238. if ( ! b || ! x )
  239. error(E_NULL,"lsqr");
  240. if ( tol <= 0.0 )
  241. tol = MACHEPS;
  242. m = b->dim; n = x->dim;
  243. u = v_get((unsigned int)m);
  244. v = v_get((unsigned int)n);
  245. w = v_get((unsigned int)n);
  246. tmp = v_get((unsigned int)n);
  247. norm_b = v_norm2(b);
  248. v_zero(x);
  249. beta = v_norm2(b);
  250. if ( beta == 0.0 )
  251. return x;
  252. sv_mlt(1.0/beta,b,u);
  253. tracecatch((*AT)(A_params,u,v),"lsqr");
  254. alpha = v_norm2(v);
  255. if ( alpha == 0.0 )
  256. return x;
  257. sv_mlt(1.0/alpha,v,v);
  258. v_copy(v,w);
  259. phi_bar = beta; rho_bar = alpha;
  260. rho_max = 1.0;
  261. iter = 0;
  262. do {
  263. if ( ++iter > max_iter )
  264. error(E_ITER,"lsqr");
  265. tmp = v_resize(tmp,m);
  266. tracecatch((*A) (A_params,v,tmp),"lsqr");
  267. v_mltadd(tmp,u,-alpha,u);
  268. beta = v_norm2(u); sv_mlt(1.0/beta,u,u);
  269. tmp = v_resize(tmp,n);
  270. tracecatch((*AT)(A_params,u,tmp),"lsqr");
  271. v_mltadd(tmp,v,-beta,v);
  272. alpha = v_norm2(v); sv_mlt(1.0/alpha,v,v);
  273. rho = sqrt(rho_bar*rho_bar+beta*beta);
  274. if ( rho > rho_max )
  275. rho_max = rho;
  276. c = rho_bar/rho;
  277. s = beta/rho;
  278. theta = s*alpha;
  279. rho_bar = -c*alpha;
  280. phi = c*phi_bar;
  281. phi_bar = s*phi_bar;
  282. /* update x & w */
  283. if ( rho == 0.0 )
  284. error(E_SING,"lsqr");
  285. v_mltadd(x,w,phi/rho,x);
  286. v_mltadd(v,w,-theta/rho,w);
  287. } while ( fabs(phi_bar*alpha*c) > tol*norm_b/rho_max );
  288. cg_num_iters = iter;
  289. V_FREE(tmp); V_FREE(u); V_FREE(v); V_FREE(w);
  290. return x;
  291. }
  292. /* sp_lsqr -- simple interface for SPMAT data structures */
  293. VEC *sp_lsqr(A,b,tol,x)
  294. SPMAT *A;
  295. VEC *b, *x;
  296. double tol;
  297. { return lsqr(sp_mv_mlt,sp_vm_mlt,A,b,tol,x); }