CliqueTrees.jl implements clique trees in Julia. You can use it to construct tree decompositions and chordal completions of graphs.
If you have a question about the library, feel free to open an issue or leave a message in the cliquetrees.jl Zulip channel.
- BandedMatrices.jl
- BayesNets.jl
- CausalInference.jl
- EinExprs.jl
- IncrementalInference.jl
- OMEinsumContractionOrders.jl
- Scruff.jl
- SparseMatrixColorings.jl
- SumOfSquares.jl
- TSSOS.jl
To install CliqueTrees.jl, enter the Pkg REPL by typing ] and run the following command.
pkg> add CliqueTreesThe function cliquetree computes tree decompositions.
julia> using CliqueTrees, LinearAlgebra, SparseArrays
julia> graph = [
0 1 0 0 0 0 0 0
1 0 1 0 0 1 0 0
0 1 0 1 0 1 1 1
0 0 1 0 0 0 0 0
0 0 0 0 0 1 1 0
0 1 1 0 1 0 0 0
0 0 1 0 1 0 0 1
0 0 1 0 0 0 1 0
];
julia> label, tree = cliquetree(graph);
julia> tree
6-element CliqueTree{Int64, Int64}:
[6, 7, 8]
└─ [5, 7, 8]
├─ [1, 5]
├─ [3, 5, 7]
│ └─ [2, 3]
└─ [4, 5, 8]The clique tree tree is a tree decomposition of the permuted graph graph[label, label].
A clique tree is a vector of cliques, so you can retrieve the clique at node 4 by typing tree[4].
julia> tree[4]
3-element Clique{Int64, Int64}:
4
5
8Warning
The numbers in each clique are vertices of the permuted graph graph[label, label].
You can see the vertices of the original graph by typing
julia> label[tree[4]]
3-element Vector{Int64}:
8
3
7Notice that the clique is no longer sorted.
The width of a clique tree is computed by the function treewidth.
julia> treewidth(tree)
2Clique trees can be used to construct chordal completions.
julia> filledgraph = FilledGraph(tree)
{8, 11} FilledGraph{Int64, Int64}
julia> sparse(filledgraph)
8×8 SparseMatrixCSC{Bool, Int64} with 11 stored entries:
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ 1 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
1 ⋅ 1 1 ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ 1 ⋅ 1 1 ⋅ ⋅
⋅ ⋅ ⋅ 1 1 1 1 ⋅The graph filledgraph is ordered: its edges are directed from lower to higher vertices. The underlying undirected graph is a chordal completion of the permuted graph graph[label, label].
julia> chordalgraph = Symmetric(sparse(filledgraph), :L)
8×8 Symmetric{Bool, SparseMatrixCSC{Bool, Int64}}:
⋅ ⋅ ⋅ ⋅ 1 ⋅ ⋅ ⋅
⋅ ⋅ 1 ⋅ ⋅ ⋅ ⋅ ⋅
⋅ 1 ⋅ ⋅ 1 ⋅ 1 ⋅
⋅ ⋅ ⋅ ⋅ 1 ⋅ ⋅ 1
1 ⋅ 1 1 ⋅ ⋅ 1 1
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1 1
⋅ ⋅ 1 ⋅ 1 1 ⋅ 1
⋅ ⋅ ⋅ 1 1 1 1 ⋅
julia> ischordal(graph)
false
julia> ischordal(chordalgraph)
true
julia> all(graph[label, label] .<= chordalgraph)
trueThe function cholesky computes Cholesky factorizations of sparse positive-definite matrices.
julia> import CliqueTrees
julia> matrix = [
3 1 0 0 0 0 0 0
1 3 1 0 0 2 0 0
0 1 3 1 0 1 2 1
0 0 1 3 0 0 0 0
0 0 0 0 3 1 1 0
0 2 1 0 1 3 0 0
0 0 2 0 1 0 3 1
0 0 1 0 0 0 1 3
];
julia> cholfact = CliqueTrees.cholesky(matrix)
CholFact{Float64, Int64}:
nnz: 19
success: trueYou can solve linear systems of equations with the operators
/ and \.
julia> rhs = rand(8, 2);
julia> sol = cholfact \ rhs # sol = inv(matrix) * rhs
8×2 Matrix{Float64}:
-0.202009 -0.164852
0.661177 0.665989
0.173183 -0.126911
0.110932 0.0915613
0.375653 0.187998
-0.556495 -0.378656
-0.0751984 0.0536805
0.0793129 0.127395Users can input graphs as adjacency matrices. Additionally, CliqueTrees.jl supports the HasGraph type from Catlab.jl and the AbstractGraph type from Graphs.jl. Instances of the latter should implement the following subset of the abstract graph interface.
is_directednenvoutneighborsvertices
Self-edges are always ignored.
If you use CliqueTrees.jl for a publication, please cite it as follows.
@misc{cliquetrees2025samuelson,
author = {Samuelson, Richard and Fairbanks, James},
url = {https://github.com/AlgebraicJulia/CliqueTrees.jl},
title = {CliqueTrees.jl: A Julia library for computing tree decompositions and chordal completions of graphs},
year = {2025}
}