PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/R2004-02-12/octave-forge/main/sparse/sparse_ops.h

#
C Header | 563 lines | 380 code | 18 blank | 165 comment | 110 complexity | e266b8bb3b592dbc6e7c8ecc6ceeccd3 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, GPL-3.0, LGPL-3.0
  1. /*
  2. Copyright (C) 1999 Andy Adler
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with Octave; see the file COPYING. If not, write to the Free
  13. Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. $Id: sparse_ops.h 1208 2003-12-22 15:13:23Z pkienzle $
  15. $Log$
  16. Revision 1.11 2003/12/22 15:13:23 pkienzle
  17. Use error/return rather than SP_FATAL_ERROR where possible.
  18. Test for zero elements from scalar multiply/power and shrink sparse
  19. accordingly; accomodate libstdc++ bugs with mixed real/complex power.
  20. Revision 1.10 2003/10/13 03:44:26 aadler
  21. check for out of bounds in allocation
  22. Revision 1.9 2003/04/03 22:06:41 aadler
  23. sparse create bug - need to use heap for large temp vars
  24. Revision 1.8 2003/02/20 23:03:59 pkienzle
  25. Use of "T x[n]" where n is not constant is a g++ extension so replace it with
  26. OCTAVE_LOCAL_BUFFER(T,x,n), and other things to keep the picky MipsPRO CC
  27. compiler happy.
  28. Revision 1.7 2002/12/25 01:33:00 aadler
  29. fixed bug which allowed zero values to be stored in sparse matrices.
  30. improved print output
  31. Revision 1.6 2002/11/27 04:46:42 pkienzle
  32. Use new exception handling infrastructure.
  33. Revision 1.5 2002/01/04 15:53:57 pkienzle
  34. Changes required to compile for gcc-3.0 in debian hppa/unstable
  35. Revision 1.4 2001/11/04 19:54:49 aadler
  36. fix bug with multiple entries in sparse creation.
  37. Added "summation" mode for matrix creation
  38. Revision 1.3 2001/10/14 03:06:31 aadler
  39. fixed memory leak in complex sparse solve
  40. fixed malloc bugs for zero size allocs
  41. Revision 1.2 2001/10/12 02:24:28 aadler
  42. Mods to fix bugs
  43. add support for all zero sparse matrices
  44. add support fom complex sparse inverse
  45. Revision 1.2 2001/04/04 02:13:46 aadler
  46. complete complex_sparse, templates, fix memory leaks
  47. Revision 1.1 2001/03/30 04:34:23 aadler
  48. "template" functions for sparse operations
  49. */
  50. // I would like to do this with templates,
  51. // but I don't think you can specify operators
  52. //
  53. // TYPX -> output type ( Complex or double)
  54. // _OP_ -> operation to implement ( + , - , != , .* )
  55. // A_B_INTERACT -> evaluate operations where A or B ==0
  56. //
  57. // I'm assuming that compiler optimization will remove
  58. // the if (0) and x+0 operations
  59. #define SPARSE_EL_OP( TYPX, _OP_, A_B_INTERACT ) \
  60. SuperMatrix X; \
  61. if ( (Anc != Bnc) || (Anr != Bnr) ) { \
  62. gripe_nonconformant ("operator " #_OP_, Anr, Anc, Bnr, Bnc); \
  63. } else { \
  64. assert(Anr == Bnr); assert(Anc == Bnc); \
  65. TYPX* coefX= (TYPX*)oct_sparse_malloc( nnz * sizeof(TYPX)); \
  66. int * ridxX= (int *)oct_sparse_malloc( nnz * sizeof(int) ); \
  67. int * cidxX= (int *)oct_sparse_malloc((Anc+1)*sizeof(int)); cidxX[0]= 0; \
  68. \
  69. int jx= 0; \
  70. for (int i= 0 ; i < Anc ; i++ ) { \
  71. int ja= cidxA[ i ]; \
  72. int ja_max= cidxA[ i+1 ]; \
  73. bool ja_lt_max= ja < ja_max; \
  74. \
  75. int jb= cidxB[ i ]; \
  76. int jb_max= cidxB[ i+1 ]; \
  77. bool jb_lt_max= jb < jb_max; \
  78. \
  79. while( ja_lt_max || jb_lt_max ) { \
  80. OCTAVE_QUIT; \
  81. if( ( !jb_lt_max ) || \
  82. ( ja_lt_max && (ridxA[ja] < ridxB[jb]) ) ) \
  83. { \
  84. if (A_B_INTERACT) { \
  85. ridxX[ jx ] = ridxA[ja]; \
  86. coefX[ jx ] = coefA[ ja ] _OP_ 0.0; \
  87. jx++; \
  88. } \
  89. ja++; ja_lt_max= ja < ja_max; \
  90. } else \
  91. if( ( !ja_lt_max ) || \
  92. ( jb_lt_max && (ridxB[jb] < ridxA[ja]) ) ) \
  93. { \
  94. if (A_B_INTERACT) { \
  95. ridxX[ jx ] = ridxB[jb]; \
  96. coefX[ jx ] = 0.0 _OP_ coefB[ jb ]; \
  97. jx++; \
  98. } \
  99. jb++; jb_lt_max= jb < jb_max; \
  100. } else \
  101. { \
  102. assert( ridxA[ja] == ridxB[jb] ); \
  103. TYPX tmpval= coefA[ ja ] _OP_ coefB[ jb ]; \
  104. if (tmpval !=0.0) { \
  105. coefX[ jx ] = tmpval; \
  106. ridxX[ jx ] = ridxA[ja]; \
  107. jx++; \
  108. } \
  109. ja++; ja_lt_max= ja < ja_max; \
  110. jb++; jb_lt_max= jb < jb_max; \
  111. } \
  112. } \
  113. cidxX[i+1] = jx; \
  114. } \
  115. maybe_shrink( jx, nnz, ridxX, coefX ); \
  116. X= create_SuperMatrix( Anr, Anc, jx, coefX, ridxX, cidxX ); \
  117. }
  118. #define SPARSE_MATRIX_EL_OP( TYPX, _OP_ ) \
  119. SuperMatrix X; \
  120. if ( (Anc != Bnc) || (Anr != Bnr) ) { \
  121. gripe_nonconformant ("operator .*", Anr, Anc, Bnr, Bnc); \
  122. } else { \
  123. assert(Anr == Bnr); assert(Anc == Bnc); \
  124. TYPX* coefX= (TYPX*)oct_sparse_malloc( nnz * sizeof(TYPX)); \
  125. int * ridxX= (int *)oct_sparse_malloc( nnz * sizeof(int) ); \
  126. int * cidxX= (int *)oct_sparse_malloc((Anc+1)*sizeof(int)); cidxX[0]= 0; \
  127. \
  128. int cx= 0; \
  129. for (int i=0; i < Anc ; i++) { \
  130. for (int j= cidxA[i] ; \
  131. j< cidxA[i+1]; j++) { \
  132. OCTAVE_QUIT; \
  133. int rowidx = ridxA[j]; \
  134. TYPX tmpval = B(rowidx,i); \
  135. if (tmpval != 0.0) { \
  136. ridxX[ cx ] = rowidx; \
  137. coefX[ cx ] = tmpval * coefA[ j ]; \
  138. cx++; \
  139. } \
  140. } \
  141. cidxX[i+1] = cx; \
  142. } \
  143. maybe_shrink( cx, nnz, ridxX, coefX ); \
  144. X= create_SuperMatrix( Anr, Anc, cx, coefX, ridxX, cidxX ); \
  145. }
  146. // multiply type ops
  147. // TYPM is the output matrix type
  148. // TYPX is the sparse matrix type
  149. #define SPARSE_MATRIX_MUL( TYPM, TYPX) \
  150. TYPM X (Anr , Bnc); \
  151. if (Anc != Bnr) { \
  152. gripe_nonconformant ("operator *", Anr, Anc, Bnr, Bnc); \
  153. } else { \
  154. assert (Anc == Bnr); \
  155. for (int i=0; i< Anr; i++ ) \
  156. for (int j=0; j< Bnc; j++ ) \
  157. X.elem(i,j)=0.; \
  158. for ( int i=0; i < Anc ; i++) { \
  159. for ( int j= cidxA[i]; j< cidxA[i+1]; j++) { \
  160. OCTAVE_QUIT; \
  161. int col = ridxA[j]; \
  162. TYPX tmpval = coefA[j]; \
  163. for ( int k=0 ; k< Bnc; k++) { \
  164. X.elem(col , k)+= tmpval * B(i,k); \
  165. } \
  166. } \
  167. } \
  168. }
  169. #define MATRIX_SPARSE_MUL( TYPM, TYPX ) \
  170. TYPM X (Anr , Bnc); \
  171. if (Anc != Bnr) { \
  172. gripe_nonconformant ("operator *", Anr, Anc, Bnr, Bnc); \
  173. } else { \
  174. assert (Anc == Bnr); \
  175. for (int i=0; i< Anr; i++ ) \
  176. for (int j=0; j< Bnc; j++ ) \
  177. X.elem(i,j)=0.; \
  178. for ( int i=0; i < Bnc ; i++) { \
  179. for ( int j= cidxB[i]; j< cidxB[i+1]; j++) { \
  180. OCTAVE_QUIT; \
  181. int col = ridxB[j]; \
  182. TYPX tmpval = coefB[j]; \
  183. for ( int k=0 ; k< Anr; k++) { \
  184. X(k, i)+= A(k,col) * tmpval; \
  185. } \
  186. } \
  187. } \
  188. }
  189. //
  190. // Multiply sparse by sparse, element by element
  191. // This algorithm allocates a full column of the output
  192. // matrix. Hopefully that won't be a storage problem.
  193. //
  194. // TODO: allocate a row or column depending on the larger
  195. // dimention.
  196. //
  197. // I'm sure there are good sparse multiplication algorithms
  198. // available in the litterature. I invented this one
  199. // to fill a gap. Tell me if you know of better ones.
  200. //
  201. #define SPARSE_SPARSE_MUL( TYPX ) \
  202. SuperMatrix X; \
  203. if (Anc != Bnr) { \
  204. gripe_nonconformant ("operator *", Anr, Anc, Bnr, Bnc); \
  205. } else { \
  206. assert (Anc == Bnr ); \
  207. int nnz = NCFA->nnz + NCFB->nnz ; \
  208. TYPX* coefX= (TYPX*)oct_sparse_malloc( nnz * sizeof(TYPX)); \
  209. int * ridxX= (int *)oct_sparse_malloc( nnz * sizeof(int) ); \
  210. int * cidxX= (int *)oct_sparse_malloc((Bnc+1)*sizeof(int)); cidxX[0]= 0; \
  211. \
  212. TYPX * Xcol= (TYPX*)oct_sparse_malloc( Anr * sizeof(TYPX)); \
  213. int cx= 0; \
  214. for ( int i=0; i < Bnc ; i++) { \
  215. OCTAVE_QUIT; \
  216. for (int k=0; k<Anr; k++) Xcol[k]= 0.; \
  217. for (int j= cidxB[i]; j< cidxB[i+1]; j++) { \
  218. int col= ridxB[j]; \
  219. TYPX tmpval = coefB[j]; \
  220. for (int k= cidxA[col] ; k< cidxA[col+1]; k++) \
  221. Xcol[ ridxA[k] ]+= tmpval * coefA[k]; \
  222. } \
  223. for (int k=0; k<Anr; k++) { \
  224. if ( Xcol[k] !=0. ) { \
  225. check_bounds( cx, nnz, ridxX, coefX ); \
  226. ridxX[ cx ]= k; \
  227. coefX[ cx ]= Xcol[k]; \
  228. cx++; \
  229. } \
  230. } \
  231. cidxX[i+1] = cx; \
  232. } \
  233. free( Xcol ); \
  234. maybe_shrink( cx, nnz, ridxX, coefX ); \
  235. X= create_SuperMatrix( Anr, Bnc, cx, coefX, ridxX, cidxX ); \
  236. }
  237. // assemble a sparse matrix from elements
  238. // called by > 1 args for sparse
  239. // NOTE: index vectors are 1 based!
  240. //
  241. // NOTE2: be careful about when we convert ri to int,
  242. // otherwise the maximum matrix size will be m*n < maxint/2
  243. //
  244. // The OCTAVE_LOCAL_BUFFER can't be used for the sort index
  245. // when the requested size is too big. we need to put it on the
  246. // heap.
  247. #define ASSEMBLE_SPARSE( TYPX ) \
  248. int nnz= MAX( ridxA.length(), cidxA.length() ); \
  249. TYPX* coefX= (TYPX*)oct_sparse_malloc( nnz * sizeof(TYPX)); \
  250. int * ridxX= (int *)oct_sparse_malloc( nnz * sizeof(int) ); \
  251. int * cidxX= (int *)oct_sparse_malloc( (n+1)* sizeof(int)); cidxX[0]= 0; \
  252. \
  253. bool ri_scalar = (ridxA.length() == 1); \
  254. bool ci_scalar = (cidxA.length() == 1); \
  255. bool cf_scalar = (coefA.length() == 1); \
  256. \
  257. sort_idxl* sidx = (sort_idxl *)oct_sparse_malloc( nnz* sizeof(sort_idxl) );\
  258. int actual_nnz=0; \
  259. OCTAVE_QUIT; \
  260. for (int i=0; i<nnz; i++) { \
  261. double rowidx= ( ri_scalar ? ridxA(0) : ridxA(i) ) - 1; \
  262. double colidx= ( ci_scalar ? cidxA(0) : cidxA(i) ) - 1; \
  263. if (rowidx >= m || rowidx < 0) \
  264. error("sparse row index out of range"); \
  265. else if (colidx >= n || colidx < 0) \
  266. error("sparse column index out of range"); \
  267. if (error_state) { actual_nnz=0; break; } \
  268. if ( coefA(cf_scalar?0:i) != 0. ) { \
  269. sidx[actual_nnz].val = (long) ( rowidx + m*colidx ); \
  270. sidx[actual_nnz].idx = i; \
  271. actual_nnz++; \
  272. } \
  273. } \
  274. \
  275. OCTAVE_QUIT; \
  276. qsort( sidx, actual_nnz, sizeof(sort_idxl), sidxl_comp ); \
  277. \
  278. OCTAVE_QUIT; \
  279. int cx= 0; \
  280. long prev_val=-1; \
  281. int ii= -1; \
  282. for (int i=0; i<actual_nnz; i++) { \
  283. OCTAVE_QUIT; \
  284. long idx= (long) sidx[i].idx; \
  285. long val= (long) sidx[i].val; \
  286. if (prev_val < val) { \
  287. ii++; \
  288. coefX[ii]= ( cf_scalar ? coefA(0) : coefA(idx) ); \
  289. double ri = ( ri_scalar ? ridxA(0) : ridxA(idx) ) - 1 ; \
  290. ridxX[ii]= (long) (ri - ((long) (ri/m))*m ) ; \
  291. long ci = (long)( ci_scalar ? cidxA(0) : cidxA(idx) ) - 1 ; \
  292. while( cx < ci ) cidxX[++cx]= ii; \
  293. } else { \
  294. if (assemble_do_sum) \
  295. coefX[ii]+= ( cf_scalar ? coefA(0) : coefA(idx) ); \
  296. else \
  297. coefX[ii] = ( cf_scalar ? coefA(0) : coefA(idx) ); \
  298. } \
  299. prev_val= val;\
  300. } \
  301. while( cx < n ) cidxX[++cx]= ii+1; \
  302. OCTAVE_QUIT; \
  303. maybe_shrink( ii+1, actual_nnz, ridxX, coefX ); \
  304. \
  305. OCTAVE_QUIT; \
  306. SuperMatrix X= create_SuperMatrix( m, n, ii+1, coefX, ridxX, cidxX ); \
  307. oct_sparse_free( sidx );
  308. // assemble a sparse matrix from full
  309. // called by one arg for sparse
  310. // start with an initial estimate for nnz and
  311. // work with it.
  312. #define MATRIX_TO_SPARSE( TYPX ) \
  313. int nnz= 100; \
  314. TYPX * coef = (TYPX *) oct_sparse_malloc ( nnz * sizeof(TYPX) ); \
  315. int * ridx = (int *) oct_sparse_malloc ( nnz * sizeof(int) ); \
  316. int * cidx = (int *) oct_sparse_malloc ((Anc+1)* sizeof(int) ); cidx[0]= 0; \
  317. int jx=0; \
  318. for (int j= 0; j<Anc ; j++ ) { \
  319. for (int i= 0; i<Anr ; i++ ) { \
  320. OCTAVE_QUIT; \
  321. TYPX tmpval= A(i,j); \
  322. if (tmpval != 0.) { \
  323. check_bounds( jx, nnz, ridx, coef ); \
  324. ridx[ jx ]= i; \
  325. coef[ jx ]= tmpval; \
  326. jx++; \
  327. } \
  328. } \
  329. cidx[j+1]= jx; \
  330. } \
  331. maybe_shrink( jx, nnz, ridx, coef ); \
  332. SuperMatrix X= create_SuperMatrix( Anr, Anc, jx, coef, ridx, cidx );
  333. //
  334. // Next three functions
  335. //
  336. // Fix the row ordering problems that
  337. // LUExtract seems to cause
  338. // NOTE: we don't try to fix other structural errors
  339. // in the generated matrices, but we bail out
  340. // if we find any. This should work since I
  341. // haven't seen any problems other than ordering
  342. //
  343. // NOTE: The right way to fix this, of course, is to
  344. // track down the bug in the superlu codebase.
  345. // define a struct and qsort
  346. // comparison function to do the reordering
  347. #define FIX_ROW_ORDER_SORT_FUNCTIONS( TYPE ) \
  348. typedef struct { unsigned int idx; \
  349. TYPE val; } fixrow_sort; \
  350. static inline int \
  351. fixrow_comp( const void *i, const void *j) \
  352. { \
  353. return ((fixrow_sort *) i)->idx - \
  354. ((fixrow_sort *) j)->idx ; \
  355. }
  356. // this define ends function like
  357. // void
  358. // fix_row_order ## TYPE( SuperMatrix X )
  359. // {
  360. // DEBUGMSG("fix_row_order");
  361. // DEFINE_SP_POINTERS_REAL( X )
  362. // FIX_ROW_ORDER_FUNCTIONS( TYPE )
  363. // }
  364. #define FIX_ROW_ORDER_FUNCTIONS \
  365. for ( int i=0; i < Xnr ; i++) { \
  366. OCTAVE_QUIT; \
  367. assert( cidxX[i] >= 0.); \
  368. assert( cidxX[i] <= NCFX->nnz); \
  369. assert( cidxX[i] <= cidxX[i+1]); \
  370. int reorder=0; \
  371. for( int j= cidxX[i]; \
  372. j< cidxX[i+1]; \
  373. j++ ) { \
  374. assert( ridxX[j] >= 0.); \
  375. assert( ridxX[j] < Xnc); \
  376. assert( coefX[j] != 0.); /* don't keep zero values */ \
  377. if (j> cidxX[i]) \
  378. if ( ridxX[j-1] > ridxX[j] ) \
  379. reorder=1; \
  380. } /* for j */ \
  381. if(reorder) { \
  382. int snum= cidxX[i+1] - cidxX[i]; \
  383. OCTAVE_LOCAL_BUFFER (fixrow_sort, arry, snum); \
  384. /* copy to the sort struct */ \
  385. for( int k=0, \
  386. j= cidxX[i]; \
  387. j< cidxX[i+1]; \
  388. j++ ) { \
  389. arry[k].idx= ridxX[j]; \
  390. arry[k].val= coefX[j]; \
  391. k++; \
  392. } \
  393. OCTAVE_QUIT; \
  394. qsort( arry, snum, sizeof(fixrow_sort), fixrow_comp ); \
  395. OCTAVE_QUIT; \
  396. /* copy back to the position */ \
  397. for( int k=0, \
  398. j= cidxX[i]; \
  399. j< cidxX[i+1]; \
  400. j++ ) { \
  401. ridxX[j]= arry[k].idx; \
  402. coefX[j]= arry[k].val; \
  403. k++; \
  404. } \
  405. } \
  406. } // for i
  407. // endof FIX_ROW_ORDER_FUNCTIONS
  408. // calculate the inverse of an
  409. // upper triangular sparse matrix
  410. //
  411. // iUt = inv(U)
  412. // Note that the transpose is returned
  413. //
  414. // CODE:
  415. //
  416. // note that the input matrix is accesses in
  417. // row major order, and the output is accessed
  418. // in column major. This is the reason that the
  419. // output matrix is the transpose of the input
  420. //
  421. // I= eye( size(A) );
  422. // for n=1:N # across
  423. // for m= n+1:N # down
  424. // v=0;
  425. // for i= m-1:-1:n
  426. // v=v- A(m,i)*I(i,n);
  427. // end
  428. // I(m,n)= v/A(m,m);
  429. // end
  430. // I(:,n)= I(:,n)/A(n,n); <- for non unit norm
  431. // end
  432. //
  433. // we need to be careful here,
  434. // U is uppertriangular, but we're treating
  435. // it as though it is a lower triag matrix in NR form
  436. //
  437. // debug code
  438. // printf("n=%d, m=%d, X[%d]=%7.4f U[%d]=%7.4f cXp=%d cUp=%d v=%7.4f\n",
  439. // n,m, rpX, coefX[ scolXp ], rpU, coefU[ scolUp ],
  440. // scolXp,scolUp, v);
  441. #if 0
  442. // this is a pain - we can't use c++ constructors because
  443. // dmalloc complains when they're free'd
  444. int * ridxX = new int [nnz]; \
  445. TYPE* coefX = new TYPE [nnz]; \
  446. int * cidxX = new int [Unc+1]; \
  447. #endif
  448. #define SPARSE_INV_UPPERTRIANG( TYPE ) \
  449. assert ( Unc == Unr ); \
  450. /* estimate inverse nnz= input nnz */ \
  451. int nnz = NCFU->nnz; \
  452. int * ridxX = (int * ) oct_sparse_malloc ( sizeof(int) *nnz); \
  453. TYPE* coefX = (TYPE* ) oct_sparse_malloc ( sizeof(TYPE)*nnz); \
  454. int * cidxX = (int * ) oct_sparse_malloc ( sizeof(int )*(Unc+1)); \
  455. \
  456. int cx= 0; \
  457. \
  458. /* iterate accross columns of output matrix */ \
  459. for ( int n=0; n < Unr ; n++) { \
  460. OCTAVE_QUIT; \
  461. /* place the 1 in the identity position */ \
  462. int cx_colstart= cx; \
  463. \
  464. cidxX[n]= cx; \
  465. check_bounds( cx, nnz, ridxX, coefX ); \
  466. ridxX[cx]= n; \
  467. coefX[cx]= 1.0; \
  468. cx++; \
  469. \
  470. /* iterate accross columns of input matrix */ \
  471. for ( int m= n+1; m< Unr; m++) { \
  472. TYPE v=0.; \
  473. /* iterate to calculate sum */ \
  474. int colXp= cidxX[n]; \
  475. int colUp= cidxU[m]; \
  476. \
  477. int rpX, rpU; \
  478. do { \
  479. OCTAVE_QUIT; \
  480. rpX= ridxX [ colXp ]; \
  481. rpU= ridxU [ colUp ]; \
  482. \
  483. if (rpX < rpU) { \
  484. colXp++; \
  485. } else \
  486. if (rpX > rpU) { \
  487. colUp++; \
  488. } else { \
  489. assert(rpX == rpU); \
  490. assert(rpX >= n); \
  491. \
  492. v-= coefX[ colXp ]*coefU[ colUp ]; \
  493. colXp++; \
  494. colUp++; \
  495. } \
  496. \
  497. } while ((rpX<m) && (rpU<m) && (colXp<cx) && (colUp<nnzU)); \
  498. \
  499. /* get A(m,m) */ \
  500. colUp= cidxU[m+1]-1; \
  501. assert (ridxU[ colUp ] == m ); /* assert U is upper triangular */ \
  502. \
  503. TYPE pivot= coefU[ colUp ]; \
  504. if (pivot == 0.) gripe_divide_by_zero (); \
  505. \
  506. if (v!=0.) { \
  507. check_bounds( cx, nnz, ridxX, coefX ); \
  508. ridxX[cx]= m; \
  509. coefX[cx]= v / pivot; \
  510. cx++; \
  511. } \
  512. } /* for m */ \
  513. \
  514. /* get A(m,m) */ \
  515. int colUp= cidxU[n+1]-1; \
  516. assert (ridxU[ colUp ] == n ); /* assert U upper triangular */ \
  517. TYPE pivot= coefU[ colUp ]; \
  518. if (pivot == 0.) gripe_divide_by_zero (); \
  519. \
  520. if (pivot!=1.0) \
  521. for( int i= cx_colstart; i< cx; i++) \
  522. coefX[i]/= pivot; \
  523. } /* for n */ \
  524. cidxX[Unr]= cx; \
  525. maybe_shrink( cx, nnz, ridxX, coefX );