Documentation
¶
Overview ¶
Package centrality implements vertex importance metrics. v1 carries Brandes' betweenness centrality and the PageRank family (T61/T62 sister tasks).
Index ¶
- Variables
- func Betweenness[W any](c *csr.CSR[W]) []float64
- func BetweennessCtx[W any](ctx context.Context, c *csr.CSR[W]) ([]float64, error)
- func BetweennessParallel[W any](c *csr.CSR[W], numWorkers int) []float64
- func BetweennessParallelCtx[W any](ctx context.Context, c *csr.CSR[W], numWorkers int) ([]float64, error)
- func PageRank[W any](c *csr.CSR[W], opts PageRankOptions) (ranks []float64, iterations int, err error)
- func PageRankCtx[W any](ctx context.Context, c *csr.CSR[W], opts PageRankOptions) (ranks []float64, iterations int, err error)
- func PersonalisedPushPageRank[W any](c *csr.CSR[W], src graph.NodeID, opts PPRPushOptions) ([]float64, error)
- func PersonalisedPushPageRankCtx[W any](ctx context.Context, c *csr.CSR[W], src graph.NodeID, opts PPRPushOptions) ([]float64, error)
- func WeightedBetweenness(c *csr.CSR[float64]) ([]float64, error)
- func WeightedBetweennessCtx(ctx context.Context, c *csr.CSR[float64]) ([]float64, error)
- type PPRPushOptions
- type PageRankOptions
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidInput = errors.New("centrality: input option contains NaN or Inf")
ErrInvalidInput is returned by centrality algorithms when their float options carry NaN or +/-Inf. Non-finite inputs propagate through the power iteration / push loops and silently corrupt the rank vector; validating once at entry is mandatory.
Functions ¶
func Betweenness ¶
Betweenness computes the exact betweenness centrality of every node in c using Brandes' algorithm (2001). Returns a slice indexed by NodeID. Unweighted: O(V * E).
The result is not normalised — callers can divide by (n-1)(n-2)/2 (undirected) or (n-1)(n-2) (directed) for the classical normalised score.
Example ¶
ExampleBetweenness computes (non-normalised) betweenness centrality on an undirected path 0-1-2. Every shortest path between the two ends runs through the middle node, so node 1 carries all the betweenness while the endpoints carry none.
package main
import (
"fmt"
"github.com/FlavioCFOliveira/GoGraph/graph/adjlist"
"github.com/FlavioCFOliveira/GoGraph/graph/csr"
"github.com/FlavioCFOliveira/GoGraph/search/centrality"
)
func main() {
// Undirected path: 0 - 1 - 2.
a := adjlist.New[int, struct{}](adjlist.Config{Directed: false})
_ = a.AddEdge(0, 1, struct{}{})
_ = a.AddEdge(1, 2, struct{}{})
c := csr.BuildFromAdjList(a)
m := a.Mapper()
bc := centrality.Betweenness(c)
for v := 0; v < 3; v++ {
id, _ := m.Lookup(v)
fmt.Printf("node %d betweenness = %.1f\n", v, bc[id])
}
}
Output: node 0 betweenness = 0.0 node 1 betweenness = 2.0 node 2 betweenness = 0.0
func BetweennessCtx ¶
BetweennessCtx is the context-aware variant of Betweenness. ctx.Err() is checked once per source vertex; on cancellation returns (nil, wrapped ctx.Err()).
func BetweennessParallel ¶
BetweennessParallel computes the exact (unweighted) betweenness centrality of every NodeID in c using the Brandes algorithm parallelised across sources. Each worker goroutine processes a disjoint range of source vertices, accumulating into its own private centrality buffer; the final reduction sums these buffers into the returned slice. Output is bit-identical to Betweenness (the order of additions is deterministic).
numWorkers <= 0 picks runtime.GOMAXPROCS(0). For tiny graphs (V below ~1024) the parallel overhead dominates and the serial Betweenness is preferable.
func BetweennessParallelCtx ¶
func BetweennessParallelCtx[W any](ctx context.Context, c *csr.CSR[W], numWorkers int) ([]float64, error)
BetweennessParallelCtx is the context-aware variant of BetweennessParallel. ctx cancellation is checked once per source vertex inside every worker; on cancellation returns (nil, wrapped ctx.Err()).
func PageRank ¶
func PageRank[W any](c *csr.CSR[W], opts PageRankOptions) (ranks []float64, iterations int, err error)
PageRank runs the in-memory power-iteration form of PageRank over c and returns the per-NodeID rank slice plus the iteration count to convergence (capped at MaxIterations).
The returned slice has length c.MaxNodeID(); only NodeIDs that participate in at least one edge (live nodes) carry non-zero rank. The sum over the slice equals 1.0 within numerical tolerance.
Concurrency: PageRank is safe to invoke from any number of goroutines on a snapshot CSR; the function allocates its working buffers per call and does not share state.
Algorithm. The implementation is the textbook power-iteration form with proper handling of dangling nodes (nodes with out-degree 0): at each iteration the mass currently held by dangling nodes is redistributed uniformly across all live nodes, modelling them as teleporting their entire share back into the system. This ensures total mass is conserved and the result is a true stationary distribution.
Example ¶
ExamplePageRank ranks the nodes of a directed star where five leaves all point at one sink. The sink accumulates the dominant share of the stationary mass; the five leaves are symmetric and share the remainder equally. Ranks are rounded to four decimals for a stable, deterministic comparison.
package main
import (
"fmt"
"github.com/FlavioCFOliveira/GoGraph/graph/adjlist"
"github.com/FlavioCFOliveira/GoGraph/graph/csr"
"github.com/FlavioCFOliveira/GoGraph/search/centrality"
)
func main() {
// Leaves 1..5 each point at sink 0.
a := adjlist.New[int, struct{}](adjlist.Config{Directed: true})
for leaf := 1; leaf <= 5; leaf++ {
_ = a.AddEdge(leaf, 0, struct{}{})
}
c := csr.BuildFromAdjList(a)
m := a.Mapper()
ranks, _, err := centrality.PageRank(c, centrality.DefaultPageRankOptions())
if err != nil {
fmt.Println("error:", err)
return
}
sink, _ := m.Lookup(0)
leaf, _ := m.Lookup(1)
fmt.Printf("sink rank = %.4f\n", ranks[sink])
fmt.Printf("leaf rank = %.4f\n", ranks[leaf])
}
Output: sink rank = 0.5122 leaf rank = 0.0976
func PageRankCtx ¶
func PageRankCtx[W any](ctx context.Context, c *csr.CSR[W], opts PageRankOptions) (ranks []float64, iterations int, err error)
PageRankCtx is the context-aware variant of PageRank. ctx.Err() is checked at every iteration boundary; on cancellation returns (nil, 0, wrapped ctx.Err()).
func PersonalisedPushPageRank ¶
func PersonalisedPushPageRank[W any](c *csr.CSR[W], src graph.NodeID, opts PPRPushOptions) ([]float64, error)
PersonalisedPushPageRank computes the personalised PageRank vector seeded at src using the local-push algorithm (Andersen-Chung-Lang, FOCS 2006). Returns the rank vector indexed by NodeID.
The algorithm pays only for the edges it touches, so on large graphs with a small high-probability cluster it runs in roughly O(1/epsilon) time rather than O(V+E).
Dangling-node handling matches the ACL paper: residue at a node with out-degree 0 is teleported back to src (probability alpha) rather than redistributed to non-existent neighbours. This keeps the rank vector summing to 1 within numerical tolerance.
Concurrency: safe to invoke from any number of goroutines on a shared CSR.
func PersonalisedPushPageRankCtx ¶
func PersonalisedPushPageRankCtx[W any](ctx context.Context, c *csr.CSR[W], src graph.NodeID, opts PPRPushOptions) ([]float64, error)
PersonalisedPushPageRankCtx is the context-aware variant of PersonalisedPushPageRank. ctx.Err() is checked every 4096 worklist pops; on cancellation returns (nil, wrapped ctx.Err()).
func WeightedBetweenness ¶
WeightedBetweenness computes the weighted betweenness centrality of every NodeID in c using Dijkstra-augmented Brandes (Brandes 2001 §3, weighted variant). Edge weights must be finite and non-negative.
Complexity is O(V * (E log V)) for binary-heap-backed Dijkstra per source. The result is not normalised; callers wanting the classical 1 / ((n-1)(n-2)) factor can divide externally.
Input contract. Returns ErrInvalidInput when any edge weight is NaN or +/-Inf; returns the global sentinel search.ErrNegativeWeight when any edge weight is strictly negative.
Concurrency: WeightedBetweenness is safe to invoke concurrently on a shared CSR.
func WeightedBetweennessCtx ¶
WeightedBetweennessCtx is the context-aware variant of WeightedBetweenness. ctx.Err() is checked once per source vertex; on cancellation returns (nil, wrapped ctx.Err()).
Types ¶
type PPRPushOptions ¶
type PPRPushOptions struct {
// Damping is the random-jump probability (alpha; typical 0.85).
Damping float64
// Epsilon stops propagation when residue/outdeg falls below it.
Epsilon float64
// MaxSteps caps the number of push operations for safety.
MaxSteps int
}
PPRPushOptions controls PersonalisedPushPageRank.
func DefaultPPRPushOptions ¶
func DefaultPPRPushOptions() PPRPushOptions
DefaultPPRPushOptions returns the Andersen-Chung-Lang reference parameters (damping 0.85, epsilon 1e-6, max 1e7 steps).
type PageRankOptions ¶
PageRankOptions configures PageRank.
func DefaultPageRankOptions ¶
func DefaultPageRankOptions() PageRankOptions
DefaultPageRankOptions returns the classic Brin-Page parameters (damping 0.85, max 100 iterations, tolerance 1e-6).