import * as _ from 'lodash-es';
import { Graph } from '../graphlib/index.js';
import { List } from './data/list.js';
export { greedyFAS };
var DEFAULT_WEIGHT_FN = _.constant(1);
function greedyFAS(g, weightFn) {
if (g.nodeCount() <= 1) {
return [];
}
var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
return _.flatten(
_.map(results, function (e) {
return g.outEdges(e.v, e.w);
})
);
}
function doGreedyFAS(g, buckets, zeroIdx) {
var results = [];
var sources = buckets[buckets.length - 1];
var sinks = buckets[0];
var entry;
while (g.nodeCount()) {
while ((entry = sinks.dequeue())) {
removeNode(g, buckets, zeroIdx, entry);
}
while ((entry = sources.dequeue())) {
removeNode(g, buckets, zeroIdx, entry);
}
if (g.nodeCount()) {
for (var i = buckets.length - 2; i > 0; --i) {
entry = buckets[i].dequeue();
if (entry) {
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
break;
}
}
}
}
return results;
}
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
var results = collectPredecessors ? [] : undefined;
_.forEach(g.inEdges(entry.v), function (edge) {
var weight = g.edge(edge);
var uEntry = g.node(edge.v);
if (collectPredecessors) {
results.push({ v: edge.v, w: edge.w });
}
uEntry.out -= weight;
assignBucket(buckets, zeroIdx, uEntry);
});
_.forEach(g.outEdges(entry.v), function (edge) {
var weight = g.edge(edge);
var w = edge.w;
var wEntry = g.node(w);
wEntry['in'] -= weight;
assignBucket(buckets, zeroIdx, wEntry);
});
g.removeNode(entry.v);
return results;
}
function buildState(g, weightFn) {
var fasGraph = new Graph();
var maxIn = 0;
var maxOut = 0;
_.forEach(g.nodes(), function (v) {
fasGraph.setNode(v, { v: v, in: 0, out: 0 });
});
_.forEach(g.edges(), function (e) {
var prevWeight = fasGraph.edge(e.v, e.w) || 0;
var weight = weightFn(e);
var edgeWeight = prevWeight + weight;
fasGraph.setEdge(e.v, e.w, edgeWeight);
maxOut = Math.max(maxOut, (fasGraph.node(e.v).out += weight));
maxIn = Math.max(maxIn, (fasGraph.node(e.w)['in'] += weight));
});
var buckets = _.range(maxOut + maxIn + 3).map(function () {
return new List();
});
var zeroIdx = maxIn + 1;
_.forEach(fasGraph.nodes(), function (v) {
assignBucket(buckets, zeroIdx, fasGraph.node(v));
});
return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
}
function assignBucket(buckets, zeroIdx, entry) {
if (!entry.out) {
buckets[0].enqueue(entry);
} else if (!entry['in']) {
buckets[buckets.length - 1].enqueue(entry);
} else {
buckets[entry.out - entry['in'] + zeroIdx].enqueue(entry);
}
}