Skip to content

Commit

Permalink
feats: added dijkstra method to package for export to use in library …
Browse files Browse the repository at this point in the history
…and move all the options to package and much more ..
  • Loading branch information
yothgewalt committed Sep 1, 2024
1 parent 80c3350 commit db89be7
Show file tree
Hide file tree
Showing 14 changed files with 262 additions and 97 deletions.
37 changes: 37 additions & 0 deletions centrality.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) 2024 Faculty of Industrial Technology and Management, KMUTNB (Provided by FITM Elite)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package grafik

import (
"github.com/fitm-elite/grafik/options"
)

// WithDijkstraStandard sets the standard algorithm for the specified dijkstra properties in the returned DijkstraOptionFunc.
func WithDijkstraStandard() options.DijkstraOptionFunc {
return func(properties *options.DijkstraProperties) {
properties.UseStandard()
}
}

// DijkstraCentrality return slice of Vertex that has result of centrality.
func DijkstraCentrality[T comparable](g Grafik[T], opts ...options.DijkstraOptionFunc) []Vertex[T] {
return DijkstraCentrality(g, opts...)
}
21 changes: 12 additions & 9 deletions centrality/dijkstra_centrality.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,39 @@ import (
"sync"

"github.com/fitm-elite/grafik"
"github.com/fitm-elite/grafik/entity"
"github.com/fitm-elite/grafik/options"
"github.com/fitm-elite/grafik/pathfinder"
)

// vertexPath represents path of vertex
type vertexPath[T comparable] struct {
// VertexPath represents path of vertex
type VertexPath[T comparable] struct {
vertexLabel T
averageLength float64
}

// Label returns label of vertex path
func (v vertexPath[T]) Label() T {
func (v VertexPath[T]) Label() T {
return v.vertexLabel
}

// AverageLength returns average length of vertex path
func (v vertexPath[T]) AverageLength() float64 {
func (v VertexPath[T]) AverageLength() float64 {
return v.averageLength
}

// DijkstraCentrality It's using a dijkstra method to find shortest path in each vertex
// and calculate to find an average value in each path to find a centroid.
//
// Returns []vertexPath[T]
func DijkstraCentrality[T comparable](g grafik.Grafik[T], opts ...pathfinder.DijkstraOptionFunc) []vertexPath[T] {
// Returns []VertexPath[T]
func DijkstraCentrality[T comparable](g entity.Grafik[T], opts ...options.DijkstraOptionFunc) []VertexPath[T] {
vertices := g.GetAllVertices()
vertexPaths := make([]vertexPath[T], 0, len(vertices))
vertexPaths := make([]VertexPath[T], 0, len(vertices))

var mu sync.Mutex
var wg sync.WaitGroup

results := make(chan vertexPath[T], len(vertices))
results := make(chan VertexPath[T], len(vertices))

wg.Add(len(vertices))
for _, v := range vertices {
Expand All @@ -69,7 +72,7 @@ func DijkstraCentrality[T comparable](g grafik.Grafik[T], opts ...pathfinder.Dij
}

averageLength := totalLength / float64(len(pathLengths))
result := vertexPath[T]{
result := VertexPath[T]{
vertexLabel: label,
averageLength: averageLength,
}
Expand Down
26 changes: 13 additions & 13 deletions centrality/dijkstra_centrality_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"testing"

"github.com/fitm-elite/grafik"
"github.com/fitm-elite/grafik/pathfinder"
"github.com/fitm-elite/grafik/options"
)

func TestDijkstraCentrality(t *testing.T) {
Expand All @@ -38,23 +38,23 @@ func TestDijkstraCentrality(t *testing.T) {
vK := g.AddVertexByLabel("K")
vQ := g.AddVertexByLabel("Q")

_, _ = g.AddEdge(vA, vB, grafik.WithEdgeWeight(1))
_, _ = g.AddEdge(vA, vE, grafik.WithEdgeWeight(5))
_, _ = g.AddEdge(vA, vJ, grafik.WithEdgeWeight(2))
_, _ = g.AddEdge(vA, vB, options.WithEdgeWeight(1))
_, _ = g.AddEdge(vA, vE, options.WithEdgeWeight(5))
_, _ = g.AddEdge(vA, vJ, options.WithEdgeWeight(2))

_, _ = g.AddEdge(vB, vC, grafik.WithEdgeWeight(3))
_, _ = g.AddEdge(vB, vE, grafik.WithEdgeWeight(1))
_, _ = g.AddEdge(vB, vC, options.WithEdgeWeight(3))
_, _ = g.AddEdge(vB, vE, options.WithEdgeWeight(1))

_, _ = g.AddEdge(vE, vC, grafik.WithEdgeWeight(4))
_, _ = g.AddEdge(vE, vJ, grafik.WithEdgeWeight(3))
_, _ = g.AddEdge(vE, vQ, grafik.WithEdgeWeight(3))
_, _ = g.AddEdge(vE, vK, grafik.WithEdgeWeight(2))
_, _ = g.AddEdge(vE, vC, options.WithEdgeWeight(4))
_, _ = g.AddEdge(vE, vJ, options.WithEdgeWeight(3))
_, _ = g.AddEdge(vE, vQ, options.WithEdgeWeight(3))
_, _ = g.AddEdge(vE, vK, options.WithEdgeWeight(2))

_, _ = g.AddEdge(vJ, vQ, grafik.WithEdgeWeight(1))
_, _ = g.AddEdge(vJ, vQ, options.WithEdgeWeight(1))

_, _ = g.AddEdge(vQ, vK, grafik.WithEdgeWeight(2))
_, _ = g.AddEdge(vQ, vK, options.WithEdgeWeight(2))

paths := DijkstraCentrality(g, pathfinder.WithDijkstraStandard())
paths := DijkstraCentrality(g, options.WithDijkstraStandard())

if len(paths) != 7 {
t.Errorf("Expected len from paths is %d, got %d", 7, len(paths))
Expand Down
23 changes: 4 additions & 19 deletions edge.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,17 @@

package grafik

// EdgeOptionFunc represent an alias of function type that
// modifies the specified edge properties.
type EdgeOptionFunc func(properties *EdgeProperties)

// EdgeProperties represents the properties of an edge.
type EdgeProperties struct {
weight float64
}

// WithEdgeWeight sets the edge weight for the specified edge
// properties in the returned EdgeOptionFunc.
func WithEdgeWeight(weight float64) EdgeOptionFunc {
return func(properties *EdgeProperties) {
properties.weight = weight
}
}
import "github.com/fitm-elite/grafik/options"

// Edge represents an edges in a graph. It contains start and end points.
type Edge[T comparable] struct {
source *Vertex[T] // start point of the edges
dest *Vertex[T] // destination or end point of the edges

properties EdgeProperties
properties options.EdgeProperties
}

func NewEdge[T comparable](source *Vertex[T], dest *Vertex[T], opts ...EdgeOptionFunc) *Edge[T] {
func NewEdge[T comparable](source *Vertex[T], dest *Vertex[T], opts ...options.EdgeOptionFunc) *Edge[T] {
e := &Edge[T]{
source: source,
dest: dest,
Expand All @@ -69,5 +54,5 @@ func (e Edge[T]) Destination() *Vertex[T] {

// Weight returns the weight of the edge.
func (e *Edge[T]) Weight() float64 {
return e.properties.weight
return e.properties.Weight()
}
8 changes: 6 additions & 2 deletions edge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@

package grafik

import "testing"
import (
"testing"

"github.com/fitm-elite/grafik/options"
)

func TestEdgeSource(t *testing.T) {
vA := NewVertex("A")
Expand Down Expand Up @@ -52,7 +56,7 @@ func TestEdgeWeight(t *testing.T) {
vA := NewVertex("A")
vB := NewVertex("B")

e := NewEdge(vA, vB, WithEdgeWeight(weight))
e := NewEdge(vA, vB, options.WithEdgeWeight(weight))

eWeight := e.Weight()
if eWeight != weight {
Expand Down
26 changes: 26 additions & 0 deletions entity/grafik.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2024 Faculty of Industrial Technology and Management, KMUTNB (Provided by FITM Elite)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package entity

import "github.com/fitm-elite/grafik"

// Grafik[T comparable] It's using for avoid cycle import.
type Grafik[T comparable] grafik.Grafik[T]
14 changes: 8 additions & 6 deletions grafik.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ package grafik

import (
"errors"

"github.com/fitm-elite/grafik/options"
)

var (
Expand All @@ -42,7 +44,7 @@ type VertexFunc[T comparable] interface {
//
// If there is a vertex with the same label in the graph, returns nil.
// Otherwise, returns the created vertex.
AddVertexByLabel(label T, options ...VertexOptionFunc) *Vertex[T]
AddVertexByLabel(label T, options ...options.VertexOptionFunc) *Vertex[T]

// AddVertex adds the input vertex to the graph. It doesn't add
// vertex to the graph if the input vertex label is already exists
Expand Down Expand Up @@ -74,7 +76,7 @@ type EdgeFunc[T comparable] interface {
// It creates the input vertices if they don't exist in the graph.
// If any of the specified vertices is nil, returns nil.
// If edge already exist, returns error.
AddEdge(from, to *Vertex[T], opts ...EdgeOptionFunc) (*Edge[T], error)
AddEdge(from, to *Vertex[T], opts ...options.EdgeOptionFunc) (*Edge[T], error)

// GetAllEdges returns a slice of all edges connecting source vertex to
// target vertex if such vertices exist in this graph.
Expand Down Expand Up @@ -140,8 +142,8 @@ func (g *grafik[T]) findVertex(label T) *Vertex[T] {
//
// If there is a vertex with the same label in the graph, returns nil.
// Otherwise, returns the created vertex.
func (g *grafik[T]) AddVertexByLabel(label T, opts ...VertexOptionFunc) *Vertex[T] {
var properties VertexProperties
func (g *grafik[T]) AddVertexByLabel(label T, opts ...options.VertexOptionFunc) *Vertex[T] {
var properties options.VertexProperties
for _, opt := range opts {
opt(&properties)
}
Expand Down Expand Up @@ -198,7 +200,7 @@ func (g *grafik[T]) ContainsVertex(v *Vertex[T]) bool {
// the baseGraph struct. Note that it doesn't add the neighbor to the source vertex.
//
// It returns the created edge.
func (g *grafik[T]) addToEdgeMap(from, to *Vertex[T], opts ...EdgeOptionFunc) *Edge[T] {
func (g *grafik[T]) addToEdgeMap(from, to *Vertex[T], opts ...options.EdgeOptionFunc) *Edge[T] {
edge := NewEdge(from, to, opts...)
if _, ok := g.edges[from.label]; !ok {
g.edges[from.label] = map[T]*Edge[T]{to.label: edge}
Expand All @@ -219,7 +221,7 @@ func (g *grafik[T]) addToEdgeMap(from, to *Vertex[T], opts ...EdgeOptionFunc) *E
// It creates the input vertices if they don't exist in the graph.
// If any of the specified vertices is nil, returns nil.
// If edge already exist, returns error.
func (g *grafik[T]) AddEdge(from, to *Vertex[T], opts ...EdgeOptionFunc) (*Edge[T], error) {
func (g *grafik[T]) AddEdge(from, to *Vertex[T], opts ...options.EdgeOptionFunc) (*Edge[T], error) {
if from == nil || to == nil {
return nil, ErrNilVertices
}
Expand Down
46 changes: 46 additions & 0 deletions options/dijkstra_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2024 Faculty of Industrial Technology and Management, KMUTNB (Provided by FITM Elite)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package options

// DijkstraOptionFunc represent an alias of function type that modifies the specified dijkstra properties.
type DijkstraOptionFunc func(properties *DijkstraProperties)

// DijkstraProperties represents the properties of an dijkstra.
type DijkstraProperties struct {
useStandard bool
}

// UseStandard set use standard to true
func (dj *DijkstraProperties) UseStandard() {
dj.useStandard = true
}

// GetUseStandard return dj.useStandard from DijkstraProperties.
func (dj DijkstraProperties) GetUseStandard() bool {
return dj.useStandard
}

// WithDijkstraStandard sets the standard algorithm for the specified dijkstra properties in the returned DijkstraOptionFunc.
func WithDijkstraStandard() DijkstraOptionFunc {
return func(properties *DijkstraProperties) {
properties.useStandard = true
}
}
43 changes: 43 additions & 0 deletions options/edge_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2024 Faculty of Industrial Technology and Management, KMUTNB (Provided by FITM Elite)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package options

// EdgeOptionFunc represent an alias of function type that
// modifies the specified edge properties.
type EdgeOptionFunc func(properties *EdgeProperties)

// EdgeProperties represents the properties of an edge.
type EdgeProperties struct {
weight float64
}

// Weight returns v.weight from VertexProperties
func (v EdgeProperties) Weight() float64 {
return v.weight
}

// WithEdgeWeight sets the edge weight for the specified edge
// properties in the returned EdgeOptionFunc.
func WithEdgeWeight(weight float64) EdgeOptionFunc {
return func(properties *EdgeProperties) {
properties.weight = weight
}
}
Loading

0 comments on commit db89be7

Please sign in to comment.