goraph

package module
v0.0.0-...-cb8f0be Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 25, 2020 License: Apache-2.0 Imports: 4 Imported by: 2

README

Golang Graph

Build Status codecov Go Report Card GoDoc License

Goraph is a golang package provides basic graph structures and algorithms.

Goraph is NOT concurrent safe.

Current implemented(√) and planned(×) algorithms:

Algorithm BFS DFS TopologicalSort Kruskal Prim Dijkstra Yen Kisp BellmanFord FloydWarshall EdmondsKarp
Complex O(V+E) O(V+E) O(V+E) O(ElogE) O(E+VlogV)¹ O(E+VlogV)¹ O(KV(E+VlogV)) O(KVlogV) O(VE) O(V3) O(VE2)
Status × × × × × × × ×
¹ With Fibonacci heap.

##Algorithms Introduction

  • BFS: breadth first search.

  • DFS: depth first search.

  • TopologicalSort: is a linear ordering of a directed graph's vertices such that for every directed edge uv from vertex u to vertex v, u comes before v in the ordering.

  • Kruskal: is a minimum-spanning-tree algorithm which finds an edge of the least possible weight that connects any two trees in the forest.

  • Prim: is a greedy algorithm that finds a minimum spanning tree for a weighted undirected graph

  • Dijkstra: computes shortest paths from a single source vertex to all of the other vertices in a graph with non-negative edge cost.

  • Yen: computes K-shortest loopless paths between two vertex in a graph with non-negative edge cost.

  • Kisp: computes K-shortest independent paths between two vertex in a graph with non-negative edge cost.

  • BellmanFord: computes shortest paths from a single source vertex to all of the other vertices in a weighted digraph with positive or negative edge weights.

  • FloydWarshall: computes all-pairs shortest paths in a weighted graph with positive or negative edge weights (but with no negative cycles).

  • EdmondsKarp: computes the maximum flow in a flow network(graph).

##Requirements #####Download this package and its dependency

go get github.com/starwander/GoFibonacciHeap
go get github.com/starwander/goraph

#####Implements Vertex interface of this package if you want to use AddVertexWithEdges(optional):

type Vertex interface {
	ID() ID
	Edges() []Edge
}

type Edge interface {
	Get() (from ID, to ID, weight float64)
}

Supported Operations

  • Graph operations:
  • GetVertex: get a vertex by input id.
  • GetEdge: gets the edge between the two vertices by input ids.
  • GetEdgeWeight: gets the weight of the edge between the two vertices by input ids.
  • AddVertex: adds a new vertex into the graph.
  • AddEdge: adds a new edge between the vertices by the input ids.
  • UpdateEdgeWeight: updates the weight of the edge between vertices by the input ids.
  • DeleteVertex: deletes a vertex from the graph and gets the value of the vertex.
  • DeleteEdge: deletes the edge between the vertices by the input id from the graph and gets the value of edge.
  • AddVertexWithEdges: adds a vertex value which implements Vertex interface.
  • CheckIntegrity: checks if any edge connects to or from unknown vertex.
  • GetPathWeight: gets the total weight along the path by input ids.
  • DisableEdge: disables the edge for further calculation.
  • DisableVertex: disables the vertex for further calculation.
  • DisablePath: disables all the vertices in the path for further calculation.
  • Reset: enables all vertices and edges for further calculation.
  • Algorithm operations:
  • Dijkstra: gets the shortest path from one vertex to all other vertices in the graph.
  • Yen: gets top k shortest loopless path between two vertex in the graph.
  • Kisp: gets top k shortest independent path between two vertex in the graph.

Example

package main

import (
	"fmt"
	"github.com/starwander/goraph"
)

type myVertex struct {
	id     string
	outTo  map[string]float64
	inFrom map[string]float64
}

type myEdge struct {
	from   string
	to     string
	weight float64
}

func (vertex *myVertex) ID() goraph.ID {
	return vertex.id
}

func (vertex *myVertex) Edges() (edges []goraph.Edge) {
	edges = make([]goraph.Edge, len(vertex.outTo)+len(vertex.inFrom))
	i := 0
	for to, weight := range vertex.outTo {
		edges[i] = &myEdge{vertex.id, to, weight}
		i++
	}
	for from, weight := range vertex.inFrom {
		edges[i] = &myEdge{from, vertex.id, weight}
		i++
	}
	return
}

func (edge *myEdge) Get() (goraph.ID, goraph.ID, float64) {
	return edge.from, edge.to, edge.weight
}

func main() {
	//Dikjstra: The distance from S to T is  44
	//Dikjstra: The path from S to T is: T<-F<-E<-B<-S
	Dijkstra()

	//Yen 1st: The distance from A to D is  2
	//Yen 1st: The path from A to D is:  [A D]
	//Yen 2nd: The distance from A to D is  3
	//Yen 2nd: The path from A to D is:  [A B C D]
	//Yen 3rd: The distance from A to D is  4
	//Yen 3rd: The path from A to D is:  [A B E D]
	Yen()

	//Kisp 1st: The distance from A to D is  5
	//Kisp 1st: The path from A to D is:  [C E F H]
	//Kisp 2nd: The distance from A to D is  11
	//Kisp 2nd: The path from A to D is:  [C D F G H]
	//Kisp 3rd: The distance from A to D is  +Inf
	//Kisp 3rd: The path from A to D is:  []
	Kisp()
}

