sptort.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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. This file contains tests for the sparse matrix part of Meschach
  26. */
  27. #include <stdio.h>
  28. #include <math.h>
  29. #include "matrix2.h"
  30. #include "sparse2.h"
  31. #include "iter.h"
  32. #define errmesg(mesg) printf("Error: %s error: line %d\n",mesg,__LINE__)
  33. #define notice(mesg) printf("# Testing %s...\n",mesg);
  34. /* for iterative methods */
  35. #if REAL == DOUBLE
  36. #define EPS 1e-7
  37. #elif REAL == FLOAT
  38. #define EPS 1e-3
  39. #endif
  40. int chk_col_accessSPT(A)
  41. SPMAT *A;
  42. {
  43. int i, j, nxt_idx, nxt_row, scan_cnt, total_cnt;
  44. SPROW *r;
  45. row_elt *e;
  46. if ( ! A )
  47. error(E_NULL,"chk_col_accessSPT");
  48. if ( ! A->flag_col )
  49. return FALSE;
  50. /* scan down each column, counting the number of entries met */
  51. scan_cnt = 0;
  52. for ( j = 0; j < A->n; j++ )
  53. {
  54. i = -1;
  55. nxt_idx = A->start_idx[j];
  56. nxt_row = A->start_row[j];
  57. while ( nxt_row >= 0 && nxt_idx >= 0 && nxt_row > i )
  58. {
  59. i = nxt_row;
  60. r = &(A->row[i]);
  61. e = &(r->elt[nxt_idx]);
  62. nxt_idx = e->nxt_idx;
  63. nxt_row = e->nxt_row;
  64. scan_cnt++;
  65. }
  66. }
  67. total_cnt = 0;
  68. for ( i = 0; i < A->m; i++ )
  69. total_cnt += A->row[i].len;
  70. if ( total_cnt != scan_cnt )
  71. return FALSE;
  72. else
  73. return TRUE;
  74. }
  75. void main(argc, argv)
  76. int argc;
  77. char *argv[];
  78. {
  79. VEC *x, *y, *z, *u, *v;
  80. Real s1, s2;
  81. PERM *pivot;
  82. SPMAT *A, *B, *C;
  83. SPMAT *B1, *C1;
  84. SPROW *r;
  85. int i, j, k, deg, seed, m, m_old, n, n_old;
  86. mem_info_on(TRUE);
  87. setbuf(stdout, (char *)NULL);
  88. /* get seed if in argument list */
  89. if ( argc == 1 )
  90. seed = 1111;
  91. else if ( argc == 2 && sscanf(argv[1],"%d",&seed) == 1 )
  92. ;
  93. else
  94. {
  95. printf("usage: %s [seed]\n", argv[0]);
  96. exit(0);
  97. }
  98. srand(seed);
  99. /* set up two random sparse matrices */
  100. m = 120;
  101. n = 100;
  102. deg = 8;
  103. notice("allocating sparse matrices");
  104. A = sp_get(m,n,deg);
  105. B = sp_get(m,n,deg);
  106. notice("setting and getting matrix entries");
  107. for ( k = 0; k < m*deg; k++ )
  108. {
  109. i = (rand() >> 8) % m;
  110. j = (rand() >> 8) % n;
  111. sp_set_val(A,i,j,rand()/((Real)MAX_RAND));
  112. i = (rand() >> 8) % m;
  113. j = (rand() >> 8) % n;
  114. sp_set_val(B,i,j,rand()/((Real)MAX_RAND));
  115. }
  116. for ( k = 0; k < 10; k++ )
  117. {
  118. s1 = rand()/((Real)MAX_RAND);
  119. i = (rand() >> 8) % m;
  120. j = (rand() >> 8) % n;
  121. sp_set_val(A,i,j,s1);
  122. s2 = sp_get_val(A,i,j);
  123. if ( fabs(s1 - s2) >= MACHEPS )
  124. break;
  125. }
  126. if ( k < 10 )
  127. errmesg("sp_set_val()/sp_get_val()");
  128. /* test copy routines */
  129. notice("copy routines");
  130. x = v_get(n);
  131. y = v_get(m);
  132. z = v_get(m);
  133. /* first copy routine */
  134. C = sp_copy(A);
  135. for ( k = 0; k < 100; k++ )
  136. {
  137. v_rand(x);
  138. sp_mv_mlt(A,x,y);
  139. sp_mv_mlt(C,x,z);
  140. if ( v_norm_inf(v_sub(y,z,z)) >= MACHEPS*deg*m )
  141. break;
  142. }
  143. if ( k < 100 )
  144. {
  145. errmesg("sp_copy()/sp_mv_mlt()");
  146. printf("# Error in A.x (inf norm) = %g [cf MACHEPS = %g]\n",
  147. v_norm_inf(z), MACHEPS);
  148. }
  149. /* second copy routine
  150. -- note that A & B have different sparsity patterns */
  151. mem_stat_mark(1);
  152. sp_copy2(A,B);
  153. mem_stat_free(1);
  154. for ( k = 0; k < 10; k++ )
  155. {
  156. v_rand(x);
  157. sp_mv_mlt(A,x,y);
  158. sp_mv_mlt(B,x,z);
  159. if ( v_norm_inf(v_sub(y,z,z)) >= MACHEPS*deg*m )
  160. break;
  161. }
  162. if ( k < 10 )
  163. {
  164. errmesg("sp_copy2()/sp_mv_mlt()");
  165. printf("# Error in A.x (inf norm) = %g [cf MACHEPS = %g]\n",
  166. v_norm_inf(z), MACHEPS);
  167. }
  168. /* now check compacting routine */
  169. notice("compacting routine");
  170. sp_compact(B,0.0);
  171. for ( k = 0; k < 10; k++ )
  172. {
  173. v_rand(x);
  174. sp_mv_mlt(A,x,y);
  175. sp_mv_mlt(B,x,z);
  176. if ( v_norm_inf(v_sub(y,z,z)) >= MACHEPS*deg*m )
  177. break;
  178. }
  179. if ( k < 10 )
  180. {
  181. errmesg("sp_compact()");
  182. printf("# Error in A.x (inf norm) = %g [cf MACHEPS = %g]\n",
  183. v_norm_inf(z), MACHEPS);
  184. }
  185. for ( i = 0; i < B->m; i++ )
  186. {
  187. r = &(B->row[i]);
  188. for ( j = 0; j < r->len; j++ )
  189. if ( r->elt[j].val == 0.0 )
  190. break;
  191. }
  192. if ( i < B->m )
  193. {
  194. errmesg("sp_compact()");
  195. printf("# Zero entry in compacted matrix\n");
  196. }
  197. /* check column access paths */
  198. notice("resizing and access paths");
  199. m_old = A->m-1;
  200. n_old = A->n-1;
  201. A = sp_resize(A,A->m+10,A->n+10);
  202. for ( k = 0 ; k < 20; k++ )
  203. {
  204. i = m_old + ((rand() >> 8) % 10);
  205. j = n_old + ((rand() >> 8) % 10);
  206. s1 = rand()/((Real)MAX_RAND);
  207. sp_set_val(A,i,j,s1);
  208. if ( fabs(s1 - sp_get_val(A,i,j)) >= MACHEPS )
  209. break;
  210. }
  211. if ( k < 20 )
  212. errmesg("sp_resize()");
  213. sp_col_access(A);
  214. if ( ! chk_col_accessSPT(A) )
  215. {
  216. errmesg("sp_col_access()");
  217. }
  218. sp_diag_access(A);
  219. for ( i = 0; i < A->m; i++ )
  220. {
  221. r = &(A->row[i]);
  222. if ( r->diag != sprow_idx(r,i) )
  223. break;
  224. }
  225. if ( i < A->m )
  226. {
  227. errmesg("sp_diag_access()");
  228. }
  229. /* test both sp_mv_mlt() and sp_vm_mlt() */
  230. x = v_resize(x,B->n);
  231. y = v_resize(y,B->m);
  232. u = v_get(B->m);
  233. v = v_get(B->n);
  234. for ( k = 0; k < 10; k++ )
  235. {
  236. v_rand(x);
  237. v_rand(y);
  238. sp_mv_mlt(B,x,u);
  239. sp_vm_mlt(B,y,v);
  240. if ( fabs(in_prod(x,v) - in_prod(y,u)) >=
  241. MACHEPS*v_norm2(x)*v_norm2(u)*5 )
  242. break;
  243. }
  244. if ( k < 10 )
  245. {
  246. errmesg("sp_mv_mlt()/sp_vm_mlt()");
  247. printf("# Error in inner products = %g [cf MACHEPS = %g]\n",
  248. fabs(in_prod(x,v) - in_prod(y,u)), MACHEPS);
  249. }
  250. SP_FREE(A);
  251. SP_FREE(B);
  252. SP_FREE(C);
  253. /* now test Cholesky and LU factorise and solve */
  254. notice("sparse Cholesky factorise/solve");
  255. A = iter_gen_sym(120,8);
  256. B = sp_copy(A);
  257. spCHfactor(A);
  258. x = v_resize(x,A->m);
  259. y = v_resize(y,A->m);
  260. v_rand(x);
  261. sp_mv_mlt(B,x,y);
  262. z = v_resize(z,A->m);
  263. spCHsolve(A,y,z);
  264. v = v_resize(v,A->m);
  265. sp_mv_mlt(B,z,v);
  266. /* compute residual */
  267. v_sub(y,v,v);
  268. if ( v_norm2(v) >= MACHEPS*v_norm2(y)*10 )
  269. {
  270. errmesg("spCHfactor()/spCHsolve()");
  271. printf("# Sparse Cholesky residual = %g [cf MACHEPS = %g]\n",
  272. v_norm2(v), MACHEPS);
  273. }
  274. /* compute error in solution */
  275. v_sub(x,z,z);
  276. if ( v_norm2(z) > MACHEPS*v_norm2(x)*10 )
  277. {
  278. errmesg("spCHfactor()/spCHsolve()");
  279. printf("# Solution error = %g [cf MACHEPS = %g]\n",
  280. v_norm2(z), MACHEPS);
  281. }
  282. /* now test symbolic and incomplete factorisation */
  283. SP_FREE(A);
  284. A = sp_copy(B);
  285. mem_stat_mark(2);
  286. spCHsymb(A);
  287. mem_stat_mark(2);
  288. spICHfactor(A);
  289. spCHsolve(A,y,z);
  290. v = v_resize(v,A->m);
  291. sp_mv_mlt(B,z,v);
  292. /* compute residual */
  293. v_sub(y,v,v);
  294. if ( v_norm2(v) >= MACHEPS*v_norm2(y)*5 )
  295. {
  296. errmesg("spCHsymb()/spICHfactor()");
  297. printf("# Sparse Cholesky residual = %g [cf MACHEPS = %g]\n",
  298. v_norm2(v), MACHEPS);
  299. }
  300. /* compute error in solution */
  301. v_sub(x,z,z);
  302. if ( v_norm2(z) > MACHEPS*v_norm2(x)*10 )
  303. {
  304. errmesg("spCHsymb()/spICHfactor()");
  305. printf("# Solution error = %g [cf MACHEPS = %g]\n",
  306. v_norm2(z), MACHEPS);
  307. }
  308. /* now test sparse LU factorisation */
  309. notice("sparse LU factorise/solve");
  310. SP_FREE(A);
  311. SP_FREE(B);
  312. A = iter_gen_nonsym(100,100,8,1.0);
  313. B = sp_copy(A);
  314. x = v_resize(x,A->n);
  315. z = v_resize(z,A->n);
  316. y = v_resize(y,A->m);
  317. v = v_resize(v,A->m);
  318. v_rand(x);
  319. sp_mv_mlt(B,x,y);
  320. pivot = px_get(A->m);
  321. mem_stat_mark(3);
  322. spLUfactor(A,pivot,0.1);
  323. spLUsolve(A,pivot,y,z);
  324. mem_stat_free(3);
  325. sp_mv_mlt(B,z,v);
  326. /* compute residual */
  327. v_sub(y,v,v);
  328. if ( v_norm2(v) >= MACHEPS*v_norm2(y)*A->m )
  329. {
  330. errmesg("spLUfactor()/spLUsolve()");
  331. printf("# Sparse LU residual = %g [cf MACHEPS = %g]\n",
  332. v_norm2(v), MACHEPS);
  333. }
  334. /* compute error in solution */
  335. v_sub(x,z,z);
  336. if ( v_norm2(z) > MACHEPS*v_norm2(x)*100*A->m )
  337. {
  338. errmesg("spLUfactor()/spLUsolve()");
  339. printf("# Sparse LU solution error = %g [cf MACHEPS = %g]\n",
  340. v_norm2(z), MACHEPS);
  341. }
  342. /* now check spLUTsolve */
  343. mem_stat_mark(4);
  344. sp_vm_mlt(B,x,y);
  345. spLUTsolve(A,pivot,y,z);
  346. sp_vm_mlt(B,z,v);
  347. mem_stat_free(4);
  348. /* compute residual */
  349. v_sub(y,v,v);
  350. if ( v_norm2(v) >= MACHEPS*v_norm2(y)*A->m )
  351. {
  352. errmesg("spLUTsolve()");
  353. printf("# Sparse LU residual = %g [cf MACHEPS = %g]\n",
  354. v_norm2(v), MACHEPS);
  355. }
  356. /* compute error in solution */
  357. v_sub(x,z,z);
  358. if ( v_norm2(z) > MACHEPS*v_norm2(x)*100*A->m )
  359. {
  360. errmesg("spLUTsolve()");
  361. printf("# Sparse LU solution error = %g [cf MACHEPS = %g]\n",
  362. v_norm2(z), MACHEPS);
  363. }
  364. /* algebraic operations */
  365. notice("addition,subtraction and multiplying by a number");
  366. SP_FREE(A);
  367. SP_FREE(B);
  368. m = 120;
  369. n = 120;
  370. deg = 5;
  371. A = sp_get(m,n,deg);
  372. B = sp_get(m,n,deg);
  373. C = sp_get(m,n,deg);
  374. C1 = sp_get(m,n,deg);
  375. for ( k = 0; k < m*deg; k++ )
  376. {
  377. i = (rand() >> 8) % m;
  378. j = (rand() >> 8) % n;
  379. sp_set_val(A,i,j,rand()/((Real)MAX_RAND));
  380. i = (rand() >> 8) % m;
  381. j = (rand() >> 8) % n;
  382. sp_set_val(B,i,j,rand()/((Real)MAX_RAND));
  383. }
  384. s1 = mrand();
  385. B1 = sp_copy(B);
  386. mem_stat_mark(1);
  387. sp_smlt(B,s1,C);
  388. sp_add(A,C,C1);
  389. sp_sub(C1,A,C);
  390. sp_smlt(C,-1.0/s1,C);
  391. sp_add(C,B1,C);
  392. s2 = 0.0;
  393. for (k=0; k < C->m; k++) {
  394. r = &(C->row[k]);
  395. for (j=0; j < r->len; j++) {
  396. if (s2 < fabs(r->elt[j].val))
  397. s2 = fabs(r->elt[j].val);
  398. }
  399. }
  400. if (s2 > MACHEPS*A->m) {
  401. errmesg("add, sub, mlt sparse matrices (args not in situ)\n");
  402. printf(" difference = %g [MACEPS = %g]\n",s2,MACHEPS);
  403. }
  404. sp_mltadd(A,B1,s1,C1);
  405. sp_sub(C1,A,A);
  406. sp_smlt(A,1.0/s1,C1);
  407. sp_sub(C1,B1,C1);
  408. mem_stat_free(1);
  409. s2 = 0.0;
  410. for (k=0; k < C1->m; k++) {
  411. r = &(C1->row[k]);
  412. for (j=0; j < r->len; j++) {
  413. if (s2 < fabs(r->elt[j].val))
  414. s2 = fabs(r->elt[j].val);
  415. }
  416. }
  417. if (s2 > MACHEPS*A->m) {
  418. errmesg("add, sub, mlt sparse matrices (args not in situ)\n");
  419. printf(" difference = %g [MACEPS = %g]\n",s2,MACHEPS);
  420. }
  421. V_FREE(x);
  422. V_FREE(y);
  423. V_FREE(z);
  424. V_FREE(u);
  425. V_FREE(v);
  426. PX_FREE(pivot);
  427. SP_FREE(A);
  428. SP_FREE(B);
  429. SP_FREE(C);
  430. SP_FREE(B1);
  431. SP_FREE(C1);
  432. printf("# Done testing (%s)\n",argv[0]);
  433. mem_info();
  434. }