diff --git a/docs/src/examples.md b/docs/src/examples.md index 3b1798e1..9158b771 100644 --- a/docs/src/examples.md +++ b/docs/src/examples.md @@ -22,6 +22,7 @@ Unless noted otherwise `A` is the adjacency matrix of an undirected graph with ` | Triangle counting (Sandia) | `Sandia.jl` | `sandia(A)` | | | Triangle counting (CMU) | `CMU.jl` | `cmu(A, n)` | | | Triangles per vertex | `NodeWiseTriangleCount.jl` | `nodewise_tc(A)` | | +| Triangle centrality | `triangle_centrality.jl` | `triangle_centrality(A)`, `triangle_centrality1(A)` | `A` has unit weights. | | k-truss | `KTruss.jl` | `ktruss(A, k)` | Returns the truss with edge supports as values. | | BFS parents | `BFSParents.jl` | `bfs_parents(A, s, n)` | The parent of the source is `0`. | | Multi-source BFS parents | `BFSParentsMultiSource.jl` | `ms_bfsp(A, S, n, s)` | Row `i` of the `s × n` matrix `S` marks source `i`. | @@ -29,6 +30,7 @@ Unless noted otherwise `A` is the adjacency matrix of an undirected graph with ` | Bellman-Ford | `BellmanFord.jl` | `bellmanford(A, s, n)` | `A[i,j]` is the weight of edge `i → j`, with explicit zeros on the diagonal. | | Floyd-Warshall | `FloydWarshall.jl` | `floydwarshall(A, n)` | Same input as Bellman-Ford. | | Prim's minimum spanning tree | `BasicPrim.jl`, `AdvancedPrim.jl` | `b_prim(A, n, zeros(n))`, `a_prim(A, n, zeros(n))` | `A` is dense, with `Inf` where there is no edge and zeros on the diagonal. | +| PageRank | `pagerank.jl` | `pagerank(A)` | `A[i,j]` is the edge `i → j`. Returns `(ranks, iterations)`. Ranks of dangling vertices are not redistributed. | | Community detection by label propagation | `CDLP.jl` | `cdlp(A, n, t)` | Runs `t` iterations. Every vertex must have a neighbour. | The graph below has edges `1-2`, `1-3`, `2-3`, `2-4`, `3-4` and `4-5`, and two triangles, `{1,2,3}` and `{2,3,4}`. diff --git a/examples/pagerank.jl b/examples/pagerank.jl index e225188d..08c98fb2 100644 --- a/examples/pagerank.jl +++ b/examples/pagerank.jl @@ -1,6 +1,14 @@ +#= +PageRank (GAP benchmark variant, dangling vertices are not redistributed): +- Reference: https://doi.org/10.1109/HPEC49654.2021.9622789, https://en.wikipedia.org/wiki/PageRank +=# + using SuiteSparseGraphBLAS +using SuiteSparseGraphBLAS: second + +#A is the adjacency matrix (A[i,j] is the edge i->j), d the out-degrees, Output: ranks and number of iterations function pagerank( - A::SuiteSparseGraphBLAS.GBArray, + A, d = reduce(+, A; dims=2), α = 0.85, maxiters = 100, diff --git a/examples/triangle_centrality.jl b/examples/triangle_centrality.jl index 6fab2c6e..81124332 100644 --- a/examples/triangle_centrality.jl +++ b/examples/triangle_centrality.jl @@ -1,15 +1,22 @@ +#= +Triangle centrality: +- Reference: https://arxiv.org/abs/2105.00110, https://doi.org/10.1109/HPEC49654.2021.9622789 +=# + using SuiteSparseGraphBLAS -using SuiteSparseGraphBLAS: pair +using SuiteSparseGraphBLAS: pair, second + +#A is the adjacency matrix of an undirected graph with unit weights, Output: triangle centrality of each vertex function triangle_centrality1(A) T = *(A, A', (+, *), mask=A) y = reduce(+, T, dims=2) k = reduce(+, y) - return (3 * *(A, y) - 2 * *(T, y) .+ y) ./ k + return (3 * *(A, y) - 2 * *(T, y, (+, second)) .+ y) ./ k end function triangle_centrality(A) - T = *(A, A', (+, pair), mask=A, Descriptor(structural_mask=true)) + T = *(A, A', (+, pair), mask=A, desc=Descriptor(structural_mask=true)) y = reduce(+, T, dims=2) k = reduce(+, y) - return (3.0 * *(A, y) .- (2.0 * *(T, y, (+, second))) .+ y) ./ k + return (3.0 * *(A, y) - (2.0 * *(T, y, (+, second))) .+ y) ./ k end diff --git a/test/examples.jl b/test/examples.jl index 730aacc4..3c7e93de 100644 --- a/test/examples.jl +++ b/test/examples.jl @@ -3,7 +3,7 @@ using SuiteSparseGraphBLAS, SparseArrays, LinearAlgebra, Test for f in ["AdvancedPrim", "BasicPrim", "BellmanFord", "BFSLevelsMultiSource", "BFSParents", "BFSParentsMultiSource", "CDLP", "CMU", "Cohen", "FloydWarshall", "KTruss", - "NodeWiseTriangleCount", "Sandia"] + "NodeWiseTriangleCount", "Sandia", "pagerank", "triangle_centrality"] include(joinpath(@__DIR__, "..", "examples", "$f.jl")) end @@ -59,4 +59,16 @@ end @test diag(Matrix(cdlp(T, 6, 2))) == [1, 1, 1, 4, 4, 4] @test diag(Matrix(cdlp(A, 5, 1))) == [2, 1, 1, 2, 4] end + +@testset "centrality" begin + Af = GBMatrix(sym(ones(6))) + # Vertex 5 is in no triangle and only sees the triangles of its neighbour 4. + @test collect(triangle_centrality(Af)) ≈ [5/6, 1, 1, 5/6, 1/2] + @test collect(triangle_centrality1(Af)) ≈ [5/6, 1, 1, 5/6, 1/2] + # PageRank is uniform on a directed cycle, otherwise compare with dense power iteration. + @test collect(pagerank(GBMatrix([1, 2, 3, 4], [2, 3, 4, 1], 1.0))[1]) ≈ fill(0.25, 4) + M = Matrix(sym(ones(6))); x = fill(0.2, 5) + for _ in 1:100; x = 0.15 / 5 .+ 0.85 .* (M' * (x ./ vec(sum(M, dims=2)))); end + @test collect(pagerank(Af)[1]) ≈ x atol=1e-5 +end end