9static void degree_bucket_remove(
size_t node,
size_t degree,
10 size_t* heads,
size_t* next,
size_t* prev)
12 if (prev[node] != SIZE_MAX) {
13 next[prev[node]] = next[node];
15 heads[degree] = next[node];
17 if (next[node] != SIZE_MAX) {
18 prev[next[node]] = prev[node];
20 next[node] = SIZE_MAX;
21 prev[node] = SIZE_MAX;
24static void degree_bucket_insert(
size_t node,
size_t degree,
25 size_t* heads,
size_t* next,
size_t* prev)
27 next[node] = heads[degree];
28 prev[node] = SIZE_MAX;
29 if (heads[degree] != SIZE_MAX) {
30 prev[heads[degree]] = node;
70 if (!lmmc_safe_mul_size(n,
sizeof(
size_t), &bytes)) {
80 degree_workspace_destroy(work);
85static size_t eliminate_neighbors(
size_t node,
const size_t* col_ptr,
88 for (
size_t p = col_ptr[node]; p < col_ptr[node + 1]; ++p) {
89 const size_t neighbor = row_idx[p];
93 size_t old_degree = work->
degree[neighbor];
94 degree_bucket_remove(neighbor, old_degree, work->
heads, work->
next, work->
prev);
95 work->
degree[neighbor] = old_degree - 1;
96 degree_bucket_insert(neighbor, work->
degree[neighbor],
98 if (work->
degree[neighbor] < current_min) {
99 current_min = work->
degree[neighbor];
105static lmmc_status_t reorder_buckets(
size_t n,
const size_t* col_ptr,
108 size_t current_min = SIZE_MAX;
110 for (
size_t i = 0; i < n; ++i) {
111 work->
heads[i] = SIZE_MAX;
112 work->
next[i] = SIZE_MAX;
113 work->
prev[i] = SIZE_MAX;
115 for (
size_t i = 0; i < n; ++i) {
116 work->
degree[i] = col_ptr[i + 1] - col_ptr[i];
118 if (current_min == SIZE_MAX || work->
degree[i] < current_min) {
119 current_min = work->
degree[i];
123 for (
size_t step = 0; step < n; ++step) {
126 while (current_min < n && work->heads[current_min] == SIZE_MAX) {
129 if (current_min == n) {
133 node = work->
heads[current_min];
134 for (candidate = work->
next[node]; candidate != SIZE_MAX; candidate = work->
next[candidate]) {
135 if (candidate < node) {
143 current_min = eliminate_neighbors(node, col_ptr, row_idx, work, current_min);
150 const size_t* col_ptr,
151 const size_t* row_idx,
157 if (!col_ptr || !perm) {
160 if (col_ptr[n] == 0) {
161 for (
size_t i = 0; i < n; ++i) perm[i] = i;
172 status = reorder_buckets(n, col_ptr, row_idx, perm, &work);
173 degree_workspace_destroy(&work);
176static lmmc_status_t count_graph_edges(
size_t n,
const size_t* col_ptr,
177 const size_t* row_idx,
size_t* graph_col_ptr)
179 for (
size_t column = 0; column < n; ++column) {
180 for (
size_t p = col_ptr[column]; p < col_ptr[column + 1]; ++p) {
181 const size_t row = row_idx[p];
188 if (graph_col_ptr[column + 1] == SIZE_MAX ||
189 graph_col_ptr[row + 1] == SIZE_MAX) {
192 ++graph_col_ptr[column + 1];
193 ++graph_col_ptr[row + 1];
196 for (
size_t column = 0; column < n; ++column) {
197 if (!lmmc_safe_add_size(graph_col_ptr[column],
198 graph_col_ptr[column + 1],
199 &graph_col_ptr[column + 1])) {
206static void fill_graph_edges(
size_t n,
const size_t* col_ptr,
207 const size_t* row_idx,
const size_t* graph_col_ptr,
208 size_t* graph_row_idx,
size_t* cursor)
210 memcpy(cursor, graph_col_ptr, n *
sizeof(
size_t));
211 for (
size_t column = 0; column < n; ++column) {
212 for (
size_t p = col_ptr[column]; p < col_ptr[column + 1]; ++p) {
213 const size_t row = row_idx[p];
217 graph_row_idx[cursor[column]++] = row;
218 graph_row_idx[cursor[row]++] = column;
223static void compact_graph_edges(
size_t n,
size_t* graph_col_ptr,
224 size_t* graph_row_idx,
size_t* stamp)
226 size_t read_begin = 0;
228 for (
size_t i = 0; i < n; ++i) stamp[i] = SIZE_MAX;
229 for (
size_t column = 0; column < n; ++column) {
230 const size_t read_end = graph_col_ptr[column + 1];
231 graph_col_ptr[column] = write;
232 for (
size_t p = read_begin; p < read_end; ++p) {
233 const size_t row = graph_row_idx[p];
234 if (stamp[row] != column) {
236 graph_row_idx[write++] = row;
239 read_begin = read_end;
241 graph_col_ptr[n] = write;
244static lmmc_status_t allocate_graph_indices(
size_t n,
size_t** graph_col_ptr,
245 size_t** cursor,
size_t** stamp)
247 size_t pointer_count, pointer_bytes, index_bytes;
248 if (!lmmc_safe_add_size(n, 1, &pointer_count) ||
249 !lmmc_safe_mul_size(pointer_count,
sizeof(
size_t), &pointer_bytes)) {
252 if (!lmmc_safe_mul_size(n,
sizeof(
size_t), &index_bytes)) {
258 if (!*graph_col_ptr || (n != 0 && (!*cursor || !*stamp))) {
264 memset(*graph_col_ptr, 0, pointer_bytes);
274 const size_t* col_ptr,
275 const size_t* row_idx,
276 size_t** out_graph_col_ptr,
277 size_t** out_graph_row_idx)
281 size_t* graph_col_ptr = NULL;
282 size_t* graph_row_idx = NULL;
283 size_t* cursor = NULL;
284 size_t* stamp = NULL;
286 status = allocate_graph_indices(n, &graph_col_ptr, &cursor, &stamp);
290status = count_graph_edges(n, col_ptr, row_idx, graph_col_ptr);
294 raw_nnz = graph_col_ptr[n];
297 if (!lmmc_safe_mul_size(raw_nnz,
sizeof(
size_t), &index_bytes)) {
301 if (!graph_row_idx) {
304 fill_graph_edges(n, col_ptr, row_idx, graph_col_ptr, graph_row_idx, cursor);
305 compact_graph_edges(n, graph_col_ptr, graph_row_idx, stamp);
307 *out_graph_col_ptr = graph_col_ptr;
308 *out_graph_row_idx = graph_row_idx;
325 size_t* sym_col_ptr = NULL;
326 size_t* sym_row_idx = NULL;
332 status = bucketed_greedy_residual_degree_reorder(
333 csc->
rows, sym_col_ptr, sym_row_idx, perm);
void * lmmc_memory_alloc(size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t lmmc_sparse_residual_reorder(const lmmc_sparse_mat_t *csc, size_t *perm)
unsigned char * eliminated
按当前残余度贪心选择顶点,度数桶支持常数时间更新。 同度数时选择原始索引最小的顶点,保证结果确定。消去时仅删除残余关联边, 不模拟填充边,区别于近似最小度算法。
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT