splufctr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /**************************************************************************
  2. **
  3. ** Copyright (C) 1993 David E. Stewart & 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. Sparse LU factorisation
  26. See also: sparse.[ch] etc for details about sparse matrices
  27. */
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include "sparse2.h"
  31. /* Macro for speedup */
  32. /* #define sprow_idx2(r,c,hint) \
  33. ( ( (hint) >= 0 && (r)->elt[hint].col == (c)) ? hint : sprow_idx((r),(c)) ) */
  34. /* spLUfactor -- sparse LU factorisation with pivoting
  35. -- uses partial pivoting and Markowitz criterion
  36. |a[p][k]| >= alpha * max_i |a[i][k]|
  37. -- creates fill-in as needed
  38. -- in situ factorisation */
  39. #ifndef ANSI_C
  40. SPMAT *spLUfactor(A,px,alpha)
  41. SPMAT *A;
  42. PERM *px;
  43. double alpha;
  44. #else
  45. SPMAT *spLUfactor(SPMAT *A, PERM *px, double alpha)
  46. #endif
  47. {
  48. int i, best_i, k, idx, len, best_len, m, n;
  49. SPROW *r, *r_piv, tmp_row;
  50. STATIC SPROW *merge = (SPROW *)NULL;
  51. Real max_val, tmp;
  52. STATIC VEC *col_vals=VNULL;
  53. if ( ! A || ! px )
  54. error(E_NULL,"spLUfctr");
  55. if ( alpha <= 0.0 || alpha > 1.0 )
  56. error(E_RANGE,"alpha in spLUfctr");
  57. if ( px->size <= A->m )
  58. px = px_resize(px,A->m);
  59. px_ident(px);
  60. col_vals = v_resize(col_vals,A->m);
  61. MEM_STAT_REG(col_vals,TYPE_VEC);
  62. m = A->m; n = A->n;
  63. if ( ! A->flag_col )
  64. sp_col_access(A);
  65. if ( ! A->flag_diag )
  66. sp_diag_access(A);
  67. A->flag_col = A->flag_diag = FALSE;
  68. if ( ! merge ) {
  69. merge = sprow_get(20);
  70. MEM_STAT_REG(merge,TYPE_SPROW);
  71. }
  72. for ( k = 0; k < n; k++ )
  73. {
  74. /* find pivot row/element for partial pivoting */
  75. /* get first row with a non-zero entry in the k-th column */
  76. max_val = 0.0;
  77. for ( i = k; i < m; i++ )
  78. {
  79. r = &(A->row[i]);
  80. idx = sprow_idx(r,k);
  81. if ( idx < 0 )
  82. tmp = 0.0;
  83. else
  84. tmp = r->elt[idx].val;
  85. if ( fabs(tmp) > max_val )
  86. max_val = fabs(tmp);
  87. col_vals->ve[i] = tmp;
  88. }
  89. if ( max_val == 0.0 )
  90. continue;
  91. best_len = n+1; /* only if no possibilities */
  92. best_i = -1;
  93. for ( i = k; i < m; i++ )
  94. {
  95. tmp = fabs(col_vals->ve[i]);
  96. if ( tmp == 0.0 )
  97. continue;
  98. if ( tmp >= alpha*max_val )
  99. {
  100. r = &(A->row[i]);
  101. idx = sprow_idx(r,k);
  102. len = (r->len) - idx;
  103. if ( len < best_len )
  104. {
  105. best_len = len;
  106. best_i = i;
  107. }
  108. }
  109. }
  110. /* swap row #best_i with row #k */
  111. MEM_COPY(&(A->row[best_i]),&tmp_row,sizeof(SPROW));
  112. MEM_COPY(&(A->row[k]),&(A->row[best_i]),sizeof(SPROW));
  113. MEM_COPY(&tmp_row,&(A->row[k]),sizeof(SPROW));
  114. /* swap col_vals entries */
  115. tmp = col_vals->ve[best_i];
  116. col_vals->ve[best_i] = col_vals->ve[k];
  117. col_vals->ve[k] = tmp;
  118. px_transp(px,k,best_i);
  119. r_piv = &(A->row[k]);
  120. for ( i = k+1; i < n; i++ )
  121. {
  122. /* compute and set multiplier */
  123. tmp = col_vals->ve[i]/col_vals->ve[k];
  124. if ( tmp != 0.0 )
  125. sp_set_val(A,i,k,tmp);
  126. else
  127. continue;
  128. /* perform row operations */
  129. merge->len = 0;
  130. r = &(A->row[i]);
  131. sprow_mltadd(r,r_piv,-tmp,k+1,merge,TYPE_SPROW);
  132. idx = sprow_idx(r,k+1);
  133. if ( idx < 0 )
  134. idx = -(idx+2);
  135. /* see if r needs expanding */
  136. if ( r->maxlen < idx + merge->len )
  137. sprow_xpd(r,idx+merge->len,TYPE_SPMAT);
  138. r->len = idx+merge->len;
  139. MEM_COPY((char *)(merge->elt),(char *)&(r->elt[idx]),
  140. merge->len*sizeof(row_elt));
  141. }
  142. }
  143. #ifdef THREADSAFE
  144. sprow_free(merge); V_FREE(col_vals);
  145. #endif
  146. return A;
  147. }
  148. /* spLUsolve -- solve A.x = b using factored matrix A from spLUfactor()
  149. -- returns x
  150. -- may not be in-situ */
  151. #ifndef ANSI_C
  152. VEC *spLUsolve(A,pivot,b,x)
  153. SPMAT *A;
  154. PERM *pivot;
  155. VEC *b, *x;
  156. #else
  157. VEC *spLUsolve(const SPMAT *A, PERM *pivot, const VEC *b, VEC *x)
  158. #endif
  159. {
  160. int i, idx, len, lim;
  161. Real sum, *x_ve;
  162. SPROW *r;
  163. row_elt *elt;
  164. if ( ! A || ! b )
  165. error(E_NULL,"spLUsolve");
  166. if ( (pivot != PNULL && A->m != pivot->size) || A->m != b->dim )
  167. error(E_SIZES,"spLUsolve");
  168. if ( ! x || x->dim != A->n )
  169. x = v_resize(x,A->n);
  170. if ( pivot != PNULL )
  171. x = px_vec(pivot,b,x);
  172. else
  173. x = v_copy(b,x);
  174. x_ve = x->ve;
  175. lim = min(A->m,A->n);
  176. for ( i = 0; i < lim; i++ )
  177. {
  178. sum = x_ve[i];
  179. r = &(A->row[i]);
  180. len = r->len;
  181. elt = r->elt;
  182. for ( idx = 0; idx < len && elt->col < i; idx++, elt++ )
  183. sum -= elt->val*x_ve[elt->col];
  184. x_ve[i] = sum;
  185. }
  186. for ( i = lim-1; i >= 0; i-- )
  187. {
  188. sum = x_ve[i];
  189. r = &(A->row[i]);
  190. len = r->len;
  191. elt = &(r->elt[len-1]);
  192. for ( idx = len-1; idx >= 0 && elt->col > i; idx--, elt-- )
  193. sum -= elt->val*x_ve[elt->col];
  194. if ( idx < 0 || elt->col != i || elt->val == 0.0 )
  195. error(E_SING,"spLUsolve");
  196. x_ve[i] = sum/elt->val;
  197. }
  198. return x;
  199. }
  200. /* spLUTsolve -- solve A.x = b using factored matrix A from spLUfactor()
  201. -- returns x
  202. -- may not be in-situ */
  203. #ifndef ANSI_C
  204. VEC *spLUTsolve(A,pivot,b,x)
  205. SPMAT *A;
  206. PERM *pivot;
  207. VEC *b, *x;
  208. #else
  209. VEC *spLUTsolve(SPMAT *A, PERM *pivot, const VEC *b, VEC *x)
  210. #endif
  211. {
  212. int i, idx, lim, rownum;
  213. Real sum, *tmp_ve;
  214. /* SPROW *r; */
  215. row_elt *elt;
  216. STATIC VEC *tmp=VNULL;
  217. if ( ! A || ! b )
  218. error(E_NULL,"spLUTsolve");
  219. if ( (pivot != PNULL && A->m != pivot->size) || A->m != b->dim )
  220. error(E_SIZES,"spLUTsolve");
  221. tmp = v_copy(b,tmp);
  222. MEM_STAT_REG(tmp,TYPE_VEC);
  223. if ( ! A->flag_col )
  224. sp_col_access(A);
  225. if ( ! A->flag_diag )
  226. sp_diag_access(A);
  227. lim = min(A->m,A->n);
  228. tmp_ve = tmp->ve;
  229. /* solve U^T.tmp = b */
  230. for ( i = 0; i < lim; i++ )
  231. {
  232. sum = tmp_ve[i];
  233. rownum = A->start_row[i];
  234. idx = A->start_idx[i];
  235. if ( rownum < 0 || idx < 0 )
  236. error(E_SING,"spLUTsolve");
  237. while ( rownum < i && rownum >= 0 && idx >= 0 )
  238. {
  239. elt = &(A->row[rownum].elt[idx]);
  240. sum -= elt->val*tmp_ve[rownum];
  241. rownum = elt->nxt_row;
  242. idx = elt->nxt_idx;
  243. }
  244. if ( rownum != i )
  245. error(E_SING,"spLUTsolve");
  246. elt = &(A->row[rownum].elt[idx]);
  247. if ( elt->val == 0.0 )
  248. error(E_SING,"spLUTsolve");
  249. tmp_ve[i] = sum/elt->val;
  250. }
  251. /* now solve L^T.tmp = (old) tmp */
  252. for ( i = lim-1; i >= 0; i-- )
  253. {
  254. sum = tmp_ve[i];
  255. rownum = i;
  256. idx = A->row[rownum].diag;
  257. if ( idx < 0 )
  258. error(E_NULL,"spLUTsolve");
  259. elt = &(A->row[rownum].elt[idx]);
  260. rownum = elt->nxt_row;
  261. idx = elt->nxt_idx;
  262. while ( rownum < lim && rownum >= 0 && idx >= 0 )
  263. {
  264. elt = &(A->row[rownum].elt[idx]);
  265. sum -= elt->val*tmp_ve[rownum];
  266. rownum = elt->nxt_row;
  267. idx = elt->nxt_idx;
  268. }
  269. tmp_ve[i] = sum;
  270. }
  271. if ( pivot != PNULL )
  272. x = pxinv_vec(pivot,tmp,x);
  273. else
  274. x = v_copy(tmp,x);
  275. #ifdef THREADSAFE
  276. V_FREE(tmp);
  277. #endif
  278. return x;
  279. }
  280. /* spILUfactor -- sparse modified incomplete LU factorisation with
  281. no pivoting
  282. -- all pivot entries are ensured to be >= alpha in magnitude
  283. -- setting alpha = 0 gives incomplete LU factorisation
  284. -- no fill-in is generated
  285. -- in situ factorisation */
  286. #ifndef ANSI_C
  287. SPMAT *spILUfactor(A,alpha)
  288. SPMAT *A;
  289. double alpha;
  290. #else
  291. SPMAT *spILUfactor(SPMAT *A, double alpha)
  292. #endif
  293. {
  294. int i, k, idx, idx_piv, m, n, old_idx, old_idx_piv;
  295. SPROW *r, *r_piv;
  296. Real piv_val, tmp;
  297. /* printf("spILUfactor: entered\n"); */
  298. if ( ! A )
  299. error(E_NULL,"spILUfactor");
  300. if ( alpha < 0.0 )
  301. error(E_RANGE,"[alpha] in spILUfactor");
  302. m = A->m; n = A->n;
  303. sp_diag_access(A);
  304. sp_col_access(A);
  305. for ( k = 0; k < n; k++ )
  306. {
  307. /* printf("spILUfactor(l.%d): checkpoint A: k = %d\n",__LINE__,k); */
  308. /* printf("spILUfactor(l.%d): A =\n", __LINE__); */
  309. /* sp_output(A); */
  310. r_piv = &(A->row[k]);
  311. idx_piv = r_piv->diag;
  312. if ( idx_piv < 0 )
  313. {
  314. sprow_set_val(r_piv,k,alpha);
  315. idx_piv = sprow_idx(r_piv,k);
  316. }
  317. /* printf("spILUfactor: checkpoint B\n"); */
  318. if ( idx_piv < 0 )
  319. error(E_BOUNDS,"spILUfactor");
  320. old_idx_piv = idx_piv;
  321. piv_val = r_piv->elt[idx_piv].val;
  322. /* printf("spILUfactor: checkpoint C\n"); */
  323. if ( fabs(piv_val) < alpha )
  324. piv_val = ( piv_val < 0.0 ) ? -alpha : alpha;
  325. if ( piv_val == 0.0 ) /* alpha == 0.0 too! */
  326. error(E_SING,"spILUfactor");
  327. /* go to next row with a non-zero in this column */
  328. i = r_piv->elt[idx_piv].nxt_row;
  329. old_idx = idx = r_piv->elt[idx_piv].nxt_idx;
  330. while ( i >= k )
  331. {
  332. /* printf("spILUfactor: checkpoint D: i = %d\n",i); */
  333. /* perform row operations */
  334. r = &(A->row[i]);
  335. /* idx = sprow_idx(r,k); */
  336. /* printf("spLUfactor(l.%d) i = %d, idx = %d\n",
  337. __LINE__, i, idx); */
  338. if ( idx < 0 )
  339. {
  340. idx = r->elt[old_idx].nxt_idx;
  341. i = r->elt[old_idx].nxt_row;
  342. continue;
  343. }
  344. /* printf("spILUfactor: checkpoint E\n"); */
  345. /* compute and set multiplier */
  346. r->elt[idx].val = tmp = r->elt[idx].val/piv_val;
  347. /* printf("spILUfactor: piv_val = %g, multiplier = %g\n",
  348. piv_val, tmp); */
  349. /* printf("spLUfactor(l.%d) multiplier = %g\n", __LINE__, tmp); */
  350. if ( tmp == 0.0 )
  351. {
  352. idx = r->elt[old_idx].nxt_idx;
  353. i = r->elt[old_idx].nxt_row;
  354. continue;
  355. }
  356. /* idx = sprow_idx(r,k+1); */
  357. /* if ( idx < 0 )
  358. idx = -(idx+2); */
  359. idx_piv++; idx++; /* now look beyond the multiplier entry */
  360. /* printf("spILUfactor: checkpoint F: idx = %d, idx_piv = %d\n",
  361. idx, idx_piv); */
  362. while ( idx_piv < r_piv->len && idx < r->len )
  363. {
  364. /* printf("spILUfactor: checkpoint G: idx = %d, idx_piv = %d\n",
  365. idx, idx_piv); */
  366. if ( r_piv->elt[idx_piv].col < r->elt[idx].col )
  367. idx_piv++;
  368. else if ( r_piv->elt[idx_piv].col > r->elt[idx].col )
  369. idx++;
  370. else /* column numbers match */
  371. {
  372. /* printf("spILUfactor(l.%d) subtract %g times the ",
  373. __LINE__, tmp); */
  374. /* printf("(%d,%d) entry to the (%d,%d) entry\n",
  375. k, r_piv->elt[idx_piv].col,
  376. i, r->elt[idx].col); */
  377. r->elt[idx].val -= tmp*r_piv->elt[idx_piv].val;
  378. idx++; idx_piv++;
  379. }
  380. }
  381. /* bump to next row with a non-zero in column k */
  382. /* printf("spILUfactor(l.%d) column = %d, row[%d] =\n",
  383. __LINE__, r->elt[old_idx].col, i); */
  384. /* sprow_foutput(stdout,r); */
  385. i = r->elt[old_idx].nxt_row;
  386. old_idx = idx = r->elt[old_idx].nxt_idx;
  387. /* printf("spILUfactor(l.%d) i = %d, idx = %d\n", __LINE__, i, idx); */
  388. /* and restore idx_piv to index of pivot entry */
  389. idx_piv = old_idx_piv;
  390. }
  391. }
  392. /* printf("spILUfactor: exiting\n"); */
  393. return A;
  394. }