built-in graph algorithms available as fixed rules (<~) in datalog. these run native implementations inside the CozoDB query engine — no external libraries, no data export

fixed rules use a distinct arrow: ?[] <~ AlgorithmName(input[], params...). the input is a relation representing edges. the output binds with algorithm-specific columns

centrality

PageRank

stationary distribution of a random walk — probability a random walker lands on each node. directly related to cyberank and diffusion

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, rank] <~ PageRank(edges[], theta: 0.85)
:order -rank
:limit 50

output: [node, rank]. theta is damping (default 0.85). optional epsilon, iterations

DegreeCentrality

in-degree, out-degree, and total degree per node

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, degree, in_deg, out_deg] <~ DegreeCentrality(edges[])
:order -degree

BetweennessCentrality

how often a node lies on shortest paths between all pairs. identifies bridge particles whose removal fragments the cybergraph

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, centrality] <~ BetweennessCentrality(edges[])
:order -centrality

ClosenessCentrality

average shortest-path distance from a node to all reachable nodes

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, centrality] <~ ClosenessCentrality(edges[])
:order -centrality

pathfinding

ShortestPathBFS

unweighted shortest path. output: [path]

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[path] <~ ShortestPathBFS(edges[], "QmParticleA", "QmParticleB")

ShortestPathDijkstra

weighted shortest path for optimal linkchains. output: [path, cost]

edges[from, to, weight] := *cyberlinks{from_particle: from, to_particle: to, weight}
?[path, cost] <~ ShortestPathDijkstra(edges[], "QmParticleA", "QmParticleB")

KShortestPathYen

k alternative shortest paths — multiple linkchains between two particles

edges[from, to, weight] := *cyberlinks{from_particle: from, to_particle: to, weight}
?[path, cost] <~ KShortestPathYen(edges[], "QmParticleA", "QmParticleB", k: 5)

ShortestPathAStar

heuristic-guided search. faster than Dijkstra when a distance estimate is available

edges[from, to, weight] := *cyberlinks{from_particle: from, to_particle: to, weight}
heuristic[node, est] := *particle_embeddings{particle: node, distance_estimate: est}
?[path, cost] <~ ShortestPathAStar(edges[], "QmParticleA", "QmParticleB", heuristic[])

BreadthFirstSearch

traversal from a source with depth tracking. optional limit caps depth

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, depth] <~ BreadthFirstSearch(edges[], "QmStartParticle")

DepthFirstSearch

depth-first traversal — explores deep chains before branching

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, depth] <~ DepthFirstSearch(edges[], "QmStartParticle")

community detection

CommunityDetectionLouvain

maximizes modularity to find topic clusters in the cybergraph — groups of particles densely interlinked but sparsely connected outside. optional resolution controls granularity

edges[from, to, weight] := *cyberlinks{from_particle: from, to_particle: to, weight}
?[node, community_id] <~ CommunityDetectionLouvain(edges[])

LabelPropagation

faster community detection. each node adopts the majority label of its neighbors

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, label] <~ LabelPropagation(edges[])

ClusteringCoefficients

fraction of a node's neighbors also connected to each other

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, coeff] <~ ClusteringCoefficients(edges[])
:order -coeff

connectedness

ConnectedComponents

connected subgraphs. reveals isolated knowledge islands

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, component_id] <~ ConnectedComponents(edges[])

StronglyConnectedComponent

subsets where every node reaches every other. required for tri-kernel convergence: cyberank stationary distribution exists when the graph is strongly connected or has teleport structure

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, scc_id] <~ StronglyConnectedComponent(edges[])

MinimumSpanningForestKruskal

minimum spanning forest. Prim's variant (MinimumSpanningTreePrim) accepts a root node

edges[from, to, weight] := *cyberlinks{from_particle: from, to_particle: to, weight}
?[from, to, weight] <~ MinimumSpanningForestKruskal(edges[])

TopSort

topological ordering of a DAG. fails on cycles — use StronglyConnectedComponent to collapse them first

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node, order] <~ TopSort(edges[])

random walks

RandomWalk

the primitive underlying diffusion. starts from a node, samples paths by following random edges. steps is walk length, times is walk count. visit frequency approximates the diffusion stationary distribution locally

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
?[node] <~ RandomWalk(edges[], "QmStartParticle", steps: 100, times: 10)

cybergraph examples

find communities of particles

edges[from, to, w] := *cyberlinks{from_particle: from, to_particle: to, weight: w}
communities[node, cid] <~ CommunityDetectionLouvain(edges[])
?[community_id, size] := communities[_, community_id], size = count(community_id)
:order -size
:limit 10

compute PageRank on cyberlinks

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
ranked[node, rank] <~ PageRank(edges[], theta: 0.85, epsilon: 1e-6)
?[particle, rank, name] := ranked[particle, rank], *names{particle, name}
:order -rank
:limit 25

find shortest linkchain between two particles

edges[from, to, w] := *cyberlinks{from_particle: from, to_particle: to, weight: w}
?[path, cost] <~ ShortestPathDijkstra(edges[], "QmSourceHash", "QmTargetHash")

detect bridge particles via betweenness centrality

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
bridges[node, score] <~ BetweennessCentrality(edges[])
?[particle, score, name] := bridges[particle, score], score > 0.01, *names{particle, name}
:order -score

random walk from a particle

edges[from, to] := *cyberlinks{from_particle: from, to_particle: to}
visited[node] <~ RandomWalk(edges[], "QmStartHash", steps: 50, times: 20)
?[node, visit_count] := visited[node], visit_count = count(node)
:order -visit_count
:limit 20

see datalog for language overview. see datalog/queries for CozoScript syntax. see cyberank for how PageRank generalizes into the tri-kernel

discover all concepts

Local Graph