Getting Started

Installation

nimble install nimnet

Or add to your .nimble file:

requires "nimnet >= 0.1.0"

Requirements

  • Nim >= 2.0.0

Your first graph

Undirected graph

import nimnet

# Create an empty undirected graph with int nodes
var g = newGraph[int]()

# Add nodes individually or in batch
g.addNode(1)
g.addNodesFrom([2, 3, 4, 5])

# Add edges
g.addEdge(1, 2)
g.addEdgesFrom([(2, 3), (3, 4), (4, 5), (5, 1)])

# Nim-idiomatic access
assert 1 in g           # contains operator
assert g.len == 5       # number of nodes
assert g[1].len == 2    # neighbors of node 1

echo g  # Graph(nodes=5, edges=5)

Directed graph

import nimnet

var dg = newDiGraph[string]()
dg.addEdge("A", "B")
dg.addEdge("B", "C")
dg.addEdge("C", "A")

assert dg.hasEdge("A", "B")
assert not dg.hasEdge("B", "A")  # directed!

echo dg.outDegree("A")  # 1
echo dg.inDegree("A")   # 1

Weighted edges

import nimnet

var g = newGraph[int]()
g.addWeightedEdge(1, 2, 3.5)
g.addWeightedEdgesFrom([(2, 3, 1.0), (3, 4, 2.5)])

echo g.weight(1, 2)  # 3.5

Using string nodes

import nimnet

var social = newGraph[string]()
social.addEdgesFrom([
  ("Alice", "Bob"),
  ("Bob", "Charlie"),
  ("Charlie", "Alice")
])

for friend in social.neighbors("Alice"):
  echo friend  # Bob, Charlie

Graph algorithms

import nimnet

var g = newGraph[int]()
g.addEdgesFrom([(1,2), (2,3), (3,4), (4,5)])

# Shortest path (BFS)
let path = shortestPath(g, 1, 5)
echo path  # @[1, 2, 3, 4, 5]

# Connected components
for comp in connectedComponents(g):
  echo comp

# Degree centrality
let dc = degreeCentrality(g)
for node, centrality in dc:
  echo node, ": ", centrality

Graph generators

import nimnet

# Classic graphs
let k5 = completeGraph[int](5)
let cycle = cycleGraph[int](10)
let petersen = petersenGraph()

# Random graphs
let er = erdosRenyiGraph[int](100, 0.05)
let ba = barabasiAlbertGraph[int](100, 3)

# Famous graphs
let karate = karateClubGraph()

I/O

import nimnet

var g = newGraph[int]()
g.addEdgesFrom([(1,2), (2,3)])

# DOT format (Graphviz)
writeDot(g, "my_graph.dot")

# Edge list
writeEdgelist(g, "my_graph.edgelist")

# Adjacency list
writeAdjlist(g, "my_graph.adjlist")

# JSON node-link format
writeJsonGraph(g, "my_graph.json")

# GML format
writeGml(g, "my_graph.gml")

# GraphML format
writeGraphml(g, "my_graph.graphml")

# GEXF format (Gephi compatible)
writeGexf(g, "my_graph.gexf")

# Pajek format
writePajek(g, "my_graph.net")

# Graph6 format (compact, for simple graphs)
let g6str = writeGraph6(g)

# SVG visualization (requires a layout)
let pos = circularLayout(g)
writeSvg(g, pos, "my_graph.svg")

Builder DSL

import nimnet

let g = buildGraph[int]:
  nodes [1, 2, 3, 4, 5]
  edges [(1,2), (2,3), (3,4), (4,5), (5,1)]

echo g  # Graph(nodes=5, edges=5)

Built-in datasets

import nimnet

let karate = karateClubGraph()
let dolphins = dolphinsGraph()
let florentine = florentineFamiliesGraph()
let lesmis = lesMiserablesGraph()

MultiGraph (parallel edges)

import nimnet

var mg = newMultiGraph[int]()
let k1 = mg.addEdge(1, 2)  # returns edge key 0
let k2 = mg.addEdge(1, 2)  # returns edge key 1 (parallel edge)
echo mg.numberOfEdges()     # 2

Graph views (lazy, zero-copy)

import nimnet

var g = newGraph[int]()
g.addEdgesFrom([(1,2), (2,3), (3,4)])

# Create a read-only view (no graph copy)
let v = view(g)
echo v.numberOfNodes()  # 3
for n in v.nodes:
  echo n

CompactGraph (CSR, cache-friendly)

import nimnet

var g = newGraph[int]()
g.addEdgesFrom([(0,1), (1,2), (2,0)])

# Convert to compressed sparse row (immutable, fast iteration)
let cg = toCompact(g)
echo cg.numberOfNodes()  # 3

# Convert back
let g2 = toGraph(cg)

Static graph (compile-time construction)

import nimnet

let g = staticGraph[int]([(1,2), (2,3), (3,1)])
let dg = staticDiGraph[int]([(1,2), (2,3)])
let wg = staticWeightedGraph[int]([(1,2, 1.5), (2,3, 2.5)])

Parallel algorithms

NimNet provides parallel versions of heavy algorithms using malebolgia threading:

import nimnet

let g = erdosRenyiGraph(1000, 0.01)

# These run on multiple threads automatically
let pr = parallelPageRank(g)
let bc = parallelBetweennessCentrality(g)
let cc = parallelClosenessCentrality(g)

Next steps

Performance

nimnet is a pure Nim implementation with no C/Fortran dependencies — yet it outperforms Python’s NetworkX (which uses scipy/numpy C backends) on most benchmarks.

Large graph (10,000 nodes, 50,000 edges):

Benchmark NimNet NetworkX Result
Graph creation 0.014s 0.051s NimNet 3.6× faster
BFS traversal 0.008s 0.015s NimNet 1.9× faster
DFS traversal 0.006s 0.010s NimNet 1.7× faster
Dijkstra 0.040s 0.012s NetworkX 3.3× faster
PageRank 0.079s 0.035s NetworkX 2.3× faster*
Connected components 0.006s 0.005s ~1×
MST (Kruskal) 0.077s 0.088s NimNet 1.1× faster

*NetworkX PageRank uses scipy sparse matrix operations (C/Fortran); NimNet is pure Nim.

To reproduce benchmarks, see the benchmarks/ directory.