func Dijkstra() {
	graph := goraph.NewGraph()
	graph.AddVertexWithEdges(&myVertex{"S", map[string]float64{"B": 14}, map[string]float64{"A": 15, "B": 14, "C": 9}})
	graph.AddVertexWithEdges(&myVertex{"A", map[string]float64{"S": 15, "B": 5, "D": 20, "T": 44}, map[string]float64{"B": 5, "D": 20, "T": 44}})
	graph.AddVertexWithEdges(&myVertex{"B", map[string]float64{"S": 14, "A": 5, "D": 30, "E": 18}, map[string]float64{"S": 14, "A": 5, "D": 30, "E": 18}})
	graph.AddVertexWithEdges(&myVertex{"C", map[string]float64{"S": 9, "E": 24}, map[string]float64{"E": 24}})
	graph.AddVertexWithEdges(&myVertex{"D", map[string]float64{"A": 20, "B": 30, "E": 2, "F": 11, "T": 16}, map[string]float64{"A": 20, "B": 30, "E": 2, "F": 11, "T": 16}})
	graph.AddVertexWithEdges(&myVertex{"E", map[string]float64{"B": 18, "C": 24, "D": 2, "F": 6, "T": 19}, map[string]float64{"B": 18, "C": 24, "D": 2, "F": 6, "T": 19}})
	graph.AddVertexWithEdges(&myVertex{"F", map[string]float64{"D": 11, "E": 6, "T": 6}, map[string]float64{"D": 11, "E": 6, "T": 6}})
	graph.AddVertexWithEdges(&myVertex{"T", map[string]float64{"A": 44, "D": 16, "E": 19, "F": 6}, map[string]float64{"A": 44, "D": 16, "E": 19, "F": 6}})

	dist, prev, _ := graph.Dijkstra("S")
	fmt.Println("Dikjstra: The distance from S to T is ", dist["T"])
	fmt.Print("Dikjstra: The path from S to T is: T")
	node := prev["T"]
	for node != nil {
		fmt.Printf("<-%s", node)
		node = prev[node]
	}
	fmt.Println()
}

func Yen() {
	graph := goraph.NewGraph()
	graph.AddVertex("A", nil)
	graph.AddVertex("B", nil)
	graph.AddVertex("C", nil)
	graph.AddVertex("D", nil)
	graph.AddVertex("E", nil)
	graph.AddEdge("A", "B", 1, nil)
	graph.AddEdge("B", "C", 1, nil)
	graph.AddEdge("C", "D", 1, nil)
	graph.AddEdge("A", "D", 2, nil)
	graph.AddEdge("B", "E", 2, nil)
	graph.AddEdge("E", "D", 1, nil)
	dist, path, _ := graph.Yen("A", "D", 3)
	fmt.Println("Yen 1st: The distance from A to D is ", dist[0])
	fmt.Println("Yen 1st: The path from A to D is: ", path[0])
	fmt.Println("Yen 2nd: The distance from A to D is ", dist[1])
	fmt.Println("Yen 2nd: The path from A to D is: ", path[1])
	fmt.Println("Yen 3rd: The distance from A to D is ", dist[2])
	fmt.Println("Yen 3rd: The path from A to D is: ", path[2])
}

func Kisp() {
	graph := goraph.NewGraph()
	graph.AddVertexWithEdges(&myVertex{"C", map[string]float64{"D": 3, "E": 2}, map[string]float64{}})
	graph.AddVertexWithEdges(&myVertex{"D", map[string]float64{"F": 4}, map[string]float64{"C": 3, "E": 1}})
	graph.AddVertexWithEdges(&myVertex{"E", map[string]float64{"D": 1, "F": 2, "G": 3}, map[string]float64{"C": 2}})
	graph.AddVertexWithEdges(&myVertex{"F", map[string]float64{"G": 2, "H": 1}, map[string]float64{"D": 4, "E": 2}})
	graph.AddVertexWithEdges(&myVertex{"G", map[string]float64{"H": 2}, map[string]float64{"E": 3, "F": 2}})
	graph.AddVertexWithEdges(&myVertex{"H", map[string]float64{}, map[string]float64{"F": 1, "G": 2}})
	dist, path, _ := graph.Kisp("C", "H", 3)
	fmt.Println("Kisp 1st: The distance from A to D is ", dist[0])
	fmt.Println("Kisp 1st: The path from A to D is: ", path[0])
	fmt.Println("Kisp 2nd: The distance from A to D is ", dist[1])
	fmt.Println("Kisp 2nd: The path from A to D is: ", path[1])
	fmt.Println("Kisp 3rd: The distance from A to D is ", dist[2])
	fmt.Println("Kisp 3rd: The path from A to D is: ", path[2])
}

Reference

GoDoc

LICENSE

goraph source code is licensed under the Apache Licence, Version 2.0.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Edge

type Edge interface {
	// Get returns the edge's inbound vertex, outbound vertex and weight.
	Get() (from ID, to ID, weight float64)
}

Edge interface represents an edge connecting two vertices.

type Graph

type Graph struct {
	// contains filtered or unexported fields
}

Graph is made up of vertices and edges. Vertices in the graph must have an unique id. Each edges in the graph connects two vertices directed with a weight.

func NewGraph

func NewGraph() *Graph

NewGraph creates a new empty graph.

func (*Graph) AddEdge

func (graph *Graph) AddEdge(from ID, to ID, weight float64, e interface{}) error

AddEdge adds a new edge between the vertices by the input ids. Try to add an edge with -Inf weight will get an error. Try to add an edge from or to a vertex not in the graph will get an error. Try to add a duplicate edge will get an error.

func (*Graph) AddVertex

func (graph *Graph) AddVertex(id ID, v interface{}) error

AddVertex adds a new vertex into the graph. Try to add a duplicate vertex will get an error.

func (*Graph) AddVertexWithEdges

func (graph *Graph) AddVertexWithEdges(v Vertex) error

AddVertexWithEdges adds a vertex value which implements Vertex interface. AddVertexWithEdges adds edges connected to the vertex at the same time, due to the Vertex interface can get the Edges.

func (*Graph) CheckIntegrity

func (graph *Graph) CheckIntegrity() error

CheckIntegrity checks if any edge connects to or from unknown vertex. If the graph is integrate, nil is returned. Otherwise an error is returned.

func (*Graph) DeleteEdge

func (graph *Graph) DeleteEdge(from ID, to ID) interface{}

DeleteEdge deletes the edge between the vertices by the input id from the graph and gets the value of edge. Try to delete an edge from or to a vertex not in the graph will get an error. Try to delete an edge between disconnected vertices will get a nil.

func (*Graph) DeleteVertex

func (graph *Graph) DeleteVertex(id ID) interface{}

DeleteVertex deletes a vertex from the graph and gets the value of the vertex. Try to delete a vertex not in the graph will get an nil.

func (*Graph) Dijkstra

func (graph *Graph) Dijkstra(source ID) (dist map[ID]float64, prev map[ID]ID, err error)

Dijkstra gets the shortest path from one vertex to all other vertices in the graph. https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm

func (*Graph) DisableEdge

func (graph *Graph) DisableEdge(from, to ID)

DisableEdge disables the edge for further calculation.

func (*Graph) DisablePath

func (graph *Graph) DisablePath(path []ID)

DisablePath disables all the vertices in the path for further calculation.

func (*Graph) DisableVertex

func (graph *Graph) DisableVertex(vertex ID)

DisableVertex disables the vertex for further calculation.

func (*Graph) GetEdge

func (graph *Graph) GetEdge(from ID, to ID) (interface{}, error)

GetEdge gets the edge between the two vertices by input ids. Try to get the edge from or to a vertex not in the graph will get an error. Try to get the edge between two disconnected vertices will get an error.

func (*Graph) GetEdgeWeight

func (graph *Graph) GetEdgeWeight(from ID, to ID) (float64, error)

GetEdgeWeight gets the weight of the edge between the two vertices by input ids. Try to get the weight of the edge from or to a vertex not in the graph will get an error. Try to get the weight of the edge between two disconnected vertices will get +Inf.

func (*Graph) GetPathWeight

func (graph *Graph) GetPathWeight(path []ID) (totalWeight float64)

GetPathWeight gets the total weight along the path by input ids. It will get -Inf if the input path is nil or empty. It will get -Inf if the path contains vertex not in the graph. It will get +Inf if the path contains vertices not connected.

func (*Graph) GetVertex

func (graph *Graph) GetVertex(id ID) (vertex interface{}, err error)

GetVertex get a vertex by input id. Try to get a vertex not in the graph will get an error.

func (*Graph) Kisp

func (graph *Graph) Kisp(source, destination ID, topK int) ([]float64, [][]ID, error)

Kisp gets top k shortest independent path between two vertex in the graph. Independent means no vertex is shared between path.

func (*Graph) Reset

func (graph *Graph) Reset()

Reset enables all vertices and edges for further calculation.

func (*Graph) UpdateEdgeWeight

func (graph *Graph) UpdateEdgeWeight(from ID, to ID, weight float64) error

UpdateEdgeWeight updates the weight of the edge between vertices by the input ids. Try to update an edge with -Inf weight will get an error. Try to update an edge from or to a vertex not in the graph will get an error. Try to update an edge between disconnected vertices will get an error.

func (*Graph) Yen

func (graph *Graph) Yen(source, destination ID, topK int) ([]float64, [][]ID, error)

Yen gets top k shortest loopless path between two vertex in the graph. https://en.wikipedia.org/wiki/Yen%27s_algorithm

type ID

type ID interface{}

ID uniquely identify a vertex.

type Vertex

type Vertex interface {
	// ID get the unique id of the vertex.
	ID() ID
	// Edges get all the edges connected to the vertex
	Edges() []Edge
}

Vertex interface represents a vertex with edges connected to it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL