Fix ability tree "appx. toposort"... finally...

This commit is contained in:
hppeng 2022-07-20 09:21:13 -07:00
parent 77726b003f
commit b0777ecfcf
3 changed files with 78 additions and 81 deletions

View file

@ -170,40 +170,23 @@ const atree_node = new (class extends ComputeNode {
}
node.parents = parents;
}
console.log(atree_map);
let sccs = make_SCC_graph(atree_head, atree_map.values());
let atree_topo_sort = [];
topological_sort_tree(atree_head, atree_topo_sort, new Map());
atree_topo_sort.reverse();
for (const scc of sccs) {
for (const node of scc.nodes) {
delete node.visited;
delete node.assigned;
delete node.scc;
atree_topo_sort.push(node);
}
}
console.log("Approximate topological order ability tree:");
console.log(atree_topo_sort);
return atree_topo_sort;
}
})();
/**
* Create a reverse topological sort of the tree in the result list.
* NOTE: our structure isn't a tree... it isn't even acyclic... but do it anyway i guess...
*
* https://en.wikipedia.org/wiki/Topological_sorting
* @param tree: Root of tree to sort
* @param res: Result list (reverse topological order)
* @param mark_state: Bookkeeping. Call with empty Map()
*/
function topological_sort_tree(tree, res, mark_state) {
const state = mark_state.get(tree);
if (state === undefined) {
// unmarked.
mark_state.set(tree, false); // temporary mark
for (const child of tree.children) {
topological_sort_tree(child, res, mark_state);
}
mark_state.set(tree, true); // permanent mark
res.push(tree);
}
// these cases are not needed. Case 1 does nothing, case 2 should never happen.
// else if (state === true) { return; } // permanent mark.
// else if (state === false) { throw "not a DAG"; } // temporary mark.
}
/**
* Display ability tree from topologically sorted list.
*

View file

@ -223,21 +223,15 @@ function construct_scc_graph(items_to_consider) {
let terminal_node = {
item: null,
children: [],
parents: nodes,
visited: false,
assigned: false,
scc: null
parents: nodes
};
let root_node = {
item: null,
children: nodes,
parents: [],
visited: false,
assigned: false,
scc: null
};
for (const item of items_to_consider) {
nodes.push({item: item, children: [terminal_node], parents: [root_node], visited: false, assigned: false, scc: null});
nodes.push({item: item, children: [terminal_node], parents: [root_node]});
}
// Dependency graph construction.
for (const node_a of nodes) {
@ -253,50 +247,6 @@ function construct_scc_graph(items_to_consider) {
}
}
}
const res = []
/*
* SCC graph construction.
* https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
*/
function visit(u, res) {
if (u.visited) { return; }
u.visited = true;
for (const child of u.children) {
if (!child.visited) { visit(child, res); }
}
res.push(u);
}
visit(root_node, res);
res.reverse();
const sccs = [];
function assign(node, cur_scc) {
if (node.assigned) { return; }
cur_scc.nodes.push(node);
node.scc = cur_scc;
node.assigned = true;
for (const parent of node.parents) {
assign(parent, cur_scc);
}
}
for (const node of res) {
if (node.assigned) { continue; }
const cur_scc = {
nodes: [],
children: new Set(),
parents: new Set()
};
assign(node, cur_scc);
sccs.push(cur_scc);
}
for (const scc of sccs) {
for (const node of scc.nodes) {
for (const child of node.children) {
scc.children.add(child.scc);
}
for (const parent of node.parents) {
scc.parents.add(parent.scc);
}
}
}
const sccs = make_SCC_graph(root_node, nodes);
return [root_node, terminal_node, sccs];
}

View file

@ -889,3 +889,67 @@ function make_elem(type, classlist = [], args = {}) {
}
return ret_elem;
}
/**
* Nodes must have:
* node: {
* parents: List[node]
* children: List[node]
* }
*
* This function will define: "visited, assigned, scc" properties
* Assuming a connected graph. (only one root)
*/
function make_SCC_graph(root_node, nodes) {
for (const node of nodes) {
node.visited = false;
node.assigned = false;
node.scc = null;
}
const res = []
/*
* SCC graph construction.
* https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
*/
function visit(u, res) {
if (u.visited) { return; }
u.visited = true;
for (const child of u.children) {
if (!child.visited) { visit(child, res); }
}
res.push(u);
}
visit(root_node, res);
res.reverse();
const sccs = [];
function assign(node, cur_scc) {
if (node.assigned) { return; }
cur_scc.nodes.push(node);
node.scc = cur_scc;
node.assigned = true;
for (const parent of node.parents) {
assign(parent, cur_scc);
}
}
for (const node of res) {
if (node.assigned) { continue; }
const cur_scc = {
nodes: [],
children: new Set(),
parents: new Set()
};
assign(node, cur_scc);
sccs.push(cur_scc);
}
for (const scc of sccs) {
for (const node of scc.nodes) {
for (const child of node.children) {
scc.children.add(child.scc);
}
for (const parent of node.parents) {
scc.parents.add(parent.scc);
}
}
}
return sccs;
}