bkpfacto.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. Matrix factorisation routines to work with the other matrix files.
  26. */
  27. static char rcsid[] = "$Id: bkpfacto.c,v 1.7 1994/01/13 05:45:50 des Exp $";
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include "matrix.h"
  31. #include "matrix2.h"
  32. #define btos(x) ((x) ? "TRUE" : "FALSE")
  33. /* Most matrix factorisation routines are in-situ unless otherwise specified */
  34. #define alpha 0.6403882032022076 /* = (1+sqrt(17))/8 */
  35. /* sqr -- returns square of x -- utility function */
  36. double sqr(x)
  37. double x;
  38. { return x*x; }
  39. /* interchange -- a row/column swap routine */
  40. static void interchange(A,i,j)
  41. MAT *A; /* assumed != NULL & also SQUARE */
  42. int i, j; /* assumed in range */
  43. {
  44. Real **A_me, tmp;
  45. int k, n;
  46. A_me = A->me; n = A->n;
  47. if ( i == j )
  48. return;
  49. if ( i > j )
  50. { k = i; i = j; j = k; }
  51. for ( k = 0; k < i; k++ )
  52. {
  53. /* tmp = A_me[k][i]; */
  54. tmp = m_entry(A,k,i);
  55. /* A_me[k][i] = A_me[k][j]; */
  56. m_set_val(A,k,i,m_entry(A,k,j));
  57. /* A_me[k][j] = tmp; */
  58. m_set_val(A,k,j,tmp);
  59. }
  60. for ( k = j+1; k < n; k++ )
  61. {
  62. /* tmp = A_me[j][k]; */
  63. tmp = m_entry(A,j,k);
  64. /* A_me[j][k] = A_me[i][k]; */
  65. m_set_val(A,j,k,m_entry(A,i,k));
  66. /* A_me[i][k] = tmp; */
  67. m_set_val(A,i,k,tmp);
  68. }
  69. for ( k = i+1; k < j; k++ )
  70. {
  71. /* tmp = A_me[k][j]; */
  72. tmp = m_entry(A,k,j);
  73. /* A_me[k][j] = A_me[i][k]; */
  74. m_set_val(A,k,j,m_entry(A,i,k));
  75. /* A_me[i][k] = tmp; */
  76. m_set_val(A,i,k,tmp);
  77. }
  78. /* tmp = A_me[i][i]; */
  79. tmp = m_entry(A,i,i);
  80. /* A_me[i][i] = A_me[j][j]; */
  81. m_set_val(A,i,i,m_entry(A,j,j));
  82. /* A_me[j][j] = tmp; */
  83. m_set_val(A,j,j,tmp);
  84. }
  85. /* BKPfactor -- Bunch-Kaufman-Parlett factorisation of A in-situ
  86. -- A is factored into the form P'AP = MDM' where
  87. P is a permutation matrix, M lower triangular and D is block
  88. diagonal with blocks of size 1 or 2
  89. -- P is stored in pivot; blocks[i]==i iff D[i][i] is a block */
  90. #ifndef ANSI_C
  91. MAT *BKPfactor(A,pivot,blocks)
  92. MAT *A;
  93. PERM *pivot, *blocks;
  94. #else
  95. MAT *BKPfactor(MAT *A, PERM *pivot, PERM *blocks)
  96. #endif
  97. {
  98. int i, j, k, n, onebyone, r;
  99. Real **A_me, aii, aip1, aip1i, lambda, sigma, tmp;
  100. Real det, s, t;
  101. if ( ! A || ! pivot || ! blocks )
  102. error(E_NULL,"BKPfactor");
  103. if ( A->m != A->n )
  104. error(E_SQUARE,"BKPfactor");
  105. if ( A->m != pivot->size || pivot->size != blocks->size )
  106. error(E_SIZES,"BKPfactor");
  107. n = A->n;
  108. A_me = A->me;
  109. px_ident(pivot); px_ident(blocks);
  110. for ( i = 0; i < n; i = onebyone ? i+1 : i+2 )
  111. {
  112. /* printf("# Stage: %d\n",i); */
  113. aii = fabs(m_entry(A,i,i));
  114. lambda = 0.0; r = (i+1 < n) ? i+1 : i;
  115. for ( k = i+1; k < n; k++ )
  116. {
  117. tmp = fabs(m_entry(A,i,k));
  118. if ( tmp >= lambda )
  119. {
  120. lambda = tmp;
  121. r = k;
  122. }
  123. }
  124. /* printf("# lambda = %g, r = %d\n", lambda, r); */
  125. /* printf("# |A[%d][%d]| = %g\n",r,r,fabs(m_entry(A,r,r))); */
  126. /* determine if 1x1 or 2x2 block, and do pivoting if needed */
  127. if ( aii >= alpha*lambda )
  128. {
  129. onebyone = TRUE;
  130. goto dopivot;
  131. }
  132. /* compute sigma */
  133. sigma = 0.0;
  134. for ( k = i; k < n; k++ )
  135. {
  136. if ( k == r )
  137. continue;
  138. tmp = ( k > r ) ? fabs(m_entry(A,r,k)) :
  139. fabs(m_entry(A,k,r));
  140. if ( tmp > sigma )
  141. sigma = tmp;
  142. }
  143. if ( aii*sigma >= alpha*sqr(lambda) )
  144. onebyone = TRUE;
  145. else if ( fabs(m_entry(A,r,r)) >= alpha*sigma )
  146. {
  147. /* printf("# Swapping rows/cols %d and %d\n",i,r); */
  148. interchange(A,i,r);
  149. px_transp(pivot,i,r);
  150. onebyone = TRUE;
  151. }
  152. else
  153. {
  154. /* printf("# Swapping rows/cols %d and %d\n",i+1,r); */
  155. interchange(A,i+1,r);
  156. px_transp(pivot,i+1,r);
  157. px_transp(blocks,i,i+1);
  158. onebyone = FALSE;
  159. }
  160. /* printf("onebyone = %s\n",btos(onebyone)); */
  161. /* printf("# Matrix so far (@checkpoint A) =\n"); */
  162. /* m_output(A); */
  163. /* printf("# pivot =\n"); px_output(pivot); */
  164. /* printf("# blocks =\n"); px_output(blocks); */
  165. dopivot:
  166. if ( onebyone )
  167. { /* do one by one block */
  168. if ( m_entry(A,i,i) != 0.0 )
  169. {
  170. aii = m_entry(A,i,i);
  171. for ( j = i+1; j < n; j++ )
  172. {
  173. tmp = m_entry(A,i,j)/aii;
  174. for ( k = j; k < n; k++ )
  175. m_sub_val(A,j,k,tmp*m_entry(A,i,k));
  176. m_set_val(A,i,j,tmp);
  177. }
  178. }
  179. }
  180. else /* onebyone == FALSE */
  181. { /* do two by two block */
  182. det = m_entry(A,i,i)*m_entry(A,i+1,i+1)-sqr(m_entry(A,i,i+1));
  183. /* Must have det < 0 */
  184. /* printf("# det = %g\n",det); */
  185. aip1i = m_entry(A,i,i+1)/det;
  186. aii = m_entry(A,i,i)/det;
  187. aip1 = m_entry(A,i+1,i+1)/det;
  188. for ( j = i+2; j < n; j++ )
  189. {
  190. s = - aip1i*m_entry(A,i+1,j) + aip1*m_entry(A,i,j);
  191. t = - aip1i*m_entry(A,i,j) + aii*m_entry(A,i+1,j);
  192. for ( k = j; k < n; k++ )
  193. m_sub_val(A,j,k,m_entry(A,i,k)*s + m_entry(A,i+1,k)*t);
  194. m_set_val(A,i,j,s);
  195. m_set_val(A,i+1,j,t);
  196. }
  197. }
  198. /* printf("# Matrix so far (@checkpoint B) =\n"); */
  199. /* m_output(A); */
  200. /* printf("# pivot =\n"); px_output(pivot); */
  201. /* printf("# blocks =\n"); px_output(blocks); */
  202. }
  203. /* set lower triangular half */
  204. for ( i = 0; i < A->m; i++ )
  205. for ( j = 0; j < i; j++ )
  206. m_set_val(A,i,j,m_entry(A,j,i));
  207. return A;
  208. }
  209. /* BKPsolve -- solves A.x = b where A has been factored a la BKPfactor()
  210. -- returns x, which is created if NULL */
  211. #ifndef ANSI_C
  212. VEC *BKPsolve(A,pivot,block,b,x)
  213. MAT *A;
  214. PERM *pivot, *block;
  215. VEC *b, *x;
  216. #else
  217. VEC *BKPsolve(const MAT *A, PERM *pivot, const PERM *block,
  218. const VEC *b, VEC *x)
  219. #endif
  220. {
  221. STATIC VEC *tmp=VNULL; /* dummy storage needed */
  222. int i, j, n, onebyone;
  223. Real **A_me, a11, a12, a22, b1, b2, det, sum, *tmp_ve, tmp_diag;
  224. if ( ! A || ! pivot || ! block || ! b )
  225. error(E_NULL,"BKPsolve");
  226. if ( A->m != A->n )
  227. error(E_SQUARE,"BKPsolve");
  228. n = A->n;
  229. if ( b->dim != n || pivot->size != n || block->size != n )
  230. error(E_SIZES,"BKPsolve");
  231. x = v_resize(x,n);
  232. tmp = v_resize(tmp,n);
  233. MEM_STAT_REG(tmp,TYPE_VEC);
  234. A_me = A->me; tmp_ve = tmp->ve;
  235. px_vec(pivot,b,tmp);
  236. /* solve for lower triangular part */
  237. for ( i = 0; i < n; i++ )
  238. {
  239. sum = v_entry(tmp,i);
  240. if ( block->pe[i] < i )
  241. for ( j = 0; j < i-1; j++ )
  242. sum -= m_entry(A,i,j)*v_entry(tmp,j);
  243. else
  244. for ( j = 0; j < i; j++ )
  245. sum -= m_entry(A,i,j)*v_entry(tmp,j);
  246. v_set_val(tmp,i,sum);
  247. }
  248. /* printf("# BKPsolve: solving L part: tmp =\n"); v_output(tmp); */
  249. /* solve for diagonal part */
  250. for ( i = 0; i < n; i = onebyone ? i+1 : i+2 )
  251. {
  252. onebyone = ( block->pe[i] == i );
  253. if ( onebyone )
  254. {
  255. tmp_diag = m_entry(A,i,i);
  256. if ( tmp_diag == 0.0 )
  257. error(E_SING,"BKPsolve");
  258. /* tmp_ve[i] /= tmp_diag; */
  259. v_set_val(tmp,i,v_entry(tmp,i) / tmp_diag);
  260. }
  261. else
  262. {
  263. a11 = m_entry(A,i,i);
  264. a22 = m_entry(A,i+1,i+1);
  265. a12 = m_entry(A,i+1,i);
  266. b1 = v_entry(tmp,i); b2 = v_entry(tmp,i+1);
  267. det = a11*a22-a12*a12; /* < 0 : see BKPfactor() */
  268. if ( det == 0.0 )
  269. error(E_SING,"BKPsolve");
  270. det = 1/det;
  271. v_set_val(tmp,i,det*(a22*b1-a12*b2));
  272. v_set_val(tmp,i+1,det*(a11*b2-a12*b1));
  273. }
  274. }
  275. /* printf("# BKPsolve: solving D part: tmp =\n"); v_output(tmp); */
  276. /* solve for transpose of lower traingular part */
  277. for ( i = n-1; i >= 0; i-- )
  278. { /* use symmetry of factored form to get stride 1 */
  279. sum = v_entry(tmp,i);
  280. if ( block->pe[i] > i )
  281. for ( j = i+2; j < n; j++ )
  282. sum -= m_entry(A,i,j)*v_entry(tmp,j);
  283. else
  284. for ( j = i+1; j < n; j++ )
  285. sum -= m_entry(A,i,j)*v_entry(tmp,j);
  286. v_set_val(tmp,i,sum);
  287. }
  288. /* printf("# BKPsolve: solving L^T part: tmp =\n");v_output(tmp); */
  289. /* and do final permutation */
  290. x = pxinv_vec(pivot,tmp,x);
  291. #ifdef THREADSAFE
  292. V_FREE(tmp);
  293. #endif
  294. return x;
  295. }