function* shortest_tree({ graph, origins, cutoff, step }) {
const start_time = performance.now(),
_step = step === undefined ? 0 : +step,
neigh = new Map();
let n = 0;
for (let i = 0, l = graph.sources.length; i < l; i++) {
const a = +graph.sources[i],
b = +graph.targets[i];
if (!neigh.has(a)) neigh.set(a, []);
neigh.get(a).push(i);
n = Math.max(n, a + 1, b + 1);
}
const q = new FlatQueue(),
front = q.ids,
cost = new Float64Array(n).fill(Infinity),
predecessor = new Int32Array(n).fill(-1),
origin = new Int32Array(n).fill(-1),
status = {
cost,
predecessor,
origin,
step: 0,
front,
max_front_size: 0,
ended: false
};
origins.forEach(node => {
if (isFinite(node)) node = { id: node, cost: 0 };
if (node.id < n) {
origin[node.id] = node.id;
q.push(node.id, (cost[node.id] = node.cost));
}
});
const time = performance.now();
while (q.length > 0) {
const curr = q.peekValue(),
node = q.pop();
if (curr > cost[node]) continue;
if (neigh.has(node)) {
for (const i of neigh.get(node)) {
const c = graph.costs ? +graph.costs[i] : 1;
if (!isFinite(c)) continue;
const tentative = c + cost[node];
if (tentative > cutoff) continue;
const dest = graph.targets[i];
if (tentative >= 0 && tentative < cost[dest]) {
predecessor[dest] = node;
origin[dest] = origin[node];
q.push(dest, (cost[dest] = tentative));
status.max_front_size = Math.max(status.max_front_size, front.length);
}
}
}
status.step++;
if (_step && status.step % _step === 0) {
status.performance = performance.now() - time;
yield status;
}
}
status.ended = true;
status.performance = performance.now() - time;
yield status;
}