1
/* ========================================================================== */
2
/* === UMF_create_element =================================================== */
3
/* ========================================================================== */
5
/* -------------------------------------------------------------------------- */
6
/* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */
7
/* Davis. All Rights Reserved. See ../README for License. */
8
/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
9
/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
10
/* -------------------------------------------------------------------------- */
13
Factorization of a frontal matrix is complete. Create a new element for
14
later assembly into a subsequent frontal matrix. Returns TRUE if
15
successful, FALSE if out of memory.
18
#include "umf_internal.h"
19
#include "umf_mem_alloc_element.h"
20
#include "umf_mem_alloc_tail_block.h"
21
#include "umf_mem_free_tail_block.h"
22
#include "umf_get_memory.h"
24
/* ========================================================================== */
25
/* === copy_column ========================================================== */
26
/* ========================================================================== */
28
PRIVATE void copy_column (Int len, Entry *X, Entry *Y)
32
for (i = 0 ; i < len ; i++)
38
/* ========================================================================== */
39
/* === UMF_create_element =================================================== */
40
/* ========================================================================== */
42
GLOBAL Int UMF_create_element
46
SymbolicType *Symbolic
49
/* ---------------------------------------------------------------------- */
51
/* ---------------------------------------------------------------------- */
53
Int j, col, row, *Fcols, *Frows, fnrows, fncols, *Cols, len, needunits, t1,
54
t2, size, e, i, *E, *Fcpos, *Frpos, *Rows, eloc, fnr_curr, f,
55
got_memory, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, max_mark,
56
*Col_degree, *Col_tlen, nn, n_row, n_col, r2, c2, do_Fcpos ;
60
Tuple *tp, *tp1, *tp2, tuple, *tpend ;
62
DEBUG2 (("FRONTAL WRAPUP\n")) ;
63
UMF_dump_current_front (Numeric, Work, TRUE) ;
66
/* ---------------------------------------------------------------------- */
68
/* ---------------------------------------------------------------------- */
70
ASSERT (Work->fnpiv == 0) ;
71
ASSERT (Work->fnzeros == 0) ;
72
Row_degree = Numeric->Rperm ;
73
Row_tuples = Numeric->Uip ;
74
Row_tlen = Numeric->Uilen ;
75
Col_degree = Numeric->Cperm ;
76
Col_tuples = Numeric->Lip ;
77
Col_tlen = Numeric->Lilen ;
80
nn = MAX (n_row, n_col) ;
85
Memory = Numeric->Memory ;
86
fncols = Work->fncols ;
87
fnrows = Work->fnrows ;
90
tp1 = (Tuple *) NULL ;
91
tp2 = (Tuple *) NULL ;
93
/* ---------------------------------------------------------------------- */
94
/* add the current frontal matrix to the degrees of each column */
95
/* ---------------------------------------------------------------------- */
99
/* but only if the column ordering is not fixed */
101
for (j = 0 ; j < fncols ; j++)
103
/* add the current frontal matrix to the degree */
104
ASSERT (Fcols [j] >= 0 && Fcols [j] < n_col) ;
105
Col_degree [Fcols [j]] += fnrows ;
109
/* ---------------------------------------------------------------------- */
110
/* add the current frontal matrix to the degrees of each row */
111
/* ---------------------------------------------------------------------- */
114
for (i = 0 ; i < fnrows ; i++)
116
/* add the current frontal matrix to the degree */
117
ASSERT (Frows [i] >= 0 && Frows [i] < n_row) ;
118
Row_degree [Frows [i]] += fncols ;
121
/* ---------------------------------------------------------------------- */
122
/* Reset the external degree counters */
123
/* ---------------------------------------------------------------------- */
126
max_mark = MAX_MARK (nn) ;
128
if (!Work->pivcol_in_front)
130
/* clear the external column degrees. no more Usons of current front */
131
Work->cdeg0 += (nn + 1) ;
132
if (Work->cdeg0 >= max_mark)
134
/* guard against integer overflow. This is very rare */
135
DEBUG1 (("Integer overflow, cdeg\n")) ;
138
for (e = 1 ; e <= Work->nel ; e++)
142
ep = (Element *) (Memory + E [e]) ;
149
if (!Work->pivrow_in_front)
151
/* clear the external row degrees. no more Lsons of current front */
152
Work->rdeg0 += (nn + 1) ;
153
if (Work->rdeg0 >= max_mark)
155
/* guard against integer overflow. This is very rare */
156
DEBUG1 (("Integer overflow, rdeg\n")) ;
159
for (e = 1 ; e <= Work->nel ; e++)
163
ep = (Element *) (Memory + E [e]) ;
170
/* ---------------------------------------------------------------------- */
171
/* clear row/col offsets */
172
/* ---------------------------------------------------------------------- */
174
if (!Work->pivrow_in_front)
177
for (j = 0 ; j < fncols ; j++)
179
Fcpos [Fcols [j]] = EMPTY ;
183
if (!Work->pivcol_in_front)
186
for (i = 0 ; i < fnrows ; i++)
188
Frpos [Frows [i]] = EMPTY ;
192
if (fncols <= 0 || fnrows <= 0)
194
/* no element to create */
195
DEBUG2 (("Element evaporation\n")) ;
196
Work->prior_element = EMPTY ;
200
/* ---------------------------------------------------------------------- */
201
/* create element for later assembly */
202
/* ---------------------------------------------------------------------- */
205
UMF_allocfail = FALSE ;
208
double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
209
DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
210
UMF_allocfail = rrr < UMF_gprob ;
211
if (UMF_allocfail) DEBUGm2 (("Random garbage collection (create)\n"));
217
eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
220
/* if UMF_get_memory needs to be called */
223
/* full compaction of current frontal matrix, since UMF_grow_front will
224
* be called next anyway. */
231
/* partial compaction. */
232
r2 = MAX (fnrows, Work->fnrows_new + 1) ;
233
c2 = MAX (fncols, Work->fncols_new + 1) ;
234
/* recompute Fcpos if pivot row is in the front */
235
do_Fcpos = Work->pivrow_in_front ;
240
/* Do garbage collection, realloc, and try again. */
241
/* Compact the current front if it needs to grow anyway. */
242
/* Note that there are no pivot rows or columns in the current front */
243
DEBUGm3 (("get_memory from umf_create_element, 1\n")) ;
244
if (!UMF_get_memory (Numeric, Work, needunits, r2, c2, do_Fcpos))
246
/* :: out of memory in umf_create_element (1) :: */
247
DEBUGm4 (("out of memory: create element (1)\n")) ;
248
return (FALSE) ; /* out of memory */
251
Memory = Numeric->Memory ;
252
eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
257
/* :: out of memory in umf_create_element (2) :: */
258
DEBUGm4 (("out of memory: create element (2)\n")) ;
259
return (FALSE) ; /* out of memory */
263
e = ++(Work->nel) ; /* get the name of this new frontal matrix */
264
Work->prior_element = e ;
265
DEBUG8 (("wrapup e "ID" nel "ID"\n", e, Work->nel)) ;
267
ASSERT (e > 0 && e < Work->elen) ;
268
ASSERT (E [e] == 0) ;
271
if (Work->pivcol_in_front)
273
/* the new element is a Uson of the next frontal matrix */
274
ep->cdeg = Work->cdeg0 ;
277
if (Work->pivrow_in_front)
279
/* the new element is an Lson of the next frontal matrix */
280
ep->rdeg = Work->rdeg0 ;
283
/* ---------------------------------------------------------------------- */
284
/* copy frontal matrix into the new element */
285
/* ---------------------------------------------------------------------- */
288
for (i = 0 ; i < fnrows ; i++)
290
Rows [i] = Frows [i] ;
293
for (i = 0 ; i < fncols ; i++)
295
Cols [i] = Fcols [i] ;
297
Fcol = Work->Fcblock ;
298
DEBUG0 (("copy front "ID" by "ID"\n", fnrows, fncols)) ;
299
fnr_curr = Work->fnr_curr ;
300
ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ;
301
for (j = 0 ; j < fncols ; j++)
303
copy_column (fnrows, Fcol, C) ;
306
copy_column (fnrows, Fcol, C) ;
308
could also use BLAS-COPY (fnrows, Fcol, C) here, but it is typically
309
not as fast as the inlined copy_column subroutine, above.
311
for (i = 0 ; i < fnrows ; i++)
320
DEBUG8 (("element copied\n")) ;
322
/* ---------------------------------------------------------------------- */
323
/* add tuples for the new element */
324
/* ---------------------------------------------------------------------- */
331
/* ------------------------------------------------------------------ */
332
/* UMF_get_memory ensures enough space exists for each new tuple */
333
/* ------------------------------------------------------------------ */
335
/* place (e,f) in the element list of each column */
336
for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
338
col = Fcols [tuple.f] ;
339
ASSERT (col >= 0 && col < n_col) ;
340
ASSERT (NON_PIVOTAL_COL (col)) ;
341
ASSERT (Col_tuples [col]) ;
342
tp = ((Tuple *) (Memory + Col_tuples [col])) + Col_tlen [col]++ ;
346
/* ------------------------------------------------------------------ */
348
/* place (e,f) in the element list of each row */
349
for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
351
row = Frows [tuple.f] ;
352
ASSERT (row >= 0 && row < n_row) ;
353
ASSERT (NON_PIVOTAL_ROW (row)) ;
354
ASSERT (Row_tuples [row]) ;
355
tp = ((Tuple *) (Memory + Row_tuples [row])) + Row_tlen [row]++ ;
363
/* ------------------------------------------------------------------ */
364
/* place (e,f) in the element list of each column */
365
/* ------------------------------------------------------------------ */
367
/* might not have enough space for each tuple */
369
for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
371
col = Fcols [tuple.f] ;
372
ASSERT (col >= 0 && col < n_col) ;
373
ASSERT (NON_PIVOTAL_COL (col)) ;
374
t1 = Col_tuples [col] ;
375
DEBUG1 (("Placing on col:"ID" , tuples at "ID"\n",
376
col, Col_tuples [col])) ;
385
size = GET_BLOCK_SIZE (p) ;
386
len = Col_tlen [col] ;
390
needunits = UNITS (Tuple, len + 1) ;
391
DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
392
len, size, needunits));
394
if (needunits > size && t1)
396
/* prune the tuples */
400
for ( ; tp < tpend ; tp++)
403
ASSERT (e > 0 && e <= Work->nel) ;
404
if (!E [e]) continue ; /* element already deallocated */
408
p += UNITS (Element, 1) ;
411
if (Cols [f] == EMPTY) continue ; /* already assembled */
412
ASSERT (col == Cols [f]) ;
413
*tp2++ = *tp ; /* leave the tuple in the list */
416
Col_tlen [col] = len ;
417
needunits = UNITS (Tuple, len + 1) ;
420
if (needunits > size)
422
/* no room exists - reallocate elsewhere */
423
DEBUG1 (("REALLOCATE Col: "ID", size "ID" to "ID"\n",
424
col, size, 2*needunits)) ;
427
UMF_allocfail = FALSE ;
428
if (UMF_gprob > 0) /* a double relop, but ignore NaN case */
430
double rrr = ((double) (rand ( ))) /
431
(((double) RAND_MAX) + 1) ;
432
DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
433
UMF_allocfail = rrr < UMF_gprob ;
434
if (UMF_allocfail) DEBUGm2 (("Random gar. (col tuple)\n")) ;
438
needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
439
t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
442
/* :: get memory in umf_create_element (1) :: */
443
/* get memory, reconstruct all tuple lists, and return */
444
/* Compact the current front if it needs to grow anyway. */
445
/* Note: no pivot rows or columns in the current front */
446
DEBUGm4 (("get_memory from umf_create_element, 1\n")) ;
447
return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
449
Col_tuples [col] = t2 ;
450
tp2 = (Tuple *) (Memory + t2) ;
453
for (i = 0 ; i < len ; i++)
457
UMF_mem_free_tail_block (Numeric, t1) ;
461
/* place the new (e,f) tuple in the element list of the column */
466
/* ------------------------------------------------------------------ */
467
/* place (e,f) in the element list of each row */
468
/* ------------------------------------------------------------------ */
470
for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
472
row = Frows [tuple.f] ;
473
ASSERT (row >= 0 && row < n_row) ;
474
ASSERT (NON_PIVOTAL_ROW (row)) ;
475
t1 = Row_tuples [row] ;
476
DEBUG1 (("Placing on row:"ID" , tuples at "ID"\n",
477
row, Row_tuples [row])) ;
485
size = GET_BLOCK_SIZE (p) ;
486
len = Row_tlen [row] ;
490
needunits = UNITS (Tuple, len + 1) ;
491
DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
492
len, size, needunits)) ;
494
if (needunits > size && t1)
496
/* prune the tuples */
500
for ( ; tp < tpend ; tp++)
503
ASSERT (e > 0 && e <= Work->nel) ;
506
continue ; /* element already deallocated */
511
p += UNITS (Element, 1) ;
513
Rows = Cols + (ep->ncols) ;
514
if (Rows [f] == EMPTY) continue ; /* already assembled */
515
ASSERT (row == Rows [f]) ;
516
*tp2++ = *tp ; /* leave the tuple in the list */
519
Row_tlen [row] = len ;
520
needunits = UNITS (Tuple, len + 1) ;
523
if (needunits > size)
525
/* no room exists - reallocate elsewhere */
526
DEBUG1 (("REALLOCATE Row: "ID", size "ID" to "ID"\n",
527
row, size, 2*needunits)) ;
530
UMF_allocfail = FALSE ;
531
if (UMF_gprob > 0) /* a double relop, but ignore NaN case */
533
double rrr = ((double) (rand ( ))) /
534
(((double) RAND_MAX) + 1) ;
535
DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
536
UMF_allocfail = rrr < UMF_gprob ;
537
if (UMF_allocfail) DEBUGm2 (("Random gar. (row tuple)\n")) ;
541
needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
542
t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
545
/* :: get memory in umf_create_element (2) :: */
546
/* get memory, reconstruct all tuple lists, and return */
547
/* Compact the current front if it needs to grow anyway. */
548
/* Note: no pivot rows or columns in the current front */
549
DEBUGm4 (("get_memory from umf_create_element, 2\n")) ;
550
return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
552
Row_tuples [row] = t2 ;
553
tp2 = (Tuple *) (Memory + t2) ;
556
for (i = 0 ; i < len ; i++)
560
UMF_mem_free_tail_block (Numeric, t1) ;
564
/* place the new (e,f) tuple in the element list of the row */
571
/* ---------------------------------------------------------------------- */
574
DEBUG1 (("Done extending\nFINAL: element row pattern: len="ID"\n", fncols));
575
for (j = 0 ; j < fncols ; j++) DEBUG1 ((""ID"\n", Fcols [j])) ;
576
DEBUG1 (("FINAL: element col pattern: len="ID"\n", fnrows)) ;
577
for (j = 0 ; j < fnrows ; j++) DEBUG1 ((""ID"\n", Frows [j])) ;
578
for (j = 0 ; j < fncols ; j++)
581
ASSERT (col >= 0 && col < n_col) ;
582
UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
584
for (j = 0 ; j < fnrows ; j++)
587
ASSERT (row >= 0 && row < n_row) ;
588
UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
590
if (n_row < 1000 && n_col < 1000)
592
UMF_dump_memory (Numeric) ;
594
DEBUG1 (("New element, after filling with stuff: "ID"\n", e)) ;
595
UMF_dump_element (Numeric, Work, e, TRUE) ;
598
DEBUG4 (("Matrix dump, after New element: "ID"\n", e)) ;
599
UMF_dump_matrix (Numeric, Work, TRUE) ;
601
DEBUG3 (("FRONTAL WRAPUP DONE\n")) ;