Documentation
¶
Overview ¶
Package gonx is a performance-oriented graph library for Go, in the spirit of Python's networkx but built around dense integer node IDs and a compact, cache-friendly representation.
The library separates mutation from reading. A Builder accumulates nodes and edges, and Builder.Build freezes it into an immutable Graph stored in Compressed Sparse Row (CSR) form. The CSR layout gives zero-copy, O(1) neighbor iteration, which is the dominant access pattern for the simulations and graph metrics this library targets. Digraph and DigraphBuilder are the directed counterparts; a Digraph stores both edge directions in CSR form, so out-neighbors and in-neighbors are equally cheap to walk.
Node IDs are dense integers in the range [0, N). Graphs are unweighted and always simple (no self-loops or duplicate edges). All randomized operations take an explicit *math/rand/v2.Rand so results are fully reproducible; the package never touches a global RNG.
Example ¶
package main
import (
"fmt"
"github.com/LuisLSousa/gonx"
)
func main() {
// Assemble a topology with Builder, then freeze it into an immutable CSR
// Graph for reading.
b := gonx.NewBuilder(4)
b.AddEdge(0, 1)
b.AddEdge(0, 2)
b.AddEdge(2, 3)
g := b.Build()
fmt.Println(g.NumNodes(), g.NumEdges())
fmt.Println(g.Neighbors(0))
fmt.Println(g.HasEdge(1, 2))
}
Output: 4 3 [1 2] false
Index ¶
- Variables
- func NewRand(seed uint64) *rand.Rand
- type Builder
- func (b *Builder) AddEdge(u, v int) bool
- func (b *Builder) AddEdgeUnchecked(u, v int) bool
- func (b *Builder) AddNode() int
- func (b *Builder) Build() *Graph
- func (b *Builder) Degree(u int) int
- func (b *Builder) HasEdge(u, v int) bool
- func (b *Builder) NumEdges() int
- func (b *Builder) NumNodes() int
- func (b *Builder) RemoveEdge(u, v int) bool
- type Digraph
- func (g *Digraph) Degree(u int) int
- func (g *Digraph) Edges() iter.Seq2[int, int]
- func (g *Digraph) HasEdge(u, v int) bool
- func (g *Digraph) InDegree(u int) int
- func (g *Digraph) InNeighbors(u int) []int32
- func (g *Digraph) InNeighborsSeq(u int) iter.Seq[int]
- func (g *Digraph) Nodes() iter.Seq[int]
- func (g *Digraph) NumEdges() int
- func (g *Digraph) NumNodes() int
- func (g *Digraph) OutDegree(u int) int
- func (g *Digraph) OutNeighbors(u int) []int32
- func (g *Digraph) OutNeighborsSeq(u int) iter.Seq[int]
- func (g *Digraph) RandomInNeighbor(u int, r *rand.Rand) (v int, ok bool)
- func (g *Digraph) RandomOutNeighbor(u int, r *rand.Rand) (v int, ok bool)
- func (g *Digraph) ToBuilder() *DigraphBuilder
- type DigraphBuilder
- func (b *DigraphBuilder) AddEdge(u, v int) bool
- func (b *DigraphBuilder) AddEdgeUnchecked(u, v int) bool
- func (b *DigraphBuilder) AddNode() int
- func (b *DigraphBuilder) Build() *Digraph
- func (b *DigraphBuilder) HasEdge(u, v int) bool
- func (b *DigraphBuilder) InDegree(u int) int
- func (b *DigraphBuilder) NumEdges() int
- func (b *DigraphBuilder) NumNodes() int
- func (b *DigraphBuilder) OutDegree(u int) int
- func (b *DigraphBuilder) RemoveEdge(u, v int) bool
- type Graph
- func (g *Graph) Degree(u int) int
- func (g *Graph) Edges() iter.Seq2[int, int]
- func (g *Graph) HasEdge(u, v int) bool
- func (g *Graph) Neighbors(u int) []int32
- func (g *Graph) NeighborsSeq(u int) iter.Seq[int]
- func (g *Graph) Nodes() iter.Seq[int]
- func (g *Graph) NumEdges() int
- func (g *Graph) NumNodes() int
- func (g *Graph) RandomNeighbor(u int, r *rand.Rand) (v int, ok bool)
- func (g *Graph) ToBuilder() *Builder
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidParam indicates a generator, transform, or metric was given // parameters it cannot work with (e.g. odd degree for Watts-Strogatz). ErrInvalidParam = errors.New("gonx: invalid parameter") // ErrNotPermutation indicates a relabeling slice is not a permutation of [0, N). ErrNotPermutation = errors.New("gonx: not a permutation of node ids") )
Sentinel errors returned by constructors and algorithms. Wrap-friendly: callers may test with errors.Is.
Functions ¶
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder is a mutable undirected graph used to assemble a topology before freezing it into an immutable Graph. It is not safe for concurrent use.
Edge methods (AddEdge, RemoveEdge, HasEdge) treat out-of-range endpoints as absent edges and report false; Degree panics on an out-of-range node.
func NewBuilder ¶
NewBuilder returns a Builder with n isolated nodes (IDs 0..n-1). It panics if n exceeds 2^31-1, the maximum node count supported by the int32 CSR layout.
func (*Builder) AddEdge ¶
AddEdge inserts the undirected edge {u, v}. It returns false (and does nothing) for self-loops, out-of-range endpoints, or edges that already exist, so the resulting graph is always simple.
func (*Builder) AddEdgeUnchecked ¶
AddEdgeUnchecked inserts the undirected edge {u, v} without checking whether it already exists. Endpoints are still validated and self-loops rejected (returning false), but inserting an edge that is already present corrupts the Builder: the graph silently becomes a multigraph with a double-counted NumEdges. Use it only when each pair is known to be produced at most once — e.g. generators that enumerate pairs with u < v — where skipping the duplicate scan turns dense O(n*m) builds into O(m).
func (*Builder) AddNode ¶
AddNode appends a new isolated node and returns its ID. It panics if the node count would exceed 2^31-1.
func (*Builder) Build ¶
Build freezes the Builder into an immutable CSR Graph. Neighbor lists are sorted so the resulting Graph supports binary-search edge tests and has a canonical, deterministic layout. The Builder may be reused afterwards.
Build panics if the total adjacency size (2 * edges) exceeds 2^31-1, the capacity of the int32 CSR offsets.
func (*Builder) Degree ¶
Degree returns the number of neighbors of u. It panics if u is out of range.
func (*Builder) RemoveEdge ¶
RemoveEdge deletes the undirected edge {u, v}, returning whether it existed.
type Digraph ¶ added in v1.1.0
type Digraph struct {
// contains filtered or unexported fields
}
Digraph is an immutable, directed, unweighted graph stored in Compressed Sparse Row form, twice: the out-neighbors of node u occupy outData[outOffsets[u]:outOffsets[u+1]] and its in-neighbors mirror that in a second CSR, both sorted ascending. Storing both directions costs 2x the edge memory and buys O(1) access from either end, which is what reverse-flow algorithms (PageRank pulls rank from in-neighbors) and "who links here" queries need. A Digraph is safe for concurrent reads.
In networkx terms, OutNeighbors are a node's successors and InNeighbors its predecessors.
Accessors that take a node ID panic with a descriptive message when the ID is outside [0, N); HasEdge is the exception and reports false for out-of-range endpoints. The zero value is not a valid Digraph; obtain one from DigraphBuilder.Build.
Example ¶
package main
import (
"fmt"
"github.com/LuisLSousa/gonx"
)
func main() {
// A tiny citation graph: later papers cite earlier ones. Direction
// matters, and a Digraph keeps both adjacency directions, so asking
// "whom does 3 cite?" and "who cites 0?" are equally cheap.
b := gonx.NewDigraphBuilder(4)
b.AddEdge(1, 0)
b.AddEdge(2, 0)
b.AddEdge(3, 0)
b.AddEdge(3, 2)
g := b.Build()
fmt.Println(g.OutNeighbors(3)) // what 3 cites
fmt.Println(g.InNeighbors(0)) // who cites 0
fmt.Println(g.HasEdge(3, 2), g.HasEdge(2, 3))
}
Output: [0 2] [1 2 3] true false
func (*Digraph) Degree ¶ added in v1.1.0
Degree returns InDegree(u) + OutDegree(u), matching networkx's DiGraph.degree. It panics if u is out of range.
func (*Digraph) Edges ¶ added in v1.1.0
Edges iterates over each directed edge exactly once as (u, v), ordered by source and then by target.
func (*Digraph) HasEdge ¶ added in v1.1.0
HasEdge reports whether the directed edge u->v exists. It binary-searches the shorter of u's out-list and v's in-list, so it runs in O(log deg).
func (*Digraph) InDegree ¶ added in v1.1.0
InDegree returns the number of incoming edges of u. It panics if u is out of range.
func (*Digraph) InNeighbors ¶ added in v1.1.0
InNeighbors returns the sources of u's incoming edges as a sorted, zero-copy slice into the graph's backing storage. Callers MUST NOT modify the returned slice. It panics if u is out of range.
func (*Digraph) InNeighborsSeq ¶ added in v1.1.0
InNeighborsSeq iterates over the sources of u's incoming edges in ascending order as ints. Hot paths should prefer Digraph.InNeighbors, which exposes the backing slice with no per-element call overhead. It panics if u is out of range.
func (*Digraph) OutDegree ¶ added in v1.1.0
OutDegree returns the number of outgoing edges of u. It panics if u is out of range.
func (*Digraph) OutNeighbors ¶ added in v1.1.0
OutNeighbors returns the targets of u's outgoing edges as a sorted, zero-copy slice into the graph's backing storage. Callers MUST NOT modify the returned slice. It panics if u is out of range.
func (*Digraph) OutNeighborsSeq ¶ added in v1.1.0
OutNeighborsSeq iterates over the targets of u's outgoing edges in ascending order as ints. Hot paths should prefer Digraph.OutNeighbors, which exposes the backing slice with no per-element call overhead. It panics if u is out of range.
Example ¶
package main
import (
"fmt"
"github.com/LuisLSousa/gonx"
)
func main() {
b := gonx.NewDigraphBuilder(4)
b.AddEdge(0, 3)
b.AddEdge(0, 1)
sum := 0
g := b.Build()
for v := range g.OutNeighborsSeq(0) {
sum += v
}
fmt.Println(sum)
}
Output: 4
func (*Digraph) RandomInNeighbor ¶ added in v1.1.0
RandomInNeighbor returns a uniformly random source of u's incoming edges. ok is false when u has none. It panics if u is out of range.
func (*Digraph) RandomOutNeighbor ¶ added in v1.1.0
RandomOutNeighbor returns a uniformly random target of u's outgoing edges. ok is false when u has none. It panics if u is out of range.
func (*Digraph) ToBuilder ¶ added in v1.1.0
func (g *Digraph) ToBuilder() *DigraphBuilder
ToBuilder returns a mutable copy of the graph.
type DigraphBuilder ¶ added in v1.1.0
type DigraphBuilder struct {
// contains filtered or unexported fields
}
DigraphBuilder is a mutable directed graph used to assemble a topology before freezing it into an immutable Digraph. It is not safe for concurrent use.
Like Builder, it keeps the graph simple: self-loops and duplicate edges are rejected. The directed edge u->v and its reverse v->u are distinct edges and may coexist.
Edge methods (AddEdge, RemoveEdge, HasEdge) treat out-of-range endpoints as absent edges and report false; the degree accessors panic on an out-of-range node.
func NewDigraphBuilder ¶ added in v1.1.0
func NewDigraphBuilder(n int) *DigraphBuilder
NewDigraphBuilder returns a DigraphBuilder with n isolated nodes (IDs 0..n-1). It panics if n exceeds 2^31-1, the maximum node count supported by the int32 CSR layout.
func (*DigraphBuilder) AddEdge ¶ added in v1.1.0
func (b *DigraphBuilder) AddEdge(u, v int) bool
AddEdge inserts the directed edge u->v. It returns false (and does nothing) for self-loops, out-of-range endpoints, or edges that already exist, so the resulting graph is always simple. Inserting v->u afterwards is a distinct edge and succeeds.
func (*DigraphBuilder) AddEdgeUnchecked ¶ added in v1.1.0
func (b *DigraphBuilder) AddEdgeUnchecked(u, v int) bool
AddEdgeUnchecked inserts the directed edge u->v without checking whether it already exists. Endpoints are still validated and self-loops rejected (returning false), but inserting an edge that is already present corrupts the Builder: the graph silently becomes a multigraph with a double-counted NumEdges. Use it only when each ordered pair is known to be produced at most once, where skipping the duplicate scan turns dense O(n*m) builds into O(m).
func (*DigraphBuilder) AddNode ¶ added in v1.1.0
func (b *DigraphBuilder) AddNode() int
AddNode appends a new isolated node and returns its ID. It panics if the node count would exceed 2^31-1.
func (*DigraphBuilder) Build ¶ added in v1.1.0
func (b *DigraphBuilder) Build() *Digraph
Build freezes the Builder into an immutable CSR Digraph, materializing both adjacency directions: the out-lists directly, the in-lists by a counting pass over them. Both are sorted, so the resulting Digraph supports binary-search edge tests and has a canonical, deterministic layout. The Builder may be reused afterwards.
Build panics if the edge count exceeds 2^31-1, the capacity of the int32 CSR offsets.
func (*DigraphBuilder) HasEdge ¶ added in v1.1.0
func (b *DigraphBuilder) HasEdge(u, v int) bool
HasEdge reports whether the directed edge u->v exists. O(outdeg(u)).
func (*DigraphBuilder) InDegree ¶ added in v1.1.0
func (b *DigraphBuilder) InDegree(u int) int
InDegree returns the number of incoming edges of u. It panics if u is out of range.
func (*DigraphBuilder) NumEdges ¶ added in v1.1.0
func (b *DigraphBuilder) NumEdges() int
NumEdges reports the number of directed edges.
func (*DigraphBuilder) NumNodes ¶ added in v1.1.0
func (b *DigraphBuilder) NumNodes() int
NumNodes reports the number of nodes.
func (*DigraphBuilder) OutDegree ¶ added in v1.1.0
func (b *DigraphBuilder) OutDegree(u int) int
OutDegree returns the number of outgoing edges of u. It panics if u is out of range.
func (*DigraphBuilder) RemoveEdge ¶ added in v1.1.0
func (b *DigraphBuilder) RemoveEdge(u, v int) bool
RemoveEdge deletes the directed edge u->v, returning whether it existed. The reverse edge v->u, if present, is unaffected.
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is an immutable, undirected, unweighted graph stored in Compressed Sparse Row form. The neighbors of node u occupy data[offsets[u]:offsets[u+1]] and are sorted ascending. A Graph is safe for concurrent reads. The zero value is not a valid Graph; obtain one from Builder.Build.
Accessors that take a node ID (Degree, Neighbors, NeighborsSeq, RandomNeighbor) panic with a descriptive message when the ID is outside [0, N); HasEdge is the exception and reports false for out-of-range endpoints.
func (*Graph) Edges ¶
Edges iterates over each undirected edge exactly once as (u, v) with u < v.
Example ¶
package main
import (
"fmt"
"github.com/LuisLSousa/gonx"
)
func main() {
b := gonx.NewBuilder(3)
b.AddEdge(0, 1)
b.AddEdge(1, 2)
g := b.Build()
for u, v := range g.Edges() {
fmt.Println(u, v)
}
}
Output: 0 1 1 2
func (*Graph) HasEdge ¶
HasEdge reports whether the undirected edge {u, v} exists. It uses binary search over the smaller-degree endpoint, so it runs in O(log deg).
func (*Graph) Neighbors ¶
Neighbors returns u's neighbor IDs as a sorted, zero-copy slice into the graph's backing storage. Callers MUST NOT modify the returned slice. It panics if u is out of range.
func (*Graph) NeighborsSeq ¶
NeighborsSeq iterates over u's neighbors in ascending order as ints. It is a convenience wrapper over Graph.Neighbors for callers who want int node IDs end-to-end; hot paths should prefer Neighbors, which exposes the backing slice with no per-element call overhead. It panics if u is out of range.
Example ¶
package main
import (
"fmt"
"github.com/LuisLSousa/gonx"
)
func main() {
b := gonx.NewBuilder(3)
b.AddEdge(0, 2)
b.AddEdge(0, 1)
g := b.Build()
for v := range g.NeighborsSeq(0) {
fmt.Println(v)
}
}
Output: 1 2
func (*Graph) RandomNeighbor ¶
RandomNeighbor returns a uniformly random neighbor of u. ok is false when u is isolated. It panics if u is out of range.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
communities
command
Renders a planted-partition graph for the README gallery: four dense communities joined by sparse bridges, built directly with gonx.Builder and colored by community.
|
Renders a planted-partition graph for the README gallery: four dense communities joined by sparse bridges, built directly with gonx.Builder and colored by community. |
|
internal/render
Package render lays out gonx graphs and writes them as self-contained SVG images.
|
Package render lays out gonx graphs and writes them as self-contained SVG images. |
|
karate
command
Renders Zachary's Karate Club — the classic 34-node social network from Zachary (1977) — for the README gallery.
|
Renders Zachary's Karate Club — the classic 34-node social network from Zachary (1977) — for the README gallery. |
|
scalefree
command
Renders a Barabási–Albert scale-free network for the README gallery.
|
Renders a Barabási–Albert scale-free network for the README gallery. |
|
smallworld
command
Renders a Watts–Strogatz small-world network for the README gallery.
|
Renders a Watts–Strogatz small-world network for the README gallery. |
|
Package generators builds graphs from classic random-graph models.
|
Package generators builds graphs from classic random-graph models. |
|
internal
|
|
|
pool
Package pool provides a minimal static work-partitioning helper used by the parallel graph metrics.
|
Package pool provides a minimal static work-partitioning helper used by the parallel graph metrics. |
|
Package metrics computes structural graph properties: clustering, connectivity, and shortest-path-based measures.
|
Package metrics computes structural graph properties: clustering, connectivity, and shortest-path-based measures. |
|
Package transform contains structure-preserving and structure-randomizing graph transformations: copying, relabeling, and degree-preserving edge swaps.
|
Package transform contains structure-preserving and structure-randomizing graph transformations: copying, relabeling, and degree-preserving edge swaps. |