Skip to content

Commit

Permalink
Added the implementation of the Edmond Karp algorithm along with test…
Browse files Browse the repository at this point in the history
… cases (#252)

* Added the implementation for bijection method binary to decimal and euler method

* Added the implementation of the edmondkarp along with tests

* Update graph/edmondkarp.ts

Co-authored-by: Lars Müller <[email protected]>

* Update edmondkarp.ts

* Update graph/edmondkarp.ts

Co-authored-by: Lars Müller <[email protected]>

* Implement the furhter changes to make the algorithm more refined

* Updated the test cases 

Updated the test cases

* Updated the code and rewrite some functions 

Updated the code and rewrite some functions

* Implement the optimal stack queue implementation in the edmond karp algorithm

* removed the bisection_method.ts, decimal_convert.ts, euler_method.ts

* Revert changes to package.json and package-lock.json

---------

Co-authored-by: Lars Müller <[email protected]>
  • Loading branch information
mapcrafter2048 and appgurueu authored Oct 16, 2024
1 parent 44127b2 commit 19b4ced
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 0 deletions.
97 changes: 97 additions & 0 deletions graph/edmonds_karp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { StackQueue } from '../data_structures/queue/stack_queue'

/**
* @function edmondsKarp
* @description Compute the maximum flow from a source node to a sink node using the Edmonds-Karp algorithm.
* @Complexity_Analysis
* Time complexity: O(V * E^2) where V is the number of vertices and E is the number of edges.
* Space Complexity: O(E) due to residual graph representation.
* @param {[number, number][][]} graph - The graph in adjacency list form.
* @param {number} source - The source node.
* @param {number} sink - The sink node.
* @return {number} - The maximum flow from the source node to the sink node.
* @see https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm
*/
export default function edmondsKarp(
graph: [number, number][][],
source: number,
sink: number
): number {
const n = graph.length

// Initialize residual graph
const residualGraph: [number, number][][] = Array.from(
{ length: n },
() => []
)

// Build residual graph from the original graph
for (let u = 0; u < n; u++) {
for (const [v, cap] of graph[u]) {
if (cap > 0) {
residualGraph[u].push([v, cap]) // Forward edge
residualGraph[v].push([u, 0]) // Reverse edge with 0 capacity
}
}
}

const findAugmentingPath = (parent: (number | null)[]): number => {
const visited = Array(n).fill(false)
const queue = new StackQueue<number>()
queue.enqueue(source)
visited[source] = true
parent[source] = null

while (queue.length() > 0) {
const u = queue.dequeue()
for (const [v, cap] of residualGraph[u]) {
if (!visited[v] && cap > 0) {
parent[v] = u
visited[v] = true
if (v === sink) {
// Return the bottleneck capacity along the path
let pathFlow = Infinity
let current = v
while (parent[current] !== null) {
const prev = parent[current]!
const edgeCap = residualGraph[prev].find(
([node]) => node === current
)![1]
pathFlow = Math.min(pathFlow, edgeCap)
current = prev
}
return pathFlow
}
queue.enqueue(v)
}
}
}
return 0
}

let maxFlow = 0
const parent = Array(n).fill(null)

while (true) {
const pathFlow = findAugmentingPath(parent)
if (pathFlow === 0) break // No augmenting path found

// Update the capacities and reverse capacities in the residual graph
let v = sink
while (parent[v] !== null) {
const u = parent[v]!
// Update capacity of the forward edge
const forwardEdge = residualGraph[u].find(([node]) => node === v)!
forwardEdge[1] -= pathFlow
// Update capacity of the reverse edge
const reverseEdge = residualGraph[v].find(([node]) => node === u)!
reverseEdge[1] += pathFlow

v = u
}

maxFlow += pathFlow
}

return maxFlow
}
82 changes: 82 additions & 0 deletions graph/test/edmonds_karp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import edmondsKarp from '../edmonds_karp'

describe('Edmonds-Karp Algorithm', () => {
it('should find the maximum flow in a simple graph', () => {
const graph: [number, number][][] = [
[
[1, 3],
[2, 2]
], // Node 0: Edges to node 1 (capacity 3), and node 2 (capacity 2)
[[3, 2]], // Node 1: Edge to node 3 (capacity 2)
[[3, 3]], // Node 2: Edge to node 3 (capacity 3)
[] // Node 3: No outgoing edges
]
const source = 0
const sink = 3
const maxFlow = edmondsKarp(graph, source, sink)
expect(maxFlow).toBe(4)
})

it('should find the maximum flow in a more complex graph', () => {
const graph: [number, number][][] = [
[
[1, 10],
[2, 10]
], // Node 0: Edges to node 1 and node 2 (both capacity 10)
[
[3, 4],
[4, 8]
], // Node 1: Edges to node 3 (capacity 4), and node 4 (capacity 8)
[[4, 9]], // Node 2: Edge to node 4 (capacity 9)
[[5, 10]], // Node 3: Edge to node 5 (capacity 10)
[[5, 10]], // Node 4: Edge to node 5 (capacity 10)
[] // Node 5: No outgoing edges (sink)
]
const source = 0
const sink = 5
const maxFlow = edmondsKarp(graph, source, sink)
expect(maxFlow).toBe(14)
})

it('should return 0 when there is no path from source to sink', () => {
const graph: [number, number][][] = [
[], // Node 0: No outgoing edges
[], // Node 1: No outgoing edges
[] // Node 2: No outgoing edges (sink)
]
const source = 0
const sink = 2
const maxFlow = edmondsKarp(graph, source, sink)
expect(maxFlow).toBe(0)
})

it('should handle graphs with no edges', () => {
const graph: [number, number][][] = [
[], // Node 0: No outgoing edges
[], // Node 1: No outgoing edges
[] // Node 2: No outgoing edges
]
const source = 0
const sink = 2
const maxFlow = edmondsKarp(graph, source, sink)
expect(maxFlow).toBe(0)
})

it('should handle graphs with self-loops', () => {
const graph: [number, number][][] = [
[
[0, 10],
[1, 10]
], // Node 0: Self-loop with capacity 10, and edge to node 1 (capacity 10)
[
[1, 10],
[2, 10]
], // Node 1: Self-loop and edge to node 2
[] // Node 2: No outgoing edges (sink)
]
const source = 0
const sink = 2
const maxFlow = edmondsKarp(graph, source, sink)
expect(maxFlow).toBe(10)
})
})

0 comments on commit 19b4ced

Please sign in to comment.