-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
47cf7e6
commit 5449893
Showing
6 changed files
with
243 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
local Graph = require "algo.Graph" | ||
local SCCSearch = require "algo.SCCSearch" | ||
local E = {} | ||
|
||
local function debug(...) | ||
-- print(...) | ||
end | ||
---@param input (table) array of directed arcs in the format of, for example, "u-v". | ||
---@return (table) a Graph object | ||
local function load_edges(input) | ||
local G = Graph:new() | ||
for _, edge in ipairs(input) do | ||
local from, to = edge:match('(%w-)%-(%w+).*') | ||
G:add(from, to, 1) | ||
end | ||
return G | ||
end | ||
|
||
local function scc_test(G) | ||
local sccs = {} | ||
for scc, id, count in SCCSearch:new(G):iterate() do | ||
debug(scc, id, count) | ||
sccs[id] = sccs[id] or {} | ||
sccs[id][scc] = true | ||
end | ||
assert(#sccs == 4) | ||
for _, scc in ipairs {'6', '8', '10'} do | ||
assert(sccs[1][scc]) | ||
end | ||
local i, j | ||
if next(sccs[2]) == '11' then | ||
i, j = 2, 3 | ||
else | ||
i, j = 3, 2 | ||
end | ||
assert(sccs[i]['11']) | ||
for _, scc in ipairs {'2', '4', '7', '9'} do | ||
assert(sccs[j][scc]) | ||
end | ||
for _, scc in ipairs {'1', '3', '5'} do | ||
assert(sccs[4][scc]) | ||
end | ||
end | ||
|
||
-- Algoriths Illuminated Part 2 by Prof. Tim Roughgarden | ||
print("Finding SCC using Graph of Figure 8.16 by Tim ...") | ||
local G = load_edges {'1-3', '3-5', '5-1', '3-11', '5-9', '5-7', '11-6', '11-8', '8-6', '6-10', '10-8', '9-2', '9-4', | ||
'2-4', '2-10', '4-7', '7-9'} | ||
|
||
scc_test(G) | ||
os.exit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
local GraphSearch = require "algo.GraphSearch" | ||
local Graph = require "algo.Graph" | ||
local TopologicalSearch = require "algo.TopologicalSearch" | ||
local DFS = require "algo.DFS" | ||
local SCCSearch = GraphSearch:class() | ||
local E = {} | ||
|
||
local function debug(...) | ||
-- print(...) | ||
end | ||
|
||
local function reversed(a) | ||
local j = #a | ||
for i = 1, #a do | ||
if i >= j then | ||
break | ||
end | ||
a[i], a[j] = a[j], a[i] | ||
j = j - 1 | ||
end | ||
return a | ||
end | ||
|
||
-- Uses the Kosaraju algorithm, but uses a topological search instead of DFS for the second pass. | ||
-- Simpler code, but arguably less "traditional" as using DFS directly. (See SccDfsSearch.lua) | ||
-- 1. Transpose the graph, then perform a topo search to get an array of vertexes in descending topo order. | ||
-- 2. Transpose the graph again, then perform a topological iteration using the reversed array as the 'src_spec'. | ||
-- A 'src_spec' is used to specify the order of source vertices to choose from whenenver | ||
-- the search needs to restart from a different source vertex. | ||
-- 3. We get a new SCC whenever the topological search retries from a different branch of the graph. | ||
-- This also works, leveraging on a Topological search instead of DFS. | ||
local function _iterate(self) | ||
local src_spec = {} | ||
local G = self.graph | ||
G:transpose() | ||
for v in TopologicalSearch:new(G):iterate() do | ||
src_spec[#src_spec + 1] = v | ||
end | ||
G:transpose() | ||
local scc_id, count = 1, 0 | ||
local src_spec = reversed(src_spec) | ||
debug(table.concat(src_spec, ",")) | ||
local topo = TopologicalSearch:new(G, nil, src_spec) | ||
for scc, is_first_scc in topo:iterate() do | ||
count = count + 1 | ||
coroutine.yield(scc, scc_id, count) | ||
if is_first_scc then | ||
scc_id, count = scc_id + 1, 0 | ||
end | ||
end | ||
end | ||
|
||
---@param G (table) graph | ||
function SCCSearch:new(G) | ||
return getmetatable(self):new(G, nil, _iterate) | ||
end | ||
|
||
return SCCSearch |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
local Graph = require "algo.Graph" | ||
local SccDfsSearch = require "algo.SccDfsSearch" | ||
local E = {} | ||
|
||
local function debug(...) | ||
-- print(...) | ||
end | ||
---@param input (table) array of directed arcs in the format of, for example, "u-v". | ||
---@return (table) a Graph object | ||
local function load_edges(input) | ||
local G = Graph:new() | ||
for _, edge in ipairs(input) do | ||
local from, to = edge:match('(%w-)%-(%w+).*') | ||
G:add(from, to, 1) | ||
end | ||
return G | ||
end | ||
|
||
local function scc_test(G) | ||
local sccs = {} | ||
for scc, id, count in SccDfsSearch:new(G):iterate() do | ||
debug(scc, id, count) | ||
sccs[id] = sccs[id] or {} | ||
sccs[id][scc] = true | ||
end | ||
assert(#sccs == 4) | ||
for _, scc in ipairs{'6', '8', '10'} do | ||
assert(sccs[1][scc]) | ||
end | ||
local i, j | ||
if next(sccs[2]) == '11' then | ||
i, j = 2, 3 | ||
else | ||
i, j = 3, 2 | ||
end | ||
assert(sccs[i]['11']) | ||
for _, scc in ipairs{'2', '4', '7', '9'} do | ||
assert(sccs[j][scc]) | ||
end | ||
for _, scc in ipairs{'1', '3', '5'} do | ||
assert(sccs[4][scc]) | ||
end | ||
end | ||
|
||
-- Algoriths Illuminated Part 2 by Prof. Tim Roughgarden | ||
print("Testing SCC using Graph of Figure 8.16 by Tim ...") | ||
local G = load_edges {'1-3', '3-5', '5-1', '3-11', '5-9', '5-7', '11-6', '11-8', '8-6', '6-10', '10-8', '9-2', '9-4', | ||
'2-4', '2-10', '4-7', '7-9'} | ||
|
||
scc_test(G) | ||
os.exit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
local GraphSearch = require "algo.GraphSearch" | ||
local Graph = require "algo.Graph" | ||
local TopologicalSearch = require "algo.TopologicalSearch" | ||
local DFS = require "algo.DFS" | ||
local SccDfsSearch = GraphSearch:class() | ||
local E = {} | ||
|
||
local function debug(...) | ||
-- print(...) | ||
end | ||
|
||
local function reversed(a) | ||
local j = #a | ||
for i = 1, #a do | ||
if i >= j then | ||
break | ||
end | ||
a[i], a[j] = a[j], a[i] | ||
j = j - 1 | ||
end | ||
return a | ||
end | ||
|
||
-- Uses the Kosaraju algorithm. | ||
-- 1. Transpose the graph, then perform a topo search to get an array of vertexes in descending topo order. | ||
-- 2. Transpose the graph again, then perform a DFS iteration using the reversed array as the 'src_spec'. | ||
-- A 'src_spec' is used to specify the order of source vertices to choose from whenenver | ||
-- the search needs to restart from a different source vertex. | ||
-- 3. We get a new SCC whenever the source vertex changes during the iteration. | ||
local function _iterate(self) | ||
local src_spec = {} | ||
local G = self.graph | ||
G:transpose() | ||
for v in TopologicalSearch:new(G):iterate() do | ||
src_spec[#src_spec + 1] = v | ||
end | ||
G:transpose() | ||
local scc_id, count = 0, 0 | ||
local src_spec = reversed(src_spec) | ||
debug(table.concat(src_spec, ",")) | ||
local dfs = DFS:new(G, nil, nil, src_spec) | ||
local scc_src_vertex | ||
for from, to, _, _, _, _, src_vertex in dfs:iterate() do | ||
debug(string.format("from=%s to=%s, src_vertex=%s", from, to, src_vertex)) | ||
if scc_src_vertex == src_vertex then | ||
if to then | ||
count = count + 1 | ||
coroutine.yield(to, scc_id, count) | ||
end | ||
else | ||
assert(from == src_vertex) | ||
scc_id, count = scc_id + 1, 1 | ||
coroutine.yield(from, scc_id, count) | ||
scc_src_vertex = src_vertex | ||
if to then | ||
count = count + 1 | ||
coroutine.yield(to, scc_id, count) | ||
end | ||
end | ||
end | ||
end | ||
|
||
---@param G (table) graph | ||
function SccDfsSearch:new(G) | ||
return getmetatable(SccDfsSearch):new(G, nil, _iterate) | ||
end | ||
|
||
return SccDfsSearch |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters