Graph Data Structures
Module — 3 files
These files compile together (same module folder).
file_1.verse
# Module library for mathematical graphs in Verse
Graphs<public> := module:
using { /Verse.org/Random }
# Integer weighted graph
IntegerWeightedGraph<public> := class<concrete>:
Vertices:?[]int = false
Edges:?[]tuple(int,int,int) = false
AdjacencyList:?[int][]tuple(int,int) = false
GetEdges<public>()<decides><transacts>:[]tuple(int,int,int) =
Edges?
GetVertices<public>()<decides><transacts>:[]int =
Vertices?
GetAdjacencyList<public>()<decides><transacts>:[int][]tuple(int,int) =
AdjacencyList?
DebugString<public>()<transacts>:string =
var ReturnString: string = ""
if (List:=AdjacencyList?):
for (Vertex->VertexEdges:List):
for(Edge:VertexEdges):
set ReturnString += "\t{Vertex} - ({Edge(1)}) -> {Edge(0)}\n"
ReturnString
# Float weighted graph
FloatWeightedGraph<public> := class<concrete>:
Vertices:?[]int = false
Edges:?[]tuple(int,int,float) = false
AdjacencyList:?[int][]tuple(int,float) = false
GetEdges<public>()<decides><transacts>: []tuple(int,int,float) =
Edges?
GetVertices<public>()<decides><transacts>: []int =
Vertices?
GetAdjacencyList<public>()<decides><transacts>: [int][]tuple(int,float) =
AdjacencyList?
DebugString<public>()<transacts>:string =
var ReturnString: string = ""
if (List:=AdjacencyList?):
for (Vertex->VertexEdges:List):
for(Edge:VertexEdges):
set ReturnString += "\t{Vertex} - ({Edge(1)}) -> {Edge(0)}\n"
ReturnString
# Obtain list of vertices from an adjacency list
GetVerticesFromAdjacencyList<internal>(AdjacencyListIn:[t][]tuple(t,s) where t:subtype(int), s:subtype(comparable))<decides><transacts>:[]t =
var Vertices:[]t = array{}
for (Vertex->VertexEdges:AdjacencyListIn):
set Vertices += array{Vertex}
Vertices
# Obtain list of edges from adjacency list
GetEdgesFromAdjacencyList<internal>(AdjacencyListIn:[t][]tuple(t,s) where t:subtype(int), s:subtype(comparable))<decides><transacts>: []tuple(t,t,s) =
var Edges: []tuple(t,t,s) = array{}
for (Vertex->VertexEdges:AdjacencyListIn):
for (Edge:VertexEdges):
set Edges += array{(Vertex,Edge(0),Edge(1))}
Edges
# Create an adjacency list from vertices and edges
BuildAdjacencyList<internal>(VerticesIn:[]t, EdgesIn:[]tuple(t,t,s) where t:subtype(int), s:subtype(comparable))<decides><transacts>: [t][]tuple(t,s) =
var AdjacencyListTemp: [t][]tuple(t,s) = map{}
for (Vertex:VerticesIn):
set AdjacencyListTemp[Vertex] = array{}
for (Triple:EdgesIn):
Source := Triple(0)
Destination := Triple(1)
Weight := Triple(2)
set AdjacencyListTemp[Source] += array{(Destination, Weight)}
AdjacencyListTemp
# Create an integer weighted graph
BuildIntegerWeightedGraph<public><constructor>(AdjacencyList:[int][]tuple(int,int)):=IntegerWeightedGraph:
Vertices := option{GetVerticesFromAdjacencyList[AdjacencyList]}
Edges := option{GetEdgesFromAdjacencyList[AdjacencyList]}
AdjacencyList := option{AdjacencyList}
# Create a float weidghted graph
BuildFloatWeightedGraph<public><constructor>(AdjacencyList:[int][]tuple(int,float)):=FloatWeightedGraph:
Vertices := option{GetVerticesFromAdjacencyList[AdjacencyList]}
Edges := option{GetEdgesFromAdjacencyList[AdjacencyList]}
AdjacencyList := option{AdjacencyList}
# Internal Constructor for integer weighted graph
BuildIntegerWeightedGraphVE<constructor>(Vertices:[]int, Edges:[]tuple(int,int,int)):=IntegerWeightedGraph:
Vertices := option{Vertices}
Edges := option{Edges}
AdjacencyList := option{BuildAdjacencyList[Vertices, Edges]}
# Internal Constructor for float weighted graph
BuildFloatWeightedGraphVE<constructor>(Vertices:[]int, Edges:[]tuple(int,int,float)):=FloatWeightedGraph:
Vertices := option{Vertices}
Edges := option{Edges}
AdjacencyList := option{BuildAdjacencyList[Vertices, Edges]}
# Generate edges for a random float weighted graph
RandomFloatWeightedGraph<public>(Size:int, EdgeProbability:float, WeightLow:float, WeightHigh:float):[]tuple(int,int,float) =
var Edges: []tuple(int,int,float) = array{}
var Low:float = WeightLow
var High:float = WeightHigh
if (WeightLow > WeightHigh):
set Low = WeightHigh
set High = WeightLow
for (Vertex1 := 1..Size, Vertex2 := 1..Size, Vertex1<>Vertex2):
BernoulliRandomVariable := Probability.Distributions.Bernoulli(EdgeProbability)
if (BernoulliRandomVariable = 1):
Weight := GetRandomFloat(Low, High)
set Edges += array{(Vertex1,Vertex2,Weight)}
Edges
# Generate edges for a random integer weighted graph
RandomIntegerWeightedGraph<public>(Size:int, EdgeProbability:float, WeightLow:int, WeightHigh:int):[]tuple(int,int,int) =
var Edges: []tuple(int,int,int) = array{}
var Low:int = WeightLow
var High:int = WeightHigh
if (WeightLow > WeightHigh):
set Low = WeightHigh
set High = WeightLow
for (Vertex1 := 1..Size, Vertex2 := 1..Size, Vertex1<>Vertex2):
BernoulliRandomVariable := Probability.Distributions.Bernoulli(EdgeProbability)
if (BernoulliRandomVariable = 1):
Weight := GetRandomInt(Low, High)
set Edges += array{(Vertex1,Vertex2,Weight)}
Edges
# Create a random integer weighted graph
GenerateIntegerWeightedRandomGraph<public>(Size:int, EdgeProbability:float, WeightLow:int, WeightHigh:int):IntegerWeightedGraph =
Vertices := for(Vertex := 1..Size):
Vertex
Edges := RandomIntegerWeightedGraph(Size, EdgeProbability, WeightLow, WeightHigh)
BuildIntegerWeightedGraphVE(Vertices, Edges)
# Create a random integer weighted graph
GenerateFloatWeightedRandomGraph<public>(Size:int, EdgeProbability:float, WeightLow:float, WeightHigh:float):FloatWeightedGraph =
Vertices := for(Vertex := 1..Size):
Vertex
Edges := RandomFloatWeightedGraph(Size, EdgeProbability, WeightLow, WeightHigh)
BuildFloatWeightedGraphVE(Vertices, Edges)
# Graph Algorithms
Algorithms<public> := module:
# Dijkstra's Algorithm for Shortest Path
Dijkstra<public> := module:
using { Heaps }
INTEGER_MAX:int = 2147483647
VertexInfo<public> := class:
Key<public>:int = -1
DistanceFromSource<public>:int = INTEGER_MAX
Predecessor<public>:?VertexInfo = false
GetKey<public>():int =
Key
GetDistance<public>():int =
DistanceFromSource
DebugString<public>()<transacts>:string =
if (DistanceFromSource = INTEGER_MAX):
"Key: {Key}, Distance: Inf"
"Key: {Key}, Distance: {DistanceFromSource}"
# Get the full path to this vertex from source
(VInfo:VertexInfo).ResolvePredecessorChain<public>()<transacts>:[]int =
var PredecessorChain: []int = array{VInfo.Key}
var CurrentVertex: VertexInfo = VInfo
loop:
if (Predecessor := CurrentVertex.Predecessor?):
set CurrentVertex = Predecessor
set PredecessorChain += array{CurrentVertex.Key}
else:
break
PredecessorChain
# ToString for vertex info array
(InfoArray:[]VertexInfo).PrintVertexInfo<public>()<transacts>:void =
for (Vertex:InfoArray):
Print(Vertex.DebugString())
# Less than helper for vertex info
VertexInfoLessThan<public>(U:VertexInfo, V:VertexInfo)<decides><transacts>:void =
U.DistanceFromSource < V.DistanceFromSource
# Equivalent helper for vertex info
VertexInfoEquivalent<public>(U:VertexInfo, V:VertexInfo)<decides><transacts>:void =
U.DistanceFromSource = V.DistanceFromSource
# Find vertex info element by key
(InfoArray:[]VertexInfo).FindByKey<internal>(Key:int)<transacts>:VertexInfo =
var ReturnInfo: VertexInfo = VertexInfo{}
for(VInfo:InfoArray):
if (VInfo.Key = Key):
set ReturnInfo = VInfo
ReturnInfo
# Get index of vertex info in array
(InfoArray:[]VertexInfo).GetIndex<internal>(Vertex:VertexInfo)<transacts>:int =
var ReturnIndex: int = -1
for (Index:=0..InfoArray.Length):
if (InfoArray[Index].Key = Vertex.Key):
set ReturnIndex = Index
ReturnIndex
# Remove vertex info by key
(InfoArray:[]VertexInfo).RemoveByKey<internal>(Key: int)<transacts>: []VertexInfo =
for (VInfo:InfoArray, VInfo.Key<>Key):
VInfo
# Relax the Destination vertex.
# If the path to Destination going through Source is shorter than going directly to Destination, add Source to the shortest path route
Relax<internal>(Source: VertexInfo, Destination: VertexInfo, Weight: int)<transacts>: VertexInfo =
var NewVertexInfo: VertexInfo = Destination
if (Destination.DistanceFromSource > Source.DistanceFromSource + Weight):
set NewVertexInfo = VertexInfo{Key := Destination.Key, DistanceFromSource := Source.DistanceFromSource + Weight, Predecessor := option{Source}}
NewVertexInfo
# Initialize the shortest path from Source to every other vertex in the graph
# Every path has inifinite weight except from source to itself
(Graph:IntegerWeightedGraph).InitializeSingleSource<internal>(Source:int)<transacts>:[]VertexInfo =
var ReturnArray: []VertexInfo = array{}
if (Vertices := Graph.GetVertices[]):
for (Vertex:Vertices):
if (Vertex=Source):
set ReturnArray += array{VertexInfo{Key := Vertex, DistanceFromSource := 0, Predecessor := false}}
else:
set ReturnArray += array{VertexInfo{Key := Vertex, DistanceFromSource := INTEGER_MAX, Predecessor := false}}
ReturnArray
# Implementation of Dijkstra's Algorithm for finding the shortest path through a graph from a single source vertex
# Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford. Introduction to Algorithms (3rd Ed.) pg. 658, MIT Press.
(Graph:IntegerWeightedGraph).Dijkstra<public>(Source: int)<transacts>: []VertexInfo =
# Initialize single source, vertex set, and heap of vertices with cost of path from source
var VertexInfoList:[]VertexInfo = Graph.InitializeSingleSource(Source)
var VertexSet:[]VertexInfo = array{}
var VertexHeap:MinHeap(VertexInfo) = MakeMinHeap(VertexInfoList, VertexInfoLessThan, VertexInfoEquivalent)
# Loop through the heap, extracting the minimum cost edge each time
loop:
if (HeapMinTuple := VertexHeap.ExtractMin[], set VertexHeap = HeapMinTuple(0)):
CurrentVertexInfo: VertexInfo = VertexInfoList.FindByKey(HeapMinTuple(1).Key)
set VertexSet += array{CurrentVertexInfo}
# Loop through the adjacency list of the Current Vertex and determine if the path to each Adjacent Vertex from the source
# is shorter if we go through the Current Vertex first. If it is, update the Vertex Info and the Heap
if (AdjacencyList := Graph.GetAdjacencyList[]):
for (Vertex : AdjacencyList[CurrentVertexInfo.Key], AdjacentVertexInfo := VertexInfoList.FindByKey(Vertex(0))):
UpdatedAdjacentVertexInfo: VertexInfo = Relax(CurrentVertexInfo, AdjacentVertexInfo, Vertex(1))
set VertexInfoList = VertexInfoList.RemoveByKey(Vertex(0)) + array{UpdatedAdjacentVertexInfo}
# Delete the old vertex info and insert the new vertex info
if (VertexHeapTemp := VertexHeap.DeleteKey[AdjacentVertexInfo]):
set VertexHeap = VertexHeapTemp.InsertKey(UpdatedAdjacentVertexInfo)
# The heap is empty
else:
break
VertexSet
Probability<public> := module:
Distributions<public> := module:
# P(X = 1) = p, P(X = 0) = 1-p
Bernoulli<public>(p:probability):int =
Bp := GetRandomFloat(0.0, 1.0)
if:
Bp <= p
then:
1
else:
0
Sign in to download module
Copy-paste each file above is always free.