From 0c79f0dc03009bbcde5a306cc392cb46002cf52c Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Wed, 20 Nov 2024 22:22:53 -0500 Subject: [PATCH 001/100] temp commit --- src/junction_trees/elimination_algorithms.jl | 88 ++++++++++++++++++-- 1 file changed, 79 insertions(+), 9 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index 71d5d5c..b11558d 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -61,36 +61,52 @@ function Order(graph::AbstractSymmetricGraph) end +""" + Order(matrix::AbstractMatrix[, ealg::EliminationAlgorithm]) + +Construct an elimination order for a matrix, optionally specifying an elimination algorithm. +""" +function Order(matrix::AbstractMatrix) + Order(matrix, DEFAULT_ELIMINATION_ALGORITHM) +end + + +# Construct an order. +function Order(graph::AbstractSymmetricGraph, ealg::Union{CuthillMcKeeJL_RCM, AMDJL_AMD, MetisJL_ND, TreeWidthSolverJL_BT}) + Order(adjacencymatrix(graph), ealg) +end + + # Construct an order using the reverse Cuthill-McKee algorithm. Uses CuthillMcKee.jl. -function Order(graph::AbstractSymmetricGraph, ealg::CuthillMcKeeJL_RCM) - order = CuthillMcKee.symrcm(adjacencymatrix(graph)) +function Order(matrix::AbstractMatrix, ealg::CuthillMcKeeJL_RCM) + order = CuthillMcKee.symrcm(matrix) Order(order) end # Construct an order using the approximate minimum degree algorithm. Uses AMD.jl. -function Order(graph::AbstractSymmetricGraph, ealg::AMDJL_AMD) - order = AMD.symamd(adjacencymatrix(graph)) +function Order(matrix::AbstractMatrix, ealg::AMDJL_AMD) + order = AMD.symamd(matrix) Order(order) end # Construct an order using the nested dissection heuristic. Uses Metis.jl. -function Order(graph::AbstractSymmetricGraph, ealg::MetisJL_ND) - order, index = Metis.permutation(adjacencymatrix(graph)) +function Order(matrix::AbstractMatrix, ealg::MetisJL_ND) + order, index = Metis.permutation(matrix) Order(order, index) end # Construct an order using the Bouchitte-Todinca algorithm. Uses TreeWidthSolver.jl. -function Order(graph::AbstractSymmetricGraph, ealg::TreeWidthSolverJL_BT) - n = nv(graph) +function Order(matrix::AbstractMatrix, ealg::TreeWidthSolverJL_BT) + n = size(matrix, 1) T = TreeWidthSolver.LongLongUInt{n ÷ 64 + 1} fadjlist = Vector{Vector{Int}}(undef, n) bitfadjlist = Vector{T}(undef, n) for i in 1:n - fadjlist[i] = sort(collect(outneighbors(graph, i))) + fadjlist[i] = matrix.rowval[matrix.colptr[i]:matrix.colptr[i + 1] - 1] bitfadjlist[i] = TreeWidthSolver.bmask(T, fadjlist[i]) end @@ -108,6 +124,13 @@ function Order(graph::AbstractSymmetricGraph, ealg::MCS) end +# Construct an order using the maximum cardinality search algorithm. +function Order(matrix::AbstractMatrix, ealg::MCS) + order, index = mcs(matrix) + Order(order, index) +end + + # Construct the adjacency matrix of a graph. function adjacencymatrix(graph::AbstractSymmetricGraph) m = ne(graph) @@ -175,4 +198,51 @@ function mcs(graph::AbstractSymmetricGraph) end +# Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs +# Tarjan and Yannakakis +# Maximum Cardinality Search +function mcs(matrix::SparseMatrixCSC) + n = size(matrix, 1) + α = Vector{Int}(undef, n) + β = Vector{Int}(undef, n) + len = Vector{Int}(undef, n) + set = Vector{LinkedLists.LinkedList{Int}}(undef, n) + pointer = Vector{LinkedLists.ListNode{Int}}(undef, n) + + for i in 1:n + len[i] = 1 + set[i] = LinkedLists.LinkedList{Int}() + pointer[i] = push!(set[1], i) + end + + i = n + j = 1 + + while i >= 1 + v = first(set[j]) + deleteat!(set[j], pointer[v]) + α[v] = i + β[i] = v + len[v] = 0 + + for w in matrix.rowval[matrix.colptr[v]:matrix.colptr[v] + 1] + if len[w] >= 1 + deleteat!(set[len[w]], pointer[w]) + len[w] += 1 + pointer[w] = push!(set[len[w]], w) + end + end + + i -= 1 + j += 1 + + while j >= 1 && isempty(set[j]) + j -= 1 + end + end + + β, α +end + + const DEFAULT_ELIMINATION_ALGORITHM = AMDJL_AMD() From 549821a99647885084862c3d9f687a2c845bb805 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Wed, 20 Nov 2024 22:29:42 -0500 Subject: [PATCH 002/100] temp commit --- src/junction_trees/elimination_algorithms.jl | 68 ++------------------ 1 file changed, 4 insertions(+), 64 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index b11558d..ddc46bc 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -52,12 +52,12 @@ struct MCS <: EliminationAlgorithm end """ - Order(graph::AbstractSymmetricGraph[, ealg::EliminationAlgorithm]) + Order(graph[, ealg::EliminationAlgorithm]) Construct an elimination order for a simple graph, optionally specifying an elimination algorithm. """ -function Order(graph::AbstractSymmetricGraph) - Order(graph, DEFAULT_ELIMINATION_ALGORITHM) +function Order(graph, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM) + Order(adjacencymatrix(graph), ealg) end @@ -71,12 +71,6 @@ function Order(matrix::AbstractMatrix) end -# Construct an order. -function Order(graph::AbstractSymmetricGraph, ealg::Union{CuthillMcKeeJL_RCM, AMDJL_AMD, MetisJL_ND, TreeWidthSolverJL_BT}) - Order(adjacencymatrix(graph), ealg) -end - - # Construct an order using the reverse Cuthill-McKee algorithm. Uses CuthillMcKee.jl. function Order(matrix::AbstractMatrix, ealg::CuthillMcKeeJL_RCM) order = CuthillMcKee.symrcm(matrix) @@ -117,13 +111,6 @@ function Order(matrix::AbstractMatrix, ealg::TreeWidthSolverJL_BT) end -# Construct an order using the maximum cardinality search algorithm. -function Order(graph::AbstractSymmetricGraph, ealg::MCS) - order, index = mcs(graph) - Order(order, index) -end - - # Construct an order using the maximum cardinality search algorithm. function Order(matrix::AbstractMatrix, ealg::MCS) order, index = mcs(matrix) @@ -132,7 +119,7 @@ end # Construct the adjacency matrix of a graph. -function adjacencymatrix(graph::AbstractSymmetricGraph) +function adjacencymatrix(graph::HasGraph) m = ne(graph) n = nv(graph) @@ -151,53 +138,6 @@ function adjacencymatrix(graph::AbstractSymmetricGraph) end -# Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs -# Tarjan and Yannakakis -# Maximum Cardinality Search -function mcs(graph::AbstractSymmetricGraph) - n = nv(graph) - α = Vector{Int}(undef, n) - β = Vector{Int}(undef, n) - size = Vector{Int}(undef, n) - set = Vector{LinkedLists.LinkedList{Int}}(undef, n) - pointer = Vector{LinkedLists.ListNode{Int}}(undef, n) - - for i in 1:n - size[i] = 1 - set[i] = LinkedLists.LinkedList{Int}() - pointer[i] = push!(set[1], i) - end - - i = n - j = 1 - - while i >= 1 - v = first(set[j]) - deleteat!(set[j], pointer[v]) - α[v] = i - β[i] = v - size[v] = 0 - - for w in neighbors(graph, v) - if size[w] >= 1 - deleteat!(set[size[w]], pointer[w]) - size[w] += 1 - pointer[w] = push!(set[size[w]], w) - end - end - - i -= 1 - j += 1 - - while j >= 1 && isempty(set[j]) - j -= 1 - end - end - - β, α -end - - # Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs # Tarjan and Yannakakis # Maximum Cardinality Search From 400e7c174796dc04154c3078fa5a7fbbea3fee05 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Wed, 20 Nov 2024 22:54:21 -0500 Subject: [PATCH 003/100] first class support for sparse matrices --- src/junction_trees/ordered_graphs.jl | 113 +++++++++++++++------------ 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index f06fa96..1cd1d03 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -7,32 +7,48 @@ end # Given a graph G, construct the ordered graph # (G, σ), -# where the permutation σ is computed using an elimination algorithm. +# where σ is a permutation computed using an elimination algorithm. # ---------------------------------------- -# sgraph simple connected graph +# graph simple connected graph # ealg elimination algorithm # ---------------------------------------- -function OrderedGraph(sgraph::AbstractSymmetricGraph, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM) - OrderedGraph(sgraph, Order(sgraph, ealg)) +function OrderedGraph(graph, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM) + OrderedGraph(adjacencymatrix(graph), ealg) end -# Given a graph G and permutation σ, construct the ordered graph -# (G, σ). +# Given a matrix M, construct the ordered graph +# (G, σ), +# where G is the sparsity graph if M and σ is a permutation computed using an elimination +# algorithm. +# ---------------------------------------- +# matrix symmetric matrix +# ealg elimination algorithm # ---------------------------------------- -# sgraph simple connected graph +function OrderedGraph(matrix::AbstractMatrix, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM) + OrderedGraph(matrix, Order(matrix, ealg)) +end + + +# Given a matrix M and permutation σ, construct the ordered graph +# (G, σ) +# where G is the sparsity graph of M. +# ---------------------------------------- +# graph symmetric matrix # order vertex order # ---------------------------------------- -function OrderedGraph(sgraph::AbstractSymmetricGraph, order::Order) - n = nv(sgraph) +function OrderedGraph(matrix::SparseMatrixCSC, order::Order) + n = size(matrix, 1) graph = Graph(n) - for e in edges(sgraph) - u = src(sgraph, e) - v = tgt(sgraph, e) - - if order(u, v) - add_edge!(graph, inverse(order, u), inverse(order, v)) + for u in 1:n + for v in matrix.rowval[matrix.colptr[u]:matrix.colptr[u + 1] - 1] + i = inverse(order, u) + j = inverse(order, v) + + if i < j + add_edge!(graph, i, j) + end end end @@ -43,25 +59,24 @@ end # Given an ordered graph (G, σ) and permutation μ, construct the ordered graph # (G, σ ∘ μ). # ---------------------------------------- -# ograph ordered graph +# graph ordered graph # order permutation # ---------------------------------------- -function OrderedGraph(ograph::OrderedGraph, order::Order) - n = nv(ograph) - graph = Graph(n) +function OrderedGraph(graph::OrderedGraph, order::Order) + digraph = Graph(nv(graph)) - for e in edges(ograph) - u = src(ograph, e) - v = tgt(ograph, e) + for edge in edges(graph) + i = inverse(order, src(graph, edge)) + j = inverse(order, tgt(graph, edge)) - if order(u, v) - add_edge!(graph, inverse(order, u), inverse(order, v)) + if i < j + add_edge!(digraph, i, j) else - add_edge!(graph, inverse(order, v), inverse(order, u)) + add_edge!(digraph, j, i) end end - OrderedGraph(graph, compose(order, ograph.order)) + OrderedGraph(digraph, compose(order, graph.order)) end @@ -98,22 +113,20 @@ function etree(graph::OrderedGraph) end -function Base.deepcopy(ograph::OrderedGraph) - order = deepcopy(ograph.order) - graph = deepcopy(ograph.graph) - OrderedGraph(graph, order) +function Base.deepcopy(graph::OrderedGraph) + OrderedGraph(deepcopy(graph.order), deepcopy(graph.graph)) end # Get the vertex σ(i). -function permutation(ograph::OrderedGraph, i) - ograph.order[i] +function permutation(graph::OrderedGraph, i) + graph.order[i] end # Get the index σ⁻¹(v). -function inverse(ograph::OrderedGraph, v) - inverse(ograph.order, v) +function inverse(graph::OrderedGraph, v) + inverse(graph.order, v) end @@ -122,41 +135,41 @@ end ############################ -function BasicGraphs.ne(ograph::OrderedGraph) - ne(ograph.graph) +function BasicGraphs.ne(graph::OrderedGraph) + ne(graph.graph) end -function BasicGraphs.nv(ograph::OrderedGraph) - nv(ograph.graph) +function BasicGraphs.nv(graph::OrderedGraph) + nv(graph.graph) end -function BasicGraphs.inneighbors(ograph::OrderedGraph, i) - inneighbors(ograph.graph, i) +function BasicGraphs.inneighbors(graph::OrderedGraph, i) + inneighbors(graph.graph, i) end -function BasicGraphs.outneighbors(ograph::OrderedGraph, i) - outneighbors(ograph.graph, i) +function BasicGraphs.outneighbors(graph::OrderedGraph, i) + outneighbors(graph.graph, i) end -function BasicGraphs.edges(ograph::OrderedGraph) - edges(ograph.graph) +function BasicGraphs.edges(graph::OrderedGraph) + edges(graph.graph) end -function BasicGraphs.vertices(ograph::OrderedGraph) - vertices(ograph.graph) +function BasicGraphs.vertices(graph::OrderedGraph) + vertices(graph.graph) end -function BasicGraphs.src(ograph::OrderedGraph, i) - src(ograph.graph, i) +function BasicGraphs.src(graph::OrderedGraph, i) + src(graph.graph, i) end -function BasicGraphs.tgt(ograph::OrderedGraph, i) - tgt(ograph.graph, i) +function BasicGraphs.tgt(graph::OrderedGraph, i) + tgt(graph.graph, i) end From 364b70c153c2002f65937eedc6a75cdf73053ec5 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Wed, 20 Nov 2024 23:28:21 -0500 Subject: [PATCH 004/100] more constructors --- src/junction_trees/elimination_trees.jl | 8 ++++---- src/junction_trees/junction_trees.jl | 19 +++++++++++++++++-- src/junction_trees/supernode_trees.jl | 10 +++++----- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/junction_trees/elimination_trees.jl b/src/junction_trees/elimination_trees.jl index 7a1afc5..97ed997 100644 --- a/src/junction_trees/elimination_trees.jl +++ b/src/junction_trees/elimination_trees.jl @@ -8,13 +8,13 @@ end # Construct an elimination tree using an elimination algorithm. # ---------------------------------------- -# graph simple connected graph -# ealg elimination algorithm +# graph_or_matrix simple connected graph +# ealg elimination algorithm # ---------------------------------------- function EliminationTree( - graph::AbstractSymmetricGraph, + graph_or_matrix, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM) - EliminationTree(OrderedGraph(graph, ealg)) + EliminationTree(OrderedGraph(graph_or_matrix, ealg)) end diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 39f525a..2fb645f 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -10,13 +10,13 @@ end """ - JunctionTree(graph::AbstractSymmetricGraph[, ealg::Union{Order, EliminationAlgorithm}[, stype::SupernodeType]]) + JunctionTree(graph[, ealg::Union{Order, EliminationAlgorithm}[, stype::SupernodeType]]) Construct a tree decomposition of a connected simple graph, optionally specifying an elimination algorithm and a supernode type. """ function JunctionTree( - graph::AbstractSymmetricGraph, + graph, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) @@ -24,6 +24,21 @@ function JunctionTree( end +""" + JunctionTree(matrix::AbstractMatrix[, ealg::Union{Order, EliminationAlgorithm}[, stype::SupernodeType]]) + +Construct a tree decomposition of a matrix, optionally specifying an elimination algorithm and +a supernode type. +""" +function JunctionTree( + matrix::AbstractMatrix, + ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, + stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) + + JunctionTree(SupernodeTree(matrix, ealg, stype)) +end + + # Construct a junction tree. # ---------------------------------------- # stree supernodal elimination tree diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index cf7ff0e..59f9f19 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -11,16 +11,16 @@ end # Construct a supernodal elimination tree using an elimination algorithm. # ---------------------------------------- -# graph simple connected graph -# ealg elimination algorithm -# stype supernode type +# graph_or_matrix simple connected graph or matrix +# ealg elimination algorithm +# stype supernode type # ---------------------------------------- function SupernodeTree( - graph::AbstractSymmetricGraph, + graph_or_matrix, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - SupernodeTree(EliminationTree(graph, ealg), stype) + SupernodeTree(EliminationTree(graph_or_matrix, ealg), stype) end From 1f7055bb37e77b2ac0286c1e5b9b065250da08ec Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 00:35:07 -0500 Subject: [PATCH 005/100] using interface functions --- src/JunctionTrees.jl | 1 + src/junction_trees/elimination_algorithms.jl | 8 ++++---- src/junction_trees/ordered_graphs.jl | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 5437baa..77e1752 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -11,6 +11,7 @@ using AbstractTrees using Catlab.BasicGraphs using DataStructures using SparseArrays +using SparseArrays: AbstractSparseMatrixCSC # Orders diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index ddc46bc..f91bf97 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -93,14 +93,14 @@ end # Construct an order using the Bouchitte-Todinca algorithm. Uses TreeWidthSolver.jl. -function Order(matrix::AbstractMatrix, ealg::TreeWidthSolverJL_BT) +function Order(matrix::AbstractSparseMatrixCSC, ealg::TreeWidthSolverJL_BT) n = size(matrix, 1) T = TreeWidthSolver.LongLongUInt{n ÷ 64 + 1} fadjlist = Vector{Vector{Int}}(undef, n) bitfadjlist = Vector{T}(undef, n) for i in 1:n - fadjlist[i] = matrix.rowval[matrix.colptr[i]:matrix.colptr[i + 1] - 1] + fadjlist[i] = rowvals(matrix)[nzrange(matrix, i)] bitfadjlist[i] = TreeWidthSolver.bmask(T, fadjlist[i]) end @@ -141,7 +141,7 @@ end # Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs # Tarjan and Yannakakis # Maximum Cardinality Search -function mcs(matrix::SparseMatrixCSC) +function mcs(matrix::AbstractSparseMatrixCSC) n = size(matrix, 1) α = Vector{Int}(undef, n) β = Vector{Int}(undef, n) @@ -165,7 +165,7 @@ function mcs(matrix::SparseMatrixCSC) β[i] = v len[v] = 0 - for w in matrix.rowval[matrix.colptr[v]:matrix.colptr[v] + 1] + for w in rowvals(matrix)[nzrange(matrix, v)] if len[w] >= 1 deleteat!(set[len[w]], pointer[w]) len[w] += 1 diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 1cd1d03..6cec0fd 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -37,12 +37,12 @@ end # graph symmetric matrix # order vertex order # ---------------------------------------- -function OrderedGraph(matrix::SparseMatrixCSC, order::Order) +function OrderedGraph(matrix::AbstractSparseMatrixCSC, order::Order) n = size(matrix, 1) graph = Graph(n) for u in 1:n - for v in matrix.rowval[matrix.colptr[u]:matrix.colptr[u + 1] - 1] + for v in rowvals(matrix)[nzrange(matrix, u)] i = inverse(order, u) j = inverse(order, v) From c969d076b9f6d919088b524ff3c5f3b2f707339c Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 00:49:29 -0500 Subject: [PATCH 006/100] api --- src/junction_trees/elimination_algorithms.jl | 38 +++++++++----------- src/junction_trees/elimination_trees.jl | 8 ++--- src/junction_trees/junction_trees.jl | 15 -------- src/junction_trees/ordered_graphs.jl | 28 +++++++-------- src/junction_trees/supernode_trees.jl | 12 +++---- 5 files changed, 40 insertions(+), 61 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index f91bf97..f655172 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -61,46 +61,42 @@ function Order(graph, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM) end -""" - Order(matrix::AbstractMatrix[, ealg::EliminationAlgorithm]) - -Construct an elimination order for a matrix, optionally specifying an elimination algorithm. -""" -function Order(matrix::AbstractMatrix) - Order(matrix, DEFAULT_ELIMINATION_ALGORITHM) +# Construct an elimination order. +function Order(graph::AbstractMatrix) + Order(graph, DEFAULT_ELIMINATION_ALGORITHM) end # Construct an order using the reverse Cuthill-McKee algorithm. Uses CuthillMcKee.jl. -function Order(matrix::AbstractMatrix, ealg::CuthillMcKeeJL_RCM) - order = CuthillMcKee.symrcm(matrix) +function Order(graph::AbstractMatrix, ealg::CuthillMcKeeJL_RCM) + order = CuthillMcKee.symrcm(graph) Order(order) end # Construct an order using the approximate minimum degree algorithm. Uses AMD.jl. -function Order(matrix::AbstractMatrix, ealg::AMDJL_AMD) - order = AMD.symamd(matrix) +function Order(graph::AbstractMatrix, ealg::AMDJL_AMD) + order = AMD.symamd(graph) Order(order) end # Construct an order using the nested dissection heuristic. Uses Metis.jl. -function Order(matrix::AbstractMatrix, ealg::MetisJL_ND) - order, index = Metis.permutation(matrix) +function Order(graph::AbstractMatrix, ealg::MetisJL_ND) + order, index = Metis.permutation(graph) Order(order, index) end # Construct an order using the Bouchitte-Todinca algorithm. Uses TreeWidthSolver.jl. -function Order(matrix::AbstractSparseMatrixCSC, ealg::TreeWidthSolverJL_BT) - n = size(matrix, 1) +function Order(graph::AbstractSparseMatrixCSC, ealg::TreeWidthSolverJL_BT) + n = size(graph, 1) T = TreeWidthSolver.LongLongUInt{n ÷ 64 + 1} fadjlist = Vector{Vector{Int}}(undef, n) bitfadjlist = Vector{T}(undef, n) for i in 1:n - fadjlist[i] = rowvals(matrix)[nzrange(matrix, i)] + fadjlist[i] = rowvals(graph)[nzrange(graph, i)] bitfadjlist[i] = TreeWidthSolver.bmask(T, fadjlist[i]) end @@ -112,8 +108,8 @@ end # Construct an order using the maximum cardinality search algorithm. -function Order(matrix::AbstractMatrix, ealg::MCS) - order, index = mcs(matrix) +function Order(graph::AbstractMatrix, ealg::MCS) + order, index = mcs(graph) Order(order, index) end @@ -141,8 +137,8 @@ end # Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs # Tarjan and Yannakakis # Maximum Cardinality Search -function mcs(matrix::AbstractSparseMatrixCSC) - n = size(matrix, 1) +function mcs(graph::AbstractSparseMatrixCSC) + n = size(graph, 1) α = Vector{Int}(undef, n) β = Vector{Int}(undef, n) len = Vector{Int}(undef, n) @@ -165,7 +161,7 @@ function mcs(matrix::AbstractSparseMatrixCSC) β[i] = v len[v] = 0 - for w in rowvals(matrix)[nzrange(matrix, v)] + for w in rowvals(graph)[nzrange(graph, v)] if len[w] >= 1 deleteat!(set[len[w]], pointer[w]) len[w] += 1 diff --git a/src/junction_trees/elimination_trees.jl b/src/junction_trees/elimination_trees.jl index 97ed997..e6981bc 100644 --- a/src/junction_trees/elimination_trees.jl +++ b/src/junction_trees/elimination_trees.jl @@ -8,13 +8,13 @@ end # Construct an elimination tree using an elimination algorithm. # ---------------------------------------- -# graph_or_matrix simple connected graph -# ealg elimination algorithm +# graph simple connected graph +# ealg elimination algorithm # ---------------------------------------- function EliminationTree( - graph_or_matrix, + graph, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM) - EliminationTree(OrderedGraph(graph_or_matrix, ealg)) + EliminationTree(OrderedGraph(graph, ealg)) end diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 2fb645f..9d9a978 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -24,21 +24,6 @@ function JunctionTree( end -""" - JunctionTree(matrix::AbstractMatrix[, ealg::Union{Order, EliminationAlgorithm}[, stype::SupernodeType]]) - -Construct a tree decomposition of a matrix, optionally specifying an elimination algorithm and -a supernode type. -""" -function JunctionTree( - matrix::AbstractMatrix, - ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, - stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - - JunctionTree(SupernodeTree(matrix, ealg, stype)) -end - - # Construct a junction tree. # ---------------------------------------- # stree supernodal elimination tree diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 6cec0fd..775c35f 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -17,42 +17,40 @@ function OrderedGraph(graph, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_EL end -# Given a matrix M, construct the ordered graph +# Given a graph G, construct the ordered graph # (G, σ), -# where G is the sparsity graph if M and σ is a permutation computed using an elimination -# algorithm. +# where σ is a permutation computed using an elimination algorithm. # ---------------------------------------- -# matrix symmetric matrix +# graph simple connected graph # ealg elimination algorithm # ---------------------------------------- -function OrderedGraph(matrix::AbstractMatrix, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM) - OrderedGraph(matrix, Order(matrix, ealg)) +function OrderedGraph(graph::AbstractMatrix, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM) + OrderedGraph(graph, Order(graph, ealg)) end -# Given a matrix M and permutation σ, construct the ordered graph +# Given a graph H and permutation σ, construct the ordered graph # (G, σ) -# where G is the sparsity graph of M. # ---------------------------------------- -# graph symmetric matrix +# graph simple connected graph # order vertex order # ---------------------------------------- -function OrderedGraph(matrix::AbstractSparseMatrixCSC, order::Order) - n = size(matrix, 1) - graph = Graph(n) +function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) + n = size(graph, 1) + digraph = Graph(n) for u in 1:n - for v in rowvals(matrix)[nzrange(matrix, u)] + for v in rowvals(graph)[nzrange(graph, u)] i = inverse(order, u) j = inverse(order, v) if i < j - add_edge!(graph, i, j) + add_edge!(digraph, i, j) end end end - OrderedGraph(graph, order) + OrderedGraph(digraph, order) end diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 59f9f19..4f58be1 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -11,18 +11,18 @@ end # Construct a supernodal elimination tree using an elimination algorithm. # ---------------------------------------- -# graph_or_matrix simple connected graph or matrix -# ealg elimination algorithm -# stype supernode type +# graph simple connected graph +# ealg elimination algorithm +# stype supernode type # ---------------------------------------- function SupernodeTree( - graph_or_matrix, + graph, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - SupernodeTree(EliminationTree(graph_or_matrix, ealg), stype) + SupernodeTree(EliminationTree(graph, ealg), stype) end - + # Construct a supernodal elimination tree. # ---------------------------------------- From 22ec20d09a1581b0bfe3f00fbdebd80332c74f44 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 01:08:12 -0500 Subject: [PATCH 007/100] added function sparsitygraph --- src/junction_trees/elimination_algorithms.jl | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index f655172..6e9114a 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -120,7 +120,7 @@ function adjacencymatrix(graph::HasGraph) n = nv(graph) colptr = ones(Int, n + 1) - rowval = sizehint!(Vector{Int}(), 2m) + rowval = sizehint!(Int[], 2m) for j in 1:n ns = collect(neighbors(graph, j)) @@ -134,6 +134,30 @@ function adjacencymatrix(graph::HasGraph) end +# Construct the sparsity graph of a matrix. +function sparsitygraph(matrix::AbstractSparseMatrixCSC) + m = nnz(matrix) + n = size(matrix, 1) + + colptr = ones(Int, n + 1) + rowval = sizehint!(Int[], m) + + for j in 1:n + colptr[j + 1] = colptr[j] + + for i in rowvals(matrix)[nzrange(matrix, j)] + if i != j + colptr[j + 1] += 1 + push!(rowval, i) + end + end + end + + nzval = ones(Int, length(rowval)) + SparseMatrixCSC(n, n, colptr, rowval, nzval) +end + + # Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs # Tarjan and Yannakakis # Maximum Cardinality Search From 9c6385ae7aeebf2f1f26e1e0a118790fd35f1be3 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 11:15:38 -0500 Subject: [PATCH 008/100] temp commit --- src/junction_trees/junction_trees.jl | 16 +++++++++++++--- src/junction_trees/ordered_graphs.jl | 6 ++++++ src/junction_trees/orders.jl | 6 ++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 9d9a978..1096722 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -33,10 +33,20 @@ function JunctionTree(stree::SupernodeTree) end +""" + Order(jtree::JunctionTree) + +Construct the elimination ordering of junction tree. +""" +function Order(jtree::JunctionTree) + Order(jtree.stree.graph) +end + + """ clique(jtree::JunctionTree, i::Integer) -Get the clique at node i. +Get the clique at node `i`. """ function clique(jtree::JunctionTree, i::Integer) [residual(jtree, i); seperator(jtree, i)] @@ -46,7 +56,7 @@ end """ seperator(jtree::JunctionTree, i::Integer) -Get the seperator at node i. +Get the seperator at node `i`. """ function seperator(jtree::JunctionTree, i::Integer) permutation(jtree.stree.graph, jtree.seperator[i]) @@ -56,7 +66,7 @@ end """ residual(jtree::JunctionTree, i::Integer) -Get the residual at node i. +Get the residual at node `i`. """ function residual(jtree::JunctionTree, i::Integer) permutation(jtree.stree.graph, supernode(jtree.stree, i)) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 775c35f..e8e6b79 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -78,6 +78,12 @@ function OrderedGraph(graph::OrderedGraph, order::Order) end +# Construct the permutation σ. +function Order(graph::OrderedGraph) + Order(graph.order) +end + + # A Compact Row Storage Scheme for Cholesky Factors Using Elimination Trees # Liu # Algorithm 4.2: Elimination Tree by Path Compression. diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 849f06e..34cbf2b 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -26,6 +26,12 @@ function Order(order::AbstractVector) end +# Construct a copy of a permutation. +function Order(order::Order) + Order(order.order, order.index) +end + + # Determine if i < j, where # u = σ(i) # v = σ(j) From 5054573cd8104e2510f2ad0d92b8af74c768236b Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 12:49:19 -0500 Subject: [PATCH 009/100] temp commit --- src/junction_trees/elimination_algorithms.jl | 4 +- src/junction_trees/ordered_graphs.jl | 100 +++++++++++-------- src/junction_trees/orders.jl | 5 - 3 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index 6e9114a..fc86332 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -115,7 +115,7 @@ end # Construct the adjacency matrix of a graph. -function adjacencymatrix(graph::HasGraph) +function adjacencymatrix(graph) m = ne(graph) n = nv(graph) @@ -123,7 +123,7 @@ function adjacencymatrix(graph::HasGraph) rowval = sizehint!(Int[], 2m) for j in 1:n - ns = collect(neighbors(graph, j)) + ns = collect(all_neighbors(graph, j)) sort!(ns) colptr[j + 1] = colptr[j] + length(ns) append!(rowval, ns) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index e8e6b79..d66cb19 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,7 +1,8 @@ # An ordered graph (G, σ). struct OrderedGraph - graph::Graph # graph - order::Order # permutation + lower::SparseMatrixCSC{Int64, Int64} # adjacency matrix (lower triangular) + upper::SparseMatrixCSC{Int64, Int64} # adjacency matrix (upper triangular) + order::Order # permutation end @@ -36,21 +37,48 @@ end # order vertex order # ---------------------------------------- function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) + m = last(nzrange(graph, size(graph, 1))) n = size(graph, 1) - digraph = Graph(n) - for u in 1:n - for v in rowvals(graph)[nzrange(graph, u)] - i = inverse(order, u) - j = inverse(order, v) + colptr_lower = Vector{Int}(undef, n + 1) + colptr_upper = Vector{Int}(undef, n + 1) + rowval_lower = Vector{Int}(undef, m ÷ 2) + rowval_upper = Vector{Int}(undef, m ÷ 2) + + colptr_lower[1] = 1 + colptr_upper[1] = 1 + + count_lower = 1 + count_upper = 1 + + for i in 1:n + colptr_lower[i] = count_lower + colptr_upper[i] = count_upper + neighbors = inverse(order, rowvals(graph)[nzrange(graph, order[i])]) + sort!(neighbors) + + for j in neighbors if i < j - add_edge!(digraph, i, j) + rowval_lower[count_lower] = j + count_lower += 1 + else + rowval_upper[count_upper] = j + count_upper += 1 end end end - OrderedGraph(digraph, order) + colptr_lower[n + 1] = m ÷ 2 + 1 + colptr_upper[n + 1] = m ÷ 2 + 1 + + nzval_lower = ones(Int, m ÷ 2) + nzval_upper = ones(Int, m ÷ 2) + + lower = SparseMatrixCSC(n, n, colptr_lower, rowval_lower, nzval_lower) + upper = SparseMatrixCSC(n, n, colptr_upper, rowval_upper, nzval_upper) + + OrderedGraph(lower, upper, order) end @@ -61,20 +89,8 @@ end # order permutation # ---------------------------------------- function OrderedGraph(graph::OrderedGraph, order::Order) - digraph = Graph(nv(graph)) - - for edge in edges(graph) - i = inverse(order, src(graph, edge)) - j = inverse(order, tgt(graph, edge)) - - if i < j - add_edge!(digraph, i, j) - else - add_edge!(digraph, j, i) - end - end - - OrderedGraph(digraph, compose(order, graph.order)) + newgraph = OrderedGraph(adjacencymatrix(graph), order) + OrderedGraph(newgraph.lower, newgraph.upper, compose(order, graph.order)) end @@ -116,11 +132,6 @@ function etree(graph::OrderedGraph) parent end - -function Base.deepcopy(graph::OrderedGraph) - OrderedGraph(deepcopy(graph.order), deepcopy(graph.graph)) -end - # Get the vertex σ(i). function permutation(graph::OrderedGraph, i) @@ -140,40 +151,45 @@ end function BasicGraphs.ne(graph::OrderedGraph) - ne(graph.graph) + last(graph.lower.colptr) - 1 end function BasicGraphs.nv(graph::OrderedGraph) - nv(graph.graph) + size(graph.lower, 1) end function BasicGraphs.inneighbors(graph::OrderedGraph, i) - inneighbors(graph.graph, i) + rowvals(graph.upper)[nzrange(graph.upper, i)] end function BasicGraphs.outneighbors(graph::OrderedGraph, i) - outneighbors(graph.graph, i) + rowvals(graph.lower)[nzrange(graph.lower, i)] end -function BasicGraphs.edges(graph::OrderedGraph) - edges(graph.graph) +function BasicGraphs.all_neighbors(graph::OrderedGraph, i) + Base.Iterators.flatten((inneighbors(graph, i), outneighbors(graph, i))) end +#function BasicGraphs.edges(graph::OrderedGraph) +# 1:ne(graph) +#end + + function BasicGraphs.vertices(graph::OrderedGraph) - vertices(graph.graph) + 1:nv(graph) end - -function BasicGraphs.src(graph::OrderedGraph, i) - src(graph.graph, i) -end +#function BasicGraphs.src(graph::OrderedGraph, i) +# src(graph.graph, i) +#end -function BasicGraphs.tgt(graph::OrderedGraph, i) - tgt(graph.graph, i) -end + +#function BasicGraphs.tgt(graph::OrderedGraph, i) +# tgt(graph.graph, i) +#end diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 34cbf2b..3043b3e 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -76,8 +76,3 @@ end function Base.size(order::Order) (length(order.order),) end - - -function Base.deepcopy(order::Order) - Order(copy(order.order), copy(order.index)) -end From 7c13ba2ac7501de889b6a0386f754d9ed023c5ef Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 12:54:41 -0500 Subject: [PATCH 010/100] temp commit --- src/junction_trees/ordered_graphs.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index d66cb19..98da065 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,8 +1,8 @@ # An ordered graph (G, σ). struct OrderedGraph - lower::SparseMatrixCSC{Int64, Int64} # adjacency matrix (lower triangular) - upper::SparseMatrixCSC{Int64, Int64} # adjacency matrix (upper triangular) - order::Order # permutation + lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) + upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) + order::Order # permutation end @@ -72,8 +72,8 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) colptr_lower[n + 1] = m ÷ 2 + 1 colptr_upper[n + 1] = m ÷ 2 + 1 - nzval_lower = ones(Int, m ÷ 2) - nzval_upper = ones(Int, m ÷ 2) + nzval_lower = ones(Bool, m ÷ 2) + nzval_upper = ones(Bool, m ÷ 2) lower = SparseMatrixCSC(n, n, colptr_lower, rowval_lower, nzval_lower) upper = SparseMatrixCSC(n, n, colptr_upper, rowval_upper, nzval_upper) From d8221d89206cfe1efd5ae380db4c1173efff67ab Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 12:56:55 -0500 Subject: [PATCH 011/100] bool matrices --- src/junction_trees/elimination_algorithms.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index fc86332..23b5c64 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -129,7 +129,7 @@ function adjacencymatrix(graph) append!(rowval, ns) end - nzval = ones(Int, length(rowval)) + nzval = ones(Bool, length(rowval)) SparseMatrixCSC(n, n, colptr, rowval, nzval) end @@ -153,7 +153,7 @@ function sparsitygraph(matrix::AbstractSparseMatrixCSC) end end - nzval = ones(Int, length(rowval)) + nzval = ones(Bool, length(rowval)) SparseMatrixCSC(n, n, colptr, rowval, nzval) end From 739f39e5eff33a6c436c48ade1aeaac818dd7794 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 13:44:45 -0500 Subject: [PATCH 012/100] temp commit --- Project.toml | 1 + src/JunctionTrees.jl | 3 +- src/junction_trees/elimination_algorithms.jl | 32 ++++++---- src/junction_trees/ordered_graphs.jl | 65 ++++++++++++-------- 4 files changed, 62 insertions(+), 39 deletions(-) diff --git a/Project.toml b/Project.toml index 4bdc28f..7741486 100644 --- a/Project.toml +++ b/Project.toml @@ -9,6 +9,7 @@ AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" CuthillMcKee = "17f17636-5e38-52e3-a803-7ae3aaaf3da9" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LinkedLists = "70f5e60a-1556-5f34-a19e-a48b3e4aaee9" MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 77e1752..405d119 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -2,14 +2,15 @@ module JunctionTrees import AMD +import Catlab.BasicGraphs import CuthillMcKee import LinkedLists import Metis import TreeWidthSolver using AbstractTrees -using Catlab.BasicGraphs using DataStructures +using Graphs using SparseArrays using SparseArrays: AbstractSparseMatrixCSC diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index 23b5c64..efbf165 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -115,25 +115,35 @@ end # Construct the adjacency matrix of a graph. -function adjacencymatrix(graph) - m = ne(graph) - n = nv(graph) +function adjacencymatrix(graph::BasicGraphs.AbstractSymmetricGraph) + m = BasicGraphs.ne(graph) + n = BasicGraphs.nv(graph) + colptr = Vector{Int}(undef, n + 1) + rowval = Vector{Int}(undef, m) + count = 1 - colptr = ones(Int, n + 1) - rowval = sizehint!(Int[], 2m) + for i in 1:n + colptr[i] = count + neighbor = collect(BasicGraphs.all_neighbors(graph, i)) + sort!(neighbor) - for j in 1:n - ns = collect(all_neighbors(graph, j)) - sort!(ns) - colptr[j + 1] = colptr[j] + length(ns) - append!(rowval, ns) + for j in neighbor + rowval[count] = j + count += 1 + end end - nzval = ones(Bool, length(rowval)) + colptr[n + 1] = m + 1 + nzval = ones(Bool, m) SparseMatrixCSC(n, n, colptr, rowval, nzval) end +function adjacencymatrix(graph::AbstractGraph) + adjacency_matrix(graph; dir=:both) +end + + # Construct the sparsity graph of a matrix. function sparsitygraph(matrix::AbstractSparseMatrixCSC) m = nnz(matrix) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 98da065..3b62dfa 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,5 +1,5 @@ # An ordered graph (G, σ). -struct OrderedGraph +struct OrderedGraph <: AbstractGraph{Int} lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) order::Order # permutation @@ -46,19 +46,16 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) rowval_lower = Vector{Int}(undef, m ÷ 2) rowval_upper = Vector{Int}(undef, m ÷ 2) - colptr_lower[1] = 1 - colptr_upper[1] = 1 - count_lower = 1 count_upper = 1 for i in 1:n colptr_lower[i] = count_lower colptr_upper[i] = count_upper - neighbors = inverse(order, rowvals(graph)[nzrange(graph, order[i])]) - sort!(neighbors) + neighbor = inverse(order, rowvals(graph)[nzrange(graph, order[i])]) + sort!(neighbor) - for j in neighbors + for j in neighbor if i < j rowval_lower[count_lower] = j count_lower += 1 @@ -82,6 +79,30 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) end +function adjacencymatrix(graph::OrderedGraph) + m = ne(graph) + n = nv(graph) + colptr = Vector{Int}(undef, n + 1) + rowval = Vector{Int}(undef, 2m) + count = 1 + + for i in 1:n + colptr[i] = count + neighbor = collect(all_neighbors(graph, i)) + sort!(neighbor) + + for j in neighbor + rowval[count] = j + count += 1 + end + end + + colptr[n + 1] = 2m + 1 + nzval = ones(Bool, 2m) + SparseMatrixCSC(n, n, colptr, rowval, nzval) +end + + # Given an ordered graph (G, σ) and permutation μ, construct the ordered graph # (G, σ ∘ μ). # ---------------------------------------- @@ -150,46 +171,36 @@ end ############################ -function BasicGraphs.ne(graph::OrderedGraph) +function Graphs.ne(graph::OrderedGraph) last(graph.lower.colptr) - 1 end -function BasicGraphs.nv(graph::OrderedGraph) +function Graphs.nv(graph::OrderedGraph) size(graph.lower, 1) end -function BasicGraphs.inneighbors(graph::OrderedGraph, i) +function Graphs.inneighbors(graph::OrderedGraph, i::Integer) rowvals(graph.upper)[nzrange(graph.upper, i)] end -function BasicGraphs.outneighbors(graph::OrderedGraph, i) +function Graphs.outneighbors(graph::OrderedGraph, i::Integer) rowvals(graph.lower)[nzrange(graph.lower, i)] end -function BasicGraphs.all_neighbors(graph::OrderedGraph, i) - Base.Iterators.flatten((inneighbors(graph, i), outneighbors(graph, i))) +function Graphs.all_neighbors(graph::OrderedGraph, i::Integer) + [inneighbors(graph, i); outneighbors(graph, i)] end -#function BasicGraphs.edges(graph::OrderedGraph) -# 1:ne(graph) -#end +function Graphs.is_directed(::Type{OrderedGraph}) + true +end -function BasicGraphs.vertices(graph::OrderedGraph) +function Graphs.vertices(graph::OrderedGraph) 1:nv(graph) end - - -#function BasicGraphs.src(graph::OrderedGraph, i) -# src(graph.graph, i) -#end - - -#function BasicGraphs.tgt(graph::OrderedGraph, i) -# tgt(graph.graph, i) -#end From d7981bf7c462dbc9aa079340b04ab6e34a01cc08 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 13:49:42 -0500 Subject: [PATCH 013/100] speedup using views --- src/junction_trees/ordered_graphs.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 3b62dfa..b90b80a 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -182,12 +182,12 @@ end function Graphs.inneighbors(graph::OrderedGraph, i::Integer) - rowvals(graph.upper)[nzrange(graph.upper, i)] + view(rowvals(graph.upper), nzrange(graph.upper, i)) end function Graphs.outneighbors(graph::OrderedGraph, i::Integer) - rowvals(graph.lower)[nzrange(graph.lower, i)] + view(rowvals(graph.lower), nzrange(graph.lower, i)) end From 7214ea0732338ab58778e00841179dd3b4f6bdca Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 14:11:27 -0500 Subject: [PATCH 014/100] using views generally --- src/junction_trees/ordered_graphs.jl | 5 ++--- src/junction_trees/orders.jl | 30 ++++++++++++++++++--------- src/junction_trees/supernode_trees.jl | 4 ++-- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index b90b80a..48ff47e 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -52,8 +52,7 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) for i in 1:n colptr_lower[i] = count_lower colptr_upper[i] = count_upper - neighbor = inverse(order, rowvals(graph)[nzrange(graph, order[i])]) - sort!(neighbor) + neighbor = sort(inverse(order, rowvals(graph)[nzrange(graph, order[i])])) for j in neighbor if i < j @@ -156,7 +155,7 @@ end # Get the vertex σ(i). function permutation(graph::OrderedGraph, i) - graph.order[i] + permutation(graph.order, i) end diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 3043b3e..c177198 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -32,32 +32,42 @@ function Order(order::Order) end -# Determine if i < j, where -# u = σ(i) -# v = σ(j) -function (order::Order)(u, v) - inverse(order, u) < inverse(order, v) -end - - # Compose two permutations. function compose(left::Order, right::Order) Order(right.order[left.order], left.index[right.index]) end -# Construct the inverse permutation. +# Construct the inverse permutation σ⁻¹. function inverse(order::Order) Order(order.index, order.order) end +# Get the element σ(i). +function permutation(order::Order, i::Integer) + order[i] +end + + +# Get the elements (σ(i₁, ..., iₙ)). +function permutation(order::Order, i) + view(order, i) +end + + # Get the index σ⁻¹(v), -function inverse(order::Order, v) +function inverse(order::Order, v::Integer) order.index[v] end +# Get the indices (σ⁻¹(v₁), ..., σ(vₙ)) +function inverse(order::Order, v) + view(order.index, v) +end + + ############################# # Abstract Vector Interface # ############################# diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 4f58be1..c95a344 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -45,8 +45,8 @@ function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPE representative = map(first, supernode) cardinality = map(length, supernode) - map!(i -> inverse(order, i), ancestor, ancestor) - map!(i -> inverse(order, i), representative, representative) + ancestor = inverse(order, ancestor) + representative = inverse(order, representative) SupernodeTree(tree, graph, representative, cardinality, ancestor, degree) end From 5702bbe33cb2e495a08c681b776ec9506aa75f6f Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 14:19:52 -0500 Subject: [PATCH 015/100] removed unused function --- src/junction_trees/elimination_algorithms.jl | 25 +------------------- 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index efbf165..47a7d17 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -139,35 +139,12 @@ function adjacencymatrix(graph::BasicGraphs.AbstractSymmetricGraph) end +# Construct the adjacency matrix of a graph. function adjacencymatrix(graph::AbstractGraph) adjacency_matrix(graph; dir=:both) end -# Construct the sparsity graph of a matrix. -function sparsitygraph(matrix::AbstractSparseMatrixCSC) - m = nnz(matrix) - n = size(matrix, 1) - - colptr = ones(Int, n + 1) - rowval = sizehint!(Int[], m) - - for j in 1:n - colptr[j + 1] = colptr[j] - - for i in rowvals(matrix)[nzrange(matrix, j)] - if i != j - colptr[j + 1] += 1 - push!(rowval, i) - end - end - end - - nzval = ones(Bool, length(rowval)) - SparseMatrixCSC(n, n, colptr, rowval, nzval) -end - - # Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs # Tarjan and Yannakakis # Maximum Cardinality Search From b2c51638161bfeb9f9fd12e0b9a27a896edba13c Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 14:53:45 -0500 Subject: [PATCH 016/100] graphs interface --- src/JunctionTrees.jl | 1 + src/junction_trees/ordered_graphs.jl | 33 +++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 405d119..79d017a 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -11,6 +11,7 @@ import TreeWidthSolver using AbstractTrees using DataStructures using Graphs +using Graphs.SimpleGraphs using SparseArrays using SparseArrays: AbstractSparseMatrixCSC diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 48ff47e..43c2533 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,5 +1,5 @@ # An ordered graph (G, σ). -struct OrderedGraph <: AbstractGraph{Int} +struct OrderedGraph <: AbstractSimpleGraph{Int} lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) order::Order # permutation @@ -170,36 +170,43 @@ end ############################ -function Graphs.ne(graph::OrderedGraph) +function SimpleGraphs.is_directed(::Type{OrderedGraph}) + true +end + + +function SimpleGraphs.edgetype(graph::OrderedGraph) + SimpleEdge{Int} +end + + +function SimpleGraphs.ne(graph::OrderedGraph) last(graph.lower.colptr) - 1 end -function Graphs.nv(graph::OrderedGraph) +function SimpleGraphs.nv(graph::OrderedGraph) size(graph.lower, 1) end -function Graphs.inneighbors(graph::OrderedGraph, i::Integer) +function SimpleGraphs.badj(graph::OrderedGraph, i::Integer) view(rowvals(graph.upper), nzrange(graph.upper, i)) end -function Graphs.outneighbors(graph::OrderedGraph, i::Integer) +function SimpleGraphs.fadj(graph::OrderedGraph, i::Integer) view(rowvals(graph.lower), nzrange(graph.lower, i)) end -function Graphs.all_neighbors(graph::OrderedGraph, i::Integer) +function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) [inneighbors(graph, i); outneighbors(graph, i)] end -function Graphs.is_directed(::Type{OrderedGraph}) - true -end - - -function Graphs.vertices(graph::OrderedGraph) - 1:nv(graph) +function SimpleGraphs.has_edge(graph::OrderedGraph, edge::SimpleEdge{Int}) + i = src(edge) + j = dst(edge) + i < j && insorted(j, outneighbors(graph, i)) end From 59c1339a8850e77bfc68b3972d4ba0a703ca512e Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 15:00:41 -0500 Subject: [PATCH 017/100] minor cleanup --- src/junction_trees/ordered_graphs.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 43c2533..f46b571 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -87,10 +87,8 @@ function adjacencymatrix(graph::OrderedGraph) for i in 1:n colptr[i] = count - neighbor = collect(all_neighbors(graph, i)) - sort!(neighbor) - for j in neighbor + for j in sort(all_neighbors(graph, i)) rowval[count] = j count += 1 end From be687169772c50f714083490b2f44e77cb18fe8f Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 16:16:51 -0500 Subject: [PATCH 018/100] moved a constructor --- src/junction_trees/ordered_graphs.jl | 35 +++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index f46b571..cde97e7 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -78,6 +78,25 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) end +# Given an ordered graph (G, σ) and permutation μ, construct the ordered graph +# (G, σ ∘ μ). +# ---------------------------------------- +# graph ordered graph +# order permutation +# ---------------------------------------- +function OrderedGraph(graph::OrderedGraph, order::Order) + newgraph = OrderedGraph(adjacencymatrix(graph), order) + OrderedGraph(newgraph.lower, newgraph.upper, compose(order, graph.order)) +end + + +# Construct the permutation σ. +function Order(graph::OrderedGraph) + Order(graph.order) +end + + +# Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) m = ne(graph) n = nv(graph) @@ -100,22 +119,6 @@ function adjacencymatrix(graph::OrderedGraph) end -# Given an ordered graph (G, σ) and permutation μ, construct the ordered graph -# (G, σ ∘ μ). -# ---------------------------------------- -# graph ordered graph -# order permutation -# ---------------------------------------- -function OrderedGraph(graph::OrderedGraph, order::Order) - newgraph = OrderedGraph(adjacencymatrix(graph), order) - OrderedGraph(newgraph.lower, newgraph.upper, compose(order, graph.order)) -end - - -# Construct the permutation σ. -function Order(graph::OrderedGraph) - Order(graph.order) -end # A Compact Row Storage Scheme for Cholesky Factors Using Elimination Trees From 1f5eeec6a1d7fd32bd1c8b65bf4808dabbc13b2a Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 16:38:19 -0500 Subject: [PATCH 019/100] printing --- src/junction_trees/junction_trees.jl | 3 ++- src/junction_trees/ordered_graphs.jl | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 1096722..707b273 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -134,7 +134,8 @@ function width(jtree::JunctionTree) end -function Base.show(io::IO, jtree::JunctionTree) +# Multiline printing. +function Base.show(io::IO, ::MIME"text/plain", jtree::JunctionTree) n = width(jtree) print(io, "width: $n\njunction tree:\n") diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index cde97e7..b9c58e1 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -166,6 +166,13 @@ function inverse(graph::OrderedGraph, v) end +# Multiline printing. +function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) + print(io, "ordered graph:\n") + SparseArrays._show_with_braille_patterns(io, graph.lower) +end + + ############################ # Abstract Graph Interface # ############################ From 70b6427c69733ad7552e450ffcc89171e6d1d95d Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 18:46:51 -0500 Subject: [PATCH 020/100] fixed docstring --- src/junction_trees/supernode_types.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 760284a..9095131 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -3,7 +3,7 @@ A type of supernode. The options are - [`Node`](@ref) -- [`Maximal](@ref) +- [`Maximal`](@ref) - [`Fundamental`](@ref) """ abstract type SupernodeType end From e23d1360e50350188a3cc9176accd7dc6f407170 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 21 Nov 2024 21:40:15 -0500 Subject: [PATCH 021/100] added function `findnode` --- src/junction_trees/junction_trees.jl | 12 ++++++++++++ src/junction_trees/supernode_trees.jl | 25 ++++++++++++++++--------- src/junction_trees/supernode_types.jl | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 707b273..519ad34 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -73,6 +73,18 @@ function residual(jtree::JunctionTree, i::Integer) end +# Find the least node i such that v ∈ clique(i). +function findnode(jtree::JunctionTree, v::Integer) + findnode(jtree.stree, inverse(jtree.stree.graph, v)) +end + + +# Find the least node i such that v ⊆ clique(i). +function findnode(jtree::JunctionTree, v) + findnode(jtree.stree, minimum(inverse(jtree.stree.graph, v))) +end + + # Construct the inclusion seperator(i) → clique(parent(i)). function seperator_to_parent(jtree::JunctionTree, i::Integer) j = parentindex(jtree, i) diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index c95a344..0b9de64 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -2,6 +2,7 @@ struct SupernodeTree tree::PostorderTree # supernodal elimination tree graph::OrderedGraph # ordered graph + partition::Vector{Int} # supernode partition representative::Vector{Int} # representative vertex cardinality::Vector{Int} # supernode cardinality ancestor::Vector{Int} # first ancestor @@ -31,24 +32,24 @@ end # ---------------------------------------- function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) degree = outdegrees(etree) - supernode, parent, ancestor = stree(etree, degree, stype) + partition, supernode, parent, ancestor = stree(etree, degree, stype) tree = Tree(parent) order = postorder(tree) tree = PostorderTree(tree, order) - permute!(supernode, order) - permute!(ancestor, order) + partition = inverse(order, partition) + supernode = view(supernode, order) + ancestor = view(ancestor, order) order = Order(vcat(supernode...)) graph = OrderedGraph(etree.graph, order) - permute!(degree, order) - - representative = map(first, supernode) - cardinality = map(length, supernode) + degree = view(degree, order) + partition = view(partition, order) ancestor = inverse(order, ancestor) - representative = inverse(order, representative) + representative = inverse(order, map(first, supernode)) + cardinality = map(length, supernode) - SupernodeTree(tree, graph, representative, cardinality, ancestor, degree) + SupernodeTree(tree, graph, partition, representative, cardinality, ancestor, degree) end @@ -66,6 +67,12 @@ function supernode(stree::SupernodeTree, i::Integer) end +# Get the unique node j satisfying i ∈ supernode(j). +function findnode(stree::SupernodeTree, i::Integer) + stree.partition[i] +end + + # Compute the (unsorted) seperators of every node in T. function seperators(stree::SupernodeTree) n = length(stree.tree) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 9095131..56a81e0 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -66,7 +66,7 @@ function stree(etree::EliminationTree, degree::AbstractVector, stype::SupernodeT end end - new, parent, first_anc + new_in_clique, new, parent, first_anc end From 2cad43bdd2be5885d97b39a78dfe40076cce628b Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 00:42:36 -0500 Subject: [PATCH 022/100] renamed some functions --- src/Decompositions.jl | 2 +- src/JunctionTrees.jl | 2 +- src/junction_trees/junction_trees.jl | 55 ++++++++++++++++----------- src/junction_trees/supernode_trees.jl | 2 +- src/junction_trees/supernode_types.jl | 31 ++++++++------- 5 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/Decompositions.jl b/src/Decompositions.jl index ef6b6db..3c43fe3 100644 --- a/src/Decompositions.jl +++ b/src/Decompositions.jl @@ -315,7 +315,7 @@ function homomorphisms(graph::AbstractSymmetricGraph, jtree::JunctionTree) for i in 1:n - 1 # seperator(i) → clique(i) - homomorphism[n + i - 1] = induced_homomorphism(subgraph[n + i], subgraph[i], seperator_to_self(jtree, i)) + homomorphism[n + i - 1] = induced_homomorphism(subgraph[n + i], subgraph[i], seperator_to_clique(jtree, i)) end subgraph, homomorphism diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 79d017a..eb27898 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -29,7 +29,7 @@ export Node, Maximal, Fundamental # Junction Trees -export JunctionTree, width, height, seperator, residual, clique, seperator_to_parent, seperator_to_self +export JunctionTree, width, height, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_residual include("junction_trees/orders.jl") diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 519ad34..c670145 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -73,46 +73,55 @@ function residual(jtree::JunctionTree, i::Integer) end -# Find the least node i such that v ∈ clique(i). -function findnode(jtree::JunctionTree, v::Integer) - findnode(jtree.stree, inverse(jtree.stree.graph, v)) +# Find the unique node i satisfying v ∈ residual(i). +function in_residual(jtree::JunctionTree, v::Integer) + in_supernode(jtree.stree, inverse(jtree.stree.graph, v)) end -# Find the least node i such that v ⊆ clique(i). -function findnode(jtree::JunctionTree, v) - findnode(jtree.stree, minimum(inverse(jtree.stree.graph, v))) +# Find the least node i such that v ∩ residual(i) is nonempty. +# If there exists a clique containing v, then v ⊆ clique(i). +function in_residual(jtree::JunctionTree, v) + in_supernode(jtree.stree, minimum(inverse(jtree.stree.graph, v))) +end + + +# Construct the inclusion seperator(i) → clique(i). +function seperator_to_clique(jtree::JunctionTree, i::Integer) + res = supernode(jtree.stree, i) + sep = jtree.seperator[i] + length(res) + 1:length(res) + length(sep) end # Construct the inclusion seperator(i) → clique(parent(i)). function seperator_to_parent(jtree::JunctionTree, i::Integer) j = parentindex(jtree, i) - sep = jtree.seperator[i] - sep_parent = jtree.seperator[j] - res_parent = supernode(jtree.stree, j) + sep = jtree.seperator[j] + res = supernode(jtree.stree, j) - i = 0 - index = Vector{Int}(undef, length(sep)) - - for (j, v) in enumerate(sep) - if v in res_parent - index[j] = v - first(res_parent) + 1 + map(jtree.seperator[i]) do v + if v in res + v - first(res) + 1 else - i += searchsortedfirst(view(sep_parent, i + 1:length(sep_parent)), v) - index[j] = length(res_parent) + i + length(res) + searchsortedfirst(sep, v) end end - - index end -# Construct the inclusion seperator(i) → clique(i). -function seperator_to_self(jtree::JunctionTree, i::Integer) - sep = jtree.seperator[i] +# Construct the inclusion set → clique(i). +function set_to_clique(jtree::JunctionTree, i::Integer, set) res = supernode(jtree.stree, i) - length(res) + 1:length(res) + length(sep) + sep = jtree.seperator[i] + + map(inverse(jtree.stree.graph, set)) do v + if v in res + v - first(res) + 1 + else + length(res) + searchsortedfirst(sep, v) + end + end end diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 0b9de64..973d2a9 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -68,7 +68,7 @@ end # Get the unique node j satisfying i ∈ supernode(j). -function findnode(stree::SupernodeTree, i::Integer) +function in_supernode(stree::SupernodeTree, i::Integer) stree.partition[i] end diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 56a81e0..a04db5f 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -70,37 +70,42 @@ function stree(etree::EliminationTree, degree::AbstractVector, stype::SupernodeT end -# Find a child w of v such that -# v ∈ snd(w). +# Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. function child_in_supernode(etree::EliminationTree, degree::AbstractVector, stype::Node, v::Integer) end -# Find a child w of v such that -# v ∈ snd(w). +# Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. function child_in_supernode(etree::EliminationTree, degree::AbstractVector, stype::Maximal, v::Integer) + u = nothing + for w in childindices(etree.tree, v) if degree[w] == degree[v] + 1 - return w + u = w + break end end + + u end -# Find a child w of v such that -# v ∈ snd(w). +# Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. function child_in_supernode(etree::EliminationTree, degree::AbstractVector, stype::Fundamental, v::Integer) - ws = childindices(etree.tree, v) + u = nothing - if length(ws) == 1 - w = only(ws) - - if degree[w] == degree[v] + 1 - return w + for w in childindices(etree.tree, v) + if isnothing(u) && degree[w] == degree[v] + 1 + u = w + else + u = nothing + break end end + + u end From 57a5df5dc3c1b72d0e1f203c88756067252486eb Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 10:58:29 -0500 Subject: [PATCH 023/100] docstrings --- src/JunctionTrees.jl | 6 ++++- src/junction_trees/junction_trees.jl | 14 +++++++++-- src/junction_trees/ordered_graphs.jl | 36 +++++++++++++++++++--------- src/junction_trees/orders.jl | 32 +++++++++++++++++-------- 4 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index eb27898..2157987 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -17,13 +17,17 @@ using SparseArrays: AbstractSparseMatrixCSC # Orders -export Order, inverse +export Order, permutation, inverse # Elimination Algorithms export AMDJL_AMD, CuthillMcKeeJL_RCM, MetisJL_ND, TreeWidthSolverJL_BT, MCS +# Ordered Graphs +export OrderedGraph + + # Supernode Types export Node, Maximal, Fundamental diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index c670145..a758135 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -1,7 +1,7 @@ """ JunctionTree -A junction tree. +An ordered graph ``(G, \\sigma``) along with a junction tree. This type implements the [indexed tree interface](https://juliacollections.github.io/AbstractTrees.jl/stable/#The-Indexed-Tree-Interface). """ struct JunctionTree stree::SupernodeTree # supernodal elimination tree @@ -36,13 +36,23 @@ end """ Order(jtree::JunctionTree) -Construct the elimination ordering of junction tree. +Construct the elimination ordering ``\\sigma``. """ function Order(jtree::JunctionTree) Order(jtree.stree.graph) end +""" + OrderedGraph(jtree::JunctionTree) + +Construct the ordered graph ``(G, \\sigma)``. +""" +function OrderedGraph(jtree::JunctionTree) + OrderedGraph(jtree.stree.graph) +end + + """ clique(jtree::JunctionTree, i::Integer) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index b9c58e1..19ab4b9 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,4 +1,8 @@ -# An ordered graph (G, σ). +""" + OrderedGraph <: AbstractSimpleGraph{Int} + +An ordered graph ``(G, \\sigma)``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). +""" struct OrderedGraph <: AbstractSimpleGraph{Int} lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) @@ -6,13 +10,11 @@ struct OrderedGraph <: AbstractSimpleGraph{Int} end -# Given a graph G, construct the ordered graph -# (G, σ), -# where σ is a permutation computed using an elimination algorithm. -# ---------------------------------------- -# graph simple connected graph -# ealg elimination algorithm -# ---------------------------------------- +""" + OrderedGraph(graph[, ealg::Union{Order, EliminationAlgorithm}]) + +Construct an ordered graph, optionally specifying an elimination algorithm. +""" function OrderedGraph(graph, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM) OrderedGraph(adjacencymatrix(graph), ealg) end @@ -90,7 +92,11 @@ function OrderedGraph(graph::OrderedGraph, order::Order) end -# Construct the permutation σ. +""" + Order(graph::OrderedGraph) + +Construct the permutation ``\\sigma``. +""" function Order(graph::OrderedGraph) Order(graph.order) end @@ -154,13 +160,21 @@ function etree(graph::OrderedGraph) end -# Get the vertex σ(i). +""" + permutation(graph::OrderedGraph, i) + +Get the vertex ``\\sigmq(i)``. +""" function permutation(graph::OrderedGraph, i) permutation(graph.order, i) end -# Get the index σ⁻¹(v). +""" + inverse(graph::OrderedGraph, v) + +Get the index ``\\sigma^{-1}(v)``. +""" function inverse(graph::OrderedGraph, v) inverse(graph.order, v) end diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index c177198..9808d8c 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -1,7 +1,7 @@ """ Order <: AbstractVector{Int} -A permutation of the set ``\\{1, \\dots, n\\}.`` +A permutation ``\\sigma`` of the set ``\\{1, \\dots, n\\}``. This type implements the [abstract array interface](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array). """ struct Order <: AbstractVector{Int} order::Vector{Int} # permutation @@ -12,7 +12,7 @@ end """ Order(order::AbstractVector) -Construct a permutation ``\\sigma`` from a sequence ``(\\sigma(1), \\dots, \\sigma(n)).`` +Construct a permutation ``\\sigma`` from a sequence ``(\\sigma(1), \\dots, \\sigma(n))``. """ function Order(order::AbstractVector) n = length(order) @@ -38,19 +38,17 @@ function compose(left::Order, right::Order) end -# Construct the inverse permutation σ⁻¹. -function inverse(order::Order) - Order(order.index, order.order) -end - - # Get the element σ(i). function permutation(order::Order, i::Integer) order[i] end -# Get the elements (σ(i₁, ..., iₙ)). +""" + permutation(order::Order, i) + +Get the element ``\\sigma(i)``. +""" function permutation(order::Order, i) view(order, i) end @@ -62,12 +60,26 @@ function inverse(order::Order, v::Integer) end -# Get the indices (σ⁻¹(v₁), ..., σ(vₙ)) +""" + inverse(order::Order, v) + +Get the index ``\\sigma^{-1}(v)``. +""" function inverse(order::Order, v) view(order.index, v) end +""" + inverse(order::Order) + +Construct the inverse permutation ``\\sigma^{-1}``. +""" +function inverse(order::Order) + Order(order.index, order.order) +end + + ############################# # Abstract Vector Interface # ############################# From 1d32be319ed5d0140817b30cde247ab432660ea8 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 12:28:34 -0500 Subject: [PATCH 024/100] docstrings --- src/JunctionTrees.jl | 2 +- src/junction_trees/junction_trees.jl | 80 ++++++++++++++++++--------- src/junction_trees/ordered_graphs.jl | 33 +++++++++-- src/junction_trees/orders.jl | 27 ++++++--- src/junction_trees/supernode_trees.jl | 8 +-- src/junction_trees/trees.jl | 4 +- 6 files changed, 107 insertions(+), 47 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 2157987..6f63862 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -33,7 +33,7 @@ export Node, Maximal, Fundamental # Junction Trees -export JunctionTree, width, height, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_residual +export JunctionTree, width, height, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_clique include("junction_trees/orders.jl") diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index a758135..837c1ad 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -1,11 +1,12 @@ """ JunctionTree -An ordered graph ``(G, \\sigma``) along with a junction tree. This type implements the [indexed tree interface](https://juliacollections.github.io/AbstractTrees.jl/stable/#The-Indexed-Tree-Interface). +A [tree decomposition](https://en.wikipedia.org/wiki/Tree_decomposition) of a graph ``G``. +This type implements the [indexed tree interface](https://juliacollections.github.io/AbstractTrees.jl/stable/#The-Indexed-Tree-Interface). """ struct JunctionTree stree::SupernodeTree # supernodal elimination tree - seperator::Vector{Vector{Int}} # seperator + seperator::Vector{Vector{Int}} # vector of seperators end @@ -36,7 +37,7 @@ end """ Order(jtree::JunctionTree) -Construct the elimination ordering ``\\sigma``. +Construct a perfect elimination ordering. """ function Order(jtree::JunctionTree) Order(jtree.stree.graph) @@ -46,7 +47,7 @@ end """ OrderedGraph(jtree::JunctionTree) -Construct the ordered graph ``(G, \\sigma)``. +Construct the ordered graph ``(G, \\sigma)``, where ``\\sigma`` is a perfect elimination ordering. """ function OrderedGraph(jtree::JunctionTree) OrderedGraph(jtree.stree.graph) @@ -56,7 +57,7 @@ end """ clique(jtree::JunctionTree, i::Integer) -Get the clique at node `i`. +Get the clique at node ``i``. """ function clique(jtree::JunctionTree, i::Integer) [residual(jtree, i); seperator(jtree, i)] @@ -66,7 +67,7 @@ end """ seperator(jtree::JunctionTree, i::Integer) -Get the seperator at node `i`. +Get the seperator at node ``i``. """ function seperator(jtree::JunctionTree, i::Integer) permutation(jtree.stree.graph, jtree.seperator[i]) @@ -76,52 +77,81 @@ end """ residual(jtree::JunctionTree, i::Integer) -Get the residual at node `i`. +Get the residual at node ``i``. """ function residual(jtree::JunctionTree, i::Integer) permutation(jtree.stree.graph, supernode(jtree.stree, i)) end -# Find the unique node i satisfying v ∈ residual(i). -function in_residual(jtree::JunctionTree, v::Integer) +""" + in_clique(jtree::JunctionTree, v::Integer) + +Find a node `i` safisfying `v ∈ clique(jtree, i)`. +""" +function in_clique(jtree::JunctionTree, v::Integer) in_supernode(jtree.stree, inverse(jtree.stree.graph, v)) end -# Find the least node i such that v ∩ residual(i) is nonempty. -# If there exists a clique containing v, then v ⊆ clique(i). -function in_residual(jtree::JunctionTree, v) - in_supernode(jtree.stree, minimum(inverse(jtree.stree.graph, v))) +""" + in_clique(jtree::JunctionTree, set::AbstractVector) + +Find a node `i` satisfying `set ⊆ clique(jtree, i)`. In none exists, return `nothing`. +""" +function in_clique(jtree::JunctionTree, set::AbstractVector) + minimum = length(jtree) + maximum = 1 + + for i in inverse(jtree.stree.graph, set) + minimum = min(minimum, i) + maximum = max(maximum, i) + end + + if maximum <= last(jtree.seperator[minimum]) + i + end end -# Construct the inclusion seperator(i) → clique(i). +""" + seperator_to_clique(jtree::JunctionTree, i::Integer) + +Construct a vector `index` satisfying `seperator(jtree, i) == clique(jtree, i)[index]` +""" function seperator_to_clique(jtree::JunctionTree, i::Integer) - res = supernode(jtree.stree, i) - sep = jtree.seperator[i] - length(res) + 1:length(res) + length(sep) + residual = supernode(jtree.stree, i) + seperator = jtree.seperator[i] + length(residual) + 1:length(residual) + length(seperator) end -# Construct the inclusion seperator(i) → clique(parent(i)). +""" + seperator_to_parent(jtree::JunctionTree, i::Integer) + +Construct a vector `index` satisfying `seperator(jtree, i) == clique(jtree, parent(jtree, i))[index]`. +""" function seperator_to_parent(jtree::JunctionTree, i::Integer) j = parentindex(jtree, i) - sep = jtree.seperator[j] - res = supernode(jtree.stree, j) + residual = supernode(jtree.stree, j) + seperator = jtree.seperator[j] map(jtree.seperator[i]) do v - if v in res - v - first(res) + 1 + if v in residual + v - first(residual) + 1 else - length(res) + searchsortedfirst(sep, v) + length(residual) + searchsortedfirst(seperator, v) end end end -# Construct the inclusion set → clique(i). -function set_to_clique(jtree::JunctionTree, i::Integer, set) +""" + set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) + +Construct a vector `index` satisfying `set == clique(jtree, i)[index]`. +""" +function set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) res = supernode(jtree.stree, i) sep = jtree.seperator[i] diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 19ab4b9..45e4fda 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,7 +1,8 @@ """ OrderedGraph <: AbstractSimpleGraph{Int} -An ordered graph ``(G, \\sigma)``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). +An [ordered graph](https://en.wikipedia.org/wiki/Ordered_graph) ``(G, \\sigma)``. +This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractSimpleGraph{Int} lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) @@ -161,21 +162,41 @@ end """ - permutation(graph::OrderedGraph, i) + permutation(graph::OrderedGraph, i::Integer) -Get the vertex ``\\sigmq(i)``. +Get the vertex ``\\sigma(i)``. """ -function permutation(graph::OrderedGraph, i) +function permutation(graph::OrderedGraph, i::Integer) permutation(graph.order, i) end """ - inverse(graph::OrderedGraph, v) + permutation(graph::OrderedGraph, i::AbstractVector) + +Get the vertices ``(\\sigma(i_1), \\dots, \\sigma(i_n))``. +""" +function permutation(graph::OrderedGraph, i::AbstractVector) + permutation(graph.order, i) +end + + +""" + inverse(graph::OrderedGraph, v::Integer) Get the index ``\\sigma^{-1}(v)``. """ -function inverse(graph::OrderedGraph, v) +function inverse(graph::OrderedGraph, v::Integer) + inverse(graph.order, v) +end + + +""" + inverse(order::Order, v::AbstractVector) + +Get the indices ``(\\sigma^{-1}(v_1), \\dots, \\sigma^{-1}(v_n))``. +""" +function inverse(graph::OrderedGraph, v::AbstractVector) inverse(graph.order, v) end diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 9808d8c..981ff8e 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -1,7 +1,8 @@ """ Order <: AbstractVector{Int} -A permutation ``\\sigma`` of the set ``\\{1, \\dots, n\\}``. This type implements the [abstract array interface](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array). +A [permutation](https://en.wikipedia.org/wiki/Permutation) ``\\sigma`` of the set ``\\{1, \\dots, n\\}``. +This type implements the [abstract array interface](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array). """ struct Order <: AbstractVector{Int} order::Vector{Int} # permutation @@ -38,34 +39,42 @@ function compose(left::Order, right::Order) end -# Get the element σ(i). +""" + permutation(order::Order, i::Integer) + +Get the element ``\\sigma(i)``. +""" function permutation(order::Order, i::Integer) order[i] end """ - permutation(order::Order, i) + permutation(order::Order, i::AbstractVector) -Get the element ``\\sigma(i)``. +Get the elements ``(\\sigma(i_1), \\dots, \\sigma(i_n))``. """ -function permutation(order::Order, i) +function permutation(order::Order, i::AbstractVector) view(order, i) end -# Get the index σ⁻¹(v), +""" + inverse(order::Order, v::Integer) + +Get the index ``\\sigma^{-1}(v)``. +""" function inverse(order::Order, v::Integer) order.index[v] end """ - inverse(order::Order, v) + inverse(order::Order, v::AbstractVector) -Get the index ``\\sigma^{-1}(v)``. +Get the indices ``(\\sigma^{-1}(v_1), \\dots, \\sigma^{-1}(v_n))``. """ -function inverse(order::Order, v) +function inverse(order::Order, v::AbstractVector) view(order.index, v) end diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 973d2a9..fe9349f 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -3,10 +3,10 @@ struct SupernodeTree tree::PostorderTree # supernodal elimination tree graph::OrderedGraph # ordered graph partition::Vector{Int} # supernode partition - representative::Vector{Int} # representative vertex - cardinality::Vector{Int} # supernode cardinality - ancestor::Vector{Int} # first ancestor - degree::Vector{Int} # higher degrees + representative::Vector{Int} # vector of representative vertices + cardinality::Vector{Int} # vector of supernode cardinalities + ancestor::Vector{Int} # vector of first ancestors + degree::Vector{Int} # vector of higher degrees end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 759d19f..6e787db 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -1,8 +1,8 @@ # A rooted tree. struct Tree root::Int # root - parent::Vector{Int} # parent - children::Vector{Vector{Int}} # children + parent::Vector{Int} # vector of parents + children::Vector{Vector{Int}} # vector of children end From ed36838e09c2007529a2b6470dc7fdc94359fce0 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 12:52:42 -0500 Subject: [PATCH 025/100] `length` -> `treesize` and `height` -> `treeheight`. --- src/Decompositions.jl | 4 +-- src/JunctionTrees.jl | 2 +- src/junction_trees/elimination_trees.jl | 2 +- src/junction_trees/junction_trees.jl | 30 +++++++------------ src/junction_trees/postorder_trees.jl | 40 +++++++++++-------------- src/junction_trees/supernode_trees.jl | 2 +- src/junction_trees/supernode_types.jl | 2 +- src/junction_trees/trees.jl | 14 ++++----- test/JunctionTrees.jl | 12 ++++---- 9 files changed, 46 insertions(+), 62 deletions(-) diff --git a/src/Decompositions.jl b/src/Decompositions.jl index 3c43fe3..39552cf 100644 --- a/src/Decompositions.jl +++ b/src/Decompositions.jl @@ -214,7 +214,7 @@ end # jtree junction tree # ---------------------------------------- function StrDecomp(graph::AbstractSymmetricGraph, jtree::JunctionTree) - n = length(jtree) + n = treesize(jtree) tree = Graph(n) for i in 1:n - 1 @@ -293,7 +293,7 @@ end function homomorphisms(graph::AbstractSymmetricGraph, jtree::JunctionTree) - n = length(jtree) + n = treesize(jtree) subgraph = Vector{Any}(undef, 2n - 1) homomorphism = Vector{Any}(undef, 2n - 2) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 6f63862..455fd65 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -33,7 +33,7 @@ export Node, Maximal, Fundamental # Junction Trees -export JunctionTree, width, height, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_clique +export JunctionTree, width, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_clique include("junction_trees/orders.jl") diff --git a/src/junction_trees/elimination_trees.jl b/src/junction_trees/elimination_trees.jl index e6981bc..cbb86e1 100644 --- a/src/junction_trees/elimination_trees.jl +++ b/src/junction_trees/elimination_trees.jl @@ -52,7 +52,7 @@ end # Gilbert, Ng, and Peyton # Figure 3: Implementation of algorithm to compute row and column counts. function supcnt(etree::EliminationTree{PostorderTree}) - n = length(etree.tree) + n = treesize(etree.tree) #### Disjoint Set Union #### diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 837c1ad..ea8535c 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -165,26 +165,6 @@ function set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) end -""" - length(jtree::JunctionTree) - -Get the number of nodes in a junction tree. -""" -function Base.length(jtree::JunctionTree) - length(jtree.stree.tree) -end - - -""" - height(jtree::JunctionTree) - -Compute the height of a junction tree. -""" -function height(jtree::JunctionTree) - height(jtree.stree.tree) -end - - """ width(jtree::JunctionTree) @@ -211,6 +191,16 @@ end ########################## +function AbstractTrees.treesize(jtree::JunctionTree) + treesize(jtree.stree.tree) +end + + +function AbstractTrees.treeheight(jtree::JunctionTree) + treeheight(jtree.stree.tree) +end + + function AbstractTrees.rootindex(jtree::JunctionTree) rootindex(jtree.stree.tree) end diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index 23ed2d8..958dd13 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -1,9 +1,10 @@ # A postordered rooted tree. +# This type implements the indexed tree interface. struct PostorderTree - parent::Vector{Int} # parent - children::Vector{Vector{Int}} # children - level::Vector{Int} # level - descendant::Vector{Int} # first descendant + parent::Vector{Int} # vector of parents + children::Vector{Vector{Int}} # vector of children + level::Vector{Int} # vector of levels + descendant::Vector{Int} # vector of first descendants end @@ -44,23 +45,18 @@ end # order postorder # ---------------------------------------- function PostorderTree(tree::Tree, order::Order) - n = length(tree) - parent = collect(1:n) + n = treesize(tree) + parent = Vector{Int}(undef, n) for i in 1:n - 1 parent[i] = inverse(order, parentindex(tree, order[i])) end + parent[n] = n PostorderTree(parent) end -# The number of node in a tree. -function Base.length(tree::PostorderTree) - length(tree.parent) -end - - # Get the level of a node i. function level(tree::PostorderTree, i::Integer) tree.level[i] @@ -73,21 +69,19 @@ function firstdescendant(tree::PostorderTree, i::Integer) end -# Determine whether the node i is a descendant of the node j. -function isdescendant(tree::PostorderTree, i::Integer, j::Integer) - getdescendant(tree, j) <= i < j -end +########################## +# Indexed Tree Interface # +########################## -# Get the height of a tree. -function height(tree::PostorderTree) - maximum(tree.level) +function AbstractTrees.treesize(tree::PostorderTree) + length(tree.parent) end -########################## -# Indexed Tree Interface # -########################## +function AbstractTrees.treeheight(tree::PostorderTree) + maximum(tree.level) +end function AbstractTrees.parentindex(tree::PostorderTree, i::Integer) @@ -103,7 +97,7 @@ end function AbstractTrees.rootindex(tree::PostorderTree) - length(tree) + treesize(tree) end diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index fe9349f..8617100 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -75,7 +75,7 @@ end # Compute the (unsorted) seperators of every node in T. function seperators(stree::SupernodeTree) - n = length(stree.tree) + n = treesize(stree.tree) seperator = Vector{Set{Int}}(undef, n) for i in 1:n - 1 diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index a04db5f..27e91db 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -37,7 +37,7 @@ struct Fundamental <: SupernodeType end # Pothen and Sun # Figure 4: The Clique Tree Algorithm 2 function stree(etree::EliminationTree, degree::AbstractVector, stype::SupernodeType) - n = length(etree.tree) + n = treesize(etree.tree) new_in_clique = Vector{Int}(undef, n) new = Vector{Int}[] parent = Int[] diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 6e787db..2a225fe 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -1,4 +1,5 @@ # A rooted tree. +# This type implements the indexed tree interface. struct Tree root::Int # root parent::Vector{Int} # vector of parents @@ -32,15 +33,9 @@ function Tree(parent::AbstractVector) end -# Get the number of nodes in a tree. -function Base.length(tree::Tree) - length(tree.parent) -end - - # Compute a postordering of tree's vertices. function postorder(tree::Tree) - n = length(tree) + n = treesize(tree) order = Vector{Int}(undef, n) index = Vector{Int}(undef, n) @@ -59,6 +54,11 @@ end ########################## +function AbstractTrees.treesize(tree::Tree) + length(tree.parent) +end + + function AbstractTrees.rootindex(tree::Tree) tree.root end diff --git a/test/JunctionTrees.jl b/test/JunctionTrees.jl index 89ecf85..f349abd 100644 --- a/test/JunctionTrees.jl +++ b/test/JunctionTrees.jl @@ -37,8 +37,8 @@ order = JunctionTrees.Order(1:17) # Figure 4.3 jtree = JunctionTree(graph, order, Node()) @test width(jtree) == 4 -@test height(jtree) == 7 -@test length(jtree) == 17 +@test treeheight(jtree) == 7 +@test treesize(jtree) == 17 @test map(i -> parentindex(jtree, i), 1:17) == [ 2, @@ -124,8 +124,8 @@ jtree = JunctionTree(graph, order, Node()) # Figure 4.7 (left) jtree = JunctionTree(graph, order, Maximal()) @test width(jtree) == 4 -@test height(jtree) == 4 -@test length(jtree) == 8 +@test treeheight(jtree) == 4 +@test treesize(jtree) == 8 @test map(i -> parentindex(jtree, i), 1:8) == [ 5, @@ -174,8 +174,8 @@ jtree = JunctionTree(graph, order, Maximal()) # Figure 4.9 jtree = JunctionTree(graph, order, Fundamental()) @test width(jtree) == 4 -@test height(jtree) == 5 -@test length(jtree) == 12 +@test treeheight(jtree) == 5 +@test treesize(jtree) == 12 @test map(i -> parentindex(jtree, i), 1:12) == [ 7, From 4630fd00ce8d9d01fdaa5b3f87f2191a73770f8e Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 12:58:13 -0500 Subject: [PATCH 026/100] `width` -> `treewidth` --- src/JunctionTrees.jl | 2 +- src/junction_trees/junction_trees.jl | 8 ++++---- src/junction_trees/supernode_trees.jl | 2 +- test/JunctionTrees.jl | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 455fd65..fa80c0a 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -33,7 +33,7 @@ export Node, Maximal, Fundamental # Junction Trees -export JunctionTree, width, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_clique +export JunctionTree, treewidth, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_clique include("junction_trees/orders.jl") diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index ea8535c..8ac7455 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -166,18 +166,18 @@ end """ - width(jtree::JunctionTree) + treewidth(jtree::JunctionTree) Compute the width of a junction tree. """ -function width(jtree::JunctionTree) - width(jtree.stree) +function treewidth(jtree::JunctionTree) + treewidth(jtree.stree) end # Multiline printing. function Base.show(io::IO, ::MIME"text/plain", jtree::JunctionTree) - n = width(jtree) + n = treewidth(jtree) print(io, "width: $n\njunction tree:\n") print_tree(io, IndexNode(jtree)) do io, node diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 8617100..3620efe 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -54,7 +54,7 @@ end # Compute the width of a supernodal elimination tree. -function width(stree::SupernodeTree) +function treewidth(stree::SupernodeTree) maximum(stree.degree[stree.representative]) end diff --git a/test/JunctionTrees.jl b/test/JunctionTrees.jl index f349abd..5f3cfea 100644 --- a/test/JunctionTrees.jl +++ b/test/JunctionTrees.jl @@ -36,7 +36,7 @@ order = JunctionTrees.Order(1:17) # Figure 4.3 jtree = JunctionTree(graph, order, Node()) -@test width(jtree) == 4 +@test treewidth(jtree) == 4 @test treeheight(jtree) == 7 @test treesize(jtree) == 17 @@ -123,7 +123,7 @@ jtree = JunctionTree(graph, order, Node()) # Figure 4.7 (left) jtree = JunctionTree(graph, order, Maximal()) -@test width(jtree) == 4 +@test treewidth(jtree) == 4 @test treeheight(jtree) == 4 @test treesize(jtree) == 8 @@ -173,7 +173,7 @@ jtree = JunctionTree(graph, order, Maximal()) # Figure 4.9 jtree = JunctionTree(graph, order, Fundamental()) -@test width(jtree) == 4 +@test treewidth(jtree) == 4 @test treeheight(jtree) == 5 @test treesize(jtree) == 12 From 75e885d7c02f00b5323874e8df4d3be472d71ec1 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 14:37:31 -0500 Subject: [PATCH 027/100] renamed functions again... --- src/JunctionTrees.jl | 2 +- src/junction_trees/junction_trees.jl | 34 ++++++++++----------------- src/junction_trees/supernode_trees.jl | 2 +- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index fa80c0a..e05bc8a 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -33,7 +33,7 @@ export Node, Maximal, Fundamental # Junction Trees -export JunctionTree, treewidth, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, in_clique +export JunctionTree, treewidth, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, find_node include("junction_trees/orders.jl") diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 8ac7455..b9f95c3 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -85,32 +85,22 @@ end """ - in_clique(jtree::JunctionTree, v::Integer) + find_node(jtree::JunctionTree, v::Integer) Find a node `i` safisfying `v ∈ clique(jtree, i)`. """ -function in_clique(jtree::JunctionTree, v::Integer) - in_supernode(jtree.stree, inverse(jtree.stree.graph, v)) +function find_node(jtree::JunctionTree, v::Integer) + find_node(jtree.stree, inverse(jtree.stree.graph, v)) end """ - in_clique(jtree::JunctionTree, set::AbstractVector) + find_node(jtree::JunctionTree, set::AbstractVector) -Find a node `i` satisfying `set ⊆ clique(jtree, i)`. In none exists, return `nothing`. +Find a node `i` satisfying `set ⊆ clique(jtree, i)`. """ -function in_clique(jtree::JunctionTree, set::AbstractVector) - minimum = length(jtree) - maximum = 1 - - for i in inverse(jtree.stree.graph, set) - minimum = min(minimum, i) - maximum = max(maximum, i) - end - - if maximum <= last(jtree.seperator[minimum]) - i - end +function find_node(jtree::JunctionTree, set::AbstractVector) + find_node(jtree.stree, minimum(inverse(jtree.stree.graph, set))) end @@ -152,14 +142,14 @@ end Construct a vector `index` satisfying `set == clique(jtree, i)[index]`. """ function set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) - res = supernode(jtree.stree, i) - sep = jtree.seperator[i] + residual = supernode(jtree.stree, i) + sepeperator = jtree.seperator[i] map(inverse(jtree.stree.graph, set)) do v - if v in res - v - first(res) + 1 + if v in residual + v - first(residual) + 1 else - length(res) + searchsortedfirst(sep, v) + length(residual) + searchsortedfirst(seperator, v) end end end diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 3620efe..d546668 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -68,7 +68,7 @@ end # Get the unique node j satisfying i ∈ supernode(j). -function in_supernode(stree::SupernodeTree, i::Integer) +function find_node(stree::SupernodeTree, i::Integer) stree.partition[i] end From 0d2964ab7d665f1c50185e3d7debad571001d40c Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 17:32:11 -0500 Subject: [PATCH 028/100] moved things around --- src/junction_trees/postorder_trees.jl | 2 ++ src/junction_trees/supernode_trees.jl | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index 958dd13..86e48a0 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -3,6 +3,8 @@ struct PostorderTree parent::Vector{Int} # vector of parents children::Vector{Vector{Int}} # vector of children + + # cache level::Vector{Int} # vector of levels descendant::Vector{Int} # vector of first descendants end diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index d546668..526f7f3 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -2,9 +2,11 @@ struct SupernodeTree tree::PostorderTree # supernodal elimination tree graph::OrderedGraph # ordered graph - partition::Vector{Int} # supernode partition representative::Vector{Int} # vector of representative vertices cardinality::Vector{Int} # vector of supernode cardinalities + + # cache + partition::Vector{Int} # supernode partition ancestor::Vector{Int} # vector of first ancestors degree::Vector{Int} # vector of higher degrees end @@ -49,7 +51,7 @@ function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPE representative = inverse(order, map(first, supernode)) cardinality = map(length, supernode) - SupernodeTree(tree, graph, partition, representative, cardinality, ancestor, degree) + SupernodeTree(tree, graph, representative, cardinality, partition, ancestor, degree) end From 9c4660cd69a840adc12fb9ead7a8f3d4bcd1dec1 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 18:51:46 -0500 Subject: [PATCH 029/100] removed functions --- src/Decompositions.jl | 2 +- src/JunctionTrees.jl | 3 +- src/junction_trees/elimination_algorithms.jl | 2 +- src/junction_trees/elimination_trees.jl | 3 +- src/junction_trees/junction_trees.jl | 10 ++--- src/junction_trees/ordered_graphs.jl | 42 +------------------- src/junction_trees/orders.jl | 42 +------------------- src/junction_trees/postorder_trees.jl | 2 +- src/junction_trees/supernode_trees.jl | 6 +-- 9 files changed, 16 insertions(+), 96 deletions(-) diff --git a/src/Decompositions.jl b/src/Decompositions.jl index 39552cf..b2c470d 100644 --- a/src/Decompositions.jl +++ b/src/Decompositions.jl @@ -323,7 +323,7 @@ end function induced_order(order::Order, elements::AbstractVector) - Order(sortperm(inverse(order, elements))) + Order(sortperm(view(inv(order), elements))) end diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index e05bc8a..f9f6f00 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -9,6 +9,7 @@ import Metis import TreeWidthSolver using AbstractTrees +using Base.Order: Ordering using DataStructures using Graphs using Graphs.SimpleGraphs @@ -17,7 +18,7 @@ using SparseArrays: AbstractSparseMatrixCSC # Orders -export Order, permutation, inverse +export Order # Elimination Algorithms diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index 47a7d17..5b8b5de 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -172,7 +172,7 @@ function mcs(graph::AbstractSparseMatrixCSC) β[i] = v len[v] = 0 - for w in rowvals(graph)[nzrange(graph, v)] + for w in view(rowvals(graph), nzrange(graph, v)) if len[w] >= 1 deleteat!(set[len[w]], pointer[w]) len[w] += 1 diff --git a/src/junction_trees/elimination_trees.jl b/src/junction_trees/elimination_trees.jl index cbb86e1..9a8dd24 100644 --- a/src/junction_trees/elimination_trees.jl +++ b/src/junction_trees/elimination_trees.jl @@ -42,9 +42,8 @@ end # Figure 3: Implementation of algorithm to compute row and column counts. function supcnt(etree::EliminationTree) order = postorder(etree.tree) - index = inverse(order) rc, cc = supcnt(EliminationTree{PostorderTree}(etree, order)) - rc[index], cc[index] + view(rc, inv(order)), view(cc, inv(order)) end diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index b9f95c3..4b15381 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -70,7 +70,7 @@ end Get the seperator at node ``i``. """ function seperator(jtree::JunctionTree, i::Integer) - permutation(jtree.stree.graph, jtree.seperator[i]) + view(Order(jtree), jtree.seperator[i]) end @@ -80,7 +80,7 @@ end Get the residual at node ``i``. """ function residual(jtree::JunctionTree, i::Integer) - permutation(jtree.stree.graph, supernode(jtree.stree, i)) + view(Order(jtree), supernode(jtree.stree, i)) end @@ -90,7 +90,7 @@ end Find a node `i` safisfying `v ∈ clique(jtree, i)`. """ function find_node(jtree::JunctionTree, v::Integer) - find_node(jtree.stree, inverse(jtree.stree.graph, v)) + find_node(jtree.stree, inv(Order(jtree))[v]) end @@ -100,7 +100,7 @@ end Find a node `i` satisfying `set ⊆ clique(jtree, i)`. """ function find_node(jtree::JunctionTree, set::AbstractVector) - find_node(jtree.stree, minimum(inverse(jtree.stree.graph, set))) + find_node(jtree.stree, minimum(view(inv(Order(jtree)), set))) end @@ -145,7 +145,7 @@ function set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) residual = supernode(jtree.stree, i) sepeperator = jtree.seperator[i] - map(inverse(jtree.stree.graph, set)) do v + map(view(inv(Order(jtree)), set)) do v if v in residual v - first(residual) + 1 else diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 45e4fda..b67ba4e 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -55,7 +55,7 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) for i in 1:n colptr_lower[i] = count_lower colptr_upper[i] = count_upper - neighbor = sort(inverse(order, rowvals(graph)[nzrange(graph, order[i])])) + neighbor = sort(view(inv(order), view(rowvals(graph), nzrange(graph, order[i])))) for j in neighbor if i < j @@ -161,46 +161,6 @@ function etree(graph::OrderedGraph) end -""" - permutation(graph::OrderedGraph, i::Integer) - -Get the vertex ``\\sigma(i)``. -""" -function permutation(graph::OrderedGraph, i::Integer) - permutation(graph.order, i) -end - - -""" - permutation(graph::OrderedGraph, i::AbstractVector) - -Get the vertices ``(\\sigma(i_1), \\dots, \\sigma(i_n))``. -""" -function permutation(graph::OrderedGraph, i::AbstractVector) - permutation(graph.order, i) -end - - -""" - inverse(graph::OrderedGraph, v::Integer) - -Get the index ``\\sigma^{-1}(v)``. -""" -function inverse(graph::OrderedGraph, v::Integer) - inverse(graph.order, v) -end - - -""" - inverse(order::Order, v::AbstractVector) - -Get the indices ``(\\sigma^{-1}(v_1), \\dots, \\sigma^{-1}(v_n))``. -""" -function inverse(graph::OrderedGraph, v::AbstractVector) - inverse(graph.order, v) -end - - # Multiline printing. function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) print(io, "ordered graph:\n") diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 981ff8e..7cf1bf4 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -39,52 +39,12 @@ function compose(left::Order, right::Order) end -""" - permutation(order::Order, i::Integer) - -Get the element ``\\sigma(i)``. -""" -function permutation(order::Order, i::Integer) - order[i] -end - - -""" - permutation(order::Order, i::AbstractVector) - -Get the elements ``(\\sigma(i_1), \\dots, \\sigma(i_n))``. -""" -function permutation(order::Order, i::AbstractVector) - view(order, i) -end - - -""" - inverse(order::Order, v::Integer) - -Get the index ``\\sigma^{-1}(v)``. -""" -function inverse(order::Order, v::Integer) - order.index[v] -end - - -""" - inverse(order::Order, v::AbstractVector) - -Get the indices ``(\\sigma^{-1}(v_1), \\dots, \\sigma^{-1}(v_n))``. -""" -function inverse(order::Order, v::AbstractVector) - view(order.index, v) -end - - """ inverse(order::Order) Construct the inverse permutation ``\\sigma^{-1}``. """ -function inverse(order::Order) +function Base.inv(order::Order) Order(order.index, order.order) end diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index 86e48a0..d365917 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -51,7 +51,7 @@ function PostorderTree(tree::Tree, order::Order) parent = Vector{Int}(undef, n) for i in 1:n - 1 - parent[i] = inverse(order, parentindex(tree, order[i])) + parent[i] = inv(order)[parentindex(tree, order[i])] end parent[n] = n diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 526f7f3..31ba435 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -39,7 +39,7 @@ function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPE order = postorder(tree) tree = PostorderTree(tree, order) - partition = inverse(order, partition) + partition = view(inv(order), partition) supernode = view(supernode, order) ancestor = view(ancestor, order) @@ -47,8 +47,8 @@ function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPE graph = OrderedGraph(etree.graph, order) degree = view(degree, order) partition = view(partition, order) - ancestor = inverse(order, ancestor) - representative = inverse(order, map(first, supernode)) + ancestor = view(inv(order), ancestor) + representative = view(inv(order), map(first, supernode)) cardinality = map(length, supernode) SupernodeTree(tree, graph, representative, cardinality, partition, ancestor, degree) From e440d8112c783ea3c3683c23271bf1b07e7f12f1 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 20:10:51 -0500 Subject: [PATCH 030/100] renamed functions again. small performance improvements --- src/Decompositions.jl | 4 +- src/JunctionTrees.jl | 2 +- src/junction_trees/junction_trees.jl | 112 +++++++++++++------------- src/junction_trees/ordered_graphs.jl | 8 +- src/junction_trees/orders.jl | 12 +-- src/junction_trees/supernode_trees.jl | 2 +- 6 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/Decompositions.jl b/src/Decompositions.jl index b2c470d..5a52f3b 100644 --- a/src/Decompositions.jl +++ b/src/Decompositions.jl @@ -310,12 +310,12 @@ function homomorphisms(graph::AbstractSymmetricGraph, jtree::JunctionTree) for i in 1:n - 1 # seperator(i) → clique(parent(i)) j = parentindex(jtree, i) - homomorphism[i] = induced_homomorphism(subgraph[n + i], subgraph[j], seperator_to_parent(jtree, i)) + homomorphism[i] = induced_homomorphism(subgraph[n + i], subgraph[j], lift_par(jtree, i)) end for i in 1:n - 1 # seperator(i) → clique(i) - homomorphism[n + i - 1] = induced_homomorphism(subgraph[n + i], subgraph[i], seperator_to_clique(jtree, i)) + homomorphism[n + i - 1] = induced_homomorphism(subgraph[n + i], subgraph[i], lift_sep(jtree, i)) end subgraph, homomorphism diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index f9f6f00..7a23898 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -34,7 +34,7 @@ export Node, Maximal, Fundamental # Junction Trees -export JunctionTree, treewidth, seperator, residual, clique, seperator_to_parent, seperator_to_clique, set_to_clique, find_node +export JunctionTree, treewidth, seperator, residual, clique, find_clique, lift_par, lift_sep, lift include("junction_trees/orders.jl") diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 4b15381..922caca 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -50,7 +50,7 @@ end Construct the ordered graph ``(G, \\sigma)``, where ``\\sigma`` is a perfect elimination ordering. """ function OrderedGraph(jtree::JunctionTree) - OrderedGraph(jtree.stree.graph) + copy(jtree.stree.graph) end @@ -60,7 +60,7 @@ end Get the clique at node ``i``. """ function clique(jtree::JunctionTree, i::Integer) - [residual(jtree, i); seperator(jtree, i)] + view(Order(jtree), [supernode(jtree.stree, i); jtree.seperator[i]]) end @@ -85,67 +85,86 @@ end """ - find_node(jtree::JunctionTree, v::Integer) + find_clique(jtree::JunctionTree, v::Integer) Find a node `i` safisfying `v ∈ clique(jtree, i)`. """ -function find_node(jtree::JunctionTree, v::Integer) - find_node(jtree.stree, inv(Order(jtree))[v]) +function find_clique(jtree::JunctionTree, v::Integer) + find_supernode(jtree.stree, inv(Order(jtree))[v]) end """ - find_node(jtree::JunctionTree, set::AbstractVector) + find_clique(jtree::JunctionTree, set::AbstractVector) -Find a node `i` satisfying `set ⊆ clique(jtree, i)`. +Find a node `i` satisfying `vertices ⊆ clique(jtree, i)`. """ -function find_node(jtree::JunctionTree, set::AbstractVector) - find_node(jtree.stree, minimum(view(inv(Order(jtree)), set))) +function find_clique(jtree::JunctionTree, vertices::AbstractVector) + find_supernode(jtree.stree, minimum(view(inv(Order(jtree)), vertices))) end """ - seperator_to_clique(jtree::JunctionTree, i::Integer) + treewidth(jtree::JunctionTree) -Construct a vector `index` satisfying `seperator(jtree, i) == clique(jtree, i)[index]` +Compute the width of a junction tree. """ -function seperator_to_clique(jtree::JunctionTree, i::Integer) +function treewidth(jtree::JunctionTree) + treewidth(jtree.stree) +end + + +# Multiline printing. +function Base.show(io::IO, ::MIME"text/plain", jtree::JunctionTree) + n = treewidth(jtree) + print(io, "width: $n\njunction tree:\n") + + print_tree(io, IndexNode(jtree)) do io, node + show(IOContext(io, :compact => true, :limit => true), clique(jtree, node.index)) + end +end + + +######### +# Lifts # +######### +# In principal, cliques are subsets C ⊆ V. In practice, we represent them by vectors +# C: n → V +# Given another vector S: m → V, we may wish to find a vector L: m → n satisfying +# C +# n → V +# ↖ ↑ S +# L m +# The vector L is called a lift, and we write L: S → C. + + +# Compute the lift L: seperator(i) → clique(i). This satisfies +# seperator(jtree, i) == clique(jtree, i)[lift_sep(jtree, i)] +function lift_sep(jtree::JunctionTree, i::Integer) residual = supernode(jtree.stree, i) seperator = jtree.seperator[i] length(residual) + 1:length(residual) + length(seperator) end +# Compute the lift L: seperator(i) → clique(parent(i)). This satisfies +# seperator(jtree, i) == clique(jtree, parentindex(jtree, i)[lift_sep_par(jtree, i)] +function lift_par(jtree::JunctionTree, i::Integer) + lift_ind(jtree, jtree.seperator[i], parentindex(jtree, i)) +end -""" - seperator_to_parent(jtree::JunctionTree, i::Integer) - -Construct a vector `index` satisfying `seperator(jtree, i) == clique(jtree, parent(jtree, i))[index]`. -""" -function seperator_to_parent(jtree::JunctionTree, i::Integer) - j = parentindex(jtree, i) - residual = supernode(jtree.stree, j) - seperator = jtree.seperator[j] - map(jtree.seperator[i]) do v - if v in residual - v - first(residual) + 1 - else - length(residual) + searchsortedfirst(seperator, v) - end - end +# Compute the lift L: vertices → clique(i). This satisfies +# vertices == clique(jtree, i)[lift(jtree, vertices, i)] +function lift(jtree::JunctionTree, vertices::AbstractVector, i::Integer) + lift_ind(jtree, view(inv(Order(jtree)), vertices), i) end -""" - set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) - -Construct a vector `index` satisfying `set == clique(jtree, i)[index]`. -""" -function set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) +function lift_ind(jtree::JunctionTree, indices::AbstractVector, i::Integer) residual = supernode(jtree.stree, i) - sepeperator = jtree.seperator[i] + seperator = jtree.seperator[i] - map(view(inv(Order(jtree)), set)) do v + map(indices) do v if v in residual v - first(residual) + 1 else @@ -155,27 +174,6 @@ function set_to_clique(jtree::JunctionTree, i::Integer, set::AbstractVector) end -""" - treewidth(jtree::JunctionTree) - -Compute the width of a junction tree. -""" -function treewidth(jtree::JunctionTree) - treewidth(jtree.stree) -end - - -# Multiline printing. -function Base.show(io::IO, ::MIME"text/plain", jtree::JunctionTree) - n = treewidth(jtree) - print(io, "width: $n\njunction tree:\n") - - print_tree(io, IndexNode(jtree)) do io, node - show(IOContext(io, :compact => true, :limit => true), clique(jtree, node.index)) - end -end - - ########################## # Indexed Tree Interface # ########################## diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index b67ba4e..4c1b2bd 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -99,7 +99,7 @@ end Construct the permutation ``\\sigma``. """ function Order(graph::OrderedGraph) - Order(graph.order) + copy(graph.order) end @@ -161,6 +161,12 @@ function etree(graph::OrderedGraph) end +# Construct a copy of an ordered graph. +function Base.copy(graph::OrderedGraph) + OrderedGraph(graph.lower, graph.upper, graph.order) +end + + # Multiline printing. function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) print(io, "ordered graph:\n") diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 7cf1bf4..26d8fe7 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -27,18 +27,18 @@ function Order(order::AbstractVector) end -# Construct a copy of a permutation. -function Order(order::Order) - Order(order.order, order.index) -end - - # Compose two permutations. function compose(left::Order, right::Order) Order(right.order[left.order], left.index[right.index]) end +# Construct a copy of a permutation. +function Base.copy(order::Order) + Order(order.order, order.index) +end + + """ inverse(order::Order) diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 31ba435..9ba7b25 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -70,7 +70,7 @@ end # Get the unique node j satisfying i ∈ supernode(j). -function find_node(stree::SupernodeTree, i::Integer) +function find_supernode(stree::SupernodeTree, i::Integer) stree.partition[i] end From b31d75cd9f4a347150663cc365e99823d3b6accc Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 22 Nov 2024 23:34:21 -0500 Subject: [PATCH 031/100] tests passing --- src/junction_trees/supernode_trees.jl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 9ba7b25..470e2ca 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -3,7 +3,6 @@ struct SupernodeTree tree::PostorderTree # supernodal elimination tree graph::OrderedGraph # ordered graph representative::Vector{Int} # vector of representative vertices - cardinality::Vector{Int} # vector of supernode cardinalities # cache partition::Vector{Int} # supernode partition @@ -48,24 +47,24 @@ function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPE degree = view(degree, order) partition = view(partition, order) ancestor = view(inv(order), ancestor) - representative = view(inv(order), map(first, supernode)) - cardinality = map(length, supernode) - SupernodeTree(tree, graph, representative, cardinality, partition, ancestor, degree) + representative = Vector{Int}(undef, treesize(tree) + 1) + representative[1:end - 1] .= view(inv(order), map(first, supernode)) + representative[end] = representative[end - 1] + length(supernode[end]) + + SupernodeTree(tree, graph, representative, partition, ancestor, degree) end # Compute the width of a supernodal elimination tree. function treewidth(stree::SupernodeTree) - maximum(stree.degree[stree.representative]) + maximum(stree.degree) end # Get the (sorted) supernode at node i. function supernode(stree::SupernodeTree, i::Integer) - v = stree.representative[i] - n = stree.cardinality[i] - v:v + n - 1 + stree.representative[i]:stree.representative[i + 1] - 1 end From a166160c9d8fbbc633ed6f3885da6b4b42d3b441 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 01:19:59 -0500 Subject: [PATCH 032/100] speedup --- src/JunctionTrees.jl | 1 + src/junction_trees/ordered_graphs.jl | 40 ++-------------------------- 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 7a23898..7c034bb 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -13,6 +13,7 @@ using Base.Order: Ordering using DataStructures using Graphs using Graphs.SimpleGraphs +using LinearAlgebra using SparseArrays using SparseArrays: AbstractSparseMatrixCSC diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 4c1b2bd..64aa59e 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -40,44 +40,8 @@ end # order vertex order # ---------------------------------------- function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) - m = last(nzrange(graph, size(graph, 1))) - n = size(graph, 1) - - colptr_lower = Vector{Int}(undef, n + 1) - colptr_upper = Vector{Int}(undef, n + 1) - - rowval_lower = Vector{Int}(undef, m ÷ 2) - rowval_upper = Vector{Int}(undef, m ÷ 2) - - count_lower = 1 - count_upper = 1 - - for i in 1:n - colptr_lower[i] = count_lower - colptr_upper[i] = count_upper - neighbor = sort(view(inv(order), view(rowvals(graph), nzrange(graph, order[i])))) - - for j in neighbor - if i < j - rowval_lower[count_lower] = j - count_lower += 1 - else - rowval_upper[count_upper] = j - count_upper += 1 - end - end - end - - colptr_lower[n + 1] = m ÷ 2 + 1 - colptr_upper[n + 1] = m ÷ 2 + 1 - - nzval_lower = ones(Bool, m ÷ 2) - nzval_upper = ones(Bool, m ÷ 2) - - lower = SparseMatrixCSC(n, n, colptr_lower, rowval_lower, nzval_lower) - upper = SparseMatrixCSC(n, n, colptr_upper, rowval_upper, nzval_upper) - - OrderedGraph(lower, upper, order) + graph = permute(graph, order, order) + OrderedGraph(tril(graph), triu(graph), order) end From 5691a937f85016d5b36ccc880bb20cc698958928 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 01:26:31 -0500 Subject: [PATCH 033/100] tiny change --- src/junction_trees/ordered_graphs.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 64aa59e..8bb57d6 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -91,7 +91,6 @@ end - # A Compact Row Storage Scheme for Cholesky Factors Using Elimination Trees # Liu # Algorithm 4.2: Elimination Tree by Path Compression. @@ -107,13 +106,13 @@ function etree(graph::OrderedGraph) for k in inneighbors(graph, i) r = k - while ancestor[r] != 0 && ancestor[r] != i + while !iszero(ancestor[r]) && ancestor[r] != i t = ancestor[r] ancestor[r] = i r = t end - if ancestor[r] == 0 + if iszero(ancestor[r]) ancestor[r] = i parent[r] = i end From 1627070f2022f05e22e745ef3648f26111e101ba Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 01:30:20 -0500 Subject: [PATCH 034/100] another speedup --- src/junction_trees/ordered_graphs.jl | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 8bb57d6..dd16c95 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -52,8 +52,8 @@ end # order permutation # ---------------------------------------- function OrderedGraph(graph::OrderedGraph, order::Order) - newgraph = OrderedGraph(adjacencymatrix(graph), order) - OrderedGraph(newgraph.lower, newgraph.upper, compose(order, graph.order)) + graph_ = OrderedGraph(adjacencymatrix(graph), order) + OrderedGraph(graph_.lower, graph_.upper, compose(order, graph.order)) end @@ -69,28 +69,10 @@ end # Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) - m = ne(graph) - n = nv(graph) - colptr = Vector{Int}(undef, n + 1) - rowval = Vector{Int}(undef, 2m) - count = 1 - - for i in 1:n - colptr[i] = count - - for j in sort(all_neighbors(graph, i)) - rowval[count] = j - count += 1 - end - end - - colptr[n + 1] = 2m + 1 - nzval = ones(Bool, 2m) - SparseMatrixCSC(n, n, colptr, rowval, nzval) + graph.lower + graph.upper end - # A Compact Row Storage Scheme for Cholesky Factors Using Elimination Trees # Liu # Algorithm 4.2: Elimination Tree by Path Compression. From 908fac66bcd4c9d1e1c956e683034c23ca82dd8f Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 01:42:18 -0500 Subject: [PATCH 035/100] another performance improvement --- src/junction_trees/ordered_graphs.jl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index dd16c95..cf1582a 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -48,12 +48,13 @@ end # Given an ordered graph (G, σ) and permutation μ, construct the ordered graph # (G, σ ∘ μ). # ---------------------------------------- -# graph ordered graph -# order permutation +# graph ordered graph +# permutation permutation # ---------------------------------------- -function OrderedGraph(graph::OrderedGraph, order::Order) - graph_ = OrderedGraph(adjacencymatrix(graph), order) - OrderedGraph(graph_.lower, graph_.upper, compose(order, graph.order)) +function OrderedGraph(graph::OrderedGraph, permutation::Order) + order = graph.order + graph = OrderedGraph(adjacencymatrix(graph), permutation) + OrderedGraph(graph.lower, graph.upper, compose(permutation, order)) end @@ -69,7 +70,7 @@ end # Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) - graph.lower + graph.upper + graph.lower .|| graph.upper end From 556c89795957ded0efaa4c8a9048ce37ed93fbd2 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 01:56:26 -0500 Subject: [PATCH 036/100] storing full adjacency matrix --- src/junction_trees/ordered_graphs.jl | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index cf1582a..634e7d6 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -5,6 +5,7 @@ An [ordered graph](https://en.wikipedia.org/wiki/Ordered_graph) ``(G, \\sigma)`` This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractSimpleGraph{Int} + adjmx::SparseMatrixCSC{Bool, Int} # adjacency matrix lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) order::Order # permutation @@ -41,7 +42,7 @@ end # ---------------------------------------- function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) graph = permute(graph, order, order) - OrderedGraph(tril(graph), triu(graph), order) + OrderedGraph(graph, tril(graph), triu(graph), order) end @@ -52,9 +53,9 @@ end # permutation permutation # ---------------------------------------- function OrderedGraph(graph::OrderedGraph, permutation::Order) - order = graph.order - graph = OrderedGraph(adjacencymatrix(graph), permutation) - OrderedGraph(graph.lower, graph.upper, compose(permutation, order)) + order = compose(permutation, graph.order) + graph = OrderedGraph(graph.adjmx, permutation) + OrderedGraph(graph.adjmx, graph.lower, graph.upper, order) end @@ -68,12 +69,6 @@ function Order(graph::OrderedGraph) end -# Construct the adjacency matrix of an ordered graph. -function adjacencymatrix(graph::OrderedGraph) - graph.lower .|| graph.upper -end - - # A Compact Row Storage Scheme for Cholesky Factors Using Elimination Trees # Liu # Algorithm 4.2: Elimination Tree by Path Compression. @@ -109,7 +104,7 @@ end # Construct a copy of an ordered graph. function Base.copy(graph::OrderedGraph) - OrderedGraph(graph.lower, graph.upper, graph.order) + OrderedGraph(graph.adjmx, graph.lower, graph.upper, graph.order) end @@ -156,7 +151,7 @@ end function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) - [inneighbors(graph, i); outneighbors(graph, i)] + view(rowvals(graph.adjmx), nzrange(graph.adjmx, i)) end From cfd104083b1b016a0c1abb28c85108671afd9acf Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 10:53:09 -0500 Subject: [PATCH 037/100] tests passing... --- src/junction_trees/trees.jl | 56 ++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 2a225fe..55b54da 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -1,9 +1,10 @@ -# A rooted tree. +# A left-child right-sibling binary tree. # This type implements the indexed tree interface. struct Tree - root::Int # root - parent::Vector{Int} # vector of parents - children::Vector{Vector{Int}} # vector of children + parent::Vector{Int} # vector of parents + head::Vector{Int} # vector of first children + next::Vector{Int} # vector of next siblings + root::Int # root end @@ -12,24 +13,21 @@ end # parent list of parents # ---------------------------------------- function Tree(parent::AbstractVector) - n = root = length(parent) - children = Vector{Vector{Int}}(undef, n) - - for i in 1:n - children[i] = [] - end + n = length(parent) + head = zeros(Int, n) + next = zeros(Int, n) + root = n - for i in 1:n - j = parent[i] - - if i == j + for i in n:-1:1 + if parent[i] == i root = i else - push!(children[j], i) + next[i] = head[parent[i]] + head[parent[i]] = i end end - Tree(root, parent, children) + Tree(parent, head, next, root) end @@ -65,17 +63,35 @@ end function AbstractTrees.parentindex(tree::Tree, i::Integer) - if i != rootindex(tree) - tree.parent[i] - end + j = tree.parent[i] + !iszero(j) ? j : nothing end function AbstractTrees.childindices(tree::Tree, i::Integer) - tree.children[i] + index = Int[] + j = tree.head[i] + + while !iszero(j) + push!(index, j) + j = tree.next[j] + end + + index end +#function AbstractTrees.nextsiblingindex(tree::Tree, i::Integer) +# j = tree.next[i] +# i != j ? j : nothing +#end + + +#function SiblingLinks(::Type{IndexNode{Tree, Int}}) +# StoredSiblings() +#end + + function AbstractTrees.NodeType(::Type{IndexNode{Tree, Int}}) HasNodeType() end From 2a8de42f05bc03044b64cbab779facda0cc599c3 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 12:49:39 -0500 Subject: [PATCH 038/100] temp commit --- src/junction_trees/trees.jl | 137 +++++++++++++++++++++++++++++++++--- test/Decompositions.jl | 3 + 2 files changed, 131 insertions(+), 9 deletions(-) diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 55b54da..c0f174d 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -31,6 +31,7 @@ function Tree(parent::AbstractVector) end +#= # Compute a postordering of tree's vertices. function postorder(tree::Tree) n = treesize(tree) @@ -45,6 +46,124 @@ function postorder(tree::Tree) Order(order, index) end +=# + + +# Compute a postordering of tree's vertices. +function postorder(tree::Tree) + n = treesize(tree) + order = Vector{Int}(undef, n) + index = Vector{Int}(undef, n) + + #= + k = 1 + + head = copy(tree.head) + next = copy(tree.next) + post = Vector{Int}(undef, n) + stack = Vector{Int}(undef, n) + + top = 1 + stack[1] = tree.root + while top >= 1 + p = stack[top] + i = head[p] + if i == 0 + top -= 1 + post[k] = p + k += 1 + else + head[p] = next[i] + top += 1 + stack[top] = i + end + end + + Order(post) + =# + + #### Stack #### + + #= + top = 0 + items = Vector{Int}(undef, n) + + function empty() + iszero(top) + end + + function push(i) + top += 1 + items[top] = i + end + + function pop() + top -= 1 + items[top + 1] + end + + ############### + + k = 1 + + head = copy(tree.head) + next = tree.next + post = Vector{Int}(undef, n) + + push(rootindex(tree)) + + while !empty() + p = pop() + i = head[p] + + if iszero(i) + post[k] = p + k += 1 + else + head[p] = next[i] + push(p) + push(i) + end + end + + Order(post) + =# + + #### Stack ### + + top = 0 + items = Vector{Int}(undef, n) + + ############## + + k = 1 + + head = copy(tree.head) + next = tree.next + post = Vector{Int}(undef, n) + + top += 1 + items[top] = rootindex(tree) + + while !iszero(top) + p = items[top] + i = head[p] + top -= 1 + + if iszero(i) + post[k] = p + k += 1 + else + head[p] = next[i] + top += 1 + items[top] = p + top += 1 + items[top] = i + end + end + + Order(post) +end ########################## @@ -64,6 +183,12 @@ end function AbstractTrees.parentindex(tree::Tree, i::Integer) j = tree.parent[i] + i != j ? j : nothing +end + + +function AbstractTrees.nextsiblingindex(tree::Tree, i::Integer) + j = tree.next[i] !iszero(j) ? j : nothing end @@ -81,15 +206,9 @@ function AbstractTrees.childindices(tree::Tree, i::Integer) end -#function AbstractTrees.nextsiblingindex(tree::Tree, i::Integer) -# j = tree.next[i] -# i != j ? j : nothing -#end - - -#function SiblingLinks(::Type{IndexNode{Tree, Int}}) -# StoredSiblings() -#end +function AbstractTrees.SiblingLinks(::Type{IndexNode{Tree, Int}}) + StoredSiblings() +end function AbstractTrees.NodeType(::Type{IndexNode{Tree, Int}}) diff --git a/test/Decompositions.jl b/test/Decompositions.jl index c9cb286..303bfca 100644 --- a/test/Decompositions.jl +++ b/test/Decompositions.jl @@ -114,6 +114,8 @@ add_edges!(graph, decomposition = StrDecomp(graph, Order(1:17), Maximal()) + +#= @test decomposition.decomp_shape == @acset Graph begin V = 8 E = 7 @@ -155,6 +157,7 @@ end ACSetTransformation(induced_subgraph(graph, [16, 17]), induced_subgraph(graph, [15, 16, 17]), V=[2, 3], E=Int[]), # p q → o p q ACSetTransformation(induced_subgraph(graph, [13, 14, 17]), induced_subgraph(graph, [10, 11, 13, 14, 17]), V=[3, 4, 5], E=Int[]), # m n q → j k m n q ] +=# end From 1bcf85d66915ea2a6465537ef064bbb823615468 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 15:15:49 -0500 Subject: [PATCH 039/100] temp commit --- src/junction_trees/trees.jl | 107 +++++++----------------------------- 1 file changed, 19 insertions(+), 88 deletions(-) diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index c0f174d..39f0fb4 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -51,118 +51,49 @@ end # Compute a postordering of tree's vertices. function postorder(tree::Tree) - n = treesize(tree) - order = Vector{Int}(undef, n) - index = Vector{Int}(undef, n) - - #= - k = 1 - - head = copy(tree.head) - next = copy(tree.next) - post = Vector{Int}(undef, n) - stack = Vector{Int}(undef, n) - - top = 1 - stack[1] = tree.root - while top >= 1 - p = stack[top] - i = head[p] - if i == 0 - top -= 1 - post[k] = p - k += 1 - else - head[p] = next[i] - top += 1 - stack[top] = i - end - end - - Order(post) - =# - #### Stack #### - #= - top = 0 - items = Vector{Int}(undef, n) + top = Ref{Int}(0) + items = Vector{Int}(undef, treesize(tree)) function empty() - iszero(top) + iszero(top[]) end function push(i) - top += 1 - items[top] = i + top[] += 1 + items[top[]] = i end function pop() - top -= 1 - items[top + 1] + top[] -= 1 + items[top[] + 1] end ############### - k = 1 - - head = copy(tree.head) - next = tree.next - post = Vector{Int}(undef, n) - push(rootindex(tree)) + order = Vector{Int}(undef, treesize(tree)) + index = Vector{Int}(undef, treesize(tree)) + head = copy(tree.head) + count = 1 while !empty() - p = pop() - i = head[p] + j = pop() + i = head[j] if iszero(i) - post[k] = p - k += 1 + order[count] = j + index[j] = count + count += 1 else - head[p] = next[i] - push(p) + head[j] = tree.next[i] + push(j) push(i) end end - Order(post) - =# - - #### Stack ### - - top = 0 - items = Vector{Int}(undef, n) - - ############## - - k = 1 - - head = copy(tree.head) - next = tree.next - post = Vector{Int}(undef, n) - - top += 1 - items[top] = rootindex(tree) - - while !iszero(top) - p = items[top] - i = head[p] - top -= 1 - - if iszero(i) - post[k] = p - k += 1 - else - head[p] = next[i] - top += 1 - items[top] = p - top += 1 - items[top] = i - end - end - - Order(post) + Order(order, index) end From fc44def246ef787ff6fdbbf6d011339c50343083 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 15:28:49 -0500 Subject: [PATCH 040/100] removed old function --- src/junction_trees/trees.jl | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 39f0fb4..ea801bd 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -31,24 +31,6 @@ function Tree(parent::AbstractVector) end -#= -# Compute a postordering of tree's vertices. -function postorder(tree::Tree) - n = treesize(tree) - order = Vector{Int}(undef, n) - index = Vector{Int}(undef, n) - - for node in PreOrderDFS(IndexNode(tree)) - order[n] = node.index - index[node.index] = n - n -= 1 - end - - Order(order, index) -end -=# - - # Compute a postordering of tree's vertices. function postorder(tree::Tree) #### Stack #### From bf53113a4358de4dd068fd32f7625465b7f528b3 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 15:30:08 -0500 Subject: [PATCH 041/100] minor change --- src/junction_trees/trees.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index ea801bd..f26eef6 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -33,10 +33,12 @@ end # Compute a postordering of tree's vertices. function postorder(tree::Tree) + n = treesize(tree) + #### Stack #### top = Ref{Int}(0) - items = Vector{Int}(undef, treesize(tree)) + items = Vector{Int}(undef, n) function empty() iszero(top[]) @@ -55,8 +57,8 @@ function postorder(tree::Tree) ############### push(rootindex(tree)) - order = Vector{Int}(undef, treesize(tree)) - index = Vector{Int}(undef, treesize(tree)) + order = Vector{Int}(undef, n) + index = Vector{Int}(undef, n) head = copy(tree.head) count = 1 From d7fcc7a131e7c7cd95354240e7cdab8f29fcd847 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 16:21:50 -0500 Subject: [PATCH 042/100] postorder tree contains a tree --- src/junction_trees/elimination_trees.jl | 2 +- src/junction_trees/postorder_trees.jl | 53 ++++++++++--------------- src/junction_trees/trees.jl | 2 +- 3 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/junction_trees/elimination_trees.jl b/src/junction_trees/elimination_trees.jl index 9a8dd24..47967f2 100644 --- a/src/junction_trees/elimination_trees.jl +++ b/src/junction_trees/elimination_trees.jl @@ -84,7 +84,7 @@ function supcnt(etree::EliminationTree{PostorderTree}) wt[parentindex(etree.tree, p)] -= 1 for u in outneighbors(etree.graph, p) - if firstdescendant(etree.tree, p) > prev_nbr[u] + if fdesc(etree.tree, p) > prev_nbr[u] wt[p] += 1 pp = prev_p[u] diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index d365917..920b263 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -1,12 +1,9 @@ # A postordered rooted tree. # This type implements the indexed tree interface. struct PostorderTree - parent::Vector{Int} # vector of parents - children::Vector{Vector{Int}} # vector of children - - # cache - level::Vector{Int} # vector of levels - descendant::Vector{Int} # vector of first descendants + tree::Tree # rooted tree + level::Vector{Int} # vector of levels + fdesc::Vector{Int} # vector of first descendants end @@ -15,29 +12,23 @@ end # parent list of parents # ---------------------------------------- function PostorderTree(parent::AbstractVector) - n = length(parent) - children = Vector{Vector{Int}}(undef, n) + tree = Tree(parent) + n = treesize(tree) level = Vector{Int}(undef, n) - descendant = Vector{Int}(undef, n) - - for i in 1:n - children[i] = [] - level[i] = 0 - descendant[i] = i + fdesc = Vector{Int}(undef, n) + level[n] = 0 + fdesc[n] = n + + for i in n - 1:-1:1 + level[i] = level[parentindex(tree, i)] + 1 + fdesc[i] = i end - + for i in 1:n - 1 - j = parent[i] - push!(children[j], i) - descendant[j] = min(descendant[i], descendant[j]) + fdesc[parentindex(tree, i)] = min(fdesc[i], fdesc[parentindex(tree, i)]) end - for i in n - 1:-1:1 - j = parent[i] - level[i] = level[j] + 1 - end - - PostorderTree(parent, children, level, descendant) + PostorderTree(tree, level, fdesc) end @@ -66,8 +57,8 @@ end # Get the first descendant of a node i. -function firstdescendant(tree::PostorderTree, i::Integer) - tree.descendant[i] +function fdesc(tree::PostorderTree, i::Integer) + tree.fdesc[i] end @@ -77,7 +68,7 @@ end function AbstractTrees.treesize(tree::PostorderTree) - length(tree.parent) + treesize(tree.tree) end @@ -87,19 +78,17 @@ end function AbstractTrees.parentindex(tree::PostorderTree, i::Integer) - if i != rootindex(tree) - tree.parent[i] - end + parentindex(tree.tree, i) end function AbstractTrees.childindices(tree::PostorderTree, i::Integer) - tree.children[i] + childindices(tree.tree, i) end function AbstractTrees.rootindex(tree::PostorderTree) - treesize(tree) + rootindex(tree.tree, i) end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index f26eef6..1eedba5 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -1,4 +1,4 @@ -# A left-child right-sibling binary tree. +# A rooted tree. # This type implements the indexed tree interface. struct Tree parent::Vector{Int} # vector of parents From ac0f690132026635a5da209d9761005439fb0d18 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 18:25:32 -0500 Subject: [PATCH 043/100] performance improvement by implementing children iterator --- src/junction_trees/child_indices.jl | 30 +++++++++++++++++++++++++++++ src/junction_trees/trees.jl | 20 ++++++------------- 2 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 src/junction_trees/child_indices.jl diff --git a/src/junction_trees/child_indices.jl b/src/junction_trees/child_indices.jl new file mode 100644 index 0000000..a73fe99 --- /dev/null +++ b/src/junction_trees/child_indices.jl @@ -0,0 +1,30 @@ +struct ChildIndices + tree::Tree + index::Int +end + + +function Base.iterate(iterator::ChildIndices) + iterate(iterator, iterator.tree.head[iterator.index]) +end + + +function Base.iterate(iterator::ChildIndices, i::Integer) + if iszero(i) + nothing + else + i, iterator.tree.next[i] + end +end + + +#= +function Base.IteratorSize(::ChildIndices) + SizeUnknown() +end +=# + + +function AbstractTrees.childindices(tree::Tree, i::Integer) + ChildIndices(tree, i) +end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 1eedba5..470c3d5 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -7,7 +7,6 @@ struct Tree root::Int # root end - # Construct a tree from a list of parents. # ---------------------------------------- # parent list of parents @@ -98,26 +97,19 @@ end function AbstractTrees.parentindex(tree::Tree, i::Integer) j = tree.parent[i] - i != j ? j : nothing + + if i != j + j + end end function AbstractTrees.nextsiblingindex(tree::Tree, i::Integer) j = tree.next[i] - !iszero(j) ? j : nothing -end - -function AbstractTrees.childindices(tree::Tree, i::Integer) - index = Int[] - j = tree.head[i] - - while !iszero(j) - push!(index, j) - j = tree.next[j] + if !iszero(j) + j end - - index end From 272577eebf7f018224e56fa7e56fe1b7668d1985 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 18:33:38 -0500 Subject: [PATCH 044/100] temp commit --- src/junction_trees/child_indices.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/child_indices.jl b/src/junction_trees/child_indices.jl index a73fe99..be44944 100644 --- a/src/junction_trees/child_indices.jl +++ b/src/junction_trees/child_indices.jl @@ -18,11 +18,14 @@ function Base.iterate(iterator::ChildIndices, i::Integer) end -#= -function Base.IteratorSize(::ChildIndices) +function Base.IteratorSize(::Type{ChildIndices}) SizeUnknown() end -=# + + +function Base.eltype(::Type{ChildIndices}) + Int +end function AbstractTrees.childindices(tree::Tree, i::Integer) From cfc29b532da6b2a91a8c1f03d4b39acb6778dea8 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 18:41:19 -0500 Subject: [PATCH 045/100] added file --- src/JunctionTrees.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 7c034bb..72c4e2b 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -42,6 +42,7 @@ include("junction_trees/orders.jl") include("junction_trees/elimination_algorithms.jl") include("junction_trees/ordered_graphs.jl") include("junction_trees/trees.jl") +include("junction_trees/child_indices.jl") include("junction_trees/postorder_trees.jl") include("junction_trees/elimination_trees.jl") include("junction_trees/supernode_types.jl") From 501fce329e7541bc8d4007d979715f1da662853b Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 19:33:35 -0500 Subject: [PATCH 046/100] tests passing --- src/junction_trees/child_indices.jl | 2 +- src/junction_trees/postorder_trees.jl | 2 +- test/Decompositions.jl | 29 +++-- test/JunctionTrees.jl | 146 +++++++++++++------------- 4 files changed, 88 insertions(+), 91 deletions(-) diff --git a/src/junction_trees/child_indices.jl b/src/junction_trees/child_indices.jl index be44944..be8dc1e 100644 --- a/src/junction_trees/child_indices.jl +++ b/src/junction_trees/child_indices.jl @@ -19,7 +19,7 @@ end function Base.IteratorSize(::Type{ChildIndices}) - SizeUnknown() + Base.SizeUnknown() end diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index 920b263..058f1a7 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -88,7 +88,7 @@ end function AbstractTrees.rootindex(tree::PostorderTree) - rootindex(tree.tree, i) + rootindex(tree.tree) end diff --git a/test/Decompositions.jl b/test/Decompositions.jl index 303bfca..8ea00ec 100644 --- a/test/Decompositions.jl +++ b/test/Decompositions.jl @@ -115,49 +115,46 @@ add_edges!(graph, decomposition = StrDecomp(graph, Order(1:17), Maximal()) -#= @test decomposition.decomp_shape == @acset Graph begin V = 8 E = 7 src = [1, 2, 3, 4, 5, 6, 7] - tgt = [5, 5, 4, 5, 6, 8, 8] + tgt = [8, 3, 6, 6, 6, 7, 8] end @test map(i -> ob_map(decomposition.diagram, i), 1:15) == [ - induced_subgraph(graph, [7, 8, 9, 15]), # g h i o - induced_subgraph(graph, [6, 9, 16]), # f i p + induced_subgraph(graph, [10, 11, 13, 14, 17]), # j k m n q induced_subgraph(graph, [2, 3, 4]), # b c d induced_subgraph(graph, [1, 3, 4, 5, 15]), # a c d e o + induced_subgraph(graph, [6, 9, 16]), # f i p + induced_subgraph(graph, [7, 8, 9, 15]), # g h i o induced_subgraph(graph, [5, 9, 15, 16]), # e i o p induced_subgraph(graph, [15, 16, 17]), # o p q - induced_subgraph(graph, [10, 11, 13, 14, 17]), # j k m n q induced_subgraph(graph, [12, 13, 14, 16, 17]), # l m n p q - induced_subgraph(graph, [9, 15]), # i o - induced_subgraph(graph, [9, 16]), # i p + induced_subgraph(graph, [13, 14, 17]), # m n q induced_subgraph(graph, [3, 4]), # c d induced_subgraph(graph, [5, 15]), # e o + induced_subgraph(graph, [9, 16]), # i p + induced_subgraph(graph, [9, 15]), # i o induced_subgraph(graph, [15, 16]), # o p induced_subgraph(graph, [16, 17]), # p q - induced_subgraph(graph, [13, 14, 17]), # m n q ] @test map(i -> hom_map(decomposition.diagram, i), 1:14) == [ - ACSetTransformation(induced_subgraph(graph, [9, 15]), induced_subgraph(graph, [5, 9, 15, 16]), V=[2, 3], E=Int[]), # i o → e i o p - ACSetTransformation(induced_subgraph(graph, [9, 16]), induced_subgraph(graph, [5, 9, 15, 16]), V=[2, 4], E=Int[]), # i p → e i o p + ACSetTransformation(induced_subgraph(graph, [13, 14, 17]), induced_subgraph(graph, [12, 13, 14, 16, 17]), V=[2, 3, 5], E=Int[]), # m n q → l m n p q ACSetTransformation(induced_subgraph(graph, [3, 4]), induced_subgraph(graph, [1, 3, 4, 5, 15]), V=[2, 3], E=Int[]), # c d → a c d e o ACSetTransformation(induced_subgraph(graph, [5, 15]), induced_subgraph(graph, [5, 9, 15, 16]), V=[1, 3], E=Int[]), # e o → e i o p + ACSetTransformation(induced_subgraph(graph, [9, 16]), induced_subgraph(graph, [5, 9, 15, 16]), V=[2, 4], E=Int[]), # i p → e i o p + ACSetTransformation(induced_subgraph(graph, [9, 15]), induced_subgraph(graph, [5, 9, 15, 16]), V=[2, 3], E=Int[]), # i o → e i o p ACSetTransformation(induced_subgraph(graph, [15, 16]), induced_subgraph(graph, [15, 16, 17]), V=[1, 2], E=Int[]), # o p → o p q ACSetTransformation(induced_subgraph(graph, [16, 17]), induced_subgraph(graph, [12, 13, 14, 16, 17]), V=[4, 5], E=Int[]), # p q → l m n p q - ACSetTransformation(induced_subgraph(graph, [13, 14, 17]), induced_subgraph(graph, [12, 13, 14, 16, 17]), V=[2, 3, 5], E=Int[]), # m n q → l m n p q - ACSetTransformation(induced_subgraph(graph, [9, 15]), induced_subgraph(graph, [7, 8, 9, 15]), V=[3, 4], E=Int[]), # i o → g h i o - ACSetTransformation(induced_subgraph(graph, [9, 16]), induced_subgraph(graph, [6, 9, 16]), V=[2, 3], E=Int[]), # i p → f i p + ACSetTransformation(induced_subgraph(graph, [13, 14, 17]), induced_subgraph(graph, [10, 11, 13, 14, 17]), V=[3, 4, 5], E=Int[]), # m n q → j k m n q ACSetTransformation(induced_subgraph(graph, [3, 4]), induced_subgraph(graph, [2, 3, 4]), V=[2, 3], E=Int[]), # c d → b c d ACSetTransformation(induced_subgraph(graph, [5, 15]), induced_subgraph(graph, [1, 3, 4, 5, 15]), V=[4, 5], E=Int[]), # e o → a c d e o + ACSetTransformation(induced_subgraph(graph, [9, 16]), induced_subgraph(graph, [6, 9, 16]), V=[2, 3], E=Int[]), # i p → f i p + ACSetTransformation(induced_subgraph(graph, [9, 15]), induced_subgraph(graph, [7, 8, 9, 15]), V=[3, 4], E=Int[]), # i o → g h i o ACSetTransformation(induced_subgraph(graph, [15, 16]), induced_subgraph(graph, [5, 9, 15, 16]), V=[3, 4], E=Int[]), # o p → e i o p ACSetTransformation(induced_subgraph(graph, [16, 17]), induced_subgraph(graph, [15, 16, 17]), V=[2, 3], E=Int[]), # p q → o p q - ACSetTransformation(induced_subgraph(graph, [13, 14, 17]), induced_subgraph(graph, [10, 11, 13, 14, 17]), V=[3, 4, 5], E=Int[]), # m n q → j k m n q ] -=# - end diff --git a/test/JunctionTrees.jl b/test/JunctionTrees.jl index 5f3cfea..4957084 100644 --- a/test/JunctionTrees.jl +++ b/test/JunctionTrees.jl @@ -42,15 +42,15 @@ jtree = JunctionTree(graph, order, Node()) @test map(i -> parentindex(jtree, i), 1:17) == [ 2, - 9, - 9, - 6, - 6, - 7, + 4, + 4, + 5, + 16, + 8, 8, 9, 10, - 16, + 14, 14, 13, 14, @@ -60,62 +60,62 @@ jtree = JunctionTree(graph, order, Node()) nothing, ] -@test map(i -> childindices(jtree, i), 1:17) == [ +@test map(i -> collect(childindices(jtree, i)), 1:17) == [ [], [1], [], + [2, 3], + [4], [], [], - [4, 5], - [6], - [7], - [2, 3, 8], + [6, 7], + [8], [9], [], [], [12], - [11, 13], + [10, 11, 13], [14], - [10, 15], + [5, 15], [16], ] @test map(i -> residual(jtree, i), 1:17) == [ - [7], # g - [8], # h - [6], # f - [2], # b + [10], # j + [11], # k + [12], # l + [13], # m + [14], # n [1], # a + [2], # b [3], # c [4], # d [5], # e + [6], # f + [7], # g + [8], # h [9], # i [15], # o - [12], # l - [10], # j - [11], # k - [13], # m - [14], # n [16], # p [17], # q ] @test map(i -> seperator(jtree, i), 1:17) == [ - [8, 9, 15], # h i o - [9, 15], # i o - [9, 16], # i p - [3, 4], # c d + [11, 13, 14, 17], # k m n q + [13, 14, 17], # m n q + [13, 14, 16, 17], # m n p q + [14, 16, 17], # n p q + [16, 17], # p q [3, 4, 5, 15], # c d e o + [3, 4], # c d [4, 5, 15], # d e o [5, 15], # e o [9, 15, 16], # i o p + [9, 16], # i p + [8, 9, 15], # h i o + [9, 15], # i o [15, 16], # o p [16, 17], # p q - [13, 14, 16, 17], # m n p q - [11, 13, 14, 17], # k m n q - [13, 14, 17], # m n q - [14, 16, 17], # n p q - [16, 17], # p q [17], # q [], # ] @@ -128,46 +128,46 @@ jtree = JunctionTree(graph, order, Maximal()) @test treesize(jtree) == 8 @test map(i -> parentindex(jtree, i), 1:8) == [ - 5, - 5, - 4, - 5, - 6, 8, + 3, + 6, + 6, + 6, + 7, 8, nothing ] -@test map(i -> childindices(jtree, i), 1:8) == [ +@test map(i -> collect(childindices(jtree, i)), 1:8) == [ [], [], + [2], [], - [3], - [1, 2, 4], - [5], [], - [6, 7], + [3, 4, 5], + [6], + [1, 7], ] @test map(i -> residual(jtree, i), 1:8) == [ - [7, 8], # g h - [6], # f + [10, 11], # j k [2], # b [1, 3, 4], # a c d + [6], # f + [7, 8], # g h [5, 9], # e i [15], # o - [10, 11], # j k [12, 13, 14, 16, 17], # l m n p q ] @test map(i -> seperator(jtree, i), 1:8) == [ - [9, 15], # i o - [9, 16], # i p + [13, 14, 17], # m n q [3, 4], # c d [5, 15], # e o + [9, 16], # i p + [9, 15], # i o [15, 16], # o p [16, 17], # p q - [13, 14, 17], # m n q [], # ] @@ -178,61 +178,61 @@ jtree = JunctionTree(graph, order, Fundamental()) @test treesize(jtree) == 12 @test map(i -> parentindex(jtree, i), 1:12) == [ - 7, - 7, - 5, - 5, + 3, + 3, + 12, + 6, 6, 7, - 8, - 12, - 11, + 10, + 10, + 10, 11, 12, nothing, ] -@test map(i -> childindices(jtree, i), 1:12) == [ +@test map(i -> collect(childindices(jtree, i)), 1:12) == [ [], [], + [1, 2], [], [], - [3, 4], - [5], - [1, 2, 6], - [7], + [4, 5], + [6], [], [], - [9, 10], - [8, 11], + [7, 8, 9], + [10], + [3, 11], ] @test map(i -> residual(jtree, i), 1:12) == [ - [7, 8], # g h - [6], # f - [2], # b + [10, 11], # j k + [12], # l + [13, 14], # m n [1], # a + [2], # b [3, 4], # c d [5], # e + [6], # f + [7, 8], # g h [9], # i [15], # o - [12], # l - [10, 11], # j k - [13, 14], # m n [16, 17], # p q ] @test map(i -> seperator(jtree, i), 1:12) == [ - [9, 15], # i o - [9, 16], # i p - [3, 4], # c d + [13, 14, 17], # m n q + [13, 14, 16, 17], # m n p q + [16, 17], # p q [3, 4, 5, 15], # c d e o + [3, 4], # c d [5, 15], # e o [9, 15, 16], # i o p + [9, 16], # i p + [9, 15], # i o [15, 16], # o p [16, 17], # p q - [13, 14, 16, 17], # m n p q - [13, 14, 17], # m n q - [16, 17], # p q [], # ] From 289391e2a1b4b27a992a267d1384f831837c86c6 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 23 Nov 2024 19:36:59 -0500 Subject: [PATCH 047/100] zeros in parents --- src/junction_trees/ordered_graphs.jl | 1 - src/junction_trees/postorder_trees.jl | 2 +- src/junction_trees/supernode_types.jl | 2 +- src/junction_trees/trees.jl | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 634e7d6..4cf99f9 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -97,7 +97,6 @@ function etree(graph::OrderedGraph) end end - parent[n] = n parent end diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index 058f1a7..e3442ad 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -45,7 +45,7 @@ function PostorderTree(tree::Tree, order::Order) parent[i] = inv(order)[parentindex(tree, order[i])] end - parent[n] = n + parent[n] = 0 PostorderTree(parent) end diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 27e91db..be0cddc 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -54,7 +54,7 @@ function stree(etree::EliminationTree, degree::AbstractVector, stype::SupernodeT else new_in_clique[v] = i += 1 push!(new, [v]) - push!(parent, i) + push!(parent, 0) push!(first_anc, n) end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 470c3d5..bc6fca2 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -18,7 +18,7 @@ function Tree(parent::AbstractVector) root = n for i in n:-1:1 - if parent[i] == i + if iszero(parent[i]) root = i else next[i] = head[parent[i]] @@ -98,7 +98,7 @@ end function AbstractTrees.parentindex(tree::Tree, i::Integer) j = tree.parent[i] - if i != j + if !iszero(j) j end end From 02c6e30a3d840bfb7acf011bb3689b065a0175f6 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 24 Nov 2024 16:03:55 -0800 Subject: [PATCH 048/100] renamed variable --- src/junction_trees/ordered_graphs.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 4cf99f9..cdd357f 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -5,10 +5,10 @@ An [ordered graph](https://en.wikipedia.org/wiki/Ordered_graph) ``(G, \\sigma)`` This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractSimpleGraph{Int} - adjmx::SparseMatrixCSC{Bool, Int} # adjacency matrix - lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) - upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) - order::Order # permutation + symmetric::SparseMatrixCSC{Bool, Int} # adjacency matrix (symmetric) + lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) + upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) + order::Order # permutation end @@ -54,8 +54,8 @@ end # ---------------------------------------- function OrderedGraph(graph::OrderedGraph, permutation::Order) order = compose(permutation, graph.order) - graph = OrderedGraph(graph.adjmx, permutation) - OrderedGraph(graph.adjmx, graph.lower, graph.upper, order) + graph = OrderedGraph(graph.symmetric, permutation) + OrderedGraph(graph.symmetric, graph.lower, graph.upper, order) end @@ -103,7 +103,7 @@ end # Construct a copy of an ordered graph. function Base.copy(graph::OrderedGraph) - OrderedGraph(graph.adjmx, graph.lower, graph.upper, graph.order) + OrderedGraph(graph.symmetric, graph.lower, graph.upper, graph.order) end @@ -150,7 +150,7 @@ end function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) - view(rowvals(graph.adjmx), nzrange(graph.adjmx, i)) + view(rowvals(graph.symmetric), nzrange(graph.symmetric, i)) end From 927470ec791ec0b75ae944ba73e8c6b9b01316d8 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 24 Nov 2024 16:23:03 -0800 Subject: [PATCH 049/100] tests passing --- src/junction_trees/junction_trees.jl | 2 +- src/junction_trees/ordered_graphs.jl | 86 +++++++++++++++++++++++++++ src/junction_trees/supernode_trees.jl | 16 ++--- src/junction_trees/supernode_types.jl | 18 +++--- 4 files changed, 102 insertions(+), 20 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 922caca..1926893 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -21,7 +21,7 @@ function JunctionTree( ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - JunctionTree(SupernodeTree(graph, ealg, stype)) + JunctionTree(SupernodeTree(OrderedGraph(graph, ealg), stype)) end diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index cdd357f..5c42b0b 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -101,6 +101,92 @@ function etree(graph::OrderedGraph) end +# An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization +# Gilbert, Ng, and Peyton +# Figure 3: Implementation of algorithm to compute row and column counts. +function supcnt(graph::OrderedGraph, tree::Tree) + order = postorder(tree) + rc, cc = supcnt(OrderedGraph(graph, order), PostorderTree(tree, order)) + view(rc, inv(order)), view(cc, inv(order)) +end + + +# An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization +# Gilbert, Ng, and Peyton +# Figure 3: Implementation of algorithm to compute row and column counts. +function supcnt(graph::OrderedGraph, tree::PostorderTree) + n = treesize(tree) + + #### Disjoint Set Union #### + + rvert = collect(1:n) + index = collect(1:n) + forest = IntDisjointSets(n) + + function find(u) + index[find_root!(forest, u)] + end + + function union(u, v) + w = max(u, v) + rvert[w] = root_union!(forest, rvert[u], rvert[v]) + index[rvert[w]] = w + end + + ############################ + + prev_p = zeros(Int, n) + prev_nbr = zeros(Int, n) + rc = ones(Int, n) + wt = ones(Int, n) + + for u in 1:n - 1 + wt[parentindex(tree, u)] = 0 + end + + for p in 1:n - 1 + wt[parentindex(tree, p)] -= 1 + + for u in outneighbors(graph, p) + if fdesc(tree, p) > prev_nbr[u] + wt[p] += 1 + pp = prev_p[u] + + if iszero(pp) + rc[u] += level(tree, p) - level(tree, u) + else + q = find(pp) + rc[u] += level(tree, p) - level(tree, q) + wt[q] -= 1 + end + + prev_p[u] = p + end + + prev_nbr[u] = p + end + + union(p, parentindex(tree, p)) + end + + cc = wt + + for v in 1:n - 1 + cc[parentindex(tree, v)] += cc[v] + end + + rc, cc +end + + +# Compute higher degree of every vertex in the elimination graph of +# (G, σ). +function outdegrees(graph::OrderedGraph, tree::Tree) + rc, cc = supcnt(graph, tree) + cc .- 1 +end + + # Construct a copy of an ordered graph. function Base.copy(graph::OrderedGraph) OrderedGraph(graph.symmetric, graph.lower, graph.upper, graph.order) diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl index 470e2ca..36af31f 100644 --- a/src/junction_trees/supernode_trees.jl +++ b/src/junction_trees/supernode_trees.jl @@ -17,12 +17,8 @@ end # ealg elimination algorithm # stype supernode type # ---------------------------------------- -function SupernodeTree( - graph, - ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, - stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - - SupernodeTree(EliminationTree(graph, ealg), stype) +function SupernodeTree(graph::OrderedGraph, stype::SupernodeType) + SupernodeTree(graph, Tree(etree(graph)), stype) end @@ -31,9 +27,9 @@ end # etree elimination tree # stype supernode type # ---------------------------------------- -function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - degree = outdegrees(etree) - partition, supernode, parent, ancestor = stree(etree, degree, stype) +function SupernodeTree(graph::OrderedGraph, tree::Tree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) + degree = outdegrees(graph, tree) + partition, supernode, parent, ancestor = stree(tree, degree, stype) tree = Tree(parent) order = postorder(tree) @@ -43,7 +39,7 @@ function SupernodeTree(etree::EliminationTree, stype::SupernodeType=DEFAULT_SUPE ancestor = view(ancestor, order) order = Order(vcat(supernode...)) - graph = OrderedGraph(etree.graph, order) + graph = OrderedGraph(graph, order) degree = view(degree, order) partition = view(partition, order) ancestor = view(inv(order), ancestor) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index be0cddc..c0631a2 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -36,8 +36,8 @@ struct Fundamental <: SupernodeType end # Compact Clique Tree Data Structures in Sparse Matrix Factorizations # Pothen and Sun # Figure 4: The Clique Tree Algorithm 2 -function stree(etree::EliminationTree, degree::AbstractVector, stype::SupernodeType) - n = treesize(etree.tree) +function stree(tree::Tree, degree::AbstractVector, stype::SupernodeType) + n = treesize(tree) new_in_clique = Vector{Int}(undef, n) new = Vector{Int}[] parent = Int[] @@ -46,7 +46,7 @@ function stree(etree::EliminationTree, degree::AbstractVector, stype::SupernodeT i = 0 for v in 1:n - u = child_in_supernode(etree, degree, stype, v) + u = child_in_supernode(tree, degree, stype, v) if !isnothing(u) new_in_clique[v] = new_in_clique[u] @@ -58,7 +58,7 @@ function stree(etree::EliminationTree, degree::AbstractVector, stype::SupernodeT push!(first_anc, n) end - for s in childindices(etree.tree, v) + for s in childindices(tree, v) if s !== u parent[new_in_clique[s]] = new_in_clique[v] first_anc[new_in_clique[s]] = v @@ -72,15 +72,15 @@ end # Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. -function child_in_supernode(etree::EliminationTree, degree::AbstractVector, stype::Node, v::Integer) end +function child_in_supernode(tree::Tree, degree::AbstractVector, stype::Node, v::Integer) end # Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. -function child_in_supernode(etree::EliminationTree, degree::AbstractVector, stype::Maximal, v::Integer) +function child_in_supernode(tree::Tree, degree::AbstractVector, stype::Maximal, v::Integer) u = nothing - for w in childindices(etree.tree, v) + for w in childindices(tree, v) if degree[w] == degree[v] + 1 u = w break @@ -93,10 +93,10 @@ end # Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. -function child_in_supernode(etree::EliminationTree, degree::AbstractVector, stype::Fundamental, v::Integer) +function child_in_supernode(tree::Tree, degree::AbstractVector, stype::Fundamental, v::Integer) u = nothing - for w in childindices(etree.tree, v) + for w in childindices(tree, v) if isnothing(u) && degree[w] == degree[v] + 1 u = w else From 68ee1cbd54846e352ec936fe1c37b912444b1bcc Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 24 Nov 2024 16:24:00 -0800 Subject: [PATCH 050/100] elimination trees gone --- src/JunctionTrees.jl | 3 +- src/junction_trees/elimination_trees.jl | 123 ------------------------ 2 files changed, 1 insertion(+), 125 deletions(-) delete mode 100644 src/junction_trees/elimination_trees.jl diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 72c4e2b..22ce58d 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -40,11 +40,10 @@ export JunctionTree, treewidth, seperator, residual, clique, find_clique, lift_p include("junction_trees/orders.jl") include("junction_trees/elimination_algorithms.jl") -include("junction_trees/ordered_graphs.jl") include("junction_trees/trees.jl") include("junction_trees/child_indices.jl") include("junction_trees/postorder_trees.jl") -include("junction_trees/elimination_trees.jl") +include("junction_trees/ordered_graphs.jl") include("junction_trees/supernode_types.jl") include("junction_trees/supernode_trees.jl") include("junction_trees/junction_trees.jl") diff --git a/src/junction_trees/elimination_trees.jl b/src/junction_trees/elimination_trees.jl deleted file mode 100644 index 47967f2..0000000 --- a/src/junction_trees/elimination_trees.jl +++ /dev/null @@ -1,123 +0,0 @@ -# An ordered graph (G, σ) equipped with the elimination tree T of its elimination graph. -# Nodes i in T correspond to vertices σ(i) in G. -struct EliminationTree{T <: Union{Tree, PostorderTree}} - tree::T # elimination tree - graph::OrderedGraph # ordered graph -end - - -# Construct an elimination tree using an elimination algorithm. -# ---------------------------------------- -# graph simple connected graph -# ealg elimination algorithm -# ---------------------------------------- -function EliminationTree( - graph, - ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM) - EliminationTree(OrderedGraph(graph, ealg)) -end - - -# Construct the elimination tree of an ordered graph. -# ---------------------------------------- -# graph ordered graph -# ---------------------------------------- -function EliminationTree(graph::OrderedGraph) - EliminationTree(Tree(etree(graph)), graph) -end - - -# Postorder an elimination tree. -# ---------------------------------------- -# graph ordered graph -# order postorder -# ---------------------------------------- -function EliminationTree{PostorderTree}(etree::EliminationTree, order::Order) - EliminationTree(PostorderTree(etree.tree, order), OrderedGraph(etree.graph, order)) -end - - -# An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization -# Gilbert, Ng, and Peyton -# Figure 3: Implementation of algorithm to compute row and column counts. -function supcnt(etree::EliminationTree) - order = postorder(etree.tree) - rc, cc = supcnt(EliminationTree{PostorderTree}(etree, order)) - view(rc, inv(order)), view(cc, inv(order)) -end - - -# An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization -# Gilbert, Ng, and Peyton -# Figure 3: Implementation of algorithm to compute row and column counts. -function supcnt(etree::EliminationTree{PostorderTree}) - n = treesize(etree.tree) - - #### Disjoint Set Union #### - - rvert = collect(1:n) - index = collect(1:n) - forest = IntDisjointSets(n) - - function find(u) - index[find_root!(forest, u)] - end - - function union(u, v) - w = max(u, v) - rvert[w] = root_union!(forest, rvert[u], rvert[v]) - index[rvert[w]] = w - end - - ############################ - - prev_p = zeros(Int, n) - prev_nbr = zeros(Int, n) - rc = ones(Int, n) - wt = ones(Int, n) - - for u in 1:n - 1 - wt[parentindex(etree.tree, u)] = 0 - end - - for p in 1:n - 1 - wt[parentindex(etree.tree, p)] -= 1 - - for u in outneighbors(etree.graph, p) - if fdesc(etree.tree, p) > prev_nbr[u] - wt[p] += 1 - pp = prev_p[u] - - if iszero(pp) - rc[u] += level(etree.tree, p) - level(etree.tree, u) - else - q = find(pp) - rc[u] += level(etree.tree, p) - level(etree.tree, q) - wt[q] -= 1 - end - - prev_p[u] = p - end - - prev_nbr[u] = p - end - - union(p, parentindex(etree.tree, p)) - end - - cc = wt - - for v in 1:n - 1 - cc[parentindex(etree.tree, v)] += cc[v] - end - - rc, cc -end - - -# Compute higher degree of every vertex in the elimination graph of -# (G, σ). -function outdegrees(etree::EliminationTree) - rc, cc = supcnt(etree) - cc .- 1 -end From 39f9da09b5e0331f439dd3654b22cc051494d19e Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Tue, 26 Nov 2024 09:16:38 -0800 Subject: [PATCH 051/100] tests passing somehow --- src/junction_trees/junction_trees.jl | 150 ++++++++++++++++++++------- src/junction_trees/ordered_graphs.jl | 27 +---- 2 files changed, 115 insertions(+), 62 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 1926893..3e84d97 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -5,8 +5,15 @@ A [tree decomposition](https://en.wikipedia.org/wiki/Tree_decomposition) of a gr This type implements the [indexed tree interface](https://juliacollections.github.io/AbstractTrees.jl/stable/#The-Indexed-Tree-Interface). """ struct JunctionTree - stree::SupernodeTree # supernodal elimination tree + order::Order # elimination order + tree::PostorderTree # supernodal elimination tree + graph::OrderedGraph # ordered graph + representative::Vector{Int} # vector of representative vertices seperator::Vector{Vector{Int}} # vector of seperators + + # cache + partition::Vector{Int} # supernode partition + degree::Vector{Int} # vector of higher degrees end @@ -18,10 +25,23 @@ a supernode type. """ function JunctionTree( graph, - ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM, + ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - JunctionTree(SupernodeTree(OrderedGraph(graph, ealg), stype)) + graph = adjacencymatrix(graph) + order = Order(graph, ealg) + JunctionTree(graph, order, stype) +end + + +function JunctionTree( + graph, + order::Order, + stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) + + graph = OrderedGraph(graph, order) + tree = Tree(etree(graph)) + JunctionTree(order, graph, tree, stype) end @@ -29,8 +49,59 @@ end # ---------------------------------------- # stree supernodal elimination tree # ---------------------------------------- -function JunctionTree(stree::SupernodeTree) - JunctionTree(stree, map(sort ∘ collect, seperators(stree))) +function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) + degree = outdegrees(graph, tree) + partition, supernode, parent, ancestor = stree(tree, degree, stype) + tree = Tree(parent) + + order = postorder(tree) + tree = PostorderTree(tree, order) + partition = view(inv(order), partition) + supernode = view(supernode, order) + ancestor = view(ancestor, order) + + order = Order(vcat(supernode...)) + graph = OrderedGraph(graph, order) + degree = view(degree, order) + partition = view(partition, order) + ancestor = view(inv(order), ancestor) + + representative = Vector{Int}(undef, treesize(tree) + 1) + representative[1:end - 1] .= view(inv(order), map(first, supernode)) + representative[end] = representative[end - 1] + length(supernode[end]) + + seperator = map(sort ∘ collect, seperators(graph, tree, representative, ancestor)) + JunctionTree(order, tree, graph, representative, seperator, partition, degree) +end + + +# Compute the (unsorted) seperators of every node in T. +function seperators(graph::OrderedGraph, tree::PostorderTree, representative::AbstractVector, ancestor::AbstractVector) + n = treesize(tree) + seperator = Vector{Set{Int}}(undef, n) + + for i in 1:n - 1 + seperator[i] = Set(ancestor[i]) + + for v in outneighbors(graph, representative[i]) + if ancestor[i] < v + push!(seperator[i], v) + end + end + end + + for j in 1:n - 1 + for i in childindices(tree, j) + for v in seperator[i] + if ancestor[j] < v + push!(seperator[j], v) + end + end + end + end + + seperator[n] = Set() + seperator end @@ -40,27 +111,38 @@ end Construct a perfect elimination ordering. """ function Order(jtree::JunctionTree) - Order(jtree.stree.graph) + Order(jtree.order) end """ - OrderedGraph(jtree::JunctionTree) + clique(jtree::JunctionTree, i::Integer) -Construct the ordered graph ``(G, \\sigma)``, where ``\\sigma`` is a perfect elimination ordering. +Get the clique at node ``i``. """ -function OrderedGraph(jtree::JunctionTree) - copy(jtree.stree.graph) +function clique(jtree::JunctionTree, i::Integer) + view(jtree.order, [residualindices(jtree, i); seperatorindices(jtree, i)]) end """ - clique(jtree::JunctionTree, i::Integer) + treewidth(jtree::JunctionTree) -Get the clique at node ``i``. +Compute the width of a junction tree. """ -function clique(jtree::JunctionTree, i::Integer) - view(Order(jtree), [supernode(jtree.stree, i); jtree.seperator[i]]) +function treewidth(jtree::JunctionTree) + maximum(jtree.degree) +end + + +# Get the (sorted) supernode at node i. +function residualindices(jtree::JunctionTree, i::Integer) + jtree.representative[i]:jtree.representative[i + 1] - 1 +end + + +function seperatorindices(jtree::JunctionTree, i::Integer) + jtree.seperator[i] end @@ -70,7 +152,7 @@ end Get the seperator at node ``i``. """ function seperator(jtree::JunctionTree, i::Integer) - view(Order(jtree), jtree.seperator[i]) + view(jtree.order, seperatorindices(jtree, i)) end @@ -80,7 +162,7 @@ end Get the residual at node ``i``. """ function residual(jtree::JunctionTree, i::Integer) - view(Order(jtree), supernode(jtree.stree, i)) + view(jtree.order, residualindices(jtree, i)) end @@ -90,7 +172,7 @@ end Find a node `i` safisfying `v ∈ clique(jtree, i)`. """ function find_clique(jtree::JunctionTree, v::Integer) - find_supernode(jtree.stree, inv(Order(jtree))[v]) + jtree.partition[inv(jtree.order)[v]] end @@ -100,17 +182,7 @@ end Find a node `i` satisfying `vertices ⊆ clique(jtree, i)`. """ function find_clique(jtree::JunctionTree, vertices::AbstractVector) - find_supernode(jtree.stree, minimum(view(inv(Order(jtree)), vertices))) -end - - -""" - treewidth(jtree::JunctionTree) - -Compute the width of a junction tree. -""" -function treewidth(jtree::JunctionTree) - treewidth(jtree.stree) + jtree.partition[minimum(view(jtree.order, vertices))] end @@ -141,28 +213,28 @@ end # Compute the lift L: seperator(i) → clique(i). This satisfies # seperator(jtree, i) == clique(jtree, i)[lift_sep(jtree, i)] function lift_sep(jtree::JunctionTree, i::Integer) - residual = supernode(jtree.stree, i) - seperator = jtree.seperator[i] + residual = residualindices(jtree, i) + seperator = seperatorindices(jtree, i) length(residual) + 1:length(residual) + length(seperator) end # Compute the lift L: seperator(i) → clique(parent(i)). This satisfies # seperator(jtree, i) == clique(jtree, parentindex(jtree, i)[lift_sep_par(jtree, i)] function lift_par(jtree::JunctionTree, i::Integer) - lift_ind(jtree, jtree.seperator[i], parentindex(jtree, i)) + lift_ind(jtree, seperatorindices(jtree, i), parentindex(jtree, i)) end # Compute the lift L: vertices → clique(i). This satisfies # vertices == clique(jtree, i)[lift(jtree, vertices, i)] function lift(jtree::JunctionTree, vertices::AbstractVector, i::Integer) - lift_ind(jtree, view(inv(Order(jtree)), vertices), i) + lift_ind(jtree, view(inv(jtree.order), vertices), i) end function lift_ind(jtree::JunctionTree, indices::AbstractVector, i::Integer) - residual = supernode(jtree.stree, i) - seperator = jtree.seperator[i] + residual = residualindices(jtree, i) + seperator = seperatorindices(jtree,i) map(indices) do v if v in residual @@ -180,27 +252,27 @@ end function AbstractTrees.treesize(jtree::JunctionTree) - treesize(jtree.stree.tree) + treesize(jtree.tree) end function AbstractTrees.treeheight(jtree::JunctionTree) - treeheight(jtree.stree.tree) + treeheight(jtree.tree) end function AbstractTrees.rootindex(jtree::JunctionTree) - rootindex(jtree.stree.tree) + rootindex(jtree.tree) end function AbstractTrees.parentindex(jtree::JunctionTree, i::Integer) - parentindex(jtree.stree.tree, i) + parentindex(jtree.tree, i) end function AbstractTrees.childindices(jtree::JunctionTree, i::Integer) - childindices(jtree.stree.tree, i) + childindices(jtree.tree, i) end diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 5c42b0b..fbeef24 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,14 +1,13 @@ """ OrderedGraph <: AbstractSimpleGraph{Int} -An [ordered graph](https://en.wikipedia.org/wiki/Ordered_graph) ``(G, \\sigma)``. +A directed simple graph whose edges i → j are oriented from lower to higher vertices. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractSimpleGraph{Int} symmetric::SparseMatrixCSC{Bool, Int} # adjacency matrix (symmetric) lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) - order::Order # permutation end @@ -42,30 +41,12 @@ end # ---------------------------------------- function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) graph = permute(graph, order, order) - OrderedGraph(graph, tril(graph), triu(graph), order) + OrderedGraph(graph, tril(graph), triu(graph)) end -# Given an ordered graph (G, σ) and permutation μ, construct the ordered graph -# (G, σ ∘ μ). -# ---------------------------------------- -# graph ordered graph -# permutation permutation -# ---------------------------------------- -function OrderedGraph(graph::OrderedGraph, permutation::Order) - order = compose(permutation, graph.order) - graph = OrderedGraph(graph.symmetric, permutation) - OrderedGraph(graph.symmetric, graph.lower, graph.upper, order) -end - - -""" - Order(graph::OrderedGraph) - -Construct the permutation ``\\sigma``. -""" -function Order(graph::OrderedGraph) - copy(graph.order) +function adjacencymatrix(graph::OrderedGraph) + graph.symmetric end From f5115d68f59addf12db230b063c9f0b8fdb64859 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Tue, 26 Nov 2024 09:19:25 -0800 Subject: [PATCH 052/100] removed type `SupernodeTree` --- src/JunctionTrees.jl | 1 - src/junction_trees/supernode_trees.jl | 100 -------------------------- 2 files changed, 101 deletions(-) delete mode 100644 src/junction_trees/supernode_trees.jl diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 22ce58d..320b619 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -45,7 +45,6 @@ include("junction_trees/child_indices.jl") include("junction_trees/postorder_trees.jl") include("junction_trees/ordered_graphs.jl") include("junction_trees/supernode_types.jl") -include("junction_trees/supernode_trees.jl") include("junction_trees/junction_trees.jl") diff --git a/src/junction_trees/supernode_trees.jl b/src/junction_trees/supernode_trees.jl deleted file mode 100644 index 36af31f..0000000 --- a/src/junction_trees/supernode_trees.jl +++ /dev/null @@ -1,100 +0,0 @@ -# An ordered graph (G, σ) equipped with a supernodal elimination tree T. -struct SupernodeTree - tree::PostorderTree # supernodal elimination tree - graph::OrderedGraph # ordered graph - representative::Vector{Int} # vector of representative vertices - - # cache - partition::Vector{Int} # supernode partition - ancestor::Vector{Int} # vector of first ancestors - degree::Vector{Int} # vector of higher degrees -end - - -# Construct a supernodal elimination tree using an elimination algorithm. -# ---------------------------------------- -# graph simple connected graph -# ealg elimination algorithm -# stype supernode type -# ---------------------------------------- -function SupernodeTree(graph::OrderedGraph, stype::SupernodeType) - SupernodeTree(graph, Tree(etree(graph)), stype) -end - - -# Construct a supernodal elimination tree. -# ---------------------------------------- -# etree elimination tree -# stype supernode type -# ---------------------------------------- -function SupernodeTree(graph::OrderedGraph, tree::Tree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - degree = outdegrees(graph, tree) - partition, supernode, parent, ancestor = stree(tree, degree, stype) - tree = Tree(parent) - - order = postorder(tree) - tree = PostorderTree(tree, order) - partition = view(inv(order), partition) - supernode = view(supernode, order) - ancestor = view(ancestor, order) - - order = Order(vcat(supernode...)) - graph = OrderedGraph(graph, order) - degree = view(degree, order) - partition = view(partition, order) - ancestor = view(inv(order), ancestor) - - representative = Vector{Int}(undef, treesize(tree) + 1) - representative[1:end - 1] .= view(inv(order), map(first, supernode)) - representative[end] = representative[end - 1] + length(supernode[end]) - - SupernodeTree(tree, graph, representative, partition, ancestor, degree) -end - - -# Compute the width of a supernodal elimination tree. -function treewidth(stree::SupernodeTree) - maximum(stree.degree) -end - - -# Get the (sorted) supernode at node i. -function supernode(stree::SupernodeTree, i::Integer) - stree.representative[i]:stree.representative[i + 1] - 1 -end - - -# Get the unique node j satisfying i ∈ supernode(j). -function find_supernode(stree::SupernodeTree, i::Integer) - stree.partition[i] -end - - -# Compute the (unsorted) seperators of every node in T. -function seperators(stree::SupernodeTree) - n = treesize(stree.tree) - seperator = Vector{Set{Int}}(undef, n) - - for i in 1:n - 1 - seperator[i] = Set(stree.ancestor[i]) - - for v in outneighbors(stree.graph, stree.representative[i]) - if stree.ancestor[i] < v - push!(seperator[i], v) - end - end - end - - for j in 1:n - 1 - for i in childindices(stree.tree, j) - for v in seperator[i] - if stree.ancestor[j] < v - push!(seperator[j], v) - end - end - end - end - - seperator[n] = Set() - seperator -end From 763552fdb4c14fe051fc500fcc913b4e61b0d052 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Tue, 26 Nov 2024 09:22:43 -0800 Subject: [PATCH 053/100] removed graph from jtree --- src/junction_trees/junction_trees.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 3e84d97..e93244a 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -7,7 +7,6 @@ This type implements the [indexed tree interface](https://juliacollections.githu struct JunctionTree order::Order # elimination order tree::PostorderTree # supernodal elimination tree - graph::OrderedGraph # ordered graph representative::Vector{Int} # vector of representative vertices seperator::Vector{Vector{Int}} # vector of seperators @@ -71,7 +70,7 @@ function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::Supe representative[end] = representative[end - 1] + length(supernode[end]) seperator = map(sort ∘ collect, seperators(graph, tree, representative, ancestor)) - JunctionTree(order, tree, graph, representative, seperator, partition, degree) + JunctionTree(order, tree, representative, seperator, partition, degree) end From aa612fe23199066ce8051e33d66557d81c3984f2 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Tue, 26 Nov 2024 09:47:28 -0800 Subject: [PATCH 054/100] renamed variables --- src/junction_trees/child_indices.jl | 4 ++-- src/junction_trees/trees.jl | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/junction_trees/child_indices.jl b/src/junction_trees/child_indices.jl index be8dc1e..b87be2d 100644 --- a/src/junction_trees/child_indices.jl +++ b/src/junction_trees/child_indices.jl @@ -5,7 +5,7 @@ end function Base.iterate(iterator::ChildIndices) - iterate(iterator, iterator.tree.head[iterator.index]) + iterate(iterator, iterator.tree.child[iterator.index]) end @@ -13,7 +13,7 @@ function Base.iterate(iterator::ChildIndices, i::Integer) if iszero(i) nothing else - i, iterator.tree.next[i] + i, iterator.tree.brother[i] end end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index bc6fca2..d3769f5 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -1,10 +1,10 @@ # A rooted tree. # This type implements the indexed tree interface. struct Tree - parent::Vector{Int} # vector of parents - head::Vector{Int} # vector of first children - next::Vector{Int} # vector of next siblings - root::Int # root + parent::Vector{Int} # vector of parents + child::Vector{Int} # vector of first children + brother::Vector{Int} # vector of brother siblings + root::Int # root end # Construct a tree from a list of parents. @@ -13,20 +13,20 @@ end # ---------------------------------------- function Tree(parent::AbstractVector) n = length(parent) - head = zeros(Int, n) - next = zeros(Int, n) + child = zeros(Int, n) + brother = zeros(Int, n) root = n for i in n:-1:1 if iszero(parent[i]) root = i else - next[i] = head[parent[i]] - head[parent[i]] = i + brother[i] = child[parent[i]] + child[parent[i]] = i end end - Tree(parent, head, next, root) + Tree(parent, child, brother, root) end @@ -58,19 +58,19 @@ function postorder(tree::Tree) push(rootindex(tree)) order = Vector{Int}(undef, n) index = Vector{Int}(undef, n) - head = copy(tree.head) + child = copy(tree.child) count = 1 while !empty() j = pop() - i = head[j] + i = child[j] if iszero(i) order[count] = j index[j] = count count += 1 else - head[j] = tree.next[i] + child[j] = tree.brother[i] push(j) push(i) end @@ -105,7 +105,7 @@ end function AbstractTrees.nextsiblingindex(tree::Tree, i::Integer) - j = tree.next[i] + j = tree.brother[i] if !iszero(j) j From 651884817891b25b5b743f3d0e6d46c45b7553a2 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Wed, 27 Nov 2024 10:58:15 -0800 Subject: [PATCH 055/100] added some docstrings --- src/junction_trees/ordered_graphs.jl | 40 ++++++++++++++++------------ src/junction_trees/trees.jl | 5 ++-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index fbeef24..f2818bb 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,7 +1,7 @@ """ OrderedGraph <: AbstractSimpleGraph{Int} -A directed simple graph whose edges i → j are oriented from lower to higher vertices. +A directed simple graph whose edges ``(i, j)`` satisfy the inequality ``i < j``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractSimpleGraph{Int} @@ -14,18 +14,16 @@ end """ OrderedGraph(graph[, ealg::Union{Order, EliminationAlgorithm}]) -Construct an ordered graph, optionally specifying an elimination algorithm. +Construct an ordered graph by permuting the vertices of a simple graph and directing them from lower to higher. """ function OrderedGraph(graph, ealg::Union{Order, EliminationAlgorithm}=DEFAULT_ELIMINATION_ALGORITHM) OrderedGraph(adjacencymatrix(graph), ealg) end -# Given a graph G, construct the ordered graph -# (G, σ), -# where σ is a permutation computed using an elimination algorithm. +# Construct an ordered graph by permuting the vertices of a simple graph and directing them from lower to higher. # ---------------------------------------- -# graph simple connected graph +# graph simple graph # ealg elimination algorithm # ---------------------------------------- function OrderedGraph(graph::AbstractMatrix, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM) @@ -33,10 +31,9 @@ function OrderedGraph(graph::AbstractMatrix, ealg::EliminationAlgorithm=DEFAULT_ end -# Given a graph H and permutation σ, construct the ordered graph -# (G, σ) +# Construct an ordered graph by permuting the vertices of a simple graph and directing them from lower to higher. # ---------------------------------------- -# graph simple connected graph +# graph simple graph # order vertex order # ---------------------------------------- function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) @@ -45,6 +42,7 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) end +# Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) graph.symmetric end @@ -53,6 +51,9 @@ end # A Compact Row Storage Scheme for Cholesky Factors Using Elimination Trees # Liu # Algorithm 4.2: Elimination Tree by Path Compression. +# ---------------------------------------- +# graph simple connected graph +# ---------------------------------------- function etree(graph::OrderedGraph) n = nv(graph) parent = Vector{Int}(undef, n) @@ -85,6 +86,10 @@ end # An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization # Gilbert, Ng, and Peyton # Figure 3: Implementation of algorithm to compute row and column counts. +# ---------------------------------------- +# graph simple connected graph +# tree elimination tree +# ---------------------------------------- function supcnt(graph::OrderedGraph, tree::Tree) order = postorder(tree) rc, cc = supcnt(OrderedGraph(graph, order), PostorderTree(tree, order)) @@ -95,6 +100,10 @@ end # An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization # Gilbert, Ng, and Peyton # Figure 3: Implementation of algorithm to compute row and column counts. +# ---------------------------------------- +# graph simple connected graph +# tree elimination tree +# ---------------------------------------- function supcnt(graph::OrderedGraph, tree::PostorderTree) n = treesize(tree) @@ -160,20 +169,17 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) end -# Compute higher degree of every vertex in the elimination graph of -# (G, σ). +# Compute higher degree of every vertex in the elimination graph of an ordered graph. +# ---------------------------------------- +# graph simple connected graph +# tree elimination tree +# ---------------------------------------- function outdegrees(graph::OrderedGraph, tree::Tree) rc, cc = supcnt(graph, tree) cc .- 1 end -# Construct a copy of an ordered graph. -function Base.copy(graph::OrderedGraph) - OrderedGraph(graph.symmetric, graph.lower, graph.upper, graph.order) -end - - # Multiline printing. function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) print(io, "ordered graph:\n") diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index d3769f5..ef88a5c 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -2,11 +2,12 @@ # This type implements the indexed tree interface. struct Tree parent::Vector{Int} # vector of parents - child::Vector{Int} # vector of first children - brother::Vector{Int} # vector of brother siblings + child::Vector{Int} # vector of left-children + brother::Vector{Int} # vector of right-siblings root::Int # root end + # Construct a tree from a list of parents. # ---------------------------------------- # parent list of parents From 9c68ef6edfaedf82b2b7b3f4f75e64bcabf5eb95 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Wed, 27 Nov 2024 12:06:35 -0800 Subject: [PATCH 056/100] removed degrees --- src/junction_trees/junction_trees.jl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index e93244a..3a13e1e 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -12,7 +12,6 @@ struct JunctionTree # cache partition::Vector{Int} # supernode partition - degree::Vector{Int} # vector of higher degrees end @@ -49,8 +48,7 @@ end # stree supernodal elimination tree # ---------------------------------------- function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - degree = outdegrees(graph, tree) - partition, supernode, parent, ancestor = stree(tree, degree, stype) + partition, supernode, parent, ancestor = stree(tree, outdegrees(graph, tree), stype) tree = Tree(parent) order = postorder(tree) @@ -61,7 +59,6 @@ function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::Supe order = Order(vcat(supernode...)) graph = OrderedGraph(graph, order) - degree = view(degree, order) partition = view(partition, order) ancestor = view(inv(order), ancestor) @@ -70,7 +67,7 @@ function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::Supe representative[end] = representative[end - 1] + length(supernode[end]) seperator = map(sort ∘ collect, seperators(graph, tree, representative, ancestor)) - JunctionTree(order, tree, representative, seperator, partition, degree) + JunctionTree(order, tree, representative, seperator, partition) end @@ -130,7 +127,8 @@ end Compute the width of a junction tree. """ function treewidth(jtree::JunctionTree) - maximum(jtree.degree) + n = treesize(jtree) + maximum(map(i -> length(residualindices(jtree, i)) + length(seperatorindices(jtree, i)) - 1, 1:n)) end From 7790f63056ce809d2cd6f87413ca1651e4166851 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 2 Dec 2024 12:22:04 -0800 Subject: [PATCH 057/100] temp commit --- src/junction_trees/junction_trees.jl | 2 +- src/junction_trees/ordered_graphs.jl | 11 ----------- src/junction_trees/supernode_types.jl | 14 +++++++------- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 3a13e1e..52e0251 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -48,7 +48,7 @@ end # stree supernodal elimination tree # ---------------------------------------- function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - partition, supernode, parent, ancestor = stree(tree, outdegrees(graph, tree), stype) + partition, supernode, parent, ancestor = stree(tree, last(supcnt(graph, tree)), stype) tree = Tree(parent) order = postorder(tree) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index f2818bb..fb3808a 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -169,17 +169,6 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) end -# Compute higher degree of every vertex in the elimination graph of an ordered graph. -# ---------------------------------------- -# graph simple connected graph -# tree elimination tree -# ---------------------------------------- -function outdegrees(graph::OrderedGraph, tree::Tree) - rc, cc = supcnt(graph, tree) - cc .- 1 -end - - # Multiline printing. function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) print(io, "ordered graph:\n") diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index c0631a2..74b6ebd 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -36,7 +36,7 @@ struct Fundamental <: SupernodeType end # Compact Clique Tree Data Structures in Sparse Matrix Factorizations # Pothen and Sun # Figure 4: The Clique Tree Algorithm 2 -function stree(tree::Tree, degree::AbstractVector, stype::SupernodeType) +function stree(tree::Tree, colcount::AbstractVector, stype::SupernodeType) n = treesize(tree) new_in_clique = Vector{Int}(undef, n) new = Vector{Int}[] @@ -46,7 +46,7 @@ function stree(tree::Tree, degree::AbstractVector, stype::SupernodeType) i = 0 for v in 1:n - u = child_in_supernode(tree, degree, stype, v) + u = child_in_supernode(tree, colcount, stype, v) if !isnothing(u) new_in_clique[v] = new_in_clique[u] @@ -72,16 +72,16 @@ end # Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. -function child_in_supernode(tree::Tree, degree::AbstractVector, stype::Node, v::Integer) end +function child_in_supernode(tree::Tree, colcount::AbstractVector, stype::Node, v::Integer) end # Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. -function child_in_supernode(tree::Tree, degree::AbstractVector, stype::Maximal, v::Integer) +function child_in_supernode(tree::Tree, colcount::AbstractVector, stype::Maximal, v::Integer) u = nothing for w in childindices(tree, v) - if degree[w] == degree[v] + 1 + if colcount[w] == colcount[v] + 1 u = w break end @@ -93,11 +93,11 @@ end # Find a child w of v such that v ∈ supernode(w). # If no such child exists, return nothing. -function child_in_supernode(tree::Tree, degree::AbstractVector, stype::Fundamental, v::Integer) +function child_in_supernode(tree::Tree, colcount::AbstractVector, stype::Fundamental, v::Integer) u = nothing for w in childindices(tree, v) - if isnothing(u) && degree[w] == degree[v] + 1 + if isnothing(u) && colcount[w] == colcount[v] + 1 u = w else u = nothing From a6fa24e9214e82202f750f374dac4b230187025c Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 2 Dec 2024 13:01:34 -0800 Subject: [PATCH 058/100] temp commit --- src/junction_trees/junction_trees.jl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 52e0251..cca04d1 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -8,7 +8,7 @@ struct JunctionTree order::Order # elimination order tree::PostorderTree # supernodal elimination tree representative::Vector{Int} # vector of representative vertices - seperator::Vector{Vector{Int}} # vector of seperators + seperator::SparseMatrixCSC{Bool, Int} # cache partition::Vector{Int} # supernode partition @@ -66,7 +66,12 @@ function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::Supe representative[1:end - 1] .= view(inv(order), map(first, supernode)) representative[end] = representative[end - 1] + length(supernode[end]) - seperator = map(sort ∘ collect, seperators(graph, tree, representative, ancestor)) + seperator = seperators(graph, tree, representative, ancestor) + colptr = accumulate(+, [0, map(length, seperator)...]) .+ 1 + rowval = reduce(vcat, map(sort ∘ collect, seperator)) + nzval = ones(Bool, length(rowval)) + seperator = SparseMatrixCSC(nv(graph), treesize(tree), colptr, rowval, nzval) + JunctionTree(order, tree, representative, seperator, partition) end @@ -139,7 +144,7 @@ end function seperatorindices(jtree::JunctionTree, i::Integer) - jtree.seperator[i] + view(rowvals(jtree.seperator), nzrange(jtree.seperator, i)) end From 695a422734bbba49d00bce12aff095f45e6c2e05 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 18:13:18 -0500 Subject: [PATCH 059/100] temp commit --- src/JunctionTrees.jl | 1 + src/junction_trees/abstract_ordered_graphs.jl | 23 +++++++++++++ src/junction_trees/filled_graphs.jl | 34 +++++++++++++++++++ .../ordered_graph_homomorphisms.jl | 6 ++++ src/junction_trees/ordered_graphs.jl | 21 ++---------- src/junction_trees/orders.jl | 6 +--- 6 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 src/junction_trees/abstract_ordered_graphs.jl create mode 100644 src/junction_trees/filled_graphs.jl create mode 100644 src/junction_trees/ordered_graph_homomorphisms.jl diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 320b619..290fa09 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -43,6 +43,7 @@ include("junction_trees/elimination_algorithms.jl") include("junction_trees/trees.jl") include("junction_trees/child_indices.jl") include("junction_trees/postorder_trees.jl") +include("junction_trees/abstract_ordered_graphs.jl") include("junction_trees/ordered_graphs.jl") include("junction_trees/supernode_types.jl") include("junction_trees/junction_trees.jl") diff --git a/src/junction_trees/abstract_ordered_graphs.jl b/src/junction_trees/abstract_ordered_graphs.jl new file mode 100644 index 0000000..88ffbad --- /dev/null +++ b/src/junction_trees/abstract_ordered_graphs.jl @@ -0,0 +1,23 @@ +abstract type AbstractOrderedGraph <: AbstractSimpleGraph{Int} end + + +############################ +# Abstract Graph Interface # +############################ + + +function SimpleGraphs.is_directed(::Type{AbstractOrderedGraph}) + true +end + + +function SimpleGraphs.edgetype(graph::AbstractOrderedGraph) + SimpleEdge{Int} +end + + +function SimpleGraphs.has_edge(graph::AbstractOrderedGraph, edge::SimpleEdge{Int}) + i = src(edge) + j = dst(edge) + i < j && insorted(j, outneighbors(graph, i)) +end diff --git a/src/junction_trees/filled_graphs.jl b/src/junction_trees/filled_graphs.jl new file mode 100644 index 0000000..dd2ff0f --- /dev/null +++ b/src/junction_trees/filled_graphs.jl @@ -0,0 +1,34 @@ +struct FilledGraph <: AbstractSimpleGraph{Int} + lower::SparseMatrixCSC{Bool, Int} + tree::PostorderTree +end + + +############################ +# Abstract Graph Interface # +############################ + + +function SimpleGraphs.ne(graph::OrderedGraph) + last(graph.lower.colptr) - 1 +end + + +function SimpleGraphs.nv(graph::OrderedGraph) + size(graph.lower, 1) +end + + +function SimpleGraphs.badj(graph::OrderedGraph, i::Integer) + view(rowvals(graph.upper), nzrange(graph.upper, i)) +end + + +function SimpleGraphs.fadj(graph::OrderedGraph, i::Integer) + view(rowvals(graph.lower), nzrange(graph.lower, i)) +end + + +function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) + view(rowvals(graph.symmetric), nzrange(graph.symmetric, i)) +end diff --git a/src/junction_trees/ordered_graph_homomorphisms.jl b/src/junction_trees/ordered_graph_homomorphisms.jl new file mode 100644 index 0000000..073350a --- /dev/null +++ b/src/junction_trees/ordered_graph_homomorphisms.jl @@ -0,0 +1,6 @@ +struct OrderedGraphHomomorphism{Domain, Codomain} + domain::Domain + codomain::Codomain + map::Vector{Int} + index::Vector{Int} +end diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index fb3808a..5309865 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -1,10 +1,10 @@ """ - OrderedGraph <: AbstractSimpleGraph{Int} + OrderedGraph <: AbstractOrderedGraph A directed simple graph whose edges ``(i, j)`` satisfy the inequality ``i < j``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ -struct OrderedGraph <: AbstractSimpleGraph{Int} +struct OrderedGraph <: AbstractOrderedGraph symmetric::SparseMatrixCSC{Bool, Int} # adjacency matrix (symmetric) lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) @@ -181,16 +181,6 @@ end ############################ -function SimpleGraphs.is_directed(::Type{OrderedGraph}) - true -end - - -function SimpleGraphs.edgetype(graph::OrderedGraph) - SimpleEdge{Int} -end - - function SimpleGraphs.ne(graph::OrderedGraph) last(graph.lower.colptr) - 1 end @@ -214,10 +204,3 @@ end function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) view(rowvals(graph.symmetric), nzrange(graph.symmetric, i)) end - - -function SimpleGraphs.has_edge(graph::OrderedGraph, edge::SimpleEdge{Int}) - i = src(edge) - j = dst(edge) - i < j && insorted(j, outneighbors(graph, i)) -end diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 26d8fe7..2c2fd50 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -18,11 +18,7 @@ Construct a permutation ``\\sigma`` from a sequence ``(\\sigma(1), \\dots, \\sig function Order(order::AbstractVector) n = length(order) index = Vector{Int}(undef, n) - - for i in 1:n - index[order[i]] = i - end - + index[order] = 1:n Order(order, index) end From 61df45610df83cc2750cc5a947541a0f8c531af2 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 18:42:33 -0500 Subject: [PATCH 060/100] performance improvement --- src/junction_trees/ordered_graphs.jl | 35 +++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 5309865..d49f202 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -5,9 +5,8 @@ A directed simple graph whose edges ``(i, j)`` satisfy the inequality ``i < j``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractOrderedGraph - symmetric::SparseMatrixCSC{Bool, Int} # adjacency matrix (symmetric) - lower::SparseMatrixCSC{Bool, Int} # adjacency matrix (lower triangular) - upper::SparseMatrixCSC{Bool, Int} # adjacency matrix (upper triangular) + matrix::SparseMatrixCSC{Bool, Int} # adjacency matrix (symmetric) + colptr::Vector{Int} end @@ -37,14 +36,26 @@ end # order vertex order # ---------------------------------------- function OrderedGraph(graph::AbstractSparseMatrixCSC, order::Order) - graph = permute(graph, order, order) - OrderedGraph(graph, tril(graph), triu(graph)) + OrderedGraph(permute(graph, order, order)) end +function OrderedGraph(graph::AbstractSparseMatrixCSC) + n = size(graph, 1) + colptr = Vector{Int}(undef, n) + + for i in 1:n + colptr[i] = graph.colptr[i] + searchsortedfirst(view(rowvals(graph), nzrange(graph, i)), i) - 1 + end + + OrderedGraph(graph, colptr) +end + + + # Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) - graph.symmetric + graph.matrix end @@ -172,7 +183,7 @@ end # Multiline printing. function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) print(io, "ordered graph:\n") - SparseArrays._show_with_braille_patterns(io, graph.lower) + SparseArrays._show_with_braille_patterns(io, graph.matrix) end @@ -181,26 +192,28 @@ end ############################ +#= function SimpleGraphs.ne(graph::OrderedGraph) last(graph.lower.colptr) - 1 end +=# function SimpleGraphs.nv(graph::OrderedGraph) - size(graph.lower, 1) + length(graph.colptr) end function SimpleGraphs.badj(graph::OrderedGraph, i::Integer) - view(rowvals(graph.upper), nzrange(graph.upper, i)) + view(rowvals(graph.matrix), graph.matrix.colptr[i]:graph.colptr[i] - 1) end function SimpleGraphs.fadj(graph::OrderedGraph, i::Integer) - view(rowvals(graph.lower), nzrange(graph.lower, i)) + view(rowvals(graph.matrix), graph.colptr[i]:graph.matrix.colptr[i + 1] - 1) end function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) - view(rowvals(graph.symmetric), nzrange(graph.symmetric, i)) + view(rowvals(graph.matrix), nzrange(graph.matrix, i)) end From d96bad723170b628c7212575d3d15dd4ffd2a7e7 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 18:56:56 -0500 Subject: [PATCH 061/100] fiddled with internals --- src/junction_trees/ordered_graphs.jl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index d49f202..48b16c6 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -5,8 +5,9 @@ A directed simple graph whose edges ``(i, j)`` satisfy the inequality ``i < j``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractOrderedGraph - matrix::SparseMatrixCSC{Bool, Int} # adjacency matrix (symmetric) colptr::Vector{Int} + adjptr::Vector{Int} + rowval::Vector{Int} end @@ -48,14 +49,14 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC) colptr[i] = graph.colptr[i] + searchsortedfirst(view(rowvals(graph), nzrange(graph, i)), i) - 1 end - OrderedGraph(graph, colptr) + OrderedGraph(colptr, graph.colptr, graph.rowval) end # Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) - graph.matrix + SparseMatrixCSC(nv(graph), nv(graph), graph.adjptr, graph.rowval, ones(Bool, length(graph.rowval))) end @@ -183,7 +184,7 @@ end # Multiline printing. function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) print(io, "ordered graph:\n") - SparseArrays._show_with_braille_patterns(io, graph.matrix) + SparseArrays._show_with_braille_patterns(io, adjacencymatrix(graph)) end @@ -205,15 +206,15 @@ end function SimpleGraphs.badj(graph::OrderedGraph, i::Integer) - view(rowvals(graph.matrix), graph.matrix.colptr[i]:graph.colptr[i] - 1) + view(graph.rowval, graph.adjptr[i]:graph.colptr[i] - 1) end function SimpleGraphs.fadj(graph::OrderedGraph, i::Integer) - view(rowvals(graph.matrix), graph.colptr[i]:graph.matrix.colptr[i + 1] - 1) + view(graph.rowval, graph.colptr[i]:graph.adjptr[i + 1] - 1) end function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) - view(rowvals(graph.matrix), nzrange(graph.matrix, i)) + view(graph.rowval, graph.adjptr[i]:graph.adjptr[i + 1] - 1) end From be4bb49579e545eb5e54709e0f4851c4fb9357d1 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 19:08:36 -0500 Subject: [PATCH 062/100] removed function fdesc --- src/junction_trees/filled_graphs.jl | 15 ++++++++++----- src/junction_trees/ordered_graphs.jl | 2 +- src/junction_trees/postorder_trees.jl | 5 ++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/junction_trees/filled_graphs.jl b/src/junction_trees/filled_graphs.jl index dd2ff0f..9e15c95 100644 --- a/src/junction_trees/filled_graphs.jl +++ b/src/junction_trees/filled_graphs.jl @@ -1,5 +1,6 @@ struct FilledGraph <: AbstractSimpleGraph{Int} - lower::SparseMatrixCSC{Bool, Int} + colptr::Vector{Int} + rowval::Vector{Int} tree::PostorderTree end @@ -9,26 +10,30 @@ end ############################ +#= function SimpleGraphs.ne(graph::OrderedGraph) last(graph.lower.colptr) - 1 end +=# function SimpleGraphs.nv(graph::OrderedGraph) - size(graph.lower, 1) + length(graph.colptr) end function SimpleGraphs.badj(graph::OrderedGraph, i::Integer) - view(rowvals(graph.upper), nzrange(graph.upper, i)) + descendantindices(graph.tree, i) end function SimpleGraphs.fadj(graph::OrderedGraph, i::Integer) - view(rowvals(graph.lower), nzrange(graph.lower, i)) + view(graph.rowval, graph.colptr[i]:graph.colptr[i + 1] - 1) end +#= function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) - view(rowvals(graph.symmetric), nzrange(graph.symmetric, i)) + view(graph.rowval, graph.adjptr[i]:graph.adjptr[i + 1] - 1) end +=# diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 48b16c6..945f6b1 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -150,7 +150,7 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) wt[parentindex(tree, p)] -= 1 for u in outneighbors(graph, p) - if fdesc(tree, p) > prev_nbr[u] + if first(descendantindices(tree, p)) > prev_nbr[u] wt[p] += 1 pp = prev_p[u] diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index e3442ad..6ca6492 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -56,9 +56,8 @@ function level(tree::PostorderTree, i::Integer) end -# Get the first descendant of a node i. -function fdesc(tree::PostorderTree, i::Integer) - tree.fdesc[i] +function descendantindices(tree::PostorderTree, i::Integer) + tree.fdesc[i]:i - 1 end From b5de2d9e90015e3ee33dd390df88702a68392539 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 19:13:32 -0500 Subject: [PATCH 063/100] fixed ne calculation --- src/junction_trees/filled_graphs.jl | 12 +++++------- src/junction_trees/ordered_graphs.jl | 4 +--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/junction_trees/filled_graphs.jl b/src/junction_trees/filled_graphs.jl index 9e15c95..758e638 100644 --- a/src/junction_trees/filled_graphs.jl +++ b/src/junction_trees/filled_graphs.jl @@ -10,24 +10,22 @@ end ############################ -#= -function SimpleGraphs.ne(graph::OrderedGraph) - last(graph.lower.colptr) - 1 +function SimpleGraphs.ne(graph::FilledGraph) + last(graph.colptr) - 1 end -=# -function SimpleGraphs.nv(graph::OrderedGraph) +function SimpleGraphs.nv(graph::FilledGraph) length(graph.colptr) end -function SimpleGraphs.badj(graph::OrderedGraph, i::Integer) +function SimpleGraphs.badj(graph::FilledGraph, i::Integer) descendantindices(graph.tree, i) end -function SimpleGraphs.fadj(graph::OrderedGraph, i::Integer) +function SimpleGraphs.fadj(graph::FilledGraph, i::Integer) view(graph.rowval, graph.colptr[i]:graph.colptr[i + 1] - 1) end diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 945f6b1..d14fc27 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -193,11 +193,9 @@ end ############################ -#= function SimpleGraphs.ne(graph::OrderedGraph) - last(graph.lower.colptr) - 1 + (last(graph.adjptr) - 1) ÷ 2 end -=# function SimpleGraphs.nv(graph::OrderedGraph) From b61b0c248a9c9b8d23c17c1204204513a3212bd2 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 19:31:05 -0500 Subject: [PATCH 064/100] changed types --- src/junction_trees/filled_graphs.jl | 2 +- src/junction_trees/ordered_graph_homomorphisms.jl | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/junction_trees/filled_graphs.jl b/src/junction_trees/filled_graphs.jl index 758e638..7361628 100644 --- a/src/junction_trees/filled_graphs.jl +++ b/src/junction_trees/filled_graphs.jl @@ -1,4 +1,4 @@ -struct FilledGraph <: AbstractSimpleGraph{Int} +struct FilledGraph <: AbstractOrderedGraph colptr::Vector{Int} rowval::Vector{Int} tree::PostorderTree diff --git a/src/junction_trees/ordered_graph_homomorphisms.jl b/src/junction_trees/ordered_graph_homomorphisms.jl index 073350a..5af9484 100644 --- a/src/junction_trees/ordered_graph_homomorphisms.jl +++ b/src/junction_trees/ordered_graph_homomorphisms.jl @@ -1,6 +1,12 @@ -struct OrderedGraphHomomorphism{Domain, Codomain} - domain::Domain - codomain::Codomain - map::Vector{Int} +struct OrderedGraphHomomorphism{Source <: AbstractOrderedGraph, Target <: AbstractOrderedGraph} + source::Source + target::Target + mapping::Vector{Int} index::Vector{Int} end + + +struct JunctionTree + order::Order + homomorphism::OrderedGraphHomomorphism{OrderedGraph, FilledGraph} +end From 97b78397d65bd8a094c5445a42ed49fcaac02d14 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 19:47:59 -0500 Subject: [PATCH 065/100] printing --- src/junction_trees/abstract_ordered_graphs.jl | 8 ++++++++ src/junction_trees/filled_graphs.jl | 6 ++++++ src/junction_trees/ordered_graphs.jl | 5 ----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/junction_trees/abstract_ordered_graphs.jl b/src/junction_trees/abstract_ordered_graphs.jl index 88ffbad..c37788c 100644 --- a/src/junction_trees/abstract_ordered_graphs.jl +++ b/src/junction_trees/abstract_ordered_graphs.jl @@ -21,3 +21,11 @@ function SimpleGraphs.has_edge(graph::AbstractOrderedGraph, edge::SimpleEdge{Int j = dst(edge) i < j && insorted(j, outneighbors(graph, i)) end + + +# Multiline printing. +function Base.show(io::IO, ::MIME"text/plain", graph::AbstractOrderedGraph) + print(io, "ordered graph:\n") + SparseArrays._show_with_braille_patterns(io, adjacencymatrix(graph)) +end + diff --git a/src/junction_trees/filled_graphs.jl b/src/junction_trees/filled_graphs.jl index 7361628..6ecb937 100644 --- a/src/junction_trees/filled_graphs.jl +++ b/src/junction_trees/filled_graphs.jl @@ -5,6 +5,12 @@ struct FilledGraph <: AbstractOrderedGraph end +function adjacencymatrix(graph::FilledGraph) + lower = SparseMatrixCSC(nv(graph), nv(graph), graph.colptr, graph.rowval, ones(Bool, ne(graph))) + lower .|| lower' +end + + ############################ # Abstract Graph Interface # ############################ diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index d14fc27..c7e8323 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -181,11 +181,6 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) end -# Multiline printing. -function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) - print(io, "ordered graph:\n") - SparseArrays._show_with_braille_patterns(io, adjacencymatrix(graph)) -end ############################ From 772162b5008f832388c90ee43a261ea6f968b3e1 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 20:16:51 -0500 Subject: [PATCH 066/100] order setindex --- src/junction_trees/elimination_algorithms.jl | 11 ++++------- src/junction_trees/orders.jl | 13 ++++++++++++- src/junction_trees/trees.jl | 6 ++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index 5b8b5de..fb0f616 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -109,8 +109,7 @@ end # Construct an order using the maximum cardinality search algorithm. function Order(graph::AbstractMatrix, ealg::MCS) - order, index = mcs(graph) - Order(order, index) + mcs(graph) end @@ -150,8 +149,7 @@ end # Maximum Cardinality Search function mcs(graph::AbstractSparseMatrixCSC) n = size(graph, 1) - α = Vector{Int}(undef, n) - β = Vector{Int}(undef, n) + α = Order(undef, n) len = Vector{Int}(undef, n) set = Vector{LinkedLists.LinkedList{Int}}(undef, n) pointer = Vector{LinkedLists.ListNode{Int}}(undef, n) @@ -168,8 +166,7 @@ function mcs(graph::AbstractSparseMatrixCSC) while i >= 1 v = first(set[j]) deleteat!(set[j], pointer[v]) - α[v] = i - β[i] = v + α[i] = v len[v] = 0 for w in view(rowvals(graph), nzrange(graph, v)) @@ -188,7 +185,7 @@ function mcs(graph::AbstractSparseMatrixCSC) end end - β, α + α end diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index 2c2fd50..a6fb978 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -23,6 +23,11 @@ function Order(order::AbstractVector) end +function Order(::UndefInitializer, n::Integer) + Order(Vector{Int}(undef, n), Vector{Int}(undef, n)) +end + + # Compose two permutations. function compose(left::Order, right::Order) Order(right.order[left.order], left.index[right.index]) @@ -50,11 +55,17 @@ end ############################# -function Base.getindex(order::Order, i) +function Base.getindex(order::Order, i::Integer) order.order[i] end +function Base.setindex!(order::Order, v::Integer, i::Integer) + order.index[v] = i + order.order[i] = v +end + + function Base.IndexStyle(::Type{Order}) IndexLinear() end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index ef88a5c..58d9745 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -57,8 +57,7 @@ function postorder(tree::Tree) ############### push(rootindex(tree)) - order = Vector{Int}(undef, n) - index = Vector{Int}(undef, n) + order = Order(undef, n) child = copy(tree.child) count = 1 @@ -68,7 +67,6 @@ function postorder(tree::Tree) if iszero(i) order[count] = j - index[j] = count count += 1 else child[j] = tree.brother[i] @@ -77,7 +75,7 @@ function postorder(tree::Tree) end end - Order(order, index) + order end From 4808c7790be19b824d6c7f582e1d8c211bec176f Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Thu, 5 Dec 2024 22:17:45 -0500 Subject: [PATCH 067/100] temp commit --- src/JunctionTrees.jl | 2 + src/junction_trees/filled_graphs.jl | 2 +- src/junction_trees/junction_trees.jl | 81 +++++++++++++++++-- .../ordered_graph_homomorphisms.jl | 8 +- src/junction_trees/ordered_graphs.jl | 6 +- src/junction_trees/orders.jl | 4 +- src/junction_trees/supernode_types.jl | 13 ++- 7 files changed, 92 insertions(+), 24 deletions(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 290fa09..1abcc44 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -45,6 +45,8 @@ include("junction_trees/child_indices.jl") include("junction_trees/postorder_trees.jl") include("junction_trees/abstract_ordered_graphs.jl") include("junction_trees/ordered_graphs.jl") +include("junction_trees/filled_graphs.jl") +include("junction_trees/ordered_graph_homomorphisms.jl") include("junction_trees/supernode_types.jl") include("junction_trees/junction_trees.jl") diff --git a/src/junction_trees/filled_graphs.jl b/src/junction_trees/filled_graphs.jl index 6ecb937..b62108c 100644 --- a/src/junction_trees/filled_graphs.jl +++ b/src/junction_trees/filled_graphs.jl @@ -22,7 +22,7 @@ end function SimpleGraphs.nv(graph::FilledGraph) - length(graph.colptr) + length(graph.colptr) - 1 end diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index cca04d1..8dd33f2 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -1,3 +1,4 @@ +#= """ JunctionTree @@ -104,6 +105,67 @@ function seperators(graph::OrderedGraph, tree::PostorderTree, representative::Ab seperator[n] = Set() seperator end +=# + + +struct JunctionTree + order::Order + homomorphism::OrderedGraphHomomorphism{OrderedGraph, FilledGraph} +end + + +function JunctionTree(graph, ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) + JunctionTree(graph, Order(graph, ealg), stype) +end + + +function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) + source = OrderedGraph(graph, order) + supernode, tree = stree(source, stype) + + postorder = Order(undef, nv(source)) + mapping = Vector{Int}(undef, nv(source)) + indptr = Vector{Int}(undef, treesize(tree) + 1) + indptr[1] = 1 + + for (i, S) in enumerate(supernode) + indptr[i + 1] = indptr[i] + length(S) + mapping[indptr[i]:indptr[i + 1] - 1] .= i + postorder[indptr[i]:indptr[i + 1] - 1] = S + end + + order = compose(postorder, order) + source = OrderedGraph(source, postorder) + + rowval = Int[] + colptr = Vector{Int}(undef, treesize(tree) + 1) + colptr[1] = 1 + + for j in 1:treesize(tree) + column = Set{Int}() + + for k in view(mapping, outneighbors(source, indptr[j])) + if j < k + push!(column, k) + end + end + + for i in childindices(tree, j) + for k in view(rowval, colptr[i]:colptr[i + 1] - 1) + if j < k + push!(column, k) + end + end + end + + append!(rowval, sort(collect(column))) + colptr[j + 1] = colptr[j] + length(column) + end + + target = FilledGraph(colptr, rowval, tree) + homomorphism = OrderedGraphHomomorphism(source, target, mapping, indptr) + JunctionTree(order, homomorphism) +end """ @@ -137,14 +199,15 @@ function treewidth(jtree::JunctionTree) end -# Get the (sorted) supernode at node i. function residualindices(jtree::JunctionTree, i::Integer) - jtree.representative[i]:jtree.representative[i + 1] - 1 + jtree.homomorphism.indptr[i]:jtree.homomorphism.indptr[i + 1] - 1 end function seperatorindices(jtree::JunctionTree, i::Integer) - view(rowvals(jtree.seperator), nzrange(jtree.seperator, i)) + mapreduce(vcat, outneighbors(jtree.homomorphism.target, i); init=Int[]) do j + jtree.homomorphism.indptr[j]:jtree.homomorphism.indptr[j + 1] - 1 + end end @@ -168,6 +231,7 @@ function residual(jtree::JunctionTree, i::Integer) end +#= """ find_clique(jtree::JunctionTree, v::Integer) @@ -186,6 +250,7 @@ Find a node `i` satisfying `vertices ⊆ clique(jtree, i)`. function find_clique(jtree::JunctionTree, vertices::AbstractVector) jtree.partition[minimum(view(jtree.order, vertices))] end +=# # Multiline printing. @@ -254,27 +319,27 @@ end function AbstractTrees.treesize(jtree::JunctionTree) - treesize(jtree.tree) + treesize(jtree.homomorphism.target.tree) end function AbstractTrees.treeheight(jtree::JunctionTree) - treeheight(jtree.tree) + treeheight(jtree.homomorphism.target.tree) end function AbstractTrees.rootindex(jtree::JunctionTree) - rootindex(jtree.tree) + rootindex(jtree.homomorphism.target.tree) end function AbstractTrees.parentindex(jtree::JunctionTree, i::Integer) - parentindex(jtree.tree, i) + parentindex(jtree.homomorphism.target.tree, i) end function AbstractTrees.childindices(jtree::JunctionTree, i::Integer) - childindices(jtree.tree, i) + childindices(jtree.homomorphism.target.tree, i) end diff --git a/src/junction_trees/ordered_graph_homomorphisms.jl b/src/junction_trees/ordered_graph_homomorphisms.jl index 5af9484..d31782c 100644 --- a/src/junction_trees/ordered_graph_homomorphisms.jl +++ b/src/junction_trees/ordered_graph_homomorphisms.jl @@ -2,11 +2,5 @@ struct OrderedGraphHomomorphism{Source <: AbstractOrderedGraph, Target <: Abstra source::Source target::Target mapping::Vector{Int} - index::Vector{Int} -end - - -struct JunctionTree - order::Order - homomorphism::OrderedGraphHomomorphism{OrderedGraph, FilledGraph} + indptr::Vector{Int} end diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index c7e8323..1171e7a 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -91,7 +91,7 @@ function etree(graph::OrderedGraph) end end - parent + Tree(parent) end @@ -181,8 +181,6 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) end - - ############################ # Abstract Graph Interface # ############################ @@ -194,7 +192,7 @@ end function SimpleGraphs.nv(graph::OrderedGraph) - length(graph.colptr) + length(graph.adjptr) - 1 end diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index a6fb978..f6763ce 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -55,12 +55,12 @@ end ############################# -function Base.getindex(order::Order, i::Integer) +function Base.getindex(order::Order, i) order.order[i] end -function Base.setindex!(order::Order, v::Integer, i::Integer) +function Base.setindex!(order::Order, v, i) order.index[v] = i order.order[i] = v end diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 74b6ebd..ab6ba45 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -36,7 +36,7 @@ struct Fundamental <: SupernodeType end # Compact Clique Tree Data Structures in Sparse Matrix Factorizations # Pothen and Sun # Figure 4: The Clique Tree Algorithm 2 -function stree(tree::Tree, colcount::AbstractVector, stype::SupernodeType) +function cta(tree::Tree, colcount::AbstractVector, stype::SupernodeType) n = treesize(tree) new_in_clique = Vector{Int}(undef, n) new = Vector{Int}[] @@ -66,7 +66,16 @@ function stree(tree::Tree, colcount::AbstractVector, stype::SupernodeType) end end - new_in_clique, new, parent, first_anc + new, Tree(parent) +end + + +function stree(graph::OrderedGraph, stype::SupernodeType) + tree = etree(graph) + rowcount, colcount = supcnt(graph, tree) + supernode, tree = cta(tree, colcount, stype) + order = postorder(tree) + view(supernode, order), PostorderTree(tree, order) end From 0243076827858ad8ede51a9de97e826d00d8f040 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 6 Dec 2024 00:17:22 -0500 Subject: [PATCH 068/100] tests passing --- src/junction_trees/junction_trees.jl | 81 +++++++++++++++------------ test/.JunctionTrees.jl.swp | Bin 0 -> 16384 bytes 2 files changed, 45 insertions(+), 36 deletions(-) create mode 100644 test/.JunctionTrees.jl.swp diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 8dd33f2..2a491e0 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -110,7 +110,19 @@ end struct JunctionTree order::Order - homomorphism::OrderedGraphHomomorphism{OrderedGraph, FilledGraph} + tree::PostorderTree + partition::Vector{Int} + + # supernodes + sndptr::Vector{Int} + + # seperators + sepptr::Vector{Int} + sepval::Vector{Int} + + # seperator → supernode + #relptr::Vector{Int} + #relval::Vector{Int} end @@ -120,51 +132,50 @@ end function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - source = OrderedGraph(graph, order) - supernode, tree = stree(source, stype) + graph = OrderedGraph(graph, order) + supernode, tree = stree(graph, stype) - postorder = Order(undef, nv(source)) - mapping = Vector{Int}(undef, nv(source)) - indptr = Vector{Int}(undef, treesize(tree) + 1) - indptr[1] = 1 - - for (i, S) in enumerate(supernode) - indptr[i + 1] = indptr[i] + length(S) - mapping[indptr[i]:indptr[i + 1] - 1] .= i - postorder[indptr[i]:indptr[i + 1] - 1] = S + postorder = Order(undef, nv(graph)) + partition = Vector{Int}(undef, nv(graph)) + sndptr = Vector{Int}(undef, treesize(tree) + 1) + sndptr[1] = 1 + + for (i, snd) in enumerate(supernode) + sndptr[i + 1] = sndptr[i] + length(snd) + partition[sndptr[i]:sndptr[i + 1] - 1] .= i + postorder[sndptr[i]:sndptr[i + 1] - 1] = snd end order = compose(postorder, order) - source = OrderedGraph(source, postorder) + graph = OrderedGraph(graph, postorder) - rowval = Int[] - colptr = Vector{Int}(undef, treesize(tree) + 1) - colptr[1] = 1 + sepval = Int[] + sepptr = Vector{Int}(undef, treesize(tree) + 1) + sepptr[1] = 1 for j in 1:treesize(tree) + u = sndptr[j + 1] - 1 column = Set{Int}() - for k in view(mapping, outneighbors(source, indptr[j])) - if j < k - push!(column, k) + for v in outneighbors(graph, sndptr[j]) + if u < v + push!(column, v) end end for i in childindices(tree, j) - for k in view(rowval, colptr[i]:colptr[i + 1] - 1) - if j < k - push!(column, k) + for v in view(sepval, sepptr[i]:sepptr[i + 1] - 1) + if u < v + push!(column, v) end end end - append!(rowval, sort(collect(column))) - colptr[j + 1] = colptr[j] + length(column) + append!(sepval, sort(collect(column))) + sepptr[j + 1] = sepptr[j] + length(column) end - target = FilledGraph(colptr, rowval, tree) - homomorphism = OrderedGraphHomomorphism(source, target, mapping, indptr) - JunctionTree(order, homomorphism) + JunctionTree(order, tree, partition, sndptr, sepptr, sepval) end @@ -200,14 +211,12 @@ end function residualindices(jtree::JunctionTree, i::Integer) - jtree.homomorphism.indptr[i]:jtree.homomorphism.indptr[i + 1] - 1 + jtree.sndptr[i]:jtree.sndptr[i + 1] - 1 end function seperatorindices(jtree::JunctionTree, i::Integer) - mapreduce(vcat, outneighbors(jtree.homomorphism.target, i); init=Int[]) do j - jtree.homomorphism.indptr[j]:jtree.homomorphism.indptr[j + 1] - 1 - end + view(jtree.sepval, jtree.sepptr[i]:jtree.sepptr[i + 1] - 1) end @@ -319,27 +328,27 @@ end function AbstractTrees.treesize(jtree::JunctionTree) - treesize(jtree.homomorphism.target.tree) + treesize(jtree.tree) end function AbstractTrees.treeheight(jtree::JunctionTree) - treeheight(jtree.homomorphism.target.tree) + treeheight(jtree.tree) end function AbstractTrees.rootindex(jtree::JunctionTree) - rootindex(jtree.homomorphism.target.tree) + rootindex(jtree.tree) end function AbstractTrees.parentindex(jtree::JunctionTree, i::Integer) - parentindex(jtree.homomorphism.target.tree, i) + parentindex(jtree.tree, i) end function AbstractTrees.childindices(jtree::JunctionTree, i::Integer) - childindices(jtree.homomorphism.target.tree, i) + childindices(jtree.tree, i) end diff --git a/test/.JunctionTrees.jl.swp b/test/.JunctionTrees.jl.swp new file mode 100644 index 0000000000000000000000000000000000000000..72ae74b4dd76c5e896ebd079d9f2dd4dc3a60d0a GIT binary patch literal 16384 zcmeI2du$v>9ml5u+7wz^Q680os!0xnEnRG{?ZmOGRM?K1Cg7CDZmP<1qV?V8ZtZ(@ zcin^lNdz=VAY36@l|NGPN1_rcgo1?B@JDz`MU_CPywp-?1qhI63rIX9C6JC`G|80)j zO#D|e>E<#Ias_e)as_e)as_e)as_e)as_e)as_e)as_e){tFdw%R;=BcD*9)@K&1t;Jr+y_3ma4*~i zdte+!!GU+d7T65GeWMW1!%yJ*@GZCi=iwZjhR?z$;iGU2T5u3%U^nc9TVV{YgMVEs z#Gl|-@MCxqF2Lh(8kXTC1W<+pa0iS*5pIEZ!X|iWqY&SNFT*mlU(0+ zXWCBzRDUAt=JT;TCuY+z8jg2Kd_>=wJ9VT!8a% z4n7Z$z=LoSj=&=LP=#Az6TJF*A)bSa@F;u)4#6mlz;@UOe|Vh`KZUQuW3UYO!$H^! zcff8KgN>lZ@{87?m6~(!Ro{`wi0?;^_~oeDv!G6U<<6aQSj6XYr%Zok(o+fCR<$Ub zLD>t6^7f@h*{yqx$gTDC_KJeM-LLSyiX846Wqb!#)UM76Le=|g>)4Qb(ugiL>xnzfo& zih4>_zgG4eWxwQw?S|OCQ$s!Jyhbys`i)9l^A3H35glyr77Xb~a%OJbas%cB_wep9H))CoL^A1P77=}4% zb(Nimow;__+SEcackN(rr=*5EPoEx@40StKJLa}3o0{J{mORc5~}nYI|| zo5r=;dv@3dT{5u|YS?A&S!U`Pi?d?pq^yV;v+crhTDxqA)zf!vE2OMXTEPM~sGUmH zv3;^Rw2fMsZhObtFm;z%hZ&!kByHgqFU!U`BUvM-Yq3^a^(5C~2-# zL6k99svw5hTq%QAz=TPTS!W==TF6f9?gnk8Jc$`IBgxcCYi#}WNZcz)OgD=bw*>`t zA;i-s3<9Ln=h-m11^ z|IozDmDf7uMSe(K`*vMV^^_2NqZ z-(sSwe_sUlADNx@gz<8du*0--Ju=rD&yZPVAM8&uo%vx-_(>|{Cs_vSpLEocER9-( zrcnziw_HBtl`CGj*{tG)i2IRIHvPeR-HZ4ZeYaZP_o(4jkOy2AFpYUHs8l`4xg6&@ z2)zbrlT`+&Ta$7AFixHJ>VDZf>^J<#lXtcvzwRG%)z|5)DwaZ)RdR-R4Rbo_Mm2Z7 z?{1c50gE)Re2*WHWtZ>LqY z>Cs9;M_+ZB@kn&2+Vw?5I>Po#{$(UnLtF zsTWe6<#Jq+9dD$uBTQ|GtnF;fxRh4eFmVR6&P1zt$3~EOvQ9^$?vLy)2rfkHQcOCh z(~+pl8E0amTS~9kiKug>9f>-|6)K$7Z|YVL6K4yy9f@{#jhVi?6n7x~*lqX3`1f$nNe;Z6Iy8Phyc8YRUH4aT cUBsD;&yXO~yj3??l#*+D`UYRi)3;6h2hKy!pa1{> literal 0 HcmV?d00001 From 4dbd44f9feb03d1c5ae924c7d44564f5a633b086 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 6 Dec 2024 00:53:31 -0500 Subject: [PATCH 069/100] tiny performance improvement --- src/junction_trees/junction_trees.jl | 9 ++++++--- src/junction_trees/supernode_types.jl | 4 +--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 2a491e0..e2fc29d 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -133,7 +133,9 @@ end function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) graph = OrderedGraph(graph, order) - supernode, tree = stree(graph, stype) + tree = etree(graph) + rowcount, colcount = supcnt(graph, tree) + supernode, tree = stree(graph, tree, colcount, stype) postorder = Order(undef, nv(graph)) partition = Vector{Int}(undef, nv(graph)) @@ -148,8 +150,9 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD order = compose(postorder, order) graph = OrderedGraph(graph, postorder) + colcount = view(colcount, postorder) - sepval = Int[] + sepval = Vector{Int}(undef, sum(colcount[sndptr[2:end] .- 1])) sepptr = Vector{Int}(undef, treesize(tree) + 1) sepptr[1] = 1 @@ -171,8 +174,8 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD end end - append!(sepval, sort(collect(column))) sepptr[j + 1] = sepptr[j] + length(column) + sepval[sepptr[j]:sepptr[j + 1] - 1] = sort(collect(column)) end JunctionTree(order, tree, partition, sndptr, sepptr, sepval) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index ab6ba45..d19bcf5 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -70,9 +70,7 @@ function cta(tree::Tree, colcount::AbstractVector, stype::SupernodeType) end -function stree(graph::OrderedGraph, stype::SupernodeType) - tree = etree(graph) - rowcount, colcount = supcnt(graph, tree) +function stree(graph::OrderedGraph, tree::Tree, colcount::AbstractVector, stype::SupernodeType) supernode, tree = cta(tree, colcount, stype) order = postorder(tree) view(supernode, order), PostorderTree(tree, order) From 820345bc944905f836d67b8ca8a7fcea07403ef3 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 6 Dec 2024 00:56:38 -0500 Subject: [PATCH 070/100] deleted swp --- test/.JunctionTrees.jl.swp | Bin 16384 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test/.JunctionTrees.jl.swp diff --git a/test/.JunctionTrees.jl.swp b/test/.JunctionTrees.jl.swp deleted file mode 100644 index 72ae74b4dd76c5e896ebd079d9f2dd4dc3a60d0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI2du$v>9ml5u+7wz^Q680os!0xnEnRG{?ZmOGRM?K1Cg7CDZmP<1qV?V8ZtZ(@ zcin^lNdz=VAY36@l|NGPN1_rcgo1?B@JDz`MU_CPywp-?1qhI63rIX9C6JC`G|80)j zO#D|e>E<#Ias_e)as_e)as_e)as_e)as_e)as_e)as_e){tFdw%R;=BcD*9)@K&1t;Jr+y_3ma4*~i zdte+!!GU+d7T65GeWMW1!%yJ*@GZCi=iwZjhR?z$;iGU2T5u3%U^nc9TVV{YgMVEs z#Gl|-@MCxqF2Lh(8kXTC1W<+pa0iS*5pIEZ!X|iWqY&SNFT*mlU(0+ zXWCBzRDUAt=JT;TCuY+z8jg2Kd_>=wJ9VT!8a% z4n7Z$z=LoSj=&=LP=#Az6TJF*A)bSa@F;u)4#6mlz;@UOe|Vh`KZUQuW3UYO!$H^! zcff8KgN>lZ@{87?m6~(!Ro{`wi0?;^_~oeDv!G6U<<6aQSj6XYr%Zok(o+fCR<$Ub zLD>t6^7f@h*{yqx$gTDC_KJeM-LLSyiX846Wqb!#)UM76Le=|g>)4Qb(ugiL>xnzfo& zih4>_zgG4eWxwQw?S|OCQ$s!Jyhbys`i)9l^A3H35glyr77Xb~a%OJbas%cB_wep9H))CoL^A1P77=}4% zb(Nimow;__+SEcackN(rr=*5EPoEx@40StKJLa}3o0{J{mORc5~}nYI|| zo5r=;dv@3dT{5u|YS?A&S!U`Pi?d?pq^yV;v+crhTDxqA)zf!vE2OMXTEPM~sGUmH zv3;^Rw2fMsZhObtFm;z%hZ&!kByHgqFU!U`BUvM-Yq3^a^(5C~2-# zL6k99svw5hTq%QAz=TPTS!W==TF6f9?gnk8Jc$`IBgxcCYi#}WNZcz)OgD=bw*>`t zA;i-s3<9Ln=h-m11^ z|IozDmDf7uMSe(K`*vMV^^_2NqZ z-(sSwe_sUlADNx@gz<8du*0--Ju=rD&yZPVAM8&uo%vx-_(>|{Cs_vSpLEocER9-( zrcnziw_HBtl`CGj*{tG)i2IRIHvPeR-HZ4ZeYaZP_o(4jkOy2AFpYUHs8l`4xg6&@ z2)zbrlT`+&Ta$7AFixHJ>VDZf>^J<#lXtcvzwRG%)z|5)DwaZ)RdR-R4Rbo_Mm2Z7 z?{1c50gE)Re2*WHWtZ>LqY z>Cs9;M_+ZB@kn&2+Vw?5I>Po#{$(UnLtF zsTWe6<#Jq+9dD$uBTQ|GtnF;fxRh4eFmVR6&P1zt$3~EOvQ9^$?vLy)2rfkHQcOCh z(~+pl8E0amTS~9kiKug>9f>-|6)K$7Z|YVL6K4yy9f@{#jhVi?6n7x~*lqX3`1f$nNe;Z6Iy8Phyc8YRUH4aT cUBsD;&yXO~yj3??l#*+D`UYRi)3;6h2hKy!pa1{> From 8d6e526956e4efc4c05b8027c4f3117669160c22 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 6 Dec 2024 01:01:39 -0500 Subject: [PATCH 071/100] fixed math --- src/junction_trees/junction_trees.jl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index e2fc29d..2ecd00c 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -113,14 +113,14 @@ struct JunctionTree tree::PostorderTree partition::Vector{Int} - # supernodes + # supernode(i) sndptr::Vector{Int} - # seperators + # seperator(i) sepptr::Vector{Int} sepval::Vector{Int} - # seperator → supernode + # seperator(i) → clique(parent(i)) #relptr::Vector{Int} #relval::Vector{Int} end @@ -136,7 +136,8 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD tree = etree(graph) rowcount, colcount = supcnt(graph, tree) supernode, tree = stree(graph, tree, colcount, stype) - + + n = 0 postorder = Order(undef, nv(graph)) partition = Vector{Int}(undef, nv(graph)) sndptr = Vector{Int}(undef, treesize(tree) + 1) @@ -146,13 +147,13 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD sndptr[i + 1] = sndptr[i] + length(snd) partition[sndptr[i]:sndptr[i + 1] - 1] .= i postorder[sndptr[i]:sndptr[i + 1] - 1] = snd + n += colcount[snd[end]] - 1 end order = compose(postorder, order) graph = OrderedGraph(graph, postorder) - colcount = view(colcount, postorder) - sepval = Vector{Int}(undef, sum(colcount[sndptr[2:end] .- 1])) + sepval = Vector{Int}(undef, n) sepptr = Vector{Int}(undef, treesize(tree) + 1) sepptr[1] = 1 From 033044621bdb96b38369504374f83bab2f0260a5 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Fri, 6 Dec 2024 13:30:49 -0500 Subject: [PATCH 072/100] pointless changes --- src/junction_trees/postorder_trees.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl index 6ca6492..dd8c523 100644 --- a/src/junction_trees/postorder_trees.jl +++ b/src/junction_trees/postorder_trees.jl @@ -17,15 +17,21 @@ function PostorderTree(parent::AbstractVector) level = Vector{Int}(undef, n) fdesc = Vector{Int}(undef, n) level[n] = 0 - fdesc[n] = n + fdesc[n] = 0 for i in n - 1:-1:1 - level[i] = level[parentindex(tree, i)] + 1 + j = parentindex(tree, i) + level[i] = level[j] + 1 fdesc[i] = i + fdesc[j] = 0 end for i in 1:n - 1 - fdesc[parentindex(tree, i)] = min(fdesc[i], fdesc[parentindex(tree, i)]) + j = parentindex(tree, i) + + if iszero(fdesc[j]) + fdesc[j] = fdesc[i] + end end PostorderTree(tree, level, fdesc) From 473918153aff43c3c0a7a10dc2812514ec9a20e1 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 9 Dec 2024 15:03:21 -0500 Subject: [PATCH 073/100] performance improvement during symbolic factorization --- src/junction_trees/junction_trees.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 2ecd00c..fc62d69 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -157,26 +157,30 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD sepptr = Vector{Int}(undef, treesize(tree) + 1) sepptr[1] = 1 + fullarray = zeros(Int, nv(graph)) + for j in 1:treesize(tree) u = sndptr[j + 1] - 1 - column = Set{Int}() + column = Int[] for v in outneighbors(graph, sndptr[j]) if u < v push!(column, v) + fullarray[v] = j end end for i in childindices(tree, j) for v in view(sepval, sepptr[i]:sepptr[i + 1] - 1) - if u < v + if u < v && fullarray[v] != j push!(column, v) + fullarray[v] = j end end end sepptr[j + 1] = sepptr[j] + length(column) - sepval[sepptr[j]:sepptr[j + 1] - 1] = sort(collect(column)) + sepval[sepptr[j]:sepptr[j + 1] - 1] = sort(column) end JunctionTree(order, tree, partition, sndptr, sepptr, sepval) From cc8e8874a58afbd4d9df9cee579c9f1bf5c3beb2 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Tue, 10 Dec 2024 18:06:13 -0500 Subject: [PATCH 074/100] removed unused files --- src/junction_trees/filled_graphs.jl | 43 ------------------- .../ordered_graph_homomorphisms.jl | 6 --- 2 files changed, 49 deletions(-) delete mode 100644 src/junction_trees/filled_graphs.jl delete mode 100644 src/junction_trees/ordered_graph_homomorphisms.jl diff --git a/src/junction_trees/filled_graphs.jl b/src/junction_trees/filled_graphs.jl deleted file mode 100644 index b62108c..0000000 --- a/src/junction_trees/filled_graphs.jl +++ /dev/null @@ -1,43 +0,0 @@ -struct FilledGraph <: AbstractOrderedGraph - colptr::Vector{Int} - rowval::Vector{Int} - tree::PostorderTree -end - - -function adjacencymatrix(graph::FilledGraph) - lower = SparseMatrixCSC(nv(graph), nv(graph), graph.colptr, graph.rowval, ones(Bool, ne(graph))) - lower .|| lower' -end - - -############################ -# Abstract Graph Interface # -############################ - - -function SimpleGraphs.ne(graph::FilledGraph) - last(graph.colptr) - 1 -end - - -function SimpleGraphs.nv(graph::FilledGraph) - length(graph.colptr) - 1 -end - - -function SimpleGraphs.badj(graph::FilledGraph, i::Integer) - descendantindices(graph.tree, i) -end - - -function SimpleGraphs.fadj(graph::FilledGraph, i::Integer) - view(graph.rowval, graph.colptr[i]:graph.colptr[i + 1] - 1) -end - - -#= -function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) - view(graph.rowval, graph.adjptr[i]:graph.adjptr[i + 1] - 1) -end -=# diff --git a/src/junction_trees/ordered_graph_homomorphisms.jl b/src/junction_trees/ordered_graph_homomorphisms.jl deleted file mode 100644 index d31782c..0000000 --- a/src/junction_trees/ordered_graph_homomorphisms.jl +++ /dev/null @@ -1,6 +0,0 @@ -struct OrderedGraphHomomorphism{Source <: AbstractOrderedGraph, Target <: AbstractOrderedGraph} - source::Source - target::Target - mapping::Vector{Int} - indptr::Vector{Int} -end From d1a182baa1aab870e20b00b6f950412a3a2df3f4 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Tue, 10 Dec 2024 22:43:58 -0500 Subject: [PATCH 075/100] removed commented code --- src/junction_trees/junction_trees.jl | 110 --------------------------- 1 file changed, 110 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index fc62d69..b463663 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -1,113 +1,3 @@ -#= -""" - JunctionTree - -A [tree decomposition](https://en.wikipedia.org/wiki/Tree_decomposition) of a graph ``G``. -This type implements the [indexed tree interface](https://juliacollections.github.io/AbstractTrees.jl/stable/#The-Indexed-Tree-Interface). -""" -struct JunctionTree - order::Order # elimination order - tree::PostorderTree # supernodal elimination tree - representative::Vector{Int} # vector of representative vertices - seperator::SparseMatrixCSC{Bool, Int} - - # cache - partition::Vector{Int} # supernode partition -end - - -""" - JunctionTree(graph[, ealg::Union{Order, EliminationAlgorithm}[, stype::SupernodeType]]) - -Construct a tree decomposition of a connected simple graph, optionally specifying an elimination algorithm and -a supernode type. -""" -function JunctionTree( - graph, - ealg::EliminationAlgorithm=DEFAULT_ELIMINATION_ALGORITHM, - stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - - graph = adjacencymatrix(graph) - order = Order(graph, ealg) - JunctionTree(graph, order, stype) -end - - -function JunctionTree( - graph, - order::Order, - stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - - graph = OrderedGraph(graph, order) - tree = Tree(etree(graph)) - JunctionTree(order, graph, tree, stype) -end - - -# Construct a junction tree. -# ---------------------------------------- -# stree supernodal elimination tree -# ---------------------------------------- -function JunctionTree(order::Order, graph::OrderedGraph, tree::Tree, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) - partition, supernode, parent, ancestor = stree(tree, last(supcnt(graph, tree)), stype) - tree = Tree(parent) - - order = postorder(tree) - tree = PostorderTree(tree, order) - partition = view(inv(order), partition) - supernode = view(supernode, order) - ancestor = view(ancestor, order) - - order = Order(vcat(supernode...)) - graph = OrderedGraph(graph, order) - partition = view(partition, order) - ancestor = view(inv(order), ancestor) - - representative = Vector{Int}(undef, treesize(tree) + 1) - representative[1:end - 1] .= view(inv(order), map(first, supernode)) - representative[end] = representative[end - 1] + length(supernode[end]) - - seperator = seperators(graph, tree, representative, ancestor) - colptr = accumulate(+, [0, map(length, seperator)...]) .+ 1 - rowval = reduce(vcat, map(sort ∘ collect, seperator)) - nzval = ones(Bool, length(rowval)) - seperator = SparseMatrixCSC(nv(graph), treesize(tree), colptr, rowval, nzval) - - JunctionTree(order, tree, representative, seperator, partition) -end - - -# Compute the (unsorted) seperators of every node in T. -function seperators(graph::OrderedGraph, tree::PostorderTree, representative::AbstractVector, ancestor::AbstractVector) - n = treesize(tree) - seperator = Vector{Set{Int}}(undef, n) - - for i in 1:n - 1 - seperator[i] = Set(ancestor[i]) - - for v in outneighbors(graph, representative[i]) - if ancestor[i] < v - push!(seperator[i], v) - end - end - end - - for j in 1:n - 1 - for i in childindices(tree, j) - for v in seperator[i] - if ancestor[j] < v - push!(seperator[j], v) - end - end - end - end - - seperator[n] = Set() - seperator -end -=# - - struct JunctionTree order::Order tree::PostorderTree From 9d09828d0792e5cd880cb92da4a73c8a8e80afb3 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Wed, 11 Dec 2024 19:49:45 -0500 Subject: [PATCH 076/100] seperate data structures. --- src/JunctionTrees.jl | 4 +-- src/junction_trees/disjoint_sets.jl | 21 +++++++++++++++ src/junction_trees/fixed_stacks.jl | 40 ++++++++++++++++++++++++++++ src/junction_trees/ordered_graphs.jl | 23 +++------------- src/junction_trees/trees.jl | 33 +++++------------------ 5 files changed, 72 insertions(+), 49 deletions(-) create mode 100644 src/junction_trees/disjoint_sets.jl create mode 100644 src/junction_trees/fixed_stacks.jl diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 1abcc44..4649042 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -38,6 +38,8 @@ export Node, Maximal, Fundamental export JunctionTree, treewidth, seperator, residual, clique, find_clique, lift_par, lift_sep, lift +include("junction_trees/fixed_stacks.jl") +include("junction_trees/disjoint_sets.jl") include("junction_trees/orders.jl") include("junction_trees/elimination_algorithms.jl") include("junction_trees/trees.jl") @@ -45,8 +47,6 @@ include("junction_trees/child_indices.jl") include("junction_trees/postorder_trees.jl") include("junction_trees/abstract_ordered_graphs.jl") include("junction_trees/ordered_graphs.jl") -include("junction_trees/filled_graphs.jl") -include("junction_trees/ordered_graph_homomorphisms.jl") include("junction_trees/supernode_types.jl") include("junction_trees/junction_trees.jl") diff --git a/src/junction_trees/disjoint_sets.jl b/src/junction_trees/disjoint_sets.jl new file mode 100644 index 0000000..ac49f7d --- /dev/null +++ b/src/junction_trees/disjoint_sets.jl @@ -0,0 +1,21 @@ +struct DisjointSets + sets::IntDisjointSets{Int} + index::Vector{Int} + root::Vector{Int} + + function DisjointSets(n::Integer) + new(IntDisjointSets(n), collect(1:n), collect(1:n)) + end +end + + +function find!(sets::DisjointSets, u::Integer) + sets.index[find_root!(sets.sets, u)] +end + + +function Base.union!(sets::DisjointSets, u::Integer, v::Integer) + w = max(u, v) + sets.root[w] = root_union!(sets.sets, sets.root[u], sets.root[v]) + sets.index[sets.root[w]] = w +end diff --git a/src/junction_trees/fixed_stacks.jl b/src/junction_trees/fixed_stacks.jl new file mode 100644 index 0000000..cf14c8f --- /dev/null +++ b/src/junction_trees/fixed_stacks.jl @@ -0,0 +1,40 @@ +struct FixedStack{T} <: AbstractVector{T} + top::Array{Int, 0} + items::Vector{T} + + function FixedStack{T}(n::Integer) where T + new(zeros(Int), Vector{T}(undef, n)) + end +end + + +function Base.push!(stack::FixedStack, v) + stack.top[] += 1 + stack.items[stack.top[]] = v +end + + +function Base.pop!(stack::FixedStack) + stack.top[] -= 1 + stack.items[stack.top[] + 1] +end + + +############################# +# Abstract Vector Interface # +############################# + + +function Base.getindex(stack::FixedStack, i) + stack.items[i] +end + + +function Base.IndexStyle(::Type{FixedStack}) + IndexLinear() +end + + +function Base.size(stack::FixedStack) + (stack.top[],) +end diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 1171e7a..0cfeef1 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -118,24 +118,7 @@ end # ---------------------------------------- function supcnt(graph::OrderedGraph, tree::PostorderTree) n = treesize(tree) - - #### Disjoint Set Union #### - - rvert = collect(1:n) - index = collect(1:n) - forest = IntDisjointSets(n) - - function find(u) - index[find_root!(forest, u)] - end - - function union(u, v) - w = max(u, v) - rvert[w] = root_union!(forest, rvert[u], rvert[v]) - index[rvert[w]] = w - end - - ############################ + sets = DisjointSets(n) prev_p = zeros(Int, n) prev_nbr = zeros(Int, n) @@ -157,7 +140,7 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) if iszero(pp) rc[u] += level(tree, p) - level(tree, u) else - q = find(pp) + q = find!(sets, pp) rc[u] += level(tree, p) - level(tree, q) wt[q] -= 1 end @@ -168,7 +151,7 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) prev_nbr[u] = p end - union(p, parentindex(tree, p)) + union!(sets, p, parentindex(tree, p)) end cc = wt diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 58d9745..7fbd994 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -34,35 +34,14 @@ end # Compute a postordering of tree's vertices. function postorder(tree::Tree) n = treesize(tree) - - #### Stack #### - - top = Ref{Int}(0) - items = Vector{Int}(undef, n) - - function empty() - iszero(top[]) - end - - function push(i) - top[] += 1 - items[top[]] = i - end - - function pop() - top[] -= 1 - items[top[] + 1] - end - - ############### - - push(rootindex(tree)) + stack = FixedStack{Int}(n) + push!(stack, rootindex(tree)) order = Order(undef, n) child = copy(tree.child) count = 1 - while !empty() - j = pop() + while !isempty(stack) + j = pop!(stack) i = child[j] if iszero(i) @@ -70,8 +49,8 @@ function postorder(tree::Tree) count += 1 else child[j] = tree.brother[i] - push(j) - push(i) + push!(stack, j) + push!(stack, i) end end From 850d75258a15d99bb553708dac2327f5a538d50d Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 14 Dec 2024 20:48:44 -0500 Subject: [PATCH 077/100] removed abstract ordered graphs --- src/JunctionTrees.jl | 1 - src/junction_trees/abstract_ordered_graphs.jl | 31 ------------------- src/junction_trees/ordered_graphs.jl | 26 +++++++++++++++- 3 files changed, 25 insertions(+), 33 deletions(-) delete mode 100644 src/junction_trees/abstract_ordered_graphs.jl diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 4649042..a2596a4 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -45,7 +45,6 @@ include("junction_trees/elimination_algorithms.jl") include("junction_trees/trees.jl") include("junction_trees/child_indices.jl") include("junction_trees/postorder_trees.jl") -include("junction_trees/abstract_ordered_graphs.jl") include("junction_trees/ordered_graphs.jl") include("junction_trees/supernode_types.jl") include("junction_trees/junction_trees.jl") diff --git a/src/junction_trees/abstract_ordered_graphs.jl b/src/junction_trees/abstract_ordered_graphs.jl deleted file mode 100644 index c37788c..0000000 --- a/src/junction_trees/abstract_ordered_graphs.jl +++ /dev/null @@ -1,31 +0,0 @@ -abstract type AbstractOrderedGraph <: AbstractSimpleGraph{Int} end - - -############################ -# Abstract Graph Interface # -############################ - - -function SimpleGraphs.is_directed(::Type{AbstractOrderedGraph}) - true -end - - -function SimpleGraphs.edgetype(graph::AbstractOrderedGraph) - SimpleEdge{Int} -end - - -function SimpleGraphs.has_edge(graph::AbstractOrderedGraph, edge::SimpleEdge{Int}) - i = src(edge) - j = dst(edge) - i < j && insorted(j, outneighbors(graph, i)) -end - - -# Multiline printing. -function Base.show(io::IO, ::MIME"text/plain", graph::AbstractOrderedGraph) - print(io, "ordered graph:\n") - SparseArrays._show_with_braille_patterns(io, adjacencymatrix(graph)) -end - diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 0cfeef1..e21696a 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -4,7 +4,7 @@ A directed simple graph whose edges ``(i, j)`` satisfy the inequality ``i < j``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ -struct OrderedGraph <: AbstractOrderedGraph +struct OrderedGraph <: AbstractSimpleGraph{Int} colptr::Vector{Int} adjptr::Vector{Int} rowval::Vector{Int} @@ -164,6 +164,13 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) end +# Multiline printing. +function Base.show(io::IO, ::MIME"text/plain", graph::OrderedGraph) + print(io, "ordered graph:\n") + SparseArrays._show_with_braille_patterns(io, adjacencymatrix(graph)) +end + + ############################ # Abstract Graph Interface # ############################ @@ -192,3 +199,20 @@ end function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) view(graph.rowval, graph.adjptr[i]:graph.adjptr[i + 1] - 1) end + + +function SimpleGraphs.is_directed(::Type{OrderedGraph}) + true +end + + +function SimpleGraphs.edgetype(graph::OrderedGraph) + SimpleEdge{Int} +end + + +function SimpleGraphs.has_edge(graph::OrderedGraph, edge::SimpleEdge{Int}) + i = src(edge) + j = dst(edge) + i < j && insorted(j, outneighbors(graph, i)) +end From f6f7f2424e121a655d9a2deac638717ac0dcbbef Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sat, 14 Dec 2024 21:13:42 -0500 Subject: [PATCH 078/100] storing adjacency matrix --- src/junction_trees/ordered_graphs.jl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index e21696a..5e84f84 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -5,9 +5,8 @@ A directed simple graph whose edges ``(i, j)`` satisfy the inequality ``i < j``. This type implements the [abstract graph interface](https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/). """ struct OrderedGraph <: AbstractSimpleGraph{Int} + matrix::SparseMatrixCSC{Bool, Int} colptr::Vector{Int} - adjptr::Vector{Int} - rowval::Vector{Int} end @@ -49,14 +48,14 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC) colptr[i] = graph.colptr[i] + searchsortedfirst(view(rowvals(graph), nzrange(graph, i)), i) - 1 end - OrderedGraph(colptr, graph.colptr, graph.rowval) + OrderedGraph(graph, colptr) end # Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) - SparseMatrixCSC(nv(graph), nv(graph), graph.adjptr, graph.rowval, ones(Bool, length(graph.rowval))) + graph.matrix end @@ -177,27 +176,27 @@ end function SimpleGraphs.ne(graph::OrderedGraph) - (last(graph.adjptr) - 1) ÷ 2 + nnz(graph.matrix) ÷ 2 end function SimpleGraphs.nv(graph::OrderedGraph) - length(graph.adjptr) - 1 + size(graph.matrix, 1) end function SimpleGraphs.badj(graph::OrderedGraph, i::Integer) - view(graph.rowval, graph.adjptr[i]:graph.colptr[i] - 1) + view(rowvals(graph.matrix), graph.matrix.colptr[i]:graph.colptr[i] - 1) end function SimpleGraphs.fadj(graph::OrderedGraph, i::Integer) - view(graph.rowval, graph.colptr[i]:graph.adjptr[i + 1] - 1) + view(rowvals(graph.matrix), graph.colptr[i]:graph.matrix.colptr[i + 1] - 1) end function SimpleGraphs.all_neighbors(graph::OrderedGraph, i::Integer) - view(graph.rowval, graph.adjptr[i]:graph.adjptr[i + 1] - 1) + view(rowvals(graph.matrix), nzrange(graph.matrix, i)) end From 4294dad8e414dea1b5b7a7a9c583bc9274c0af18 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 17:09:30 -0500 Subject: [PATCH 079/100] ordered handled in place --- src/junction_trees/junction_trees.jl | 3 ++- src/junction_trees/orders.jl | 17 +++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index b463663..2a3f062 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -22,6 +22,7 @@ end function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) + order = deepcopy(order) graph = OrderedGraph(graph, order) tree = etree(graph) rowcount, colcount = supcnt(graph, tree) @@ -40,7 +41,7 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD n += colcount[snd[end]] - 1 end - order = compose(postorder, order) + permute!(order, postorder) graph = OrderedGraph(graph, postorder) sepval = Vector{Int}(undef, n) diff --git a/src/junction_trees/orders.jl b/src/junction_trees/orders.jl index f6763ce..6b426db 100644 --- a/src/junction_trees/orders.jl +++ b/src/junction_trees/orders.jl @@ -16,9 +16,8 @@ end Construct a permutation ``\\sigma`` from a sequence ``(\\sigma(1), \\dots, \\sigma(n))``. """ function Order(order::AbstractVector) - n = length(order) - index = Vector{Int}(undef, n) - index[order] = 1:n + index = Vector{Int}(undef, length(order)) + index[order] = eachindex(order) Order(order, index) end @@ -28,9 +27,10 @@ function Order(::UndefInitializer, n::Integer) end -# Compose two permutations. -function compose(left::Order, right::Order) - Order(right.order[left.order], left.index[right.index]) +function Base.permute!(order::Order, permutation::AbstractVector) + permute!(order.order, permutation) + order.index[order.order] = eachindex(order.order) + order end @@ -40,6 +40,11 @@ function Base.copy(order::Order) end +function Base.deepcopy(order::Order) + Order(copy(order.order), copy(order.index)) +end + + """ inverse(order::Order) From ccfc43620c31d8daf440663f16b5a58b7394d856 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 17:22:27 -0500 Subject: [PATCH 080/100] permuting graphs in place --- src/junction_trees/junction_trees.jl | 2 +- src/junction_trees/ordered_graphs.jl | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 2a3f062..6f39dfa 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -42,7 +42,7 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD end permute!(order, postorder) - graph = OrderedGraph(graph, postorder) + permute!(graph, postorder) sepval = Vector{Int}(undef, n) sepptr = Vector{Int}(undef, treesize(tree) + 1) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 5e84f84..34f72bf 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -52,6 +52,16 @@ function OrderedGraph(graph::AbstractSparseMatrixCSC) end +function Base.permute!(graph::OrderedGraph, permutation::AbstractVector) + permute!(graph.matrix, permutation, permutation) + + map!(graph.colptr, vertices(graph)) do i + first(nzrange(graph.matrix, i)) + searchsortedfirst(all_neighbors(graph, i), i) - 1 + end + + graph +end + # Construct the adjacency matrix of an ordered graph. function adjacencymatrix(graph::OrderedGraph) From d13d0b2043901d2734720a0a24dd8531a80b93cd Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 17:29:59 -0500 Subject: [PATCH 081/100] rewrote a function --- src/junction_trees/elimination_algorithms.jl | 30 +++++++------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index fb0f616..02af005 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -102,7 +102,7 @@ function Order(graph::AbstractSparseMatrixCSC, ealg::TreeWidthSolverJL_BT) bitgraph = TreeWidthSolver.MaskedBitGraph(bitfadjlist, fadjlist, TreeWidthSolver.bmask(T, 1:n)) decomposition = TreeWidthSolver.bt_algorithm(bitgraph, TreeWidthSolver.all_pmc_enmu(bitgraph, false), ones(n), false, true) - order = reverse(vcat(TreeWidthSolver.EliminationOrder(decomposition.tree).order...)) + order = reverse(reduce(vcat, TreeWidthSolver.EliminationOrder(decomposition.tree).order)) Order(order) end @@ -115,26 +115,18 @@ end # Construct the adjacency matrix of a graph. function adjacencymatrix(graph::BasicGraphs.AbstractSymmetricGraph) - m = BasicGraphs.ne(graph) - n = BasicGraphs.nv(graph) - colptr = Vector{Int}(undef, n + 1) - rowval = Vector{Int}(undef, m) - count = 1 - - for i in 1:n - colptr[i] = count - neighbor = collect(BasicGraphs.all_neighbors(graph, i)) - sort!(neighbor) - - for j in neighbor - rowval[count] = j - count += 1 - end + rowval = Vector{Int}(undef, BasicGraphs.ne(graph)) + colptr = Vector{Int}(undef, BasicGraphs.nv(graph) + 1) + colptr[1] = 1 + + for i in BasicGraphs.vertices(graph) + column = collect(BasicGraphs.all_neighbors(graph, i)) + colptr[i + 1] = colptr[i] + length(column) + rowval[colptr[i]:colptr[i + 1] - 1] = sort!(column) end - colptr[n + 1] = m + 1 - nzval = ones(Bool, m) - SparseMatrixCSC(n, n, colptr, rowval, nzval) + nzval = ones(Bool, BasicGraphs.ne(graph)) + SparseMatrixCSC(BasicGraphs.nv(graph), BasicGraphs.nv(graph), colptr, rowval, nzval) end From b32201b690a299341cd9ab0c37063bdfbea02b1b Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 17:36:38 -0500 Subject: [PATCH 082/100] tiny change --- src/junction_trees/elimination_algorithms.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index 02af005..ad21c39 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -120,9 +120,9 @@ function adjacencymatrix(graph::BasicGraphs.AbstractSymmetricGraph) colptr[1] = 1 for i in BasicGraphs.vertices(graph) - column = collect(BasicGraphs.all_neighbors(graph, i)) + column = BasicGraphs.all_neighbors(graph, i) colptr[i + 1] = colptr[i] + length(column) - rowval[colptr[i]:colptr[i + 1] - 1] = sort!(column) + rowval[colptr[i]:colptr[i + 1] - 1] = sort!(collect(column)) end nzval = ones(Bool, BasicGraphs.ne(graph)) From 971ec938f69fe02577755c8c188b32813c654e1b Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 22:14:03 -0500 Subject: [PATCH 083/100] postordertree -> tree --- src/junction_trees/junction_trees.jl | 2 +- src/junction_trees/supernode_types.jl | 4 +- src/junction_trees/trees.jl | 58 +++++++++++++++++++++++++-- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 6f39dfa..4068af4 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -1,6 +1,6 @@ struct JunctionTree order::Order - tree::PostorderTree + tree::Tree partition::Vector{Int} # supernode(i) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index d19bcf5..df5647a 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -72,8 +72,8 @@ end function stree(graph::OrderedGraph, tree::Tree, colcount::AbstractVector, stype::SupernodeType) supernode, tree = cta(tree, colcount, stype) - order = postorder(tree) - view(supernode, order), PostorderTree(tree, order) + order = postorder!(tree) + view(supernode, order), tree end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index 7fbd994..dae45d8 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -4,7 +4,7 @@ struct Tree parent::Vector{Int} # vector of parents child::Vector{Int} # vector of left-children brother::Vector{Int} # vector of right-siblings - root::Int # root + root::Array{Int, 0} # root end @@ -16,11 +16,11 @@ function Tree(parent::AbstractVector) n = length(parent) child = zeros(Int, n) brother = zeros(Int, n) - root = n + root = fill(n) for i in n:-1:1 if iszero(parent[i]) - root = i + root .= i else brother[i] = child[parent[i]] child[parent[i]] = i @@ -58,6 +58,56 @@ function postorder(tree::Tree) end +function postorder!(tree::Tree) + order = postorder(tree) + index = inv(order) + parent = copy(tree.parent) + + map!(tree.parent, order) do i + j = parent[i] + iszero(j) ? 0 : index[j] + end + + n = treesize(tree) + tree.child .= 0 + tree.root .= n + + for i in n - 1:-1:1 + tree.brother[i] = tree.child[tree.parent[i]] + tree.child[tree.parent[i]] = i + end + + order +end + + +function level(tree::Tree) + n = treesize(tree) + level = Vector{Int}(undef, n) + level[n] = 0 + + for i in n - 1:-1:1 + j = parentindex(tree, i) + level[i] = level[j] + 1 + end + + level +end + + +function fdesc(tree::Tree) + n = treesize(tree) + fdesc = collect(1:n) + + for i in 1:n - 1 + j = parentindex(tree, i) + fdesc[j] = min(fdesc[i], fdesc[j]) + end + + fdesc +end + + ########################## # Indexed Tree Interface # ########################## @@ -69,7 +119,7 @@ end function AbstractTrees.rootindex(tree::Tree) - tree.root + tree.root[] end From c169c83ce0b10ee2d171a2c7536c986238b16088 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 22:20:51 -0500 Subject: [PATCH 084/100] removed a variable --- src/junction_trees/trees.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index dae45d8..ffde7d7 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -60,12 +60,11 @@ end function postorder!(tree::Tree) order = postorder(tree) - index = inv(order) parent = copy(tree.parent) map!(tree.parent, order) do i j = parent[i] - iszero(j) ? 0 : index[j] + iszero(j) ? 0 : inv(order)[j] end n = treesize(tree) From 0bee9b74c17318738a3f1d575195f694a8706de4 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 22:38:25 -0500 Subject: [PATCH 085/100] postorder trees gone --- src/JunctionTrees.jl | 1 - src/junction_trees/junction_trees.jl | 5 ++ src/junction_trees/ordered_graphs.jl | 22 +----- src/junction_trees/postorder_trees.jl | 107 -------------------------- src/junction_trees/trees.jl | 4 +- test/JunctionTrees.jl | 3 - 6 files changed, 11 insertions(+), 131 deletions(-) delete mode 100644 src/junction_trees/postorder_trees.jl diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index a2596a4..f3d68fa 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -44,7 +44,6 @@ include("junction_trees/orders.jl") include("junction_trees/elimination_algorithms.jl") include("junction_trees/trees.jl") include("junction_trees/child_indices.jl") -include("junction_trees/postorder_trees.jl") include("junction_trees/ordered_graphs.jl") include("junction_trees/supernode_types.jl") include("junction_trees/junction_trees.jl") diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 4068af4..7ad5966 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -25,6 +25,11 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD order = deepcopy(order) graph = OrderedGraph(graph, order) tree = etree(graph) + + postorder = postorder!(tree) + permute!(order, postorder) + permute!(graph, postorder) + rowcount, colcount = supcnt(graph, tree) supernode, tree = stree(graph, tree, colcount, stype) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index 34f72bf..bc35869 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -111,21 +111,7 @@ end # graph simple connected graph # tree elimination tree # ---------------------------------------- -function supcnt(graph::OrderedGraph, tree::Tree) - order = postorder(tree) - rc, cc = supcnt(OrderedGraph(graph, order), PostorderTree(tree, order)) - view(rc, inv(order)), view(cc, inv(order)) -end - - -# An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization -# Gilbert, Ng, and Peyton -# Figure 3: Implementation of algorithm to compute row and column counts. -# ---------------------------------------- -# graph simple connected graph -# tree elimination tree -# ---------------------------------------- -function supcnt(graph::OrderedGraph, tree::PostorderTree) +function supcnt(graph::OrderedGraph, tree::Tree, level::AbstractVector=levels(tree), fdesc::AbstractVector=firstdescendants(tree)) n = treesize(tree) sets = DisjointSets(n) @@ -142,15 +128,15 @@ function supcnt(graph::OrderedGraph, tree::PostorderTree) wt[parentindex(tree, p)] -= 1 for u in outneighbors(graph, p) - if first(descendantindices(tree, p)) > prev_nbr[u] + if fdesc[p] > prev_nbr[u] wt[p] += 1 pp = prev_p[u] if iszero(pp) - rc[u] += level(tree, p) - level(tree, u) + rc[u] += level[p] - level[u] else q = find!(sets, pp) - rc[u] += level(tree, p) - level(tree, q) + rc[u] += level[p] - level[q] wt[q] -= 1 end diff --git a/src/junction_trees/postorder_trees.jl b/src/junction_trees/postorder_trees.jl deleted file mode 100644 index dd8c523..0000000 --- a/src/junction_trees/postorder_trees.jl +++ /dev/null @@ -1,107 +0,0 @@ -# A postordered rooted tree. -# This type implements the indexed tree interface. -struct PostorderTree - tree::Tree # rooted tree - level::Vector{Int} # vector of levels - fdesc::Vector{Int} # vector of first descendants -end - - -# Construct a tree from a postordered list of parents. -# ---------------------------------------- -# parent list of parents -# ---------------------------------------- -function PostorderTree(parent::AbstractVector) - tree = Tree(parent) - n = treesize(tree) - level = Vector{Int}(undef, n) - fdesc = Vector{Int}(undef, n) - level[n] = 0 - fdesc[n] = 0 - - for i in n - 1:-1:1 - j = parentindex(tree, i) - level[i] = level[j] + 1 - fdesc[i] = i - fdesc[j] = 0 - end - - for i in 1:n - 1 - j = parentindex(tree, i) - - if iszero(fdesc[j]) - fdesc[j] = fdesc[i] - end - end - - PostorderTree(tree, level, fdesc) -end - - -# Postorder a tree. -# ---------------------------------------- -# tree tree -# order postorder -# ---------------------------------------- -function PostorderTree(tree::Tree, order::Order) - n = treesize(tree) - parent = Vector{Int}(undef, n) - - for i in 1:n - 1 - parent[i] = inv(order)[parentindex(tree, order[i])] - end - - parent[n] = 0 - PostorderTree(parent) -end - - -# Get the level of a node i. -function level(tree::PostorderTree, i::Integer) - tree.level[i] -end - - -function descendantindices(tree::PostorderTree, i::Integer) - tree.fdesc[i]:i - 1 -end - - -########################## -# Indexed Tree Interface # -########################## - - -function AbstractTrees.treesize(tree::PostorderTree) - treesize(tree.tree) -end - - -function AbstractTrees.treeheight(tree::PostorderTree) - maximum(tree.level) -end - - -function AbstractTrees.parentindex(tree::PostorderTree, i::Integer) - parentindex(tree.tree, i) -end - - -function AbstractTrees.childindices(tree::PostorderTree, i::Integer) - childindices(tree.tree, i) -end - - -function AbstractTrees.rootindex(tree::PostorderTree) - rootindex(tree.tree) -end - - -function AbstractTrees.NodeType(::Type{IndexNode{PostorderTree, Int}}) - HasNodeType() -end - - -function AbstractTrees.nodetype(::Type{IndexNode{PostorderTree, Int}}) - IndexNode{PostorderTree, Int} -end diff --git a/src/junction_trees/trees.jl b/src/junction_trees/trees.jl index ffde7d7..6e85a1f 100644 --- a/src/junction_trees/trees.jl +++ b/src/junction_trees/trees.jl @@ -80,7 +80,7 @@ function postorder!(tree::Tree) end -function level(tree::Tree) +function levels(tree::Tree) n = treesize(tree) level = Vector{Int}(undef, n) level[n] = 0 @@ -94,7 +94,7 @@ function level(tree::Tree) end -function fdesc(tree::Tree) +function firstdescendants(tree::Tree) n = treesize(tree) fdesc = collect(1:n) diff --git a/test/JunctionTrees.jl b/test/JunctionTrees.jl index 4957084..06b66e0 100644 --- a/test/JunctionTrees.jl +++ b/test/JunctionTrees.jl @@ -37,7 +37,6 @@ order = JunctionTrees.Order(1:17) # Figure 4.3 jtree = JunctionTree(graph, order, Node()) @test treewidth(jtree) == 4 -@test treeheight(jtree) == 7 @test treesize(jtree) == 17 @test map(i -> parentindex(jtree, i), 1:17) == [ @@ -124,7 +123,6 @@ jtree = JunctionTree(graph, order, Node()) # Figure 4.7 (left) jtree = JunctionTree(graph, order, Maximal()) @test treewidth(jtree) == 4 -@test treeheight(jtree) == 4 @test treesize(jtree) == 8 @test map(i -> parentindex(jtree, i), 1:8) == [ @@ -174,7 +172,6 @@ jtree = JunctionTree(graph, order, Maximal()) # Figure 4.9 jtree = JunctionTree(graph, order, Fundamental()) @test treewidth(jtree) == 4 -@test treeheight(jtree) == 5 @test treesize(jtree) == 12 @test map(i -> parentindex(jtree, i), 1:12) == [ From f40b329310ba6604d034a14359f92cdaacf886cd Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 22:44:36 -0500 Subject: [PATCH 086/100] simplified things a bit --- src/junction_trees/junction_trees.jl | 10 +++------- src/junction_trees/ordered_graphs.jl | 9 +++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 7ad5966..26961d3 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -24,14 +24,10 @@ end function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) order = deepcopy(order) graph = OrderedGraph(graph, order) - tree = etree(graph) + etree = etree!(order, graph) - postorder = postorder!(tree) - permute!(order, postorder) - permute!(graph, postorder) - - rowcount, colcount = supcnt(graph, tree) - supernode, tree = stree(graph, tree, colcount, stype) + rowcount, colcount = supcnt(graph, etree) + supernode, tree = stree(graph, etree, colcount, stype) n = 0 postorder = Order(undef, nv(graph)) diff --git a/src/junction_trees/ordered_graphs.jl b/src/junction_trees/ordered_graphs.jl index bc35869..5ae2ef2 100644 --- a/src/junction_trees/ordered_graphs.jl +++ b/src/junction_trees/ordered_graphs.jl @@ -104,6 +104,15 @@ function etree(graph::OrderedGraph) end +function etree!(order::Order, graph::OrderedGraph) + tree = etree(graph) + postorder = postorder!(tree) + permute!(order, postorder) + permute!(graph, postorder) + tree +end + + # An Efficient Algorithm to Compute Row and Column Counts for Sparse Cholesky Factorization # Gilbert, Ng, and Peyton # Figure 3: Implementation of algorithm to compute row and column counts. From ba23c91cd5a2710998b1b33c7e598802b1b01ef0 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 23:08:50 -0500 Subject: [PATCH 087/100] moved code to seperate function --- src/junction_trees/junction_trees.jl | 29 ++++------------------ src/junction_trees/supernode_types.jl | 35 ++++++++++++++++++++------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 26961d3..509c200 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -24,34 +24,15 @@ end function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) order = deepcopy(order) graph = OrderedGraph(graph, order) - etree = etree!(order, graph) - - rowcount, colcount = supcnt(graph, etree) - supernode, tree = stree(graph, etree, colcount, stype) - - n = 0 - postorder = Order(undef, nv(graph)) - partition = Vector{Int}(undef, nv(graph)) - sndptr = Vector{Int}(undef, treesize(tree) + 1) - sndptr[1] = 1 - - for (i, snd) in enumerate(supernode) - sndptr[i + 1] = sndptr[i] + length(snd) - partition[sndptr[i]:sndptr[i + 1] - 1] .= i - postorder[sndptr[i]:sndptr[i + 1] - 1] = snd - n += colcount[snd[end]] - 1 - end - - permute!(order, postorder) - permute!(graph, postorder) + stree, sndptr, partition, n = stree!(order, graph, stype) sepval = Vector{Int}(undef, n) - sepptr = Vector{Int}(undef, treesize(tree) + 1) + sepptr = Vector{Int}(undef, treesize(stree) + 1) sepptr[1] = 1 fullarray = zeros(Int, nv(graph)) - for j in 1:treesize(tree) + for j in 1:treesize(stree) u = sndptr[j + 1] - 1 column = Int[] @@ -62,7 +43,7 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD end end - for i in childindices(tree, j) + for i in childindices(stree, j) for v in view(sepval, sepptr[i]:sepptr[i + 1] - 1) if u < v && fullarray[v] != j push!(column, v) @@ -75,7 +56,7 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD sepval[sepptr[j]:sepptr[j + 1] - 1] = sort(column) end - JunctionTree(order, tree, partition, sndptr, sepptr, sepval) + JunctionTree(order, stree, partition, sndptr, sepptr, sepval) end diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index df5647a..da971dd 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -36,8 +36,8 @@ struct Fundamental <: SupernodeType end # Compact Clique Tree Data Structures in Sparse Matrix Factorizations # Pothen and Sun # Figure 4: The Clique Tree Algorithm 2 -function cta(tree::Tree, colcount::AbstractVector, stype::SupernodeType) - n = treesize(tree) +function pothensun(etree::Tree, colcount::AbstractVector, stype::SupernodeType) + n = treesize(etree) new_in_clique = Vector{Int}(undef, n) new = Vector{Int}[] parent = Int[] @@ -46,7 +46,7 @@ function cta(tree::Tree, colcount::AbstractVector, stype::SupernodeType) i = 0 for v in 1:n - u = child_in_supernode(tree, colcount, stype, v) + u = child_in_supernode(etree, colcount, stype, v) if !isnothing(u) new_in_clique[v] = new_in_clique[u] @@ -55,10 +55,10 @@ function cta(tree::Tree, colcount::AbstractVector, stype::SupernodeType) new_in_clique[v] = i += 1 push!(new, [v]) push!(parent, 0) - push!(first_anc, n) + push!(first_anc, 0) end - for s in childindices(tree, v) + for s in childindices(etree, v) if s !== u parent[new_in_clique[s]] = new_in_clique[v] first_anc[new_in_clique[s]] = v @@ -70,10 +70,27 @@ function cta(tree::Tree, colcount::AbstractVector, stype::SupernodeType) end -function stree(graph::OrderedGraph, tree::Tree, colcount::AbstractVector, stype::SupernodeType) - supernode, tree = cta(tree, colcount, stype) - order = postorder!(tree) - view(supernode, order), tree +function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree::Tree=etree!(order, graph)) + rowcount, colcount = supcnt(graph, etree) + supernode, stree = pothensun(etree, colcount, stype) + + n = 0 + postorder = Order(undef, nv(graph)) + partition = Vector{Int}(undef, nv(graph)) + sndptr = Vector{Int}(undef, treesize(stree) + 1) + sndptr[1] = 1 + + for (i, j) in enumerate(postorder!(stree)) + residual = supernode[j] + sndptr[i + 1] = sndptr[i] + length(residual) + partition[sndptr[i]:sndptr[i + 1] - 1] .= i + postorder[sndptr[i]:sndptr[i + 1] - 1] = residual + n += colcount[residual[end]] - 1 + end + + permute!(order, postorder) + permute!(graph, postorder) + stree, sndptr, partition, n end From 066322623fa212eb10b3fa8cb932ccc7e57e07c0 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 23:15:23 -0500 Subject: [PATCH 088/100] computing sepptr earlier --- src/junction_trees/junction_trees.jl | 8 ++------ src/junction_trees/supernode_types.jl | 9 +++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 509c200..86329ed 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -24,12 +24,9 @@ end function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) order = deepcopy(order) graph = OrderedGraph(graph, order) - stree, sndptr, partition, n = stree!(order, graph, stype) - - sepval = Vector{Int}(undef, n) - sepptr = Vector{Int}(undef, treesize(stree) + 1) - sepptr[1] = 1 + stree, sndptr, sepptr, partition = stree!(order, graph, stype) + sepval = Vector{Int}(undef, last(sepptr) - 1) fullarray = zeros(Int, nv(graph)) for j in 1:treesize(stree) @@ -52,7 +49,6 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD end end - sepptr[j + 1] = sepptr[j] + length(column) sepval[sepptr[j]:sepptr[j + 1] - 1] = sort(column) end diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index da971dd..23d4917 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -74,23 +74,24 @@ function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree:: rowcount, colcount = supcnt(graph, etree) supernode, stree = pothensun(etree, colcount, stype) - n = 0 + sndptr = Vector{Int}(undef, treesize(stree) + 1) + sepptr = Vector{Int}(undef, treesize(stree) + 1) postorder = Order(undef, nv(graph)) partition = Vector{Int}(undef, nv(graph)) - sndptr = Vector{Int}(undef, treesize(stree) + 1) sndptr[1] = 1 + sepptr[1] = 1 for (i, j) in enumerate(postorder!(stree)) residual = supernode[j] sndptr[i + 1] = sndptr[i] + length(residual) + sepptr[i + 1] = sepptr[i] + colcount[last(residual)] - 1 partition[sndptr[i]:sndptr[i + 1] - 1] .= i postorder[sndptr[i]:sndptr[i + 1] - 1] = residual - n += colcount[residual[end]] - 1 end permute!(order, postorder) permute!(graph, postorder) - stree, sndptr, partition, n + stree, sndptr, sepptr, partition end From a82562e9031dabd9653b6f871389c7c38b37293b Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 23:19:31 -0500 Subject: [PATCH 089/100] changed vector type --- src/junction_trees/supernode_types.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 23d4917..89653e5 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -76,10 +76,9 @@ function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree:: sndptr = Vector{Int}(undef, treesize(stree) + 1) sepptr = Vector{Int}(undef, treesize(stree) + 1) - postorder = Order(undef, nv(graph)) + postorder = Vector{Int}(undef, nv(graph)) partition = Vector{Int}(undef, nv(graph)) - sndptr[1] = 1 - sepptr[1] = 1 + sndptr[1] = sepptr[1] = 1 for (i, j) in enumerate(postorder!(stree)) residual = supernode[j] From 3f0bb9803424d619134455262847272a19d4a63a Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 23:37:58 -0500 Subject: [PATCH 090/100] allocating arrays --- src/junction_trees/junction_trees.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 86329ed..9836500 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -31,11 +31,12 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD for j in 1:treesize(stree) u = sndptr[j + 1] - 1 - column = Int[] + column = Vector{Int}(undef, sepptr[j + 1] - sepptr[j]) + count = 0 for v in outneighbors(graph, sndptr[j]) if u < v - push!(column, v) + column[count += 1] = v fullarray[v] = j end end @@ -43,13 +44,13 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD for i in childindices(stree, j) for v in view(sepval, sepptr[i]:sepptr[i + 1] - 1) if u < v && fullarray[v] != j - push!(column, v) + column[count += 1] = v fullarray[v] = j end end end - sepval[sepptr[j]:sepptr[j + 1] - 1] = sort(column) + sepval[sepptr[j]:sepptr[j + 1] - 1] = sort!(column) end JunctionTree(order, stree, partition, sndptr, sepptr, sepval) From 038f9db6b14f987fab2c5f4106a109f15ce8a6cc Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 23:45:47 -0500 Subject: [PATCH 091/100] removed field partition --- src/junction_trees/junction_trees.jl | 5 ++--- src/junction_trees/supernode_types.jl | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/junction_trees/junction_trees.jl b/src/junction_trees/junction_trees.jl index 9836500..724d5ed 100644 --- a/src/junction_trees/junction_trees.jl +++ b/src/junction_trees/junction_trees.jl @@ -1,7 +1,6 @@ struct JunctionTree order::Order tree::Tree - partition::Vector{Int} # supernode(i) sndptr::Vector{Int} @@ -24,7 +23,7 @@ end function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNODE_TYPE) order = deepcopy(order) graph = OrderedGraph(graph, order) - stree, sndptr, sepptr, partition = stree!(order, graph, stype) + stree, sndptr, sepptr = stree!(order, graph, stype) sepval = Vector{Int}(undef, last(sepptr) - 1) fullarray = zeros(Int, nv(graph)) @@ -53,7 +52,7 @@ function JunctionTree(graph, order::Order, stype::SupernodeType=DEFAULT_SUPERNOD sepval[sepptr[j]:sepptr[j + 1] - 1] = sort!(column) end - JunctionTree(order, stree, partition, sndptr, sepptr, sepval) + JunctionTree(order, stree, sndptr, sepptr, sepval) end diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 89653e5..3ac3bcc 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -77,20 +77,18 @@ function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree:: sndptr = Vector{Int}(undef, treesize(stree) + 1) sepptr = Vector{Int}(undef, treesize(stree) + 1) postorder = Vector{Int}(undef, nv(graph)) - partition = Vector{Int}(undef, nv(graph)) sndptr[1] = sepptr[1] = 1 for (i, j) in enumerate(postorder!(stree)) residual = supernode[j] sndptr[i + 1] = sndptr[i] + length(residual) sepptr[i + 1] = sepptr[i] + colcount[last(residual)] - 1 - partition[sndptr[i]:sndptr[i + 1] - 1] .= i postorder[sndptr[i]:sndptr[i + 1] - 1] = residual end permute!(order, postorder) permute!(graph, postorder) - stree, sndptr, sepptr, partition + stree, sndptr, sepptr end From 0ef1db9f31b12175ac69dd80dedbc7d44532bb27 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 23:50:15 -0500 Subject: [PATCH 092/100] tiny change --- src/junction_trees/fixed_stacks.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/junction_trees/fixed_stacks.jl b/src/junction_trees/fixed_stacks.jl index cf14c8f..c43adf9 100644 --- a/src/junction_trees/fixed_stacks.jl +++ b/src/junction_trees/fixed_stacks.jl @@ -11,12 +11,14 @@ end function Base.push!(stack::FixedStack, v) stack.top[] += 1 stack.items[stack.top[]] = v + v end function Base.pop!(stack::FixedStack) + v = stack.items[stack.top[]] stack.top[] -= 1 - stack.items[stack.top[] + 1] + v end From d58b567e9fdaa40b4ed52ec42edd4f229b11ed42 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Sun, 15 Dec 2024 23:53:05 -0500 Subject: [PATCH 093/100] tiny change --- src/junction_trees/fixed_stacks.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/junction_trees/fixed_stacks.jl b/src/junction_trees/fixed_stacks.jl index c43adf9..0d00e84 100644 --- a/src/junction_trees/fixed_stacks.jl +++ b/src/junction_trees/fixed_stacks.jl @@ -9,7 +9,7 @@ end function Base.push!(stack::FixedStack, v) - stack.top[] += 1 + stack.top .+= 1 stack.items[stack.top[]] = v v end @@ -17,7 +17,7 @@ end function Base.pop!(stack::FixedStack) v = stack.items[stack.top[]] - stack.top[] -= 1 + stack.top .-= 1 v end From 2d1aaab00033b9d4ba47d83e1551ead9e9eab993 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 16 Dec 2024 00:00:19 -0500 Subject: [PATCH 094/100] size hints --- src/junction_trees/supernode_types.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 3ac3bcc..8f1b5e0 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -39,9 +39,9 @@ struct Fundamental <: SupernodeType end function pothensun(etree::Tree, colcount::AbstractVector, stype::SupernodeType) n = treesize(etree) new_in_clique = Vector{Int}(undef, n) - new = Vector{Int}[] - parent = Int[] - first_anc = Int[] + new = sizehint!(Vector{Int}[], n) + parent = sizehint!(Int[], n) + first_anc = sizehint!(Int[], n) i = 0 From 33de42bc203960bcb365cecdac42243ce339bf81 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 16 Dec 2024 00:40:28 -0500 Subject: [PATCH 095/100] removed a variable --- src/junction_trees/elimination_algorithms.jl | 6 +++--- src/junction_trees/supernode_types.jl | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index ad21c39..1059ec0 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -143,12 +143,12 @@ function mcs(graph::AbstractSparseMatrixCSC) n = size(graph, 1) α = Order(undef, n) len = Vector{Int}(undef, n) - set = Vector{LinkedLists.LinkedList{Int}}(undef, n) - pointer = Vector{LinkedLists.ListNode{Int}}(undef, n) + set = Vector{LinkedList{Int}}(undef, n) + pointer = Vector{ListNode{Int}}(undef, n) for i in 1:n len[i] = 1 - set[i] = LinkedLists.LinkedList{Int}() + set[i] = LinkedList{Int}() pointer[i] = push!(set[1], i) end diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 8f1b5e0..4134cea 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -43,8 +43,6 @@ function pothensun(etree::Tree, colcount::AbstractVector, stype::SupernodeType) parent = sizehint!(Int[], n) first_anc = sizehint!(Int[], n) - i = 0 - for v in 1:n u = child_in_supernode(etree, colcount, stype, v) @@ -52,7 +50,7 @@ function pothensun(etree::Tree, colcount::AbstractVector, stype::SupernodeType) new_in_clique[v] = new_in_clique[u] push!(new[new_in_clique[v]], v) else - new_in_clique[v] = i += 1 + new_in_clique[v] = length(new) + 1 push!(new, [v]) push!(parent, 0) push!(first_anc, 0) From 6271a324bf7b329ee89471112bda6cf2a3ae2080 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 16 Dec 2024 01:28:55 -0500 Subject: [PATCH 096/100] commented out first_anc --- src/junction_trees/supernode_types.jl | 44 ++++++++++++++++----------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 4134cea..2497446 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -39,53 +39,63 @@ struct Fundamental <: SupernodeType end function pothensun(etree::Tree, colcount::AbstractVector, stype::SupernodeType) n = treesize(etree) new_in_clique = Vector{Int}(undef, n) - new = sizehint!(Vector{Int}[], n) + new_first = sizehint!(Int[], n) + new_last = sizehint!(Int[], n) parent = sizehint!(Int[], n) - first_anc = sizehint!(Int[], n) + # first_anc = sizehint!(Int[], n) for v in 1:n u = child_in_supernode(etree, colcount, stype, v) if !isnothing(u) new_in_clique[v] = new_in_clique[u] - push!(new[new_in_clique[v]], v) + new_last[new_in_clique[v]] = v else - new_in_clique[v] = length(new) + 1 - push!(new, [v]) + new_in_clique[v] = length(new_first) + 1 + push!(new_first, v) + push!(new_last, v) push!(parent, 0) - push!(first_anc, 0) + # push!(first_anc, 0) end for s in childindices(etree, v) if s !== u parent[new_in_clique[s]] = new_in_clique[v] - first_anc[new_in_clique[s]] = v + # first_anc[new_in_clique[s]] = v end end end - new, Tree(parent) + new_first, new_last, Tree(parent) end function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree::Tree=etree!(order, graph)) rowcount, colcount = supcnt(graph, etree) - supernode, stree = pothensun(etree, colcount, stype) - + new_first, new_last, stree = pothensun(etree, colcount, stype) + sndptr = Vector{Int}(undef, treesize(stree) + 1) sepptr = Vector{Int}(undef, treesize(stree) + 1) - postorder = Vector{Int}(undef, nv(graph)) + sndval = Vector{Int}(undef, nv(graph)) sndptr[1] = sepptr[1] = 1 for (i, j) in enumerate(postorder!(stree)) - residual = supernode[j] - sndptr[i + 1] = sndptr[i] + length(residual) - sepptr[i + 1] = sepptr[i] + colcount[last(residual)] - 1 - postorder[sndptr[i]:sndptr[i + 1] - 1] = residual + sndptr[i + 1] = sndptr[i] + colcount[new_first[j]] - colcount[new_last[j]] + 1 + sepptr[i + 1] = sepptr[i] + colcount[new_last[j]] - 1 + + k = new_first[j] + l = sndptr[i] + sndval[l] = k + + while k != new_last[j] + k = parentindex(etree, k) + l += 1 + sndval[l] = k + end end - permute!(order, postorder) - permute!(graph, postorder) + permute!(order, sndval) + permute!(graph, sndval) stree, sndptr, sepptr end From 25b3337cf000c5d9502a7bc7ee23f601fa9bea1c Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 16 Dec 2024 01:57:07 -0500 Subject: [PATCH 097/100] tests passing --- src/junction_trees/supernode_types.jl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index 2497446..d1a70fb 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -80,18 +80,18 @@ function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree:: sndptr[1] = sepptr[1] = 1 for (i, j) in enumerate(postorder!(stree)) - sndptr[i + 1] = sndptr[i] + colcount[new_first[j]] - colcount[new_last[j]] + 1 - sepptr[i + 1] = sepptr[i] + colcount[new_last[j]] - 1 - - k = new_first[j] - l = sndptr[i] - sndval[l] = k - - while k != new_last[j] - k = parentindex(etree, k) - l += 1 - sndval[l] = k + v = new_first[j] + p = sndptr[i] + sndval[p] = v + + while v != new_last[j] + v = parentindex(etree, v) + p += 1 + sndval[p] = v end + + sndptr[i + 1] = p + 1 + sepptr[i + 1] = sndptr[i] + sepptr[i] + colcount[new_first[j]] - p - 1 end permute!(order, sndval) From 503ed6da892f389584f7906f68049261444d05eb Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 16 Dec 2024 02:03:28 -0500 Subject: [PATCH 098/100] ancestors back --- src/junction_trees/supernode_types.jl | 30 ++++++++++++--------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/junction_trees/supernode_types.jl b/src/junction_trees/supernode_types.jl index d1a70fb..3085aa0 100644 --- a/src/junction_trees/supernode_types.jl +++ b/src/junction_trees/supernode_types.jl @@ -39,40 +39,37 @@ struct Fundamental <: SupernodeType end function pothensun(etree::Tree, colcount::AbstractVector, stype::SupernodeType) n = treesize(etree) new_in_clique = Vector{Int}(undef, n) - new_first = sizehint!(Int[], n) - new_last = sizehint!(Int[], n) + new = sizehint!(Int[], n) parent = sizehint!(Int[], n) - # first_anc = sizehint!(Int[], n) + ancestor = sizehint!(Int[], n) for v in 1:n u = child_in_supernode(etree, colcount, stype, v) if !isnothing(u) new_in_clique[v] = new_in_clique[u] - new_last[new_in_clique[v]] = v else - new_in_clique[v] = length(new_first) + 1 - push!(new_first, v) - push!(new_last, v) + new_in_clique[v] = length(new) + 1 + push!(new, v) push!(parent, 0) - # push!(first_anc, 0) + push!(ancestor, 0) end for s in childindices(etree, v) if s !== u parent[new_in_clique[s]] = new_in_clique[v] - # first_anc[new_in_clique[s]] = v + ancestor[new_in_clique[s]] = v end end end - new_first, new_last, Tree(parent) + new, ancestor, Tree(parent) end function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree::Tree=etree!(order, graph)) rowcount, colcount = supcnt(graph, etree) - new_first, new_last, stree = pothensun(etree, colcount, stype) + new, ancestor, stree = pothensun(etree, colcount, stype) sndptr = Vector{Int}(undef, treesize(stree) + 1) sepptr = Vector{Int}(undef, treesize(stree) + 1) @@ -80,18 +77,17 @@ function stree!(order::Order, graph::OrderedGraph, stype::SupernodeType, etree:: sndptr[1] = sepptr[1] = 1 for (i, j) in enumerate(postorder!(stree)) - v = new_first[j] + v = new[j] p = sndptr[i] - sndval[p] = v - while v != new_last[j] + while !isnothing(v) && v != ancestor[j] + sndval[p] = v v = parentindex(etree, v) p += 1 - sndval[p] = v end - sndptr[i + 1] = p + 1 - sepptr[i + 1] = sndptr[i] + sepptr[i] + colcount[new_first[j]] - p - 1 + sndptr[i + 1] = p + sepptr[i + 1] = sndptr[i] + sepptr[i] + colcount[new[j]] - p end permute!(order, sndval) From db66855066832c883f58231432ca1d73775daac4 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 16 Dec 2024 02:10:09 -0500 Subject: [PATCH 099/100] imports --- src/JunctionTrees.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index f3d68fa..0764ccd 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -4,7 +4,7 @@ module JunctionTrees import AMD import Catlab.BasicGraphs import CuthillMcKee -import LinkedLists +import LinkedLists: ListNode, LinkedList import Metis import TreeWidthSolver From 42411274ef7c3121699a0538c6d2bf0ce09ecbc9 Mon Sep 17 00:00:00 2001 From: Richard Samuelson Date: Mon, 16 Dec 2024 02:21:01 -0500 Subject: [PATCH 100/100] added symrcm ordering --- Project.toml | 1 + src/JunctionTrees.jl | 3 ++- src/junction_trees/elimination_algorithms.jl | 15 +++++++++++++++ test/JunctionTrees.jl | 15 +++++++++------ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Project.toml b/Project.toml index 7741486..754ea16 100644 --- a/Project.toml +++ b/Project.toml @@ -16,6 +16,7 @@ MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b" PartialFunctions = "570af359-4316-4cb7-8c74-252c00c2016b" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +SymRCM = "286e6d88-80af-4590-acc9-0001b223b9bd" TreeWidthSolver = "7d267fc5-9ace-409f-a54c-cd2374872a55" [compat] diff --git a/src/JunctionTrees.jl b/src/JunctionTrees.jl index 0764ccd..29b5292 100644 --- a/src/JunctionTrees.jl +++ b/src/JunctionTrees.jl @@ -6,6 +6,7 @@ import Catlab.BasicGraphs import CuthillMcKee import LinkedLists: ListNode, LinkedList import Metis +import SymRCM import TreeWidthSolver using AbstractTrees @@ -23,7 +24,7 @@ export Order # Elimination Algorithms -export AMDJL_AMD, CuthillMcKeeJL_RCM, MetisJL_ND, TreeWidthSolverJL_BT, MCS +export AMDJL_AMD, CuthillMcKeeJL_RCM, SymRCMJL_RCM, MetisJL_ND, TreeWidthSolverJL_BT, MCS # Ordered Graphs diff --git a/src/junction_trees/elimination_algorithms.jl b/src/junction_trees/elimination_algorithms.jl index 1059ec0..5721738 100644 --- a/src/junction_trees/elimination_algorithms.jl +++ b/src/junction_trees/elimination_algorithms.jl @@ -3,6 +3,7 @@ A graph elimination algorithm. The options are - [`CuthillMcKeeJL_RCM`](@ref) +- [`SymRCMJL_RCM`](@ref) - [`AMDJL_AMD`](@ref) - [`MetisJL_ND`](@ref) - [`TreeWidthSolverJL_BT`](@ref) @@ -19,6 +20,14 @@ The reverse Cuthill-McKee algorithm. Uses CuthillMckee.jl. struct CuthillMcKeeJL_RCM <: EliminationAlgorithm end +""" + SymRCMJL_RCM <: EliminationAlgorithm + +The reverse Cuthill-McKee algorithm. Uses SymRCM.jl. +""" +struct SymRCMJL_RCM <: EliminationAlgorithm end + + """ AMDJL_AMD <: EliminationAlgorithm @@ -74,6 +83,12 @@ function Order(graph::AbstractMatrix, ealg::CuthillMcKeeJL_RCM) end +function Order(graph::AbstractMatrix, ealg::SymRCMJL_RCM) + order = SymRCM.symrcm(graph) + Order(order) +end + + # Construct an order using the approximate minimum degree algorithm. Uses AMD.jl. function Order(graph::AbstractMatrix, ealg::AMDJL_AMD) order = AMD.symamd(graph) diff --git a/test/JunctionTrees.jl b/test/JunctionTrees.jl index 06b66e0..484cab8 100644 --- a/test/JunctionTrees.jl +++ b/test/JunctionTrees.jl @@ -16,22 +16,25 @@ add_edges!(graph, [1, 1, 1, 1, 2, 2, 5, 5, 6, 6, 7, 7, 7, 10, 10, 10, 10, 12, 12, 12, 12, 15], [3, 4, 5, 15, 3, 4, 9, 16, 9, 16, 8, 9, 15, 11, 13, 14, 17, 13, 14, 16, 17, 17]) -order = JunctionTrees.Order(graph, CuthillMcKeeJL_RCM()) +order = Order(graph, CuthillMcKeeJL_RCM()) @test length(order) == 17 -order = JunctionTrees.Order(graph, AMDJL_AMD()) +order = Order(graph, SymRCMJL_RCM()) @test length(order) == 17 -order = JunctionTrees.Order(graph, MetisJL_ND()) +order = Order(graph, AMDJL_AMD()) @test length(order) == 17 -order = JunctionTrees.Order(graph, TreeWidthSolverJL_BT()) +order = Order(graph, MetisJL_ND()) @test length(order) == 17 -order = JunctionTrees.Order(graph, MCS()) +order = Order(graph, TreeWidthSolverJL_BT()) @test length(order) == 17 -order = JunctionTrees.Order(1:17) +order = Order(graph, MCS()) +@test length(order) == 17 + +order = Order(1:17) @test length(order) == 17 # Figure 4.3