From a76146cdafc79f92389ac5e64a095e3d5a09e7c9 Mon Sep 17 00:00:00 2001 From: Jukka Aho Date: Sat, 8 Nov 2025 11:29:19 +0200 Subject: [PATCH] feat: Consolidate GraphOrdering.jl (RCM bandwidth minimization) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added 96 lines of graph algorithm code to src/graph/ - Reverse Cuthill-McKee (RCM) ordering for sparse matrix bandwidth minimization - Critical for efficient FEM assembly and solving - Functions: symrcm, bandwidth, reorder - Renamed Result → GraphOrderingResult for clarity Result: 8 vendor packages consolidated (~6500 lines total) Tests: 5 passing (baseline maintained) --- src/JuliaFEM.jl | 3 ++ src/graph/graph_ordering.jl | 98 +++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/graph/graph_ordering.jl diff --git a/src/JuliaFEM.jl b/src/JuliaFEM.jl index 0a36479..0446e0e 100644 --- a/src/JuliaFEM.jl +++ b/src/JuliaFEM.jl @@ -167,6 +167,9 @@ include("deprecated_fembase.jl") # Deprecated/legacy methods from FEMBase (l # Mesh readers (consolidated from AbaqusReader.jl and AsterReader.jl) include("readers.jl") +# Graph algorithms (RCM bandwidth minimization from GraphOrdering.jl) +include("graph/graph_ordering.jl") + using TimerOutputs export @timeit, print_timer diff --git a/src/graph/graph_ordering.jl b/src/graph/graph_ordering.jl new file mode 100644 index 0000000..998de70 --- /dev/null +++ b/src/graph/graph_ordering.jl @@ -0,0 +1,98 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/GraphOrdering.jl/blob/master/LICENSE +# +# Graph ordering algorithms (RCM bandwidth minimization) +# Consolidated from GraphOrdering.jl + +struct GraphOrderingResult + perm :: Vector{Int} + invperm :: Vector{Int} + degrees :: Vector{Int} + edge :: Vector{Int} + dist :: Vector{Int} +end + +""" + bandwidth(G) + +Calculate the bandwidth of the graph G. +""" + +function bandwidth(G) + bw = -1 + for (v, adj) in G + for w in adj + bw = max(bw, abs(v-w)) + end + end + return 2*bw + 1 +end + +""" + symrcm(G, v) + +Sparse reverse Cuthill-McKee ordering. `G` is graph presented as adjacency list +and `v` is starting vertex. Returns `Result` type, which contains bandwidth +minimizing permutation, inverse of permutation and some other results. +""" +function symrcm(G, v) + n = length(G) + permutation = zeros(Int, n) + permutation[1] = v + visited = zeros(Bool, n) + visited[v] = true + degrees = [length(G[i]) for i in 1:n] + order = Base.Order.By(j -> degrees[j]) + connected = zeros(Int, n) + edge = zeros(Int, n) + dist = zeros(Int, n) + nwrk = 0 + wrk = zeros(Int, nwrk) + idx = 2 + + for i=1:n + + v = permutation[i] + adj = G[v] + nadj = length(adj) + + aux = adj + # aux is adj or wrk, depending is adj in order. If adj is not sorted, + # copy degrees from adj to aux and make in-place sort + if (!issorted(aux, order)) + aux = wrk + resize!(aux, max(nadj, length(aux))) + copyto!(aux, adj) + sort!(aux, 1, nadj, InsertionSort, order) + end + + for wi = 1:nadj + w = aux[wi] + visited[w] && continue + visited[w] = true + permutation[idx] = w + edge[w] = v + dist[w] = dist[v] + 1 + idx += 1 + end + + end + + perm = reverse(permutation) + return GraphOrderingResult(perm, invperm(perm), degrees, edge, dist) +end + +""" + reorder(G, res) + +Given result of `symrcm`, reorder nodes of graph `G`. Returns +new graph with nodes ordered corresponding the new permuation. +""" +function reorder(G, res::GraphOrderingResult) + H = empty(G) + for (v, adj) in G + H[res.invperm[v]] = [res.invperm[w] for w in adj] + end + return H +end +