Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ go get github.com/elecbug/netkit@latest
### Extensible

- [`bimap`](./bimap/): Bidirectional map with O(1) lookups key->value and value->key.
- [`slice`](./slice/): Generic helpers: binary search, stable merge sort, parallel sort, and `IsSorted`.

## Development

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ import (
"runtime"
"sync"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// BetweennessCentrality computes betweenness centrality using cached all shortest paths.
// - Uses AllShortestPaths(g, cfg) (assumed cached/fast) to enumerate all shortest paths.
// - For each pair (s,t), each interior node on a shortest path gets 1/|SP(s,t)| credit.
// - Undirected graphs enqueue only i<j pairs (no double counting).
// - Normalization matches NetworkX: undirected => 2/((n-1)(n-2)), directed => 1/((n-1)(n-2)).
func BetweennessCentrality(g *graph.Graph, cfg *config.Config) map[node.ID]float64 {
func BetweennessCentrality(g *graph.Graph, cfg *Config) map[node.ID]float64 {
res := make(map[node.ID]float64)
if g == nil {
return res
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package algorithm
import (
"sync"

"github.com/elecbug/netkit/network-graph/path"
"github.com/elecbug/netkit/graph/path"
)

var cachedAllShortestPaths = make(map[string]path.GraphPaths)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package algorithm

import (
"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// ClosenessCentrality computes NetworkX-compatible closeness centrality.
Expand All @@ -18,7 +17,7 @@ import (
// Requirements:
// - AllShortestPaths(g, cfg) must respect directedness of g.
// - cfg.Closeness.WfImproved follows NetworkX default (true) unless overridden.
func ClosenessCentrality(g *graph.Graph, cfg *config.Config) map[node.ID]float64 {
func ClosenessCentrality(g *graph.Graph, cfg *Config) map[node.ID]float64 {
out := make(map[node.ID]float64)
if g == nil {
return out
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import (
"runtime"
"sync"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// ClusteringCoefficientAll computes local clustering coefficients for all nodes.
// - If g.IsBidirectional()==false (directed): Fagiolo (2007) directed clustering (matches NetworkX).
// - If g.IsBidirectional()==true (undirected): standard undirected clustering.
// Returns map[node.ID]float64 with a value for every node in g.
func ClusteringCoefficient(g *graph.Graph, cfg *config.Config) map[node.ID]float64 {
func ClusteringCoefficient(g *graph.Graph, cfg *Config) map[node.ID]float64 {
res := make(map[node.ID]float64)
if g == nil {
return res
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Package config provides configuration settings for the graph algorithms.
package config
package algorithm

import (
"runtime"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ package algorithm
import (
"math"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// DegreeAssortativityCoefficient computes Newman's degree assortativity coefficient (Pearson correlation)
Expand All @@ -24,7 +23,7 @@ import (
//
// - Self-loops are ignored by default (configurable).
// - Replace neighbor getters with your Graph's actual API if different.
func DegreeAssortativityCoefficient(g *graph.Graph, cfg *config.Config) float64 {
func DegreeAssortativityCoefficient(g *graph.Graph, cfg *Config) float64 {
if g == nil {
return 0.0
}
Expand All @@ -35,8 +34,8 @@ func DegreeAssortativityCoefficient(g *graph.Graph, cfg *config.Config) float64
}

// Resolve config with sane defaults.
assCfg := &config.AssortativityCoefficientConfig{
Mode: config.AssortativityProjected,
assCfg := &AssortativityCoefficientConfig{
Mode: AssortativityProjected,
IgnoreSelfLoops: true,
}
if cfg != nil && cfg.Assortativity != nil {
Expand All @@ -50,8 +49,8 @@ func DegreeAssortativityCoefficient(g *graph.Graph, cfg *config.Config) float64
isUndirected := g.IsBidirectional()

// Default directed mode: "out-in" is common in literature.
if !isUndirected && assCfg.Mode == config.AssortativityProjected {
assCfg.Mode = config.AssortativityOutIn
if !isUndirected && assCfg.Mode == AssortativityProjected {
assCfg.Mode = AssortativityOutIn
}

// Build an index for upper-triangle filtering on undirected graphs.
Expand Down Expand Up @@ -119,19 +118,19 @@ func DegreeAssortativityCoefficient(g *graph.Graph, cfg *config.Config) float64
jv = float64(undeg[v])
} else {
switch assCfg.Mode {
case config.AssortativityOutIn:
case AssortativityOutIn:
ju = float64(outDeg[u])
jv = float64(inDeg[v])
case config.AssortativityOutOut:
case AssortativityOutOut:
ju = float64(outDeg[u])
jv = float64(outDeg[v])
case config.AssortativityInIn:
case AssortativityInIn:
ju = float64(inDeg[u])
jv = float64(inDeg[v])
case config.AssortativityInOut:
case AssortativityInOut:
ju = float64(inDeg[u])
jv = float64(outDeg[v])
case config.AssortativityProjected:
case AssortativityProjected:
// Directed but projected (if user explicitly requests)
ju = float64(undeg[u])
jv = float64(undeg[v])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import (
"runtime"
"sync"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// DegreeCentralityConfig (suggested to be added inside your config package)
Expand All @@ -22,7 +21,7 @@ import (
// Mode string
// }
//
// In config.Config:
// In Config:
// type Config struct {
// Workers int
// Degree *DegreeCentralityConfig
Expand All @@ -33,7 +32,7 @@ import (
// - Undirected: deg(u)/(n-1).
// - Directed (default "total"): (in(u)+out(u))/(n-1). Use "in"/"out" for the specific variants.
// Self-loops are ignored for centrality.
func DegreeCentrality(g *graph.Graph, cfg *config.Config) map[node.ID]float64 {
func DegreeCentrality(g *graph.Graph, cfg *Config) map[node.ID]float64 {
res := make(map[node.ID]float64)
if g == nil {
return res
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package algorithm

import (
"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/graph"
)

// Diameter computes the diameter of the graph using all-pairs shortest paths.
func Diameter(g *graph.Graph, cfg *config.Config) int {
func Diameter(g *graph.Graph, cfg *Config) int {
result := 0
paths := AllShortestPaths(g, cfg)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import (
"runtime"
"sync"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

func makeEdgeKey(u, v node.ID, undirected bool) (node.ID, node.ID) {
Expand Down Expand Up @@ -38,7 +37,7 @@ func makeEdgeKey(u, v node.ID, undirected bool) (node.ID, node.ID) {
// - map[node.ID]map[node.ID]float64 where:
// - Undirected: key is canonical [min(u,v), max(u,v)]
// - Directed: key is (u,v) ordered
func EdgeBetweennessCentrality(g *graph.Graph, cfg *config.Config) map[node.ID]map[node.ID]float64 {
func EdgeBetweennessCentrality(g *graph.Graph, cfg *Config) map[node.ID]map[node.ID]float64 {
out := make(map[node.ID]map[node.ID]float64)
if g == nil {
return out
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import (
"runtime"
"sync"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// EigenvectorCentrality computes eigenvector centrality using parallel power iteration.
Expand All @@ -17,7 +16,7 @@ import (
// Set Reverse=true to use successors/out-edges (right eigenvector).
//
// Unweighted edges are assumed. The result vector is L2-normalized (sum of squares == 1).
func EigenvectorCentrality(g *graph.Graph, cfg *config.Config) map[node.ID]float64 {
func EigenvectorCentrality(g *graph.Graph, cfg *Config) map[node.ID]float64 {
out := make(map[node.ID]float64)
if g == nil {
return out
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ import (
"container/heap"
"math"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// Modularity computes Newman-Girvan modularity Q.
// If cfg.Modularity.Partition == nil, it runs greedy CNM to obtain a partition first.
// All computations are performed on an undirected projection (to match NetworkX).
func Modularity(g *graph.Graph, cfg *config.Config) float64 {
func Modularity(g *graph.Graph, cfg *Config) float64 {
if g == nil || cfg == nil || cfg.Modularity == nil {
return 0.0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import (
"runtime"
"sync"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
)

// PageRank computes PageRank using a parallel power-iteration that mirrors NetworkX semantics:
Expand All @@ -17,7 +16,7 @@ import (
// - For directed graphs, Reverse=false is the standard PageRank (incoming influence).
// Reverse=true flips direction (treat in-neighbors as outs).
// - For undirected graphs, neighbors are used as outs (degree-based normalization).
func PageRank(g *graph.Graph, cfg *config.Config) map[node.ID]float64 {
func PageRank(g *graph.Graph, cfg *Config) map[node.ID]float64 {
res := make(map[node.ID]float64)
if g == nil {
return res
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import (
"runtime"
"sync"

"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/network-graph/path"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/node"
"github.com/elecbug/netkit/graph/path"
)

// ShortestPaths finds all shortest paths between two nodes in a graph.
Expand Down Expand Up @@ -59,7 +58,7 @@ func ShortestPaths(g *graph.Graph, start, end node.ID) []path.Path {
// (matching prior behavior and saving work). If you need reversed node order per entry, that can be changed,
// but be aware of the extra cost.
// - Self paths [u][u] are set to a single self path.
func AllShortestPaths(g *graph.Graph, cfg *config.Config) path.GraphPaths {
func AllShortestPaths(g *graph.Graph, cfg *Config) path.GraphPaths {
if g == nil {
return path.GraphPaths{}
}
Expand Down Expand Up @@ -327,7 +326,7 @@ func allShortestPathsBFS(g *graph.Graph, start, end node.ID) []path.Path {
// - For each source u, the inner map contains v -> dist(u,v) for all reachable v (including u with 0).
// - Unreachable targets are omitted from the inner map.
// - Uses a worker pool sized by cfg.Workers (or NumCPU when <=0).
func AllShortestPathLength(g *graph.Graph, cfg *config.Config) path.PathLength {
func AllShortestPathLength(g *graph.Graph, cfg *Config) path.PathLength {
out := make(path.PathLength)
if g == nil {
return out
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package config
package algorithm

import "github.com/elecbug/netkit/network-graph/node"
import "github.com/elecbug/netkit/graph/node"

// ClosenessCentralityConfig holds the configuration settings for the closeness centrality algorithm.
type ClosenessCentralityConfig struct {
Expand Down
2 changes: 1 addition & 1 deletion network-graph/graph/edge.go → graph/edge.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package graph
import (
"fmt"

"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph/node"
)

// AddEdge adds an edge from -> to. If bidirectional is true, adds the reverse edge as well.
Expand Down
2 changes: 1 addition & 1 deletion network-graph/graph/graph.go → graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"fmt"
"strings"

"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph/node"
)

// Graph maintains nodes and adjacency edges.
Expand Down
17 changes: 8 additions & 9 deletions network-graph/graph_test.go → graph/graph_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package network_graph_test
package graph_test

import (
"encoding/json"
Expand All @@ -9,11 +9,10 @@ import (
"reflect"
"testing"

"github.com/elecbug/netkit/network-graph/algorithm"
"github.com/elecbug/netkit/network-graph/algorithm/config"
"github.com/elecbug/netkit/network-graph/graph"
"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/network-graph/path"
"github.com/elecbug/netkit/graph"
"github.com/elecbug/netkit/graph/algorithm"
"github.com/elecbug/netkit/graph/node"
"github.com/elecbug/netkit/graph/path"
)

func TestSimple(t *testing.T) {
Expand Down Expand Up @@ -76,12 +75,12 @@ func TestPathLengths(t *testing.T) {
var want path.PathLength

t.Run("WithPaths", func(t *testing.T) {
got = algorithm.AllShortestPaths(g, &config.Config{Workers: 4})
got = algorithm.AllShortestPaths(g, &algorithm.Config{Workers: 4})
})
gotLengths := got.OnlyLength()

t.Run("WithoutPaths", func(t *testing.T) {
want = algorithm.AllShortestPathLength(g, &config.Config{Workers: 4})
want = algorithm.AllShortestPathLength(g, &algorithm.Config{Workers: 4})
})

if !reflect.DeepEqual(gotLengths, want) {
Expand Down Expand Up @@ -163,7 +162,7 @@ func TestDirectionalGraph(t *testing.T) {

func graphMetrics(t *testing.T, g *graph.Graph, text string) {
results := make(map[string]interface{})
cfg := config.Default()
cfg := algorithm.Default()

t.Run("ShortestPaths", func(t *testing.T) {
// results["shortest_path_length"] = algo.AllShortestPathLength(g, cfg)
Expand Down
2 changes: 1 addition & 1 deletion network-graph/graph/node.go → graph/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package graph
import (
"fmt"

"github.com/elecbug/netkit/network-graph/node"
"github.com/elecbug/netkit/graph/node"
)

// AddNode adds a node to the graph.
Expand Down
File renamed without changes.
Loading
Loading