sparse.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  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. Sparse matrix package
  26. See also: sparse.h, matrix.h
  27. */
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include <stdlib.h>
  31. #include "sparse.h"
  32. static char rcsid[] = "$Id: sparse.c,v 1.10 1994/03/08 05:46:07 des Exp $";
  33. #define MINROWLEN 10
  34. /* sp_get_val -- returns the (i,j) entry of the sparse matrix A */
  35. #ifndef ANSI_C
  36. double sp_get_val(A,i,j)
  37. SPMAT *A;
  38. int i, j;
  39. #else
  40. double sp_get_val(const SPMAT *A, int i, int j)
  41. #endif
  42. {
  43. SPROW *r;
  44. int idx;
  45. if ( A == SMNULL )
  46. error(E_NULL,"sp_get_val");
  47. if ( i < 0 || i >= A->m || j < 0 || j >= A->n )
  48. error(E_SIZES,"sp_get_val");
  49. r = A->row+i;
  50. idx = sprow_idx(r,j);
  51. if ( idx < 0 )
  52. return 0.0;
  53. /* else */
  54. return r->elt[idx].val;
  55. }
  56. /* sp_set_val -- sets the (i,j) entry of the sparse matrix A */
  57. #ifndef ANSI_C
  58. double sp_set_val(A,i,j,val)
  59. SPMAT *A;
  60. int i, j;
  61. double val;
  62. #else
  63. double sp_set_val(SPMAT *A, int i, int j, double val)
  64. #endif
  65. {
  66. SPROW *r;
  67. int idx, idx2, new_len;
  68. if ( A == SMNULL )
  69. error(E_NULL,"sp_set_val");
  70. if ( i < 0 || i >= A->m || j < 0 || j >= A->n )
  71. error(E_SIZES,"sp_set_val");
  72. r = A->row+i;
  73. idx = sprow_idx(r,j);
  74. /* printf("sp_set_val: idx = %d\n",idx); */
  75. if ( idx >= 0 )
  76. { r->elt[idx].val = val; return val; }
  77. /* else */ if ( idx < -1 )
  78. {
  79. /* Note: this destroys the column & diag access paths */
  80. A->flag_col = A->flag_diag = FALSE;
  81. /* shift & insert new value */
  82. idx = -(idx+2); /* this is the intended insertion index */
  83. if ( r->len >= r->maxlen )
  84. {
  85. r->len = r->maxlen;
  86. new_len = max(2*r->maxlen+1,5);
  87. if (mem_info_is_on()) {
  88. mem_bytes(TYPE_SPMAT,A->row[i].maxlen*sizeof(row_elt),
  89. new_len*sizeof(row_elt));
  90. }
  91. r->elt = RENEW(r->elt,new_len,row_elt);
  92. if ( ! r->elt ) /* can't allocate */
  93. error(E_MEM,"sp_set_val");
  94. r->maxlen = 2*r->maxlen+1;
  95. }
  96. for ( idx2 = r->len-1; idx2 >= idx; idx2-- )
  97. MEM_COPY((char *)(&(r->elt[idx2])),
  98. (char *)(&(r->elt[idx2+1])),sizeof(row_elt));
  99. /************************************************************
  100. if ( idx < r->len )
  101. MEM_COPY((char *)(&(r->elt[idx])),(char *)(&(r->elt[idx+1])),
  102. (r->len-idx)*sizeof(row_elt));
  103. ************************************************************/
  104. r->len++;
  105. r->elt[idx].col = j;
  106. return r->elt[idx].val = val;
  107. }
  108. /* else -- idx == -1, error in index/matrix! */
  109. return 0.0;
  110. }
  111. /* sp_mv_mlt -- sparse matrix/dense vector multiply
  112. -- result is in out, which is returned unless out==NULL on entry
  113. -- if out==NULL on entry then the result vector is created */
  114. #ifndef ANSI_C
  115. VEC *sp_mv_mlt(A,x,out)
  116. SPMAT *A;
  117. VEC *x, *out;
  118. #else
  119. VEC *sp_mv_mlt(const SPMAT *A, const VEC *x, VEC *out)
  120. #endif
  121. {
  122. int i, j_idx, m, n, max_idx;
  123. Real sum, *x_ve;
  124. SPROW *r;
  125. row_elt *elts;
  126. if ( ! A || ! x )
  127. error(E_NULL,"sp_mv_mlt");
  128. if ( x->dim != A->n )
  129. error(E_SIZES,"sp_mv_mlt");
  130. if ( ! out || out->dim < A->m )
  131. out = v_resize(out,A->m);
  132. if ( out == x )
  133. error(E_INSITU,"sp_mv_mlt");
  134. m = A->m; n = A->n;
  135. x_ve = x->ve;
  136. for ( i = 0; i < m; i++ )
  137. {
  138. sum = 0.0;
  139. r = &(A->row[i]);
  140. max_idx = r->len;
  141. elts = r->elt;
  142. for ( j_idx = 0; j_idx < max_idx; j_idx++, elts++ )
  143. sum += elts->val*x_ve[elts->col];
  144. out->ve[i] = sum;
  145. }
  146. return out;
  147. }
  148. /* sp_vm_mlt -- sparse matrix/dense vector multiply from left
  149. -- result is in out, which is returned unless out==NULL on entry
  150. -- if out==NULL on entry then result vector is created & returned */
  151. #ifndef ANSI_C
  152. VEC *sp_vm_mlt(A,x,out)
  153. SPMAT *A;
  154. VEC *x, *out;
  155. #else
  156. VEC *sp_vm_mlt(const SPMAT *A, const VEC *x, VEC *out)
  157. #endif
  158. {
  159. int i, j_idx, m, n, max_idx;
  160. Real tmp, *x_ve, *out_ve;
  161. SPROW *r;
  162. row_elt *elts;
  163. if ( ! A || ! x )
  164. error(E_NULL,"sp_vm_mlt");
  165. if ( x->dim != A->m )
  166. error(E_SIZES,"sp_vm_mlt");
  167. if ( ! out || out->dim < A->n )
  168. out = v_resize(out,A->n);
  169. if ( out == x )
  170. error(E_INSITU,"sp_vm_mlt");
  171. m = A->m; n = A->n;
  172. v_zero(out);
  173. x_ve = x->ve; out_ve = out->ve;
  174. for ( i = 0; i < m; i++ )
  175. {
  176. r = A->row+i;
  177. max_idx = r->len;
  178. elts = r->elt;
  179. tmp = x_ve[i];
  180. for ( j_idx = 0; j_idx < max_idx; j_idx++, elts++ )
  181. out_ve[elts->col] += elts->val*tmp;
  182. }
  183. return out;
  184. }
  185. /* sp_get -- get sparse matrix
  186. -- len is number of elements available for each row without
  187. allocating further memory */
  188. #ifndef ANSI_C
  189. SPMAT *sp_get(m,n,maxlen)
  190. int m, n, maxlen;
  191. #else
  192. SPMAT *sp_get(int m, int n, int maxlen)
  193. #endif
  194. {
  195. SPMAT *A;
  196. SPROW *rows;
  197. int i;
  198. if ( m < 0 || n < 0 )
  199. error(E_NEG,"sp_get");
  200. maxlen = max(maxlen,1);
  201. A = NEW(SPMAT);
  202. if ( ! A ) /* can't allocate */
  203. error(E_MEM,"sp_get");
  204. else if (mem_info_is_on()) {
  205. mem_bytes(TYPE_SPMAT,0,sizeof(SPMAT));
  206. mem_numvar(TYPE_SPMAT,1);
  207. }
  208. /* fprintf(stderr,"Have SPMAT structure\n"); */
  209. A->row = rows = NEW_A(m,SPROW);
  210. if ( ! A->row ) /* can't allocate */
  211. error(E_MEM,"sp_get");
  212. else if (mem_info_is_on()) {
  213. mem_bytes(TYPE_SPMAT,0,m*sizeof(SPROW));
  214. }
  215. /* fprintf(stderr,"Have row structure array\n"); */
  216. A->start_row = NEW_A(n,int);
  217. A->start_idx = NEW_A(n,int);
  218. if ( ! A->start_row || ! A->start_idx ) /* can't allocate */
  219. error(E_MEM,"sp_get");
  220. else if (mem_info_is_on()) {
  221. mem_bytes(TYPE_SPMAT,0,2*n*sizeof(int));
  222. }
  223. for ( i = 0; i < n; i++ )
  224. A->start_row[i] = A->start_idx[i] = -1;
  225. /* fprintf(stderr,"Have start_row array\n"); */
  226. A->m = A->max_m = m;
  227. A->n = A->max_n = n;
  228. for ( i = 0; i < m; i++, rows++ )
  229. {
  230. rows->elt = NEW_A(maxlen,row_elt);
  231. if ( ! rows->elt )
  232. error(E_MEM,"sp_get");
  233. else if (mem_info_is_on()) {
  234. mem_bytes(TYPE_SPMAT,0,maxlen*sizeof(row_elt));
  235. }
  236. /* fprintf(stderr,"Have row %d element array\n",i); */
  237. rows->len = 0;
  238. rows->maxlen = maxlen;
  239. rows->diag = -1;
  240. }
  241. return A;
  242. }
  243. /* sp_free -- frees up the memory for a sparse matrix */
  244. #ifndef ANSI_C
  245. int sp_free(A)
  246. SPMAT *A;
  247. #else
  248. int sp_free(SPMAT *A)
  249. #endif
  250. {
  251. SPROW *r;
  252. int i;
  253. if ( ! A )
  254. return -1;
  255. if ( A->start_row != (int *)NULL ) {
  256. if (mem_info_is_on()) {
  257. mem_bytes(TYPE_SPMAT,A->max_n*sizeof(int),0);
  258. }
  259. free((char *)(A->start_row));
  260. }
  261. if ( A->start_idx != (int *)NULL ) {
  262. if (mem_info_is_on()) {
  263. mem_bytes(TYPE_SPMAT,A->max_n*sizeof(int),0);
  264. }
  265. free((char *)(A->start_idx));
  266. }
  267. if ( ! A->row )
  268. {
  269. if (mem_info_is_on()) {
  270. mem_bytes(TYPE_SPMAT,sizeof(SPMAT),0);
  271. mem_numvar(TYPE_SPMAT,-1);
  272. }
  273. free((char *)A);
  274. return 0;
  275. }
  276. for ( i = 0; i < A->m; i++ )
  277. {
  278. r = &(A->row[i]);
  279. if ( r->elt != (row_elt *)NULL ) {
  280. if (mem_info_is_on()) {
  281. mem_bytes(TYPE_SPMAT,A->row[i].maxlen*sizeof(row_elt),0);
  282. }
  283. free((char *)(r->elt));
  284. }
  285. }
  286. if (mem_info_is_on()) {
  287. if (A->row)
  288. mem_bytes(TYPE_SPMAT,A->max_m*sizeof(SPROW),0);
  289. mem_bytes(TYPE_SPMAT,sizeof(SPMAT),0);
  290. mem_numvar(TYPE_SPMAT,-1);
  291. }
  292. free((char *)(A->row));
  293. free((char *)A);
  294. return 0;
  295. }
  296. /* sp_copy -- constructs a copy of a given matrix
  297. -- note that the max_len fields (etc) are no larger in the copy
  298. than necessary
  299. -- result is returned */
  300. #ifndef ANSI_C
  301. SPMAT *sp_copy(A)
  302. SPMAT *A;
  303. #else
  304. SPMAT *sp_copy(const SPMAT *A)
  305. #endif
  306. {
  307. SPMAT *out;
  308. SPROW *row1, *row2;
  309. int i;
  310. if ( A == SMNULL )
  311. error(E_NULL,"sp_copy");
  312. if ( ! (out=NEW(SPMAT)) )
  313. error(E_MEM,"sp_copy");
  314. else if (mem_info_is_on()) {
  315. mem_bytes(TYPE_SPMAT,0,sizeof(SPMAT));
  316. mem_numvar(TYPE_SPMAT,1);
  317. }
  318. out->m = out->max_m = A->m; out->n = out->max_n = A->n;
  319. /* set up rows */
  320. if ( ! (out->row=NEW_A(A->m,SPROW)) )
  321. error(E_MEM,"sp_copy");
  322. else if (mem_info_is_on()) {
  323. mem_bytes(TYPE_SPMAT,0,A->m*sizeof(SPROW));
  324. }
  325. for ( i = 0; i < A->m; i++ )
  326. {
  327. row1 = &(A->row[i]);
  328. row2 = &(out->row[i]);
  329. if ( ! (row2->elt=NEW_A(max(row1->len,3),row_elt)) )
  330. error(E_MEM,"sp_copy");
  331. else if (mem_info_is_on()) {
  332. mem_bytes(TYPE_SPMAT,0,max(row1->len,3)*sizeof(row_elt));
  333. }
  334. row2->len = row1->len;
  335. row2->maxlen = max(row1->len,3);
  336. row2->diag = row1->diag;
  337. MEM_COPY((char *)(row1->elt),(char *)(row2->elt),
  338. row1->len*sizeof(row_elt));
  339. }
  340. /* set up start arrays -- for column access */
  341. if ( ! (out->start_idx=NEW_A(A->n,int)) ||
  342. ! (out->start_row=NEW_A(A->n,int)) )
  343. error(E_MEM,"sp_copy");
  344. else if (mem_info_is_on()) {
  345. mem_bytes(TYPE_SPMAT,0,2*A->n*sizeof(int));
  346. }
  347. MEM_COPY((char *)(A->start_idx),(char *)(out->start_idx),
  348. A->n*sizeof(int));
  349. MEM_COPY((char *)(A->start_row),(char *)(out->start_row),
  350. A->n*sizeof(int));
  351. return out;
  352. }
  353. /* sp_col_access -- set column access path; i.e. nxt_row, nxt_idx fields
  354. -- returns A */
  355. #ifndef ANSI_C
  356. SPMAT *sp_col_access(A)
  357. SPMAT *A;
  358. #else
  359. SPMAT *sp_col_access(SPMAT *A)
  360. #endif
  361. {
  362. int i, j, j_idx, len, m, n;
  363. SPROW *row;
  364. row_elt *r_elt;
  365. int *start_row, *start_idx;
  366. if ( A == SMNULL )
  367. error(E_NULL,"sp_col_access");
  368. m = A->m; n = A->n;
  369. /* initialise start_row and start_idx */
  370. start_row = A->start_row; start_idx = A->start_idx;
  371. for ( j = 0; j < n; j++ )
  372. { *start_row++ = -1; *start_idx++ = -1; }
  373. start_row = A->start_row; start_idx = A->start_idx;
  374. /* now work UP the rows, setting nxt_row, nxt_idx fields */
  375. for ( i = m-1; i >= 0; i-- )
  376. {
  377. row = &(A->row[i]);
  378. r_elt = row->elt;
  379. len = row->len;
  380. for ( j_idx = 0; j_idx < len; j_idx++, r_elt++ )
  381. {
  382. j = r_elt->col;
  383. r_elt->nxt_row = start_row[j];
  384. r_elt->nxt_idx = start_idx[j];
  385. start_row[j] = i;
  386. start_idx[j] = j_idx;
  387. }
  388. }
  389. A->flag_col = TRUE;
  390. return A;
  391. }
  392. /* sp_diag_access -- set diagonal access path(s) */
  393. #ifndef ANSI_C
  394. SPMAT *sp_diag_access(A)
  395. SPMAT *A;
  396. #else
  397. SPMAT *sp_diag_access(SPMAT *A)
  398. #endif
  399. {
  400. int i, m;
  401. SPROW *row;
  402. if ( A == SMNULL )
  403. error(E_NULL,"sp_diag_access");
  404. m = A->m;
  405. row = A->row;
  406. for ( i = 0; i < m; i++, row++ )
  407. row->diag = sprow_idx(row,i);
  408. A->flag_diag = TRUE;
  409. return A;
  410. }
  411. /* sp_m2dense -- convert a sparse matrix to a dense one */
  412. #ifndef ANSI_C
  413. MAT *sp_m2dense(A,out)
  414. SPMAT *A;
  415. MAT *out;
  416. #else
  417. MAT *sp_m2dense(const SPMAT *A, MAT *out)
  418. #endif
  419. {
  420. int i, j_idx;
  421. SPROW *row;
  422. row_elt *elt;
  423. if ( ! A )
  424. error(E_NULL,"sp_m2dense");
  425. if ( ! out || out->m < A->m || out->n < A->n )
  426. out = m_get(A->m,A->n);
  427. m_zero(out);
  428. for ( i = 0; i < A->m; i++ )
  429. {
  430. row = &(A->row[i]);
  431. elt = row->elt;
  432. for ( j_idx = 0; j_idx < row->len; j_idx++, elt++ )
  433. out->me[i][elt->col] = elt->val;
  434. }
  435. return out;
  436. }
  437. /* C = A+B, can be in situ */
  438. #ifndef ANSI_C
  439. SPMAT *sp_add(A,B,C)
  440. SPMAT *A, *B, *C;
  441. #else
  442. SPMAT *sp_add(const SPMAT *A, const SPMAT *B, SPMAT *C)
  443. #endif
  444. {
  445. int i, in_situ;
  446. SPROW *rc;
  447. STATIC SPROW *tmp = NULL;
  448. if ( ! A || ! B )
  449. error(E_NULL,"sp_add");
  450. if ( A->m != B->m || A->n != B->n )
  451. error(E_SIZES,"sp_add");
  452. if (C == A || C == B)
  453. in_situ = TRUE;
  454. else in_situ = FALSE;
  455. if ( ! C )
  456. C = sp_get(A->m,A->n,5);
  457. else {
  458. if ( C->m != A->m || C->n != A->n )
  459. error(E_SIZES,"sp_add");
  460. if (!in_situ) sp_zero(C);
  461. }
  462. if (tmp == (SPROW *)NULL && in_situ) {
  463. tmp = sprow_get(MINROWLEN);
  464. MEM_STAT_REG(tmp,TYPE_SPROW);
  465. }
  466. if (in_situ)
  467. for (i=0; i < A->m; i++) {
  468. rc = &(C->row[i]);
  469. sprow_add(&(A->row[i]),&(B->row[i]),0,tmp,TYPE_SPROW);
  470. sprow_resize(rc,tmp->len,TYPE_SPMAT);
  471. MEM_COPY(tmp->elt,rc->elt,tmp->len*sizeof(row_elt));
  472. rc->len = tmp->len;
  473. }
  474. else
  475. for (i=0; i < A->m; i++) {
  476. sprow_add(&(A->row[i]),&(B->row[i]),0,&(C->row[i]),TYPE_SPMAT);
  477. }
  478. C->flag_col = C->flag_diag = FALSE;
  479. #ifdef THREADSAFE
  480. sprow_free(tmp);
  481. #endif
  482. return C;
  483. }
  484. /* C = A-B, cannot be in situ */
  485. #ifndef ANSI_C
  486. SPMAT *sp_sub(A,B,C)
  487. SPMAT *A, *B, *C;
  488. #else
  489. SPMAT *sp_sub(const SPMAT *A, const SPMAT *B, SPMAT *C)
  490. #endif
  491. {
  492. int i, in_situ;
  493. SPROW *rc;
  494. STATIC SPROW *tmp = NULL;
  495. if ( ! A || ! B )
  496. error(E_NULL,"sp_sub");
  497. if ( A->m != B->m || A->n != B->n )
  498. error(E_SIZES,"sp_sub");
  499. if (C == A || C == B)
  500. in_situ = TRUE;
  501. else in_situ = FALSE;
  502. if ( ! C )
  503. C = sp_get(A->m,A->n,5);
  504. else {
  505. if ( C->m != A->m || C->n != A->n )
  506. error(E_SIZES,"sp_sub");
  507. if (!in_situ) sp_zero(C);
  508. }
  509. if (tmp == (SPROW *)NULL && in_situ) {
  510. tmp = sprow_get(MINROWLEN);
  511. MEM_STAT_REG(tmp,TYPE_SPROW);
  512. }
  513. if (in_situ)
  514. for (i=0; i < A->m; i++) {
  515. rc = &(C->row[i]);
  516. sprow_sub(&(A->row[i]),&(B->row[i]),0,tmp,TYPE_SPROW);
  517. sprow_resize(rc,tmp->len,TYPE_SPMAT);
  518. MEM_COPY(tmp->elt,rc->elt,tmp->len*sizeof(row_elt));
  519. rc->len = tmp->len;
  520. }
  521. else
  522. for (i=0; i < A->m; i++) {
  523. sprow_sub(&(A->row[i]),&(B->row[i]),0,&(C->row[i]),TYPE_SPMAT);
  524. }
  525. C->flag_col = C->flag_diag = FALSE;
  526. #ifdef THREADSAFE
  527. sprow_free(tmp);
  528. #endif
  529. return C;
  530. }
  531. /* C = A+alpha*B, cannot be in situ */
  532. #ifndef ANSI_C
  533. SPMAT *sp_mltadd(A,B,alpha,C)
  534. SPMAT *A, *B, *C;
  535. double alpha;
  536. #else
  537. SPMAT *sp_mltadd(const SPMAT *A, const SPMAT *B, double alpha, SPMAT *C)
  538. #endif
  539. {
  540. int i, in_situ;
  541. SPROW *rc;
  542. STATIC SPROW *tmp = NULL;
  543. if ( ! A || ! B )
  544. error(E_NULL,"sp_mltadd");
  545. if ( A->m != B->m || A->n != B->n )
  546. error(E_SIZES,"sp_mltadd");
  547. if (C == A || C == B)
  548. in_situ = TRUE;
  549. else in_situ = FALSE;
  550. if ( ! C )
  551. C = sp_get(A->m,A->n,5);
  552. else {
  553. if ( C->m != A->m || C->n != A->n )
  554. error(E_SIZES,"sp_mltadd");
  555. if (!in_situ) sp_zero(C);
  556. }
  557. if (tmp == (SPROW *)NULL && in_situ) {
  558. tmp = sprow_get(MINROWLEN);
  559. MEM_STAT_REG(tmp,TYPE_SPROW);
  560. }
  561. if (in_situ)
  562. for (i=0; i < A->m; i++) {
  563. rc = &(C->row[i]);
  564. sprow_mltadd(&(A->row[i]),&(B->row[i]),alpha,0,tmp,TYPE_SPROW);
  565. sprow_resize(rc,tmp->len,TYPE_SPMAT);
  566. MEM_COPY(tmp->elt,rc->elt,tmp->len*sizeof(row_elt));
  567. rc->len = tmp->len;
  568. }
  569. else
  570. for (i=0; i < A->m; i++) {
  571. sprow_mltadd(&(A->row[i]),&(B->row[i]),alpha,0,
  572. &(C->row[i]),TYPE_SPMAT);
  573. }
  574. C->flag_col = C->flag_diag = FALSE;
  575. #ifdef THREADSAFE
  576. sprow_free(tmp);
  577. #endif
  578. return C;
  579. }
  580. /* B = alpha*A, can be in situ */
  581. #ifndef ANSI_C
  582. SPMAT *sp_smlt(A,alpha,B)
  583. SPMAT *A, *B;
  584. double alpha;
  585. #else
  586. SPMAT *sp_smlt(const SPMAT *A, double alpha, SPMAT *B)
  587. #endif
  588. {
  589. int i;
  590. if ( ! A )
  591. error(E_NULL,"sp_smlt");
  592. if ( ! B )
  593. B = sp_get(A->m,A->n,5);
  594. else
  595. if ( A->m != B->m || A->n != B->n )
  596. error(E_SIZES,"sp_smlt");
  597. for (i=0; i < A->m; i++) {
  598. sprow_smlt(&(A->row[i]),alpha,0,&(B->row[i]),TYPE_SPMAT);
  599. }
  600. return B;
  601. }
  602. /* sp_zero -- zero all the (represented) elements of a sparse matrix */
  603. #ifndef ANSI_C
  604. SPMAT *sp_zero(A)
  605. SPMAT *A;
  606. #else
  607. SPMAT *sp_zero(SPMAT *A)
  608. #endif
  609. {
  610. int i, idx, len;
  611. row_elt *elt;
  612. if ( ! A )
  613. error(E_NULL,"sp_zero");
  614. for ( i = 0; i < A->m; i++ )
  615. {
  616. elt = A->row[i].elt;
  617. len = A->row[i].len;
  618. for ( idx = 0; idx < len; idx++ )
  619. (*elt++).val = 0.0;
  620. }
  621. return A;
  622. }
  623. /* sp_copy2 -- copy sparse matrix (type 2)
  624. -- keeps structure of the OUT matrix */
  625. #ifndef ANSI_C
  626. SPMAT *sp_copy2(A,OUT)
  627. SPMAT *A, *OUT;
  628. #else
  629. SPMAT *sp_copy2(const SPMAT *A, SPMAT *OUT)
  630. #endif
  631. {
  632. int i /* , idx, len1, len2 */;
  633. SPROW *r1, *r2;
  634. STATIC SPROW *scratch = (SPROW *)NULL;
  635. /* row_elt *e1, *e2; */
  636. if ( ! A )
  637. error(E_NULL,"sp_copy2");
  638. if ( ! OUT )
  639. OUT = sp_get(A->m,A->n,10);
  640. if ( ! scratch ) {
  641. scratch = sprow_xpd(scratch,MINROWLEN,TYPE_SPROW);
  642. MEM_STAT_REG(scratch,TYPE_SPROW);
  643. }
  644. if ( OUT->m < A->m )
  645. {
  646. if (mem_info_is_on()) {
  647. mem_bytes(TYPE_SPMAT,A->max_m*sizeof(SPROW),
  648. A->m*sizeof(SPROW));
  649. }
  650. OUT->row = RENEW(OUT->row,A->m,SPROW);
  651. if ( ! OUT->row )
  652. error(E_MEM,"sp_copy2");
  653. for ( i = OUT->m; i < A->m; i++ )
  654. {
  655. OUT->row[i].elt = NEW_A(MINROWLEN,row_elt);
  656. if ( ! OUT->row[i].elt )
  657. error(E_MEM,"sp_copy2");
  658. else if (mem_info_is_on()) {
  659. mem_bytes(TYPE_SPMAT,0,MINROWLEN*sizeof(row_elt));
  660. }
  661. OUT->row[i].maxlen = MINROWLEN;
  662. OUT->row[i].len = 0;
  663. }
  664. OUT->m = A->m;
  665. }
  666. OUT->flag_col = OUT->flag_diag = FALSE;
  667. /* sp_zero(OUT); */
  668. for ( i = 0; i < A->m; i++ )
  669. {
  670. r1 = &(A->row[i]); r2 = &(OUT->row[i]);
  671. sprow_copy(r1,r2,scratch,TYPE_SPROW);
  672. if ( r2->maxlen < scratch->len )
  673. sprow_xpd(r2,scratch->len,TYPE_SPMAT);
  674. MEM_COPY((char *)(scratch->elt),(char *)(r2->elt),
  675. scratch->len*sizeof(row_elt));
  676. r2->len = scratch->len;
  677. /*******************************************************
  678. e1 = r1->elt; e2 = r2->elt;
  679. len1 = r1->len; len2 = r2->len;
  680. for ( idx = 0; idx < len2; idx++, e2++ )
  681. e2->val = 0.0;
  682. for ( idx = 0; idx < len1; idx++, e1++ )
  683. sprow_set_val(r2,e1->col,e1->val);
  684. *******************************************************/
  685. }
  686. sp_col_access(OUT);
  687. #ifdef THREADSAFE
  688. sprow_free(scratch);
  689. #endif
  690. return OUT;
  691. }
  692. /* sp_resize -- resize a sparse matrix
  693. -- don't destroying any contents if possible
  694. -- returns resized matrix */
  695. #ifndef ANSI_C
  696. SPMAT *sp_resize(A,m,n)
  697. SPMAT *A;
  698. int m, n;
  699. #else
  700. SPMAT *sp_resize(SPMAT *A, int m, int n)
  701. #endif
  702. {
  703. int i, len;
  704. SPROW *r;
  705. if (m < 0 || n < 0)
  706. error(E_NEG,"sp_resize");
  707. if ( ! A )
  708. return sp_get(m,n,10);
  709. if (m == A->m && n == A->n)
  710. return A;
  711. if ( m <= A->max_m )
  712. {
  713. for ( i = A->m; i < m; i++ )
  714. A->row[i].len = 0;
  715. A->m = m;
  716. }
  717. else
  718. {
  719. if (mem_info_is_on()) {
  720. mem_bytes(TYPE_SPMAT,A->max_m*sizeof(SPROW),
  721. m*sizeof(SPROW));
  722. }
  723. A->row = RENEW(A->row,(unsigned)m,SPROW);
  724. if ( ! A->row )
  725. error(E_MEM,"sp_resize");
  726. for ( i = A->m; i < m; i++ )
  727. {
  728. if ( ! (A->row[i].elt = NEW_A(MINROWLEN,row_elt)) )
  729. error(E_MEM,"sp_resize");
  730. else if (mem_info_is_on()) {
  731. mem_bytes(TYPE_SPMAT,0,MINROWLEN*sizeof(row_elt));
  732. }
  733. A->row[i].len = 0; A->row[i].maxlen = MINROWLEN;
  734. }
  735. A->m = A->max_m = m;
  736. }
  737. /* update number of rows */
  738. A->n = n;
  739. /* do we need to increase the size of start_idx[] and start_row[] ? */
  740. if ( n > A->max_n )
  741. { /* only have to update the start_idx & start_row arrays */
  742. if (mem_info_is_on())
  743. {
  744. mem_bytes(TYPE_SPMAT,2*A->max_n*sizeof(int),
  745. 2*n*sizeof(int));
  746. }
  747. A->start_row = RENEW(A->start_row,(unsigned)n,int);
  748. A->start_idx = RENEW(A->start_idx,(unsigned)n,int);
  749. if ( ! A->start_row || ! A->start_idx )
  750. error(E_MEM,"sp_resize");
  751. A->max_n = n; /* ...and update max_n */
  752. return A;
  753. }
  754. if ( n <= A->n )
  755. /* make sure that all rows are truncated just before column n */
  756. for ( i = 0; i < A->m; i++ )
  757. {
  758. r = &(A->row[i]);
  759. len = sprow_idx(r,n);
  760. if ( len < 0 )
  761. len = -(len+2);
  762. if ( len < 0 )
  763. error(E_MEM,"sp_resize");
  764. r->len = len;
  765. }
  766. return A;
  767. }
  768. /* sp_compact -- removes zeros and near-zeros from a sparse matrix */
  769. #ifndef ANSI_C
  770. SPMAT *sp_compact(A,tol)
  771. SPMAT *A;
  772. double tol;
  773. #else
  774. SPMAT *sp_compact(SPMAT *A, double tol)
  775. #endif
  776. {
  777. int i, idx1, idx2;
  778. SPROW *r;
  779. row_elt *elt1, *elt2;
  780. if ( ! A )
  781. error(E_NULL,"sp_compact");
  782. if ( tol < 0.0 )
  783. error(E_RANGE,"sp_compact");
  784. A->flag_col = A->flag_diag = FALSE;
  785. for ( i = 0; i < A->m; i++ )
  786. {
  787. r = &(A->row[i]);
  788. elt1 = elt2 = r->elt;
  789. idx1 = idx2 = 0;
  790. while ( idx1 < r->len )
  791. {
  792. /* printf("# sp_compact: idx1 = %d, idx2 = %d\n",idx1,idx2); */
  793. if ( fabs(elt1->val) <= tol )
  794. { idx1++; elt1++; continue; }
  795. if ( elt1 != elt2 )
  796. MEM_COPY(elt1,elt2,sizeof(row_elt));
  797. idx1++; elt1++;
  798. idx2++; elt2++;
  799. }
  800. r->len = idx2;
  801. }
  802. return A;
  803. }
  804. /* sp_mlt (C) Copyright David Stewart and Fabrizio Novalis <novalis@mars.elet.polimi.it> */
  805. /* sp_mlt -- computes out = A*B and returns out */
  806. SPMAT *sp_mlt(const SPMAT *A, const SPMAT *B, SPMAT *out)
  807. {
  808. int i, j, k, idx, cp;
  809. SPROW *rA, *rB, *rout, *rtemp;
  810. double valA;
  811. if ( ! A || ! B )
  812. error(E_NULL,"sp_mlt");
  813. if ( A->n != B->m )
  814. error(E_SIZES,"sp_mlt");
  815. out = sp_resize(out,A->m,B->n);
  816. sp_zero(out);
  817. rtemp = sprow_get(B->n);
  818. for ( i = 0; i < A->m; i++ ) /* per ogni riga */
  819. {
  820. rtemp = sprow_resize(rtemp,0,TYPE_SPROW);
  821. rA = &(A->row[i]);
  822. rout = &(out->row[i]);
  823. for ( idx = 0; idx < rA->len; idx++ ) /* per ogni elemento != 0
  824. della riga corrente */
  825. {
  826. j = rA->elt[idx].col;
  827. valA = rA->elt[idx].val;
  828. rB = &(B->row[j]);
  829. sprow_mltadd(rtemp,rB,valA,0,rout,TYPE_SPMAT);
  830. for ( cp = 0; cp < rout->len; cp++ )
  831. {
  832. rtemp->elt[cp].col = rout->elt[cp].col;
  833. rtemp->elt[cp].val = rout->elt[cp].val;
  834. }
  835. rtemp->len=rout->len;
  836. }
  837. }
  838. return out;
  839. }
  840. /* varying number of arguments */
  841. #ifdef ANSI_C
  842. /* To allocate memory to many arguments.
  843. The function should be called:
  844. sp_get_vars(m,n,deg,&x,&y,&z,...,NULL);
  845. where
  846. int m,n,deg;
  847. SPMAT *x, *y, *z,...;
  848. The last argument should be NULL !
  849. m x n is the dimension of matrices x,y,z,...
  850. returned value is equal to the number of allocated variables
  851. */
  852. int sp_get_vars(int m,int n,int deg,...)
  853. {
  854. va_list ap;
  855. int i=0;
  856. SPMAT **par;
  857. va_start(ap, deg);
  858. while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/
  859. *par = sp_get(m,n,deg);
  860. i++;
  861. }
  862. va_end(ap);
  863. return i;
  864. }
  865. /* To resize memory for many arguments.
  866. The function should be called:
  867. sp_resize_vars(m,n,&x,&y,&z,...,NULL);
  868. where
  869. int m,n;
  870. SPMAT *x, *y, *z,...;
  871. The last argument should be NULL !
  872. m X n is the resized dimension of matrices x,y,z,...
  873. returned value is equal to the number of allocated variables.
  874. If one of x,y,z,.. arguments is NULL then memory is allocated to this
  875. argument.
  876. */
  877. int sp_resize_vars(int m,int n,...)
  878. {
  879. va_list ap;
  880. int i=0;
  881. SPMAT **par;
  882. va_start(ap, n);
  883. while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/
  884. *par = sp_resize(*par,m,n);
  885. i++;
  886. }
  887. va_end(ap);
  888. return i;
  889. }
  890. /* To deallocate memory for many arguments.
  891. The function should be called:
  892. sp_free_vars(&x,&y,&z,...,NULL);
  893. where
  894. SPMAT *x, *y, *z,...;
  895. The last argument should be NULL !
  896. There must be at least one not NULL argument.
  897. returned value is equal to the number of allocated variables.
  898. Returned value of x,y,z,.. is VNULL.
  899. */
  900. int sp_free_vars(SPMAT **va,...)
  901. {
  902. va_list ap;
  903. int i=1;
  904. SPMAT **par;
  905. sp_free(*va);
  906. *va = (SPMAT *) NULL;
  907. va_start(ap, va);
  908. while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/
  909. sp_free(*par);
  910. *par = (SPMAT *)NULL;
  911. i++;
  912. }
  913. va_end(ap);
  914. return i;
  915. }
  916. #elif VARARGS
  917. /* To allocate memory to many arguments.
  918. The function should be called:
  919. sp_get_vars(m,n,deg,&x,&y,&z,...,NULL);
  920. where
  921. int m,n,deg;
  922. SPMAT *x, *y, *z,...;
  923. The last argument should be NULL !
  924. m x n is the dimension of matrices x,y,z,...
  925. returned value is equal to the number of allocated variables
  926. */
  927. int sp_get_vars(va_alist) va_dcl
  928. {
  929. va_list ap;
  930. int i=0, m, n, deg;
  931. SPMAT **par;
  932. va_start(ap);
  933. m = va_arg(ap,int);
  934. n = va_arg(ap,int);
  935. deg = va_arg(ap,int);
  936. while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/
  937. *par = sp_get(m,n,deg);
  938. i++;
  939. }
  940. va_end(ap);
  941. return i;
  942. }
  943. /* To resize memory for many arguments.
  944. The function should be called:
  945. sp_resize_vars(m,n,&x,&y,&z,...,NULL);
  946. where
  947. int m,n;
  948. SPMAT *x, *y, *z,...;
  949. The last argument should be NULL !
  950. m X n is the resized dimension of matrices x,y,z,...
  951. returned value is equal to the number of allocated variables.
  952. If one of x,y,z,.. arguments is NULL then memory is allocated to this
  953. argument.
  954. */
  955. int sp_resize_vars(va_alist) va_dcl
  956. {
  957. va_list ap;
  958. int i=0, m, n;
  959. SPMAT **par;
  960. va_start(ap);
  961. m = va_arg(ap,int);
  962. n = va_arg(ap,int);
  963. while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/
  964. *par = sp_resize(*par,m,n);
  965. i++;
  966. }
  967. va_end(ap);
  968. return i;
  969. }
  970. /* To deallocate memory for many arguments.
  971. The function should be called:
  972. sp_free_vars(&x,&y,&z,...,NULL);
  973. where
  974. SPMAT *x, *y, *z,...;
  975. The last argument should be NULL !
  976. There must be at least one not NULL argument.
  977. returned value is equal to the number of allocated variables.
  978. Returned value of x,y,z,.. is VNULL.
  979. */
  980. int sp_free_vars(va_alist) va_dcl
  981. {
  982. va_list ap;
  983. int i=0;
  984. SPMAT **par;
  985. va_start(ap);
  986. while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/
  987. sp_free(*par);
  988. *par = (SPMAT *)NULL;
  989. i++;
  990. }
  991. va_end(ap);
  992. return i;
  993. }
  994. #endif