Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file: -- http://angg.twu.net/LUA/DFS.lua.html -- http://angg.twu.net/LUA/DFS.lua -- (find-angg "LUA/DFS.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- -- (defun d () (interactive) (find-angg "LUA/DFS.lua")) -- (defun dt () (interactive) (find-angg "LUA/DFSTriangle.lua")) -- «.test-triangle» (to "test-triangle") -- «.test-tname» (to "test-tname") transpose = function (A) local B = {} for k,v in pairs(A) do B[v] = k end return B end -- Experimental, overridden by the next definition. -- See: (find-angg "LUA/lua50init.lua" "SetL") -- (find-angg "LUA/lua50init.lua" "SetL" " add =") -- -- This is a class for doing depth-first searches on graphs that may -- have loops. Remember that in DFSs we "open" a node A and then we -- visit recursively all the nodes that are accessible from A; we only -- "close" A when we have "closed" all nodes accessible from A. This -- class allows setting a node B to "open" without doing the step that -- visits the nodes that are accessible from B, has a method -- :recurseopennodes() that... [TODO: finish explaining this] -- DFS = Class { type = "DFS", new = function () return DFS { opened = SetL.new(), closed = SetL.new(), arrowsfrom = SetL.new(), named = SetL.new(), -- used in some applications } end, __index = { -- -- Very low-level DFS methods. isopened = function (d, node) return d.opened:has(node) end, isclosed = function (d, node) return d.closed:has(node) end, open0 = function (d, node) d.opened:add(node) end, close0 = function (d, node) d.closed:add(node) end, isnew = function (d, node) return (not d:isopened(node)) and (not d:isclosed(node)) end, -- -- Names and arrows. -- To register a new name or a new arrow, use name0 and arrow0. -- Calling d:name0(node, name2) again will not overwrite the old name. -- Calling d:arrow0(src, tgt, arrowname2) will add arrowname2 to -- the SetL that stores the names of arrows from src to tgt. name0 = function (d, node, name) d.named:add(node, name) end, arrow0 = function (d, src, tgt, arrowname) if not d.arrowsfrom:has(src) then d.arrowsfrom:add(src, SetL.new()) end d.arrowsfrom:get(src):add(tgt, arrowname) end, getname = function (d, node) return d.named:val(node) end, genallarrows = function (d) return cow(function () for src,tgts in d.arrowsfrom:gen() do for tgt,arrowname in tgts:gen() do coy(src, tgt, arrowname) end end end) end, -- -- These methods can be overriden. -- The :genarrowsfrom() below is for :nameluatables(). -- The :ignorearrowsfrom() is an internal method that is used -- only by this implementation of :genarrowsfrom(). ignorearrowsfrom = function (d, src) local ot = otype(src) return (ot == "Set") or (ot == "SetL") or (ot == "DFS") end, genarrowsfrom = function (d, src) if not (type(src) == "table") then return cow(nop) end if d:ignorearrowsfrom(src) then return cow(nop) end return cow(function () for name,tgt in pairs(src) do if type(name) == "string" and type(tgt) == "table" then coy(tgt, name) end local mt = getmetatable(o) if type(mt) == "table" then coy(mt, "__mt") end end end) end, -- -- Medium-level methods for DFSs. -- In standard DFSs users would only call d:openrec(node). -- In hackish DFSs users first call d:open0(nodei) on some nodes -- to delay recursion on them, then they call d:openrec(nodej) on -- some "normal" nodes, then they call d:recurseopennodes() to -- recurse on all the delayed nodes. close = function (d, node) d:open0(node); d:close0(node); end, recurse = function (d, node) for tgt,arrowname in d:genarrowsfrom(node) do d:arrow0(node, tgt, arrowname) d:openrec(tgt) end end, openrec = function (d, node) if d:isnew(node) then d:open0(node) d:recurse(node) d:close0(node) end end, recurseopennodes = function (d) for node in (d.opened - d.closed):gen() do d:recurse(node) d:close0(node) end end, -- -- High-level methodes for DFSs with names. namenoderec = function (d, node, name) d:name0(node, name) d:open0(node, name) if not d:isclosed(node) then d:recurse(node) d:close0(node) end end, namenodenonrec = function (d, node, name) d:name0(node, name) d:open0(node, name) end, nameglobaltables = function (d) d:namenodenonrec(_G, "_G") for k,v in pairs(_G) do if type(k) == "string" and type(v) == "table" then local node, name = _G[k], k d:namenodenonrec(node, name) end end end, nameothertables = function (d) for src,tgt,arrowname in d:genallarrows() do local tgtname = d:getname(src) .. "." .. arrowname d:name0(tgt, tgtname) end end, nameluatables = function (d) d:nameglobaltables() d:recurseopennodes() d:nameothertables() return d end, -- namefunctionsin0 = function (d, tbl, prefix) if not type(tbl) == "table" then error("Not a table!") end for k,v in pairs(tbl) do if type(k) == "string" and type(v) == "function" then d:name0(v, prefix..k) end end end, namefunctionsin = function (d, o) local tbl, prefix if o == _G or o == "" then tbl,prefix = _G, "" elseif type(o) == "table" then tbl,prefix = o, d:getname(o).."." elseif type(o) == "string" then tbl,prefix = expr(o), o.."." end d:namefunctionsin0(tbl, prefix) end, nameallfunctions = function (d) d:namefunctionsin("") for tbl in d.closed:gen() do d:namefunctionsin(tbl) end return d end, }, } --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "DFS.lua" d = DFS.new():nameluatables() for node in d.closed:gen() do print(d:getname(node)) end = d:getname(_G) = d:getname(Class) = d:getname(Set.__index) --]] --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "DFS.lua" d = DFS.new():nameluatables():nameallfunctions() for a,b in d.named:gen() do print(a, b) end PPV(infomanual_basedir) --]] -- Local Variables: -- coding: utf-8-unix -- End: