diff --git a/src/Graphoscope/Graphoscope.fsproj b/src/Graphoscope/Graphoscope.fsproj
index ebd9fc4..794de9d 100644
--- a/src/Graphoscope/Graphoscope.fsproj
+++ b/src/Graphoscope/Graphoscope.fsproj
@@ -44,6 +44,7 @@
+
diff --git a/src/Graphoscope/Measures/LongestPath.fs b/src/Graphoscope/Measures/LongestPath.fs
new file mode 100644
index 0000000..d0da2a4
--- /dev/null
+++ b/src/Graphoscope/Measures/LongestPath.fs
@@ -0,0 +1,189 @@
+namespace Graphoscope.Measures
+
+open Graphoscope
+open System.Collections.Generic
+
+type LongestPath() =
+
+ ///
+ /// Determines whether a cycle can be formed in the given FGraph starting from the specified node,
+ /// using an algorithm based on priority queues and breadth-first traversal.
+ ///
+ /// The node from which to check for the existence of a cycle.
+ /// The FGraph in which to search for the cycle.
+ /// True if a cycle is found, otherwise false.
+ static member hasCycleFromNodeInFGraph (starting : 'NodeKey) (graph : FGraph<'NodeKey, 'NodeData, 'EdgeData>) =
+ let visited = HashSet<'NodeKey>()
+ //let stack = Stack<'NodeKey>()
+ let priorityQueue: Queue<('NodeKey)> = System.Collections.Generic.Queue()//Priority_Queue.SimplePriorityQueue<('NodeKey*float),float>()
+
+ //stack.Push(starting)
+ priorityQueue.Enqueue(starting)
+ visited.Add(starting) |> ignore
+
+
+ let rec outerLoop counter =
+ if priorityQueue.Count>0 then
+ //if stack.Count > 0 then
+ let nodeKey = priorityQueue.Dequeue() //et nodeKey = (stack.Pop())
+ let (_, nd, s) = graph.[nodeKey]
+
+ printfn $"{nodeKey}"
+ let rec innerLoops counter =
+ if counter=s.Count then
+ outerLoop (counter+1)
+ else
+ let node = s.Keys|>Seq.item counter
+ if node=starting then
+ true
+ elif not(visited.Contains(node)) then
+ //stack.Push(node)
+ priorityQueue.Enqueue(node)
+ visited.Add(node) |> ignore
+ innerLoops (counter+1)
+ else
+ innerLoops (counter+1)
+ innerLoops 0
+ else
+ false
+ outerLoop 0
+
+ ///
+ /// Determines whether a cycle exists in the given FGraph.
+ ///
+ /// The FGraph to check for the presence of a cycle
+ /// True if a cycle is found, otherwise false.
+ static member hasCycleInFGraph (graph : FGraph<'NodeKey, 'NodeData, 'EdgeData>) =
+
+ let nodes = graph|>Seq.map(fun kvp -> kvp.Key)
+
+ let rec isCyclic (counter:int) =
+ if counter = (nodes|>Seq.length) then
+ false
+ else
+ let node = nodes |>Seq.item counter
+ if LongestPath.hasCycleFromNodeInFGraph node graph then
+ true
+ else
+ isCyclic (counter+1)
+ isCyclic 0
+
+ ///
+ /// Computes longest paths from for using an inverse Dijkstra's algorithm.
+ ///
+ /// Calculate the longest paths from this node.
+ /// Function to convert the EdgeData to a float.
+ /// The FGraph for which to compute the longest path. Has to be an Directed Acyclic Graph.
+ /// If there isn't a path between two edges, the distance is set to `infinity`.
+ /// Tuples of an ordered list containing the path and the distance of the longest path.
+ static member getLongestPathOfFGraphUnchecked (starting : 'NodeKey) (getEdgeWeight : 'EdgeData -> float) (graph : FGraph<'NodeKey, 'NodeData, 'EdgeData> ) =
+
+ //Inverse Version of Djikstra, transforming the edgeWeights into negatives
+ let getLongestPathDictOfFGraph (starting : 'NodeKey) (getEdgeWeight : 'EdgeData -> float) (graph : FGraph<'NodeKey, 'NodeData, 'EdgeData> ) =
+ let distance = Dictionary<'NodeKey, ('NodeKey*float)>()
+ //let priorityQueue = SortedSet<'NodeKey * float>(Comparer<'NodeKey * float>.Create(fun (_, d1) (_, d2) -> compare d1 d2))
+ let priorityQueue: Queue<('NodeKey * float)> = System.Collections.Generic.Queue()//Priority_Queue.SimplePriorityQueue<('NodeKey*float),float>()
+ let infinity = System.Double.MaxValue
+
+ // Initialize distances to infinity for all nodes except the starting node
+ // TODO: this can be improved by getOrDefault
+ for nodeKey in graph.Keys do
+ if nodeKey = starting then
+ distance.[nodeKey] <- (starting,0.)
+ else
+ distance.[nodeKey] <- (starting,infinity)
+
+ priorityQueue.Enqueue((starting, 0.)) |> ignore
+
+ while priorityQueue.Count > 0 do
+ let (currentNode, currentDistance) = priorityQueue.Dequeue()
+
+ let (_, _, predecessors) = graph.[currentNode]
+
+ for kv in predecessors do
+ if kv.Key <> currentNode then
+ let kvValue = kv.Value |> getEdgeWeight |> fun x -> -x
+ //if kvValue < 0. then failwithf "Dijkstra does not handle neg. edge weight"
+ let totalDistance = (currentDistance + kvValue) // Assuming edgeWeight is always 1 in this example
+ let prevNode,prevDistance = distance.[kv.Key]
+
+ // Improve getValue
+ if totalDistance < prevDistance then
+ distance.[kv.Key] <- (currentNode,totalDistance)
+ priorityQueue.Enqueue(kv.Key,totalDistance) |> ignore
+ Seq.sortBy snd priorityQueue |>ignore
+
+ distance
+
+ //Contains the dictionary create by getLongestPathDictOfFGraph of nodeKey,(pred,pathLenght)
+ let longestPathDict = getLongestPathDictOfFGraph (starting : 'NodeKey) (getEdgeWeight : 'EdgeData -> float) (graph : FGraph<'NodeKey, 'NodeData, 'EdgeData> )
+
+ //Contains the most distant nodeKey and the negative path lenght to it
+ let mostDistantNode,longestPath =
+ longestPathDict
+ |>Seq.minBy(fun kvp ->
+ kvp.Value
+ |>snd
+ )
+ |>fun kvp ->
+ kvp.Key,snd kvp.Value
+
+ //Function to recreate the path to the node with the longest path based on the inverse Djikstra. Returns an ordered List of the path from the starting node to the most distant node
+ let rec reconstructPath (path: 'NodeKey list) =
+ if List.head path = starting then
+ path
+ else
+ let currentHead = List.head path
+ let pred: 'NodeKey = longestPathDict.[currentHead] |>fst
+ reconstructPath (pred::path)
+
+ reconstructPath [mostDistantNode] , (longestPath|>fun x -> x*(-1.))
+
+ ///
+ /// Computes longest paths from for using an inverse Dijkstra's algorithm.
+ ///
+ /// Calculate the longest paths from this node.
+ /// Function to convert the EdgeData to a float.
+ /// The FGraph for which to compute the longest path. Has to be an Directed Acyclic Graph.
+ /// Uses hasCycleInFGraph to check for cyclic character. If the given FGraph is not a Directed Acyclic Graph this will fail.
+ /// Tuples of an ordered list containing the path and the distance of the longest path.
+ static member getLongestPathOfFGraph (starting : 'NodeKey) (getEdgeWeight : 'EdgeData -> float) (graph : FGraph<'NodeKey, 'NodeData, 'EdgeData> ) =
+ if LongestPath.hasCycleInFGraph graph then
+ failwith "The given FGraph is not a Directed Acyclic Graph!"
+ else
+ LongestPath.getLongestPathOfFGraphUnchecked starting getEdgeWeight graph
+
+
+ ///
+ /// Computes longest paths from for using an inverse Dijkstra's algorithm.
+ ///
+ /// Calculate the longest paths from this node.
+ /// The FGraph for which to compute the longest path. Has to be an Directed Acyclic Graph.
+ /// If there isn't a path between two edges, the distance is set to `infinity`.
+ /// Compute sets all EdgeWeights to 1. If you do not want this, consider computeByEdgeData of computeByEdgeDataWith.
+ /// Tuples of an ordered list containing the path and the distance of the longest path.
+ static member compute((starting : 'NodeKey),(graph : FGraph<'NodeKey, 'NodeData, 'EdgeData> )) =
+ LongestPath.getLongestPathOfFGraph starting (fun x -> 1.) graph
+
+ ///
+ /// Computes longest paths from for using an inverse Dijkstra's algorithm.
+ ///
+ /// Calculate the longest paths from this node.
+ /// The FGraph for which to compute the longest path. Has to be an Directed Acyclic Graph.
+ /// If there isn't a path between two edges, the distance is set to `infinity`.
+ /// computeByEdgeData uses the value in EdgeData as the distance. Only usable with float weights as EdgeData.
+ /// Tuples of an ordered list containing the path and the distance of the longest path.
+ static member computeByEdgeData((starting : 'NodeKey),(graph : FGraph<'NodeKey, 'NodeData, float> )) =
+ LongestPath.getLongestPathOfFGraph starting id graph
+
+ ///
+ /// Computes longest paths from for using an inverse Dijkstra's algorithm.
+ ///
+ /// Calculate the longest paths from this node.
+ /// Function to convert the EdgeData to a float.
+ /// The FGraph for which to compute the longest path. Has to be an Directed Acyclic Graph.
+ /// If there isn't a path between two edges, the distance is set to `infinity`.
+ /// computeByEdgeDataWith uses to convert the EdgeData into the needed float weights.
+ /// Tuples of an ordered list containing the path and the distance of the longest path.
+ static member computeByEdgeDataWith((starting : 'NodeKey),(getEdgeWeight : 'EdgeData -> float),(graph : FGraph<'NodeKey, 'NodeData, 'EdgeData> )) =
+ LongestPath.getLongestPathOfFGraph starting getEdgeWeight graph
diff --git a/tests/Graphoscope.Tests/Graphoscope.Tests.fsproj b/tests/Graphoscope.Tests/Graphoscope.Tests.fsproj
index a942876..06662d3 100644
--- a/tests/Graphoscope.Tests/Graphoscope.Tests.fsproj
+++ b/tests/Graphoscope.Tests/Graphoscope.Tests.fsproj
@@ -19,6 +19,7 @@
+
diff --git a/tests/Graphoscope.Tests/LongestPath.fs b/tests/Graphoscope.Tests/LongestPath.fs
new file mode 100644
index 0000000..26619f0
--- /dev/null
+++ b/tests/Graphoscope.Tests/LongestPath.fs
@@ -0,0 +1,49 @@
+module LongestPath
+
+open System
+open Xunit
+open Graphoscope
+open System.IO
+
+open Xunit
+
+[]
+let ``smallCyclicGraphReturnsExceptedResults``() =
+ let cyclicGraphExample =
+ seq{
+ "a","b",1.
+ "a","c",1.
+ "a","d",15.
+ "a","e",1.
+ "c","e",1.
+ "b","d",13.
+ "d","e",1.
+ "e","b",1.
+ "d","d",2.
+ }
+ |> Seq.map(fun (s, t, w) -> (s, s, t, t, w))
+ |> FGraph.ofSeq
+
+ let ex = new System.Exception("The given FGraph is not a Directed Acyclic Graph!")
+
+ // Assert
+ Assert.Throws(fun () -> Measures.LongestPath.compute("a", cyclicGraphExample) |> ignore)
+ |> fun thrown -> Assert.Equal(ex.Message, thrown.Message)
+
+[]
+let smallAcyclicGraphReturnsExceptedResults () =
+
+ let acyclicGraphExample =
+ seq{
+ "A","B",2.
+ "A","D",1.
+ "B","C",2.
+ "D","C",17.2
+ "A","C",18.
+
+ }
+ |>Seq.map(fun (s,t,w) -> (s,s,t,t,w))
+ |>FGraph.ofSeq
+
+ Assert.Equal((["A"; "D"; "C"], 18.2),Measures.LongestPath.computeByEdgeData("A",acyclicGraphExample))
+ Assert.Equal((["A"; "B"; "C"], 2.),Measures.LongestPath.compute("A",acyclicGraphExample))