lanczos.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. File containing Lanczos type routines for finding eigenvalues
  26. of large, sparse, symmetic matrices
  27. */
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include "matrix.h"
  31. #include "sparse.h"
  32. static char rcsid[] = "$Id: lanczos.c,v 1.4 1994/01/13 05:28:24 des Exp $";
  33. #ifdef ANSI_C
  34. extern VEC *trieig(VEC *,VEC *,MAT *);
  35. #else
  36. extern VEC *trieig();
  37. #endif
  38. /* lanczos -- raw lanczos algorithm -- no re-orthogonalisation
  39. -- creates T matrix of size == m,
  40. but no larger than before beta_k == 0
  41. -- uses passed routine to do matrix-vector multiplies */
  42. void lanczos(A_fn,A_params,m,x0,a,b,beta2,Q)
  43. VEC *(*A_fn)(); /* VEC *(*A_fn)(void *A_params,VEC *in, VEC *out) */
  44. void *A_params;
  45. int m;
  46. VEC *x0, *a, *b;
  47. Real *beta2;
  48. MAT *Q;
  49. {
  50. int j;
  51. VEC *v, *w, *tmp;
  52. Real alpha, beta;
  53. if ( ! A_fn || ! x0 || ! a || ! b )
  54. error(E_NULL,"lanczos");
  55. if ( m <= 0 )
  56. error(E_BOUNDS,"lanczos");
  57. if ( Q && ( Q->m < x0->dim || Q->n < m ) )
  58. error(E_SIZES,"lanczos");
  59. a = v_resize(a,(unsigned int)m);
  60. b = v_resize(b,(unsigned int)(m-1));
  61. v = v_get(x0->dim);
  62. w = v_get(x0->dim);
  63. tmp = v_get(x0->dim);
  64. beta = 1.0;
  65. /* normalise x0 as w */
  66. sv_mlt(1.0/v_norm2(x0),x0,w);
  67. (*A_fn)(A_params,w,v);
  68. for ( j = 0; j < m; j++ )
  69. {
  70. /* store w in Q if Q not NULL */
  71. if ( Q )
  72. set_col(Q,j,w);
  73. alpha = in_prod(w,v);
  74. a->ve[j] = alpha;
  75. v_mltadd(v,w,-alpha,v);
  76. beta = v_norm2(v);
  77. if ( beta == 0.0 )
  78. {
  79. v_resize(a,(unsigned int)j+1);
  80. v_resize(b,(unsigned int)j);
  81. *beta2 = 0.0;
  82. if ( Q )
  83. Q = m_resize(Q,Q->m,j+1);
  84. return;
  85. }
  86. if ( j < m-1 )
  87. b->ve[j] = beta;
  88. v_copy(w,tmp);
  89. sv_mlt(1/beta,v,w);
  90. sv_mlt(-beta,tmp,v);
  91. (*A_fn)(A_params,w,tmp);
  92. v_add(v,tmp,v);
  93. }
  94. *beta2 = beta;
  95. V_FREE(v); V_FREE(w); V_FREE(tmp);
  96. }
  97. extern double frexp(), ldexp();
  98. /* product -- returns the product of a long list of numbers
  99. -- answer stored in mant (mantissa) and expt (exponent) */
  100. static double product(a,offset,expt)
  101. VEC *a;
  102. double offset;
  103. int *expt;
  104. {
  105. Real mant, tmp_fctr;
  106. int i, tmp_expt;
  107. if ( ! a )
  108. error(E_NULL,"product");
  109. mant = 1.0;
  110. *expt = 0;
  111. if ( offset == 0.0 )
  112. for ( i = 0; i < a->dim; i++ )
  113. {
  114. mant *= frexp(a->ve[i],&tmp_expt);
  115. *expt += tmp_expt;
  116. if ( ! (i % 10) )
  117. {
  118. mant = frexp(mant,&tmp_expt);
  119. *expt += tmp_expt;
  120. }
  121. }
  122. else
  123. for ( i = 0; i < a->dim; i++ )
  124. {
  125. tmp_fctr = a->ve[i] - offset;
  126. tmp_fctr += (tmp_fctr > 0.0 ) ? -MACHEPS*offset :
  127. MACHEPS*offset;
  128. mant *= frexp(tmp_fctr,&tmp_expt);
  129. *expt += tmp_expt;
  130. if ( ! (i % 10) )
  131. {
  132. mant = frexp(mant,&tmp_expt);
  133. *expt += tmp_expt;
  134. }
  135. }
  136. mant = frexp(mant,&tmp_expt);
  137. *expt += tmp_expt;
  138. return mant;
  139. }
  140. /* product2 -- returns the product of a long list of numbers
  141. -- answer stored in mant (mantissa) and expt (exponent) */
  142. static double product2(a,k,expt)
  143. VEC *a;
  144. int k; /* entry of a to leave out */
  145. int *expt;
  146. {
  147. Real mant, mu, tmp_fctr;
  148. int i, tmp_expt;
  149. if ( ! a )
  150. error(E_NULL,"product2");
  151. if ( k < 0 || k >= a->dim )
  152. error(E_BOUNDS,"product2");
  153. mant = 1.0;
  154. *expt = 0;
  155. mu = a->ve[k];
  156. for ( i = 0; i < a->dim; i++ )
  157. {
  158. if ( i == k )
  159. continue;
  160. tmp_fctr = a->ve[i] - mu;
  161. tmp_fctr += ( tmp_fctr > 0.0 ) ? -MACHEPS*mu : MACHEPS*mu;
  162. mant *= frexp(tmp_fctr,&tmp_expt);
  163. *expt += tmp_expt;
  164. if ( ! (i % 10) )
  165. {
  166. mant = frexp(mant,&tmp_expt);
  167. *expt += tmp_expt;
  168. }
  169. }
  170. mant = frexp(mant,&tmp_expt);
  171. *expt += tmp_expt;
  172. return mant;
  173. }
  174. /* dbl_cmp -- comparison function to pass to qsort() */
  175. static int dbl_cmp(x,y)
  176. Real *x, *y;
  177. {
  178. Real tmp;
  179. tmp = *x - *y;
  180. return (tmp > 0 ? 1 : tmp < 0 ? -1: 0);
  181. }
  182. /* lanczos2 -- lanczos + error estimate for every e-val
  183. -- uses Cullum & Willoughby approach, Sparse Matrix Proc. 1978
  184. -- returns multiple e-vals where multiple e-vals may not exist
  185. -- returns evals vector */
  186. VEC *lanczos2(A_fn,A_params,m,x0,evals,err_est)
  187. VEC *(*A_fn)();
  188. void *A_params;
  189. int m;
  190. VEC *x0; /* initial vector */
  191. VEC *evals; /* eigenvalue vector */
  192. VEC *err_est; /* error estimates of eigenvalues */
  193. {
  194. VEC *a;
  195. STATIC VEC *b=VNULL, *a2=VNULL, *b2=VNULL;
  196. Real beta, pb_mant, det_mant, det_mant1, det_mant2;
  197. int i, pb_expt, det_expt, det_expt1, det_expt2;
  198. if ( ! A_fn || ! x0 )
  199. error(E_NULL,"lanczos2");
  200. if ( m <= 0 )
  201. error(E_RANGE,"lanczos2");
  202. a = evals;
  203. a = v_resize(a,(unsigned int)m);
  204. b = v_resize(b,(unsigned int)(m-1));
  205. MEM_STAT_REG(b,TYPE_VEC);
  206. lanczos(A_fn,A_params,m,x0,a,b,&beta,MNULL);
  207. /* printf("# beta =%g\n",beta); */
  208. pb_mant = 0.0;
  209. if ( err_est )
  210. {
  211. pb_mant = product(b,(double)0.0,&pb_expt);
  212. /* printf("# pb_mant = %g, pb_expt = %d\n",pb_mant, pb_expt); */
  213. }
  214. /* printf("# diags =\n"); out_vec(a); */
  215. /* printf("# off diags =\n"); out_vec(b); */
  216. a2 = v_resize(a2,a->dim - 1);
  217. b2 = v_resize(b2,b->dim - 1);
  218. MEM_STAT_REG(a2,TYPE_VEC);
  219. MEM_STAT_REG(b2,TYPE_VEC);
  220. for ( i = 0; i < a2->dim - 1; i++ )
  221. {
  222. a2->ve[i] = a->ve[i+1];
  223. b2->ve[i] = b->ve[i+1];
  224. }
  225. a2->ve[a2->dim-1] = a->ve[a2->dim];
  226. trieig(a,b,MNULL);
  227. /* sort evals as a courtesy */
  228. qsort((void *)(a->ve),(int)(a->dim),sizeof(Real),(int (*)())dbl_cmp);
  229. /* error estimates */
  230. if ( err_est )
  231. {
  232. err_est = v_resize(err_est,(unsigned int)m);
  233. trieig(a2,b2,MNULL);
  234. /* printf("# a =\n"); out_vec(a); */
  235. /* printf("# a2 =\n"); out_vec(a2); */
  236. for ( i = 0; i < a->dim; i++ )
  237. {
  238. det_mant1 = product2(a,i,&det_expt1);
  239. det_mant2 = product(a2,(double)a->ve[i],&det_expt2);
  240. /* printf("# det_mant1=%g, det_expt1=%d\n",
  241. det_mant1,det_expt1); */
  242. /* printf("# det_mant2=%g, det_expt2=%d\n",
  243. det_mant2,det_expt2); */
  244. if ( det_mant1 == 0.0 )
  245. { /* multiple e-val of T */
  246. err_est->ve[i] = 0.0;
  247. continue;
  248. }
  249. else if ( det_mant2 == 0.0 )
  250. {
  251. err_est->ve[i] = HUGE_VAL;
  252. continue;
  253. }
  254. if ( (det_expt1 + det_expt2) % 2 )
  255. /* if odd... */
  256. det_mant = sqrt(2.0*fabs(det_mant1*det_mant2));
  257. else /* if even... */
  258. det_mant = sqrt(fabs(det_mant1*det_mant2));
  259. det_expt = (det_expt1+det_expt2)/2;
  260. err_est->ve[i] = fabs(beta*
  261. ldexp(pb_mant/det_mant,pb_expt-det_expt));
  262. }
  263. }
  264. #ifdef THREADSAFE
  265. V_FREE(b); V_FREE(a2); V_FREE(b2);
  266. #endif
  267. return a;
  268. }
  269. /* sp_lanczos -- version that uses sparse matrix data structure */
  270. void sp_lanczos(A,m,x0,a,b,beta2,Q)
  271. SPMAT *A;
  272. int m;
  273. VEC *x0, *a, *b;
  274. Real *beta2;
  275. MAT *Q;
  276. { lanczos(sp_mv_mlt,A,m,x0,a,b,beta2,Q); }
  277. /* sp_lanczos2 -- version of lanczos2() that uses sparse matrix data
  278. structure */
  279. VEC *sp_lanczos2(A,m,x0,evals,err_est)
  280. SPMAT *A;
  281. int m;
  282. VEC *x0; /* initial vector */
  283. VEC *evals; /* eigenvalue vector */
  284. VEC *err_est; /* error estimates of eigenvalues */
  285. { return lanczos2(sp_mv_mlt,A,m,x0,evals,err_est); }