PageRenderTime 44ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mesch/sparse.c

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