00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 #ifndef EIGEN_COLAMD_H
00052 #define EIGEN_COLAMD_H
00053
00054 namespace internal {
00055
00056 #ifndef COLAMD_NDEBUG
00057 #define COLAMD_NDEBUG
00058 #endif
00059
00060
00061
00062
00063
00064 #define COLAMD_KNOBS 20
00065
00066
00067 #define COLAMD_STATS 20
00068
00069
00070 #define COLAMD_DENSE_ROW 0
00071
00072
00073 #define COLAMD_DENSE_COL 1
00074
00075
00076 #define COLAMD_DEFRAG_COUNT 2
00077
00078
00079 #define COLAMD_STATUS 3
00080
00081
00082 #define COLAMD_INFO1 4
00083 #define COLAMD_INFO2 5
00084 #define COLAMD_INFO3 6
00085
00086
00087 #define COLAMD_OK (0)
00088 #define COLAMD_OK_BUT_JUMBLED (1)
00089 #define COLAMD_ERROR_A_not_present (-1)
00090 #define COLAMD_ERROR_p_not_present (-2)
00091 #define COLAMD_ERROR_nrow_negative (-3)
00092 #define COLAMD_ERROR_ncol_negative (-4)
00093 #define COLAMD_ERROR_nnz_negative (-5)
00094 #define COLAMD_ERROR_p0_nonzero (-6)
00095 #define COLAMD_ERROR_A_too_small (-7)
00096 #define COLAMD_ERROR_col_length_negative (-8)
00097 #define COLAMD_ERROR_row_index_out_of_bounds (-9)
00098 #define COLAMD_ERROR_out_of_memory (-10)
00099 #define COLAMD_ERROR_internal_error (-999)
00100
00101
00102
00103
00104
00105 #define COLAMD_MAX(a,b) (((a) > (b)) ? (a) : (b))
00106 #define COLAMD_MIN(a,b) (((a) < (b)) ? (a) : (b))
00107
00108 #define ONES_COMPLEMENT(r) (-(r)-1)
00109
00110
00111
00112 #define COLAMD_EMPTY (-1)
00113
00114
00115 #define ALIVE (0)
00116 #define DEAD (-1)
00117
00118
00119 #define DEAD_PRINCIPAL (-1)
00120 #define DEAD_NON_PRINCIPAL (-2)
00121
00122
00123 #define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
00124 #define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
00125 #define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
00126 #define COL_IS_DEAD(c) (Col [c].start < ALIVE)
00127 #define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
00128 #define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
00129 #define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
00130 #define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
00131 #define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
00132
00133
00134
00135
00136
00137
00138 template <typename Index>
00139 struct colamd_col
00140 {
00141 Index start ;
00142
00143 Index length ;
00144 union
00145 {
00146 Index thickness ;
00147
00148 Index parent ;
00149
00150 } shared1 ;
00151 union
00152 {
00153 Index score ;
00154 Index order ;
00155 } shared2 ;
00156 union
00157 {
00158 Index headhash ;
00159
00160 Index hash ;
00161 Index prev ;
00162
00163 } shared3 ;
00164 union
00165 {
00166 Index degree_next ;
00167 Index hash_next ;
00168 } shared4 ;
00169
00170 };
00171
00172 template <typename Index>
00173 struct Colamd_Row
00174 {
00175 Index start ;
00176 Index length ;
00177 union
00178 {
00179 Index degree ;
00180 Index p ;
00181 } shared1 ;
00182 union
00183 {
00184 Index mark ;
00185 Index first_column ;
00186 } shared2 ;
00187
00188 };
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 template <typename Index>
00209 inline Index colamd_c(Index n_col)
00210 { return Index( ((n_col) + 1) * sizeof (colamd_col<Index>) / sizeof (Index) ) ; }
00211
00212 template <typename Index>
00213 inline Index colamd_r(Index n_row)
00214 { return Index(((n_row) + 1) * sizeof (Colamd_Row<Index>) / sizeof (Index)); }
00215
00216
00217 template <typename Index>
00218 static Index init_rows_cols (Index n_row, Index n_col, Colamd_Row<Index> Row [], colamd_col<Index> col [], Index A [], Index p [], Index stats[COLAMD_STATS] );
00219
00220 template <typename Index>
00221 static void init_scoring (Index n_row, Index n_col, Colamd_Row<Index> Row [], colamd_col<Index> Col [], Index A [], Index head [], double knobs[COLAMD_KNOBS], Index *p_n_row2, Index *p_n_col2, Index *p_max_deg);
00222
00223 template <typename Index>
00224 static Index find_ordering (Index n_row, Index n_col, Index Alen, Colamd_Row<Index> Row [], colamd_col<Index> Col [], Index A [], Index head [], Index n_col2, Index max_deg, Index pfree);
00225
00226 template <typename Index>
00227 static void order_children (Index n_col, colamd_col<Index> Col [], Index p []);
00228
00229 template <typename Index>
00230 static void detect_super_cols (colamd_col<Index> Col [], Index A [], Index head [], Index row_start, Index row_length ) ;
00231
00232 template <typename Index>
00233 static Index garbage_collection (Index n_row, Index n_col, Colamd_Row<Index> Row [], colamd_col<Index> Col [], Index A [], Index *pfree) ;
00234
00235 template <typename Index>
00236 static inline Index clear_mark (Index n_row, Colamd_Row<Index> Row [] ) ;
00237
00238
00239
00240 #define COLAMD_DEBUG0(params) ;
00241 #define COLAMD_DEBUG1(params) ;
00242 #define COLAMD_DEBUG2(params) ;
00243 #define COLAMD_DEBUG3(params) ;
00244 #define COLAMD_DEBUG4(params) ;
00245
00246 #define COLAMD_ASSERT(expression) ((void) 0)
00247
00248
00263 template <typename Index>
00264 inline Index colamd_recommended ( Index nnz, Index n_row, Index n_col)
00265 {
00266 if ((nnz) < 0 || (n_row) < 0 || (n_col) < 0)
00267 return (-1);
00268 else
00269 return (2 * (nnz) + colamd_c (n_col) + colamd_r (n_row) + (n_col) + ((nnz) / 5));
00270 }
00271
00293 static inline void colamd_set_defaults(double knobs[COLAMD_KNOBS])
00294 {
00295
00296
00297 int i ;
00298
00299 if (!knobs)
00300 {
00301 return ;
00302 }
00303 for (i = 0 ; i < COLAMD_KNOBS ; i++)
00304 {
00305 knobs [i] = 0 ;
00306 }
00307 knobs [COLAMD_DENSE_ROW] = 0.5 ;
00308 knobs [COLAMD_DENSE_COL] = 0.5 ;
00309 }
00310
00328 template <typename Index>
00329 static bool colamd(Index n_row, Index n_col, Index Alen, Index *A, Index *p, double knobs[COLAMD_KNOBS], Index stats[COLAMD_STATS])
00330 {
00331
00332
00333 Index i ;
00334 Index nnz ;
00335 Index Row_size ;
00336 Index Col_size ;
00337 Index need ;
00338 Colamd_Row<Index> *Row ;
00339 colamd_col<Index> *Col ;
00340 Index n_col2 ;
00341 Index n_row2 ;
00342 Index ngarbage ;
00343 Index max_deg ;
00344 double default_knobs [COLAMD_KNOBS] ;
00345
00346
00347
00348
00349 if (!stats)
00350 {
00351 COLAMD_DEBUG0 (("colamd: stats not present\n")) ;
00352 return (false) ;
00353 }
00354 for (i = 0 ; i < COLAMD_STATS ; i++)
00355 {
00356 stats [i] = 0 ;
00357 }
00358 stats [COLAMD_STATUS] = COLAMD_OK ;
00359 stats [COLAMD_INFO1] = -1 ;
00360 stats [COLAMD_INFO2] = -1 ;
00361
00362 if (!A)
00363 {
00364 stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
00365 COLAMD_DEBUG0 (("colamd: A not present\n")) ;
00366 return (false) ;
00367 }
00368
00369 if (!p)
00370 {
00371 stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
00372 COLAMD_DEBUG0 (("colamd: p not present\n")) ;
00373 return (false) ;
00374 }
00375
00376 if (n_row < 0)
00377 {
00378 stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
00379 stats [COLAMD_INFO1] = n_row ;
00380 COLAMD_DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
00381 return (false) ;
00382 }
00383
00384 if (n_col < 0)
00385 {
00386 stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
00387 stats [COLAMD_INFO1] = n_col ;
00388 COLAMD_DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
00389 return (false) ;
00390 }
00391
00392 nnz = p [n_col] ;
00393 if (nnz < 0)
00394 {
00395 stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
00396 stats [COLAMD_INFO1] = nnz ;
00397 COLAMD_DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
00398 return (false) ;
00399 }
00400
00401 if (p [0] != 0)
00402 {
00403 stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
00404 stats [COLAMD_INFO1] = p [0] ;
00405 COLAMD_DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
00406 return (false) ;
00407 }
00408
00409
00410
00411 if (!knobs)
00412 {
00413 colamd_set_defaults (default_knobs) ;
00414 knobs = default_knobs ;
00415 }
00416
00417
00418
00419 Col_size = colamd_c (n_col) ;
00420 Row_size = colamd_r (n_row) ;
00421 need = 2*nnz + n_col + Col_size + Row_size ;
00422
00423 if (need > Alen)
00424 {
00425
00426 stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
00427 stats [COLAMD_INFO1] = need ;
00428 stats [COLAMD_INFO2] = Alen ;
00429 COLAMD_DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
00430 return (false) ;
00431 }
00432
00433 Alen -= Col_size + Row_size ;
00434 Col = (colamd_col<Index> *) &A [Alen] ;
00435 Row = (Colamd_Row<Index> *) &A [Alen + Col_size] ;
00436
00437
00438
00439 if (!Eigen::internal::init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
00440 {
00441
00442 COLAMD_DEBUG0 (("colamd: Matrix invalid\n")) ;
00443 return (false) ;
00444 }
00445
00446
00447
00448 Eigen::internal::init_scoring (n_row, n_col, Row, Col, A, p, knobs,
00449 &n_row2, &n_col2, &max_deg) ;
00450
00451
00452
00453 ngarbage = Eigen::internal::find_ordering (n_row, n_col, Alen, Row, Col, A, p,
00454 n_col2, max_deg, 2*nnz) ;
00455
00456
00457
00458 Eigen::internal::order_children (n_col, Col, p) ;
00459
00460
00461
00462 stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
00463 stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
00464 stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
00465 COLAMD_DEBUG0 (("colamd: done.\n")) ;
00466 return (true) ;
00467 }
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 template <typename Index>
00489 static Index init_rows_cols
00490 (
00491
00492
00493 Index n_row,
00494 Index n_col,
00495 Colamd_Row<Index> Row [],
00496 colamd_col<Index> Col [],
00497 Index A [],
00498 Index p [],
00499 Index stats [COLAMD_STATS]
00500 )
00501 {
00502
00503
00504 Index col ;
00505 Index row ;
00506 Index *cp ;
00507 Index *cp_end ;
00508 Index *rp ;
00509 Index *rp_end ;
00510 Index last_row ;
00511
00512
00513
00514 for (col = 0 ; col < n_col ; col++)
00515 {
00516 Col [col].start = p [col] ;
00517 Col [col].length = p [col+1] - p [col] ;
00518
00519 if (Col [col].length < 0)
00520 {
00521
00522 stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
00523 stats [COLAMD_INFO1] = col ;
00524 stats [COLAMD_INFO2] = Col [col].length ;
00525 COLAMD_DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
00526 return (false) ;
00527 }
00528
00529 Col [col].shared1.thickness = 1 ;
00530 Col [col].shared2.score = 0 ;
00531 Col [col].shared3.prev = COLAMD_EMPTY ;
00532 Col [col].shared4.degree_next = COLAMD_EMPTY ;
00533 }
00534
00535
00536
00537
00538
00539 stats [COLAMD_INFO3] = 0 ;
00540
00541 for (row = 0 ; row < n_row ; row++)
00542 {
00543 Row [row].length = 0 ;
00544 Row [row].shared2.mark = -1 ;
00545 }
00546
00547 for (col = 0 ; col < n_col ; col++)
00548 {
00549 last_row = -1 ;
00550
00551 cp = &A [p [col]] ;
00552 cp_end = &A [p [col+1]] ;
00553
00554 while (cp < cp_end)
00555 {
00556 row = *cp++ ;
00557
00558
00559 if (row < 0 || row >= n_row)
00560 {
00561 stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
00562 stats [COLAMD_INFO1] = col ;
00563 stats [COLAMD_INFO2] = row ;
00564 stats [COLAMD_INFO3] = n_row ;
00565 COLAMD_DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
00566 return (false) ;
00567 }
00568
00569 if (row <= last_row || Row [row].shared2.mark == col)
00570 {
00571
00572
00573 stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
00574 stats [COLAMD_INFO1] = col ;
00575 stats [COLAMD_INFO2] = row ;
00576 (stats [COLAMD_INFO3]) ++ ;
00577 COLAMD_DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
00578 }
00579
00580 if (Row [row].shared2.mark != col)
00581 {
00582 Row [row].length++ ;
00583 }
00584 else
00585 {
00586
00587
00588 Col [col].length-- ;
00589 }
00590
00591
00592 Row [row].shared2.mark = col ;
00593
00594 last_row = row ;
00595 }
00596 }
00597
00598
00599
00600
00601
00602 Row [0].start = p [n_col] ;
00603 Row [0].shared1.p = Row [0].start ;
00604 Row [0].shared2.mark = -1 ;
00605 for (row = 1 ; row < n_row ; row++)
00606 {
00607 Row [row].start = Row [row-1].start + Row [row-1].length ;
00608 Row [row].shared1.p = Row [row].start ;
00609 Row [row].shared2.mark = -1 ;
00610 }
00611
00612
00613
00614 if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
00615 {
00616
00617 for (col = 0 ; col < n_col ; col++)
00618 {
00619 cp = &A [p [col]] ;
00620 cp_end = &A [p [col+1]] ;
00621 while (cp < cp_end)
00622 {
00623 row = *cp++ ;
00624 if (Row [row].shared2.mark != col)
00625 {
00626 A [(Row [row].shared1.p)++] = col ;
00627 Row [row].shared2.mark = col ;
00628 }
00629 }
00630 }
00631 }
00632 else
00633 {
00634
00635 for (col = 0 ; col < n_col ; col++)
00636 {
00637 cp = &A [p [col]] ;
00638 cp_end = &A [p [col+1]] ;
00639 while (cp < cp_end)
00640 {
00641 A [(Row [*cp++].shared1.p)++] = col ;
00642 }
00643 }
00644 }
00645
00646
00647
00648 for (row = 0 ; row < n_row ; row++)
00649 {
00650 Row [row].shared2.mark = 0 ;
00651 Row [row].shared1.degree = Row [row].length ;
00652 }
00653
00654
00655
00656 if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
00657 {
00658 COLAMD_DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
00659
00660
00661
00662
00663
00664
00665
00666
00667 Col [0].start = 0 ;
00668 p [0] = Col [0].start ;
00669 for (col = 1 ; col < n_col ; col++)
00670 {
00671
00672
00673 Col [col].start = Col [col-1].start + Col [col-1].length ;
00674 p [col] = Col [col].start ;
00675 }
00676
00677
00678
00679 for (row = 0 ; row < n_row ; row++)
00680 {
00681 rp = &A [Row [row].start] ;
00682 rp_end = rp + Row [row].length ;
00683 while (rp < rp_end)
00684 {
00685 A [(p [*rp++])++] = row ;
00686 }
00687 }
00688 }
00689
00690
00691
00692 return (true) ;
00693 }
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 template <typename Index>
00705 static void init_scoring
00706 (
00707
00708
00709 Index n_row,
00710 Index n_col,
00711 Colamd_Row<Index> Row [],
00712 colamd_col<Index> Col [],
00713 Index A [],
00714 Index head [],
00715 double knobs [COLAMD_KNOBS],
00716 Index *p_n_row2,
00717 Index *p_n_col2,
00718 Index *p_max_deg
00719 )
00720 {
00721
00722
00723 Index c ;
00724 Index r, row ;
00725 Index *cp ;
00726 Index deg ;
00727 Index *cp_end ;
00728 Index *new_cp ;
00729 Index col_length ;
00730 Index score ;
00731 Index n_col2 ;
00732 Index n_row2 ;
00733 Index dense_row_count ;
00734 Index dense_col_count ;
00735 Index min_score ;
00736 Index max_deg ;
00737 Index next_col ;
00738
00739
00740
00741
00742 dense_row_count = COLAMD_MAX (0, COLAMD_MIN (knobs [COLAMD_DENSE_ROW] * n_col, n_col)) ;
00743 dense_col_count = COLAMD_MAX (0, COLAMD_MIN (knobs [COLAMD_DENSE_COL] * n_row, n_row)) ;
00744 COLAMD_DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
00745 max_deg = 0 ;
00746 n_col2 = n_col ;
00747 n_row2 = n_row ;
00748
00749
00750
00751
00752
00753 for (c = n_col-1 ; c >= 0 ; c--)
00754 {
00755 deg = Col [c].length ;
00756 if (deg == 0)
00757 {
00758
00759 Col [c].shared2.order = --n_col2 ;
00760 KILL_PRINCIPAL_COL (c) ;
00761 }
00762 }
00763 COLAMD_DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
00764
00765
00766
00767
00768 for (c = n_col-1 ; c >= 0 ; c--)
00769 {
00770
00771 if (COL_IS_DEAD (c))
00772 {
00773 continue ;
00774 }
00775 deg = Col [c].length ;
00776 if (deg > dense_col_count)
00777 {
00778
00779 Col [c].shared2.order = --n_col2 ;
00780
00781 cp = &A [Col [c].start] ;
00782 cp_end = cp + Col [c].length ;
00783 while (cp < cp_end)
00784 {
00785 Row [*cp++].shared1.degree-- ;
00786 }
00787 KILL_PRINCIPAL_COL (c) ;
00788 }
00789 }
00790 COLAMD_DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
00791
00792
00793
00794 for (r = 0 ; r < n_row ; r++)
00795 {
00796 deg = Row [r].shared1.degree ;
00797 COLAMD_ASSERT (deg >= 0 && deg <= n_col) ;
00798 if (deg > dense_row_count || deg == 0)
00799 {
00800
00801 KILL_ROW (r) ;
00802 --n_row2 ;
00803 }
00804 else
00805 {
00806
00807 max_deg = COLAMD_MAX (max_deg, deg) ;
00808 }
00809 }
00810 COLAMD_DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820 for (c = n_col-1 ; c >= 0 ; c--)
00821 {
00822
00823 if (COL_IS_DEAD (c))
00824 {
00825 continue ;
00826 }
00827 score = 0 ;
00828 cp = &A [Col [c].start] ;
00829 new_cp = cp ;
00830 cp_end = cp + Col [c].length ;
00831 while (cp < cp_end)
00832 {
00833
00834 row = *cp++ ;
00835
00836 if (ROW_IS_DEAD (row))
00837 {
00838 continue ;
00839 }
00840
00841 *new_cp++ = row ;
00842
00843 score += Row [row].shared1.degree - 1 ;
00844
00845 score = COLAMD_MIN (score, n_col) ;
00846 }
00847
00848 col_length = (Index) (new_cp - &A [Col [c].start]) ;
00849 if (col_length == 0)
00850 {
00851
00852
00853 COLAMD_DEBUG2 (("Newly null killed: %d\n", c)) ;
00854 Col [c].shared2.order = --n_col2 ;
00855 KILL_PRINCIPAL_COL (c) ;
00856 }
00857 else
00858 {
00859
00860 COLAMD_ASSERT (score >= 0) ;
00861 COLAMD_ASSERT (score <= n_col) ;
00862 Col [c].length = col_length ;
00863 Col [c].shared2.score = score ;
00864 }
00865 }
00866 COLAMD_DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
00867 n_col-n_col2)) ;
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878 for (c = 0 ; c <= n_col ; c++)
00879 {
00880 head [c] = COLAMD_EMPTY ;
00881 }
00882 min_score = n_col ;
00883
00884
00885 for (c = n_col-1 ; c >= 0 ; c--)
00886 {
00887
00888 if (COL_IS_ALIVE (c))
00889 {
00890 COLAMD_DEBUG4 (("place %d score %d minscore %d ncol %d\n",
00891 c, Col [c].shared2.score, min_score, n_col)) ;
00892
00893
00894
00895 score = Col [c].shared2.score ;
00896
00897 COLAMD_ASSERT (min_score >= 0) ;
00898 COLAMD_ASSERT (min_score <= n_col) ;
00899 COLAMD_ASSERT (score >= 0) ;
00900 COLAMD_ASSERT (score <= n_col) ;
00901 COLAMD_ASSERT (head [score] >= COLAMD_EMPTY) ;
00902
00903
00904 next_col = head [score] ;
00905 Col [c].shared3.prev = COLAMD_EMPTY ;
00906 Col [c].shared4.degree_next = next_col ;
00907
00908
00909
00910 if (next_col != COLAMD_EMPTY)
00911 {
00912 Col [next_col].shared3.prev = c ;
00913 }
00914 head [score] = c ;
00915
00916
00917 min_score = COLAMD_MIN (min_score, score) ;
00918
00919
00920 }
00921 }
00922
00923
00924
00925
00926 *p_n_col2 = n_col2 ;
00927 *p_n_row2 = n_row2 ;
00928 *p_max_deg = max_deg ;
00929 }
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941 template <typename Index>
00942 static Index find_ordering
00943 (
00944
00945
00946 Index n_row,
00947 Index n_col,
00948 Index Alen,
00949 Colamd_Row<Index> Row [],
00950 colamd_col<Index> Col [],
00951 Index A [],
00952 Index head [],
00953 Index n_col2,
00954 Index max_deg,
00955 Index pfree
00956 )
00957 {
00958
00959
00960 Index k ;
00961 Index pivot_col ;
00962 Index *cp ;
00963 Index *rp ;
00964 Index pivot_row ;
00965 Index *new_cp ;
00966 Index *new_rp ;
00967 Index pivot_row_start ;
00968 Index pivot_row_degree ;
00969 Index pivot_row_length ;
00970 Index pivot_col_score ;
00971 Index needed_memory ;
00972 Index *cp_end ;
00973 Index *rp_end ;
00974 Index row ;
00975 Index col ;
00976 Index max_score ;
00977 Index cur_score ;
00978 unsigned int hash ;
00979 Index head_column ;
00980 Index first_col ;
00981 Index tag_mark ;
00982 Index row_mark ;
00983 Index set_difference ;
00984 Index min_score ;
00985 Index col_thickness ;
00986 Index max_mark ;
00987 Index pivot_col_thickness ;
00988 Index prev_col ;
00989 Index next_col ;
00990 Index ngarbage ;
00991
00992
00993
00994
00995 max_mark = INT_MAX - n_col ;
00996 tag_mark = Eigen::internal::clear_mark (n_row, Row) ;
00997 min_score = 0 ;
00998 ngarbage = 0 ;
00999 COLAMD_DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
01000
01001
01002
01003 for (k = 0 ; k < n_col2 ; )
01004 {
01005
01006
01007
01008
01009 COLAMD_ASSERT (min_score >= 0) ;
01010 COLAMD_ASSERT (min_score <= n_col) ;
01011 COLAMD_ASSERT (head [min_score] >= COLAMD_EMPTY) ;
01012
01013
01014 while (head [min_score] == COLAMD_EMPTY && min_score < n_col)
01015 {
01016 min_score++ ;
01017 }
01018 pivot_col = head [min_score] ;
01019 COLAMD_ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
01020 next_col = Col [pivot_col].shared4.degree_next ;
01021 head [min_score] = next_col ;
01022 if (next_col != COLAMD_EMPTY)
01023 {
01024 Col [next_col].shared3.prev = COLAMD_EMPTY ;
01025 }
01026
01027 COLAMD_ASSERT (COL_IS_ALIVE (pivot_col)) ;
01028 COLAMD_DEBUG3 (("Pivot col: %d\n", pivot_col)) ;
01029
01030
01031 pivot_col_score = Col [pivot_col].shared2.score ;
01032
01033
01034 Col [pivot_col].shared2.order = k ;
01035
01036
01037 pivot_col_thickness = Col [pivot_col].shared1.thickness ;
01038 k += pivot_col_thickness ;
01039 COLAMD_ASSERT (pivot_col_thickness > 0) ;
01040
01041
01042
01043 needed_memory = COLAMD_MIN (pivot_col_score, n_col - k) ;
01044 if (pfree + needed_memory >= Alen)
01045 {
01046 pfree = Eigen::internal::garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
01047 ngarbage++ ;
01048
01049 COLAMD_ASSERT (pfree + needed_memory < Alen) ;
01050
01051 tag_mark = Eigen::internal::clear_mark (n_row, Row) ;
01052
01053 }
01054
01055
01056
01057
01058 pivot_row_start = pfree ;
01059
01060
01061 pivot_row_degree = 0 ;
01062
01063
01064
01065 Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
01066
01067
01068 cp = &A [Col [pivot_col].start] ;
01069 cp_end = cp + Col [pivot_col].length ;
01070 while (cp < cp_end)
01071 {
01072
01073 row = *cp++ ;
01074 COLAMD_DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
01075
01076 if (ROW_IS_DEAD (row))
01077 {
01078 continue ;
01079 }
01080 rp = &A [Row [row].start] ;
01081 rp_end = rp + Row [row].length ;
01082 while (rp < rp_end)
01083 {
01084
01085 col = *rp++ ;
01086
01087 col_thickness = Col [col].shared1.thickness ;
01088 if (col_thickness > 0 && COL_IS_ALIVE (col))
01089 {
01090
01091 Col [col].shared1.thickness = -col_thickness ;
01092 COLAMD_ASSERT (pfree < Alen) ;
01093
01094 A [pfree++] = col ;
01095 pivot_row_degree += col_thickness ;
01096 }
01097 }
01098 }
01099
01100
01101 Col [pivot_col].shared1.thickness = pivot_col_thickness ;
01102 max_deg = COLAMD_MAX (max_deg, pivot_row_degree) ;
01103
01104
01105
01106
01107
01108 cp = &A [Col [pivot_col].start] ;
01109 cp_end = cp + Col [pivot_col].length ;
01110 while (cp < cp_end)
01111 {
01112
01113 row = *cp++ ;
01114 COLAMD_DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
01115 KILL_ROW (row) ;
01116 }
01117
01118
01119
01120 pivot_row_length = pfree - pivot_row_start ;
01121 if (pivot_row_length > 0)
01122 {
01123
01124 pivot_row = A [Col [pivot_col].start] ;
01125 COLAMD_DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
01126 }
01127 else
01128 {
01129
01130 pivot_row = COLAMD_EMPTY ;
01131 COLAMD_ASSERT (pivot_row_length == 0) ;
01132 }
01133 COLAMD_ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156 COLAMD_DEBUG3 (("** Computing set differences phase. **\n")) ;
01157
01158
01159
01160 COLAMD_DEBUG3 (("Pivot row: ")) ;
01161
01162 rp = &A [pivot_row_start] ;
01163 rp_end = rp + pivot_row_length ;
01164 while (rp < rp_end)
01165 {
01166 col = *rp++ ;
01167 COLAMD_ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
01168 COLAMD_DEBUG3 (("Col: %d\n", col)) ;
01169
01170
01171 col_thickness = -Col [col].shared1.thickness ;
01172 COLAMD_ASSERT (col_thickness > 0) ;
01173 Col [col].shared1.thickness = col_thickness ;
01174
01175
01176
01177 cur_score = Col [col].shared2.score ;
01178 prev_col = Col [col].shared3.prev ;
01179 next_col = Col [col].shared4.degree_next ;
01180 COLAMD_ASSERT (cur_score >= 0) ;
01181 COLAMD_ASSERT (cur_score <= n_col) ;
01182 COLAMD_ASSERT (cur_score >= COLAMD_EMPTY) ;
01183 if (prev_col == COLAMD_EMPTY)
01184 {
01185 head [cur_score] = next_col ;
01186 }
01187 else
01188 {
01189 Col [prev_col].shared4.degree_next = next_col ;
01190 }
01191 if (next_col != COLAMD_EMPTY)
01192 {
01193 Col [next_col].shared3.prev = prev_col ;
01194 }
01195
01196
01197
01198 cp = &A [Col [col].start] ;
01199 cp_end = cp + Col [col].length ;
01200 while (cp < cp_end)
01201 {
01202
01203 row = *cp++ ;
01204 row_mark = Row [row].shared2.mark ;
01205
01206 if (ROW_IS_MARKED_DEAD (row_mark))
01207 {
01208 continue ;
01209 }
01210 COLAMD_ASSERT (row != pivot_row) ;
01211 set_difference = row_mark - tag_mark ;
01212
01213 if (set_difference < 0)
01214 {
01215 COLAMD_ASSERT (Row [row].shared1.degree <= max_deg) ;
01216 set_difference = Row [row].shared1.degree ;
01217 }
01218
01219 set_difference -= col_thickness ;
01220 COLAMD_ASSERT (set_difference >= 0) ;
01221
01222 if (set_difference == 0)
01223 {
01224 COLAMD_DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
01225 KILL_ROW (row) ;
01226 }
01227 else
01228 {
01229
01230 Row [row].shared2.mark = set_difference + tag_mark ;
01231 }
01232 }
01233 }
01234
01235
01236
01237
01238 COLAMD_DEBUG3 (("** Adding set differences phase. **\n")) ;
01239
01240
01241 rp = &A [pivot_row_start] ;
01242 rp_end = rp + pivot_row_length ;
01243 while (rp < rp_end)
01244 {
01245
01246 col = *rp++ ;
01247 COLAMD_ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
01248 hash = 0 ;
01249 cur_score = 0 ;
01250 cp = &A [Col [col].start] ;
01251
01252 new_cp = cp ;
01253 cp_end = cp + Col [col].length ;
01254
01255 COLAMD_DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
01256
01257 while (cp < cp_end)
01258 {
01259
01260 row = *cp++ ;
01261 COLAMD_ASSERT(row >= 0 && row < n_row) ;
01262 row_mark = Row [row].shared2.mark ;
01263
01264 if (ROW_IS_MARKED_DEAD (row_mark))
01265 {
01266 continue ;
01267 }
01268 COLAMD_ASSERT (row_mark > tag_mark) ;
01269
01270 *new_cp++ = row ;
01271
01272 hash += row ;
01273
01274 cur_score += row_mark - tag_mark ;
01275
01276 cur_score = COLAMD_MIN (cur_score, n_col) ;
01277 }
01278
01279
01280 Col [col].length = (Index) (new_cp - &A [Col [col].start]) ;
01281
01282
01283
01284 if (Col [col].length == 0)
01285 {
01286 COLAMD_DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
01287
01288 KILL_PRINCIPAL_COL (col) ;
01289 pivot_row_degree -= Col [col].shared1.thickness ;
01290 COLAMD_ASSERT (pivot_row_degree >= 0) ;
01291
01292 Col [col].shared2.order = k ;
01293
01294 k += Col [col].shared1.thickness ;
01295 }
01296 else
01297 {
01298
01299
01300 COLAMD_DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
01301
01302
01303 Col [col].shared2.score = cur_score ;
01304
01305
01306 hash %= n_col + 1 ;
01307
01308 COLAMD_DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
01309 COLAMD_ASSERT (hash <= n_col) ;
01310
01311 head_column = head [hash] ;
01312 if (head_column > COLAMD_EMPTY)
01313 {
01314
01315
01316 first_col = Col [head_column].shared3.headhash ;
01317 Col [head_column].shared3.headhash = col ;
01318 }
01319 else
01320 {
01321
01322 first_col = - (head_column + 2) ;
01323 head [hash] = - (col + 2) ;
01324 }
01325 Col [col].shared4.hash_next = first_col ;
01326
01327
01328 Col [col].shared3.hash = (Index) hash ;
01329 COLAMD_ASSERT (COL_IS_ALIVE (col)) ;
01330 }
01331 }
01332
01333
01334
01335
01336
01337 COLAMD_DEBUG3 (("** Supercolumn detection phase. **\n")) ;
01338
01339 Eigen::internal::detect_super_cols (Col, A, head, pivot_row_start, pivot_row_length) ;
01340
01341
01342
01343 KILL_PRINCIPAL_COL (pivot_col) ;
01344
01345
01346
01347 tag_mark += (max_deg + 1) ;
01348 if (tag_mark >= max_mark)
01349 {
01350 COLAMD_DEBUG2 (("clearing tag_mark\n")) ;
01351 tag_mark = Eigen::internal::clear_mark (n_row, Row) ;
01352 }
01353
01354
01355
01356 COLAMD_DEBUG3 (("** Finalize scores phase. **\n")) ;
01357
01358
01359 rp = &A [pivot_row_start] ;
01360
01361 new_rp = rp ;
01362 rp_end = rp + pivot_row_length ;
01363 while (rp < rp_end)
01364 {
01365 col = *rp++ ;
01366
01367 if (COL_IS_DEAD (col))
01368 {
01369 continue ;
01370 }
01371 *new_rp++ = col ;
01372
01373 A [Col [col].start + (Col [col].length++)] = pivot_row ;
01374
01375
01376
01377
01378 cur_score = Col [col].shared2.score + pivot_row_degree ;
01379
01380
01381
01382
01383 max_score = n_col - k - Col [col].shared1.thickness ;
01384
01385
01386 cur_score -= Col [col].shared1.thickness ;
01387
01388
01389 cur_score = COLAMD_MIN (cur_score, max_score) ;
01390 COLAMD_ASSERT (cur_score >= 0) ;
01391
01392
01393 Col [col].shared2.score = cur_score ;
01394
01395
01396
01397 COLAMD_ASSERT (min_score >= 0) ;
01398 COLAMD_ASSERT (min_score <= n_col) ;
01399 COLAMD_ASSERT (cur_score >= 0) ;
01400 COLAMD_ASSERT (cur_score <= n_col) ;
01401 COLAMD_ASSERT (head [cur_score] >= COLAMD_EMPTY) ;
01402 next_col = head [cur_score] ;
01403 Col [col].shared4.degree_next = next_col ;
01404 Col [col].shared3.prev = COLAMD_EMPTY ;
01405 if (next_col != COLAMD_EMPTY)
01406 {
01407 Col [next_col].shared3.prev = col ;
01408 }
01409 head [cur_score] = col ;
01410
01411
01412 min_score = COLAMD_MIN (min_score, cur_score) ;
01413
01414 }
01415
01416
01417
01418 if (pivot_row_degree > 0)
01419 {
01420
01421
01422 Row [pivot_row].start = pivot_row_start ;
01423 Row [pivot_row].length = (Index) (new_rp - &A[pivot_row_start]) ;
01424 Row [pivot_row].shared1.degree = pivot_row_degree ;
01425 Row [pivot_row].shared2.mark = 0 ;
01426
01427 }
01428 }
01429
01430
01431
01432 return (ngarbage) ;
01433 }
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452 template <typename Index>
01453 static inline void order_children
01454 (
01455
01456
01457 Index n_col,
01458 colamd_col<Index> Col [],
01459 Index p []
01460 )
01461 {
01462
01463
01464 Index i ;
01465 Index c ;
01466 Index parent ;
01467 Index order ;
01468
01469
01470
01471 for (i = 0 ; i < n_col ; i++)
01472 {
01473
01474 COLAMD_ASSERT (COL_IS_DEAD (i)) ;
01475 if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == COLAMD_EMPTY)
01476 {
01477 parent = i ;
01478
01479 do
01480 {
01481 parent = Col [parent].shared1.parent ;
01482 } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
01483
01484
01485
01486 c = i ;
01487
01488 order = Col [parent].shared2.order ;
01489
01490 do
01491 {
01492 COLAMD_ASSERT (Col [c].shared2.order == COLAMD_EMPTY) ;
01493
01494
01495 Col [c].shared2.order = order++ ;
01496
01497 Col [c].shared1.parent = parent ;
01498
01499
01500 c = Col [c].shared1.parent ;
01501
01502
01503
01504
01505 } while (Col [c].shared2.order == COLAMD_EMPTY) ;
01506
01507
01508 Col [parent].shared2.order = order ;
01509 }
01510 }
01511
01512
01513
01514 for (c = 0 ; c < n_col ; c++)
01515 {
01516 p [Col [c].shared2.order] = c ;
01517 }
01518 }
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553 template <typename Index>
01554 static void detect_super_cols
01555 (
01556
01557
01558 colamd_col<Index> Col [],
01559 Index A [],
01560 Index head [],
01561 Index row_start,
01562 Index row_length
01563 )
01564 {
01565
01566
01567 Index hash ;
01568 Index *rp ;
01569 Index c ;
01570 Index super_c ;
01571 Index *cp1 ;
01572 Index *cp2 ;
01573 Index length ;
01574 Index prev_c ;
01575 Index i ;
01576 Index *rp_end ;
01577 Index col ;
01578 Index head_column ;
01579 Index first_col ;
01580
01581
01582
01583 rp = &A [row_start] ;
01584 rp_end = rp + row_length ;
01585 while (rp < rp_end)
01586 {
01587 col = *rp++ ;
01588 if (COL_IS_DEAD (col))
01589 {
01590 continue ;
01591 }
01592
01593
01594 hash = Col [col].shared3.hash ;
01595 COLAMD_ASSERT (hash <= n_col) ;
01596
01597
01598
01599 head_column = head [hash] ;
01600 if (head_column > COLAMD_EMPTY)
01601 {
01602 first_col = Col [head_column].shared3.headhash ;
01603 }
01604 else
01605 {
01606 first_col = - (head_column + 2) ;
01607 }
01608
01609
01610
01611 for (super_c = first_col ; super_c != COLAMD_EMPTY ;
01612 super_c = Col [super_c].shared4.hash_next)
01613 {
01614 COLAMD_ASSERT (COL_IS_ALIVE (super_c)) ;
01615 COLAMD_ASSERT (Col [super_c].shared3.hash == hash) ;
01616 length = Col [super_c].length ;
01617
01618
01619 prev_c = super_c ;
01620
01621
01622
01623 for (c = Col [super_c].shared4.hash_next ;
01624 c != COLAMD_EMPTY ; c = Col [c].shared4.hash_next)
01625 {
01626 COLAMD_ASSERT (c != super_c) ;
01627 COLAMD_ASSERT (COL_IS_ALIVE (c)) ;
01628 COLAMD_ASSERT (Col [c].shared3.hash == hash) ;
01629
01630
01631 if (Col [c].length != length ||
01632 Col [c].shared2.score != Col [super_c].shared2.score)
01633 {
01634 prev_c = c ;
01635 continue ;
01636 }
01637
01638
01639 cp1 = &A [Col [super_c].start] ;
01640 cp2 = &A [Col [c].start] ;
01641
01642 for (i = 0 ; i < length ; i++)
01643 {
01644
01645 COLAMD_ASSERT (ROW_IS_ALIVE (*cp1)) ;
01646 COLAMD_ASSERT (ROW_IS_ALIVE (*cp2)) ;
01647
01648
01649 if (*cp1++ != *cp2++)
01650 {
01651 break ;
01652 }
01653 }
01654
01655
01656 if (i != length)
01657 {
01658 prev_c = c ;
01659 continue ;
01660 }
01661
01662
01663
01664 COLAMD_ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
01665
01666 Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
01667 Col [c].shared1.parent = super_c ;
01668 KILL_NON_PRINCIPAL_COL (c) ;
01669
01670 Col [c].shared2.order = COLAMD_EMPTY ;
01671
01672 Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
01673 }
01674 }
01675
01676
01677
01678 if (head_column > COLAMD_EMPTY)
01679 {
01680
01681 Col [head_column].shared3.headhash = COLAMD_EMPTY ;
01682 }
01683 else
01684 {
01685
01686 head [hash] = COLAMD_EMPTY ;
01687 }
01688 }
01689 }
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704 template <typename Index>
01705 static Index garbage_collection
01706 (
01707
01708
01709 Index n_row,
01710 Index n_col,
01711 Colamd_Row<Index> Row [],
01712 colamd_col<Index> Col [],
01713 Index A [],
01714 Index *pfree
01715 )
01716 {
01717
01718
01719 Index *psrc ;
01720 Index *pdest ;
01721 Index j ;
01722 Index r ;
01723 Index c ;
01724 Index length ;
01725
01726
01727
01728 pdest = &A[0] ;
01729 for (c = 0 ; c < n_col ; c++)
01730 {
01731 if (COL_IS_ALIVE (c))
01732 {
01733 psrc = &A [Col [c].start] ;
01734
01735
01736 COLAMD_ASSERT (pdest <= psrc) ;
01737 Col [c].start = (Index) (pdest - &A [0]) ;
01738 length = Col [c].length ;
01739 for (j = 0 ; j < length ; j++)
01740 {
01741 r = *psrc++ ;
01742 if (ROW_IS_ALIVE (r))
01743 {
01744 *pdest++ = r ;
01745 }
01746 }
01747 Col [c].length = (Index) (pdest - &A [Col [c].start]) ;
01748 }
01749 }
01750
01751
01752
01753 for (r = 0 ; r < n_row ; r++)
01754 {
01755 if (ROW_IS_ALIVE (r))
01756 {
01757 if (Row [r].length == 0)
01758 {
01759
01760 COLAMD_DEBUG3 (("Defrag row kill\n")) ;
01761 KILL_ROW (r) ;
01762 }
01763 else
01764 {
01765
01766 psrc = &A [Row [r].start] ;
01767 Row [r].shared2.first_column = *psrc ;
01768 COLAMD_ASSERT (ROW_IS_ALIVE (r)) ;
01769
01770 *psrc = ONES_COMPLEMENT (r) ;
01771
01772 }
01773 }
01774 }
01775
01776
01777
01778 psrc = pdest ;
01779 while (psrc < pfree)
01780 {
01781
01782 if (*psrc++ < 0)
01783 {
01784 psrc-- ;
01785
01786 r = ONES_COMPLEMENT (*psrc) ;
01787 COLAMD_ASSERT (r >= 0 && r < n_row) ;
01788
01789 *psrc = Row [r].shared2.first_column ;
01790 COLAMD_ASSERT (ROW_IS_ALIVE (r)) ;
01791
01792
01793 COLAMD_ASSERT (pdest <= psrc) ;
01794 Row [r].start = (Index) (pdest - &A [0]) ;
01795 length = Row [r].length ;
01796 for (j = 0 ; j < length ; j++)
01797 {
01798 c = *psrc++ ;
01799 if (COL_IS_ALIVE (c))
01800 {
01801 *pdest++ = c ;
01802 }
01803 }
01804 Row [r].length = (Index) (pdest - &A [Row [r].start]) ;
01805
01806 }
01807 }
01808
01809 COLAMD_ASSERT (debug_rows == 0) ;
01810
01811
01812
01813 return ((Index) (pdest - &A [0])) ;
01814 }
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825 template <typename Index>
01826 static inline Index clear_mark
01827 (
01828
01829
01830 Index n_row,
01831 Colamd_Row<Index> Row []
01832 )
01833 {
01834
01835
01836 Index r ;
01837
01838 for (r = 0 ; r < n_row ; r++)
01839 {
01840 if (ROW_IS_ALIVE (r))
01841 {
01842 Row [r].shared2.mark = 0 ;
01843 }
01844 }
01845 return (1) ;
01846 }
01847
01848
01849 }
01850 #endif