NEURON
spchfctr.c
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 /**************************************************************************
4 **
5 ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
6 **
7 ** Meschach Library
8 **
9 ** This Meschach Library is provided "as is" without any express
10 ** or implied warranty of any kind with respect to this software.
11 ** In particular the authors shall not be liable for any direct,
12 ** indirect, special, incidental or consequential damages arising
13 ** in any way from use of the software.
14 **
15 ** Everyone is granted permission to copy, modify and redistribute this
16 ** Meschach Library, provided:
17 ** 1. All copies contain this copyright notice.
18 ** 2. All modified copies shall carry a notice stating who
19 ** made the last modification and the date of such modification.
20 ** 3. No charge is made for this software or works derived from it.
21 ** This clause shall not be construed as constraining other software
22 ** distributed on the same medium as this software, nor is a
23 ** distribution fee considered a charge.
24 **
25 ***************************************************************************/
26 
27 
28 /*
29  Sparse Cholesky factorisation code
30  To be used with sparse.h, sparse.c etc
31 
32 */
33 
34 static char rcsid[] = "spchfctr.c,v 1.1 1997/12/04 17:55:51 hines Exp";
35 
36 #include <stdio.h>
37 #include "sparse2.h"
38 #include <math.h>
39 
40 
41 #ifndef MALLOCDECL
42 #ifndef ANSI_C
43 extern char *calloc(), *realloc();
44 #endif
45 #endif
46 
47 
48 
49 /* sprow_ip -- finds the (partial) inner product of a pair of sparse rows
50  -- uses a "merging" approach & assumes column ordered rows
51  -- row indices for inner product are all < lim */
52 double sprow_ip(row1, row2, lim)
53 SPROW *row1, *row2;
54 int lim;
55 {
56  int idx1, idx2, len1, len2, tmp;
57  int sprow_idx();
58  register row_elt *elts1, *elts2;
59  register Real sum;
60 
61  elts1 = row1->elt; elts2 = row2->elt;
62  len1 = row1->len; len2 = row2->len;
63 
64  sum = 0.0;
65 
66  if ( len1 <= 0 || len2 <= 0 )
67  return 0.0;
68  if ( elts1->col >= lim || elts2->col >= lim )
69  return 0.0;
70 
71  /* use sprow_idx() to speed up inner product where one row is
72  much longer than the other */
73  idx1 = idx2 = 0;
74  if ( len1 > 2*len2 )
75  {
76  idx1 = sprow_idx(row1,elts2->col);
77  idx1 = (idx1 < 0) ? -(idx1+2) : idx1;
78  if ( idx1 < 0 )
79  error(E_UNKNOWN,"sprow_ip");
80  len1 -= idx1;
81  }
82  else if ( len2 > 2*len1 )
83  {
84  idx2 = sprow_idx(row2,elts1->col);
85  idx2 = (idx2 < 0) ? -(idx2+2) : idx2;
86  if ( idx2 < 0 )
87  error(E_UNKNOWN,"sprow_ip");
88  len2 -= idx2;
89  }
90  if ( len1 <= 0 || len2 <= 0 )
91  return 0.0;
92 
93  elts1 = &(elts1[idx1]); elts2 = &(elts2[idx2]);
94 
95 
96  for ( ; ; ) /* forever do... */
97  {
98  if ( (tmp=elts1->col-elts2->col) < 0 )
99  {
100  len1--; elts1++;
101  if ( ! len1 || elts1->col >= lim )
102  break;
103  }
104  else if ( tmp > 0 )
105  {
106  len2--; elts2++;
107  if ( ! len2 || elts2->col >= lim )
108  break;
109  }
110  else
111  {
112  sum += elts1->val * elts2->val;
113  len1--; elts1++;
114  len2--; elts2++;
115  if ( ! len1 || ! len2 ||
116  elts1->col >= lim || elts2->col >= lim )
117  break;
118  }
119  }
120 
121  return sum;
122 }
123 
124 /* sprow_sqr -- returns same as sprow_ip(row, row, lim) */
125 double sprow_sqr(row, lim)
126 SPROW *row;
127 int lim;
128 {
129  register row_elt *elts;
130  int idx, len;
131  register Real sum, tmp;
132 
133  sum = 0.0;
134  elts = row->elt; len = row->len;
135  for ( idx = 0; idx < len; idx++, elts++ )
136  {
137  if ( elts->col >= lim )
138  break;
139  tmp = elts->val;
140  sum += tmp*tmp;
141  }
142 
143  return sum;
144 }
145 
146 static int *scan_row = (int *)NULL, *scan_idx = (int *)NULL,
147  *col_list = (int *)NULL;
148 static int scan_len = 0;
149 
150 /* set_scan -- expand scan_row and scan_idx arrays
151  -- return new length */
152 int set_scan(new_len)
153 int new_len;
154 {
155  if ( new_len <= scan_len )
156  return scan_len;
157  if ( new_len <= scan_len+5 )
158  new_len += 5;
159 
160  if ( ! scan_row || ! scan_idx || ! col_list )
161  {
162  scan_row = (int *)calloc(new_len,sizeof(int));
163  scan_idx = (int *)calloc(new_len,sizeof(int));
164  col_list = (int *)calloc(new_len,sizeof(int));
165  }
166  else
167  {
168  scan_row = (int *)realloc((char *)scan_row,new_len*sizeof(int));
169  scan_idx = (int *)realloc((char *)scan_idx,new_len*sizeof(int));
170  col_list = (int *)realloc((char *)col_list,new_len*sizeof(int));
171  }
172 
173  if ( ! scan_row || ! scan_idx || ! col_list )
174  error(E_MEM,"set_scan");
175  return new_len;
176 }
177 
178 /* spCHfactor -- sparse Cholesky factorisation
179  -- only the lower triangular part of A (incl. diagonal) is used */
181 SPMAT *A;
182 {
183  register int i;
184  int idx, k, m, minim, n, num_scan, diag_idx, tmp1;
185  Real pivot, tmp2;
186  SPROW *r_piv, *r_op;
187  row_elt *elt_piv, *elt_op, *old_elt;
188 
189  if ( A == SMNULL )
190  error(E_NULL,"spCHfactor");
191  if ( A->m != A->n )
192  error(E_SQUARE,"spCHfactor");
193 
194  /* set up access paths if not already done so */
195  sp_col_access(A);
196  sp_diag_access(A);
197 
198  /* printf("spCHfactor() -- checkpoint 1\n"); */
199  m = A->m; n = A->n;
200  for ( k = 0; k < m; k++ )
201  {
202  r_piv = &(A->row[k]);
203  if ( r_piv->len > scan_len )
204  set_scan(r_piv->len);
205  elt_piv = r_piv->elt;
206  diag_idx = sprow_idx2(r_piv,k,r_piv->diag);
207  if ( diag_idx < 0 )
208  error(E_POSDEF,"spCHfactor");
209  old_elt = &(elt_piv[diag_idx]);
210  for ( i = 0; i < r_piv->len; i++ )
211  {
212  if ( elt_piv[i].col > k )
213  break;
214  col_list[i] = elt_piv[i].col;
215  scan_row[i] = elt_piv[i].nxt_row;
216  scan_idx[i] = elt_piv[i].nxt_idx;
217  }
218  /* printf("spCHfactor() -- checkpoint 2\n"); */
219  num_scan = i; /* number of actual entries in scan_row etc. */
220  /* printf("num_scan = %d\n",num_scan); */
221 
222  /* set diagonal entry of Cholesky factor */
223  tmp2 = elt_piv[diag_idx].val - sprow_sqr(r_piv,k);
224  if ( tmp2 <= 0.0 )
225  error(E_POSDEF,"spCHfactor");
226  elt_piv[diag_idx].val = pivot = sqrt(tmp2);
227 
228  /* now set the k-th column of the Cholesky factors */
229  /* printf("k = %d\n",k); */
230  for ( ; ; ) /* forever do... */
231  {
232  /* printf("spCHfactor() -- checkpoint 3\n"); */
233  /* find next row where something (non-trivial) happens
234  i.e. find min(scan_row) */
235  /* printf("scan_row: "); */
236  minim = n;
237  for ( i = 0; i < num_scan; i++ )
238  {
239  tmp1 = scan_row[i];
240  /* printf("%d ",tmp1); */
241  minim = ( tmp1 >= 0 && tmp1 < minim ) ? tmp1 : minim;
242  }
243  /* printf("minim = %d\n",minim); */
244  /* printf("col_list: "); */
245 /**********************************************************************
246  for ( i = 0; i < num_scan; i++ )
247  printf("%d ",col_list[i]);
248  printf("\n");
249 **********************************************************************/
250 
251  if ( minim >= n )
252  break; /* nothing more to do for this column */
253  r_op = &(A->row[minim]);
254  elt_op = r_op->elt;
255 
256  /* set next entry in column k of Cholesky factors */
257  idx = sprow_idx2(r_op,k,scan_idx[num_scan-1]);
258  if ( idx < 0 )
259  { /* fill-in */
260  sp_set_val(A,minim,k,
261  -sprow_ip(r_piv,r_op,k)/pivot);
262  /* in case a realloc() has occurred... */
263  elt_op = r_op->elt;
264  /* now set up column access path again */
265  idx = sprow_idx2(r_op,k,-(idx+2));
266  tmp1 = old_elt->nxt_row;
267  old_elt->nxt_row = minim;
268  r_op->elt[idx].nxt_row = tmp1;
269  tmp1 = old_elt->nxt_idx;
270  old_elt->nxt_idx = idx;
271  r_op->elt[idx].nxt_idx = tmp1;
272  }
273  else
274  elt_op[idx].val = (elt_op[idx].val -
275  sprow_ip(r_piv,r_op,k))/pivot;
276 
277  /* printf("spCHfactor() -- checkpoint 4\n"); */
278 
279  /* remember current element in column k for column chain */
280  idx = sprow_idx2(r_op,k,idx);
281  old_elt = &(r_op->elt[idx]);
282 
283  /* update scan_row */
284  /* printf("spCHfactor() -- checkpoint 5\n"); */
285  /* printf("minim = %d\n",minim); */
286  for ( i = 0; i < num_scan; i++ )
287  {
288  if ( scan_row[i] != minim )
289  continue;
290  idx = sprow_idx2(r_op,col_list[i],scan_idx[i]);
291  if ( idx < 0 )
292  { scan_row[i] = -1; continue; }
293  scan_row[i] = elt_op[idx].nxt_row;
294  scan_idx[i] = elt_op[idx].nxt_idx;
295  /* printf("scan_row[%d] = %d\n",i,scan_row[i]); */
296  /* printf("scan_idx[%d] = %d\n",i,scan_idx[i]); */
297  }
298 
299  }
300  /* printf("spCHfactor() -- checkpoint 6\n"); */
301  /* sp_dump(stdout,A); */
302  /* printf("\n\n\n"); */
303  }
304 
305  return A;
306 }
307 
308 /* spCHsolve -- solve L.L^T.out=b where L is a sparse matrix,
309  -- out, b dense vectors
310  -- returns out; operation may be in-situ */
311 VEC *spCHsolve(L,b,out)
312 SPMAT *L;
313 VEC *b, *out;
314 {
315  int i, j_idx, n, scan_idx, scan_row;
316  SPROW *row;
317  row_elt *elt;
318  Real diag_val, sum, *out_ve;
319 
320  if ( L == SMNULL || b == VNULL )
321  error(E_NULL,"spCHsolve");
322  if ( L->m != L->n )
323  error(E_SQUARE,"spCHsolve");
324  if ( b->dim != L->m )
325  error(E_SIZES,"spCHsolve");
326 
327  if ( ! L->flag_col )
328  sp_col_access(L);
329  if ( ! L->flag_diag )
330  sp_diag_access(L);
331 
332  out = v_copy(b,out);
333  out_ve = out->ve;
334 
335  /* forward substitution: solve L.x=b for x */
336  n = L->n;
337  for ( i = 0; i < n; i++ )
338  {
339  sum = out_ve[i];
340  row = &(L->row[i]);
341  elt = row->elt;
342  for ( j_idx = 0; j_idx < row->len; j_idx++, elt++ )
343  {
344  if ( elt->col >= i )
345  break;
346  sum -= elt->val*out_ve[elt->col];
347  }
348  if ( row->diag >= 0 )
349  out_ve[i] = sum/(row->elt[row->diag].val);
350  else
351  error(E_SING,"spCHsolve");
352  }
353 
354  /* backward substitution: solve L^T.out = x for out */
355  for ( i = n-1; i >= 0; i-- )
356  {
357  sum = out_ve[i];
358  row = &(L->row[i]);
359  /* Note that row->diag >= 0 by above loop */
360  elt = &(row->elt[row->diag]);
361  diag_val = elt->val;
362 
363  /* scan down column */
364  scan_idx = elt->nxt_idx;
365  scan_row = elt->nxt_row;
366  while ( scan_row >= 0 /* && scan_idx >= 0 */ )
367  {
368  row = &(L->row[scan_row]);
369  elt = &(row->elt[scan_idx]);
370  sum -= elt->val*out_ve[scan_row];
371  scan_idx = elt->nxt_idx;
372  scan_row = elt->nxt_row;
373  }
374  out_ve[i] = sum/diag_val;
375  }
376 
377  return out;
378 }
379 
380 /* spICHfactor -- sparse Incomplete Cholesky factorisation
381  -- does a Cholesky factorisation assuming NO FILL-IN
382  -- as for spCHfactor(), only the lower triangular part of A is used */
384 SPMAT *A;
385 {
386  int k, m, n, nxt_row, nxt_idx, diag_idx;
387  Real pivot, tmp2;
388  SPROW *r_piv, *r_op;
389  row_elt *elt_piv, *elt_op;
390 
391  if ( A == SMNULL )
392  error(E_NULL,"spICHfactor");
393  if ( A->m != A->n )
394  error(E_SQUARE,"spICHfactor");
395 
396  /* set up access paths if not already done so */
397  if ( ! A->flag_col )
398  sp_col_access(A);
399  if ( ! A->flag_diag )
400  sp_diag_access(A);
401 
402  m = A->m; n = A->n;
403  for ( k = 0; k < m; k++ )
404  {
405  r_piv = &(A->row[k]);
406 
407  diag_idx = r_piv->diag;
408  if ( diag_idx < 0 )
409  error(E_POSDEF,"spICHfactor");
410 
411  elt_piv = r_piv->elt;
412 
413  /* set diagonal entry of Cholesky factor */
414  tmp2 = elt_piv[diag_idx].val - sprow_sqr(r_piv,k);
415  if ( tmp2 <= 0.0 )
416  error(E_POSDEF,"spICHfactor");
417  elt_piv[diag_idx].val = pivot = sqrt(tmp2);
418 
419  /* find next row where something (non-trivial) happens */
420  nxt_row = elt_piv[diag_idx].nxt_row;
421  nxt_idx = elt_piv[diag_idx].nxt_idx;
422 
423  /* now set the k-th column of the Cholesky factors */
424  while ( nxt_row >= 0 && nxt_idx >= 0 )
425  {
426  /* nxt_row and nxt_idx give next next row (& index)
427  of the entry to be modified */
428  r_op = &(A->row[nxt_row]);
429  elt_op = r_op->elt;
430  elt_op[nxt_idx].val = (elt_op[nxt_idx].val -
431  sprow_ip(r_piv,r_op,k))/pivot;
432 
433  nxt_row = elt_op[nxt_idx].nxt_row;
434  nxt_idx = elt_op[nxt_idx].nxt_idx;
435  }
436  }
437 
438  return A;
439 }
440 
441 
442 /* spCHsymb -- symbolic sparse Cholesky factorisation
443  -- does NOT do any floating point arithmetic; just sets up the structure
444  -- only the lower triangular part of A (incl. diagonal) is used */
446 SPMAT *A;
447 {
448  register int i;
449  int idx, k, m, minim, n, num_scan, diag_idx, tmp1;
450  SPROW *r_piv, *r_op;
451  row_elt *elt_piv, *elt_op, *old_elt;
452 
453  if ( A == SMNULL )
454  error(E_NULL,"spCHsymb");
455  if ( A->m != A->n )
456  error(E_SQUARE,"spCHsymb");
457 
458  /* set up access paths if not already done so */
459  if ( ! A->flag_col )
460  sp_col_access(A);
461  if ( ! A->flag_diag )
462  sp_diag_access(A);
463 
464  /* printf("spCHsymb() -- checkpoint 1\n"); */
465  m = A->m; n = A->n;
466  for ( k = 0; k < m; k++ )
467  {
468  r_piv = &(A->row[k]);
469  if ( r_piv->len > scan_len )
470  set_scan(r_piv->len);
471  elt_piv = r_piv->elt;
472  diag_idx = sprow_idx2(r_piv,k,r_piv->diag);
473  if ( diag_idx < 0 )
474  error(E_POSDEF,"spCHsymb");
475  old_elt = &(elt_piv[diag_idx]);
476  for ( i = 0; i < r_piv->len; i++ )
477  {
478  if ( elt_piv[i].col > k )
479  break;
480  col_list[i] = elt_piv[i].col;
481  scan_row[i] = elt_piv[i].nxt_row;
482  scan_idx[i] = elt_piv[i].nxt_idx;
483  }
484  /* printf("spCHsymb() -- checkpoint 2\n"); */
485  num_scan = i; /* number of actual entries in scan_row etc. */
486  /* printf("num_scan = %d\n",num_scan); */
487 
488  /* now set the k-th column of the Cholesky factors */
489  /* printf("k = %d\n",k); */
490  for ( ; ; ) /* forever do... */
491  {
492  /* printf("spCHsymb() -- checkpoint 3\n"); */
493  /* find next row where something (non-trivial) happens
494  i.e. find min(scan_row) */
495  minim = n;
496  for ( i = 0; i < num_scan; i++ )
497  {
498  tmp1 = scan_row[i];
499  /* printf("%d ",tmp1); */
500  minim = ( tmp1 >= 0 && tmp1 < minim ) ? tmp1 : minim;
501  }
502 
503  if ( minim >= n )
504  break; /* nothing more to do for this column */
505  r_op = &(A->row[minim]);
506  elt_op = r_op->elt;
507 
508  /* set next entry in column k of Cholesky factors */
509  idx = sprow_idx2(r_op,k,scan_idx[num_scan-1]);
510  if ( idx < 0 )
511  { /* fill-in */
512  sp_set_val(A,minim,k,0.0);
513  /* in case a realloc() has occurred... */
514  elt_op = r_op->elt;
515  /* now set up column access path again */
516  idx = sprow_idx2(r_op,k,-(idx+2));
517  tmp1 = old_elt->nxt_row;
518  old_elt->nxt_row = minim;
519  r_op->elt[idx].nxt_row = tmp1;
520  tmp1 = old_elt->nxt_idx;
521  old_elt->nxt_idx = idx;
522  r_op->elt[idx].nxt_idx = tmp1;
523  }
524 
525  /* printf("spCHsymb() -- checkpoint 4\n"); */
526 
527  /* remember current element in column k for column chain */
528  idx = sprow_idx2(r_op,k,idx);
529  old_elt = &(r_op->elt[idx]);
530 
531  /* update scan_row */
532  /* printf("spCHsymb() -- checkpoint 5\n"); */
533  /* printf("minim = %d\n",minim); */
534  for ( i = 0; i < num_scan; i++ )
535  {
536  if ( scan_row[i] != minim )
537  continue;
538  idx = sprow_idx2(r_op,col_list[i],scan_idx[i]);
539  if ( idx < 0 )
540  { scan_row[i] = -1; continue; }
541  scan_row[i] = elt_op[idx].nxt_row;
542  scan_idx[i] = elt_op[idx].nxt_idx;
543  /* printf("scan_row[%d] = %d\n",i,scan_row[i]); */
544  /* printf("scan_idx[%d] = %d\n",i,scan_idx[i]); */
545  }
546 
547  }
548  /* printf("spCHsymb() -- checkpoint 6\n"); */
549  }
550 
551  return A;
552 }
553 
554 /* comp_AAT -- compute A.A^T where A is a given sparse matrix */
556 SPMAT *A;
557 {
558  SPMAT *AAT;
559  SPROW *r, *r2;
560  row_elt *elts, *elts2;
561  int i, idx, idx2, j, m, minim, n, num_scan, tmp1;
562  Real ip;
563 
564  if ( ! A )
565  error(E_NULL,"comp_AAT");
566  m = A->m; n = A->n;
567 
568  /* set up column access paths */
569  if ( ! A->flag_col )
570  sp_col_access(A);
571 
572  AAT = sp_get(m,m,10);
573 
574  for ( i = 0; i < m; i++ )
575  {
576  /* initialisation */
577  r = &(A->row[i]);
578  elts = r->elt;
579 
580  /* set up scan lists for this row */
581  if ( r->len > scan_len )
582  set_scan(r->len);
583  for ( j = 0; j < r->len; j++ )
584  {
585  col_list[j] = elts[j].col;
586  scan_row[j] = elts[j].nxt_row;
587  scan_idx[j] = elts[j].nxt_idx;
588  }
589  num_scan = r->len;
590 
591  /* scan down the rows for next non-zero not
592  associated with a diagonal entry */
593  for ( ; ; )
594  {
595  minim = m;
596  for ( idx = 0; idx < num_scan; idx++ )
597  {
598  tmp1 = scan_row[idx];
599  minim = ( tmp1 >= 0 && tmp1 < minim ) ? tmp1 : minim;
600  }
601  if ( minim >= m )
602  break;
603  r2 = &(A->row[minim]);
604  if ( minim > i )
605  {
606  ip = sprow_ip(r,r2,n);
607  sp_set_val(AAT,minim,i,ip);
608  sp_set_val(AAT,i,minim,ip);
609  }
610  /* update scan entries */
611  elts2 = r2->elt;
612  for ( idx = 0; idx < num_scan; idx++ )
613  {
614  if ( scan_row[idx] != minim || scan_idx[idx] < 0 )
615  continue;
616  idx2 = scan_idx[idx];
617  scan_row[idx] = elts2[idx2].nxt_row;
618  scan_idx[idx] = elts2[idx2].nxt_idx;
619  }
620  }
621 
622  /* set the diagonal entry */
623  sp_set_val(AAT,i,i,sprow_sqr(r,n));
624  }
625 
626  return AAT;
627 }
628 
#define E_SQUARE
Definition: err.h:103
#define error(err_num, fn_name)
Definition: err.h:73
#define E_MEM
Definition: err.h:97
#define E_NULL
Definition: err.h:102
#define E_SING
Definition: err.h:98
#define E_UNKNOWN
Definition: err.h:94
#define E_SIZES
Definition: err.h:95
#define E_POSDEF
Definition: err.h:99
#define Real
Definition: machine.h:189
#define VNULL
Definition: matrix.h:631
#define v_copy(in, out)
Definition: matrix.h:404
#define i
Definition: md1redef.h:12
sqrt
Definition: extdef.h:3
#define A(i)
Definition: multisplit.cpp:63
static unsigned row
Definition: nonlin.cpp:85
int const size_t const size_t n
Definition: nrngsl.h:11
size_t j
static philox4x32_key_t k
Definition: nrnran123.cpp:11
double sp_set_val(SPMAT *A, int i, int j, double val)
Definition: sparse.c:66
SPMAT * sp_diag_access(SPMAT *A)
Definition: sparse.c:417
SPMAT * sp_get(int m, int n, int maxlen)
Definition: sparse.c:198
SPMAT * sp_col_access(SPMAT *A)
Definition: sparse.c:376
#define SMNULL
Definition: sparse.h:74
int sprow_idx(SPROW *, int)
Definition: sprow.c:75
#define sprow_idx2(r, c, hint)
Definition: sparse.h:78
static int * col_list
Definition: spchfctr.c:147
SPMAT * spCHsymb(SPMAT *A)
Definition: spchfctr.c:445
VEC * spCHsolve(SPMAT *L, VEC *b, VEC *out)
Definition: spchfctr.c:311
static int * scan_row
Definition: spchfctr.c:146
SPMAT * comp_AAT(SPMAT *A)
Definition: spchfctr.c:555
double sprow_ip(SPROW *row1, SPROW *row2, int lim)
Definition: spchfctr.c:52
SPMAT * spICHfactor(SPMAT *A)
Definition: spchfctr.c:383
double sprow_sqr(SPROW *row, int lim)
Definition: spchfctr.c:125
static int * scan_idx
Definition: spchfctr.c:146
static int scan_len
Definition: spchfctr.c:148
SPMAT * spCHfactor(SPMAT *A)
Definition: spchfctr.c:180
static char rcsid[]
Definition: spchfctr.c:34
int set_scan(int new_len)
Definition: spchfctr.c:152
#define NULL
Definition: sptree.h:16
Definition: sparse.h:54
Definition: sparse.h:49
int diag
Definition: sparse.h:50
int len
Definition: sparse.h:50
row_elt * elt
Definition: sparse.h:51
Definition: matrix.h:67
u_int dim
Definition: matrix.h:68
Real * ve
Definition: matrix.h:69
Definition: sparse.h:44
int nxt_row
Definition: sparse.h:45
int nxt_idx
Definition: sparse.h:45
int col
Definition: sparse.h:45
Real val
Definition: sparse.h:46