Skip to content

Commit

Permalink
Add BFS.lua
Browse files Browse the repository at this point in the history
  • Loading branch information
hansonchar committed Jan 14, 2025
1 parent 068cd42 commit 62b5726
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
49 changes: 49 additions & 0 deletions learning-lua/algo/BFS-tests.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
local BFS = require "algo.BFS"
local Graph = require "algo.Graph"

local function load_input(input)
local G = Graph:new()
for _, edge in ipairs(input) do
local from, to, cost = edge:match('(%w-)%-(%w+)=(%d+)')
G:add(from, to, cost)
end
return G
end

local function tim_test()
print("BFS tim_test...")
local input<const> = {'s-v=1', 's-w=4', 'v-w=2', 'v-t=6', 'w-t=3'}
local src<const> = 's'
local G = load_input(input)
local level_counts = {}
for from, to, weight, level in BFS:new(G, src):iterate() do
level_counts[level] = level_counts[level] or 0
level_counts[level] = level_counts[level] + 1
print(string.format("%d: %s-%s=%d", level, from, to, weight))
end
assert(level_counts[1] == 2)
assert(level_counts[2] == 3)
assert(level_counts[3] == 1)
end

local function scott_moura_test()
print("BFS scott_moura_test ... ")
local input<const> = {'A-B=2', 'A-C=4', 'A-D=4', 'B-F=6', 'C-F=5', 'C-E=7', 'C-D=1', 'D-E=5', 'D-H=11', 'E-G=3',
'E-H=4', 'F-H=5', 'F-G=2', 'F-E=1', 'G-H=2'}
local src<const> = 'A'
local level_counts = {}
local G = load_input(input)
for from, to, weight, level in BFS:new(G, src):iterate() do
level_counts[level] = level_counts[level] or 0
level_counts[level] = level_counts[level] + 1
print(string.format("%d: %s-%s=%d", level, from, to, weight))
end
assert(level_counts[1] == 3)
assert(level_counts[2] == 6)
assert(level_counts[3] == 12)
assert(level_counts[4] == 10)
assert(level_counts[5] == 3)
end

tim_test()
scott_moura_test()
47 changes: 47 additions & 0 deletions learning-lua/algo/BFS.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
local Graph = require "algo.Graph"
local Queue = require "algo.Queue"
local BFS = {}
local E = {}

local function _iterate(bfs)
local q = Queue:new()
local level = 0
local from = bfs.src_vertex
repeat
local vertex = bfs.graph:vertex(from)
level = level + 1
for to, weight in vertex:outgoings() do
coroutine.yield(from, to, weight, level)
q:enqueue{to, weight, level, from}
end
local item = (q:dequeue() or E)
from, level = item[1], item[3]
until not from or from == bfs.src_vertex
end

function BFS:iterate()
return coroutine.wrap(function()
_iterate(self)
end)
end

function BFS:class(o)
setmetatable(o, BFS)
BFS.__index = BFS
return o
end

---@param G (table) graph
---@param src (any) source vertex
function BFS:new(G, src)
assert(G, "Missing Graph")
assert(Graph.isGraph(G), "G must be a graph object")
assert(src, "Missing source vertex")
assert(G:vertex(src), "Source vertex not found in graph")
return BFS:class{
graph = G,
src_vertex = src
}
end

return BFS

0 comments on commit 62b5726

Please sign in to comment.