Skip to content

Commit

Permalink
Merge pull request #8 from elecbug/v0.3
Browse files Browse the repository at this point in the history
Update v0.3.2
  • Loading branch information
elecbug authored Jan 19, 2025
2 parents e3607ff + fc2b788 commit 43087ac
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 45 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.3.0
v0.3.2
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (u *Unit) computePaths() {
continue
}

path := ShortestPath(g, start, end)
path := shortestPath(g, start, end)

if path.Distance() != graph.INF {
u.shortestPaths = append(u.shortestPaths, *path)
Expand Down Expand Up @@ -68,7 +68,7 @@ func (pu *ParallelUnit) computePaths() {
go func() {
defer wg.Done()
for job := range jobChan {
path := ShortestPath(g, job.start, job.end)
path := shortestPath(g, job.start, job.end)

if path.Distance() != graph.INF {
resultChan <- *path
Expand Down Expand Up @@ -109,7 +109,7 @@ func (pu *ParallelUnit) computePaths() {
g.Update()
}

// ShortestPath computes the shortest path between two nodes in a graph.
// shortestPath computes the shortest path between two nodes in a graph.
//
// Parameters:
// - g: The graph to perform the computation on.
Expand All @@ -119,7 +119,7 @@ func (pu *ParallelUnit) computePaths() {
// Returns:
// - A graph.Path containing the shortest path and its total distance.
// - If no path exists, the returned Path has distance INF and an empty node sequence.
func ShortestPath(g *graph.Graph, start, end graph.NodeID) *graph.Path {
func shortestPath(g *graph.Graph, start, end graph.NodeID) *graph.Path {
if g.Type() == graph.DIRECTED_WEIGHTED || g.Type() == graph.UNDIRECTED_WEIGHTED {
return weightedShortestPath(g.Matrix(), start, end)
} else if g.Type() == graph.DIRECTED_UNWEIGHTED || g.Type() == graph.UNDIRECTED_UNWEIGHTED {
Expand Down
72 changes: 72 additions & 0 deletions internal/algorithm/path_length.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,62 @@ import (
"github.com/elecbug/go-netrics/internal/graph"
)

// ShortestPath finds and returns the shortest path between two nodes in the graph for a Unit.
//
// Parameters:
// - from: The identifier of the source node.
// - to: The identifier of the destination node.
//
// Returns:
// - A `graph.Path` representing the shortest path from `from` to `to`.
// - If no path exists, returns a `graph.Path` with distance `INF` and the nodes `{from, to}`.
//
// Notes:
// - If the graph or the Unit has been updated, shortest paths are recomputed before the search.
func (u *Unit) ShortestPath(from, to graph.NodeID) graph.Path {
g := u.graph

if !g.IsUpdated() || !u.updated {
u.computePaths()
}

for _, p := range u.shortestPaths {
if p.Nodes()[0] == from && p.Nodes()[len(p.Nodes())-1] == to {
return p
}
}

return *graph.NewPath(graph.INF, []graph.NodeID{from, to})
}

// ShortestPath finds and returns the shortest path between two nodes in the graph for a ParallelUnit.
//
// Parameters:
// - from: The identifier of the source node.
// - to: The identifier of the destination node.
//
// Returns:
// - A `graph.Path` representing the shortest path from `from` to `to`.
// - If no path exists, returns a `graph.Path` with distance `INF` and the nodes `{from, to}`.
//
// Notes:
// - If the graph or the ParallelUnit has been updated, shortest paths are recomputed in parallel before the search.
func (pu *ParallelUnit) ShortestPath(from, to graph.NodeID) graph.Path {
g := pu.graph

if !g.IsUpdated() || !pu.updated {
pu.computePaths()
}

for _, p := range pu.shortestPaths {
if p.Nodes()[0] == from && p.Nodes()[len(p.Nodes())-1] == to {
return p
}
}

return *graph.NewPath(graph.INF, []graph.NodeID{from, to})
}

// AverageShortestPathLength computes the average shortest path length in the graph.
//
// Returns:
Expand Down Expand Up @@ -37,6 +93,12 @@ func (u *Unit) AverageShortestPathLength() float64 {

// ParallelUnit version of AverageShortestPathLength.
// Computes the average shortest path length using parallel computations.
//
// Returns:
// - The average shortest path length as a float64.
//
// Notes:
// - If no shortest paths are found, the function returns 0.
func (pu *ParallelUnit) AverageShortestPathLength() float64 {
g := pu.graph

Expand Down Expand Up @@ -95,6 +157,16 @@ func (u *Unit) PercentileShortestPathLength(percentile float64) graph.Distance {

// ParallelUnit version of PercentileShortestPathLength.
// Computes the percentile shortest path length using parallel computations.
//
// Parameters:
// - percentile: A float64 between 0 and 1 indicating the desired percentile.
//
// Returns:
// - The shortest path length corresponding to the given percentile.
//
// Notes:
// - The percentile is calculated based on the sorted list of shortest paths.
// - If the percentile is out of range, it is clamped to valid indices.
func (pu *ParallelUnit) PercentileShortestPathLength(percentile float64) graph.Distance {
g := pu.graph

Expand Down
4 changes: 4 additions & 0 deletions internal/algorithm/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

// Unit represents a computation unit for graph algorithms.
// It stores shortest paths within the graph and performs computations.
//
// Fields:
// - shortestPaths: A slice of all shortest paths in the graph, sorted by distance in ascending order.
// - graph: A reference to the graph on which computations are performed.
Expand All @@ -17,6 +18,7 @@ type Unit struct {

// ParallelUnit extends Unit for parallel computation of graph algorithms.
// It supports dividing tasks across multiple CPU cores for better performance.
//
// Fields:
// - Unit: Embeds the Unit structure for shared functionality.
// - maxCore: The maximum number of CPU cores to use for parallel computation.
Expand All @@ -26,6 +28,7 @@ type ParallelUnit struct {
}

// NewUnit creates and initializes a new Unit instance.
//
// Parameters:
// - g: The graph to associate with this computation unit.
//
Expand All @@ -40,6 +43,7 @@ func NewUnit(g *graph.Graph) *Unit {
}

// NewParallelUnit creates and initializes a new ParallelUnit instance.
//
// Parameters:
// - g: The graph to associate with this computation unit.
// - core: The maximum number of CPU cores to use for parallel computations.
Expand Down
10 changes: 5 additions & 5 deletions internal/graph/internal/graph_err/graph_err.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ func InvalidEdge(graphKey, edgeKey string) error {
}

func SelfEdge(key string) error {
return fmt.Errorf("node connect to self: [%s]", key)
return fmt.Errorf("node can not connect to self: [%s]", key)
}

func AlreadyEdge(fromKey, toKey string) error {
return fmt.Errorf("edge is already existed: [%s ---> %s]", fromKey, toKey)
}

func NotExistEdge(fromKey, toKey string) error {
return fmt.Errorf("edge not exist: [%s ---> %s]", fromKey, toKey)
}

func AlreadyNode(key string) error {
return fmt.Errorf("node is already existed: [%s]", key)
}

func NotExistNode(key string) error {
return fmt.Errorf("node not exist: [%s]", key)
}

func NotExistEdge(fromKey, toKey string) error {
return fmt.Errorf("edge not exist: [%s ---> %s]", fromKey, toKey)
}
2 changes: 2 additions & 0 deletions internal/graph/node_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ func (id NodeID) String() string {
// Use fmt.Sprintf to format the Identifier as a decimal string.
return fmt.Sprintf("%d", id)
}

// const ALL_NODE = NodeID(math.MaxUint)
18 changes: 10 additions & 8 deletions netrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ func (g *GraphParams) ToParallelUnit(core uint) *ParallelUnit {
return algorithm.NewParallelUnit(g.Graph, core)
}

func (g *GraphParams) ShortestPath(start, end NodeID) Path {
return &PathParams{algorithm.ShortestPath(g.Graph, start, end)}
}
// func (g *GraphParams) ShortestPath(start, end NodeID) Path {
// return &PathParams{algorithm.ShortestPath(g.Graph, start, end)}
// }

const INF = graph.INF
const INF = Distance(graph.INF)

const DIRECTED_UNWEIGHTED = graph.DIRECTED_UNWEIGHTED
const DIRECTED_WEIGHTED = graph.DIRECTED_WEIGHTED
const UNDIRECTED_UNWEIGHTED = graph.UNDIRECTED_UNWEIGHTED
const UNDIRECTED_WEIGHTED = graph.UNDIRECTED_WEIGHTED
const (
DIRECTED_UNWEIGHTED = GraphType(graph.DIRECTED_UNWEIGHTED)
DIRECTED_WEIGHTED = GraphType(graph.DIRECTED_WEIGHTED)
UNDIRECTED_UNWEIGHTED = GraphType(graph.UNDIRECTED_UNWEIGHTED)
UNDIRECTED_WEIGHTED = GraphType(graph.UNDIRECTED_WEIGHTED)
)
Binary file not shown.
66 changes: 39 additions & 27 deletions test/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,43 @@ func TestMain(t *testing.T) {
g.AddEdge(from, to)
}

t.Log(g.String())

u := g.ToUnit()

t.Logf("AverageShortestPathLength: %v\n", spew.Sdump(u.AverageShortestPathLength()))
t.Logf("BetweennessCentrality: %v\n", spew.Sdump(u.BetweennessCentrality()))
t.Logf("ClusteringCoefficient: %v\n", spew.Sdump(u.ClusteringCoefficient()))
t.Logf("DegreeCentrality: %v\n", spew.Sdump(u.DegreeCentrality()))
t.Logf("Diameter: %v\n", spew.Sdump(u.Diameter()))
t.Logf("EigenvectorCentrality: %v\n", spew.Sdump(u.EigenvectorCentrality(1000, 1e-6)))
t.Logf("GlobalEfficiency: %v\n", spew.Sdump(u.GlobalEfficiency()))
t.Logf("LocalEfficiency: %v\n", spew.Sdump(u.LocalEfficiency()))
t.Logf("PercentileShortestPathLength: %v\n", spew.Sdump(u.PercentileShortestPathLength(30)))
t.Logf("RichClubCoefficient: %v\n", spew.Sdump(u.RichClubCoefficient(2)))

pu := g.ToParallelUnit(20)

t.Logf("AverageShortestPathLength: %v\n", spew.Sdump(pu.AverageShortestPathLength()))
t.Logf("BetweennessCentrality: %v\n", spew.Sdump(pu.BetweennessCentrality()))
t.Logf("ClusteringCoefficient: %v\n", spew.Sdump(pu.ClusteringCoefficient()))
t.Logf("DegreeCentrality: %v\n", spew.Sdump(pu.DegreeCentrality()))
t.Logf("Diameter: %v\n", spew.Sdump(pu.Diameter()))
t.Logf("EigenvectorCentrality: %v\n", spew.Sdump(pu.EigenvectorCentrality(1000, 1e-6)))
t.Logf("GlobalEfficiency: %v\n", spew.Sdump(pu.GlobalEfficiency()))
t.Logf("LocalEfficiency: %v\n", spew.Sdump(pu.LocalEfficiency()))
t.Logf("PercentileShortestPathLength: %v\n", spew.Sdump(pu.PercentileShortestPathLength(30)))
t.Logf("RichClubCoefficient: %v\n", spew.Sdump(pu.RichClubCoefficient(2)))
t.Logf("\n%s\n", g.String())

{
u := g.ToUnit()
s := time.Now()

t.Logf("\nAverageShortestPathLength: %v\n", spew.Sdump(u.AverageShortestPathLength()))
t.Logf("\nBetweennessCentrality: %v\n", spew.Sdump(u.BetweennessCentrality()))
t.Logf("\nClusteringCoefficient: %v\n", spew.Sdump(u.ClusteringCoefficient()))
t.Logf("\nDegreeCentrality: %v\n", spew.Sdump(u.DegreeCentrality()))
t.Logf("\nDiameter: %v\n", spew.Sdump(u.Diameter()))
t.Logf("\nEigenvectorCentrality: %v\n", spew.Sdump(u.EigenvectorCentrality(1000, 1e-6)))
t.Logf("\nGlobalEfficiency: %v\n", spew.Sdump(u.GlobalEfficiency()))
t.Logf("\nLocalEfficiency: %v\n", spew.Sdump(u.LocalEfficiency()))
t.Logf("\nPercentileShortestPathLength: %v\n", spew.Sdump(u.PercentileShortestPathLength(30)))
t.Logf("\nRichClubCoefficient: %v\n", spew.Sdump(u.RichClubCoefficient(2)))

duration := time.Since(s)
t.Logf("execution time: %s", duration)
}
{

pu := g.ToParallelUnit(20)
s := time.Now()

t.Logf("\nAverageShortestPathLength: %v\n", spew.Sdump(pu.AverageShortestPathLength()))
t.Logf("\nBetweennessCentrality: %v\n", spew.Sdump(pu.BetweennessCentrality()))
t.Logf("\nClusteringCoefficient: %v\n", spew.Sdump(pu.ClusteringCoefficient()))
t.Logf("\nDegreeCentrality: %v\n", spew.Sdump(pu.DegreeCentrality()))
t.Logf("\nDiameter: %v\n", spew.Sdump(pu.Diameter()))
t.Logf("\nEigenvectorCentrality: %v\n", spew.Sdump(pu.EigenvectorCentrality(1000, 1e-6)))
t.Logf("\nGlobalEfficiency: %v\n", spew.Sdump(pu.GlobalEfficiency()))
t.Logf("\nLocalEfficiency: %v\n", spew.Sdump(pu.LocalEfficiency()))
t.Logf("\nPercentileShortestPathLength: %v\n", spew.Sdump(pu.PercentileShortestPathLength(30)))
t.Logf("\nRichClubCoefficient: %v\n", spew.Sdump(pu.RichClubCoefficient(2)))

duration := time.Since(s)
t.Logf("execution time: %s", duration)
}
}

0 comments on commit 43087ac

Please sign in to comment.