93 ErrorANotPresent = -1,
94 ErrorPNotPresent = -2,
95 ErrorNrowNegative = -3,
96 ErrorNcolNegative = -4,
97 ErrorNnzNegative = -5,
100 ErrorColLengthNegative = -8,
101 ErrorRowIndexOutOfBounds = -9,
102 ErrorOutOfMemory = -10,
103 ErrorInternalError = -999
109template <
typename IndexType>
110IndexType ones_complement(
const IndexType r) {
118enum RowColumnStatus { Alive = 0, Dead = -1 };
121enum ColumnStatus { DeadPrincipal = -1, DeadNonPrincipal = -2 };
128template <
typename IndexType>
151 IndexType degree_next;
155 inline bool is_dead()
const {
return start < Alive; }
157 inline bool is_alive()
const {
return start >= Alive; }
159 inline bool is_dead_principal()
const {
return start == DeadPrincipal; }
161 inline void kill_principal() { start = DeadPrincipal; }
163 inline void kill_non_principal() { start = DeadNonPrincipal; }
166template <
typename IndexType>
176 IndexType first_column;
179 inline bool is_dead()
const {
return shared2.mark < Alive; }
181 inline bool is_alive()
const {
return shared2.mark >= Alive; }
183 inline void kill() { shared2.mark = Dead; }
204template <
typename IndexType>
205inline IndexType colamd_c(IndexType n_col) {
206 return IndexType(((n_col) + 1) *
sizeof(ColStructure<IndexType>) /
sizeof(IndexType));
209template <
typename IndexType>
210inline IndexType colamd_r(IndexType n_row) {
211 return IndexType(((n_row) + 1) *
sizeof(RowStructure<IndexType>) /
sizeof(IndexType));
215template <
typename IndexType>
216static IndexType init_rows_cols(IndexType n_row, IndexType n_col, RowStructure<IndexType> Row[],
217 ColStructure<IndexType> col[], IndexType A[], IndexType p[], IndexType stats[NStats]);
219template <
typename IndexType>
220static void init_scoring(IndexType n_row, IndexType n_col, RowStructure<IndexType> Row[], ColStructure<IndexType> Col[],
221 IndexType A[], IndexType head[],
double knobs[NKnobs], IndexType *p_n_row2,
222 IndexType *p_n_col2, IndexType *p_max_deg);
224template <
typename IndexType>
225static IndexType find_ordering(IndexType n_row, IndexType n_col, IndexType Alen, RowStructure<IndexType> Row[],
226 ColStructure<IndexType> Col[], IndexType A[], IndexType head[], IndexType n_col2,
227 IndexType max_deg, IndexType pfree);
229template <
typename IndexType>
230static void order_children(IndexType n_col, ColStructure<IndexType> Col[], IndexType p[]);
232template <
typename IndexType>
233static void detect_super_cols(ColStructure<IndexType> Col[], IndexType A[], IndexType head[], IndexType row_start,
234 IndexType row_length);
236template <
typename IndexType>
237static IndexType garbage_collection(IndexType n_row, IndexType n_col, RowStructure<IndexType> Row[],
238 ColStructure<IndexType> Col[], IndexType A[], IndexType *pfree);
240template <
typename IndexType>
241static inline IndexType clear_mark(IndexType n_row, RowStructure<IndexType> Row[]);
245#define COLAMD_DEBUG0(params) ;
246#define COLAMD_DEBUG1(params) ;
247#define COLAMD_DEBUG2(params) ;
248#define COLAMD_DEBUG3(params) ;
249#define COLAMD_DEBUG4(params) ;
251#define COLAMD_ASSERT(expression) ((void)0)
267template <
typename IndexType>
268inline IndexType recommended(IndexType nnz, IndexType n_row, IndexType n_col) {
269 if ((nnz) < 0 || (n_row) < 0 || (n_col) < 0)
272 return (2 * (nnz) + colamd_c(n_col) + colamd_r(n_row) + (n_col) + ((nnz) / 5));
296static inline void set_defaults(
double knobs[NKnobs]) {
304 for (i = 0; i < NKnobs; i++) {
307 knobs[Colamd::DenseRow] = 0.5;
308 knobs[Colamd::DenseCol] = 0.5;
328template <
typename IndexType>
329static bool compute_ordering(IndexType n_row, IndexType n_col, IndexType Alen, IndexType *A, IndexType *p,
330 double knobs[NKnobs], IndexType stats[NStats]) {
338 Colamd::RowStructure<IndexType> *Row;
339 Colamd::ColStructure<IndexType> *Col;
344 double default_knobs[NKnobs];
349 COLAMD_DEBUG0((
"colamd: stats not present\n"));
352 for (i = 0; i < NStats; i++) {
355 stats[Colamd::Status] = Colamd::Ok;
356 stats[Colamd::Info1] = -1;
357 stats[Colamd::Info2] = -1;
361 stats[Colamd::Status] = Colamd::ErrorANotPresent;
362 COLAMD_DEBUG0((
"colamd: A not present\n"));
368 stats[Colamd::Status] = Colamd::ErrorPNotPresent;
369 COLAMD_DEBUG0((
"colamd: p not present\n"));
375 stats[Colamd::Status] = Colamd::ErrorNrowNegative;
376 stats[Colamd::Info1] = n_row;
377 COLAMD_DEBUG0((
"colamd: nrow negative %d\n", n_row));
383 stats[Colamd::Status] = Colamd::ErrorNcolNegative;
384 stats[Colamd::Info1] = n_col;
385 COLAMD_DEBUG0((
"colamd: ncol negative %d\n", n_col));
392 stats[Colamd::Status] = Colamd::ErrorNnzNegative;
393 stats[Colamd::Info1] = nnz;
394 COLAMD_DEBUG0((
"colamd: number of entries negative %d\n", nnz));
399 stats[Colamd::Status] = Colamd::ErrorP0Nonzero;
400 stats[Colamd::Info1] = p[0];
401 COLAMD_DEBUG0((
"colamd: p[0] not zero %d\n", p[0]));
408 set_defaults(default_knobs);
409 knobs = default_knobs;
414 Col_size = colamd_c(n_col);
415 Row_size = colamd_r(n_row);
416 need = 2 * nnz + n_col + Col_size + Row_size;
420 stats[Colamd::Status] = Colamd::ErrorATooSmall;
421 stats[Colamd::Info1] = need;
422 stats[Colamd::Info2] = Alen;
423 COLAMD_DEBUG0((
"colamd: Need Alen >= %d, given only Alen = %d\n", need, Alen));
427 Alen -= Col_size + Row_size;
428 Col = (ColStructure<IndexType> *)&A[Alen];
429 Row = (RowStructure<IndexType> *)&A[Alen + Col_size];
433 if (!Colamd::init_rows_cols(n_row, n_col, Row, Col, A, p, stats)) {
435 COLAMD_DEBUG0((
"colamd: Matrix invalid\n"));
441 Colamd::init_scoring(n_row, n_col, Row, Col, A, p, knobs, &n_row2, &n_col2, &max_deg);
445 ngarbage = Colamd::find_ordering(n_row, n_col, Alen, Row, Col, A, p, n_col2, max_deg, 2 * nnz);
449 Colamd::order_children(n_col, Col, p);
453 stats[Colamd::DenseRow] = n_row - n_row2;
454 stats[Colamd::DenseCol] = n_col - n_col2;
455 stats[Colamd::DefragCount] = ngarbage;
456 COLAMD_DEBUG0((
"colamd: done.\n"));
478template <
typename IndexType>
479static IndexType init_rows_cols
485 RowStructure<IndexType> Row[],
486 ColStructure<IndexType> Col[],
489 IndexType stats[NStats]
503 for (col = 0; col < n_col; col++) {
504 Col[col].start = p[col];
505 Col[col].length = p[col + 1] - p[col];
507 if ((Col[col].length) < 0)
510 stats[Colamd::Status] = Colamd::ErrorColLengthNegative;
511 stats[Colamd::Info1] = col;
512 stats[Colamd::Info2] = Col[col].length;
513 COLAMD_DEBUG0((
"colamd: col %d length %d < 0\n", col, Col[col].length));
517 Col[col].shared1.thickness = 1;
518 Col[col].shared2.score = 0;
519 Col[col].shared3.prev = Empty;
520 Col[col].shared4.degree_next = Empty;
529 for (row = 0; row < n_row; row++) {
531 Row[row].shared2.mark = -1;
534 for (col = 0; col < n_col; col++) {
538 cp_end = &A[p[col + 1]];
540 while (cp < cp_end) {
544 if (row < 0 || row >= n_row) {
545 stats[Colamd::Status] = Colamd::ErrorRowIndexOutOfBounds;
546 stats[Colamd::Info1] = col;
547 stats[Colamd::Info2] = row;
548 stats[Colamd::Info3] = n_row;
549 COLAMD_DEBUG0((
"colamd: row %d col %d out of bounds\n", row, col));
553 if (row <= last_row || Row[row].shared2.mark == col) {
556 stats[Colamd::Status] = Colamd::OkButJumbled;
557 stats[Colamd::Info1] = col;
558 stats[Colamd::Info2] = row;
559 (stats[Colamd::Info3])++;
560 COLAMD_DEBUG1((
"colamd: row %d col %d unsorted/duplicate\n", row, col));
563 if (Row[row].shared2.mark != col) {
572 Row[row].shared2.mark = col;
582 Row[0].start = p[n_col];
583 Row[0].shared1.p = Row[0].start;
584 Row[0].shared2.mark = -1;
585 for (row = 1; row < n_row; row++) {
586 Row[row].start = Row[row - 1].start + Row[row - 1].length;
587 Row[row].shared1.p = Row[row].start;
588 Row[row].shared2.mark = -1;
593 if (stats[Status] == OkButJumbled) {
595 for (col = 0; col < n_col; col++) {
597 cp_end = &A[p[col + 1]];
598 while (cp < cp_end) {
600 if (Row[row].shared2.mark != col) {
601 A[(Row[row].shared1.p)++] = col;
602 Row[row].shared2.mark = col;
608 for (col = 0; col < n_col; col++) {
610 cp_end = &A[p[col + 1]];
611 while (cp < cp_end) {
612 A[(Row[*cp++].shared1.p)++] = col;
619 for (row = 0; row < n_row; row++) {
620 Row[row].shared2.mark = 0;
621 Row[row].shared1.degree = Row[row].length;
626 if (stats[Status] == OkButJumbled) {
627 COLAMD_DEBUG0((
"colamd: reconstructing column form, matrix jumbled\n"));
637 for (col = 1; col < n_col; col++) {
640 Col[col].start = Col[col - 1].start + Col[col - 1].length;
641 p[col] = Col[col].start;
646 for (row = 0; row < n_row; row++) {
647 rp = &A[Row[row].start];
648 rp_end = rp + Row[row].length;
649 while (rp < rp_end) {
650 A[(p[*rp++])++] = row;
668template <
typename IndexType>
669static void init_scoring(
674 RowStructure<IndexType> Row[],
675 ColStructure<IndexType> Col[],
678 double knobs[NKnobs],
691 IndexType col_length;
695 IndexType dense_row_count;
696 IndexType dense_col_count;
703 dense_row_count = numext::maxi(IndexType(0), numext::mini(IndexType(knobs[Colamd::DenseRow] * n_col), n_col));
704 dense_col_count = numext::maxi(IndexType(0), numext::mini(IndexType(knobs[Colamd::DenseCol] * n_row), n_row));
705 COLAMD_DEBUG1((
"colamd: densecount: %d %d\n", dense_row_count, dense_col_count));
714 for (c = n_col - 1; c >= 0; c--) {
718 Col[c].shared2.order = --n_col2;
719 Col[c].kill_principal();
722 COLAMD_DEBUG1((
"colamd: null columns killed: %d\n", n_col - n_col2));
727 for (c = n_col - 1; c >= 0; c--) {
729 if (Col[c].is_dead()) {
733 if (deg > dense_col_count) {
735 Col[c].shared2.order = --n_col2;
737 cp = &A[Col[c].start];
738 cp_end = cp + Col[c].length;
739 while (cp < cp_end) {
740 Row[*cp++].shared1.degree--;
742 Col[c].kill_principal();
745 COLAMD_DEBUG1((
"colamd: Dense and null columns killed: %d\n", n_col - n_col2));
749 for (r = 0; r < n_row; r++) {
750 deg = Row[r].shared1.degree;
751 COLAMD_ASSERT(deg >= 0 && deg <= n_col);
752 if (deg > dense_row_count || deg == 0) {
758 max_deg = numext::maxi(max_deg, deg);
761 COLAMD_DEBUG1((
"colamd: Dense and null rows killed: %d\n", n_row - n_row2));
771 for (c = n_col - 1; c >= 0; c--) {
773 if (Col[c].is_dead()) {
777 cp = &A[Col[c].start];
779 cp_end = cp + Col[c].length;
780 while (cp < cp_end) {
784 if (Row[row].is_dead()) {
790 score += Row[row].shared1.degree - 1;
792 score = numext::mini(score, n_col);
795 col_length = (IndexType)(new_cp - &A[Col[c].start]);
796 if (col_length == 0) {
799 COLAMD_DEBUG2((
"Newly null killed: %d\n", c));
800 Col[c].shared2.order = --n_col2;
801 Col[c].kill_principal();
804 COLAMD_ASSERT(score >= 0);
805 COLAMD_ASSERT(score <= n_col);
806 Col[c].length = col_length;
807 Col[c].shared2.score = score;
810 COLAMD_DEBUG1((
"colamd: Dense, null, and newly-null columns killed: %d\n", n_col - n_col2));
820 for (c = 0; c <= n_col; c++) {
826 for (c = n_col - 1; c >= 0; c--) {
828 if (Col[c].is_alive()) {
829 COLAMD_DEBUG4((
"place %d score %d minscore %d ncol %d\n", c, Col[c].shared2.score, min_score, n_col));
833 score = Col[c].shared2.score;
835 COLAMD_ASSERT(min_score >= 0);
836 COLAMD_ASSERT(min_score <= n_col);
837 COLAMD_ASSERT(score >= 0);
838 COLAMD_ASSERT(score <= n_col);
839 COLAMD_ASSERT(head[score] >= Empty);
842 next_col = head[score];
843 Col[c].shared3.prev = Empty;
844 Col[c].shared4.degree_next = next_col;
848 if (next_col != Empty) {
849 Col[next_col].shared3.prev = c;
854 min_score = numext::mini(min_score, score);
862 *p_max_deg = max_deg;
874template <
typename IndexType>
875static IndexType find_ordering
882 RowStructure<IndexType> Row[],
883 ColStructure<IndexType> Col[],
899 IndexType pivot_row_start;
900 IndexType pivot_row_degree;
901 IndexType pivot_row_length;
902 IndexType pivot_col_score;
903 IndexType needed_memory;
911 IndexType head_column;
915 IndexType set_difference;
917 IndexType col_thickness;
919 IndexType pivot_col_thickness;
926 max_mark = INT_MAX - n_col;
927 tag_mark = Colamd::clear_mark(n_row, Row);
930 COLAMD_DEBUG1((
"colamd: Ordering, n_col2=%d\n", n_col2));
934 for (k = 0; k < n_col2; ) {
938 COLAMD_ASSERT(min_score >= 0);
939 COLAMD_ASSERT(min_score <= n_col);
940 COLAMD_ASSERT(head[min_score] >= Empty);
943 while (min_score < n_col && head[min_score] == Empty) {
946 pivot_col = head[min_score];
947 COLAMD_ASSERT(pivot_col >= 0 && pivot_col <= n_col);
948 next_col = Col[pivot_col].shared4.degree_next;
949 head[min_score] = next_col;
950 if (next_col != Empty) {
951 Col[next_col].shared3.prev = Empty;
954 COLAMD_ASSERT(Col[pivot_col].is_alive());
955 COLAMD_DEBUG3((
"Pivot col: %d\n", pivot_col));
958 pivot_col_score = Col[pivot_col].shared2.score;
961 Col[pivot_col].shared2.order = k;
964 pivot_col_thickness = Col[pivot_col].shared1.thickness;
965 k += pivot_col_thickness;
966 COLAMD_ASSERT(pivot_col_thickness > 0);
970 needed_memory = numext::mini(pivot_col_score, n_col - k);
971 if (pfree + needed_memory >= Alen) {
972 pfree = Colamd::garbage_collection(n_row, n_col, Row, Col, A, &A[pfree]);
975 COLAMD_ASSERT(pfree + needed_memory < Alen);
977 tag_mark = Colamd::clear_mark(n_row, Row);
983 pivot_row_start = pfree;
986 pivot_row_degree = 0;
990 Col[pivot_col].shared1.thickness = -pivot_col_thickness;
993 cp = &A[Col[pivot_col].start];
994 cp_end = cp + Col[pivot_col].length;
995 while (cp < cp_end) {
998 COLAMD_DEBUG4((
"Pivot col pattern %d %d\n", Row[row].is_alive(), row));
1000 if (Row[row].is_dead()) {
1003 rp = &A[Row[row].start];
1004 rp_end = rp + Row[row].length;
1005 while (rp < rp_end) {
1009 col_thickness = Col[col].shared1.thickness;
1010 if (col_thickness > 0 && Col[col].is_alive()) {
1012 Col[col].shared1.thickness = -col_thickness;
1013 COLAMD_ASSERT(pfree < Alen);
1016 pivot_row_degree += col_thickness;
1022 Col[pivot_col].shared1.thickness = pivot_col_thickness;
1023 max_deg = numext::maxi(max_deg, pivot_row_degree);
1028 cp = &A[Col[pivot_col].start];
1029 cp_end = cp + Col[pivot_col].length;
1030 while (cp < cp_end) {
1033 COLAMD_DEBUG3((
"Kill row in pivot col: %d\n", row));
1039 pivot_row_length = pfree - pivot_row_start;
1040 if (pivot_row_length > 0) {
1042 pivot_row = A[Col[pivot_col].start];
1043 COLAMD_DEBUG3((
"Pivotal row is %d\n", pivot_row));
1047 COLAMD_ASSERT(pivot_row_length == 0);
1049 COLAMD_ASSERT(Col[pivot_col].length > 0 || pivot_row_length == 0);
1072 COLAMD_DEBUG3((
"** Computing set differences phase. **\n"));
1076 COLAMD_DEBUG3((
"Pivot row: "));
1078 rp = &A[pivot_row_start];
1079 rp_end = rp + pivot_row_length;
1080 while (rp < rp_end) {
1082 COLAMD_ASSERT(Col[col].is_alive() && col != pivot_col);
1083 COLAMD_DEBUG3((
"Col: %d\n", col));
1086 col_thickness = -Col[col].shared1.thickness;
1087 COLAMD_ASSERT(col_thickness > 0);
1088 Col[col].shared1.thickness = col_thickness;
1092 cur_score = Col[col].shared2.score;
1093 prev_col = Col[col].shared3.prev;
1094 next_col = Col[col].shared4.degree_next;
1095 COLAMD_ASSERT(cur_score >= 0);
1096 COLAMD_ASSERT(cur_score <= n_col);
1097 COLAMD_ASSERT(cur_score >= Empty);
1098 if (prev_col == Empty) {
1099 head[cur_score] = next_col;
1101 Col[prev_col].shared4.degree_next = next_col;
1103 if (next_col != Empty) {
1104 Col[next_col].shared3.prev = prev_col;
1109 cp = &A[Col[col].start];
1110 cp_end = cp + Col[col].length;
1111 while (cp < cp_end) {
1115 if (Row[row].is_dead()) {
1118 row_mark = Row[row].shared2.mark;
1119 COLAMD_ASSERT(row != pivot_row);
1120 set_difference = row_mark - tag_mark;
1122 if (set_difference < 0) {
1123 COLAMD_ASSERT(Row[row].shared1.degree <= max_deg);
1124 set_difference = Row[row].shared1.degree;
1127 set_difference -= col_thickness;
1128 COLAMD_ASSERT(set_difference >= 0);
1130 if (set_difference == 0) {
1131 COLAMD_DEBUG3((
"aggressive absorption. Row: %d\n", row));
1135 Row[row].shared2.mark = set_difference + tag_mark;
1142 COLAMD_DEBUG3((
"** Adding set differences phase. **\n"));
1145 rp = &A[pivot_row_start];
1146 rp_end = rp + pivot_row_length;
1147 while (rp < rp_end) {
1150 COLAMD_ASSERT(Col[col].is_alive() && col != pivot_col);
1153 cp = &A[Col[col].start];
1156 cp_end = cp + Col[col].length;
1158 COLAMD_DEBUG4((
"Adding set diffs for Col: %d.\n", col));
1160 while (cp < cp_end) {
1163 COLAMD_ASSERT(row >= 0 && row < n_row);
1165 if (Row[row].is_dead()) {
1168 row_mark = Row[row].shared2.mark;
1169 COLAMD_ASSERT(row_mark > tag_mark);
1175 cur_score += row_mark - tag_mark;
1177 cur_score = numext::mini(cur_score, n_col);
1181 Col[col].length = (IndexType)(new_cp - &A[Col[col].start]);
1185 if (Col[col].length == 0) {
1186 COLAMD_DEBUG4((
"further mass elimination. Col: %d\n", col));
1188 Col[col].kill_principal();
1189 pivot_row_degree -= Col[col].shared1.thickness;
1190 COLAMD_ASSERT(pivot_row_degree >= 0);
1192 Col[col].shared2.order = k;
1194 k += Col[col].shared1.thickness;
1198 COLAMD_DEBUG4((
"Preparing supercol detection for Col: %d.\n", col));
1201 Col[col].shared2.score = cur_score;
1206 COLAMD_DEBUG4((
" Hash = %d, n_col = %d.\n", hash, n_col));
1207 COLAMD_ASSERT(hash <= n_col);
1209 head_column = head[hash];
1210 if (head_column > Empty) {
1213 first_col = Col[head_column].shared3.headhash;
1214 Col[head_column].shared3.headhash = col;
1217 first_col = -(head_column + 2);
1218 head[hash] = -(col + 2);
1220 Col[col].shared4.hash_next = first_col;
1223 Col[col].shared3.hash = (IndexType)hash;
1224 COLAMD_ASSERT(Col[col].is_alive());
1232 COLAMD_DEBUG3((
"** Supercolumn detection phase. **\n"));
1234 Colamd::detect_super_cols(Col, A, head, pivot_row_start, pivot_row_length);
1238 Col[pivot_col].kill_principal();
1242 tag_mark += (max_deg + 1);
1243 if (tag_mark >= max_mark) {
1244 COLAMD_DEBUG2((
"clearing tag_mark\n"));
1245 tag_mark = Colamd::clear_mark(n_row, Row);
1250 COLAMD_DEBUG3((
"** Finalize scores phase. **\n"));
1253 rp = &A[pivot_row_start];
1256 rp_end = rp + pivot_row_length;
1257 while (rp < rp_end) {
1260 if (Col[col].is_dead()) {
1265 A[Col[col].start + (Col[col].length++)] = pivot_row;
1270 cur_score = Col[col].shared2.score + pivot_row_degree;
1275 max_score = n_col - k - Col[col].shared1.thickness;
1278 cur_score -= Col[col].shared1.thickness;
1281 cur_score = numext::mini(cur_score, max_score);
1282 COLAMD_ASSERT(cur_score >= 0);
1285 Col[col].shared2.score = cur_score;
1289 COLAMD_ASSERT(min_score >= 0);
1290 COLAMD_ASSERT(min_score <= n_col);
1291 COLAMD_ASSERT(cur_score >= 0);
1292 COLAMD_ASSERT(cur_score <= n_col);
1293 COLAMD_ASSERT(head[cur_score] >= Empty);
1294 next_col = head[cur_score];
1295 Col[col].shared4.degree_next = next_col;
1296 Col[col].shared3.prev = Empty;
1297 if (next_col != Empty) {
1298 Col[next_col].shared3.prev = col;
1300 head[cur_score] = col;
1303 min_score = numext::mini(min_score, cur_score);
1308 if (pivot_row_degree > 0) {
1311 Row[pivot_row].start = pivot_row_start;
1312 Row[pivot_row].length = (IndexType)(new_rp - &A[pivot_row_start]);
1313 Row[pivot_row].shared1.degree = pivot_row_degree;
1314 Row[pivot_row].shared2.mark = 0;
1340template <
typename IndexType>
1341static inline void order_children(
1345 ColStructure<IndexType> Col[],
1357 for (i = 0; i < n_col; i++) {
1359 COLAMD_ASSERT(col_is_dead(Col, i));
1360 if (!Col[i].is_dead_principal() && Col[i].shared2.order == Empty) {
1364 parent = Col[parent].shared1.parent;
1365 }
while (!Col[parent].is_dead_principal());
1371 order = Col[parent].shared2.order;
1374 COLAMD_ASSERT(Col[c].shared2.order == Empty);
1377 Col[c].shared2.order = order++;
1379 Col[c].shared1.parent = parent;
1382 c = Col[c].shared1.parent;
1387 }
while (Col[c].shared2.order == Empty);
1390 Col[parent].shared2.order = order;
1396 for (c = 0; c < n_col; c++) {
1397 p[Col[c].shared2.order] = c;
1433template <
typename IndexType>
1434static void detect_super_cols(
1437 ColStructure<IndexType> Col[],
1440 IndexType row_start,
1441 IndexType row_length
1456 IndexType head_column;
1457 IndexType first_col;
1462 rp_end = rp + row_length;
1463 while (rp < rp_end) {
1465 if (Col[col].is_dead()) {
1470 hash = Col[col].shared3.hash;
1471 COLAMD_ASSERT(hash <= n_col);
1475 head_column = head[hash];
1476 if (head_column > Empty) {
1477 first_col = Col[head_column].shared3.headhash;
1479 first_col = -(head_column + 2);
1484 for (super_c = first_col; super_c != Empty; super_c = Col[super_c].shared4.hash_next) {
1485 COLAMD_ASSERT(Col[super_c].is_alive());
1486 COLAMD_ASSERT(Col[super_c].shared3.hash == hash);
1487 length = Col[super_c].length;
1494 for (c = Col[super_c].shared4.hash_next; c != Empty; c = Col[c].shared4.hash_next) {
1495 COLAMD_ASSERT(c != super_c);
1496 COLAMD_ASSERT(Col[c].is_alive());
1497 COLAMD_ASSERT(Col[c].shared3.hash == hash);
1500 if (Col[c].length != length || Col[c].shared2.score != Col[super_c].shared2.score) {
1506 cp1 = &A[Col[super_c].start];
1507 cp2 = &A[Col[c].start];
1509 for (i = 0; i < length; i++) {
1511 COLAMD_ASSERT(cp1->is_alive());
1512 COLAMD_ASSERT(cp2->is_alive());
1515 if (*cp1++ != *cp2++) {
1528 COLAMD_ASSERT(Col[c].shared2.score == Col[super_c].shared2.score);
1530 Col[super_c].shared1.thickness += Col[c].shared1.thickness;
1531 Col[c].shared1.parent = super_c;
1532 Col[c].kill_non_principal();
1534 Col[c].shared2.order = Empty;
1536 Col[prev_c].shared4.hash_next = Col[c].shared4.hash_next;
1542 if (head_column > Empty) {
1544 Col[head_column].shared3.headhash = Empty;
1564template <
typename IndexType>
1565static IndexType garbage_collection
1571 RowStructure<IndexType> Row[],
1572 ColStructure<IndexType> Col[],
1588 for (c = 0; c < n_col; c++) {
1589 if (Col[c].is_alive()) {
1590 psrc = &A[Col[c].start];
1593 COLAMD_ASSERT(pdest <= psrc);
1594 Col[c].start = (IndexType)(pdest - &A[0]);
1595 length = Col[c].length;
1596 for (j = 0; j < length; j++) {
1598 if (Row[r].is_alive()) {
1602 Col[c].length = (IndexType)(pdest - &A[Col[c].start]);
1608 for (r = 0; r < n_row; r++) {
1609 if (Row[r].is_alive()) {
1610 if (Row[r].length == 0) {
1612 COLAMD_DEBUG3((
"Defrag row kill\n"));
1616 psrc = &A[Row[r].start];
1617 Row[r].shared2.first_column = *psrc;
1618 COLAMD_ASSERT(Row[r].is_alive());
1620 *psrc = ones_complement(r);
1628 while (psrc < pfree) {
1633 r = ones_complement(*psrc);
1634 COLAMD_ASSERT(r >= 0 && r < n_row);
1636 *psrc = Row[r].shared2.first_column;
1637 COLAMD_ASSERT(Row[r].is_alive());
1640 COLAMD_ASSERT(pdest <= psrc);
1641 Row[r].start = (IndexType)(pdest - &A[0]);
1642 length = Row[r].length;
1643 for (j = 0; j < length; j++) {
1645 if (Col[c].is_alive()) {
1649 Row[r].length = (IndexType)(pdest - &A[Row[r].start]);
1653 COLAMD_ASSERT(debug_rows == 0);
1657 return ((IndexType)(pdest - &A[0]));
1668template <
typename IndexType>
1669static inline IndexType clear_mark
1674 RowStructure<IndexType> Row[]
1680 for (r = 0; r < n_row; r++) {
1681 if (Row[r].is_alive()) {
1682 Row[r].shared2.mark = 0;